Skip to content

Instantly share code, notes, and snippets.

@jasondavies
Forked from mbostock/.block
Created September 17, 2012 13:54
Show Gist options
  • Save jasondavies/3737384 to your computer and use it in GitHub Desktop.
Save jasondavies/3737384 to your computer and use it in GitHub Desktop.
Interrupted Sinusoidal Projection
<!DOCTYPE html>
<meta charset="utf-8">
<style>
body {
height: 500px;
position: relative;
width: 960px;
font-family: sans-serif;
}
#gores-slider {
position: absolute;
left: 10px;
top: 10px;
}
.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>
<label for="gores" id="gores-slider"><input type="range" id="gores" step="1" min="1" max="24" value="3"> Gores = <output id="gores-output">3</output></label>
<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.sinusoidal()
.scale(130)
.translate([width / 2 - .5, height / 2 - .5]);
var path = d3.geo.path();
var graticule = d3.geo.graticule();
var interrupt, x, y;
function lobes(n) {
var dλ = (180 - -180) / n;
return {
type: "Polygon",
coordinates: [hemilobes(n, -180, 180, 0, 90).concat(hemilobes(n, 180, -180, 0, -90))].map(resample),
properties: {interruptions: d3.range(-180, 180 + dλ / 2, dλ)}
};
}
function hemilobes(n, λ0, λ1, φ0, φ1) {
var d = [],
dλ = (λ1 - λ0) / n,
δ = dλ / 1e6;
λ0 += δ;
for (var i = 0; i < n; i++) {
d.push([λ0, φ0], [λ0, φ1], [λ0 += dλ - 2 * δ, φ1], [λ0, φ0]);
λ0 += 2 * δ;
}
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");
var background = svg.append("path")
.attr("class", "background");
var graticules = svg.selectAll(".graticule")
.data(graticule.lines)
.enter().append("path")
.attr("class", "graticule");
var foreground = svg.append("path")
.attr("class", "foreground");
d3.select("#gores").on("change", gores);
gores();
function gores() {
var n = +d3.select("#gores").property("value");
d3.select("#gores-output").property("value", n);
interrupt = lobes(n);
x = interrupt.properties.interruptions;
y = x.map(function(x) { return projection([x, 0]); });
path.projection(d3.geo.projection(function(λ, φ) {
var coordinates = [λ *= 180 / π, φ *= 180 / π];
for (var i = 1; i < x.length; i++) {
if (coordinates[0] < x[i] + 1e-6) {
coordinates = projection([coordinates[0] - (x[i - 1] + x[i]) / 2, coordinates[1]]);
coordinates[0] += (y[i - 1][0] + y[i][0]) / 2 - width / 2 - .5;
coordinates[1] = -coordinates[1];
break;
}
}
return coordinates;
}).scale(1));
clipPath.datum(interrupt);
background.datum(interrupt);
foreground.datum(interrupt);
svg.selectAll("path").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