rshinyr-leaflet

Leaflet map in R Shiny shows white screen temporarily (on country click or first load)


Problem: I'm building an interactive R Shiny app that uses leaflet to show a world map with country polygons and raster overlays (.tif) for each. Users can switch between the "World" view (aggregated polygons) and individual countries (raster data) by clicking on the leaflet. Issue:

When clicking on a country or switching back to "World", the map becomes blank/white. The same issue happens on the first load of the app: the map is white for a second before rendering the polygons and tiles.

After selecting a country map, a spinner appears:

then the map becomes completely white, without any visible raster and polygon:

The raster finally appears after a delay, showing correct data for the selected country:

What I already tried:

Code snippet from renderLeaflet():

output$map <- renderLeaflet({
  leaflet(options = leafletOptions(minZoom = 1.8)) %>%
    addProviderTiles("OpenStreetMap", group = "OpenStreetMap") %>%
    addProviderTiles("Esri.WorldImagery", group = "Satellite") %>%
    addLayersControl(
      baseGroups = c("OpenStreetMap", "Satellite"),
      position = "topright"
    ) %>%
    onRender("
      function(el, x) {
        this.on('tileload', function() {
          Shiny.setInputValue('raster_rendered', Math.random());
        });
      }
    ")
})

Solution

  • The one-second “white flash” (or a totally blank map while switching between World → Country → World) happens because the browser is still rendering the new polygon/raster layer while the old layer has already been cleared.

    Nothing is “wrong” with the TIFFs or with leafletProxy()—it is just a race condition between

    1. the server telling Leaflet to add a new layer, and

    2. the client repainting that layer and the base tiles.

    output$map <- renderLeaflet({
      leaflet(options = leafletOptions(minZoom = 1.8)) %>%
        addProviderTiles("OpenStreetMap", group = "OpenStreetMap") %>%
        addProviderTiles("Esri.WorldImagery", group = "Satellite") %>%
        addLayersControl(
          baseGroups = c("OpenStreetMap", "Satellite"),
          position = "topright"
        ) %>%
     onRender(
            "
            var map = this;
            var fired = false;
    
            // fires for every layer that is added later via leafletProxy()
            map.on('layeradd', function(e) {
              if (!fired && e.layer.options && e.layer.options.group === 'polygons') {
                fired = true;
                Shiny.setInputValue('raster_rendered', Math.random());
             }
              
             fired = false;
            });
            }
          "
          )
    })
    
    
      observeEvent(input$raster_rendered, {
        remove_modal_spinner()
      })
    

    Why this works