Open brendanhoganvt opened 9 years ago
One thing you can do is use leafletProxy
to only redraw the data layers that change as described in the Leaflet for R documentation on using Shiny. That way it doesn't change the view when you render new data.
I'm using leafletProxy to change the provider tiles. When this happens, it resets the zoom. Is there a way to prevent this OR to query the current zoom and location and re-apply them after adding the new provider tiles?
@jzadra Do you have a reproducible example for this? I’m a little surprised this happens.
Maybe if you call %>% mapOptions(zoomToLimits="first")
on the initial leaflet
object (not the leafletProxy
)?
Ah you are right. in producing my reprex I realized that my initial renderLeaflet that has the reactive value in it ALSO sets the view.
Oddly replacing that with %>% mapOptions(zoomToLimits="first")
doesn't produce a map at all.
output$map <- renderLeaflet({
leaflet(options = leafletOptions(minZoom = 12)) %>%
addProviderTiles(theme_mode()$basemap) %>%
#leafem::addMouseCoordinates() %>%
setView(lng = -122.74, lat = 45.59, zoom = 13)
It might not be producing a map (or at least creating it and not zooming anywhere in particular) because there's no lat/long data being added to the map as part of that renderLeaflet
, unless you're just not showing it in your comment.
I've tried the followign but no luck producing the map either:
output$map <- renderLeaflet({
leaflet(options = leafletOptions(minZoom = 12)) %>%
#addProviderTiles(theme_mode()$basemap) %>%
#leafem::addMouseCoordinates() %>%
setView(lng = -122.74, lat = 45.59, zoom = 13)
# %>%
observe({
leafletProxy("map") %>%
clearTiles() %>%
addProviderTiles(theme_mode()$basemap)
})
Can you provide me with the entire app.R so I can run it?
I'll have to finish the reprex as the rest of it is too big and requires confidential data...
library(shiny)
library(shinyWidgets)
library(shinyjs)
library(leaflet)
ui <- fillPage(
leafletOutput("map", width = "100%", height = "100%"),
absolutePanel(id = "filter", class = "mypanel", fixed = TRUE,
draggable = T, top = "auto", left = 20, right = "auto", bottom = 20,
width = 300, height = "auto",
checkboxInput(
inputId = "themeToggle",
label = icon("sun")
))
)
server <- function(input, output, session) {
theme_mode <- reactive({
if(!input$themeToggle) { #light mode
basemap <- providers$CartoDB.Positron
plot_background <- "white"
theme_mode <- list(basemap = basemap, plot_background = plot_background)
}
if(input$themeToggle) { #dark mode
basemap <- providers$CartoDB.DarkMatter
#pal <- invert_colors(light_pal)
#map_pal <- colorFactor(pal, domain = pcb$cluster)
plot_background <- ("black")
theme_mode <- list(basemap = basemap, plot_background = plot_background)
}
return(theme_mode)
})
output$map <- renderLeaflet({
leaflet() %>%
addProviderTiles(theme_mode()$basemap) %>%
addCircleMarkers(lat = 45.610289237285116, lng = -122.78470610571989)
})
}
shinyApp(ui, server)
Your reprex uses renderLeaflet
, not leafletProxy
; the former re-creates the map from scratch whenever it renders, whereas leafletProxy
is used to mutate existing maps. Try replacing your output definition with this:
output$map <- renderLeaflet({
leaflet() %>%
addProviderTiles(isolate(theme_mode()$basemap), layerId = "tiles") %>%
addCircleMarkers(lat = 45.610289237285116, lng = -122.78470610571989)
})
observe({
leafletProxy("map") %>%
addProviderTiles(theme_mode()$basemap, layerId = "tiles")
})
By using the same layerId
in each addProviderTiles
call, it ensures that the existing provider tile layer is removed when the new one is added. Note also the isolate()
call I added to the renderLeaflet
definition; this prevents the output from re-rendering from scratch whenever theme_mode
changes, which would defeat the purpose of the observer I added.
It would be helpful to both be able to set an initial view (either with setView or fitBounds) and to have a user-selected view be retained when new data is rendered. Right now it seems like it's either one or the other. For example, if I don't define an initial view and use mapOptions(zoomToLimits = "first"), the view will initially cover the extent of the data and will retain the user-selected view, as desired. But if I have an explicit call to setView in there to default to a subset of the data's extent, the setView command is referenced on each rendering and there is no way to retain a user-selected view. Maybe this could be addressed by adding an option to setView so that it interacts with zoomToLimits.