简体   繁体   English

d3 v4更新/合并分组数据

[英]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 . 我想对于力模拟D3 V4,类似的数据更新这个不成功的尝试和半类似这种成功的一个 CodePen here CodePen 在这里

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: HTML:

<button onclick="addData()">Add Data</button>
<svg width="960" height="600"></svg>

JavaScript: 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 . 您的selectAll是按元素类型nodeWrapper选择的,而您的选择是类.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. 您在.merge之后将类名称更改为“ merged”,则无法执行此操作,因为它会破坏.nodeWrapper类将来的选择。
  3. When you .merge your selection, you are merging circle s with g s. 当你.merge您的选择,您合并circle以s g秒。 You should stay consistent and operate on the g s only. 您应保持一致并仅在g s上操作。

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 : 注意 ,我还修改了您的tick函数,使其在g而不是circle上进行操作:

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

Full code is here . 完整的代码在这里

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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