我在D3.js v4中使用了力布局。现在我想点击一个节点,并仅使用collide
这样的强制物理作为该节点。
整个SVG上每个节点的模拟如下:
var simulation = d3.forceSimulation()
.force("link", d3.forceLink().id(function(d) {
return d.index
}))
.force("collide", d3.forceCollide(function(d) {
return d.r + 8
}).iterations(16))
.force("charge", d3.forceManyBody())
.force("center", d3.forceCenter(chartWidth / 2, chartWidth / 2))
现在我想更改我点击的一个节点的collide
行为,以推开其他节点或吸引它们。
有人知道解决方案吗?我尝试了一下过滤功能并停止/重新启动布局,但它没有用。
答案 0 :(得分:1)
你说:“我想改变我点击的一个节点的碰撞行为以推开其他节点或吸引他们”。
如果您想使用d3.forceCollide
吸引其他节点,那么您将使用错误的工具完成任务。
根据API:
碰撞力将节点视为具有给定半径而不是点的圆,并防止节点重叠。
因此,collide
基本上将其他节点推开,以避免重叠。
话虽这么说,这个解决方案只处理问题的第一部分:“我想改变我点击的推送其他节点的一个节点的碰撞行为”
有不同的方法可以做到这一点。在我的解决方案中,当您单击某个节点时,它会更改绑定数据中的r
属性:
d3.select(this).datum().r = 20;
不重绘实际的SVG圈。这会推动其他节点离开,将点击的节点维持在相同的大小。
这是演示(点击节点):
var svg = d3.select("svg");
var colour = d3.scaleOrdinal(d3.schemeCategory10);
var data = d3.range(30).map(d => ({
r: 6
}));
var simulation = d3.forceSimulation(data)
.force("x", d3.forceX(150).strength(0.05))
.force("y", d3.forceY(75).strength(0.05))
.force("collide", d3.forceCollide(function(d) {
return d.r + 1;
}));
var node = svg.selectAll(".circles")
.data(data)
.enter()
.append("circle")
.attr("r", d => d.r)
.attr("fill", (d, i) => colour(i));
node.on("click", function(d) {
d3.selectAll("circle").data().forEach(d => d.r = 6);
d3.select(this).datum().r = 20;
simulation.nodes(data);
simulation.alpha(0.8).restart();
})
simulation.nodes(data)
.on("tick", d => {
node.attr("cx", d => d.x).attr("cy", d => d.y);
});
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg></svg>