Sierpinski carpet using a recursive D3 selection pattern. The cursor will automatically split areas further.
Last active
April 13, 2016 22:08
-
-
Save MrHen/1c2907a5f06e10d6595eeadaf51f4eef to your computer and use it in GitHub Desktop.
Sierpinski carpet
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
height: 729 | |
scrolling: true | |
license: MIT |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<html> | |
<head> | |
<link rel="stylesheet" href="style.css"> | |
</head> | |
<body> | |
<div id="sierpinski-carpet-container"></div> | |
<script src="//cdnjs.cloudflare.com/ajax/libs/d3/3.5.16/d3.min.js"></script> | |
<script src="//cdnjs.cloudflare.com/ajax/libs/lodash.js/4.6.1/lodash.min.js"></script> | |
<script src="script.js"></script> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var startingDepth = 3; | |
var batch = 10; | |
var tick = 300; | |
var root = { | |
x: 0, | |
y: 0, | |
resized: false, | |
depth: 0, | |
size: 729 | |
}; | |
// http://colorbrewer2.org/?type=sequential&scheme=BuGn&n=9 | |
var colors = d3.scale.quantize().domain([8, 0]).range(['#fff7fb', '#ece2f0', '#d0d1e6', '#a6bddb', '#67a9cf', '#3690c0', '#02818a', '#016c59', '#014636']); | |
var background = "#211"; | |
var svg = d3.select("#sierpinski-carpet-container") | |
.append("svg") | |
.attr("id", "sierpinski-carpet-chart") | |
.attr("height", root.size) | |
.attr("width", root.size) | |
.style("background-color", background); | |
svg.call(drawLayer, [root]); | |
function drawLayer(selection, squares) { | |
var layer = selection.selectAll("g") | |
.data(function(d) { | |
// Use specific data if it was provided; otherwise use children | |
return squares || d.children; | |
}); | |
layer.enter() | |
.append("g") | |
.on("mouseover", function(d) { | |
// Only split groups that haven't been split yet | |
if (!d.children) { | |
d3.select(this).call(split); | |
} | |
}) | |
.append("rect") | |
.call(layout); | |
// Resize any groups that were just split | |
selection.select("rect") | |
.filter(function(d) { | |
return !d.resized && d.children; | |
}) | |
.each(resize) | |
.on("mouseover", null) | |
.transition().duration(tick) | |
.call(layout) | |
.call(endAll, function() { | |
// Check to see if we should automatically generate the next depth | |
layer | |
.filter(function(d) { | |
return !d.children && d.depth < startingDepth; | |
}) | |
.call(split); | |
}); | |
} | |
function layout(selection) { | |
selection.attr("height", function(d) { | |
return d.size; | |
}) | |
.attr("width", function(d) { | |
return d.size; | |
}) | |
.attr("transform", function(d) { | |
return `translate(${d.x}, ${d.y})`; | |
}) | |
.attr("fill", function(d) { | |
return d.children ? colors(d.depth) : background; | |
}); | |
} | |
// These are the "holes" in the Sierpinski carpet | |
function resize(square) { | |
square.resized = true; | |
square.size /= 3; | |
square.x = square.x + square.size; | |
square.y = square.y + square.size; | |
} | |
function split(selection) { | |
selection.each(splitSquare) | |
.call(function(s) { | |
if (!s.empty()) { | |
setTimeout(drawLayer.bind(null, s)); | |
} | |
}); | |
} | |
function splitSquare(square) { | |
if (square.children) { | |
return square.children; | |
} | |
square.children = []; | |
var size = square.size / 3; | |
for (var i = 0; i < 3; i++) { | |
for (var j = 0; j < 3; j++) { | |
if (i === 1 && j === 1) { | |
continue; | |
} | |
square.children.push({ | |
x: square.x + size * i, | |
y: square.y + size * j, | |
size: size, | |
depth: square.depth + 1 | |
}); | |
} | |
} | |
return square.children; | |
} | |
// Wait until all transitions are done then use callback | |
function endAll(transition, callback) { | |
var n; | |
if (transition.empty()) { | |
callback(); | |
} else { | |
n = transition.size(); | |
transition.each("end", function() { | |
n--; | |
if (n === 0) { | |
callback(); | |
} | |
}); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
body { | |
margin: 0; | |
padding: 0; | |
background-color: #333; | |
} | |
#sierpinski-carpet-chart { | |
cursor: crosshair; | |
display: block; | |
margin: auto; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment