I forked this simple tree example to demonstrate the very helpful set of each*
each
/ breadth-firsteachAfter
/ post-order traversaleachBefore
/ pre-order traversaltraversal methods in d3-hierarchy
.
The d3.tree layout implements the Reingold-Tilford algorithm for efficient, tidy arrangement of layered nodes. The depth of nodes is computed by distance from the root, leading to a ragged appearance. Radial orientations are also supported. Implementation based on work by Jeff Heer and Jason Davies using Buchheim et al.’s linear-time variant of the Reingold-Tilford algorithm. Data shows the Flare class hierarchy, also courtesy Jeff Heer.
Compare to this radial layout.
forked from timelyportfolio's block: Tidy Tree | Vis each* d3-hierarchy methods
xxxxxxxxxx
<meta charset="utf-8">
<style>
.node circle {
fill: #999;
}
.node text {
font: 10px sans-serif;
}
.node--internal circle {
fill: #555;
}
.node--internal text {
text-shadow: 0 1px 0 #fff, 0 -1px 0 #fff, 1px 0 0 #fff, -1px 0 0 #fff;
}
.link {
fill: none;
stroke: #555;
stroke-opacity: 0.4;
stroke-width: 1.5px;
}
</style>
<select id = "each-select">
<option value = "each">each</option>
<option value = "eachAfter">eachAfter</option>
<option value = "eachBefore">eachBefore</option>
</select>
<svg width="960" height="2000"></svg>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>
var svg = d3.select("svg"),
width = +svg.attr("width"),
height = +svg.attr("height"),
g = svg.append("g").attr("transform", "translate(40,0)");
var tree = d3.tree()
.size([height, width - 160]);
var stratify = d3.stratify()
.parentId(function(d) { return d.id.substring(0, d.id.lastIndexOf(".")); });
d3.csv("flare.csv", function(error, data) {
if (error) throw error;
var root = stratify(data)
.sort(function(a, b) { return (a.height - b.height) || a.id.localeCompare(b.id); });
var link = g.selectAll(".link")
.data(tree(root).descendants().slice(1))
.enter().append("path")
.attr("class", "link")
.attr("d", function(d) {
return "M" + d.y + "," + d.x
+ "C" + (d.y + d.parent.y) / 2 + "," + d.x
+ " " + (d.y + d.parent.y) / 2 + "," + d.parent.x
+ " " + d.parent.y + "," + d.parent.x;
});
var node = g.selectAll(".node")
.data(root.descendants())
.enter().append("g")
.attr("class", function(d) { return "node" + (d.children ? " node--internal" : " node--leaf"); })
.attr("transform", function(d) { return "translate(" + d.y + "," + d.x + ")"; })
node.append("circle")
.attr("r", 2.5);
node.append("text")
.attr("dy", 3)
.attr("x", function(d) { return d.children ? -8 : 8; })
.style("text-anchor", function(d) { return d.children ? "end" : "start"; })
.text(function(d) { return d.id.substring(d.id.lastIndexOf(".") + 1); });
// there is probably a better way doing this,
// but to ease lookup of svg dom element from node in hierarchy
// we will attach the node svg g dom element in the hierarchy
(function() {
var nodes = node.nodes();
var i = 0;
root.each(function(d) {d.node=nodes[i];i++;})
})();
// wire it to the select input
d3.select("#each-select").on("input", function(){
visEach(root, node, this.value);
})
// start automatically with each
setTimeout(
function(){
visEach(root, node, d3.select("#each-select").node().value);
},
200
);
});
function resetNodes(node) {
node.selectAll("*").interrupt();
node.selectAll("circle,text").style("fill","black");
}
function visEach(root, node, eachMethod) {
resetNodes(node);
var counter = 0;
root[eachMethod](function(d) {
d3.select(d.node)
.selectAll('circle,text')
.transition()
.delay(counter*200)
.style("fill","red");
counter++;
});
}
</script>
https://d3js.org/d3.v4.min.js