2015-09-04 17 views
1

我在htmlwidgets框架中編寫了一個rgl小部件,因此rgl場景可用於在Shiny應用中輸出。事情基本上正在進行(雖然它的邊緣仍然很粗糙;請參閱http://R-forge.r-project.org上的rglwidget包),但它不如已經在rgl中的原生Javascript控件那樣快速響應。 我懷疑問題是往返服務器。一個Shiny應用程序能否響應控件而不必去服務器?

有時候這是不可避免的:如果你想對場景做大的改變,你可能想在R中做很多計算。但是在其他情況下(本地控件覆蓋的那些),沒有必要對於R來說,一切都可以用Javascript完成。

我不想複製已經寫入Shiny輸入控件的所有工作,但我想使用它們。所以我的問題是:

有沒有辦法告訴一個Shiny輸入來調用一個Javascript函數,當它改變了,而不是發送它的值到服務器用於Shiny輸出?

回答

2

我的問題的答案是「是」!它實際上相當簡單,至少如果控件使用htmlwidgets框架。

警告:我對JavaScript不太熟練,所以這可能不是很好的Javascript風格。如果有,請告訴我,我會改進它。

這裏的想法:如果我有一個閃亮的sliderInput()控制與inputId = "foo",然後我自己的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(); 
}, 
相關問題