Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I move states in the d3 AlbersUSA projection?

I'm using the standard AlbersUSA projection within d3.

The one thing I'm running into though is that since Alaska and Puerto Rico are outside the "rectangle" drawn by the contiguous states, I can't quite maximize my zoom factor to fit within a smaller viewport.

Ideally I'd like to move Puerto Rico below Louisiana and potentially swap places with Hawaii and Alaska, which would give me better bounds to work with.

Looking over the documentation, I see the AlbersUSA composite was created with the following function:

function albersUsa(coordinates) {
  var lon = coordinates[0],
      lat = coordinates[1];
  return (lat > 50 ? alaska
      : lon < -140 ? hawaii
      : lat < 21 ? puertoRico
      : lower48)(coordinates);
}

How can I modify this function (or effectively create my own) so that I can move the states around without having to worry about augmenting the GeoJSON data itself?

like image 909
Dillie-O Avatar asked Nov 13 '22 19:11

Dillie-O


1 Answers

(I haven't tried this)

  1. Copy the code for d3.geo.albersUsa out of the d3 source (code is included at bottom of this post).

  2. Modify the name: d3.geo.myAlbersUsa = function() { ... }

  3. Look inside the function albersUsa.translate. That's where the 3 states are moved to their "artificial" positions. Eg alaska.translate([dx - 400 * dz, dy + 170 * dz]);

  4. Tweak these numbers (400 and 170) until it moves to where you want it to be (start with small changes, like +/- 10).

  5. For any path that you're drawing the data into, you need to specify its projection to be your custom projection: path.projection(d3.geo.myAlbersUsa())

From the D3 source, this is the code you need to copy/paste in step 1:

// 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());
};
like image 96
meetamit Avatar answered Nov 15 '22 09:11

meetamit