Skip to content

Instantly share code, notes, and snippets.

@topologicallytony
Last active January 6, 2017 03:27
Show Gist options
  • Save topologicallytony/dcad982821f737ce81df963a50692177 to your computer and use it in GitHub Desktop.
Save topologicallytony/dcad982821f737ce81df963a50692177 to your computer and use it in GitHub Desktop.
Sierpinski Triangle
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Sierpinski Triangle</title>
<!-- D3.js -->
<script src="https://d3js.org/d3.v4.min.js"></script>
<!-- Latest compiled and minified CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css">
<style type="text/css">
.line {
fill: none;
stroke: steelblue;
stroke-width: 1px;
}
.base_line {
fill: none;
stroke: steelblue;
stroke-width: 1px;
}
</style>
</head>
<body>
<div>
Click to Iterate
</div>
<script type="text/javascript">
//Basic idea is you have 2 datasets
//The first holds line segments that are drawn
//The second holds all the triangles that are iterated on
//Width and height of the visualization
var w = 500;
var h = 500;
//How much skew? 0.5 means sierpinski
var skew = 0.5;
//padding creates a buffer of white space around the chart to make it a little easier to look at
var padding = 15;
//Create the scales used to map the set
var xScale = d3.scaleLinear()
.domain([-.5, 1.5])
.range([padding, w - padding]);
var yScale = d3.scaleLinear()
.domain([-1, 1])
.range([h - padding, padding]);
//Create a canvas to display the chart on
var svg = d3.select("body").append("svg")
.attr("width", w)
.attr("height", h);
//Create group elements to layer the svg
//This is an easy way to make sure things you want on top are on top, and things you want behind stay behind
var layer1 = svg.append('g');
var layer2 = svg.append('g');
var layer3 = svg.append('g');
//This function will iterate the koch snowflake and is called on mouse click
function step() {
//temp_dataset holds the most recently displayed iteration
temp_dataset = triangles;
//dataset will get loaded with the next iteration
triangles = [];
//How many triangles we need to iterate on
var len = temp_dataset.length;
//For each triangle, add an inscribed triangle
for (var i = 0; i < len; i++) {
//get the endpoints of the current triangle
var x1 = temp_dataset[i][0];
var y1 = temp_dataset[i][1];
var x2 = temp_dataset[i][2];
var y2 = temp_dataset[i][3];
var x3 = temp_dataset[i][4];
var y3 = temp_dataset[i][5];
//find points at skew
var x13_new = x1 + ((x3 - x1) * skew);
var y13_new = y1 + ((y3 - y1) * skew);
var x12_new = x2 + ((x1 - x2) * skew);
var y12_new = y2 + ((y1 - y2) * skew);
var x23_new = x3 + ((x2 - x3) * skew);
var y23_new = y3 + ((y2 - y3) * skew);
//Store the 3 new triangles, and 3 new line segments
triangles.push([x1, y1, x12_new, y12_new, x13_new, y13_new]);
triangles.push([x2, y2, x23_new, y23_new, x12_new, y12_new]);
triangles.push([x3, y3, x13_new, y13_new, x23_new, y23_new]);
lines.push([x1, y1, x2, y2, x3, y3]);
lines.push([x2, y2, x3, y3, x1, y1]);
lines.push([x3, y3, x1, y1, x2, y2]);
}
}
function display() {
//Draw all the lines
var line = layer2.selectAll(".line").data(lines);
line
.attr("x1", function(d){return xScale(d[0] + ((d[4] - d[0]) * skew));})
.attr("y1", function(d){return yScale(d[1] + ((d[5] - d[1]) * skew));})
.attr("x2", function(d){return xScale(d[2] + ((d[0] - d[2]) * skew));})
.attr("y2", function(d){return yScale(d[3] + ((d[1] - d[3]) * skew));});
line.enter().append("line")
.attr("x1", function(d){return xScale(d[0]);})
.attr("y1", function(d){return yScale(d[1]);})
.attr("x2", function(d){return xScale(d[2]);})
.attr("y2", function(d){return yScale(d[3]);})
.transition()
.duration(1250)
.attr("x1", function(d){return xScale(d[0] + ((d[4] - d[0]) * skew));})
.attr("y1", function(d){return yScale(d[1] + ((d[5] - d[1]) * skew));})
.attr("x2", function(d){return xScale(d[2] + ((d[0] - d[2]) * skew));})
.attr("y2", function(d){return yScale(d[3] + ((d[1] - d[3]) * skew));})
.attr("class", "line");
}
//initialize the datasets
var temp_dataset = [];
//lines will hold all the line segments
//initialize with an equilateral triangle.
var lines = [
[0, 0, Math.cos(Math.PI / 3), Math.sin(Math.PI / 3)],
[Math.cos(Math.PI / 3), Math.sin(Math.PI / 3), 1, 0],
[1, 0, 0, 0]
];
var triangles = [
[0, 0, 1, 0, Math.cos(Math.PI / 3), Math.sin(Math.PI / 3)]
];
layer2.selectAll(".base_line").data(lines).enter().append("line")
.attr("x1", function(d){return xScale(d[0]);})
.attr("y1", function(d){return yScale(d[1]);})
.attr("x2", function(d){return xScale(d[2]);})
.attr("y2", function(d){return yScale(d[3]);})
.attr("class", "base_line");
lines = [];
d3.select("body")
.on("click", function() {
step();
display();
});
d3.select("body")
.on("touchstart", function() {
step();
display();
});
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment