Search code examples
rshinyr-leaflet

Only render leaflet map when zoom passes a threshold


I have built a leaflet map in a Shiny application that shows different layers depending on what zoom you have.

I have built this combining leafletProxy with observeEvent and leaflet's input$MAPID_zoom.

server <- shinyServer(function(input, output, session) {
  
  output$map <- renderLeaflet({
    leaflet() |> 
      addTiles() |> 
      mapOptions(zoomToLimits="first") |> 
      setView(lat = 47.218637, lng = -1.554136, zoom = 7)
  })
  
  observeEvent(
    eventExpr = input$map_zoom, {
      map_proxy <- leafletProxy(mapId = "map", session = session)
      
        if(input$map_zoom < 8){
          map_proxy |> 
            clearMarkers() |> 
        addMarkers(
          data = df, lng = ~lng, lat = ~lat
        )
        } else {
          map_proxy |> 
            clearMarkers() |> 
          addMarkers(
            data = df_2, lng = ~lng, lat = ~lat
          )
        }
      
    }
  )
})

However, this rerenders the leaflet map every time the zoom changes. I would like the map to only render when the threshold in the if-statement is surpassed. What would be a way to approach this?

Code for UI and data:

library(shiny)
library(leaflet)

df <- data.frame(
  location_name = c('S1', 'S2'),
  lng = c(-1.554136,  -2.10401),
  lat = c(47.218637, 47.218637), 
  stringsAsFactors = FALSE
)

df_2 <- data.frame(
  location_name = c('S3', 'S4'),
  lng = c(-1.654136,  -2.2401),
  lat = c(47.218637, 47.218637), 
  stringsAsFactors = FALSE
)

ui <- shinyUI(
  fluidPage(
    leafletOutput(outputId = 'map')
  )
)


Solution

  • I can't reproduce your problem but here is a solution. You have to create both layers and play with visibility.

    server <- shinyServer(function(input, output, session) {
      
      output$map <- renderLeaflet({
        leaflet() |> 
          addTiles() |> 
          mapOptions(zoomToLimits="first") |> 
          setView(lat = 47.218637, lng = -1.554136, zoom = 7) |>
          addMarkers(
            data = df, lng = ~lng, lat = ~lat, group = "S1S2"
          ) |> 
          addMarkers(
            data = df_2, lng = ~lng, lat = ~lat, group="S3S4")
      })
      
      observeEvent(
        eventExpr = input$map_zoom, {
          map_proxy <- leafletProxy(mapId = "map", session = session)
          
          if(input$map_zoom < 8){
            map_proxy |> 
              showGroup("S1S2") |>
              hideGroup("S3S4")
          } else {
            map_proxy |> 
              showGroup("S3S4") |>
              hideGroup("S1S2")
          }
          
        }
      )
    })
    

    Here each layer gets a different group id and depending of the zoom level we hide or show corresponding group.