Wie entferne ich alle untergeordneten Elemente von einem Knoten und wende sie dann erneut mit unterschiedlicher Farbe und Größe an?

87

Ich habe also den nächsten Force-Layout-Diagrammcode zum Festlegen von Knoten, Links und anderen Elementen:

var setLinks = function ()
{
    link = visualRoot.selectAll("line.link")
        .data(graphData.links)
        .enter().append("svg:line")
        .attr("class", "link")
        .style("stroke-width", function (d) { return nodeStrokeColorDefault; })
        .style("stroke", function (d) { return fill(d); })
        .attr("x1", function (d) { return d.source.x; })
        .attr("y1", function (d) { return d.source.y; })
        .attr("x2", function (d) { return d.target.x; })
        .attr("y2", function (d) { return d.target.y; });

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


var setNodes = function ()
{
    node = visualRoot.selectAll(".node")
        .data(graphData.nodes)
        .enter().append("g")
        .attr("id", function (d) { return d.id; })
        .attr("title", function (d) { return d.name; })
        .attr("class", "node")
        .on("click", function (d, i) { loadAdditionalData(d.userID, this); })
        .call(force.drag)
        .on("mouseover", fadeNode(.1)).on("mouseout", fadeNode(1));
};

//append the visual element to the node
var appendVisualElementsToNodes = function ()
{
    node.append("circle")
        .attr("id", function (d) { return "circleid_" + d.id; })
        .attr("class", "circle")
        .attr("cx", function (d) { return 0; })
        .attr("cy", function (d) { return 0; })
        .attr("r", function (d) { return getNodeSize(d); })
        .style("fill", function (d) { return getNodeColor(d); })
        .style("stroke", function (d) { return nodeStrokeColorDefault; })
        .style("stroke-width", function (d) { return nodeStrokeWidthDefault; });

    //context menu:
    d3.selectAll(".circle").on("contextmenu", function (data, index)
    {
        d3.select('#my_custom_menu')
          .style('position', 'absolute')
          .style('left', d3.event.dx + "px")
          .style('top', d3.event.dy + "px")
          .style('display', 'block');

        d3.event.preventDefault();
    });
    //d3.select("svg").node().oncontextmenu = function(){return false;};

    node.append("image")
        .attr("class", "image")
        .attr("xlink:href", function (d) { return d.profile_image_url; })//"Images/twitterimage_2.png"
        .attr("x", -12)
        .attr("y", -12)
        .attr("width", 24)
        .attr("height", 24);

    node.append("svg:title")
        .text(function (d) { return d.name + "\n" + d.description; });
};

Jetzt haben sich die Farb- und Größenabhängigkeiten geändert und ich muss die Diagrammkreise (+ alle angehängten Elemente) mit unterschiedlichen Farben und Radien neu zeichnen. Probleme damit haben.

Ich kann dies tun:

visualRoot.selectAll(".circle").remove();

aber ich habe alle Bilder, die ich angehängt habe, '.circles'noch da.

In jedem Fall wird jede Hilfe geschätzt. Lassen Sie mich wissen, wenn die Erklärung nicht klar genug ist. Ich werde versuchen, sie zu beheben.

PS Was ist der Unterschied zwischen graphData.nodes und d3.selectAll('.nodes')?

HotFrost
quelle

Antworten:

127

Ihre Antwort wird funktionieren, aber für die Nachwelt sind diese Methoden allgemeiner.

Entfernen Sie alle untergeordneten Elemente aus HTML:

d3.select("div.parent").html("");

Entfernen Sie alle untergeordneten Elemente aus SVG / HTML:

d3.select("g.parent").selectAll("*").remove();

Der .html("")Aufruf funktioniert mit meinem SVG, kann jedoch ein Nebeneffekt bei der Verwendung von innerSVG sein .

Glenn
quelle
3
Leider funktioniert .html ("") in Safari nicht. Funktioniert gut in allen anderen Browsern.
Glyphe
1
@glyph: siehe stackoverflow.com/a/43661877/1587329 für den offiziellen Weg, dies zu tun
serv-inc
8

Mein erster Rat ist, dass Sie die d3.jsAPI zu Auswahlen lesen sollten : https://github.com/mbostock/d3/wiki/Selections

Sie müssen verstehen, wie der enter()Befehl funktioniert ( API ). Die Tatsache, dass Sie es verwenden müssen, um neue Knoten zu behandeln, hat eine Bedeutung, die Ihnen helfen wird.

Hier ist der grundlegende Prozess, mit dem Sie sich befassen selection.data():

  • Zuerst möchten Sie einige Daten an die Auswahl "anhängen". Also hast du:

    var nodes = visualRoot.selectAll(".node")
        .data(graphData.nodes)
  • Dann können Sie alle Knoten jedes Mal ändern, wenn Daten geändert werden (dies wird genau das tun, was Sie wollen). Wenn Sie beispielsweise den Radius alter Knoten ändern, die sich in dem neuen Datensatz befinden, den Sie geladen haben

    nodes.attr("r", function(d){return d.radius})
  • Dann müssen Sie neue Knoten behandeln, dafür müssen Sie die neuen Knoten auswählen, dafür ist gedacht selection.enter():

    var nodesEnter = nodes.enter()
        .attr("fill", "red")
        .attr("r", function(d){return d.radius})
  • Schließlich möchten Sie sicherlich die Knoten entfernen, die Sie nicht mehr möchten. Dazu müssen Sie sie auswählen. Dafür ist dies selection.exit()gemacht.

    var nodesRemove = nodes.exit().remove()

Ein gutes Beispiel für den gesamten Prozess finden Sie auch im API-Wiki: https://github.com/mbostock/d3/wiki/Selections#wiki-exit

Christopher Chiche
quelle
Hallo Chris, danke für die Vorschläge und Punkte. Tatsache ist, dass ich keine neuen Daten habe. Daten immer noch die gleichen. Alles ist das selbe. Ich möchte den gesamten Force-Prozess nicht noch einmal durchführen. Soweit ich weiß (korrigiere mich, wenn ich falsch liege). Alles was ich tun muss ist
HotFrost
Alles, was ich tun muss, ist, Dom-Elemente mit der Klasse '.circle' und ihren Kindern zu finden. Entferne sie. Suchen Sie die SVG-Elemente mit der Klasse '.node' und wenden Sie den Prozess 'Anhängen' erneut für SVG-Kreise und andere visuelle Elemente an, die in der Funktion 'Visualvisements anwenden' beschrieben sind. Dieses Mal wird der Radius jedoch anders berechnet, wenn er berechnet wird.
HotFrost
auf jeden Fall habe ich es sehr einfach gelöst, visualRoot.selectAll (". circle"). remove (); visualRoot.selectAll (". image"). remove ();
HotFrost
7

auf diese Weise habe ich es sehr leicht gelöst,

visualRoot.selectAll(".circle").remove();
visualRoot.selectAll(".image").remove();

und dann habe ich nur visuelle Elemente wieder hinzugefügt, die anders gerendert wurden, weil der Code zur Berechnung von Radius und Farbe die Eigenschaften geändert hatte. Danke dir.

HotFrost
quelle
6

Wenn Sie das Element selbst entfernen möchten, verwenden element.remove()Sie es einfach wie zuvor. Wenn Sie nur den Inhalt des Elements entfernen möchten, das Element jedoch unverändert lassen möchten, können Sie f.ex verwenden.

visualRoot.selectAll(".circle").html(null);
visualRoot.selectAll(".image").html(null);

statt .html("")(Ich war mir nicht sicher, welche Kinder des Elements gelöscht werden sollen). Dadurch bleibt das Element selbst erhalten, es werden jedoch alle enthaltenen Inhalte bereinigt . Es ist der offizielle Weg, dies zu tun , sollte also browserübergreifend funktionieren.

PS: Sie wollten die Kreisgrößen ändern. Hast du es versucht

d3.selectAll(".circle").attr("r", newValue);
serv-inc
quelle
html(null)funktioniert nicht für mich in Internet Explorer 11
Robert
@ Robert: "Ein Nullwert löscht den Inhalt." Scheint wie ein Fehler. Hat etwas an die Konsole gemeldet?
serv-inc
Nein, keine Fehler oder Warnungen. Gibt nur das ausgewählte Objekt zurück. d3.select($0).html('')von der ausgewählten Antwort funktioniert bei mir auch im IE nicht, d3.select($0).selectAll('*').remove()funktioniert aber .
Robert
@ Robert: Möchtest du das melden ?
serv-inc
3

So entfernen Sie alle Elemente von einem Knoten:

var siblings = element.parentNode.childNodes;
for (var i = 0; i < siblings.length; i++) {
    for (var j = 0; j < siblings.length; j++) {
        siblings[i].parentElement.removeChild(siblings[j]);
    }
}`
jedd.ahyoung
quelle
Sie nähen, um etwas zu zitieren, was ist die Quelle?
Christopher Chiche
Müssen Sie wirklich auch alle diese Knoten von ihren eigenen Knoten entfernen? Sicherlich würde die von DOM empfohlene Methode ausreichen, da die Knoten nicht vom aktuellen Knoten entfernt wären und nicht auch auseinandergerissen werden müssen.
Tatarize
var element = document.getElementById ("top"); while (element.firstChild) {element.removeChild (element.firstChild); }
Tatarize