rstudio / leaflet

R Interface to Leaflet Maps
http://rstudio.github.io/leaflet/
Other
805 stars 508 forks source link

Set initial view and retain zoom settings with new data #54

Open brendanhoganvt opened 9 years ago

brendanhoganvt commented 9 years ago

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.

chokn commented 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.

jzadra commented 2 years ago

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?

jcheng5 commented 2 years ago

@jzadra Do you have a reproducible example for this? I’m a little surprised this happens.

jcheng5 commented 2 years ago

Maybe if you call %>% mapOptions(zoomToLimits="first") on the initial leaflet object (not the leafletProxy)?

jzadra commented 2 years ago

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)
jcheng5 commented 2 years ago

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.

jzadra commented 2 years ago

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)
    })
jcheng5 commented 2 years ago

Can you provide me with the entire app.R so I can run it?

jzadra commented 2 years ago

I'll have to finish the reprex as the rest of it is too big and requires confidential data...

jzadra commented 2 years ago
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)
jcheng5 commented 2 years ago

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.