Javascript 修复 D3 力导向布局中的节点位置
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10392505/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Fix Node Position in D3 Force Directed Layout
提问by Elijah
I want some of the nodes in my force-directed layout to ignore all forces and stay in fixed positions based on an attribute of the node, while still being able to be dragged and exert repulsion on other nodes and maintain their link lines.
我希望我的力导向布局中的一些节点忽略所有力并根据节点的属性保持在固定位置,同时仍然能够被拖动并对其他节点施加排斥力并保持它们的链接线。
I thought it would be as simple as this:
我认为它会像这样简单:
force.on("tick", function() {
vis.selectAll("g.node")
.attr("transform", function(d) {
return (d.someAttribute == true) ?
"translate(" + d.xcoordFromAttribute + "," + d.ycoordFromAttribute +")" :
"translate(" + d.x + "," + d.y + ")"
});
});
I have also tried to manually set the node's x and y attributes each tick, but then the links continue to float out to where the node would be if it was affected by the force.
我还尝试在每个刻度上手动设置节点的 x 和 y 属性,但是如果节点受到力的影响,链接会继续浮动到节点所在的位置。
Obviously I have a basic misunderstanding of how this is supposed to work. How can I fix nodes in a position, while keeping links and still allowing for them to be draggable?
显然,我对这应该如何工作有一个基本的误解。如何在一个位置固定节点,同时保持链接并仍然允许它们可拖动?
回答by mbostock
Set d.fixed
on the desired nodes to true, and initialize d.x
and d.y
to the desired position. These nodes will then still be part of the simulation, and you can use the normal display code (e.g., setting a transform attribute); however, because they are marked as fixed, they can only be moved by dragging and not by the simulation.
d.fixed
在所需的节点上设置为 true,并初始化d.x
和d.y
到所需的位置。然后这些节点仍将是模拟的一部分,您可以使用正常的显示代码(例如,设置转换属性);但是,因为它们被标记为固定的,所以它们只能通过拖动而不是通过模拟来移动。
See the force layout documentation for more details (v3 docs, current docs), and also see how the root node is positioned in this example.
有关更多详细信息,请参阅 force layout 文档(v3 docs、current docs),并查看本示例中根节点的位置。
回答by Andrew Reid
Fixed nodes in force layout for d3v4 and d4v5
修复了 d3v4 和 d4v5 强制布局中的节点
In d3v3 d.fixed
will fix nodes at d.x
and d.y
; however, in d3v4/5 this method no longer is supported. The d3 documentationstates:
在 d3v3d.fixed
中将修复节点在d.x
和d.y
;但是,在 d3v4/5 中不再支持此方法。在D3的文件中指出:
To fix a node in a given position, you may specify two additional properties:
fx - the node's fixed x-position
fy - the node's fixed y-position
At the end of each tick, after the application of any forces, a node with a defined node.fx has node.x reset to this value and node.vx set to zero; likewise, a node with a defined node.fy has node.y reset to this value and node.vy set to zero. To unfix a node that was previously fixed, set node.fx and node.fy to null, or delete these properties.
要将节点固定在给定位置,您可以指定两个附加属性:
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,或删除这些属性。
You can set fx
and fy
attributes for the force nodes in your data source, or you can add and remove fx
and fy
values dynamically. The snippet below sets these properties at the end of drag events, just drag a node to fix its position:
您可以为数据源中的力节点设置fx
和fy
属性,也可以动态添加和删除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("drag", dragged)
.on("end", dragended));
simulation
.nodes(data.nodes)
.on("tick", ticked)
.alphaDecay(0);
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 d.x; })
.attr("cy", function(d) { return d.y; });
}
function dragged(d) {
d.fx = d3.event.x;
d.fy = d3.event.y;
}
function dragended(d) {
d.fx = d3.event.x;
d.fy = d3.event.y;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.6.0/d3.min.js"></script>