73 votes

Mettez en surbrillance le noeud sélectionné, ses liens et ses enfants dans un graphe orienté de force D3

Je suis en train de travailler sur une force dirigée graphique D3. Je tiens à souligner le passage de la souris avais nœud, ses liens et ses nœuds enfants en définissant tous les autres nœuds et de liens à une diminution de l'opacité.

Dans cet exemple, http://jsfiddle.net/xReHA/, je suis en mesure de la fermeture de tous les liens et de nœuds puis fondu dans les liens utiles, mais, jusqu'à présent, je n'ai pas pu élégamment fondu dans les nœuds connectés qui sont des enfants de la mouseover avais nœud.

C'est la clé de la fonction dans le code:

function fade(opacity) {
    return function(d, i) {
        //fade all elements
        svg.selectAll("circle, line").style("opacity", opacity);

        var associated_links = svg.selectAll("line").filter(function(d) {
            return d.source.index == i || d.target.index == i;
        }).each(function(dLink, iLink) {
            //unfade links and nodes connected to the current node
            d3.select(this).style("opacity", 1);
            //THE FOLLOWING CAUSES: Uncaught TypeError: Cannot call method 'setProperty' of undefined
            d3.select(dLink.source).style("opacity", 1);
            d3.select(dLink.target).style("opacity", 1);
        });
    };
}

Je suis un Uncaught TypeError: Cannot call method 'setProperty' of undefined d'erreur lorsque je tente de régler l'opacité sur un élément que j'ai chargé à partir de la source.cible. J'imagine que ce n'est pas la bonne façon de charger ce nœud comme un d3 objet, mais je ne peux pas trouver un autre moyen de le charger sans itération sur tous les nœuds de nouveau pour trouver ceux qui correspondent à la cible du lien ou de la source. Pour conserver les performances raisonnables, je ne veux pas itérer sur tous les nœuds de plus que nécessaire.

J'ai pris l'exemple de la décoloration des liens à partir de la http://mbostock.github.com/d3/ex/chord.html:

enter image description here

Toutefois, cela ne veut pas montrer comment modifier l'enfant en lien avec les nœuds.

Toutes les bonnes suggestions sur la façon de résoudre ou d'améliorer ce sera furieusement upvoted :)

97voto

mbostock Points 25336

L'erreur est parce que vous êtes en sélectionnant les objets de données (d.source et d.cible) plutôt que sur les éléments du DOM associés à ces objets de données.

Vous avez la ligne mettant en évidence le travail, mais je serais probablement combiner votre code en une seule itération, comme ceci:

 link.style("opacity", function(o) {
   return o.source === d || o.target === d ? 1 : opacity;
 });

Mettant en évidence les nœuds voisins est plus difficile parce que vous avez besoin de connaître les voisins pour chaque nœud. Cette information n'est pas facile de déterminer avec votre actuelle des structures de données, puisque tout ce que vous avez comme un ensemble de nœuds et d'un tableau de liens. Oubliez les DOM pendant une seconde, et demandez-vous comment vous permettrait de déterminer si les deux nœuds a et b sont des voisins?

function neighboring(a, b) {
  // ???
}

Un moyen coûteux de le faire est de parcourir tous les liens et voir si il y a un lien qui relie a et b:

function neighboring(a, b) {
  return links.some(function(d) {
    return (d.source === a && d.target === b)
        || (d.source === b && d.target === a);
  });
}

(Cela suppose que les liens sont non-orienté. Si vous souhaitez uniquement pour mettre en surbrillance l'avant-connecté voisins, puis éliminer la seconde moitié de la OU de.)

Un moyen plus efficace de l'informatique, si vous avez à le faire fréquemment, est d'avoir une carte ou une matrice qui permet de constante de temps de recherche pour tester si a et b sont voisins. Par exemple:

var linkedByIndex = {};
links.forEach(function(d) {
  linkedByIndex[d.source.index + "," + d.target.index] = 1;
});

Maintenant, vous pouvez dire:

function neighboring(a, b) {
  return linkedByIndex[a.index + "," + b.index];
}

Et ainsi, vous pouvez maintenant parcourir les nœuds et mise à jour de leur opacité correctement:

node.style("opacity", function(o) {
  return neighboring(d, o) ? 1 : opacity;
});

(Vous pouvez également cas à la mouseovered lien lui-même, soit par la pose d'une auto-link pour chaque nœud linkedByIndex, ou en testant d directement au moment de calculer le style, ou en utilisant un !important css :hover de style.)

La dernière chose que je voudrais changer dans votre code est à utiliser fill-opacity et de l'avc-opacité plutôt que de l'opacité, car ceux-ci offrent de bien meilleures performances.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X