Comment supprimer tous les éléments enfants d'un nœud, puis les appliquer à nouveau avec une couleur et une taille différentes?

J'ai donc le code graphique de disposition de force suivant pour définir des nœuds, des liens et d'autres éléments:

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

Maintenant, les couleurs et les dépendances de taille ont changé et j'ai besoin de redessiner les cercles du graphique (+tous les éléments ajoutés) avec une couleur et un rayon différents. Avoir un problème avec elle.

Je peux faire ceci:

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

Mais j'ai toutes les images que j'ai attachées à '.circles' toujours là.

De toute façon, toute aide sera appréciée, faites-moi savoir si l'explication n'est pas assez claire, je va essayer de le réparer.

P. S. quelle est la différence entre graphData.nodes et d3.selectAll('.nodes')?

71
demandé sur serv-inc 2013-01-20 10:15:27

5 réponses

Votre réponse fonctionnera, mais pour la postérité, ces méthodes sont plus génériques.

Supprimer tous les enfants de HTML:

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

Supprimer tous les enfants de SVG / HTML:

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

L'appel .html("") fonctionne avec mon SVG, mais cela peut être un effet secondaire de l'utilisation de innerSVG .

101
répondu Glenn 2014-03-20 03:43:51

Mon premier conseil est que vous devriez lire l'API d3.js sur les sélections: https://github.com/mbostock/d3/wiki/Selections

Vous devez comprendre comment fonctionne la commande enter() (API ). Le fait que vous devez l'utiliser pour gérer de nouveaux nœuds a une signification qui vous aidera.

Ici est le processus de base lorsque vous traitez avec selection.data():

  • Vous voulez D'abord "attacher" des données à la sélection. Donc, vous avez:

    var nodes = visualRoot.selectAll(".node")
        .data(graphData.nodes)
    
  • Ensuite, vous pouvez modifier tous les nœuds chaque fois que les données sont modifiées (cela fera exactement ce que vous voulez). Si par exemple vous modifiez le rayon des anciens nœuds qui se trouvent dans le nouvel ensemble de données que vous avez chargé

    nodes.attr("r", function(d){return d.radius})
    
  • Ensuite, vous avez à gérer de nouveaux nœuds, pour cela, vous devez sélectionner les nouveaux nœuds, c'est ce que selection.enter() est fait:

    var nodesEnter = nodes.enter()
        .attr("fill", "red")
        .attr("r", function(d){return d.radius})
    
  • Enfin, vous voulez certainement supprimer les nœuds que vous ne voulez plus, pour ce faire, vous devez sélectionner pour eux, c'est pour ça que selection.exit() est fait.

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

Un bon exemple de l'ensemble du processus peut également être trouvé sur le wiki de L'API: https://github.com/mbostock/d3/wiki/Selections#wiki-exit

6
répondu Christopher Chiche 2013-01-20 15:18:07

De cette façon, je l'ai résolu très facilement,

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

Et puis j'ai juste ajouté des éléments visuels qui ont été rendus différemment parce que le code pour calculer le rayon et la couleur avait changé les propriétés. Merci.

6
répondu HotFrost 2016-06-07 07:36:34

Pour supprimer tous les éléments d'un nœud:

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]);
    }
}`
3
répondu jedd.ahyoung 2013-07-30 04:00:57

Si vous voulez supprimer l'élément lui-même, utilisez simplement element.remove(), comme toi. Dans le cas où vous voulez juste supprimer le contenu de l'élément, mais garder l'élément tel quel, vous pouvez utiliser F. ex.

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

Au lieu de .html("") (Je n'étais pas sûr des enfants de l'élément que vous voulez supprimer). Ceci conserve l'élément lui-même, mais nettoie tout le contenu inclus. Il la façon officielle de le faire , devrait donc fonctionner cross-browser.

PS: vous vouliez changer le cercle taille. Avez-vous essayé

d3.selectAll(".circle").attr("r", newValue);
3
répondu serv-inc 2017-04-27 15:27:55