javascript - d3 v4 update/merge grouped data -


i trying update data force simulation in d3 v4, similar this unsuccessful attempt , semi-similar this successful one. codepen here

instead of joining new nodes appears doubling nodes (see pictures). not seem refreshing graph correctly either.

initial graph (initial graph)

graph after adding data (after adding data)

html:

<button onclick="adddata()">add data</button> <svg width="960" height="600"></svg> 

javascript:

function adddata() {     graph.nodes.push({"id": "extra1", "group": 11},{"id": "extra2", "group": 11})     graph.links.push({"source": "extra1", "target": "valjean", "strength": 1},{"source": "extra1", "target": "extra2", "strength": 2})     update()     simulation.restart() }  var svg = d3.select("svg"),     width = +svg.attr("width"),     height = +svg.attr("height");  var link, linkenter, nodewrapper, nodewrapperenter;  var simulation = d3.forcesimulation()     .force("link", d3.forcelink().id(function(d) { return d.id; }))     .force("charge", d3.forcemanybody())     .force("center", d3.forcecenter(width / 2, height / 2))     .on("tick", ticked);  var alllinkg = svg.append("g")     .attr("class", "alllinkg")  var allnodeg = svg.append("g")     .attr("class", "allnodeg")  update() simulation.restart()  function update(){    link = alllinkg     .selectall("line")     .data(graph.links, function(d){ return d.id })     link.exit().remove()    linkenter = link     .enter().append("line");    link = linkenter.merge(link).attr("class","merged");     nodewrapper = allnodeg     .selectall("nodewrapper")     .data(graph.nodes, function(d) { return d.id; })    nodewrapper.exit().remove();    nodewrapperenter = nodewrapper.enter()     .append("g").attr("class","nodewrapper")     .append("circle")     .attr("r", 2.5)    nodewrapper = nodewrapperenter     .merge(nodewrapper).attr("class","merged");     simulation       .nodes(graph.nodes);    simulation.force("link")       .links(graph.links); }  function ticked() {     link         .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; });      nodewrapper         .attr("cx", function(d) { return d.x; })         .attr("cy", function(d) { return d.y; }); } 

thanks help.

a few issues here:

  1. your selectall selecting element type nodewrapper, meant class .nodewrapper.
  2. you change class name "merged" after .merge, can't breaks future selections .nodewrapper class.
  3. when .merge selection, merging circles gs. should stay consistent , operate on gs only.

quick refactor:

function update() {    link = alllinkg     .selectall("line")     .data(graph.links, function(d) {       return d.id     })    link.exit().remove()    linkenter = link     .enter().append("line");    link = linkenter.merge(link).attr("class", "merged");    nodewrapper = allnodeg     .selectall(".nodewrapper") //<-- class nodewrapper     .data(graph.nodes, function(d) {       return d.id;     })    nodewrapperenter = nodewrapper.enter()     .append("g").attr("class", "nodewrapper"); //<-- enter selection should gs    nodewrapperenter //<-- append  circles     .append("circle")     .attr("r", 2.5)    nodewrapper = nodewrapperenter //<-- merge, don't change class     .merge(nodewrapper);    nodewrapper.exit().remove();  //<-- , exit    simulation     .nodes(graph.nodes);    simulation.force("link")     .links(graph.links); } 

note, modified tick function operate on g instead of circle:

nodewrapper   .attr("transform", function(d) {     return "translate(" + d.x + "," + d.y + ")";   }); 

full code here.


Comments