Skip to content

Instantly share code, notes, and snippets.

@treboresque
Last active August 19, 2016 01:36
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save treboresque/28476a3ae1297af52d95 to your computer and use it in GitHub Desktop.
Save treboresque/28476a3ae1297af52d95 to your computer and use it in GitHub Desktop.
Sierpinski Charlet
<!DOCTYPE html>
<html >
<head>
<title>Sierpinski</title>
<link rel="stylesheet" href="./style.css">
</head>
<body>
<div class="chart"></div>
</body>
<script src="http://d3js.org/d3.v3.min.js" type="text/javascript"></script>
<script src="https://rawgit.com/twitter/d3kit/v0.1.0/dist/d3kit.min.js" type="text/javascript"></script>
<script src="main.js" type="text/javascript"></script>
</html>
var DEFAULT_OPTIONS = {
margin: {top: 20, right: 20, bottom: 20, left: 20}
};
// create sierpinski
var sierpinski = new Sierpinski(6);
var chart = new d3Kit.Skeleton('.chart', DEFAULT_OPTIONS)
.autoResize('both')
.on('resize', onResize);
var options = chart.options();
// add sierpinski to
chart.getRootG()
.call(sierpinski.enter);
// handle resize
function onResize() {
var width = chart.getInnerWidth ();
var height = chart.getInnerHeight();
var center = [options.margin.left + width / 2, options.margin.top + height / 2];
sierpinski.property('edgeLength', d3.min([width, height]));
chart.getRootG()
.attr('transform', 'translate(' + center + ')')
.call(sierpinski.update);
}
// sierpinski chartlet
function Sierpinski(depth, color) {
// constants
var ANGLES = d3.range(0, 360, 120).map(function(d) {return degreesToRadians(d + 30);});
var TRIANGLE = 'M P0 L P1 L P2 z';
var EDGE_RADIUS_RATIO = Math.sqrt(3) / 3;
color = color || [255, 128, 128];
var events = [];
var children = depth > 0 ? new Sierpinski(depth - 1) : null;
var charlet = d3Kit.Chartlet(enter, update, exit, events);
function enter(selection, onEnd) {
// if bottom out on depth, actually add path to plot triangles
if (depth == 0) {
selection
.append('path')
.classed('triangle', true)
.attr('d', function() {
return createTrianglePath(0);
})
.style('fill', triangleColor);
}
// otherwise add children
else {
// create 3 groups one for each child sierpinski triangle
var groups = selection.selectAll('g.child')
.data(ANGLES)
.enter()
.append('g')
.classed('child', true)
.attr('transform', 'translate(0, 0)');
groups.call(children.enter);
}
onEnd();
}
function update(selection, onEnd) {
var radius = charlet.getPropertyValue('edgeLength') * EDGE_RADIUS_RATIO;
// if children, update those
if (children) {
// update done when children update is done
children.on('updateDone', onEnd);
selection.selectAll('g.child')
.transition()
.attr('transform', function(d) {
var x = Math.cos(d) * radius / 2;
var y = Math.sin(d) * radius / 2 + radius / 8;
return 'translate(' + x + ', ' + y + ')';
});
children.property('edgeLength', charlet.getPropertyValue('edgeLength') / 2);
selection.selectAll('g.child')
.call(children.update);
}
// otherwise update the triangle
else {
selection.selectAll('path.triangle')
.transition()
.attr('d', function() {
return createTrianglePath(radius);
})
.each('end', onEnd);
}
}
function exit(selection, onEnd) {
onEnd();
}
function triangleColor(d, i) {
var localColor = color.map(function(_d, _i) {return i != _i ? _d * .7 : _d;});
return d3.rgb(localColor[0], localColor[1], localColor[2]);
};
// join a pattern and a set of x,y points
function pathPoints(pattern, points) {
return points.reduce(function(acc, point, i) {
return acc.replace('P' + i, point.x + ' ' + point.y);
}, pattern);
}
// convert degrees to radians
function degreesToRadians(degrees) {
return degrees / 180 * Math.PI;
}
// given a radius, create a triangel around the origin
function createTrianglePath(radius) {
var points = ANGLES.map(function(angle) {
return {
x: Math.cos(angle) * radius,
y: Math.sin(angle) * radius + radius / 4,
};
});
return pathPoints(TRIANGLE, points);
}
return charlet;
}
html {
margin: 0px;
padding: 0px;
width: 100%;
height: 100%;
}
body {
margin: 0px;
padding: 0px;
width: 100%;
height: 100%;
}
.chart {
width: 100%;
height: 100%;
}
path {
stroke: #888;
stroke-width: 1px;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment