2017-02-23 1 views
1

Lors de l'utilisation de la disposition de force dans d3.js, il est possible de repousser les noeuds à l'aide de la force de collision en augmentant un rayon imaginaire entourant les noeuds.Modifier le comportement de collision de nombreux noeuds stockés dans un tableau

J'ai créé un bouton séparé nommé button et je veux utiliser .data() (pour sélectionner un tableau entier) pour augmenter le rayon de collision dans 40 de nombreux nœuds lorsque vous cliquez sur ce bouton. Par exemple, quand un certain nombre filtré de noeuds est stocké dans un tableau appelé abc, j'ai essayé ce code:

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(); 
     }) 

Je suis en mesure de cliquer sur 2 nœuds et stocker ces 2 noeuds et tous les nœuds entre eux dans le tableau abc. Ceci est possible avec l'aide de la fonction d3.js path() qui renvoie le chemin le plus court entre 2 nœuds.
Mais malheureusement, cela ne fonctionne pas. Peut-être qu'il y a quelqu'un qui peut m'aider avec le problème. L'idée de base de repousser les nœuds est déjà discutée ici: Using the force-layout physics for seperated elements Merci beaucoup!

+0

Vous voulez dire des citations dans cette ligne? 'd3.select (" abc "). data(). r = 40;'? –

+1

Oui. Êtes-vous en train de sélectionner un tag? Je ne le crois pas. Veuillez également spécifier comment abc est créé. –

+0

Je viens d'éditer le code. –

Répondre

1

Après plusieurs commentaires, j'ai enfin une idée de la manière dont vous filtrez la sélection de noeuds.

Dans la démo suivante, les cercles ont 4 couleurs différentes:

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

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

Ainsi, lorsque vous cliquez sur le bouton, nous filtrons simplement les noeuds avec la couleur « rouge » et l'augmentation de leurs biens r, ce qui rend la Collide augmentation de rayon, en utilisant each:

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

Si vous voulez utiliser data comme getter, vous pouvez le faire avec un forEach:

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

Qui a le même résultat.

Voici une démo, tous les nœuds rouges repousser les autres noeuds après le clic, avec un rayon de 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

Wow, merci encore. Dans mon cas (j'utilise la disposition des forces en combinaison avec 'hierarchy'), j'ai dû remplacer la ligne' return d3.select (this) .attr ("fill") === "red" 'dans' return this. style.fill === 'red'' pour le faire fonctionner. Pas sûr, pourquoi est-ce. Avant de faire ce remplacement, j'ai essayé de changer 'attr' en' style' pour qu'il ressemble à ceci: '' return d3.select (this) .style ("fill") === "rouge" '' Mais ceci aussi n'a pas fonctionné pour moi. Y a-t-il une explication à ce sujet? –

+1

Si vous définissez le remplissage en utilisant 'style', vous devez changer en utilisant' style'. –

+0

Savez-vous, s'il est possible de changer la distance (longueur) des liens de la même manière? J'ai essayé juste d'utiliser this'd3.forceSimulation(). Force ("lien", d3.forceLink(). Distance (fonction (d) { return dr + 10; }) ', mais cela n'a pas fonctionné. –