1

Im learning d3 js layout and having difficulty in adding node to the tree layout.

Hoping for a way of adding dynamic node(children) after clicking the parent node.

My current implementation do add the node, but instead of updating it, it added new children and keep the child from before.

Can someone help me understand the problem and a correct way of approaching this.

Here is my code and my Fiddle (click on the root node):

HTML

<div id="body"> 
</div>
<script src="https://d3js.org/d3.v3.min.js" charset="utf-8"></script>

JS

var margin = {top: 100, right: 50, bottom: 100, left: 50},
    width = 900 - margin.left - margin.right,
    height = 500 - margin.top - margin.bottom;


var tree = d3.layout.tree()
    .separation(function(a, b) { return a.children === b.children ? 1 : 1.2; })
    .size([width, height]); 

 var svg = d3.select("body")
    .attr("bgcolor", "#fff")
    .append("svg")
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom)
    .append("g")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

var dataOne = {
  "name": "Mike and Marcia",
  "children": [
    {
      "name": "Children",
      "children": [
        { "name": "Mikael" }
      ]
    }
  ]
};

var drawTree = function(source){

 var nodes = tree.nodes(source);
 var node = svg.selectAll(".node")
    .data(nodes)
    .enter()
    .append("g");

 var boxes = node.selectAll('g')
            .data(nodes)
            .enter()
            .append('g')
            .append('rect')
            .attr("width", 50)
            .attr("height", 40)
            .attr("fill", "tan")
            .attr("x", function(d) { return d.x; })
            .attr("y", function(d) { return d.y + 50; });


  boxes.on("click", function(d,i){
   clickOutside(d);
  });


};

var clickOutside = function(value){
  var newData = {
        "name": "Mike and Marcia",
        "children": [{
            "name": "Children",
            "children": [{
                "name": "Mikael"
            }]
        },{
            "name": "Pets",
            "children": []
        }]
     };

 drawTree(newData);    
 console.log(value);

}

drawTree(dataOne);

1 Answer 1

1

The problem is that you are drawing the new graph over the old graph.

That is the reason why you get the impression that its adding child to the old parent.

So the correct approach would be to

  1. draw the graph
  2. remove all nodes that is not required.

So 1st point

 var nodedata = svg.selectAll(".node")
    .data(nodes, function(d){ /* function which return the Unique id of each node */ return d.name;})

    //make all the nodes.
    nodedata.enter().append('g')
            .attr("class", "node")
            .append('rect')
            .attr("width", 50)
            .attr("height", 40)
            .attr("fill", "tan")
            .attr("x", function(d) { return d.x; })
            .attr("y", function(d) { return d.y + 50; })
            .on("click", function(d,i){
             clickOutside(d);
            });

2nd point

Remove all nodes which are intersection of first set of passed data and the second set of passed data.

nodedata.exit().remove();

Last point add children to parent

You can change the JSON

var dataOne = {
  "name": "Mike and Marcia",
  "children": [
    {
      "name": "Children",
      "children": [
        { "name": "Mikael" }
      ]
    }
  ]
};

Add whatever structure JSON and pass it down your drawTree function

Working code here

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you so much for the short but comprehensive explanation @Cyril. That's exactly how i want it to work. I do have follow up question to further understand d3 concepts. Is it okay if i directed the question to you?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.