Accurate sized Alaska (but not accurate position, of course)
Forked from mbostock's block: AlbersUSA + PR
forked from Fil's block: AlbersUSA inverse proj parameters
| license: gpl-3.0 |
Accurate sized Alaska (but not accurate position, of course)
Forked from mbostock's block: AlbersUSA + PR
forked from Fil's block: AlbersUSA inverse proj parameters
| // A modified d3.geoAlbersUsa to include Puerto Rico. | |
| // See also https://bl.ocks.org/rveciana/5040be82aea528b6f785464f8816690f | |
| function albersUsaPr() { | |
| var ε = 1e-6; | |
| var lower48 = d3.geoAlbers(); | |
| // EPSG:3338 | |
| var alaska = d3.geoConicEqualArea() | |
| .rotate([154, 0]) | |
| .center([-2, 58.5]) | |
| .parallels([55, 65]); | |
| // ESRI:102007 | |
| var hawaii = d3.geoConicEqualArea() | |
| .rotate([157, 0]) | |
| .center([-3, 19.9]) | |
| .parallels([8, 18]); | |
| // XXX? You should check that this is a standard PR projection! | |
| var puertoRico = d3.geoConicEqualArea() | |
| .rotate([66, 0]) | |
| .center([0, 18]) | |
| .parallels([8, 18]); | |
| var point, | |
| pointStream = {point: function(x, y) { point = [x, y]; }}, | |
| lower48Point, | |
| alaskaPoint, | |
| hawaiiPoint, | |
| puertoRicoPoint; | |
| function albersUsa(coordinates) { | |
| var x = coordinates[0], y = coordinates[1]; | |
| point = null; | |
| (lower48Point(x, y), point) | |
| || (alaskaPoint(x, y), point) | |
| || (hawaiiPoint(x, y), point) | |
| || (puertoRicoPoint(x, y), point); | |
| return point; | |
| } | |
| albersUsa.invert = function(coordinates) { | |
| var k = lower48.scale(), | |
| t = lower48.translate(), | |
| x = (coordinates[0] - t[0]) / k, | |
| y = (coordinates[1] - t[1]) / k; | |
| return (y >= .120 && y < .234 && x >= -.425 && x < -.214 ? alaska | |
| : y >= .166 && y < .234 && x >= -.214 && x < -.115 ? hawaii | |
| : y >= .204 && y < .234 && x >= .320 && x < .380 ? puertoRico | |
| : lower48).invert(coordinates); | |
| }; | |
| // A naïve multi-projection stream. | |
| // The projections must have mutually exclusive clip regions on the sphere, | |
| // as this will avoid emitting interleaving lines and polygons. | |
| albersUsa.stream = function(stream) { | |
| var lower48Stream = lower48.stream(stream), | |
| alaskaStream = alaska.stream(stream), | |
| hawaiiStream = hawaii.stream(stream), | |
| puertoRicoStream = puertoRico.stream(stream); | |
| return { | |
| point: function(x, y) { | |
| lower48Stream.point(x, y); | |
| alaskaStream.point(x, y); | |
| hawaiiStream.point(x, y); | |
| puertoRicoStream.point(x, y); | |
| }, | |
| sphere: function() { | |
| lower48Stream.sphere(); | |
| alaskaStream.sphere(); | |
| hawaiiStream.sphere(); | |
| puertoRicoStream.sphere(); | |
| }, | |
| lineStart: function() { | |
| lower48Stream.lineStart(); | |
| alaskaStream.lineStart(); | |
| hawaiiStream.lineStart(); | |
| puertoRicoStream.lineStart(); | |
| }, | |
| lineEnd: function() { | |
| lower48Stream.lineEnd(); | |
| alaskaStream.lineEnd(); | |
| hawaiiStream.lineEnd(); | |
| puertoRicoStream.lineEnd(); | |
| }, | |
| polygonStart: function() { | |
| lower48Stream.polygonStart(); | |
| alaskaStream.polygonStart(); | |
| hawaiiStream.polygonStart(); | |
| puertoRicoStream.polygonStart(); | |
| }, | |
| polygonEnd: function() { | |
| lower48Stream.polygonEnd(); | |
| alaskaStream.polygonEnd(); | |
| hawaiiStream.polygonEnd(); | |
| puertoRicoStream.polygonEnd(); | |
| } | |
| }; | |
| }; | |
| albersUsa.precision = function(_) { | |
| if (!arguments.length) return lower48.precision(); | |
| lower48.precision(_); | |
| alaska.precision(_); | |
| hawaii.precision(_); | |
| puertoRico.precision(_); | |
| return albersUsa; | |
| }; | |
| albersUsa.scale = function(_) { | |
| if (!arguments.length) return lower48.scale(); | |
| lower48.scale(_ * .75); | |
| alaska.scale(_ * .75); | |
| hawaii.scale(_* .75); | |
| puertoRico.scale(_* .75); | |
| return albersUsa.translate(lower48.translate()); | |
| }; | |
| albersUsa.translate = function(_) { | |
| if (!arguments.length) return lower48.translate(); | |
| var k = lower48.scale(), x = +_[0], y = +_[1]; | |
| lower48Point = lower48 | |
| .translate([x + 0.16 * k, y - 0.08 * k]) | |
| .clipExtent([[x - .455 * k, y - 0.4172864 * k], [x + .55 * k, y + .238 * k]]) | |
| .stream(pointStream).point; | |
| alaskaPoint = alaska | |
| .translate([x - 0.34 * k, y + 0.19 * k]) | |
| .clipExtent([[x - .825 * k + ε, y - .820 * k + ε], [x + 0 * k - ε, y + .434 * k - ε]]) | |
| .stream(pointStream).point; | |
| hawaiiPoint = hawaii | |
| .translate([x - .01 * k, y + .23 * k]) | |
| .clipExtent([[x - .214 * k + ε, y + .016 * k + ε], [x + .115 * k - ε, y + .334 * k - ε]]) | |
| .stream(pointStream).point; | |
| puertoRicoPoint = puertoRico | |
| .translate([x + .420 * k, y + .214 * k]) | |
| .clipExtent([[x + .320 * k, y + .104 * k], [x + .480 * k, y + .434 * k]]) | |
| .stream(pointStream).point; | |
| return albersUsa; | |
| }; | |
| return albersUsa.scale(1070); | |
| } |
| <!DOCTYPE html> | |
| <meta charset="utf-8"> | |
| <style> | |
| path { | |
| fill: #ccc; | |
| stroke: #aaa; | |
| stroke-linejoin: round; | |
| } | |
| </style> | |
| <body> | |
| <script src="https://d3js.org/d3.v4.min.js"></script> | |
| <script src="https://d3js.org/topojson.v2.min.js"></script> | |
| <script src="albers-usa-pr.js"></script> | |
| <script> | |
| var width = 960, | |
| height = 500; | |
| var projection = albersUsaPr() | |
| .scale(1070) | |
| .translate([width / 2, height / 2]); | |
| var path = d3.geoPath() | |
| .projection(projection); | |
| var svg = d3.select("body").append("svg") | |
| .attr("width", width) | |
| .attr("height", height); | |
| d3.json("https://gist.githubusercontent.com/mbostock/4090846/raw/d534aba169207548a8a3d670c9c2cc719ff05c47/us.json", function(error, us) { | |
| if (error) throw error; | |
| svg.append('g') | |
| .selectAll("path") | |
| .data(topojson.feature(us, us.objects.states).features) | |
| .enter() | |
| .append("path") | |
| .attr("class", "mesh") | |
| .attr("d", path); | |
| }); | |
| </script> |