Jak usunąć wszystkie elementy podrzędne z węzła, a następnie zastosować je ponownie w innym kolorze i rozmiarze?

87

Mam więc następny kod wykresu układu siły do ​​ustawiania węzłów, linków i innych elementów:

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

Teraz zmieniły się zależności kolorów i rozmiaru i muszę przerysować koła wykresu (+ wszystkie dołączone elementy) z innym kolorem i promieniem. Mam z tym problem.

Mogę to zrobić:

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

ale wciąż mam wszystkie obrazy, do których dołączyłem '.circles'.

W każdym razie każda pomoc zostanie doceniona, daj mi znać, jeśli wyjaśnienie nie jest wystarczająco jasne, spróbuję to naprawić.

PS Jaka jest różnica między graphData.nodes i d3.selectAll('.nodes')?

HotFrost
źródło

Odpowiedzi:

132

Twoja odpowiedź będzie działać, ale dla potomnych metody te są bardziej ogólne.

Usuń wszystkie elementy podrzędne z HTML:

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

Usuń wszystkie elementy podrzędne z SVG / HTML:

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

.html("")Wezwanie współpracuje z moim SVG, ale może to być skutkiem ubocznym stosowania innerSVG .

Glenn
źródło
3
Niestety .html („”) nie działa w przeglądarce Safari. Działa dobrze we wszystkich innych przeglądarkach.
glif
1
@glyph: zobacz stackoverflow.com/a/43661877/1587329, aby zobaczyć oficjalny sposób zrobienia tego
serv-inc
8

Moja pierwsza rada jest taka, że ​​powinieneś przeczytać d3.jsAPI o wyborach: https://github.com/mbostock/d3/wiki/Selections

Musisz zrozumieć, jak enter()działa polecenie ( API ). Fakt, że musisz go używać do obsługi nowych węzłów, ma znaczenie, które ci pomoże.

Oto podstawowy proces, gdy masz do czynienia z selection.data():

  • najpierw chcesz „dołączyć” jakieś dane do zaznaczenia. Więc masz:

      var nodes = visualRoot.selectAll(".node")
          .data(graphData.nodes)
    
  • Następnie możesz modyfikować wszystkie węzły za każdym razem, gdy dane są zmieniane (zrobi to dokładnie to, co chcesz). Jeśli na przykład zmienisz promień starych węzłów, które są w nowym załadowanym zbiorze danych

      nodes.attr("r", function(d){return d.radius})
    
  • Następnie musisz obsłużyć nowe węzły, w tym celu musisz wybrać nowe węzły, oto co selection.enter()jest stworzone dla:

      var nodesEnter = nodes.enter()
          .attr("fill", "red")
          .attr("r", function(d){return d.radius})
    
  • Wreszcie na pewno chcesz usunąć węzły, których już nie chcesz, aby to zrobić, musisz je wybrać, do tego właśnie selection.exit()służy.

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

Dobry przykład całego procesu można również znaleźć na wiki API: https://github.com/mbostock/d3/wiki/Selections#wiki-exit

Christopher Chiche
źródło
Cześć Chris, dzięki za sugestie i punkty. Faktem jest, że nie mam nowych danych .. Dane wciąż te same. Wszystko jest takie samo. Nie chcę ponownie wykonywać całego procesu wymuszania. O ile rozumiem (popraw mnie, jeśli się mylę). Wszystko, co muszę zrobić, to
HotFrost
wszystko, co muszę zrobić, to znaleźć elementy dom z klasą „.circle” i ich dziećmi. Usuń ich. Znajdź elementy svg z klasą „.node” i ponownie zastosuj proces „attach” dla okręgów svg i innych wizualizacji opisanych w funkcji „applyvisualelements”, ale tym razem, gdy zostanie obliczony promień, zostanie obliczony inaczej.
HotFrost
w jakikolwiek sposób rozwiązałem to bardzo łatwo, visualRoot.selectAll (". circle"). remove (); visualRoot.selectAll („. image”). remove ();
HotFrost
7

w ten sposób bardzo łatwo to rozwiązałem,

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

a potem po prostu ponownie dodałem elementy wizualne, które były renderowane inaczej, ponieważ kod do obliczania promienia i koloru zmienił właściwości. Dziękuję Ci.

HotFrost
źródło
6

Jeśli chcesz usunąć sam element, po prostu użyj element.remove(), tak jak zrobiłeś. W przypadku, gdy chcesz po prostu usunąć zawartość elementu, ale zachować element tak, jak jest, możesz użyć f.ex.

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

zamiast .html("")(nie byłem pewien, które dzieci elementu chcesz usunąć). To zachowuje sam element, ale czyści całą zawartą w nim zawartość . Jest to oficjalny sposób , więc powinien działać w różnych przeglądarkach.

PS: chciałeś zmienić rozmiary kół. Czy próbowałeś

d3.selectAll(".circle").attr("r", newValue);
serv-inc
źródło
html(null)nie działa dla mnie w przeglądarce Internet Explorer 11
Robert
@Robert: "Wartość pusta wyczyści zawartość." Wygląda na błąd. Coś zgłoszono konsoli?
serv-inc
Nie, żadnych błędów ani ostrzeżeń. Po prostu zwraca wybrany obiekt. d3.select($0).html('')z wybranej odpowiedzi również nie działa dla mnie w IE, ale d3.select($0).selectAll('*').remove()działa.
Robert
@Robert: Czy chcesz to zgłosić ?
serv-inc
3

Aby usunąć cały element z węzła:

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
źródło
Chcesz coś zacytować, jakie jest źródło?
Christopher Chiche
Czy naprawdę musisz usunąć wszystkie te węzły z ich własnych węzłów? Z pewnością metoda zalecana przez DOM byłaby wystarczająca, ponieważ węzły nie byłyby poza bieżącym węzłem, nie trzeba też rozrywać.
Tatarize
var element = document.getElementById ("top"); while (element.firstChild) {element.removeChild (element.firstChild); }
Tatarize