添加新的同级树时,树未更新节点位置 [英] Tree not updating nodes position when adding a new sibling

查看:103
本文介绍了添加新的同级树时,树未更新节点位置的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have the following code which draws a very simple tree. On clicking any node I'm calling the update function with new data to add a new child at the bottom of the tree.

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

The new node is added but the sibling node does not update it's position.

如果我注销节点:

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

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

I can see that the position x,y has been correctly updated but I get an overlapping effect where the previous node has not moved position.

我在这里做错了什么

<!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>

推荐答案

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

In a D3 data binding (d3.select(s).data(d)), we should be prepared to do 3 things:

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

  • enter, which adds a geom for each element in our data that's not yet in the selected DOM,

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

transition, which changes each selected element in the DOM using the new data, and

exit,如果我们的数据少于所选DOM中的元素,它将从DOM中删除元素.

exit, which removes elements from the DOM if we have less data than elements in the selected DOM.

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

In your case, you just need to update your update() function to perform each of these three actions:

<!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>

如果您想更多地查看数据绑定,我会整理一下有关D3中数据绑定的教程,这可能会有所帮助.

If you want to review data bindings more, I put together a little tutorial on data binding in D3 here that may help.

这篇关于添加新的同级树时,树未更新节点位置的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