user2596192
user2596192

Reputation: 21

Make the svg follow a hierarchical structure

I'm new with d3 and I was wondering if it is possible to make the svg follow the hierarchical structure of a tree.

Let's say that I have a json like that :

{
       "name": "root",
       "children": [
           {
               "name" : "child1",
               "children": [
                   {
                       "name": "child1_1"
                   },
                   {
                       "name": "child1_2"
                   }
               ]
           },
           {
               "name": "child2",
               "children": [
                   {
                  "name": "child2_1"
                   },
                   {
                       "name": "child2_2"
                   }
               ]
           }   
        ]
}

How can I have a svg structure like this :

<g class="root">
  <g class="child1">
    <g class="child1_1">
    </g>
    <g class="child1_2">
    </g>
  </g>
  <g class="child2">
    <g class="child2_1">
    </g>
    <g class="child2_2">
    </g>
  </g>
</g>

I've tried stuff like that :

var w = 960,
    h = 2000,
    i = 0,
    root;

var diagonal = d3.svg.diagonal()
    .projection(function(d) { return [d.y, d.x]; });

var vis = d3.select("#chart").append("svg:svg")
    .attr("width", w)
    .attr("height", h)
    .append("svg:g")
    .attr("transform", "translate(40,0)");

d3.json(
    './small_tree.json',
    function(json) {
        json.x0 = 800;
        json.y0 = 0;
        update(root = json);
    }
);
function update(source) {

    var nodes = tree.nodes(root);
    var child = vis.selectAll('g.child_node')
        .data(nodes,function(d){return d.children;})
        .enter()
        .append('g')
        .attr("class", "child_node");
}

And I'm getting a tag for the children of the root node, but I don't know how to recursively create nested group for children of children.

Anyone have an idea ?

Thanks,

Rem

Upvotes: 2

Views: 1557

Answers (1)

nrabinowitz
nrabinowitz

Reputation: 55688

D3 doesn't natively handle recursion, and it looks like the standard hierarchical layouts don't, in general, create nested structures. Instead, you need to recurse in your own code. Here's one implementation:

// simple offset, just to make things visible
var offset = 0;

// recursion function
function addNode(selection, depth) {
   // set the current children as the data array
   var nodeGroup = selection.selectAll('g.child_node')
       .data(function(d) { return d.children })
     .enter()
       // add a node for each child
       .append('g')
       .attr("class", "child_node")
       // very simple depth-based placement
       .attr("transform", "translate(" + (depth * 30) + "," +
            (++offset * 15) + ")");

    nodeGroup.append("text")
       .attr("dy", "1em")
       .text(function(d) { return d.name });

    // recurse - there might be a way to ditch the conditional here
    nodeGroup.each(function(d) {
        if (d.children) nodeGroup.call(addNode, depth + 1);
    });
}

d3.json(
    './small_tree.json',
    function(root) {
        // kick off the recursive append
        vis
            .datum({ children: [root] })
            .call(addNode, 0);
    }
}

See fiddle: http://jsfiddle.net/nrabinowitz/ELYWa/

Upvotes: 1

Related Questions