Just stripping down and tweaking Bostock's example to animate between Voronoi sites and polygons by clipping the site circle to the polygon and blowing up the radius. Silly and simple but I do like that it illustrates what a Voronoi tessellation is! ’Cuz every circle hits the bound against a well-matched antagonist.
xxxxxxxxxx
<meta charset="utf-8">
<svg width="960" height="500"></svg>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>
var svg = d3.select("svg"),
width = +svg.attr("width"),
height = +svg.attr("height");
var sites = d3.range(100)
.map(function(d) { return [Math.random() * width, Math.random() * height]; });
var voronoi = d3.voronoi()
.extent([[-1, -1], [width + 1, height + 1]]);
var polygon = svg.append("defs")
.selectAll("clipPath")
.data(voronoi.polygons(sites))
.enter().append("clipPath")
.attr("id", function(d,i) { return "clip" + i; })
.append("path")
.attr("d", function(d) { return d ? "M" + d.join("L") + "Z" : null; });
var site = svg.append("g")
.selectAll("circle")
.data(sites)
.enter().append("circle")
.attr("r", 2.5)
.attr("cx", function(d) { return d[0]; })
.attr("cy", function(d) { return d[1]; })
.attr("clip-path", function(d,i) { return "url(#clip" + i + ")"; })
.attr("fill", function() { return "#" + Math.random().toString(16).slice(2, 8); })
.transition()
.delay(500)
.duration(5000)
.attr("r", getMaxLinkDistance(voronoi.links(sites)));
function getMaxLinkDistance(links) {
return d3.max(links.map(function(d) {
return Math.sqrt(
Math.pow(d.target[0] - d.source[0],2) +
Math.pow(d.target[1] - d.source[1],2)
);
}));
}
</script>
https://d3js.org/d3.v4.min.js