简体   繁体   中英

d3 v4 update/merge grouped data

I am trying to update data for a force simulation in D3 v4, similar to this unsuccessful attempt and semi-similar to this successful one . CodePen here

Instead of joining the new nodes it appears to be doubling all the nodes (see pictures). It does not seem to be refreshing the graph correctly either.

初始图 (initial graph)

添加数据后的图形 (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 very much for any help.

A few issues here:

  1. Your selectAll is selecting by element type nodeWrapper , you meant by class .nodeWrapper .
  2. You change the class name to "merged" after your .merge , you can't do this as it breaks future selections by .nodeWrapper class.
  3. When you .merge your selection, you are merging circle s with g s. You should stay consistent and operate on the g s 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 be gs

  nodeWrapperEnter //<-- append  your circles
    .append("circle")
    .attr("r", 2.5)

  nodeWrapper = nodeWrapperEnter //<-- merge, don't change class
    .merge(nodeWrapper);

  nodeWrapper.exit().remove();  //<-- and the exit

  simulation
    .nodes(graph.nodes);

  simulation.force("link")
    .links(graph.links);
}

Note , I also modified your tick function to operate on the g instead of the circle :

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

Full code is here .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM