Skip to content

Instantly share code, notes, and snippets.

@almccon
Last active July 10, 2019 23:01
Show Gist options
  • Save almccon/0ae88401cc9b142d6fb35c9251633888 to your computer and use it in GitHub Desktop.
Save almccon/0ae88401cc9b142d6fb35c9251633888 to your computer and use it in GitHub Desktop.
So you want a bigger Alaska?
license: gpl-3.0
// 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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment