Shiny slider restrict reaction to releasing left mouse button

前端 未结 2 1866
旧巷少年郎
旧巷少年郎 2021-02-04 06:05

I am using a Shiny application in which it may take some time to set a slider to the right value.

So while trying to set the slider to the right value (and not releasing

相关标签:
2条回答
  • 2021-02-04 06:47

    Shiny's sliderInput uses Ion.RangeSlider, which has an onFinish callback for when a user releases their mouse. That sounds like just what we need.

    Here's a custom input binding for a "lazy" slider input that only signals a value change when a user releases their mouse (onFinish) or when the slider is forcibly updated (onUpdate).

    For the example, I just inlined code that changes the behavior of ALL sliderInputs. You'll want to move this to an external script and customize further. Also, onUpdate gets called when the slider is initialized, but before Shiny initializes input values. You have to wait until Shiny does this to call the value change callback in onUpdate. The solution I worked in isn't fantastic, but I was too lazy to find a cleaner way.

    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 讨论(0)
  • 2021-02-04 06:48

    Alright, after some digging, I think I've found the solution. It appears the cleanest way to do this, without needing to mess with Java script, would be to use the shinyCustom package, which has a useShinyCustom and customSliderInput function. With these, you can set the reactivity to "debounce" and also mess with the delay time. If you were to use these options together, you should be able to find the sweet spot for only updating the output once the slider stops moving. It won't be a perfect "on release of mouse button;" but it should be pretty darn close!

    For example, you may try something like:

    # 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 讨论(0)
提交回复
热议问题