闪亮的自定义输出不渲染 [英] Shiny Custom Output not Rendering
问题描述
我试图将来自D3.js的网络可视化绑定到Shiny中的自定义输出。由于某些原因,似乎我的渲染函数没有被调用。这是我的代码:
I'm trying to bind a network visualization from D3.js to a custom output in Shiny. For some reason, it seems like my rendering functions are not being called. Here is my code:
rbindings.js
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
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渲染函数中的行不会被调用,以及js渲染函数中的alert()。有了一些js调试,我可以看到我的自定义绑定正确地给svg元素渲染以及其id。这可能是简单的,但我不能弄清楚。
As you can see from the comments, the browser() lines in my R rendering functions are never called, as well as the alert() in the js rendering function. With some js debugging I can see that my custom binding is correctly giving the svg element to render to as well as its id. This might be something simple but I cannot figure it out.
推荐答案
当Shiny初始化时,它调用 initShiny()
然后调用 bindOutputs
。
现在,这里是 bindOutputs
函数看起来像:
When Shiny initializes, it calls initShiny()
, which then calls bindOutputs
.
Now, here is what the bindOutputs
function looks like:
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);
}
标记为的行
是什么原因导致所有的问题。
这真的不是Shiny 本身的错误:这行代码依靠 jQuery
添加一个类到 el
,它是使用 forceNetwork()$创建的
svg
c $ c>函数。
The line I marked with <- oops
is what causes all the problem.
This really isn't a bug of Shiny per se: this line of code relies on jQuery
to add a class to el
, which is the svg
DOM element that you've created with forceNetwork()
function.
类 shiny-bound-output
/ em>绑定到工作。
The class shiny-bound-output
is important for the actual binding to work.
问题是 $。addClass
< svg>
。
为了方便参考,请参阅这篇文章或这个问题在stackoverflow 。
因此,因此,您的< svg>
元素缺少必需的 -bound-output
类,这将使您的自定义 OutputBinding
正确运行。
So, as a result, your <svg>
element lacks the required shiny-bound-output
class that would make your custom OutputBinding
to function correctly.
不要使用< svg>
作为您的输出的容器。请改用< div>
。
这意味着,您应该将 forceNetwork
函数更改为:
Don't use <svg>
as the container of your output. Use a <div>
instead.
It means, you should change your forceNetwork
function to:
forceNetwork <- function(id, width = '400px', height = '400px') {
tag('div', list(id = id, class = 'rio-force-network', width = width, height = height))
}
$ c>< svg> 使用 d3.select(...)。append('svg')
You can easily append a <svg>
using d3.select(...).append('svg')
and set the width and height there.
(请记住修改中的
find()
函数 rbindings.js
以及)。
(Remember to modify your find()
function in rbindings.js
as well).
如果您以某种方式向您的JavaScript代码添加 d3.select(...)。append('svg')
,请记住 )
中的< div>
实际d3绘图。否则每次 renderForceNetwork
被调用时,它将为您的添加一个新的
容器。< svg>
>< div>
If you somehow add d3.select(...).append('svg')
to your javascript code, remember to clear()
the <div>
container in the output binding's renderValue()
function before the actual d3 drawing. Otherwise every time renderForceNetwork
is called, it will add a new <svg>
element to your <div>
container.
这篇关于闪亮的自定义输出不渲染的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!