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)
debounce()
: stackoverflow.com/questions/32235525 – Cosmic