动态添加节点到D3树布局请求(在切换时)

时间:2015-12-31 08:21:44

标签: javascript d3.js

简介: 我正在尝试扩展d3 - 树布局。

我正在尝试通过ajax / setTimeout在切换事件上添加新节点。

我做了什么: 我成功地添加了同步的新节点: https://jsfiddle.net/xfj875vc/1/

我只更改了代码的两部分:

更改1(添加了将新子项添加到没有子项的节点的方法): function addNewNode(d, item) { d._children = d._children || []; d._children = d._children.concat(item); }

更改2(点击切换时调用addNewNode,我只为没有孩子的节点添加新节点):

 var nodeEnter = node.enter().append("svg:g")
      .attr("class", "node")
      .attr("transform", function(d) { return "translate(" + source.y0 + "," + source.x0 + ")"; })
      .on("click", function(d) {

            // change start
            var newItem;

            if (!d._children || d._children.length === 0) {
                newItem = [
                    {
                        "name": "i am new",
                        "children": [
                            { "name": "i am new child 1"},
                            { "name": "i am new child 2"}
                        ]
                    }
                ];
                addNewNode(d, newItem);
            }
            // change end

            toggle(d); update(d);
        });

2个问题:

  1. 在添加带子节点的节点时,它会显示并扩展所有内容,应尽量减少孩子。
  2. 如果我想在setTimeout中包装代码,则添加子代。但是,过渡和动画不能正常工作,d3也会扩展嵌套的孩子,你可以在这里看到它:
  3. https://jsfiddle.net/xfj875vc/3/(尝试点击一次以上)

    由于

1 个答案:

答案 0 :(得分:0)

首先是你的方法

   function addNewNode(d, item) {
        d._children = d._children || [];
        d._children = d._children.concat(item);
    }
  • 我们必须在此了解d._children has values when collapsedso d.children will be undefined。 反之,当节点扩展时。因此,我不确定您在上述代码中尝试做什么。

  • 其次这会放一个d._children.concat(item);数组内的数组。这是不期望的,因此我在下面的for循环中做同样的事情。

应该是:

function addNewNode(d, item) {
      item.forEach(function(i){
        if(d._children)
            d._children.push(i)//will add child to the closed node      
        else 
            d.children.push(i)//will add child to expanded node.
      })
}

接下来,我在数据中保留一个标志,表示不需要在点击时通过ajax加载。

{
 "name": "flare",
 "loaded" : true, //so this node flare will not be loaded on click via ajax
 "children": [
  {
   "name": "analytics",
   "loaded" : true,//so this node analytics will not be loaded on click via ajax
   "children": [...

最后在我的点击功能中,只有当此标志未定义时才会加载。

.on("click", function(d) {

  if (d.loaded === undefined) {\\do ajax
    setTimeout(function() {
      var newItem;

      newItem = [{
        "name": "i am new",
        "children": [{
          "name": "i am new child 1"
        }, {
          "name": "i am new child 2"
        }]
      }];
      addNewNode(d, newItem);
      d.loaded = true;//mark it as loaded so it doesn't load next time
      console.log("called", d)

      toggle(d);
      update(d);

    }, 1000)
  } else {//already loaded so dont do ajax
      toggle(d);
      update(d);
  }
});

工作代码here

如果您希望折叠加载的节点。

您可以像这样创建一个新节点:

      newItem = [{
        "name": "i am new",
        "children": [{
          "name": "i am new child 1"
        }, {
          "name": "i am new child 2"
        }]
      }];

而不是那样做

      newItem = [{
        "name": "i am new",
        "_children": [{ //note its changed to _children to show collapsed
          "name": "i am new child 1"
        }, {
          "name": "i am new child 2"
        }]
      }];

工作代码here

希望这有帮助!