Блестящий слайдер ограничивает реакцию на освобождение левой кнопки мыши

Я использую приложение Shiny, в котором может потребоваться некоторое время, чтобы установить ползунок в нужное значение.

Поэтому, пытаясь установить ползунок в правильное значение (и не отпускать левую кнопку мыши!), (то есть мой локальный) сервер наблюдал несколько новых значений и реагировал соответственно.

Поскольку ответ моего сервера на любое новое значение может занять несколько секунд, я был бы рад, если бы мог:

  • отложить передачу сигнала серверу до отпускания левой кнопки мыши или
  • на стороне сервера, отмените любые более ранние ответы, если он получит новое значение

Ответ 1

Хорошо, после некоторого копания, я думаю, что нашел решение. По-видимому, самый чистый способ сделать это, без необходимости связываться с Java script, - это использовать пакет shinyCustom, который имеет функцию useShinyCustom и customSliderInput. С их помощью вы можете установить реактивность на "debounce", а также испортить время задержки. Если бы вы использовали эти параметры вместе, вы должны были бы найти сладкое пятно для обновления только после того, как ползунок перестанет двигаться. Это не будет идеальным "при отпускании кнопки мыши"; но это должно быть довольно чертовски близко!

Например, вы можете попробовать что-то вроде:

# 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)

Ответ 2

Shiny sliderInput использует Ion.RangeSlider, у которого есть обратный вызов onFinish, когда пользователь отпускает свою мышь. Это похоже на то, что нам нужно.

Здесь пользовательская привязка ввода для "ленивого" слайдера, который только сигнализирует о значении, изменяется, когда пользователь отпускает свою мышь (onFinish) или когда ползунок принудительно обновляется (onUpdate).

В качестве примера, я просто ввел код, который изменяет поведение ALL sliderInputs. Вы захотите перенести это на внешний script и настроить далее. Кроме того, onUpdate вызывается, когда ползунок инициализируется, но до того, как Shiny инициализирует входные значения. Вам нужно подождать, пока Shiny сделает это, чтобы вызвать обратный вызов изменения значения в onUpdate. Решение, над которым я работал, не фантастично, но я был слишком ленив, чтобы найти более чистый способ.

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)