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> |