function projection_transition_pic(p0, p1, t) {
let w = 800;
let h = 0.625 * w;
let proj = interpolateProjection(p0, p1)(t);
let svg = d3
.create("svg")
.attr("viewBox", [0, 0, w, h])
.style("max-width", `${w}px`)
let path = d3.geoPath().projection(proj);
let graticule = d3.geoGraticule().extent([
[-180, -80],
[180, 80]
])();
let graticule_path = svg
.append("g")
.selectAll("path.graticule")
.data([graticule])
.join("path")
.attr("d", path)
.attr("fill", "none")
.attr("stroke", "#333")
.attr("stroke-width", 0.4);
let land_group = svg.append("g");
land_group
.selectAll("path.land")
.data(land.features)
.join("path")
.attr("class", "land")
.attr("d", path)
.attr("fill", "#eee")
.attr("stroke", "black")
.attr("stroke-width", 1)
.attr("opacity", 1);
return svg.node();
function interpolateProjection(p0, p1) {
const {
scale: scale0,
translate: translate0,
rotate: rotate0
} = fit(p0.projection, p0.polar);
const {
scale: scale1,
translate: translate1,
rotate: rotate1
} = fit(p1.projection, p1.polar);
return (t) =>
d3
.geoProjection((x, y) =>
lerp2(p0.projection(x, y), p1.projection(x, y), t)
)
.scale(lerp1(scale0, scale1, t))
.translate(lerp2(translate0, translate1, t))
.rotate(lerp2(rotate0, rotate1, t));
function lerp1(x0, x1, t) {
return (1 - t) * x0 + t * x1;
}
function lerp2([x0, y0], [x1, y1], t) {
return [(1 - t) * x0 + t * x1, (1 - t) * y0 + t * y1];
}
function fit(raw, polar) {
let p = d3.geoProjection(raw);
p.fitExtent(
[
[0.5, 0.5],
[w - 0.5, h - 0.5]
],
land
);
if (polar) {
p.rotate([0, -90]).scale(200);
}
return { scale: p.scale(), translate: p.translate(), rotate: p.rotate() };
}
}
}