Graph 具有定向路径的D3js可折叠力布局?
我正在尝试做一个力定向布局,其中链接是指向节点的箭头(如和中所示),并且具有子节点的节点是可折叠的(如Mike Bostock的示例:或中所示) 到目前为止,折叠节点工作正常,但我很难理解箭头是如何包含在路径中的。以下是基于上述示例的部分代码:Graph 具有定向路径的D3js可折叠力布局?,graph,svg,d3.js,Graph,Svg,D3.js,我正在尝试做一个力定向布局,其中链接是指向节点的箭头(如和中所示),并且具有子节点的节点是可折叠的(如Mike Bostock的示例:或中所示) 到目前为止,折叠节点工作正常,但我很难理解箭头是如何包含在路径中的。以下是基于上述示例的部分代码: force.nodes(nodes) .links(links) .gravity(0.05) .charge(-1500) .linkDistance(100) .friction(0.5) .linkS
force.nodes(nodes)
.links(links)
.gravity(0.05)
.charge(-1500)
.linkDistance(100)
.friction(0.5)
.linkStrength(function(l, i) {return 1 })
.size([w, h])
.start();
// Append markers
vis.append("svg:defs").selectAll("marker")
.data(["end"])
.enter().append("svg:marker")
.attr("id", String)
.attr("viewBox", "0 -5 10 10")
.attr("refX", 15)
.attr("refY", -1.5)
.attr("markerWidth", 6)
.attr("markerHeight", 6)
.attr("orient", "auto")
//.append("svg:path") // <-- I not sure what this does
//.attr("d", "M0,-5L10,0L0,5");
var path = vis.selectAll("path")
.data(force.links());
// Enter new paths
path.enter().insert("svg:path")
.attr("class", "link")
.attr("marker-end", "url(#end)")
.style("stroke", "#ccc");
// Exit any old paths.
path.exit().remove();
// Update the nodes…
var node = vis.selectAll("g.node")
.data(nodes, function(d) { return d.id; })
node.select("circle")
.style("fill", color);
// Enter any new nodes.
var nodeEnter = node.enter().append("svg:g")
.attr("class", "node")
.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; })
.on("click", click)
.call(force.drag);
//Add an immage to the node
nodeEnter.append("svg:image")
.attr("xlink:href", function(d) { return d.image;})
.attr("x", function(d) { return (0 - Math.sqrt(d.size)) / 10 || 4.5;})
.attr("y", function(d) { return (0 - Math.sqrt(d.size)) / 10 || 4.5;})
.attr("height", 16)
.attr("width", 16);
// Exit any old nodes.
node.exit().remove();
// Re-select for update.
node = vis.selectAll("g.node");
path = vis.selectAll("path")
force.on("tick", function() {
// Draw curved links
path.attr("d", function(d) {
var dx = d.target.x - d.source.x,
dy = d.target.y - d.source.y,
dr = Math.sqrt(dx * dx + dy * dy);
return "M" + d.source.x + ","
+ d.source.y
+ "A" + dr + ","
+ dr + " 0 0,1 "
+ d.target.x + ","
+ d.target.y;
});
node.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });
});
然后,在输入路径时(即.attr(“标记结束”,“url(#结束)”);
)会引用该路径
但我可能遗漏了一些东西,因为在我的图表中显示的是路径,而不是箭头
谢谢你的帮助 我找到了一个“几乎”奏效的解决方案。下面是完整的代码,并简要解释了底部仍然存在的问题:
var w = 1280,
h = 800,
root,
vis;
var force = d3.layout.force()
.gravity(200)
.charge(-1500)
.linkDistance(100)
.friction(0.01)
.size([w, h])
;
$(document).ready(function() {
var newHeight = '100%';
$("#svgdiv").html("<svg id='graph' xmlns='http://www.w3.org/2000/svg' width='100%' height='100%'></svg>");
vis = d3.select("svg");
d3.json("../json/flare.json", function(json) {
root = json;
root.fixed = true;
root.x = w / 2;
root.y = h / 2;
// Build the arrow
var defs = vis.insert("svg:defs").selectAll("marker")
.data(["end"]);
defs.enter().append("svg:marker")
.attr("id", String)
.attr("viewBox", "0 -5 15 15")
.attr("refX", 15)
.attr("refY", -1.5)
.attr("markerWidth", 6)
.attr("markerHeight", 6)
.attr("orient", "auto")
.append("svg:path")
.attr("d", "M0,-5L10,0L0,5");
update();
});
});
/**
*
*/
function update() {
var nodes = flatten(root),
links = d3.layout.tree().links(nodes);
// Restart the force layout.
force.nodes(nodes)
.links(links)
.gravity(0.05)
.charge(-1500)
.linkDistance(100)
.friction(0.5)
.linkStrength(function(l, i) {return 1 })
.size([w, h])
.start();
var path = vis.selectAll("path.link") // <-- THIS WAS CHANGED TO "path.links"
.data(links, function(d) { return d.target.id; });
path.enter().insert("svg:path")
.attr("class", "link")
.attr("marker-end", "url(#end)")
.style("stroke", "#ccc");
// Exit any old paths.
path.exit().remove();
// Update the nodes…
var node = vis.selectAll("g.node")
.data(nodes, function(d) { return d.id; });
// Enter any new nodes.
var nodeEnter = node.enter().insert("svg:g")
.attr("class", "node")
.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; })
.on("click", click)
.call(force.drag);
node.select("circle")
.style("fill", color);
nodeEnter.append("svg:circle")
.attr("r", function(d) { return Math.sqrt(d.size) / 10 || 4.5; })
.style("fill", color);
// Add text to the node (as defined by the json file)
nodeEnter.append("svg:text")
.attr("text-anchor", "middle")
.attr("dx", function(d) { return Math.sqrt(d.size) / 10 || 4.5; })
.attr("dy", ".35em")
.text(function(d) { return d.name; });
/* */
//Add an image to the node
nodeEnter.append("svg:image")
.attr("xlink:href", function(d) { return d.logo;})
.attr("x", function(d) { return (0 - Math.sqrt(d.size)) / 10 || 4.5;})
.attr("y", function(d) { return (0 - Math.sqrt(d.size)) / 10 || 4.5;})
.attr("height", 16)
.attr("width", 16);
/* */
// Exit any old nodes.
node.exit().remove();
// Re-select for update.
node = vis.selectAll("g.node");
path = vis.selectAll("path.link"); // <-- THIS WAS CHANGED TO "path.link"
force.on("tick", function() {
path.attr("d", function(d) {
var dx = d.target.x - d.source.x,
dy = d.target.y - d.source.y,
dr = Math.sqrt(dx * dx + dy * dy);
return "M" + d.source.x + ","
+ d.source.y
+ "A" + dr + ","
+ dr + " 0 0,1 "
+ d.target.x + ","
+ d.target.y;
});
node.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });
});
}
// Color leaf nodes orange, and packages white or blue.
function color(d) {
return d._children ? "#3182bd" : d.children ? "#c6dbef" : "#fd8d3c";
}
// 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 = [];
var i = 0;
function recurse(node) {
if (node.children)
node.children.forEach(recurse);
if (!node.id)
node.id = ++i;
nodes.push(node);
}
recurse(root);
return nodes;
}
它应该在哪里:
var path = vis.selectAll("path.link").)
然后我还发现箭头标记的def应该在update()函数之外定义,该函数在折叠和展开节点时调用。否则,每次单击节点时都会将其附加到svg,这不是很有效
因此,现在节点在单击时折叠并绘制箭头(尽管它们很难看)。然而,还有一个问题让我非常困惑:过了一段时间,没有任何明显的时间间隔或点击模式,图形冻结,在浏览器中调试说,无法读取未定义的
的属性“target”。此错误在“勾号”功能上触发,其中定义了弯曲路径:
path.attr("d", function(d) {
var dx = d.target.x - d.source.x,
dy = d.target.y - d.source.y,
dr = Math.sqrt(dx * dx + dy * dy);
return "M" + d.source.x + ","
+ d.source.y
+ "A" + dr + ","
+ dr + " 0 0,1 "
+ d.target.x + ","
+ d.target.y;
});
它找不到d.target
,因为在输入force.on(“tick”,function()…
之前,路径变量被重新初始化(如path=vis.selectAll(“path.link”);
)
奇怪的是,它在一开始就可以工作,但在一段随机时间后可能会突然停止工作!
那么有没有人知道会发生什么事
编辑:
我现在知道是怎么回事了。出于某种原因,我使用了我在某处找到的脚本d3.layout.js,我认为这是折叠树所需要的。我删除了该库并使用了正常的d3.v3.js,一切都正常工作……只是箭头很难看。因此,上面的脚本应该可以工作,具有可折叠的节点和定向路径。问得好!天哪,我一直在努力对付那些箭头。我期待着看到这里出现了什么。SVG标记定义中附加的
路径负责绘制实际的箭头。您是否在运行代码时注释掉了这些箭头(第一个代码块)?谢谢@LarsKotthoff,我在发布问题后就发现了这一点。它在未注释之前不起作用,因为我不理解它的作用,所以我对它进行了注释。编写path.link
几乎修复了它。我将我的答案放在下面。但是,仍然有一点东西阻止它完全正常工作……我创建了一个要点以显示一个实例:
var path = vis.selectAll("path.link").)
path.attr("d", function(d) {
var dx = d.target.x - d.source.x,
dy = d.target.y - d.source.y,
dr = Math.sqrt(dx * dx + dy * dy);
return "M" + d.source.x + ","
+ d.source.y
+ "A" + dr + ","
+ dr + " 0 0,1 "
+ d.target.x + ","
+ d.target.y;
});