2017-02-23 47 views
1

при использовании компоновки сил в 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(), которая возвращает кратчайший путь между двумя узлами.
Но, к сожалению, это не сработает. Может быть, есть кто-то, кто может помочь мне в этой проблеме. Основная идея отталкивания узлов уже обсуждается здесь: Using the force-layout physics for seperated elements Большое спасибо!

+0

Вы имеете в виду цитаты в этой строке? 'd3.select (" abc "). data(). r = 40;'? –

+1

Да. Вы выбираете тег? Я так не верю. Также укажите, как создается abc. –

+0

Я только что отредактировал код. –

ответ

1

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

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

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

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

Таким образом, при нажатии на кнопку, мы просто отфильтровать узлы с «красный» цвет и увеличить их r собственности, в результате чего Collide радиус увеличения, используя each:

node.filter(function() { 
    return d3.select(this).attr("fill") === "red" 
}).each(d => d.r = 40); 

Если вы хотите использовать data как геттер, вы можете сделать это с forEach:

node.filter(function() { 
    return d3.select(this).attr("fill") === "red" 
}).data().forEach(d => d.r = 40); 

У кого такой же результат.

Вот демо, все красные узлы будут отталкивать другие узлы после щелчка, с радиусом Collide 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) { 
 
\t \t node.filter(function(){ 
 
\t \t return d3.select(this).attr("fill") === "red" 
 
\t \t }).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>

+0

Вау, еще раз спасибо. В моем случае (я использую компоновку силы в сочетании с «иерархией») мне пришлось заменить строку «return d3.select (this) .attr (« fill ») ===« red »' in 'return this. style.fill === 'red'', чтобы заставить его работать. Не уверен, почему. Прежде чем я сделал эту замену, я попытался изменить 'attr' в' style', чтобы он выглядел следующим образом: '' return d3.select (this) .style ("fill") === "red" '' Но это также не сработало для меня. Есть ли объяснения для этого? –

+1

Если вы установите заливку с помощью 'style', вам нужно изменить с помощью' style'. –

+0

Знаете ли вы, если можно так же изменить расстояние (длину) ссылок? Я попытался использовать это 'd3.forceSimulation(). Force (« link », d3.forceLink(). Distance (function (d) { return dr + 10; })', но это не сработало. –