Изменение поведения столкновений многих узлов, хранящихся в массиве

63
8

при использовании компоновки сил в d3.js можно удалять узлы с помощью силы столкновения путем увеличения мнимого радиуса, окружающего узлы.

Я создал отдельную кнопку с именем button и я хочу использовать .data() (чтобы выбрать целый массив), чтобы увеличить радиус столкновения на 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() который возвращает кратчайший путь между двумя узлами.
Но, к сожалению, это не сработает. Может быть, есть кто-то, кто может помочь мне в этой проблеме. Основная идея отталкивания узлов уже обсуждается здесь: Использование физики силового макета для отдельных элементов Большое спасибо!

спросил(а) 2021-01-25T17:59:55+03:00 4 месяца, 4 недели назад
1
Решение
63

После нескольких комментариев я наконец понял, как вы фильтруете выбор узла.

В следующем демо кружки имеют 4 разных цвета:

var colours = ["blue", "red", "green", "yellow"];

node.attr("fill", (d, i) => colours[i%4]);

Таким образом, когда вы нажимаете кнопку, мы просто фильтруем узлы с "красным" цветом и увеличиваем их свойство 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);

Что имеет тот же результат.

Вот демонстрация, все красные узлы будут отталкивать другие узлы после щелчка с радиусом столкновения 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>

ответил(а) 2021-01-25T17:59:55+03:00 4 месяца, 4 недели назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема