Skip to content

Instantly share code, notes, and snippets.

@Fil
Last active July 2, 2016 17:12
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 Fil/57f8ee29e49baa205f049ba4395316ab to your computer and use it in GitHub Desktop.
Save Fil/57f8ee29e49baa205f049ba4395316ab to your computer and use it in GitHub Desktop.
Rotating Voronoi in d3v4
license: gpl-3.0

Mario Klingemann has made some beautiful Voronoi diagrams. This is my attempt to recreate them using D3. To achieve the curved cells, each side of the Voronoi polygon is subdivided into three equal-length segments and then joined using the "basis-closed" line interpolator. There are some discontinuities in the animation when the sides of a polygon approach zero which could likely be avoided by adding a minimum-length threshold to the subdivision.

If you’d like to see other instances of this pattern, Mario describes the algorithm on Flickr.

forked from mbostock's block: Rotating Voronoi

<!DOCTYPE html>
<meta charset="utf-8">
<style>
body {
background: #000;
}
path {
fill: #fff;
stroke: #000;
stroke-width: 1.5px;
}
</style>
<body>
<script src="//d3js.org/d3.v4.min.js"></script>
<script>
var width = 960,
height = 500;
var points = [];
circle(0, 0, 120, 96, -.001);
circle(0, 0, 30, 10, .03);
circle(0, 0, 60, 3, -.05);
circle(0, 0, 15, 4, -.02);
circle(0, 0, 0, 1, -.02);
circle(240, -120, 80, 4, -.02);
circle(240, -120, 0, 1, -.02);
circle(280, +120, 40, 8, .02);
circle(280, +120, 20, 8, -.02);
circle(280, +120, 0, 1, .02);
var line = d3.line()
.curve(d3.curveBasisClosed);
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + (width / 2) + "," + (height / 2) + ")");
var path = svg.selectAll("path")
.data(points)
.enter().append("path");
d3.timer(function() {
var voronoi = d3.voronoi()
.extent([[-width / 2, -height / 2], [+width / 2, +height / 2]])
.polygons(points);
path.attr("d", function(point, i) { return line(resample(voronoi[i])); });
});
function circle(cx, cy, r, n, δθ) {
d3.range(1e-6, 2 * Math.PI, 2 * Math.PI / n).map(function(θ, i) {
var point = [cx + Math.cos(θ) * r, cy + Math.sin(θ) * r];
d3.timer(function(elapsed) {
var angle = θ + δθ * elapsed / 60;
point[0] = cx + Math.cos(angle) * r;
point[1] = cy + Math.sin(angle) * r;
});
points.push(point);
return point;
});
}
function resample(points) {
var i = -1,
n = points.length,
p0 = points[n - 1], x0 = p0[0], y0 = p0[1], p1, x1, y1,
points2 = [];
while (++i < n) {
p1 = points[i], x1 = p1[0], y1 = p1[1];
points2.push(
[(x0 * 2 + x1) / 3, (y0 * 2 + y1) / 3],
[(x0 + x1 * 2) / 3, (y0 + y1 * 2) / 3],
p1
);
p0 = p1, x0 = x1, y0 = y1;
}
return points2;
}
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment