Skip to content

Instantly share code, notes, and snippets.

@alexmacy
Last active February 10, 2024 07:04
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save alexmacy/6700d44240d2b6d3ec9767a5a5854e42 to your computer and use it in GitHub Desktop.
Save alexmacy/6700d44240d2b6d3ec9767a5a5854e42 to your computer and use it in GitHub Desktop.
Projection Transitions v4
license: gpl-3.0

A v4 update to mbostock's block: Projection Transitions

I also tweaked the transition so that it's constantly moving...

These projections are available in the geo.projection plugin.

<!DOCTYPE html>
<meta charset="utf-8">
<style>
body {
background: #fcfcfa;
height: 500px;
position: relative;
width: 960px;
}
#projection-menu {
position: absolute;
right: 10px;
top: 10px;
}
.stroke {
fill: none;
stroke: #000;
stroke-width: 3px;
}
.fill {
fill: #fff;
}
.graticule {
fill: none;
stroke: #777;
stroke-width: .5px;
stroke-opacity: .5;
}
.land {
fill: #222;
}
.boundary {
fill: none;
stroke: #fff;
stroke-width: .5px;
}
</style>
<select id="projection-menu"></select>
<script src="//d3js.org/d3.v4.min.js"></script>
<script src="//d3js.org/d3-geo-projection.v1.min.js"></script>
<script src="//d3js.org/topojson.v2.min.js"></script>
<script>
var width = 960,
height = 500;
var options = [
{name: "Aitoff", projection: d3.geoAitoff()},
{name: "Albers", projection: d3.geoAlbers().scale(145).parallels([20, 50])},
{name: "August", projection: d3.geoAugust().scale(60)},
{name: "Baker", projection: d3.geoBaker().scale(100)},
{name: "Boggs", projection: d3.geoBoggs()},
{name: "Bonne", projection: d3.geoBonne().scale(120)},
{name: "Bromley", projection: d3.geoBromley()},
{name: "Collignon", projection: d3.geoCollignon().scale(93)},
{name: "Craster Parabolic", projection: d3.geoCraster()},
{name: "Eckert I", projection: d3.geoEckert1().scale(165)},
{name: "Eckert II", projection: d3.geoEckert2().scale(165)},
{name: "Eckert III", projection: d3.geoEckert3().scale(180)},
{name: "Eckert IV", projection: d3.geoEckert4().scale(180)},
{name: "Eckert V", projection: d3.geoEckert5().scale(170)},
{name: "Eckert VI", projection: d3.geoEckert6().scale(170)},
{name: "Eisenlohr", projection: d3.geoEisenlohr().scale(60)},
{name: "Equirectangular (Plate Carrée)", projection: d3.geoEquirectangular()},
{name: "Hammer", projection: d3.geoHammer().scale(165)},
{name: "Hill", projection: d3.geoHill()},
{name: "Goode Homolosine", projection: d3.geoHomolosine()},
{name: "Kavrayskiy VII", projection: d3.geoKavrayskiy7()},
{name: "Lambert cylindrical equal-area", projection: d3.geoCylindricalEqualArea()},
{name: "Lagrange", projection: d3.geoLagrange().scale(120)},
{name: "Larrivée", projection: d3.geoLarrivee().scale(95)},
{name: "Laskowski", projection: d3.geoLaskowski().scale(120)},
{name: "Loximuthal", projection: d3.geoLoximuthal()},
// {name: "Mercator", projection: d3.geoMercator().scale(490 / 2 / Math.PI)},
{name: "Miller", projection: d3.geoMiller().scale(100)},
{name: "McBryde–Thomas Flat-Polar Parabolic", projection: d3.geoMtFlatPolarParabolic()},
{name: "McBryde–Thomas Flat-Polar Quartic", projection: d3.geoMtFlatPolarQuartic()},
{name: "McBryde–Thomas Flat-Polar Sinusoidal", projection: d3.geoMtFlatPolarSinusoidal()},
{name: "Mollweide", projection: d3.geoMollweide().scale(165)},
{name: "Natural Earth", projection: d3.geoNaturalEarth()},
{name: "Nell–Hammer", projection: d3.geoNellHammer()},
{name: "Polyconic", projection: d3.geoPolyconic().scale(100)},
{name: "Robinson", projection: d3.geoRobinson()},
{name: "Sinusoidal", projection: d3.geoSinusoidal()},
{name: "Sinu-Mollweide", projection: d3.geoSinuMollweide()},
{name: "van der Grinten", projection: d3.geoVanDerGrinten().scale(75)},
{name: "van der Grinten IV", projection: d3.geoVanDerGrinten4().scale(120)},
{name: "Wagner IV", projection: d3.geoWagner4()},
{name: "Wagner VI", projection: d3.geoWagner6()},
{name: "Wagner VII", projection: d3.geoWagner7()},
{name: "Winkel Tripel", projection: d3.geoWinkel3()}
];
options.forEach(function(o) {
o.projection.rotate([0, 0]).center([0, 0]);
});
var //interval = setInterval(loop, 750),
i = 0,
n = options.length - 1;
var projection = options[i].projection;
var path = d3.geoPath(projection);
var graticule = d3.geoGraticule();
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
svg.append("defs").append("path")
.datum({type: "Sphere"})
.attr("id", "sphere")
.attr("d", path);
svg.append("use")
.attr("class", "stroke")
.attr("xlink:href", "#sphere");
svg.append("use")
.attr("class", "fill")
.attr("xlink:href", "#sphere");
svg.append("path")
.datum(graticule)
.attr("class", "graticule")
.attr("d", path);
d3.json("world-110m.json", function(error, world) {
if (error) throw error;
svg.insert("path", ".graticule")
.datum(topojson.feature(world, world.objects.land))
.attr("class", "land")
.attr("d", path);
});
var menu = d3.select("#projection-menu")
.on("change", change);
menu.selectAll("option")
.data(options)
.enter().append("option")
.text(function(d) { return d.name; });
update(options[0])
function loop() {
var j = Math.floor(Math.random() * n);
menu.property("selectedIndex", i = j + (j >= i));
update(options[i]);
}
function change() {
clearInterval(interval);
update(options[this.selectedIndex]);
}
function update(option) {
svg.selectAll("path").interrupt().transition()
.duration(1000).ease(d3.easeLinear)
.attrTween("d", projectionTween(projection, projection = option.projection))
d3.timeout(loop, 1000)
}
function projectionTween(projection0, projection1) {
return function(d) {
var t = 0;
var projection = d3.geoProjection(project)
.scale(1)
.translate([width / 2, height / 2]);
var path = d3.geoPath(projection);
function project(λ, φ) {
λ *= 180 / Math.PI, φ *= 180 / Math.PI;
var p0 = projection0([λ, φ]), p1 = projection1([λ, φ]);
return [(1 - t) * p0[0] + t * p1[0], (1 - t) * -p0[1] + t * -p1[1]];
}
return function(_) {
t = _;
return path(d);
};
};
}
</script>
Display the source blob
Display the rendered blob
Raw
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment