import “albers”; import “conic-equal-area”; import “geo”;

// A composite projection for the United States, configured by default for // 960×500. Also works quite well at 960×600 with scale 1285. The set of // standard parallels for each region comes from USGS, which is published here: // egsc.usgs.gov/isb/pubs/MapProjections/projections.html#albers d3.geo.albersUsa = function() {

var lower48 = d3.geo.albers();

// EPSG:3338
var alaska = d3.geo.conicEqualArea()
    .rotate([154, 0])
    .center([-2, 58.5])
    .parallels([55, 65]);

// ESRI:102007
var hawaii = d3.geo.conicEqualArea()
    .rotate([157, 0])
    .center([-3, 19.9])
    .parallels([8, 18]);

var point,
    pointStream = {point: function(x, y) { point = [x, y]; }},
    lower48Point,
    alaskaPoint,
    hawaiiPoint;

function albersUsa(coordinates) {
  var x = coordinates[0], y = coordinates[1];
  point = null;
  (lower48Point(x, y), point)
      || (alaskaPoint(x, y), point)
      || hawaiiPoint(x, y);
  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
      : 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);
  return {
    point: function(x, y) {
      lower48Stream.point(x, y);
      alaskaStream.point(x, y);
      hawaiiStream.point(x, y);
    },
    sphere: function() {
      lower48Stream.sphere();
      alaskaStream.sphere();
      hawaiiStream.sphere();
    },
    lineStart: function() {
      lower48Stream.lineStart();
      alaskaStream.lineStart();
      hawaiiStream.lineStart();
    },
    lineEnd: function() {
      lower48Stream.lineEnd();
      alaskaStream.lineEnd();
      hawaiiStream.lineEnd();
    },
    polygonStart: function() {
      lower48Stream.polygonStart();
      alaskaStream.polygonStart();
      hawaiiStream.polygonStart();
    },
    polygonEnd: function() {
      lower48Stream.polygonEnd();
      alaskaStream.polygonEnd();
      hawaiiStream.polygonEnd();
    }
  };
};

albersUsa.precision = function(_) {
  if (!arguments.length) return lower48.precision();
  lower48.precision(_);
  alaska.precision(_);
  hawaii.precision(_);
  return albersUsa;
};

albersUsa.scale = function(_) {
  if (!arguments.length) return lower48.scale();
  lower48.scale(_);
  alaska.scale(_ * .35);
  hawaii.scale(_);
  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(_)
      .clipExtent([[x - .455 * k, y - .238 * k], [x + .455 * k, y + .238 * k]])
      .stream(pointStream).point;

  alaskaPoint = alaska
      .translate([x - .307 * k, y + .201 * k])
      .clipExtent([[x - .425 * k + ε, y + .120 * k + ε], [x - .214 * k - ε, y + .234 * k - ε]])
      .stream(pointStream).point;

  hawaiiPoint = hawaii
      .translate([x - .205 * k, y + .212 * k])
      .clipExtent([[x - .214 * k + ε, y + .166 * k + ε], [x - .115 * k - ε, y + .234 * k - ε]])
      .stream(pointStream).point;

  return albersUsa;
};

return albersUsa.scale(1070);

};