UNPKG

plotly.js

Version:

The open source javascript graphing library that powers plotly

445 lines (439 loc) 19.2 kB
/** * Copyright 2012-2020, Plotly, Inc. * All rights reserved. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ /* * Generated by https://github.com/etpinard/d3-geo-projection-picker * * which is hand-picks projection from https://github.com/d3/d3-geo-projection * * into a CommonJS require-able module. */ 'use strict'; /* eslint-disable */ function addProjectionsToD3(d3) { d3.geo.project = function(object, projection) { var stream = projection.stream; if (!stream) throw new Error("not yet supported"); return (object && d3_geo_projectObjectType.hasOwnProperty(object.type) ? d3_geo_projectObjectType[object.type] : d3_geo_projectGeometry)(object, stream); }; function d3_geo_projectFeature(object, stream) { return { type: "Feature", id: object.id, properties: object.properties, geometry: d3_geo_projectGeometry(object.geometry, stream) }; } function d3_geo_projectGeometry(geometry, stream) { if (!geometry) return null; if (geometry.type === "GeometryCollection") return { type: "GeometryCollection", geometries: object.geometries.map(function(geometry) { return d3_geo_projectGeometry(geometry, stream); }) }; if (!d3_geo_projectGeometryType.hasOwnProperty(geometry.type)) return null; var sink = d3_geo_projectGeometryType[geometry.type]; d3.geo.stream(geometry, stream(sink)); return sink.result(); } var d3_geo_projectObjectType = { Feature: d3_geo_projectFeature, FeatureCollection: function(object, stream) { return { type: "FeatureCollection", features: object.features.map(function(feature) { return d3_geo_projectFeature(feature, stream); }) }; } }; var d3_geo_projectPoints = [], d3_geo_projectLines = []; var d3_geo_projectPoint = { point: function(x, y) { d3_geo_projectPoints.push([ x, y ]); }, result: function() { var result = !d3_geo_projectPoints.length ? null : d3_geo_projectPoints.length < 2 ? { type: "Point", coordinates: d3_geo_projectPoints[0] } : { type: "MultiPoint", coordinates: d3_geo_projectPoints }; d3_geo_projectPoints = []; return result; } }; var d3_geo_projectLine = { lineStart: d3_geo_projectNoop, point: function(x, y) { d3_geo_projectPoints.push([ x, y ]); }, lineEnd: function() { if (d3_geo_projectPoints.length) d3_geo_projectLines.push(d3_geo_projectPoints), d3_geo_projectPoints = []; }, result: function() { var result = !d3_geo_projectLines.length ? null : d3_geo_projectLines.length < 2 ? { type: "LineString", coordinates: d3_geo_projectLines[0] } : { type: "MultiLineString", coordinates: d3_geo_projectLines }; d3_geo_projectLines = []; return result; } }; var d3_geo_projectPolygon = { polygonStart: d3_geo_projectNoop, lineStart: d3_geo_projectNoop, point: function(x, y) { d3_geo_projectPoints.push([ x, y ]); }, lineEnd: function() { var n = d3_geo_projectPoints.length; if (n) { do d3_geo_projectPoints.push(d3_geo_projectPoints[0].slice()); while (++n < 4); d3_geo_projectLines.push(d3_geo_projectPoints), d3_geo_projectPoints = []; } }, polygonEnd: d3_geo_projectNoop, result: function() { if (!d3_geo_projectLines.length) return null; var polygons = [], holes = []; d3_geo_projectLines.forEach(function(ring) { if (d3_geo_projectClockwise(ring)) polygons.push([ ring ]); else holes.push(ring); }); holes.forEach(function(hole) { var point = hole[0]; polygons.some(function(polygon) { if (d3_geo_projectContains(polygon[0], point)) { polygon.push(hole); return true; } }) || polygons.push([ hole ]); }); d3_geo_projectLines = []; return !polygons.length ? null : polygons.length > 1 ? { type: "MultiPolygon", coordinates: polygons } : { type: "Polygon", coordinates: polygons[0] }; } }; var d3_geo_projectGeometryType = { Point: d3_geo_projectPoint, MultiPoint: d3_geo_projectPoint, LineString: d3_geo_projectLine, MultiLineString: d3_geo_projectLine, Polygon: d3_geo_projectPolygon, MultiPolygon: d3_geo_projectPolygon, Sphere: d3_geo_projectPolygon }; function d3_geo_projectNoop() {} function d3_geo_projectClockwise(ring) { if ((n = ring.length) < 4) return false; var i = 0, n, area = ring[n - 1][1] * ring[0][0] - ring[n - 1][0] * ring[0][1]; while (++i < n) area += ring[i - 1][1] * ring[i][0] - ring[i - 1][0] * ring[i][1]; return area <= 0; } function d3_geo_projectContains(ring, point) { var x = point[0], y = point[1], contains = false; for (var i = 0, n = ring.length, j = n - 1; i < n; j = i++) { var pi = ring[i], xi = pi[0], yi = pi[1], pj = ring[j], xj = pj[0], yj = pj[1]; if (yi > y ^ yj > y && x < (xj - xi) * (y - yi) / (yj - yi) + xi) contains = !contains; } return contains; } var ε = 1e-6, ε2 = ε * ε, π = Math.PI, halfπ = π / 2, sqrtπ = Math.sqrt(π), radians = π / 180, degrees = 180 / π; function sinci(x) { return x ? x / Math.sin(x) : 1; } function sgn(x) { return x > 0 ? 1 : x < 0 ? -1 : 0; } function asin(x) { return x > 1 ? halfπ : x < -1 ? -halfπ : Math.asin(x); } function acos(x) { return x > 1 ? 0 : x < -1 ? π : Math.acos(x); } function asqrt(x) { return x > 0 ? Math.sqrt(x) : 0; } var projection = d3.geo.projection, projectionMutator = d3.geo.projectionMutator; d3.geo.interrupt = function(project) { var lobes = [ [ [ [ -π, 0 ], [ 0, halfπ ], [ π, 0 ] ] ], [ [ [ -π, 0 ], [ 0, -halfπ ], [ π, 0 ] ] ] ]; var bounds; function forward(λ, φ) { var sign = φ < 0 ? -1 : +1, hemilobes = lobes[+(φ < 0)]; for (var i = 0, n = hemilobes.length - 1; i < n && λ > hemilobes[i][2][0]; ++i) ; var coordinates = project(λ - hemilobes[i][1][0], φ); coordinates[0] += project(hemilobes[i][1][0], sign * φ > sign * hemilobes[i][0][1] ? hemilobes[i][0][1] : φ)[0]; return coordinates; } function reset() { bounds = lobes.map(function(hemilobes) { return hemilobes.map(function(lobe) { var x0 = project(lobe[0][0], lobe[0][1])[0], x1 = project(lobe[2][0], lobe[2][1])[0], y0 = project(lobe[1][0], lobe[0][1])[1], y1 = project(lobe[1][0], lobe[1][1])[1], t; if (y0 > y1) t = y0, y0 = y1, y1 = t; return [ [ x0, y0 ], [ x1, y1 ] ]; }); }); } if (project.invert) forward.invert = function(x, y) { var hemibounds = bounds[+(y < 0)], hemilobes = lobes[+(y < 0)]; for (var i = 0, n = hemibounds.length; i < n; ++i) { var b = hemibounds[i]; if (b[0][0] <= x && x < b[1][0] && b[0][1] <= y && y < b[1][1]) { var coordinates = project.invert(x - project(hemilobes[i][1][0], 0)[0], y); coordinates[0] += hemilobes[i][1][0]; return pointEqual(forward(coordinates[0], coordinates[1]), [ x, y ]) ? coordinates : null; } } }; var projection = d3.geo.projection(forward), stream_ = projection.stream; projection.stream = function(stream) { var rotate = projection.rotate(), rotateStream = stream_(stream), sphereStream = (projection.rotate([ 0, 0 ]), stream_(stream)); projection.rotate(rotate); rotateStream.sphere = function() { d3.geo.stream(sphere(), sphereStream); }; return rotateStream; }; projection.lobes = function(_) { if (!arguments.length) return lobes.map(function(lobes) { return lobes.map(function(lobe) { return [ [ lobe[0][0] * 180 / π, lobe[0][1] * 180 / π ], [ lobe[1][0] * 180 / π, lobe[1][1] * 180 / π ], [ lobe[2][0] * 180 / π, lobe[2][1] * 180 / π ] ]; }); }); lobes = _.map(function(lobes) { return lobes.map(function(lobe) { return [ [ lobe[0][0] * π / 180, lobe[0][1] * π / 180 ], [ lobe[1][0] * π / 180, lobe[1][1] * π / 180 ], [ lobe[2][0] * π / 180, lobe[2][1] * π / 180 ] ]; }); }); reset(); return projection; }; function sphere() { var ε = 1e-6, coordinates = []; for (var i = 0, n = lobes[0].length; i < n; ++i) { var lobe = lobes[0][i], λ0 = lobe[0][0] * 180 / π, φ0 = lobe[0][1] * 180 / π, φ1 = lobe[1][1] * 180 / π, λ2 = lobe[2][0] * 180 / π, φ2 = lobe[2][1] * 180 / π; coordinates.push(resample([ [ λ0 + ε, φ0 + ε ], [ λ0 + ε, φ1 - ε ], [ λ2 - ε, φ1 - ε ], [ λ2 - ε, φ2 + ε ] ], 30)); } for (var i = lobes[1].length - 1; i >= 0; --i) { var lobe = lobes[1][i], λ0 = lobe[0][0] * 180 / π, φ0 = lobe[0][1] * 180 / π, φ1 = lobe[1][1] * 180 / π, λ2 = lobe[2][0] * 180 / π, φ2 = lobe[2][1] * 180 / π; coordinates.push(resample([ [ λ2 - ε, φ2 - ε ], [ λ2 - ε, φ1 + ε ], [ λ0 + ε, φ1 + ε ], [ λ0 + ε, φ0 - ε ] ], 30)); } return { type: "Polygon", coordinates: [ d3.merge(coordinates) ] }; } function resample(coordinates, m) { var i = -1, n = coordinates.length, p0 = coordinates[0], p1, dx, dy, resampled = []; while (++i < n) { p1 = coordinates[i]; dx = (p1[0] - p0[0]) / m; dy = (p1[1] - p0[1]) / m; for (var j = 0; j < m; ++j) resampled.push([ p0[0] + j * dx, p0[1] + j * dy ]); p0 = p1; } resampled.push(p1); return resampled; } function pointEqual(a, b) { return Math.abs(a[0] - b[0]) < ε && Math.abs(a[1] - b[1]) < ε; } return projection; }; function eckert4(λ, φ) { var k = (2 + halfπ) * Math.sin(φ); φ /= 2; for (var i = 0, δ = Infinity; i < 10 && Math.abs(δ) > ε; i++) { var cosφ = Math.cos(φ); φ -= δ = (φ + Math.sin(φ) * (cosφ + 2) - k) / (2 * cosφ * (1 + cosφ)); } return [ 2 / Math.sqrt(π * (4 + π)) * λ * (1 + Math.cos(φ)), 2 * Math.sqrt(π / (4 + π)) * Math.sin(φ) ]; } eckert4.invert = function(x, y) { var A = .5 * y * Math.sqrt((4 + π) / π), k = asin(A), c = Math.cos(k); return [ x / (2 / Math.sqrt(π * (4 + π)) * (1 + c)), asin((k + A * (c + 2)) / (2 + halfπ)) ]; }; (d3.geo.eckert4 = function() { return projection(eckert4); }).raw = eckert4; var hammerAzimuthalEqualArea = d3.geo.azimuthalEqualArea.raw; function hammer(A, B) { if (arguments.length < 2) B = A; if (B === 1) return hammerAzimuthalEqualArea; if (B === Infinity) return hammerQuarticAuthalic; function forward(λ, φ) { var coordinates = hammerAzimuthalEqualArea(λ / B, φ); coordinates[0] *= A; return coordinates; } forward.invert = function(x, y) { var coordinates = hammerAzimuthalEqualArea.invert(x / A, y); coordinates[0] *= B; return coordinates; }; return forward; } function hammerProjection() { var B = 2, m = projectionMutator(hammer), p = m(B); p.coefficient = function(_) { if (!arguments.length) return B; return m(B = +_); }; return p; } function hammerQuarticAuthalic(λ, φ) { return [ λ * Math.cos(φ) / Math.cos(φ /= 2), 2 * Math.sin(φ) ]; } hammerQuarticAuthalic.invert = function(x, y) { var φ = 2 * asin(y / 2); return [ x * Math.cos(φ / 2) / Math.cos(φ), φ ]; }; (d3.geo.hammer = hammerProjection).raw = hammer; function kavrayskiy7(λ, φ) { return [ 3 * λ / (2 * π) * Math.sqrt(π * π / 3 - φ * φ), φ ]; } kavrayskiy7.invert = function(x, y) { return [ 2 / 3 * π * x / Math.sqrt(π * π / 3 - y * y), y ]; }; (d3.geo.kavrayskiy7 = function() { return projection(kavrayskiy7); }).raw = kavrayskiy7; function miller(λ, φ) { return [ λ, 1.25 * Math.log(Math.tan(π / 4 + .4 * φ)) ]; } miller.invert = function(x, y) { return [ x, 2.5 * Math.atan(Math.exp(.8 * y)) - .625 * π ]; }; (d3.geo.miller = function() { return projection(miller); }).raw = miller; function mollweideBromleyθ(Cp) { return function(θ) { var Cpsinθ = Cp * Math.sin(θ), i = 30, δ; do θ -= δ = (θ + Math.sin(θ) - Cpsinθ) / (1 + Math.cos(θ)); while (Math.abs(δ) > ε && --i > 0); return θ / 2; }; } function mollweideBromley(Cx, Cy, Cp) { var θ = mollweideBromleyθ(Cp); function forward(λ, φ) { return [ Cx * λ * Math.cos(φ = θ(φ)), Cy * Math.sin(φ) ]; } forward.invert = function(x, y) { var θ = asin(y / Cy); return [ x / (Cx * Math.cos(θ)), asin((2 * θ + Math.sin(2 * θ)) / Cp) ]; }; return forward; } var mollweideθ = mollweideBromleyθ(π), mollweide = mollweideBromley(Math.SQRT2 / halfπ, Math.SQRT2, π); (d3.geo.mollweide = function() { return projection(mollweide); }).raw = mollweide; function naturalEarth(λ, φ) { var φ2 = φ * φ, φ4 = φ2 * φ2; return [ λ * (.8707 - .131979 * φ2 + φ4 * (-.013791 + φ4 * (.003971 * φ2 - .001529 * φ4))), φ * (1.007226 + φ2 * (.015085 + φ4 * (-.044475 + .028874 * φ2 - .005916 * φ4))) ]; } naturalEarth.invert = function(x, y) { var φ = y, i = 25, δ; do { var φ2 = φ * φ, φ4 = φ2 * φ2; φ -= δ = (φ * (1.007226 + φ2 * (.015085 + φ4 * (-.044475 + .028874 * φ2 - .005916 * φ4))) - y) / (1.007226 + φ2 * (.015085 * 3 + φ4 * (-.044475 * 7 + .028874 * 9 * φ2 - .005916 * 11 * φ4))); } while (Math.abs(δ) > ε && --i > 0); return [ x / (.8707 + (φ2 = φ * φ) * (-.131979 + φ2 * (-.013791 + φ2 * φ2 * φ2 * (.003971 - .001529 * φ2)))), φ ]; }; (d3.geo.naturalEarth = function() { return projection(naturalEarth); }).raw = naturalEarth; var robinsonConstants = [ [ .9986, -.062 ], [ 1, 0 ], [ .9986, .062 ], [ .9954, .124 ], [ .99, .186 ], [ .9822, .248 ], [ .973, .31 ], [ .96, .372 ], [ .9427, .434 ], [ .9216, .4958 ], [ .8962, .5571 ], [ .8679, .6176 ], [ .835, .6769 ], [ .7986, .7346 ], [ .7597, .7903 ], [ .7186, .8435 ], [ .6732, .8936 ], [ .6213, .9394 ], [ .5722, .9761 ], [ .5322, 1 ] ]; robinsonConstants.forEach(function(d) { d[1] *= 1.0144; }); function robinson(λ, φ) { var i = Math.min(18, Math.abs(φ) * 36 / π), i0 = Math.floor(i), di = i - i0, ax = (k = robinsonConstants[i0])[0], ay = k[1], bx = (k = robinsonConstants[++i0])[0], by = k[1], cx = (k = robinsonConstants[Math.min(19, ++i0)])[0], cy = k[1], k; return [ λ * (bx + di * (cx - ax) / 2 + di * di * (cx - 2 * bx + ax) / 2), (φ > 0 ? halfπ : -halfπ) * (by + di * (cy - ay) / 2 + di * di * (cy - 2 * by + ay) / 2) ]; } robinson.invert = function(x, y) { var yy = y / halfπ, φ = yy * 90, i = Math.min(18, Math.abs(φ / 5)), i0 = Math.max(0, Math.floor(i)); do { var ay = robinsonConstants[i0][1], by = robinsonConstants[i0 + 1][1], cy = robinsonConstants[Math.min(19, i0 + 2)][1], u = cy - ay, v = cy - 2 * by + ay, t = 2 * (Math.abs(yy) - by) / u, c = v / u, di = t * (1 - c * t * (1 - 2 * c * t)); if (di >= 0 || i0 === 1) { φ = (y >= 0 ? 5 : -5) * (di + i); var j = 50, δ; do { i = Math.min(18, Math.abs(φ) / 5); i0 = Math.floor(i); di = i - i0; ay = robinsonConstants[i0][1]; by = robinsonConstants[i0 + 1][1]; cy = robinsonConstants[Math.min(19, i0 + 2)][1]; φ -= (δ = (y >= 0 ? halfπ : -halfπ) * (by + di * (cy - ay) / 2 + di * di * (cy - 2 * by + ay) / 2) - y) * degrees; } while (Math.abs(δ) > ε2 && --j > 0); break; } } while (--i0 >= 0); var ax = robinsonConstants[i0][0], bx = robinsonConstants[i0 + 1][0], cx = robinsonConstants[Math.min(19, i0 + 2)][0]; return [ x / (bx + di * (cx - ax) / 2 + di * di * (cx - 2 * bx + ax) / 2), φ * radians ]; }; (d3.geo.robinson = function() { return projection(robinson); }).raw = robinson; function sinusoidal(λ, φ) { return [ λ * Math.cos(φ), φ ]; } sinusoidal.invert = function(x, y) { return [ x / Math.cos(y), y ]; }; (d3.geo.sinusoidal = function() { return projection(sinusoidal); }).raw = sinusoidal; function aitoff(λ, φ) { var cosφ = Math.cos(φ), sinciα = sinci(acos(cosφ * Math.cos(λ /= 2))); return [ 2 * cosφ * Math.sin(λ) * sinciα, Math.sin(φ) * sinciα ]; } aitoff.invert = function(x, y) { if (x * x + 4 * y * y > π * π + ε) return; var λ = x, φ = y, i = 25; do { var sinλ = Math.sin(λ), sinλ_2 = Math.sin(λ / 2), cosλ_2 = Math.cos(λ / 2), sinφ = Math.sin(φ), cosφ = Math.cos(φ), sin_2φ = Math.sin(2 * φ), sin2φ = sinφ * sinφ, cos2φ = cosφ * cosφ, sin2λ_2 = sinλ_2 * sinλ_2, C = 1 - cos2φ * cosλ_2 * cosλ_2, E = C ? acos(cosφ * cosλ_2) * Math.sqrt(F = 1 / C) : F = 0, F, fx = 2 * E * cosφ * sinλ_2 - x, fy = E * sinφ - y, δxδλ = F * (cos2φ * sin2λ_2 + E * cosφ * cosλ_2 * sin2φ), δxδφ = F * (.5 * sinλ * sin_2φ - E * 2 * sinφ * sinλ_2), δyδλ = F * .25 * (sin_2φ * sinλ_2 - E * sinφ * cos2φ * sinλ), δyδφ = F * (sin2φ * cosλ_2 + E * sin2λ_2 * cosφ), denominator = δxδφ * δyδλ - δyδφ * δxδλ; if (!denominator) break; var δλ = (fy * δxδφ - fx * δyδφ) / denominator, δφ = (fx * δyδλ - fy * δxδλ) / denominator; λ -= δλ, φ -= δφ; } while ((Math.abs(δλ) > ε || Math.abs(δφ) > ε) && --i > 0); return [ λ, φ ]; }; (d3.geo.aitoff = function() { return projection(aitoff); }).raw = aitoff; function winkel3(λ, φ) { var coordinates = aitoff(λ, φ); return [ (coordinates[0] + λ / halfπ) / 2, (coordinates[1] + φ) / 2 ]; } winkel3.invert = function(x, y) { var λ = x, φ = y, i = 25; do { var cosφ = Math.cos(φ), sinφ = Math.sin(φ), sin_2φ = Math.sin(2 * φ), sin2φ = sinφ * sinφ, cos2φ = cosφ * cosφ, sinλ = Math.sin(λ), cosλ_2 = Math.cos(λ / 2), sinλ_2 = Math.sin(λ / 2), sin2λ_2 = sinλ_2 * sinλ_2, C = 1 - cos2φ * cosλ_2 * cosλ_2, E = C ? acos(cosφ * cosλ_2) * Math.sqrt(F = 1 / C) : F = 0, F, fx = .5 * (2 * E * cosφ * sinλ_2 + λ / halfπ) - x, fy = .5 * (E * sinφ + φ) - y, δxδλ = .5 * F * (cos2φ * sin2λ_2 + E * cosφ * cosλ_2 * sin2φ) + .5 / halfπ, δxδφ = F * (sinλ * sin_2φ / 4 - E * sinφ * sinλ_2), δyδλ = .125 * F * (sin_2φ * sinλ_2 - E * sinφ * cos2φ * sinλ), δyδφ = .5 * F * (sin2φ * cosλ_2 + E * sin2λ_2 * cosφ) + .5, denominator = δxδφ * δyδλ - δyδφ * δxδλ, δλ = (fy * δxδφ - fx * δyδφ) / denominator, δφ = (fx * δyδλ - fy * δxδλ) / denominator; λ -= δλ, φ -= δφ; } while ((Math.abs(δλ) > ε || Math.abs(δφ) > ε) && --i > 0); return [ λ, φ ]; }; (d3.geo.winkel3 = function() { return projection(winkel3); }).raw = winkel3; } module.exports = addProjectionsToD3;