Skip to content

Instantly share code, notes, and snippets.

@renemonroy
Forked from sim0nf/README.md
Created January 22, 2016 15:54
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save renemonroy/a785e09b67ce0282813c to your computer and use it in GitHub Desktop.
Save renemonroy/a785e09b67ce0282813c to your computer and use it in GitHub Desktop.
Dynamic Node-Link Tree (D3)

This is an example of building a tree layout using the Reingold-Tilford "tidy" algorithm, as described in "Tidier Drawings of Trees". As each new element is added to the graph, it animates in, starting at the previous position of the parent node. Thus, the existing nodes and the new node transition smoothly to their new positions. The animation stops when 500 nodes have been added to the tree.

Built with D3.js.

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
<title>Node-Link Tree</title>
<script type="text/javascript" src="http://mbostock.github.com/d3/d3.js"></script>
<script type="text/javascript" src="http://mbostock.github.com/d3/d3.layout.js"></script>
<style type="text/css">
.node {
stroke: #fff;
stroke-width: 2px;
}
.link {
fill: none;
stroke: #000;
}
</style>
</head>
<body>
<script type="text/javascript">
var sfid = 1000;
var w = 960,
h = 500,
root = {},
data = [root],
tree = d3.layout.tree().size([w - 20, h - 20]),
diagonal = d3.svg.diagonal(),
duration = 250,
timer = setInterval(update, duration);
var vis = d3.select("body").append("svg:svg")
.attr("width", w)
.attr("height", h)
.append("svg:g")
.attr("transform", "translate(10, 10)");
vis.selectAll("circle")
.data(tree(root))
.enter().append("svg:circle")
.attr("class", "node")
.attr("r", 3.5)
.attr("cx", x)
.attr("cy", y);
function update() {
if (data.length >= 100) {
data.splice(50, 1);
}
// Add a new datum to a random parent.
var d = {id: "ohai"+(++sfid)}, parent = data[~~(Math.random() * data.length)];
if (parent.children) parent.children.push(d); else parent.children = [d];
data.push(d);
// Compute the new tree layout. We'll stash the old layout in the data.
var nodes = tree(root);
// Update the nodes…
var node = vis.selectAll("circle.node")
.data(nodes, nodeId);
// Enter any new nodes at the parent's previous position.
node.enter().append("svg:circle")
.attr("class", "node")
.attr("r", 3.5)
.attr("cx", function(d) { return d.parent.data.x0; })
.attr("cy", function(d) { return d.parent.data.y0; })
.transition()
.duration(duration)
.attr("cx", x)
.attr("cy", y);
node.exit().remove();
// Transition nodes to their new position.
node.transition()
.duration(duration)
.attr("cx", x)
.attr("cy", y);
// Update the links…
var link = vis.selectAll("path.link")
.data(tree.links(nodes), linkId);
// Enter any new links at the parent's previous position.
link.enter().insert("svg:path", "circle")
.attr("class", "link")
.attr("d", function(d) {
var o = {x: d.source.data.x0, y: d.source.data.y0};
return diagonal({source: o, target: o});
})
.transition()
.duration(duration)
.attr("d", diagonal);
// Transition links to their new position.
link.transition()
.duration(duration)
.attr("d", diagonal);
}
function linkId(d) {
return d.source.data.id + "-" + d.target.data.id;
}
function nodeId(d) {
return d.data.id;
}
function x(d) {
return d.data.x0 = d.x;
}
function y(d) {
return d.data.y0 = d.y;
}
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment