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](https://cdn.statically.io/img/i.sstatic.net/mdnqC.gif)