// Derived from Tom Carden's Albers implementation for Protovis. // http://gist.github.com/476238 // http://mathworld.wolfram.com/AlbersEqual-AreaConicProjection.html d3.geo.albers = function() { var origin = [-98, 38], parallels = [29.5, 45.5], scale = 1000, translate = [480, 250], lng0, // d3_geo_radians * origin[0] n, C, p0; function albers(coordinates) { var t = n * (d3_geo_radians * coordinates[0] - lng0), p = Math.sqrt(C - 2 * n * Math.sin(d3_geo_radians * coordinates[1])) / n; return [ scale * p * Math.sin(t) + translate[0], scale * (p * Math.cos(t) - p0) + translate[1] ]; } albers.invert = function(coordinates) { var x = (coordinates[0] - translate[0]) / scale, y = (coordinates[1] - translate[1]) / scale, p0y = p0 + y, t = Math.atan2(x, p0y), p = Math.sqrt(x * x + p0y * p0y); return [ (lng0 + t / n) / d3_geo_radians, Math.asin((C - p * p * n * n) / (2 * n)) / d3_geo_radians ]; }; function reload() { var phi1 = d3_geo_radians * parallels[0], phi2 = d3_geo_radians * parallels[1], lat0 = d3_geo_radians * origin[1], s = Math.sin(phi1), c = Math.cos(phi1); lng0 = d3_geo_radians * origin[0]; n = .5 * (s + Math.sin(phi2)); C = c * c + 2 * n * s; p0 = Math.sqrt(C - 2 * n * Math.sin(lat0)) / n; return albers; } albers.origin = function(x) { if (!arguments.length) return origin; origin = [+x[0], +x[1]]; return reload(); }; albers.parallels = function(x) { if (!arguments.length) return parallels; parallels = [+x[0], +x[1]]; return reload(); }; albers.scale = function(x) { if (!arguments.length) return scale; scale = +x; return albers; }; albers.translate = function(x) { if (!arguments.length) return translate; translate = [+x[0], +x[1]]; return albers; }; return reload(); }; // A composite projection for the United States, 960x500. 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 // TODO allow the composite projection to be rescaled? d3.geo.albersUsa = function() { var lower48 = d3.geo.albers(); var alaska = d3.geo.albers() .origin([-160, 60]) .parallels([55, 65]); var hawaii = d3.geo.albers() .origin([-160, 20]) .parallels([8, 18]); var puertoRico = d3.geo.albers() .origin([-60, 10]) .parallels([8, 18]); function albersUsa(coordinates) { var lon = coordinates[0], lat = coordinates[1]; return (lat > 50 ? alaska : lon < -140 ? hawaii : lat < 21 ? puertoRico : lower48)(coordinates); } albersUsa.scale = function(x) { if (!arguments.length) return lower48.scale(); lower48.scale(x); alaska.scale(x * .6); hawaii.scale(x); puertoRico.scale(x * 1.5); return albersUsa.translate(lower48.translate()); }; albersUsa.translate = function(x) { if (!arguments.length) return lower48.translate(); var dz = lower48.scale() / 1000, dx = x[0], dy = x[1]; lower48.translate(x); alaska.translate([dx - 400 * dz, dy + 170 * dz]); hawaii.translate([dx - 190 * dz, dy + 200 * dz]); puertoRico.translate([dx + 580 * dz, dy + 430 * dz]); return albersUsa; }; return albersUsa.scale(lower48.scale()); };