Skip to content

Instantly share code, notes, and snippets.

@amoeba
Created February 5, 2015 23:50
Show Gist options
  • Select an option

  • Save amoeba/4acfb22c99e623d2c78d to your computer and use it in GitHub Desktop.

Select an option

Save amoeba/4acfb22c99e623d2c78d to your computer and use it in GitHub Desktop.
Random Right-Angled Trees
<!DOCTYPE html>
<meta charset="utf-8">
<h1>Random Trees</h1>
<p>Written by <a href="http://brycemecum.com/">Bryce Mecum</a></p>
<p>Code adapted from <a href="http://www.jasondavies.com/">Jason Davies</a> for generating right-angled trees and <a href="https://github.com/yuanyan/">yuanyan</a> for the Poisson distribution code.</p>
<p>
<button id="start" onclick="start()">Start</button>
<button id="stop" onclick="stop()">Stop</button>
</p>
<div id="tree"></div>
<style type="text/css">
.overlay {
fill: none;
pointer-events: all;
}
#tree
{
width: 600px;
height: 600px;
border: 1px solid black;
}
</style>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script type="text/javascript">
var running = false;
var timer = null;
var start = function() {
if(!running) {
running = true;
timer = window.setInterval(generate_nodes, 1000);
}
}
var stop = function() {
if(running) {
running = false;
window.clearInterval(timer);
}
}
function poisson(expectvalue) {
var n = 0,
limit = Math.exp(-expectvalue),
x = Math.random();
while(x > limit) {
n++;
x *= Math.random();
}
return n;
}
var add_nodes = function(node) {
depth++;
var num_children = poisson(3)
num_children += (depth == 1) ? 1 : 0
for(var i = 0; i < num_children; i++) {
node.children.push({
"children" : []
})
if (depth < 3)
{
add_nodes(node.children[i])
}
}
depth--;
}
var clear = function() {
var tree = document.getElementById("tree"),
child = tree.firstChild;
while(child) {
tree.removeChild(child);
child = tree.firstChild;
}
}
var nodes = {};
var depth = 0;
var generate_nodes = function() {
nodes = {"children":[]};
depth = 0;
clear();
add_nodes(nodes);
draw_tree(nodes);
}
rightAngleDiagonal = function() {
var projection = function(d) { return [d.x, d.y]; }
var path = function(pathData) {
return "M" + pathData[0] + ' ' + pathData[1] + " " + pathData[2];
}
function diagonal(diagonalPath, i) {
var source = diagonalPath.source,
target = diagonalPath.target,
midpointX = (source.x + target.x) / 2,
midpointY = (source.y + target.y) / 2,
pathData = [source, {x: target.x, y: source.y}, target];
pathData = pathData.map(projection);
return path(pathData)
}
return diagonal;
}
var draw_tree = function(nodes) {
var width = 600,
height = 600;
var tree = d3.layout.cluster()
.size([width, height])
.separation(function(a, b) {
return 1
});
var diagonal = rightAngleDiagonal();
var vis = d3.select("#tree").append("svg:svg")
.attr("width", width)
.attr("height", height)
.append("svg:g")
.attr("transform", "translate(0, 0)");
vis.append("rect")
.attr("class", "overlay")
.attr("width", width + width / 2)
.attr("height", height + height / 2);
var nodes = tree(nodes);
// Visit all nodes and adjust y pos width distance metric
var visitPreOrder = function(root, callback) {
callback(root)
if (root.children) {
for (var i = root.children.length - 1; i >= 0; i--){
visitPreOrder(root.children[i], callback)
};
}
}
visitPreOrder(nodes[0], function(node) {
node.rootDist = (node.parent ? node.parent.rootDist : 0) + 10
})
var rootDists = nodes.map(function(n) { return n.rootDist; });
var yscale = d3.scale.linear()
.domain([0, d3.max(rootDists) * 1.15])
.range([0, width * 1]);
visitPreOrder(nodes[0], function(node) {
node.y = yscale(node.rootDist)
})
var link = vis.selectAll("path.link")
.data(tree.links(nodes))
.enter().append("svg:path")
.attr("class", "link")
.attr("d", diagonal)
.attr("fill", "none")
.attr("stroke", "black")
.attr("stroke-width", "1px");
var node = vis.selectAll("g.node")
.data(nodes)
.enter().append("svg:g")
.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; })
node.append("svg:circle")
.attr("r", 4.5)
.attr('stroke', "black")
.attr('fill', "white")
.attr('stroke-width', '1px');
}
start();
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment