|
<!DOCTYPE html> |
|
<head> |
|
<meta charset="utf-8"> |
|
<script src="https://d3js.org/d3.v4.min.js"></script> |
|
<script src="https://unpkg.com/flubber"></script> |
|
<script src="https://d3js.org/topojson.v3.min.js"></script> |
|
<style> |
|
body { margin:0;position:fixed;top:0;right:0;bottom:0;left:0; } |
|
</style> |
|
</head> |
|
|
|
<body> |
|
<script> |
|
|
|
|
|
|
|
var width = 960, |
|
height = 500; |
|
|
|
var rows = 10, |
|
cols = 20; |
|
|
|
var svg = d3.select("body").append("svg") |
|
.attr("width", width) |
|
.attr("height", height); |
|
|
|
d3.queue() |
|
.defer(d3.json, "https://unpkg.com/world-atlas@1.1.4/world/110m.json") |
|
.await(drawMap); |
|
|
|
function circlePath(x, y, radius) { |
|
var l = `${x - radius},${y}`, |
|
r = `${x + radius},${y}`, |
|
pre = `A${radius},${radius},0,1,1`; |
|
return `M${l}${pre},${r}${pre},${l}Z`; |
|
} |
|
svg.append("path") |
|
.attr("d", circlePath(width/2, height/2, 15)) |
|
.style("fill", "red"); |
|
|
|
function drawMap(error, worldMap) { |
|
|
|
// hackily get rid of Canada, Indonesia, Russia, USA... |
|
worldMap.objects.countries.geometries = |
|
worldMap.objects.countries.geometries.filter(function(d) { |
|
return [124,360,643,840].indexOf(d.id? +d.id : +d.properties.id) === -1; |
|
}); |
|
|
|
var feature = topojson.feature(worldMap, worldMap.objects.countries); |
|
|
|
var proj = d3.geoEquirectangular() |
|
.fitSize([width, height], feature); |
|
var geoPath = d3.geoPath().projection(proj); |
|
|
|
var path = svg.selectAll("country") |
|
.data(feature.features) |
|
.enter().append("path") |
|
.style("fill", "steelblue") |
|
.attr("d", function(d) { return geoPath(d); }); |
|
|
|
var inward = feature.features.map(function(d,i) { |
|
return flubber.combine(flubber.splitPathString(geoPath(d)), |
|
circlePath((1+(i%cols))*(width/cols), |
|
(Math.floor(i/cols)+1)*(height/rows), |
|
15), |
|
{ single: true }); |
|
}); |
|
|
|
var outward = feature.features.map(function(d,i) { |
|
return flubber.separate(circlePath((1+(i%cols))*(width/cols), |
|
(Math.floor(i/cols)+1)*(height/rows), |
|
15), |
|
flubber.splitPathString(geoPath(d)), |
|
{ single: true }); |
|
}); |
|
|
|
|
|
function morph() { |
|
path |
|
.transition().delay(2000).duration(3000) |
|
.attrTween("d", function(d,i) { |
|
return inward[i]; |
|
}) |
|
.transition().delay(2000).duration(3000) |
|
.attrTween("d", function(d,i) { |
|
return outward[i]; |
|
}) |
|
//.on("end", morph) |
|
} |
|
morph(); |
|
|
|
} |
|
|
|
|
|
</script> |
|
</body> |