Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Interrupted Goode Homolosine
<!DOCTYPE html>
<meta charset="utf-8">
<style>
.background {
fill: #a4bac7;
}
.foreground {
fill: none;
stroke: #333;
stroke-width: 1.5px;
}
.graticule {
fill: none;
stroke: #fff;
stroke-width: .5px;
}
.graticule:nth-child(2n) {
stroke-dasharray: 2,2;
}
.land {
fill: #d7c7ad;
stroke: #766951;
}
.boundary {
fill: none;
stroke: #a5967e;
}
</style>
<body>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script src="https://raw.github.com/d3/d3-plugins/master/geo/projection/projection.js"></script>
<script>
var π = Math.PI;
var width = 960,
height = 500;
var projection = d3.geo.homolosine().scale(1).translate([0, 0]);
var graticule = d3.geo.graticule();
// λ0, λ1, central meridian
var goode = [[
[-180, -40, -100],
[ -40, 180, 30]
], [
[-180, -100, -160],
[-100, -20, -60],
[ -20, 80, 20],
[ 80, 180, 140]
]];
var interrupt = {
type: "Polygon",
coordinates: [hemilobes(goode[0], 0, 90).concat(hemilobes(goode[1], 0, -90).reverse())].map(resample)
}
var y = goode.map(function(d) {
return d.map(function(d) { return projection([d[2], 0]); });
});
var path = d3.geo.path()
.projection(d3.geo.projection(function(λ, φ) {
λ *= 180 / π;
var j = (φ *= 180 / π) >= 0 ? 0 : 1;
for (var i = 0; i < goode[j].length; i++) {
if (λ < goode[j][i][1] + 1e-9) {
var coordinates = projection([λ - goode[j][i][2], φ]);
coordinates[0] += y[j][i][0];
coordinates[1] = -coordinates[1];
break;
}
}
return coordinates;
}).translate([width / 2 - .5, height / 2 - .5]));
function hemilobes(interrupts, φ0, φ1) {
var n = interrupts.length,
d = [],
λ,
δ = 1e-6;
for (var i = 0; i < n; i++) {
λ = interrupts[i];
d.push([λ[0] + δ, φ0], [λ[0] + δ, φ1], [λ[1] - δ, φ1], [λ[1] - δ, φ0]);
}
return d;
}
function resample(coordinates) {
var n = coordinates.length;
if (!n) return coordinates;
var samples = 50,
a = coordinates[0],
b,
resampled = [];
for (var i = 0; ++i < n;) {
b = coordinates[i];
dx = (b[0] - a[0]) / samples;
dy = (b[1] - a[1]) / samples;
resampled.push(a);
for (var j = 1; j < samples; j++) {
resampled.push([dx ? a[0] + j * dx : a[0], dy ? a[1] + j * dy : a[1]]);
}
a = b;
}
if (b) resampled.push(b);
return resampled;
}
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
var clipPath = svg.append("defs").append("clipPath")
.attr("id", "clip")
.append("path")
.datum(interrupt)
.attr("d", path);
svg.append("path")
.datum(interrupt)
.attr("class", "background")
.attr("d", path);
svg.selectAll(".graticule")
.data(graticule.lines)
.enter().append("path")
.attr("class", "graticule")
.attr("d", path);
svg.append("path")
.datum(interrupt)
.attr("class", "foreground")
.attr("d", path);
d3.json("/d/3682676/readme-boundaries.json", function(err, collection) {
svg.insert("g", ".graticule")
.attr("class", "boundary")
.attr("clip-path", "url(#clip)")
.selectAll("path")
.data(collection.geometries)
.enter().append("path")
.attr("d", path);
});
d3.json("/d/3682676/readme-land.json", function(err, collection) {
svg.insert("g", ".graticule,.boundary")
.attr("class", "land")
.attr("clip-path", "url(#clip)")
.selectAll("path")
.data(collection.geometries)
.enter().append("path")
.attr("d", path);
});
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment