2015-03-23 3 views
10

Ich verwende eine Shiny-Anwendung, in der es einige Zeit dauern kann, um einen Schieberegler auf den richtigen Wert zu setzen.Shiny Slider schränkt die Reaktion auf das Loslassen der linken Maustaste ein

Während ich versuchte, den Schieberegler auf den richtigen Wert zu setzen (und nicht meine linke Maustaste loszulassen!), Beobachtete der (d. H. Mein lokaler) Server mehrere neue Werte und reagierte entsprechend.

Als Antwort von meinem Server auf jedem neuen Wert kann einige Sekunden dauern, würde ich mich freuen, wenn ich könnte entweder:

  • verschieben Signalisierung der Server bis zur Freigabe der linken Maustaste oder
  • auf der Serverseite, alle früheren Antworten abbrechen, wenn sie einen neuen Wert erhalten

Antwort

4

In Ordnung, nach ein wenig Graben, ich denke, ich habe die Lösung gefunden. Es scheint der sauberste Weg, dies zu tun, ohne mit Java-Skript zu verwirren wäre, das shinyCustom-Paket zu verwenden, das eine useShinyCustom und customSliderInput-Funktion hat. Mit diesen können Sie die Reaktivität auf "Entprellen" einstellen und auch die Verzögerungszeit durcheinander bringen. Wenn Sie diese Optionen zusammen verwenden, sollten Sie in der Lage sein, den Sweet Spot zu finden, um nur dann die Ausgabe zu aktualisieren, wenn der Schieberegler sich nicht mehr bewegt. Es wird nicht perfekt sein "bei der Freigabe der Maustaste;" aber es sollte verdammt nah sein!

Zum Beispiel können Sie versuchen, so etwas wie:

# Slider delay type is actually "debounce" by default 
useShinyCustom(slider_delay = "500"), # Doubles the default delay time in ms 
customSliderInput("bins", #Use customSliderInput instead of sliderInput 
       "Number of bins:", 
       min = 1, 
       max = 50, 
       value = 30) 
+0

schönes Paket. In der Tat, es ist die Hälfte der Weg zu gehen, um die PB zu lösen ... – agenis

+0

Ja, ich stelle mir vor, wenn der Benutzer interessiert ist, genau das zu bekommen, was sie angefordert haben, könnten sie wahrscheinlich in das Java-Skript durch diesen Code generiert. Aber es ist ein bisschen außerhalb meiner Reichweite, bezüglich der Zeit, um nachzuforschen. – creutzml

+2

Dieses Paket wurde geschrieben, bevor ['debounce'] (https://shiny.rstudio.com/reference/shiny/1.0.4/debounce.html) und' gascross' hinzugefügt wurden. Jetzt ist es einfach, jeden Eingang zu entprellen/zu drosseln - wickeln Sie einfach den Eingangswert in einen reaktiven wie 'debounce (reactive (input $ slider), 500)' –

2

Shiny der sliderInput verwendet Ion.RangeSlider, die für einen onFinish Rückruf hat, wenn ein Benutzer veröffentlicht ihre Maus. Das klingt nach genau dem, was wir brauchen.

Hier ist eine benutzerdefinierte Eingabebindung für einen "faulen" Slider-Eingang, der nur eine Wertänderung signalisiert, wenn ein Benutzer die Maus loslässt (onFinish) oder wenn der Schieber zwangsweise aktualisiert wird (onUpdate).

Für das Beispiel habe ich gerade inline Code, der das Verhalten aller SliderInputs ändert. Sie sollten dies in ein externes Skript verschieben und weiter anpassen. Außerdem wird onUpdate aufgerufen, wenn der Schieberegler initialisiert wird, aber bevor Shiny die Eingabewerte initialisiert. Sie müssen warten, bis Shiny dies tut, um den Wertänderungs-Callback in onUpdate aufzurufen. Die Lösung, in der ich arbeitete, ist nicht fantastisch, aber ich war zu faul, um einen saubereren Weg zu finden.

library(shiny) 

ui <- fluidPage(
    tags$head(
    tags$script(HTML(" 
     (function() { 
     var sliderInputBinding = Shiny.inputBindings.bindingNames['shiny.sliderInput'].binding; 

     var lazySliderInputBinding = $.extend({}, sliderInputBinding, { 
      subscribe: function(el, callback) { 
      var $el = $(el); 
      var slider = $el.data('ionRangeSlider'); 

      var handleChange = function() { 
       if (!inputsInitialized) return; 
       callback(!$el.data('immediate') && !$el.data('animating')); 
      }; 

      slider.update({ 
       onUpdate: handleChange, 
       onFinish: handleChange 
      }); 
      }, 

      unsubscribe: function(el, callback) { 
      var slider = $(el).data('ionRangeSlider'); 
      slider.update({ 
       onUpdate: null, 
       onFinish: null 
      }); 
      } 
     }); 

     Shiny.inputBindings.register(lazySliderInputBinding, 'shiny.lazySliderInput'); 

     var inputsInitialized = false; 
     $(document).one('shiny:connected', function() { 
      inputsInitialized = true; 
     }); 
     })(); 
    ")) 
), 
    sliderInput("sliderA", "A", 0, 10, 5), 
    uiOutput("sliderB"), 
    verbatimTextOutput("sliderValues"), 
    actionButton("resetSliders", "Reset Sliders") 
) 

server <- function(input, output, session) { 
    observeEvent(input$resetSliders, { 
    updateSliderInput(session, "sliderA", value = 5) 
    updateSliderInput(session, "sliderB", value = c(4, 6)) 
    }) 

    output$sliderB <- renderUI({ 
    sliderInput("sliderB", "B", 0, 10, c(4, 6)) 
    }) 

    output$sliderValues <- renderPrint({ 
    cat(paste("Slider A =", input$sliderA), "\n") 
    cat(paste("Slider B =", paste(input$sliderB, collapse = " "))) 
    }) 
} 

shinyApp(ui, server) 
+0

danke, das ist wirklich was ich brauche, ich lege es in einen 'lazy_slider. js 'Datei, wie Sie empfehlen – agenis

Verwandte Themen