The Goode Homolosine projection is available as d3.geo.homolosine in the geo.projection D3 plugin.
| <!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