Skip to content

Instantly share code, notes, and snippets.

@cjhin
Last active August 7, 2016 20:36
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 cjhin/7d3455b76ebea88423d144e4878352a6 to your computer and use it in GitHub Desktop.
Save cjhin/7d3455b76ebea88423d144e4878352a6 to your computer and use it in GitHub Desktop.
trees
<!DOCTYPE html>
<meta charset="utf-8">
<style>
</style>
<body>
<svg width=960 height=500></svg>
</body>
<script src="//d3js.org/d3.v3.min.js"></script>
<script>
/*
Influenced by Miguel Ferreira:
https://codepen.io/MigFerreira/pen/RPZpgd
The original tree generation code is theirs.
I simplified some of the branch generation code and then added
code to allow for the animation.
*/
// Tree configuration
var branches = [];
var seed = {i: 0, x1: 480, y1: 700, x2: 480, y2: 425, a: 0, l: 75, d:0, children: []}; // a = angle, l = length, d = depth
var child_angle = 0.6; // Angle delta, all child branches will angle between 0 - 0.6 radians away from the parent angle
var child_length = 0.85; // Length delta (factor), all child branches will be 0.85 the length of the parent
var maxDepth = 10;
// Recursively create the tree
function create_branch(b) {
branches.push(b);
if (b.d === maxDepth)
return;
// two branches, flip the i from -1 to 1 to handle "left and right" branches
for(var i = -1; i < 2; i = i + 2) {
var ang = b.a + (Math.random() * child_angle * i);
var newB = {
i: branches.length,
x1: b.x2,
y1: b.y2,
x2: b.x2 + (b.l * child_length) * Math.sin( ang ),
y2: b.y2 - (b.l * child_length) * Math.cos( ang ),
a: ang,
orig_a: ang, // for book-keeping in animation
animating: false,
animate_counter: 0,
l: b.l * child_length,
d: b.d + 1,
children: []
};
b.children.push(newB.i)
create_branch(newB);
}
}
function draw() {
var color = d3.scale.linear()
.domain([0, maxDepth])
.range(["sienna","darkolivegreen"]);
d3.select('svg').selectAll('line')
.data(branches)
.enter()
.append('line')
.attr('id', function(d) { return "branch" + d.i; })
.attr('x1', function(d) { return d.x1; })
.attr('y1', function(d) { return d.y1; })
.attr('x2', function(d) { return d.x2; })
.attr('y2', function(d) { return d.y2; })
.style('stroke-width', function(d) { return parseInt((maxDepth - d.d + 2) * .5) + 'px'; })
.style('stroke', function(d) { return color(d.d); });
}
function animate() {
// this runs every second,
// every 10 seconds, stop triggering new animations for 10 seconds to allow things to settle
// this ends up giving the perception of "breezes"
animationCounter += 1;
if(animationCounter == 20) { animationCounter = 0; }
else if(animationCounter % 20 > 10) { return };
branches.forEach(function(branch) {
if(branch.animating == false && Math.random() < (branch.d / 500.0)) {
branch.animating = true;
moveBranch(branch);
}
});
}
function moveBranch(branch) {
modifier = branch.d / 15;
branch.a = branch.orig_a + (Math.random() * modifier - (modifier/2.0));
branch.x2 = branch.x1 + branch.l * Math.sin( branch.a );
branch.y2 = branch.y1 - branch.l * Math.cos( branch.a );
// This is probably "bad" d3 with regards to the data selection,
// it might even be easier to do this in jQuery or vanilla JS,
// the one benefit is to take advantage of d3 duration/ease animation functionality.
d3.select("#branch" + branch.i)
.data([branch])
.transition()
.duration(3000)
.ease('linear')
.attr('x1', function(d) { return d.x1; })
.attr('y1', function(d) { return d.y1; })
.attr('x2', function(d) { return d.x2; })
.attr('y2', function(d) { return d.y2; })
.each('end', function(d) {
if(d.animating == true) {
if(d.animate_counter < 3) { // keep "swaying" for 3 more frames
d.animate_counter += 1;
moveBranch(d);
} else {
d.animating = false;
d.animate_counter = 0;
}
}
});
// make the children move
branch.children.forEach(function(childIdx) {
var currChild = branches[childIdx];
currChild.x1 = branch.x2;
currChild.y1 = branch.y2;
moveBranch(currChild);
});
}
create_branch(seed);
draw();
var animationCounter = 0;
setInterval(animate, 1000);
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment