我正在htmlwidgets框架内编写一个rgl
小部件,以便{1}}场景可以用于Shiny应用程序中的输出。事情基本上是有效的(虽然它仍然很粗糙;请参阅http://R-forge.r-project.org上的rgl
包),但它不像rglwidget
中已有的原生Javascript控件那样响应。
我怀疑问题是到服务器的往返。
有时候这是不可避免的:如果你想对一个场景进行大的改动,你可能想在R中做很多计算。但在其他情况下(原生控件覆盖的那些),没有必要R参与其中,一切都可以在Javascript中完成。
我不想复制编写Shiny输入控件的所有工作,但我想使用它们。所以我的问题是:
有没有办法告诉Shiny输入在更改时调用Javascript函数,而不是将其值发送到要在Shiny输出中使用的服务器?
答案 0 :(得分:2)
我的问题的答案是"是"!它实际上相当简单,至少如果控件使用htmlwidgets
框架。
警告:我在Javascript方面不是很有经验,所以这可能不是很好的Javascript风格。如果是的话请告诉我,我会改进它。
以下是这样的想法:如果我有一个带有sliderInput()
的闪亮inputId = "foo"
控件,那么我自己的Javascript代码可以使用window["foo"]
来获取它,并且可以设置一个&# 34;平变化"它上面的事件处理程序当触发该事件处理程序时,我可以读取"值"属性,并将其发送到我的控件。
如果我不使用滑块的无功输入,我就不会因为去服务器而感到延迟。
这是我当前为小部件设计的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();
},