import clipAntimeridian from "../clip/antimeridian"; import clipCircle from "../clip/circle"; import {clipExtent} from "../clip/extent"; import compose from "../compose"; import identity from "../identity"; import {degrees, radians, sqrt} from "../math"; import {rotateRadians} from "../rotation"; import {transformer} from "../transform"; import {fitExtent, fitSize} from "./fit"; import resample from "./resample"; var transformRadians = transformer({ point: function(x, y) { this.stream.point(x * radians, y * radians); } }); export default function projection(project) { return projectionMutator(function() { return project; })(); } export function projectionMutator(projectAt) { var project, k = 150, // scale x = 480, y = 250, // translate dx, dy, lambda = 0, phi = 0, // center deltaLambda = 0, deltaPhi = 0, deltaGamma = 0, rotate, projectRotate, // rotate theta = null, preclip = clipAntimeridian, // clip angle x0 = null, y0, x1, y1, postclip = identity, // clip extent delta2 = 0.5, projectResample = resample(projectTransform, delta2), // precision cache, cacheStream; function projection(point) { point = projectRotate(point[0] * radians, point[1] * radians); return [point[0] * k + dx, dy - point[1] * k]; } function invert(point) { point = projectRotate.invert((point[0] - dx) / k, (dy - point[1]) / k); return point && [point[0] * degrees, point[1] * degrees]; } function projectTransform(x, y) { return x = project(x, y), [x[0] * k + dx, dy - x[1] * k]; } projection.stream = function(stream) { return cache && cacheStream === stream ? cache : cache = transformRadians(preclip(rotate, projectResample(postclip(cacheStream = stream)))); }; projection.clipAngle = function(_) { return arguments.length ? (preclip = +_ ? clipCircle(theta = _ * radians, 6 * radians) : (theta = null, clipAntimeridian), reset()) : theta * degrees; }; projection.clipExtent = function(_) { return arguments.length ? (postclip = _ == null ? (x0 = y0 = x1 = y1 = null, identity) : clipExtent(x0 = +_[0][0], y0 = +_[0][1], x1 = +_[1][0], y1 = +_[1][1]), reset()) : x0 == null ? null : [[x0, y0], [x1, y1]]; }; projection.scale = function(_) { return arguments.length ? (k = +_, recenter()) : k; }; projection.translate = function(_) { return arguments.length ? (x = +_[0], y = +_[1], recenter()) : [x, y]; }; projection.center = function(_) { return arguments.length ? (lambda = _[0] % 360 * radians, phi = _[1] % 360 * radians, recenter()) : [lambda * degrees, phi * degrees]; }; projection.rotate = function(_) { return arguments.length ? (deltaLambda = _[0] % 360 * radians, deltaPhi = _[1] % 360 * radians, deltaGamma = _.length > 2 ? _[2] % 360 * radians : 0, recenter()) : [deltaLambda * degrees, deltaPhi * degrees, deltaGamma * degrees]; }; projection.precision = function(_) { return arguments.length ? (projectResample = resample(projectTransform, delta2 = _ * _), reset()) : sqrt(delta2); }; projection.fitExtent = function(extent, object) { return fitExtent(projection, extent, object); }; projection.fitSize = function(size, object) { return fitSize(projection, size, object); }; function recenter() { projectRotate = compose(rotate = rotateRadians(deltaLambda, deltaPhi, deltaGamma), project); var center = project(lambda, phi); dx = x - center[0] * k; dy = y + center[1] * k; return reset(); } function reset() { cache = cacheStream = null; return projection; } return function() { project = projectAt.apply(this, arguments); projection.invert = project.invert && invert; return recenter(); }; }