簡體   English   中英

閃亮的自定義輸出未渲染

[英]Shiny Custom Output not Rendering

我正在嘗試將D3.js的網絡可視化綁定到Shiny中的自定義輸出。 由於某種原因,似乎我的渲染函數沒有被調用。 這是我的代碼:

rbindings.js

var forceNetworkOB = new Shiny.OutputBinding();

forceNetworkOB.find = function(scope) {
  return $(scope).find("svg.rio-force-network");
};

forceNetworkOB.renderValue = function(el, graph) {

  alert('rendering')

  //actual rendering code here...

};

Shiny.outputBindings.register(forceNetworkOB, "jumpy.forceNetworkOB");

CustomIO.R

renderForceNetwork <- function(expr, env=parent.frame(), quoted=FALSE) {

  func <- exprToFunction(expr, env, quoted)

  function() {

    # Never called
    browser()

    graph <- func()

    list(nodes = graph$nodes,
         links = graph$edges
    )
  }
}

forceNetwork <- function(id, width = '400px', height = '400px') {

  tag('svg', list(id = id, class = 'rio-force-network', width = width, height = height))

}

ui.R

library(shiny)
source('customIO.R')

shinyUI(fluidPage(

  tags$script(src = 'js/d3.min.js'),
  tags$script(src = 'js/rbindings.js'),

  titlePanel('Network Visualization'),

  tabsetPanel(
    tabPanel('D3.js Force Layout',
      forceNetwork('vis.force', width = '800px', height = '800px'),
    )
  )

))

和server.R

library(shiny)

source('cytoscape.R')
source('customIO.R')

shinyServer(function(session, input, output) {


  # Load the network
  network <- networkFromCytoscape('network.cyjs')

  output$vis.force <- renderForceNetwork({

    # Never called
    print('rendering')
    browser()

    list(
      nodes = data.frame(name = network$nodes.data$Label_for_display, group = rep(1, nrow(network$nodes.data))),
      edges = data.frame(from = network$edges[,1], to = network$edges[,2])
    )

  })

})

從注釋中可以看出,我的R渲染函數中的browser()行以及js渲染函數中的alert()都從未被調用。 通過一些js調試,我可以看到我的自定義綁定正確地將svg元素及其ID給出了。 這可能很簡單,但我無法弄清楚。

好吧,盡管代碼看起來很合法,但您確實必須深入研究Shiny的源代碼才能找到罪魁禍首。

當Shiny初始化時,它將調用initShiny() ,然后再調用bindOutputs 現在,這是bindOutputs函數的樣子:

function bindOutputs(scope) {

  if (scope === undefined)
    scope = document;

  scope = $(scope);

  var bindings = outputBindings.getBindings();

  for (var i = 0; i < bindings.length; i++) {
    var binding = bindings[i].binding;
    var matches = binding.find(scope) || [];
    for (var j = 0; j < matches.length; j++) {
      var el = matches[j];
      var id = binding.getId(el);

      // Check if ID is falsy
      if (!id)
        continue;

      var bindingAdapter = new OutputBindingAdapter(el, binding);
      shinyapp.bindOutput(id, bindingAdapter);
      $(el).data('shiny-output-binding', bindingAdapter);
      $(el).addClass('shiny-bound-output'); // <- oops!
    }
  }

  // Send later in case DOM layout isn't final yet.
  setTimeout(sendImageSize, 0);
  setTimeout(sendOutputHiddenState, 0);
}

我用<- oops標記的行是導致所有問題的原因。 這實際上並不是Shiny 本身的錯誤:此行代碼依靠jQueryel添加一個類,這是您使用forceNetwork()函數創建的svg DOM元素。

shiny-bound-output類對於實際的綁定工作很重要。

問題是$.addClass<svg>不起作用。 要獲得良好的參考, 請參閱本文有關stackoverflow的問題

因此,結果,您的<svg>元素缺少必需的OutputBinding shiny-bound-output類,該類會使您的自定義OutputBinding正常運行。


解:

不要將<svg>用作輸出的容器 使用<div>代替。 這意味着,您應該將forceNetwork函數更改為:

forceNetwork <- function(id, width = '400px', height = '400px') {    
  tag('div', list(id = id, class = 'rio-force-network', width = width, height = height))
}

您可以使用d3.select(...).append('svg')輕松添加<svg>並在那里設置寬度和高度。

(還記得在rbindings.js修改您的find()函數)。


最后的話

如果您以某種方式將d3.select(...).append('svg')到您的JavaScript代碼中,請記住在實際d3繪圖之前clear()輸出綁定的renderValue()函數中的<div>容器。 否則,每次調用renderForceNetwork ,它將向您的<div>容器添加一個新的<svg>元素。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM