D3.js树通过node.name点击R Shiny

我想先解决我的意图

1)在Shiny中创build一个预定义的D3.js可折叠树

2)点击一个节点,这个特定节点的名字从D3.js传递到R进一步的操作。

那么在这个时候,我在Shiny中有一个预定义的D3.js可折叠树。 我为下面的js,server.R和ui.R提供了代码。 现在,我只是有一个互动的graphics,但我想更进一步。

只要我点击一个节点,我想获得节点的名称作为一个variables。

我做了我的研究(主要在这里: https : //github.com/metrumresearchgroup/SearchTree ),所以我知道,我必须使用d3OutputBinding创build一个新的variables。 我进一步发现了这一点

.on('click', function(node) { alert(node.name); 

至less会popup一个带有节点名称的消息。 所以我认为,我必须使用类似的东西

 var d3OutputBinding = new Shiny.OutputBinding(); $.extend(d3OutputBinding, { find: function(scope) { return $(scope).find('.div_tree2'); }, renderValue: function(el) { var svg = d3.select(el).select("svg"); ... function update(source) { ... nodeEnter = node.enter().append("g") .on('click', function(node) {var nodes1 = node.name; }); ... Shiny.onInputChange(".nodesData", JSON.decycle(nodes1)); ... } // end of renderValue }); // end of .extend 

并通过反应函数(input$ .nodesData)将其插入到server.R中。

不幸的是,我实在太笨了。 所以我恳请你提供任何build议。

如前所述,我会提供我的代码。 这里是我的d3script_tree.js

  Shiny.addCustomMessageHandler("jsondata_tree", function(message){ var treeData = [ { "name": "Parent", "parent": "null", "children": [ { "name": "A", "parent": "Parent" }, { "name": "B", "parent": "Parent" } ] } ]; // ************** Generate the tree diagram ***************** var margin = {top: 20, right: 120, bottom: 20, left: 120}, width = 960 - margin.right - margin.left, height = 250 - margin.top - margin.bottom; var i = 0, duration = 750, root; var tree = d3.layout.tree() .size([height, width]); var diagonal = d3.svg.diagonal() .projection(function(d) { return [dy, dx]; }); var svg = d3.select("#div_tree2").append("svg") .attr("width", width + margin.right + margin.left) .attr("height", height + margin.top + margin.bottom) .append("g") .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); root = treeData[0]; root.x0 = height / 2; root.y0 = 0; update(root); d3.select(self.frameElement).style("height", "500px"); function update(source) { // Compute the new tree layout. var nodes = tree.nodes(root).reverse(), links = tree.links(nodes); // Normalize for fixed-depth. nodes.forEach(function(d) { dy = d.depth * 180; }); // Update the nodes… /* var node = svg.selectAll("g.node") .data(nodes, function(d) { return d.id || (d.id = ++i); }) */ var node = svg.selectAll("g.node") .data(nodes, function(d) { return d.id || (d.id = ++i); }) // Enter any new nodes at the parent's previous position. var nodeEnter = node.enter().append("g") .attr("class", "node") .attr("transform", function(d) { return "translate(" + source.y0 + "," + source.x0 + ")"; }) //.on("click", click); .on('click', function(node) { alert(node.name); }); nodeEnter.append("circle") .attr("r", 1e-6) .style("fill", function (d) { return '#05415A'; }) //.style("fill", function(d) { return d._children ? "#C00000" : "#fff"; }); nodeEnter.append("link") .style("stroke-width", "3px"); nodeEnter.append("text") .attr("x", function(d) { return d.children || d._children ? -13 : 13; }) .attr("dy", ".35em") .attr("text-anchor", function(d) { return d.children || d._children ? "end" : "start"; }) .text(function(d) { return d.name; }) .style("fill-opacity", 1e-6); // Transition nodes to their new position. var nodeUpdate = node.transition() .duration(duration) .attr("transform", function(d) { return "translate(" + dy + "," + dx + ")"; }); nodeUpdate.select("circle") .attr("r", 10) .style("fill", function (d) { return '#05415A'; }) // .style("fill", function(d) { return d._children ? "#C00000" : "#fff"; }); nodeUpdate.select("text") .style("fill-opacity", 1); nodeUpdate.select("link") .style("stroke-width", "3px"); // Transition exiting nodes to the parent's new position. var nodeExit = node.exit().transition() .duration(duration) .attr("transform", function(d) { return "translate(" + source.y + "," + source.x + ")"; }) .remove(); nodeExit.select("circle") .attr("r", 1e-6); nodeExit.select("text") .style("fill-opacity", 1e-6); // Update the links… var link = svg.selectAll("path.link") .data(links, function(d) { return d.target.id; }); // Enter any new links at the parent's previous position. link.enter().insert("path", "g") .attr("class", "link") .attr("d", function(d) { var o = {x: source.x0, y: source.y0}; return diagonal({source: o, target: o}); }); // Transition links to their new position. link.transition() .duration(duration) .attr("d", diagonal); // Transition exiting nodes to the parent's new position. link.exit().transition() .duration(duration) .attr("d", function(d) { var o = {x: source.x, y: source.y}; return diagonal({source: o, target: o}); }) .remove(); // Stash the old positions for transition. nodes.forEach(function(d) { d.x0 = dx; d.y0 = dy; }); } // Toggle children on click. function click(d) { if (d.children) { d._children = d.children; d.children = null; } else { d.children = d._children; d._children = null; } update(d); } }); 

接下来我有ui.R引用它。 CSS样式并不重要,所以可以忽略。

 library(shinydashboard) library(shinyjs) sidebar <- dashboardSidebar( sidebarMenu( menuItem("Toy example", tabName = "toy", icon = icon("cog")) ) ) body <- dashboardBody( tags$head( tags$link(rel = "stylesheet", type = "text/css", href = "custom.css") ), tabItems( tabItem(tabName = "toy", tags$div(class="d3-div", #to style to d3 output pull in css tags$head(tags$link(rel = "stylesheet", type = "text/css", href = "style.css")), #load D3JS library tags$script(src="d3.min.js"), #tags$script(src="https://d3js.org/d3.v3.min.js"), #load javascript tags$script(src="d3script_tree.js"), #create div referring to div in the d3script tags$div(id="div_tree2")) ) ) ) # Put them together into a dashboardPage dashboardPage( dashboardHeader(title = "Toy Example"), sidebar, body ) 

最后,有server.R来触发这个Java脚本。

 library(shiny) library(shinyjs) shinyServer(function(input, output, session) { options(shiny.maxRequestSize=30*1024^2, shiny.usecairo=T) var_json_tree <- toJSON(1, pretty = T) #push data into d3script session$sendCustomMessage(type="jsondata_tree",var_json_tree) }) 

我不认为你需要Shiny.OutputBinding(); 部分为此,您可以使用Shiny.onInputChange传递节点名称回到server.R

我没有运行你的整个代码,但你可以尝试:

 .on('click', function(node) { Shiny.onInputChange("node_name", node.name); } 

server.Rinput$node_name将保存节点的名称。

编辑

要保留折叠树,只需在javascript的末尾编辑clickfunction即可:

 function click(d) { Shiny.onInputChange("node_name", d.name); if (d.children) { d._children = d.children; d.children = null; } else { d.children = d._children; d._children = null; } update(d); } });