"Pinning" 个 D3 力导向图中的节点
"Pinning" nodes in a D3 force-directed graph
我构建了一个常规 "grid",将节点放置在网格中均匀分布的点上。然后,通过随机化 linkDistance,我可以 "stir up" 网格,使其不那么规则。
我想 "pin" 所有边缘点都不会移动 - 只留下内部点受力布局的影响。
我的见解是,由于这是一个规则的四边形网格,任何权重小于 4 的点都是 "edge" 点,因此应该被固定。
我认为只有在将节点和链接添加到力布局后才计算权重,所以我在将其添加到力布局后 forEach
遍历 nodes
数组布局,并根据权重有条件地设置 fixed
属性。
然后,我将重新应用 nodes
属性 和 start
模拟。
不好。在示例中,我附加了所有点移动。
force = d3.layout.force()
.size( [w, h ] )
.nodes( nodes )
.links( links )
.linkDistance( function( d ){ return Math.random() * GRID_SPACING; } )
.linkStrength( 1 )
.charge( 0 )
.gravity( 0 )
.friction( .5 )
.on( "tick", function() {
d3links.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; });
d3nodes.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; });
} );
// "Pin" all the edge nodes.
nodes.forEach( function( node ){
if ( node.weight < 4 ){
node.fixed = true;
}
} );
force.nodes( nodes ).start();
您的见解很好!但时机就是一切...
"start" 事件在权重初始化后触发,因此这应该有效...
force = d3.layout.force()
.size([w, h])
.nodes(nodes)
.links(links)
.linkDistance(function (d) { return Math.random() * GRID_SPACING; })
.linkStrength(1)
.charge(0)
.gravity(0)
.friction(.5)
.on("tick", function () {
d3links.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; });
d3nodes.attr("cx", function (d) { return d.x; })
.attr("cy", function (d) { return d.y; });
})
.on("start", function () {
// "Pin" all the edge nodes.
nodes.forEach(function (node) {
if (node.weight < 4) {
node.fixed = true;
}
});
})
force.nodes(nodes).start();
(如果你想包含拖动行为,那么你也需要在 dragend 之后重新修复。)
我构建了一个常规 "grid",将节点放置在网格中均匀分布的点上。然后,通过随机化 linkDistance,我可以 "stir up" 网格,使其不那么规则。
我想 "pin" 所有边缘点都不会移动 - 只留下内部点受力布局的影响。
我的见解是,由于这是一个规则的四边形网格,任何权重小于 4 的点都是 "edge" 点,因此应该被固定。
我认为只有在将节点和链接添加到力布局后才计算权重,所以我在将其添加到力布局后 forEach
遍历 nodes
数组布局,并根据权重有条件地设置 fixed
属性。
然后,我将重新应用 nodes
属性 和 start
模拟。
不好。在示例中,我附加了所有点移动。
force = d3.layout.force()
.size( [w, h ] )
.nodes( nodes )
.links( links )
.linkDistance( function( d ){ return Math.random() * GRID_SPACING; } )
.linkStrength( 1 )
.charge( 0 )
.gravity( 0 )
.friction( .5 )
.on( "tick", function() {
d3links.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; });
d3nodes.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; });
} );
// "Pin" all the edge nodes.
nodes.forEach( function( node ){
if ( node.weight < 4 ){
node.fixed = true;
}
} );
force.nodes( nodes ).start();
您的见解很好!但时机就是一切...
"start" 事件在权重初始化后触发,因此这应该有效...
force = d3.layout.force()
.size([w, h])
.nodes(nodes)
.links(links)
.linkDistance(function (d) { return Math.random() * GRID_SPACING; })
.linkStrength(1)
.charge(0)
.gravity(0)
.friction(.5)
.on("tick", function () {
d3links.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; });
d3nodes.attr("cx", function (d) { return d.x; })
.attr("cy", function (d) { return d.y; });
})
.on("start", function () {
// "Pin" all the edge nodes.
nodes.forEach(function (node) {
if (node.weight < 4) {
node.fixed = true;
}
});
})
force.nodes(nodes).start();
(如果你想包含拖动行为,那么你也需要在 dragend 之后重新修复。)