d3.js如何动态地向树中添加节点
d3.js如何动态地向树中添加节点
我正在使用d3.js的树状图,并希望动态地添加节点,而不是预先加载整个树。
当节点被点击时,我想要修改以下内容以动态添加额外的JSON节点。 (参见下面的链接和代码)
http://mbostock.github.com/d3/talk/20111018/tree.html
所以,与其预先加载整个树,我宁愿在单击父节点时只获取子节点。我可以在toggle函数中获取子节点的JSON,但是我无法弄清楚如何将它们添加到树中。
var m = [20, 120, 20, 120], w = 1280 - m[1] - m[3], h = 800 - m[0] - m[2], i = 0, root; var tree = d3.layout.tree() .size([h, w]); var diagonal = d3.svg.diagonal() .projection(function(d) { return [d.y, d.x]; }); var vis = d3.select("#body").append("svg:svg") .attr("width", w + m[1] + m[3]) .attr("height", h + m[0] + m[2]) .append("svg:g") .attr("transform", "translate(" + m[3] + "," + m[0] + ")"); d3.json("flare.json", function(json) { root = json; root.x0 = h / 2; root.y0 = 0; function toggleAll(d) { if (d.children) { d.children.forEach(toggleAll); toggle(d); } } // 初始化显示一些节点。 root.children.forEach(toggleAll); toggle(root.children[1]); toggle(root.children[1].children[2]); toggle(root.children[9]); toggle(root.children[9].children[0]); update(root); }); function update(source) { var duration = d3.event && d3.event.altKey ? 5000 : 500; // 计算新的树布局。 var nodes = tree.nodes(root).reverse(); // 标准化固定深度。 nodes.forEach(function(d) { d.y = d.depth * 180; }); // 更新节点... var node = vis.selectAll("g.node") .data(nodes, function(d) { return d.id || (d.id = ++i); }); // 在父节点的之前位置插入任何新节点。 var nodeEnter = node.enter().append("svg:g") .attr("class", "node") .attr("transform", function(d) { return "translate(" + source.y0 + "," + source.x0 + ")"; }) .on("click", function(d) { toggle(d); update(d); }); nodeEnter.append("svg:circle") .attr("r", 1e-6) .style("fill", function(d) { return d._children ? "lightsteelblue" : "#fff"; }); nodeEnter.append("svg:text") .attr("x", function(d) { return d.children || d._children ? -10 : 10; }) .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); // 过渡节点到新位置。 var nodeUpdate = node.transition() .duration(duration) .attr("transform", function(d) { return "translate(" + d.y + "," + d.x + ")"; }); nodeUpdate.select("circle") .attr("r", 4.5) .style("fill", function(d) { return d._children ? "lightsteelblue" : "#fff"; }); nodeUpdate.select("text") .style("fill-opacity", 1); // 过渡退出的节点到父节点的新位置。 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); // 更新链接... var link = vis.selectAll("path.link") .data(tree.links(nodes), function(d) { return d.target.id; }); // 在父节点的之前位置插入任何新链接。 link.enter().insert("svg:path", "g") .attr("class", "link") .attr("d", function(d) { var o = {x: source.x0, y: source.y0}; return diagonal({source: o, target: o}); }) .transition() .duration(duration) .attr("d", diagonal); // 过渡链接到新位置。 link.transition() .duration(duration) .attr("d", diagonal); // 过渡退出的节点到父节点的新位置。 link.exit().transition() .duration(duration) .attr("d", function(d) { var o = {x: source.x, y: source.y}; return diagonal({source: o, target: o}); }) .remove(); // 保存旧位置以进行过渡。 nodes.forEach(function(d) { d.x0 = d.x; d.y0 = d.y; }); } // 切换子节点。 function toggle(d) { // 我可以在这里获取子节点,但是如何将它们添加到树中呢? if (d.children) { d._children = d.children; d.children = null; } else { d.children = d._children; d._children = null; } }