Вот способ сделать это с помощью функции addMeasure()
из leaflet
и некоторого JavaScript.
Часть JavaScript, безусловно, может быть оптимизирована с некоторым делегированием событий, поскольку кнопки отображаются динамически. Поэтому я использую функцию setTimeout
, которая переоценивает каждую секунду. Я уверен, что это можно сделать более плавно, но я не эксперт JS. ;)
Код JavaScript ожидает нажатия кнопки Завершить измерение и получает результат из этой части HTML $('.js-results').children()[2].innerText
.
Затем он передается в measurefinish
с помощью Shiny.onInputChange
, чтобы вы могли получить доступ к этому значению в коде своего сервера с помощью input$measurefinish
.
Одно из возможных решений:
library(shiny)
library(leaflet)
js <- HTML("
$(document).on('shiny:connected', function(event) {
setTimeout(function(){
var fin = document.getElementsByClassName('js-finish');
fin[0].addEventListener('click', function eventHandler(event) {
var area = $('.js-results').children()[2].innerText;
Shiny.onInputChange('measurefinish', area);
});
}, 1000);
});
")
ui <- fluidPage(
tags$head(tags$script(js)),
leafletOutput("map1"),
verbatimTextOutput("area")
)
server <- function(input, output, session) {
output$map1 <-renderLeaflet({
m<-leaflet() %>%
addMeasure() %>%
addProviderTiles('Esri.WorldImagery')
m
})
output$area <- renderText({
req(input$measurefinish)
area <- input$measurefinish
area <- gsub(pattern = "\n", "", x = area, fixed = T)
## Convert to numeric value
# area <- regmatches(area, regexpr("\\(?[0-9,.]+", area))
# area <- as.numeric(gsub(pattern = ",", "", area, fixed=T))
area
})
}
shinyApp(ui, server)
На основании вашего комментария к ответу @ NicE я отредактировал его код, чтобы суммировать все измерения площади. Я использую reactiveValues
объект, где сумма суммируется. Чтобы восстановить общую площадь до 0, я использую actionButton
с observeEvent
деталью.
library(leaflet)
library(shiny)
ui <- fluidPage(
leafletOutput("mymap"),
br(),
actionButton("resetArea", label = "Reset total area to 0"),
textOutput("areaText"),
textOutput("areaSumText")
)
server <- function(input, output, session) {
output$mymap <- renderLeaflet({
leaflet() %>% addTiles() %>%
fitBounds(-73.9, 40.75, -73.95,40.8) %>%
addMeasure() %>%
htmlwidgets::onRender("
function(el, x) {
var myMap = this;
myMap.on('measurefinish',
function (e) {
Shiny.onInputChange('selectedArea', e.area);
})
}")
})
totalArea <- reactiveValues(sum = NULL)
observe({
req(input$selectedArea)
isolate({
if (is.null(totalArea$sum)) {
totalArea$sum = input$selectedArea
} else {
totalArea$sum = totalArea$sum + input$selectedArea
}
})
})
observeEvent(input$resetArea, {
totalArea$sum = NULL
})
output$areaText <- renderText({
paste("Area",input$selectedArea)
})
output$areaSumText <- renderText({
req(totalArea$sum)
paste("Sum of Area",totalArea$sum)
})
}
shinyApp(ui, server)