更改存储在数组中的许多节点的碰撞行为
Change the collision behavior of many nodes stored in an array
当使用 d3.js 中的力布局时,可以通过增加围绕节点的假想半径在碰撞力的帮助下将节点推开。
我创建了一个名为 button
的单独按钮,我想使用 .data()
(对 select 整个数组)在单击时将碰撞半径增加到 40 个节点那个按钮。例如,当过滤后的节点数存储在名为 abc
的数组中时,我尝试了以下代码:
var node =......
.on("click", function(d, i) {
abc = start && start.path(d) || [];
node.style("fill", function(n) {
if (n == start ) {
return "yellow";
} else if ( n == d) {
return "green"
} else if (abc.includes(n)) {
return "red"
} else {
return "lightgrey"
}
.....
}});
button.on("click", function(d) {
d3.selectAll("circle").data().forEach(d => d.r = 6);
d3.select(abc).data().r = 40;
simulation.nodes(data);
simulation.alpha(0.8).restart();
})
我可以点击 2 个节点并将这 2 个节点和它们之间的所有节点存储在数组中abc
。这可以在 d3.js 函数 path()
的帮助下实现,其中 returns 是两个节点之间的最短路径。
但不幸的是它不起作用。也许有人可以帮我解决这个问题。推开节点的基本思想已经在这里讨论过:
非常感谢!
经过多次评论后,我终于了解了您是如何过滤节点选择的。
在下面的演示中,圆圈有 4 种不同的颜色:
var colours = ["blue", "red", "green", "yellow"];
node.attr("fill", (d, i) => colours[i%4]);
所以,当你点击按钮时,我们简单地过滤"red"颜色的节点并增加它们的r
属性,使碰撞半径增加,使用each
:
node.filter(function() {
return d3.select(this).attr("fill") === "red"
}).each(d => d.r = 40);
如果您想将 data
用作 getter,您可以使用 forEach
:
node.filter(function() {
return d3.select(this).attr("fill") === "red"
}).data().forEach(d => d.r = 40);
结果相同
这里有一个demo,点击后所有红色节点都会推开其他节点,碰撞半径为40:
var svg = d3.select("svg");
var colours = ["blue", "red", "green", "yellow"];
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) => colours[i%4]);
d3.select("button").on("click", function(d) {
node.filter(function(){
return d3.select(this).attr("fill") === "red"
}).each(d=>d.r = 40);
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>
<button>Click me</button>
<br>
<svg></svg>
当使用 d3.js 中的力布局时,可以通过增加围绕节点的假想半径在碰撞力的帮助下将节点推开。
我创建了一个名为 button
的单独按钮,我想使用 .data()
(对 select 整个数组)在单击时将碰撞半径增加到 40 个节点那个按钮。例如,当过滤后的节点数存储在名为 abc
的数组中时,我尝试了以下代码:
var node =......
.on("click", function(d, i) {
abc = start && start.path(d) || [];
node.style("fill", function(n) {
if (n == start ) {
return "yellow";
} else if ( n == d) {
return "green"
} else if (abc.includes(n)) {
return "red"
} else {
return "lightgrey"
}
.....
}});
button.on("click", function(d) {
d3.selectAll("circle").data().forEach(d => d.r = 6);
d3.select(abc).data().r = 40;
simulation.nodes(data);
simulation.alpha(0.8).restart();
})
我可以点击 2 个节点并将这 2 个节点和它们之间的所有节点存储在数组中abc
。这可以在 d3.js 函数 path()
的帮助下实现,其中 returns 是两个节点之间的最短路径。
但不幸的是它不起作用。也许有人可以帮我解决这个问题。推开节点的基本思想已经在这里讨论过:
经过多次评论后,我终于了解了您是如何过滤节点选择的。
在下面的演示中,圆圈有 4 种不同的颜色:
var colours = ["blue", "red", "green", "yellow"];
node.attr("fill", (d, i) => colours[i%4]);
所以,当你点击按钮时,我们简单地过滤"red"颜色的节点并增加它们的r
属性,使碰撞半径增加,使用each
:
node.filter(function() {
return d3.select(this).attr("fill") === "red"
}).each(d => d.r = 40);
如果您想将 data
用作 getter,您可以使用 forEach
:
node.filter(function() {
return d3.select(this).attr("fill") === "red"
}).data().forEach(d => d.r = 40);
结果相同
这里有一个demo,点击后所有红色节点都会推开其他节点,碰撞半径为40:
var svg = d3.select("svg");
var colours = ["blue", "red", "green", "yellow"];
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) => colours[i%4]);
d3.select("button").on("click", function(d) {
node.filter(function(){
return d3.select(this).attr("fill") === "red"
}).each(d=>d.r = 40);
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>
<button>Click me</button>
<br>
<svg></svg>