Search code examples
rshinyr-leaflet

Getting data from measure tool


I'm trying to get the results (area specifically) of when a user uses the measure tool on an RShiny Leaflet map. According to the leaflet-measure documentation, you can subscribe to 2 events on the leaflet map named measurestart and measurefinish. I need to subscribe to these events and get the result data that the events give but I don't know how.

I have tried many different ways to subscribe to the event, but none of them are getting triggered by the map.

Here is some code that feels like it's the closest to working:

observeEvent(input$map1_measurefinish, {
    print("user finished measurement")
})

or

observeEvent(input$measurefinish, {
    print("user finished measurement")
})

The code for the leaflet in my server section looks like this:

output$map1 <-renderLeaflet({
      m<-leaflet() %>%
      addProviderTiles('Esri.WorldImagery') %>%...
# there's more code here but I don't think its relevant for the issue

What do I need to do to 1. Properly subscribe to the event to detect when a measurement is finished and 2. receive the output data to do things with in the observer method?

Edit: Solution (as given by @NicE)

The changes I made to my code to make it work:

Inside the leaflet added the marked code:

output$map1 <-renderLeaflet({
     m<-leaflet() %>%
     addMeasure() %>%
     # Start
     htmlwidgets::onRender("
        function(el, x) {
          var myMap = this;
          myMap.on('measurefinish',
          function (e) {
            Shiny.onInputChange('selectedArea', e.area);
            Shiny.onInputChange('inputtedCoordinates', e.lastCoord);
          })
        }")
     # End

And additionally added an observer (will do more exciting things than printing):

observeEvent(input$selectedArea, {
    print(paste0("area received:", input$selectedArea))
})

Solution

  • You can leverage the onRender function to add listeners to plugin events. For example you could try:

    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);
                })
            }")
    

    This adds a listener on measurefinish, and passes the area to the selectedArea shiny input. You can change e.area to any fields mentionned here.

    Here is a MWE:

    library(leaflet)
    library(shiny)
    
    
    ui <- fluidPage(
      leafletOutput("mymap"),
      br(),
      textOutput("areaText")
    )
    
    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);
                })
            }")
        })
    
      output$areaText <- renderText({
        paste("Area",input$selectedArea)
      })
    }
    
    shinyApp(ui, server)