对分离元素使用力布局物理
Using the force-layout physics for seperated elements
我在 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
我单击的一个节点的行为以推开或吸引其他节点。
有知道解决办法的人吗?我尝试了一些过滤功能和 stop/restart 布局,但它没有用。
你说:"I want to change the collide behavior for the one node i clicked on to push other nodes away or attract them".
如果您想使用 d3.forceCollide
吸引 其他节点,那么您使用的工具是错误的。
根据 API:
The collision force treats nodes as circles with a given radius, rather than points, and prevents nodes from overlapping.
因此,collide
基本上将其他节点推开,以避免重叠。
也就是说,此解决方案仅处理问题的第一部分:"I want to change the collide behavior for the one node i clicked on to push other nodes away".
有多种方法可以做到这一点。在我的解决方案中,当您单击一个节点时,它会更改绑定数据中的 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>
我在 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
我单击的一个节点的行为以推开或吸引其他节点。
有知道解决办法的人吗?我尝试了一些过滤功能和 stop/restart 布局,但它没有用。
你说:"I want to change the collide behavior for the one node i clicked on to push other nodes away or attract them".
如果您想使用 d3.forceCollide
吸引 其他节点,那么您使用的工具是错误的。
根据 API:
The collision force treats nodes as circles with a given radius, rather than points, and prevents nodes from overlapping.
因此,collide
基本上将其他节点推开,以避免重叠。
也就是说,此解决方案仅处理问题的第一部分:"I want to change the collide behavior for the one node i clicked on to push other nodes away".
有多种方法可以做到这一点。在我的解决方案中,当您单击一个节点时,它会更改绑定数据中的 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>