diff -r efd9c589177a -r c0b4a8b5a012 toolkit/javascript/d3/src/geo/albers.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toolkit/javascript/d3/src/geo/albers.js Thu Apr 10 14:20:23 2014 +0200 @@ -0,0 +1,126 @@ +// 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()); +};