使svg遵循层次结构

时间:2013-07-18 15:30:12

标签: svg d3.js

我是d3的新手,我想知道是否有可能让svg遵循树的层次结构。

让我们说我有一个像这样的json:

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

我怎样才能拥有这样的svg结构:

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

我尝过类似的东西:

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");
}

我正在为根节点的子节点获取标记,但我不知道如何以递归方式为子节点的子节点创建嵌套组。

有人有想法吗?

谢谢,

雷姆

1 个答案:

答案 0 :(得分:1)

D3本身并不处理递归,看起来标准的分层布局通常不会创建嵌套结构。相反,您需要在自己的代码中进行递归。这是一个实现:

// 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);
    }
}

请参阅小提琴:http://jsfiddle.net/nrabinowitz/ELYWa/