| import "albers"; | |
| import "conic-equal-area"; | |
| import "geo"; | |
| // A composite projection for the United States, configured by default for | |
| // 960×500. Also works quite well at 960×600 with scale 1285. The set of | |
| // standard parallels for each region comes from USGS, which is published here: | |
| // http://egsc.usgs.gov/isb/pubs/MapProjections/projections.html#albers | |
| d3.geo.albersUsa = function() { | |
| var lower48 = d3.geo.albers(); | |
| // EPSG:3338 | |
| var alaska = d3.geo.conicEqualArea() | |
| .rotate([154, 0]) | |
| .center([-2, 58.5]) | |
| .parallels([55, 65]); | |
| // ESRI:102007 | |
| var hawaii = d3.geo.conicEqualArea() | |
| .rotate([157, 0]) | |
| .center([-3, 19.9]) | |
| .parallels([8, 18]); | |
| var point, | |
| pointStream = {point: function(x, y) { point = [x, y]; }}, | |
| lower48Point, | |
| alaskaPoint, | |
| hawaiiPoint; | |
| function albersUsa(coordinates) { | |
| var x = coordinates[0], y = coordinates[1]; | |
| point = null; | |
| (lower48Point(x, y), point) | |
| || (alaskaPoint(x, y), point) | |
| || hawaiiPoint(x, y); | |
| 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 | |
| : 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); | |
| return { | |
| point: function(x, y) { | |
| lower48Stream.point(x, y); | |
| alaskaStream.point(x, y); | |
| hawaiiStream.point(x, y); | |
| }, | |
| sphere: function() { | |
| lower48Stream.sphere(); | |
| alaskaStream.sphere(); | |
| hawaiiStream.sphere(); | |
| }, | |
| lineStart: function() { | |
| lower48Stream.lineStart(); | |
| alaskaStream.lineStart(); | |
| hawaiiStream.lineStart(); | |
| }, | |
| lineEnd: function() { | |
| lower48Stream.lineEnd(); | |
| alaskaStream.lineEnd(); | |
| hawaiiStream.lineEnd(); | |
| }, | |
| polygonStart: function() { | |
| lower48Stream.polygonStart(); | |
| alaskaStream.polygonStart(); | |
| hawaiiStream.polygonStart(); | |
| }, | |
| polygonEnd: function() { | |
| lower48Stream.polygonEnd(); | |
| alaskaStream.polygonEnd(); | |
| hawaiiStream.polygonEnd(); | |
| } | |
| }; | |
| }; | |
| albersUsa.precision = function(_) { | |
| if (!arguments.length) return lower48.precision(); | |
| lower48.precision(_); | |
| alaska.precision(_); | |
| hawaii.precision(_); | |
| return albersUsa; | |
| }; | |
| albersUsa.scale = function(_) { | |
| if (!arguments.length) return lower48.scale(); | |
| lower48.scale(_); | |
| alaska.scale(_ * .35); | |
| hawaii.scale(_); | |
| 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(_) | |
| .clipExtent([[x - .455 * k, y - .238 * k], [x + .455 * k, y + .238 * k]]) | |
| .stream(pointStream).point; | |
| alaskaPoint = alaska | |
| .translate([x - .307 * k, y + .201 * k]) | |
| .clipExtent([[x - .425 * k + ε, y + .120 * k + ε], [x - .214 * k - ε, y + .234 * k - ε]]) | |
| .stream(pointStream).point; | |
| hawaiiPoint = hawaii | |
| .translate([x - .205 * k, y + .212 * k]) | |
| .clipExtent([[x - .214 * k + ε, y + .166 * k + ε], [x - .115 * k - ε, y + .234 * k - ε]]) | |
| .stream(pointStream).point; | |
| return albersUsa; | |
| }; | |
| return albersUsa.scale(1070); | |
| }; |