Shiny 应用程序可以在不访问服务器的情况下响应控件吗?

Can a Shiny app respond to a control without going to the server?

我正在 htmlwidgets 框架内编写一个 rgl 小部件,以便 rgl 场景可用于 Shiny 应用程序中的输出。事情基本上可以正常工作(尽管它的边缘仍然很粗糙;请参阅 http://R-forge.r-project.org 上的 rglwidget 包),但它的响应速度不如 [=] 中已有的本机 Javascript 控件10=]。 我怀疑问题是到服务器的往返。

有时这将是不可避免的:如果您想对场景进行大的更改,您可能需要在 R 中进行大量计算。但在其他情况下(本机控件涵盖的那些),没有需要R参与,一切都可以在Javascript.

中完成

我不想重复编写 Shiny 输入控件的所有工作,但我想使用它们。所以我的问题是:

有没有办法告诉 Shiny 输入在更改时调用 Javascript 函数,而不是将其值发送到服务器以在 Shiny 输出中使用?

我的问题的答案是 "Yes"!它实际上相当简单,至少如果控件使用 htmlwidgets 框架。

警告:我对 Javascript 不是很有经验,所以这可能不是很好的 Javascript 风格。如果有请告诉我,我会改进的。

思路是这样的:如果我有一个带 inputId = "foo" 的 Shiny sliderInput() 控件,那么我自己的 Javascript 代码可以使用 window["foo"] 获取它,并且可以设置一个"onchange" 事件处理程序就可以了。当该事件处理程序被触发时,我可以读取 "value" 属性,并将其发送到我的控件。

如果我不使用滑块的反应性输入,我就不会延迟到服务器。

这是我当前的小部件 renderValue 函数:

renderValue: function(el, x, instance) {
  var applyVals = function() {

    /* We might be running before the scene exists.  If so, it
       will have to apply our initial value. */

      var scene = window[x.sceneId].rglinstance;
      if (typeof scene !== "undefined") {
        scene.applyControls(x.controls);
        instance.initialized = true;
      } else {
        instance.controls = x.controls;
        instance.initialized = false;
      }
    };

  el.rglcontroller = instance;

  if (x.respondTo !== null) {
    var control = window[x.respondTo];
    if (typeof control !== "undefined") {
      var self = this, i, oldhandler = control.onchange;
      control.onchange = function() {
        for (i=0; i<x.controls.length; i++) {
          x.controls[i].value = control.value;
        }
        if (oldhandler !== null)
          oldhandler.call(this);
        applyVals();
      };
      control.onchange();
    }
  }
  applyVals();
},