5

I have a shiny app that displays a leaflet map. One of the functionalities of the app allows users to add a new geographic marker on the map. However, I would like to make the popup of such marker already opened as soon as it is added on the map, but always keeping the possibility to close it with the "x" button or by clicking on the map.

I've read the "Marker" guide of the leaflet documentation (sub-section "Popup methods inherited from Layer", the very detailed guide is, apparently, not available in the R language) and I've found this option openPopup(). Unfortunately, this doesn't seem to work for my code. Here's a simple example:

library(leaflet)

leaflet() %>% 
  addTiles() %>% 
  addMarkers(lng = -100,
             lat = 50,
             popup = "ALE",
             options = popupOptions(openPopup = TRUE))

The expected behaviour is the one shown in this online tool that uses leaflet. Please try to search for an address and look as the new marker has its own popup immediately open.

Thanks in advance for your help!

1 Answer 1

5

Code

I guess a bit of JavaScript will be needed as the interface seems not to support this feature.

Below a working shiny example:

library(shiny)
library(leaflet)
library(shinyjs)

js_save_map_instance <- HTML(
   paste(
      "var mapsPlaceholder = [];",
      "L.Map.addInitHook(function () {",
      "   mapsPlaceholder.push(this); // Use whatever global scope variable you like.",
      "});", sep = "\n"
   )
)

js_open_popup <- HTML(
   paste("function open_popup(id) {",
         "   console.log('open popup for ' + id);",
         "   mapsPlaceholder[0].eachLayer(function(l) {",
         "      if (l.options && l.options.layerId == id) {",
         "         l.openPopup();",
         "      }",
         "   });",
         "}", sep = "\n"
   )
)

ui <- fluidPage(
   tags$head(
      tags$script(type = "text/javascript",
                  js_save_map_instance,
                  js_open_popup),
      useShinyjs()
   ),
   wellPanel(
      fluidRow(
         sliderInput("lng", "Longitude:", 10, 60, 35, 0.01),
         sliderInput("lat", "Latitude:", 35, 75, 42.5, 0.01),
         actionButton("add", "Add Marker")
      )
   ),
   fluidRow(
      leafletOutput("map")
   )
)

server <- function(input, output, session) {
   map <- leaflet() %>% 
      addTiles() %>%
      fitBounds(10, 35, 60, 75)
   
   output$map <- renderLeaflet(
      map
   )
   
   observeEvent(input$add, {
      id <- paste0("marker", input$add)
      leafletProxy("map") %>%
         addMarkers(input$lng, input$lat, id,
                    "mymarkers", 
                    popup = sprintf("%.2f / %.2f: %s", input$lng, input$lat, 
                                    id))
      runjs(sprintf("setTimeout(() => open_popup('%s'), 10)", id))
   })
}

shinyApp(ui, server)

Remarks

  • leaflet.js does not provide an out-of-the-box functionality to retrieve the map instance after the initialization. Thus, we have to use a workaround to save the map explicitly upon initialization. This is done in the JS code stored in js_save_map_instance. The idea is taken from Find Leaflet map object after initialisation.
  • We create a JS function, which takes the id of the marker for which we want to open the popup. In this function we take the first element of our array, where we stored all map instances (if there should be more than one leaflet map on the page, this needs to be adapted.
  • On this map instance we can loop through all layers and if the layerId equals the one we are looking for, we can call openPopup on this layer. (N.B. ideally we could access the layer directly (again I did not find any function in the API for that) and we could use the private _layer property, but since it is private, I use the loop apprach.)
  • All what is left, is to call open_popup in the right place on the shiny side. I needed to add a small delay to avoid that we call the function before the marker is added.

Results

Popup on creation

1
  • I confirm this is the correct answer for the shiny and R environment. Thanks really a lot for your perfect explanation!
    – nd091680
    Commented Feb 25, 2021 at 7:02

Not the answer you're looking for? Browse other questions tagged or ask your own question.