Skip to content

Instantly share code, notes, and snippets.

@gchan
Created December 9, 2013 23:56
Show Gist options
  • Save gchan/7883303 to your computer and use it in GitHub Desktop.
Save gchan/7883303 to your computer and use it in GitHub Desktop.
Koch Snowflake
<!DOCTYPE html>
<meta charset="utf-8">
<style>
polygon {
stroke: steelblue;
fill: none;
}
body {
font: 12px sans-serif;
}
</style>
<body>
<script src="//cdnjs.cloudflare.com/ajax/libs/d3/3.3.11/d3.min.js"></script>
<div id='controls'>
<button id='subtract'>-</button>
<button id='add'>+</button>
Level <strong id='level'>4</strong>
</div>
<script>
var margin = { top: 20, right: 20, bottom: 20, left: 20 },
width = 420 - margin.left - margin.right,
height = 480 - margin.top - margin.bottom;
var svg = d3.select("body").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var tan_sixty = Math.tan(Math.PI * 1 / 3);
var triangle_height = width / 2 * tan_sixty;
var root_triangle = [
{ x: width / 2, y: 0 },
{ x: 0, y: triangle_height },
{ x: width, y: triangle_height },
{ x: width / 2, y: 0 }
];
var data_cache = {
0: root_triangle
};
var level = 4;
function clone_obj(obj) {
return JSON.parse(JSON.stringify(obj));
}
function koch_iteration(v0, v1) {
var base_vector = {
x: v1.x - v0.x,
y: v1.y - v0.y
};
var orthogonal_vector = {
x: v0.y - v1.y,
y: v1.x - v0.x
};
var left, right, top;
left = {
x: v0.x + base_vector.x / 3,
y: v0.y + base_vector.y / 3
};
right = {
x: v1.x - base_vector.x / 3,
y: v1.y - base_vector.y / 3
};
top = {
x: v0.x + base_vector.x / 2 + tan_sixty * orthogonal_vector.x / 6,
y: v0.y + base_vector.y / 2 + tan_sixty * orthogonal_vector.y / 6
};
return [ left, top, right ];
}
function compute_points(levels) {
var data, new_points, previous_data;
var splice = Function.prototype.apply.bind(Array.prototype.splice);
if (data_cache[levels]) {
return data_cache[levels];
}
previous_data = compute_points(levels - 1);
data = clone_obj(previous_data);
previous_data.forEach(function(point, index, array) {
if (index + 1 >= array.length) {
return;
}
new_points = koch_iteration(point, array[index + 1]);
splice(data, [index * 4 + 1, 0].concat(new_points));
});
data_cache[levels] = data;
return data;
}
function vertex_to_string(vertex) {
return vertex.x + ", " + vertex.y;
}
function polygon_points(polygon) {
var points = "";
polygon.forEach(function(point) {
points += " " + vertex_to_string(point);
});
return points;
}
function render_koch_snowflake(levels) {
d3.select('#level').text(level);
svg.selectAll("*").remove();
svg.selectAll("polygon")
.data([compute_points(levels)])
.enter().append("polygon")
.attr('points', polygon_points);
}
function increase_level() {
level = Math.min(level + 1, 7);
render_koch_snowflake(level);
}
function decrease_level() {
level = Math.max(level - 1, 0);
render_koch_snowflake(level);
}
d3.select('#subtract').on('click', decrease_level);
d3.select('#add').on('click', increase_level);
render_koch_snowflake(level);
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment