{
const context = DOM.context2d(width, height);
const width1 = width * 0.8;
const width2 = width - width1;
const projection1 = d3.geoMercator();
const projection2 = d3.geoOrthographic();
const legendMargin = 30;
context.font = `${legendMargin / 2}px serif`;
context.textAlign = 'center';
context.textBaseline = 'middle';
projection1.fitExtent(
[[10, 10], [width1 - 10, height - 10 - legendMargin]],
sphere
);
projection2.fitExtent([[width1 + 10, 10], [width - 10, width2 - 10]], sphere);
const path1 = d3.geoPath(projection1, context);
const path2 = d3.geoPath(projection2, context);
function renderOnePath(country, arc, path) {
context.beginPath(),
path(land),
(context.fillStyle = "#ccc"),
context.fill();
context.beginPath(),
path(country),
(context.fillStyle = "#f00"),
context.fill();
context.beginPath(),
path(borders),
(context.strokeStyle = "#fff"),
(context.lineWidth = 0.5),
context.stroke();
context.beginPath(),
path(sphere),
(context.strokeStyle = "#000"),
(context.lineWidth = 1.5),
context.stroke();
context.beginPath(), path(arc), context.stroke();
}
function render(country, arc) {
context.clearRect(0, 0, width, height);
renderOnePath(country, arc, path1);
renderOnePath(country, arc, path2);
context.save();
context.fillStyle = 'black';
context.fillText(
'Mercator projection',
width1 / 2,
height - legendMargin / 2
);
context.restore();
return context.canvas;
}
let p1,
p2 = [0, 0],
r1,
r2 = [0, 0, 0];
for (const country of countries) {
mutable name = country.properties.name;
yield render(country);
(p1 = p2), (p2 = d3.geoCentroid(country));
(r1 = r2), (r2 = [-p2[0], tilt - p2[1], 0]);
const ip = d3.geoInterpolate(p1, p2);
const iv = Versor.interpolateAngles(r1, r2);
await d3
.transition()
.duration(1250)
.tween("render", () => t => {
projection1.rotate(iv(t));
projection2.rotate(iv(t));
render(country, { type: "LineString", coordinates: [p1, ip(t)] });
})
.transition()
.tween("render", () => t => {
render(country, { type: "LineString", coordinates: [ip(t), p2] });
})
.end();
}
}