daattali / shinycssloaders

⌛ Add loading animations to a Shiny output while it's recalculating
https://daattali.com/shiny/shinycssloaders-demo/
Other
395 stars 45 forks source link

Missing spinner when leafletOutput is updated through leafletProxy #17

Closed aoles closed 3 years ago

aoles commented 6 years ago

Hi, the package works great with renderLeaflet, thanks a lot! However, the spinner doesn't show up when updating the map with leafletProxy, as illustrated by the following MWE. Do you have any advice on how to overlay a loader animation over the map while it is being updated by a call to leafletProxy?

Cheers, Andrzej

library(shiny)
library(shinycssloaders)
library(leaflet)

ui <- fluidPage(
  withSpinner(leafletOutput("map")),
  p(),
  actionButton("recalc", "New points")
)

server <- function(input, output, session) {

  points <- eventReactive(input$recalc, {
    Sys.sleep(1)
    cbind(rnorm(40) * 2 + 13, rnorm(40) + 48)
  }, ignoreNULL = FALSE)

  output$map <- renderLeaflet({
    leaflet() %>%  setView(13, 48, 6) %>%
      addProviderTiles(providers$Stamen.TonerLite)
  })

  observe({
    leafletProxy("map") %>%
      clearMarkers() %>%
      addMarkers(data = points())
  })
}

shinyApp(ui, server)
Mikea0228 commented 6 years ago

I also have this exact same issue.

eroten commented 6 years ago

I am also having this issue.

charlie-becker commented 5 years ago

Also seeking a solution.

elhohn commented 5 years ago

Same.

richardtc commented 5 years ago

Also interested.

J-O-H-N-P-A-U-L commented 5 years ago

also interested

ktsperry commented 5 years ago

I am also interested.

eroten commented 5 years ago

Has anyone come up with a workaround?

kimberlycl commented 5 years ago

I used the shinyWidgets package in my shiny app. For this example I added the line shinyjs::useShinyjs() in the ui as well as a fluidRow to add a div that loads a spinner (you probably want to change the layout so it appears over the map but I'm not sure how to do that). Then I added the line shinyjs::showElement(id = 'loading') inside the observe function and before the leafletProxy call, and shinyjs::hideElement(id = 'loading') after the leafletProxy call at the end of the observe function. The spinner now shows up while the map is loading. Hope this helps!

`library(shiny) library(shinycssloaders) library(leaflet) library(shinyWidgets)

ui <- fluidPage( shinyjs::useShinyjs(), leafletOutput("map"), p(), actionButton("recalc", "New points"), p(), fluidRow(column(3, shinyjs::hidden(div(id = 'loading', addSpinner(div(), spin = "circle", color = "blue"))) )) )

server <- function(input, output, session) {

points <- eventReactive(input$recalc, { Sys.sleep(1) cbind(rnorm(40) * 2 + 13, rnorm(40) + 48) }, ignoreNULL = FALSE)

output$map <- renderLeaflet({ leaflet() %>% setView(13, 48, 6) %>% addProviderTiles(providers$Stamen.TonerLite) })

observe({ shinyjs::showElement(id = 'loading')

leafletProxy("map") %>%
  clearMarkers() %>%
  addMarkers(data = points())

shinyjs::hideElement(id = 'loading')

}) }

shinyApp(ui, server)`

ngfrey commented 4 years ago

The solution above is great, except it doesn't work for larger shape renderings. For example, a map of US county polygons with some aesthetic mappings will not be rendered on the screen before the spinner is removed. If anyone has a workaround, it would be wonderful to see how to work around this problem.

daattali commented 4 years ago

When I tried running the example given, I wasn't even getting a loader to show up initially on the map. It looks like any output with the name "map" was not working https://github.com/daattali/shinycssloaders/issues/49. This is now fixed

The other issue here is not seeing the loader when using the leaflet proxy. Without looking into this, I'm pretty sure it's happening because the actual plot object isn't getting recalculated. Any widget that uses a proxy to update it (leaflet, plotly, whatever else supports updating without a complete re-render) doesn't trigger a redraw from shiny, so shinycssloaders doesn't think it's recalculating.

I don't know enough and haven't looked into how the leafetlet proxy works, but unless there's a signal that shiny knows the specific map is being re-plotted, I don't think this will be solved with shinycssloaders.

daattali commented 3 years ago

Unfortunately I believe this is not an issue that can be solved with shinycssloaders. The problem is that shiny itself isn't sending a message saying that the plot is recalculating. There are specific javascript events that shiny usually fires when an output recalculates, namely outputinvalidated, but it's not getting fired when an output is modified via a proxy. If shiny is ever able to catach these proxy events and fire them, then shinycssloaders will automatically work. Until then, the work around is to manually show and hide a spinner, for example usiny shinyjs