(function() { var distance, margin, max_depth, rand_tree, width, zip; rand_tree = function(d, MAX_D, MAX_N) { /* return a tree with maximum depth MAX_D that branches with probability p at most N times for each internal node. p starts from 1 and decreases linearly with d, reaching zero at MAX_D */ /* this still seems to be necessary to avoid infinte recursion (floating point precision?) */ var children, i, n, p; if (d === MAX_D) { return { children: [] }; } p = (MAX_D - d) / MAX_D; /* if the tree branches, at least one branch is made */ n = Math.floor(Math.random() * MAX_N) + 1; children = []; for (i = 0; 0 <= n ? i < n : i > n; 0 <= n ? i++ : i--) { if (p >= Math.random()) { children.push(rand_tree(d + 1, MAX_D, MAX_N)); } else { children.push({ children: [] }); } } return { children: children }; }; width = 960; distance = 14; margin = 40; max_depth = 10; d3.select(self.frameElement).style('height', "" + (2 * margin) + "px"); /* python-like zip */ zip = function() { var args, shortest; args = [].slice.call(arguments); shortest = args.length === 0 ? [] : args.reduce((function(a, b) { if (a.length < b.length) { return a; } else { return b; } })); return shortest.map((function(_, i) { return args.map(function(array) { return array[i]; }); })); }; window.main = function() { /* create the tree */ var diagonal, height, link, links, node, nodes, root, rsort, tcmp, tree, vis; root = rand_tree(1, max_depth, 3); /* sort the tree */ tcmp = function(a, b) { var ai, bi, ci, _i, _len, _ref, _ref2; _ref = zip(a.children, b.children); for (_i = 0, _len = _ref.length; _i < _len; _i++) { _ref2 = _ref[_i], ai = _ref2[0], bi = _ref2[1]; ci = tcmp(ai, bi); if (ci !== 0) return ci; } return b.children.length - a.children.length; }; rsort = function(t) { var c, _i, _len, _ref; _ref = t.children; for (_i = 0, _len = _ref.length; _i < _len; _i++) { c = _ref[_i]; rsort(c); } return t.children.sort(tcmp); }; rsort(root); /* initialize the layout */ tree = d3.layout.tree().size([0, 0]); nodes = tree.nodes(root); links = tree.links(nodes); height = 0; /* force the layout to display nodes in fixed rows and columns */ nodes.forEach(function(n) { if ((n.parent != null) && n.parent.children[0] !== n) height += distance; n.x = height; return n.y = n.depth * (width / max_depth); }); /* draw the vis */ diagonal = d3.svg.diagonal().projection(function(d) { return [d.y, d.x]; }); vis = d3.select('body').append('svg').attr('width', width).attr('height', height + 2 * margin).append('g').attr('transform', "translate(" + margin + "," + margin + ")"); link = vis.selectAll('path.link').data(links).enter().append('path').attr('class', 'link').attr('d', diagonal); node = vis.selectAll('g.node').data(nodes).enter().append('g').attr('class', 'node').attr('transform', function(d) { return "translate(" + d.y + "," + d.x + ")"; }); node.append('circle').attr('r', 4).attr('fill', function(d) { if (d.children) { return 'white'; } else { return 'steelblue'; } }); /* adapt bl.ocks.org frame to the tree */ return d3.select(self.frameElement).transition().duration(500).style('height', "" + (height + 2 * margin) + "px"); }; }).call(this);