添加新的同级树时,树未更新节点位置

时间:2018-11-03 11:29:44

标签: d3.js

我有以下代码绘制了一个非常简单的树。单击任何节点后,我将调用带有新数据的update函数,以在树的底部添加一个新的子代。

已添加新节点,但兄弟节点不会更新其位置。

如果我注销节点:

var nodes = root.descendants();
console.log(nodes);

我可以看到位置x,y已经正确更新,但是在上一个节点没有移动位置的情况下,我得到了重叠效果。

我在这里做错了什么

<!DOCTYPE html>
<meta charset="utf-8">
<head>
  <title></title>
</head>

<style>
    .node {
      fill: #fff;
      stroke: steelblue;
      cursor: pointer;
    }

    .link {
      fill: none;
      stroke: #ddd;
      stroke-width: 2px;
    }
</style>

<body>
  <svg width="1500" height="920">
      <g transform="translate(550, 100)">
          <g class="links"></g>
          <g class="nodes"></g>
      </g>
  </svg>

  <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.2.2/d3.min.js"></script>
  <script>
      var treeData = {
          "name": "root",
          "children": [
            {
              "name": "ORIG"
            }
         ]
      }

      var treeLayout = d3.tree()
        .size([900, 200])
        .nodeSize([210, 40])

function update(data) {

    var root = d3.hierarchy(data);

    treeLayout(root);

    var nodes = root.descendants();
    var links = root.links();

    var nodeWidth = 190;
    var nodeHeight = 90;

    nodes.forEach(function (d) {
        d.y = d.depth * 170;
    });

    // Nodes
    const nodesEnter = d3.select('.nodes')
      .selectAll('.node')
      .data(nodes)
      .enter()
      .append('rect')
      .classed('node', true)
      .attr("width", 190)
      .attr("height", 90)
      .attr('x', function(d) {return d.x;})
      .attr('y', function(d) {return d.y;})
      .on("click", click);

    // Links
    d3.select('.links')
      .selectAll('.link')
      .data(links)
      .enter()
      .append('line')
      .classed('link', true)
      .attr('x1', function(d, i) {return d.source.x + (nodeWidth / 2);})
      .attr('y1', function(d) {return d.source.y + (nodeHeight);})
      .attr('x2', function(d) {return d.target.x + (nodeWidth / 2);})
      .attr('y2', function(d) {return d.target.y + 0;});

      function click(d) {

          update({
              "name": "root",
              "children": [
                {
                  "name": "ORIG"
              },
              {
                "name": "NEW"
              }
             ]
          });
      }
}

update(treeData);

  </script>
</body>
</html>

1 个答案:

答案 0 :(得分:0)

在D3数据绑定(d3.select(s).data(d))中,我们应该准备做三件事:

  • enter,它为数据中尚未选择的DOM中的每个元素添加了一个几何图形,

  • transition,它使用新数据更改DOM中的每个选定元素,并且

  • exit,如果我们的数据少于所选DOM中的元素,则会从DOM中删除元素。

对于您而言,您只需要更新update()函数即可执行以下三个操作:

<!DOCTYPE html>
<meta charset="utf-8">
<head></head>
<style>
    .node {
      fill: #fff;
      stroke: steelblue;
      cursor: pointer;
    }

    .link {
      fill: none;
      stroke: #ddd;
      stroke-width: 2px;
    }
</style>

<body>
  <svg width="1500" height="920">
      <g transform="translate(550, 100)">
          <g class="links"></g>
          <g class="nodes"></g>
      </g>
  </svg>

  <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.2.2/d3.min.js"></script>
  <script>
      var treeData = {
          "name": "root",
          "children": [
            {
              "name": "ORIG"
            }
         ]
      }

      var treeLayout = d3.tree()
        .size([900, 200])
        .nodeSize([210, 40])

function update(data) {

    var root = treeLayout(d3.hierarchy(data)),
        nodes = root.descendants(),
        links = root.links(),
        nodeWidth = 190,
        nodeHeight = 90;

    nodes.forEach(d => d.y = d.depth * 170)

    // Nodes
    const node = d3.select('.nodes').selectAll('.node').data(nodes)

    node.enter()
      .append('rect')
      .classed('node', true)
      .attr("width", 190)
      .attr("height", 90)
      .attr('x', d => d.x)
      .attr('y', d => d.y)
      .on("click", click)

    node.transition()
      .attr('x', d => d.x)
      .attr('y', d => d.y)

    node.exit()
      .remove()

    // Links
    const link = d3.select('.links').selectAll('.link').data(links)

    link.enter()
        .append('line')
        .classed('link', true)
        .attr('x1', d => d.source.x + (nodeWidth / 2))
        .attr('y1', d => d.source.y + (nodeHeight))
        .attr('x2', d => d.target.x + (nodeWidth / 2))
        .attr('y2', d => d.target.y)

    link.transition()
        .attr('x1', d => d.source.x + (nodeWidth / 2))
        .attr('y1', d => d.source.y + (nodeHeight))
        .attr('x2', d => d.target.x + (nodeWidth / 2))
        .attr('y2', d => d.target.y)

    link.exit()
        .remove()

      function click(d) {
          update({
              "name": "root",
              "children": [
                {
                    "name": "ORIG"
                },
                {
                  "name": "NEW"
                }
             ]
          });
      }
}

update(treeData);

  </script>
</body>
</html>

如果您想更多地查看数据绑定,我在这里整理了一下tutorial on data binding in D3,可能会有帮助。