it-swarm.com.de

Markieren Sie den ausgewählten Knoten, seine Verknüpfungen und seine untergeordneten Knoten in einem erzwungenen D3-Diagramm

Ich arbeite an einem kraftgerichteten Graphen in D3. Ich möchte den mit der Maus überfahrenen Knoten, seine Verknüpfungen und seine untergeordneten Knoten hervorheben, indem ich alle anderen Knoten und Verknüpfungen auf eine niedrigere Deckkraft einstelle.

In diesem Beispiel, http://jsfiddle.net/xReHA/ , kann ich alle Verknüpfungen und Knoten ausblenden und dann die verbundenen Verknüpfungen einblenden, habe ich aber bisher noch nicht in der Lage gewesen, die verbundenen Knoten elegant einzublenden, die Kinder des aktuell mit der Maus überfahrenen Knotens sind.

Dies ist die Schlüsselfunktion aus dem 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);
        });
    };
}

Ich bekomme ein Uncaught TypeError: Cannot call method 'setProperty' of undefined Fehler beim Versuch, die Deckkraft für ein Element festzulegen, das ich aus der Datei source.target geladen habe. Ich vermute, dass dies nicht der richtige Weg ist, um diesen Knoten als d3-Objekt zu laden, aber ich kann keinen anderen Weg finden, um ihn zu laden, ohne alle Knoten erneut zu durchlaufen, um diejenigen zu finden, die dem Ziel oder der Quelle des Links entsprechen. Um die Leistung angemessen zu halten, möchte ich nicht mehr als nötig über alle Knoten iterieren.

Ich habe das Beispiel zum Ausblenden der Links aus http://mbostock.github.com/d3/ex/chord.html genommen:

enter image description here

Dies zeigt jedoch nicht, wie die verbundenen untergeordneten Knoten geändert werden.

Irgendwelche guten Vorschläge, wie man dies löst oder verbessert, werden heftig befürwortet :)

69

Der Fehler liegt darin, dass Sie die Datenobjekte (d.source und d.target) und nicht die diesen Datenobjekten zugeordneten DOM-Elemente auswählen.

Die Hervorhebung der Zeile funktioniert, aber ich würde Ihren Code wahrscheinlich in einer einzigen Iteration zusammenfassen:

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

Das Hervorheben der benachbarten Knoten ist schwieriger, da Sie die Nachbarn für jeden Knoten kennen müssen. Diese Informationen sind mit Ihren aktuellen Datenstrukturen nicht so einfach zu ermitteln, da Sie nur ein Array von Knoten und ein Array von Links haben. Vergessen Sie das DOM für eine Sekunde und fragen Sie sich, wie Sie feststellen würden, ob zwei Knoten a und b Nachbarn sind?

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

Eine teure Möglichkeit, dies zu tun, besteht darin, alle Links zu durchlaufen und zu prüfen, ob es einen Link gibt, der a und b verbindet:

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

(Dies setzt voraus, dass Verknüpfungen ungerichtet sind. Wenn Sie nur vorwärts verbundene Nachbarn markieren möchten, müssen Sie die zweite Hälfte des ODERs entfernen.)

Eine effizientere Methode, dies zu berechnen, besteht darin, wenn Sie dies häufig tun müssen, eine Karte oder eine Matrix zu haben, mit der in konstanter Zeit nachgeschlagen werden kann, ob a und b Nachbarn sind. Beispielsweise:

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

Nun können Sie sagen:

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

Und so können Sie jetzt über die Knoten iterieren und deren Deckkraft korrekt aktualisieren:

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

(Möglicherweise möchten Sie auch den mit der Maus überzogenen Link selbst als Sonderfall definieren, indem Sie entweder einen Selbstlink für jeden Knoten in linkedByIndex festlegen oder direkt beim Berechnen des Stils auf d testen oder indem Sie mit einem! wichtigen CSS :hover style.)

Das Letzte, was ich an Ihrem Code ändern würde, ist, Füll- und Strichopazität anstelle von Opazität zu verwenden, da diese eine viel bessere Leistung bieten.

88
mbostock