在D3力定向布局中修复节点位置
我希望我的强制布局中的一些节点能够忽略这个力,并且根据这个节点的属性保持在固定的位置上,同时仍然能够被拖拽并且排斥其他节点并保持它们的连接线。 我认为这将是如此简单:
force.on("tick", function() { vis.selectAll("g.node") .attr("transform", function(d) { return (d.someAttribute == true) ? "translate(" + d.xcoordFromAttribute + "," + d.ycoordFromAttribute +")" : "translate(" + dx + "," + dy + ")" }); });
我也尝试过手动设置节点的x和y属性,但是如果节点受到这个力的影响,链接将继续浮动到节点所在的位置。
很明显,我对这个应该如何工作有一个基本的误解,所以有人可能会指出我的一个例子,其中一些节点固定在他们的位置(但仍然可拖动),其余的节点都是围绕着类似于力的方向,所有的链接还在工作?
将所需节点上的d.fixed
设置为true,并将dx
和dy
初始化为所需的位置。 这些节点将仍然是模拟的一部分,您可以使用正常的显示代码(例如,设置转换属性)。 但是,因为它们被标记为固定的,所以只能通过拖动来移动,而不能通过模拟来移动。
有关更多详细信息,请参阅强制布局文档,还可以在此示例中查看根节点的位置。
d3v4固定节点有效布局
在d3v3中, d.fixed
将在dx
和dy
修复节点; 但是,在d3v4中,不再支持此方法。 d3v4文档指出:
要修复给定位置的节点,您可以指定两个附加属性:
fx - the node's fixed x-position
fy - the node's fixed y-position
在每个节拍结束时,在施加任何力之后,具有定义的节点node.fx的节点将node.x重置为该值,并且将node.vx设置为零; 同样,具有已定义的节点node.fy的节点已将node.y重置为此值,并将node.vy设置为零。 要修复之前修复的节点,请将node.fx和node.fy设置为null,或者删除这些属性。
您可以为数据源中的强制节点设置fx
和fy
属性,也可以dynamic添加和删除fx
和fy
值。 下面的代码片段在拖动事件结束时设置这些属性,只需拖动一个节点来修复它的位置:
var data ={ "nodes": [{"id": "A"},{"id": "B"},{"id": "C"},{"id":"D"}], "links": [{"source": "A", "target": "B"}, {"source": "B", "target": "C"}, {"source": "C", "target": "A"}, {"source": "D", "target": "A"}] } var height = 250; var width = 400; var svg = d3.select("body").append("svg") .attr("width",width) .attr("height",height); var simulation = d3.forceSimulation() .force("link", d3.forceLink().id(function(d) { return d.id; }).distance(50)) .force("charge", d3.forceManyBody()) .force("center", d3.forceCenter(width / 2, height / 2)); var link = svg.append("g") .selectAll("line") .data(data.links) .enter().append("line") .attr("stroke","black"); var node = svg.append("g") .selectAll("circle") .data(data.nodes) .enter().append("circle") .attr("r", 5) .call(d3.drag() .on("start", dragstarted) .on("drag", dragged) .on("end", dragended)); simulation .nodes(data.nodes) .on("tick", ticked); simulation.force("link") .links(data.links); function ticked() { 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; }); } function dragstarted(d) { d.fx = null; d.fy = null; } function dragged(d) { dx = d3.event.x; dy = d3.event.y; } function dragended(d) { d.fx = d3.event.x; d.fy = d3.event.y; }
<script src="ajax/libs/d3/4.6.0/d3.min.js"></script>