可折叠力导向图上的D3.js标题

所以我一直在研究基于以下示例的可折叠力导向图。

我试图从那里前进,并为每个节点添加标题。 我在stackoverflow上遵循了类似的答案 ,但是我无法将该答案的解决方案实现到上面的示例和其他类似的解决方案中。

请有人指出我正确的方向。

实施前请参阅下面的项目代码。

在此处输入图像描述

JS

var w = 600, h = 600, radius = 10, node, link, root; var force = d3.layout.force() .on("tick", tick) .charge(function(d) { return -500; }) .linkDistance(function(d) { return d.target._children ? 100 : 50; }) .size([w, h - 160]); var svg = d3.select("body").append("svg") .attr("width", w) .attr("height", h); root = words[0]; //set root node root.fixed = true; root.x = w / 2; root.y = h / 2 - 80; update(); function update() { var nodes = flatten(root), links = d3.layout.tree().links(nodes); // Restart the force layout. force .nodes(nodes) .links(links) .start(); // Update the links… link = svg.selectAll(".link") .data(links); // Enter any new links. link.enter().insert("svg:line", ".node") .attr("class", "link") .attr("x1", function(d) { return d.source.x; }) .attr("y1", function(d) { return d.source.y; }) .attr("x2", function(d) { return d.target.x; }) .attr("y2", function(d) { return d.target.y; }); // Exit any old links. link.exit().remove(); // Update the nodes… node = svg.selectAll("circle.node") .data(nodes) .style("fill", color); node.transition() .attr("r", radius); node.append("title") .text(function(d) { return d.name; }); // Enter any new nodes. node.enter().append("svg:circle") .attr("class", "node") .attr("cx", function(d) { return dx; }) .attr("cy", function(d) { return dy; }) .attr("r", radius) .style("fill", color) .on("click", click) .call(force.drag); // Exit any old nodes. node.exit().remove(); } function tick() { link.attr("x1", function(d) { return d.source.x; }) .attr("y1", function(d) { return d.source.y; }) .attr("x2", function(d) { return d.target.x; }) .attr("y2", function(d) { return d.target.y; }); node.attr("cx", function(d) { return dx; }) .attr("cy", function(d) { return dy; }); } // Color leaf nodes orange, and packages white or blue. function color(d) { if(d._children){ return "#95a5a6"; }else{ switch(d.group) { case 'r': //adverb return "#e74c3c"; break; case 'n': //noun return "#3498db"; break; case 'v': //verb return "#2ecc71"; break; case 's': //adjective return "#e78229"; break; default: return "#9b59b6"; } } } // 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(); } // Returns a list of all nodes under the root. function flatten(root) { var nodes = [], i = 0; function recurse(node) { if (node.children) node.size = node.children.reduce(function(p, v) { return p + recurse(v); }, 0); if (!node.id) node.id = ++i; nodes.push(node); return node.size; } root.size = recurse(root); return nodes; } 

