Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Shiny Loading Spinner displaying too frequently

I have a loading spinner in shiny which is implemented similarly to this answer:

conditionalPanel(condition="$('html').hasClass('shiny-busy')",
                 tags$div("Loading...",id="loadmessage")
)



runApp(list(
  ui = pageWithSidebar(
      headerPanel("Test"),
         sidebarPanel(
           tags$head(tags$style(type="text/css", "
             #loadmessage {
               position: fixed;
               top: 0px;
               left: 0px;
               width: 100%;
               padding: 5px 0px 5px 0px;
               text-align: center;
               font-weight: bold;
               font-size: 100%;
               color: #000000;
               background-color: #CCFF66;
               z-index: 105;
             }
          ")),
           numericInput('n', 'Number of obs', 100),
           conditionalPanel(condition="$('html').hasClass('shiny-busy')",
                            tags$div("Loading...",id="loadmessage"))
         ),
         mainPanel(plotOutput('plot'))
  ),
  server = function(input, output) {
    output$plot <- renderPlot({ Sys.sleep(2); hist(runif(input$n)) })
  }
))

The issue I'm having is that the loader comes up all the time, even when shiny is busy for just a fraction of a second. This leads to the app blinking in and out all the time. Is there a way to basically set a delay on the conditional panel so that the spinner only comes up after the page is busy for a second?

like image 932
Shorpy Avatar asked Feb 08 '23 17:02

Shorpy


1 Answers

If I understood you right, the task is to show specific class and "busy" message after certain delay of "busyness". The spinner has to be shown only for significant busy times (maybe longer than a second).

This could be easily achieved with debounce concept. It has implementation in many libraries, here's the lodash debounce implementation, for example.

I will not provide the code snippets, it's up to how to integrate in your code, but will provide the pseudo code, so you understand how to use it:

// flag of busyness
var isBusy = false;

// ...
// operation in progress, start the counting
isBusy = true;
_.debounce(showSpinner, 1000, {
   'trailing': true             // we need to trigger only when 1 seconds interval passed from last iteration
}));

// ... when done
hideSpinner();

// will be debounced after 1 second interval, and if still busy - the spinner will be shown
var showSpinner = function() {
    if (isBusy) {
        $('selector').addClass('shiny-busy');
    }
}

var hideSpinner = function() {
   isBusy = false;        // our external variable is used
   if ($('selector').hasClass('shiny-busy')) {
       $('selector').removeClass('shiny-busy');
   }
}

The pseudo-code is just to illustrate the concept, but hopefully it will explain you how to use it.

like image 186
Farside Avatar answered Feb 10 '23 23:02

Farside