Search code examples
javascriptsvgd3.jsdendrogram

Tree/dendrogram with elbow connectors in d3


I'm very new to d3.js (and SVG in general), and I want to do something simple: a tree/dendrogram with angled connectors.

I have cannibalised the d3 example from here:http://mbostock.github.com/d3/ex/cluster.html and I want to make it more like the protovis examples here:

I have made a start here: http://jsbin.com/ugacud/2/edit#javascript,html and I think it's the following snippet that's wrong:

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

However there's no obvious replacement, I could use d3.svg.line, but I don't know how to integrate it properly, and ideally I'd like an elbow connector....although I am wondering if I am using the wrong library for this, as a lot of the d3 examples I've seen are using the gravitational force to do graphs of objects instead of trees.


Solution

  • Replace the diagonal function with a custom path generator, using SVG's "H" and "V" path commands.

    function elbow(d, i) {
      return "M" + d.source.y + "," + d.source.x
          + "V" + d.target.x + "H" + d.target.y;
    }
    

    Note that the source and target's coordinates (x and y) are swapped. This example displays the layout with a horizontal orientation, however the layout always uses the same coordinate system: x is the breadth of the tree, and y is the depth of the tree. So, if you want to display the tree with the leaf (bottommost) nodes on the right edge, then you need to swap x and y. That's what the diagonal's projection function does, but in the above elbow implementation I just hard-coded the behavior rather than using a configurable function.

    As in:

    svg.selectAll("path.link")
        .data(cluster.links(nodes))
      .enter().append("path")
        .attr("class", "link")
        .attr("d", elbow);
    

    And a working example: