Permalink
Browse files

Merge branch 'tree'

  • Loading branch information...
2 parents a262ba7 + 597443b commit 915be32ef7117c688652609eb7e6de6e32d7b024 @mbostock mbostock committed Apr 11, 2011
View
@@ -105,6 +105,7 @@ d3.layout.js: \
src/layout/pie.js \
src/layout/stack.js \
src/layout/hierarchy.js \
+ src/layout/tree.js \
src/layout/treemap.js \
src/end.js
View
2 d3.js
@@ -1,4 +1,4 @@
-(function(){d3 = {version: "1.9.1"}; // semver
+(function(){d3 = {version: "1.10.0"}; // semver
if (!Date.now) Date.now = function() {
return +new Date();
};
View
@@ -739,6 +739,244 @@ function d3_layout_hierarchyValue(d) {
function d3_layout_hierarchySort(a, b) {
return b.value - a.value;
}
+// Node-link tree diagram using the Reingold-Tilford "tidy" algorithm
+d3.layout.tree = function() {
+ var hierarchy = d3.layout.hierarchy(),
+ separation = d3_layout_treeSeparation,
+ size = [1, 1]; // width, height
+
+ function tree(d, i) {
+ var nodes = hierarchy.call(this, d, i),
+ root = nodes[0];
+
+ function firstWalk(node, previousSibling) {
+ var children = node.children,
+ layout = node._tree;
+ if (children) {
+ var n = children.length,
+ firstChild = children[0],
+ previousChild,
+ ancestor = firstChild,
+ child,
+ i = -1;
+ while (++i < n) {
+ child = children[i];
+ firstWalk(child, previousChild);
+ ancestor = apportion(child, previousChild, ancestor);
+ previousChild = child;
+ }
+ d3_layout_treeShift(node);
+ var midpoint = .5 * (firstChild._tree.prelim + child._tree.prelim);
+ if (previousSibling) {
+ layout.prelim = previousSibling._tree.prelim + separation(node, previousSibling);
+ layout.mod = layout.prelim - midpoint;
+ } else {
+ layout.prelim = midpoint;
+ }
+ } else {
+ if (previousSibling) {
+ layout.prelim = previousSibling._tree.prelim + separation(node, previousSibling);
+ }
+ }
+ }
+
+ function secondWalk(node, x) {
+ node.x = node._tree.prelim + x;
+ var children = node.children;
+ if (children) {
+ var i = -1,
+ n = children.length;
+ x += node._tree.mod;
+ while (++i < n) {
+ secondWalk(children[i], x);
+ }
+ }
+ }
+
+ function apportion(node, previousSibling, ancestor) {
+ if (previousSibling) {
+ var vip = node,
+ vop = node,
+ vim = previousSibling,
+ vom = node.parent.children[0],
+ sip = vip._tree.mod,
+ sop = vop._tree.mod,
+ sim = vim._tree.mod,
+ som = vom._tree.mod,
+ shift;
+ while (vim = d3_layout_treeRight(vim), vip = d3_layout_treeLeft(vip), vim && vip) {
+ vom = d3_layout_treeLeft(vom);
+ vop = d3_layout_treeRight(vop);
+ vop._tree.ancestor = node;
+ shift = vim._tree.prelim + sim - vip._tree.prelim - sip + separation(vim, vip);
+ if (shift > 0) {
+ d3_layout_treeMove(d3_layout_treeAncestor(vim, node, ancestor), node, shift);
+ sip += shift;
+ sop += shift;
+ }
+ sim += vim._tree.mod;
+ sip += vip._tree.mod;
+ som += vom._tree.mod;
+ sop += vop._tree.mod;
+ }
+ if (vim && !d3_layout_treeRight(vop)) {
+ vop._tree.thread = vim;
+ vop._tree.mod += sim - sop;
+ }
+ if (vip && !d3_layout_treeLeft(vom)) {
+ vom._tree.thread = vip;
+ vom._tree.mod += sip - som;
+ ancestor = node;
+ }
+ }
+ return ancestor;
+ }
+
+ // Initialize temporary layout variables.
+ d3_layout_treeVisitAfter(root, function(node, previousSibling) {
+ node._tree = {
+ ancestor: node,
+ prelim: 0,
+ mod: 0,
+ change: 0,
+ shift: 0,
+ number: previousSibling ? previousSibling._tree.number + 1 : 0
+ };
+ });
+
+ // Compute the layout using Buchheim et al.'s algorithm.
+ firstWalk(root);
+ secondWalk(root, -root._tree.prelim);
+
+ // Compute the left-most, right-most, and depth-most nodes for extents.
+ var left = d3_layout_treeSearch(root, d3_layout_treeLeftmost),
+ right = d3_layout_treeSearch(root, d3_layout_treeRightmost),
+ deep = d3_layout_treeSearch(root, d3_layout_treeDeepest),
+ x0 = left.x - separation(left, right) / 2,
+ x1 = right.x + separation(right, left) / 2,
+ y1 = deep.depth;
+
+ // Clear temporary layout variables; transform x and y.
+ d3_layout_treeVisitAfter(root, function(node) {
+ node.x = (node.x - x0) / (x1 - x0) * size[0];
+ node.y = node.depth / y1 * size[1];
+ delete node._tree;
+ });
+
+ return nodes;
+ }
+
+ tree.sort = d3.rebind(tree, hierarchy.sort);
+ tree.children = d3.rebind(tree, hierarchy.children);
+ tree.value = d3.rebind(tree, hierarchy.value);
+
+ tree.separation = function(x) {
+ if (!arguments.length) return separation;
+ separation = x;
+ return tree;
+ };
+
+ tree.size = function(x) {
+ if (!arguments.length) return size;
+ size = x;
+ return tree;
+ };
+
+ return tree;
+};
+
+function d3_layout_treeSeparation(a, b) {
+ return a.parent == b.parent ? 1 : 2;
+}
+
+// function d3_layout_treeSeparationRadial(a, b) {
+// return (a.parent == b.parent ? 1 : 2) / a.depth;
+// }
+
+function d3_layout_treeLeft(node) {
+ return node.children ? node.children[0] : node._tree.thread;
+}
+
+function d3_layout_treeRight(node) {
+ return node.children ? node.children[node.children.length - 1] : node._tree.thread;
+}
+
+function d3_layout_treeSearch(node, compare) {
+ var children = node.children;
+ if (children) {
+ var child,
+ n = children.length,
+ i = -1;
+ while (++i < n) {
+ if (compare(child = d3_layout_treeSearch(children[i], compare), node) > 0) {
+ node = child;
+ }
+ }
+ }
+ return node;
+}
+
+function d3_layout_treeRightmost(a, b) {
+ return a.x - b.x;
+}
+
+function d3_layout_treeLeftmost(a, b) {
+ return b.x - a.x;
+}
+
+function d3_layout_treeDeepest(a, b) {
+ return a.depth - b.depth;
+}
+
+function d3_layout_treeVisitAfter(node, callback) {
+ function visit(node, previousSibling) {
+ var children = node.children;
+ if (children) {
+ var child,
+ previousChild = null,
+ i = -1,
+ n = children.length;
+ while (++i < n) {
+ child = children[i];
+ visit(child, previousChild);
+ previousChild = child;
+ }
+ }
+ callback(node, previousSibling);
+ }
+ visit(node, null);
+}
+
+function d3_layout_treeShift(node) {
+ var shift = 0,
+ change = 0,
+ children = node.children,
+ i = children.length,
+ child;
+ while (--i >= 0) {
+ child = children[i]._tree;
+ child.prelim += shift;
+ child.mod += shift;
+ shift += child.shift + (change += child.change);
+ }
+}
+
+function d3_layout_treeMove(ancestor, node, shift) {
+ ancestor = ancestor._tree;
+ node = node._tree;
+ var change = shift / (node.number - ancestor.number);
+ ancestor.change += change;
+ node.change -= change;
+ node.shift += shift;
+ node.prelim += shift;
+ node.mod += shift;
+}
+
+function d3_layout_treeAncestor(vim, node, ancestor) {
+ return vim._tree.ancestor.parent == node.parent
+ ? vim._tree.ancestor
+ : ancestor;
+}
// Squarified Treemaps by Mark Bruls, Kees Huizing, and Jarke J. van Wijk
d3.layout.treemap = function() {
var hierarchy = d3.layout.hierarchy(),
View

Large diffs are not rendered by default.

Oops, something went wrong.
View

Large diffs are not rendered by default.

Oops, something went wrong.
View
@@ -35,6 +35,8 @@
<li><a href="stream/stream.html">stream</a></li>
<li><a href="stream/stack.html">stack</a></li>
<li><a href="symbol-map/symbol-map.html">symbol-map</a></li>
+ <li><a href="tree/tree.html">tree</a></li>
+ <li><a href="tree/tree-radial.html">tree-radial</a></li>
<li><a href="treemap/treemap.html">treemap</a></li>
<li><a href="voronoi/voronoi.html">voronoi</a></li>
<li><a href="zoom/zoom.html">zoom</a></li>
Oops, something went wrong.

0 comments on commit 915be32

Please sign in to comment.