CSS

 circle.node { cursor: pointer; stroke: #34495e; stroke-width: 2px; box-sizing: border-box; stroke-location: inside; } line.link { fill: none; stroke: #34495e; stroke-width: 1.5px; } 

HTML

     var words = [ { "group":"n", "word":"main node", "children":[ { "group":"n", "name":"sub node 1" }, { "group":"n", "name":"sub node 2" }, { "group":"n", "name":"sub node 3" }, { "group":"v", "name":"sub node 4" }, { "group":"s", "name":"sub node 5" }, { "group":"s", "name":"sub node 6" }, { "group":"s", "name":"sub node 7" }, { "group":"s", "name":"sub node 8" }, { "group":"s", "name":"sub node 9" }, { "group":"s", "name":"sub node 10" }, { "group":"s", "name":"sub node 11" }, { "group":"r", "name":"sub node 12", "children":[ { "group":"r", "name":"sub sub node 1" }, { "group":"r", "name":"sub sub node 2" }, { "group":"r", "name":"sub sub node 3" } ] } ] } ]   

的jsfiddle

像这样添加标题到节点。

 title = svg.selectAll("text.title") .data(nodes); title.enter() .append("text") //In your code you used title instead of text .attr("class", "title") .text(function(d) { return d.name; }); title.exit().remove(); 

请注意,标题应附加在圆形节点之后。 否则标题可能会被切断。

还可以在tick函数中更新标题的位置。

  title.attr("transform", function(d){ return "translate("+d.x+","+d.y+")"; }); 

这是jsfiddle

有趣的是,它有点像你的代码一样在你的代码中工作,但只有在你折叠或扩展节点之后。 这应该可以让您了解问题所在。 基本上,您在节点实际存在之前将title元素添加到每个节点。 移动

 node.append("title") .text(function(d) { return d.name; }); 

之后

 node.enter().append("svg:circle") .attr("class", "node") .attr("cx", function(d) { return dx; }) .attr("cy", function(d) { return dy; }) .attr("r", radius) .style("fill", color) .on("click", click) .call(force.drag); 

呼叫。

以下是完成该更改的代码段:

 var words = [{ "group": "n", "word": "main node", "children": [{ "group": "n", "name": "sub node 1" }, { "group": "n", "name": "sub node 2" }, { "group": "n", "name": "sub node 3" }, { "group": "v", "name": "sub node 4" }, { "group": "s", "name": "sub node 5" }, { "group": "s", "name": "sub node 6" }, { "group": "s", "name": "sub node 7" }, { "group": "s", "name": "sub node 8" }, { "group": "s", "name": "sub node 9" }, { "group": "s", "name": "sub node 10" }, { "group": "s", "name": "sub node 11" }, { "group": "r", "name": "sub node 12", "children": [{ "group": "r", "name": "sub sub node 1" }, { "group": "r", "name": "sub sub node 2" }, { "group": "r", "name": "sub sub node 3" }] }] }] var w = 600, h = 600, radius = 10, node, link, root; var force = d3.layout.force() .on("tick", tick) .charge(function(d) { return -500; }) .linkDistance(function(d) { return d.target._children ? 100 : 50; }) .size([w, h - 160]); var svg = d3.select("#viz").append("svg") .attr("width", w) .attr("height", h); root = words[0]; //set root node root.fixed = true; root.x = w / 2; root.y = h / 2 - 80; update(); function update() { var nodes = flatten(root), links = d3.layout.tree().links(nodes); // Restart the force layout. force .nodes(nodes) .links(links) .start(); // Update the links… link = svg.selectAll(".link") .data(links); // Enter any new links. link.enter().insert("svg:line", ".node") .attr("class", "link") .attr("x1", function(d) { return d.source.x; }) .attr("y1", function(d) { return d.source.y; }) .attr("x2", function(d) { return d.target.x; }) .attr("y2", function(d) { return d.target.y; }); // Exit any old links. link.exit().remove(); // Update the nodes… node = svg.selectAll("circle.node") .data(nodes) .style("fill", color); node.transition() .attr("r", radius); // Enter any new nodes. node.enter().append("svg:circle") .attr("class", "node") .attr("cx", function(d) { return dx; }) .attr("cy", function(d) { return dy; }) .attr("r", radius) .style("fill", color) .on("click", click) .call(force.drag); node.append("title") .text(function(d) { return d.name; }); // Exit any old nodes. node.exit().remove(); } function tick() { link.attr("x1", function(d) { return d.source.x; }) .attr("y1", function(d) { return d.source.y; }) .attr("x2", function(d) { return d.target.x; }) .attr("y2", function(d) { return d.target.y; }); node.attr("cx", function(d) { return dx; }) .attr("cy", function(d) { return dy; }); } // Color leaf nodes orange, and packages white or blue. function color(d) { if (d._children) { return "#95a5a6"; } else { switch (d.group) { case 'r': //adverb return "#e74c3c"; break; case 'n': //noun return "#3498db"; break; case 'v': //verb return "#2ecc71"; break; case 's': //adjective return "#e78229"; break; default: return "#9b59b6"; } } } // 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(); } // Returns a list of all nodes under the root. function flatten(root) { var nodes = [], i = 0; function recurse(node) { if (node.children) node.size = node.children.reduce(function(p, v) { return p + recurse(v); }, 0); if (!node.id) node.id = ++i; nodes.push(node); return node.size; } root.size = recurse(root); return nodes; } 
 circle.node { cursor: pointer; stroke: #34495e; stroke-width: 2px; box-sizing: border-box; stroke-location: inside; } line.link { fill: none; stroke: #34495e; stroke-width: 1.5px; }