Recursive text

HTML

<script src="http://d3js.org/d3.v3.min.js"></script>
<script src="http://underscorejs.org/underscore-min.js"></script>
<html>
    
    <body>
        <svg/>
    </body>

</html>

JavaScript

var data = { children: [{
        txt: "a", children: [{
            txt: "aa", children: [{
                txt: "aaa"}, {
                txt: "aab"}]}, {
            txt: "ab"}]}, {
        txt: "b", children: [{
            txt: "ba"}, {
            txt: "bb"}, {
            txt: "bc"}]}, {
        txt: "c"}]};

var svg = d3.selectAll("svg");

svg.attr({ width: 500, height: 500});

var recurse = svg.selectAll("g.level0")
		.data([data])
recurse.enter()
    .append("g").classed("level0", true)

recurse.exit().remove()

var maxLevels = 4;
for (var level = 0; level < maxLevels; level++) {

    var nextLevel = level + 1;

    var next = svg.selectAll("g.level" + level).filter(function (d) {
        return d.children !== undefined;
    });

    next.selectAll("g.level" + nextLevel)
        .data(function (d) { return d.children; })
        .enter().append("g")
        .attr("class", function (d) {
        	return "level" + nextLevel + " " + d.txt;
    	})
        .attr("transform", function (d, i) {
        	return "translate(" + (nextLevel * 25) + "," + (i * 10 * (5 - level) + 15) + ")";
    	});

    next.selectAll("text")
    	.data(function (d) {  return d.children; })
    	.enter().append("text")
        .attr("x", function (d, i, j) {  return nextLevel * 25;  })
        .attr("y", function (d, i, j) {
        	return j * (10 * (10 - level)) + (i+1) * 15;
    	})
        .attr("fill", "black")
    	.text(function (d) { return d.txt; });
}