three-globe
Version:
Globe data visualization as a ThreeJS reusable 3D object
1,314 lines (1,251 loc) • 205 kB
JavaScript
import { BackSide, BufferAttribute, Color, Mesh, ShaderMaterial, Group, LineBasicMaterial, LineSegments, MeshPhongMaterial, SphereGeometry, SRGBColorSpace, TextureLoader, BufferGeometry, CylinderGeometry, Matrix4, MeshLambertMaterial, Object3D, Vector3, CubicBezierCurve3, Curve, Line, NormalBlending, QuadraticBezierCurve3, TubeGeometry, DoubleSide, MeshBasicMaterial, CircleGeometry, Euler, BoxGeometry, Camera, Frustum, Vector2 } from 'three';
import Kapsule from 'kapsule';
import { Tween, Easing, Group as Group$1 } from '@tweenjs/tween.js';
import SlippyMap from 'three-slippy-map-globe';
import GeoJsonGeometry from 'three-geojson-geometry';
import { geoGraticule10, geoDistance as geoDistance$1, geoInterpolate } from 'd3-geo';
import * as _bfg from 'three/addons/utils/BufferGeometryUtils.js';
import accessorFn from 'accessor-fn';
import { color } from 'd3-color';
import tinyColor from 'tinycolor2';
import DataBindMapper from 'data-bind-mapper';
import _FrameTicker from 'frame-ticker';
import { scaleLinear, scaleQuantize } from 'd3-scale';
import ConicPolygonGeometry from 'three-conic-polygon-geometry';
import indexBy from 'index-array-by';
import { latLngToCell, cellToLatLng, cellToBoundary, polygonToCells } from 'h3-js';
import { interpolateTurbo } from 'd3-scale-chromatic';
import { sum, max } from 'd3-array';
import yaOctree from 'yaot';
import { Line2 } from 'three/addons/lines/Line2.js';
import { LineGeometry } from 'three/addons/lines/LineGeometry.js';
import { LineMaterial } from 'three/addons/lines/LineMaterial.js';
import { interpolateArray } from 'd3-interpolate';
import { TextGeometry } from 'three/addons/geometries/TextGeometry.js';
import { Font } from 'three/addons/loaders/FontLoader.js';
import { CSS2DObject } from 'three/addons/renderers/CSS2DRenderer.js';
function _arrayLikeToArray(r, a) {
(null == a || a > r.length) && (a = r.length);
for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e];
return n;
}
function _arrayWithHoles(r) {
if (Array.isArray(r)) return r;
}
function _arrayWithoutHoles(r) {
if (Array.isArray(r)) return _arrayLikeToArray(r);
}
function _assertClassBrand(e, t, n) {
if ("function" == typeof e ? e === t : e.has(t)) return arguments.length < 3 ? t : n;
throw new TypeError("Private element is not present on this object");
}
function _assertThisInitialized(e) {
if (undefined === e) throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
return e;
}
function _callSuper(t, o, e) {
return o = _getPrototypeOf(o), _possibleConstructorReturn(t, _isNativeReflectConstruct() ? Reflect.construct(o, e || [], _getPrototypeOf(t).constructor) : o.apply(t, e));
}
function _checkPrivateRedeclaration(e, t) {
if (t.has(e)) throw new TypeError("Cannot initialize the same private elements twice on an object");
}
function _classCallCheck(a, n) {
if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function");
}
function _classPrivateFieldGet2(s, a) {
return s.get(_assertClassBrand(s, a));
}
function _classPrivateFieldInitSpec(e, t, a) {
_checkPrivateRedeclaration(e, t), t.set(e, a);
}
function _classPrivateFieldSet2(s, a, r) {
return s.set(_assertClassBrand(s, a), r), r;
}
function _classPrivateMethodInitSpec(e, a) {
_checkPrivateRedeclaration(e, a), a.add(e);
}
function _construct(t, e, r) {
if (_isNativeReflectConstruct()) return Reflect.construct.apply(null, arguments);
var o = [null];
o.push.apply(o, e);
var p = new (t.bind.apply(t, o))();
return p;
}
function _defineProperties(e, r) {
for (var t = 0; t < r.length; t++) {
var o = r[t];
o.enumerable = o.enumerable || false, o.configurable = true, "value" in o && (o.writable = true), Object.defineProperty(e, _toPropertyKey(o.key), o);
}
}
function _createClass(e, r, t) {
return r && _defineProperties(e.prototype, r), Object.defineProperty(e, "prototype", {
writable: false
}), e;
}
function _defineProperty(e, r, t) {
return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, {
value: t,
enumerable: true,
configurable: true,
writable: true
}) : e[r] = t, e;
}
function _get() {
return _get = "undefined" != typeof Reflect && Reflect.get ? Reflect.get.bind() : function (e, t, r) {
var p = _superPropBase(e, t);
if (p) {
var n = Object.getOwnPropertyDescriptor(p, t);
return n.get ? n.get.call(arguments.length < 3 ? e : r) : n.value;
}
}, _get.apply(null, arguments);
}
function _getPrototypeOf(t) {
return _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf.bind() : function (t) {
return t.__proto__ || Object.getPrototypeOf(t);
}, _getPrototypeOf(t);
}
function _inherits(t, e) {
if ("function" != typeof e && null !== e) throw new TypeError("Super expression must either be null or a function");
t.prototype = Object.create(e && e.prototype, {
constructor: {
value: t,
writable: true,
configurable: true
}
}), Object.defineProperty(t, "prototype", {
writable: false
}), e && _setPrototypeOf(t, e);
}
function _isNativeReflectConstruct() {
try {
var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {}));
} catch (t) {}
return (_isNativeReflectConstruct = function () {
return !!t;
})();
}
function _iterableToArray(r) {
if ("undefined" != typeof Symbol && null != r[Symbol.iterator] || null != r["@@iterator"]) return Array.from(r);
}
function _iterableToArrayLimit(r, l) {
var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"];
if (null != t) {
var e,
n,
i,
u,
a = [],
f = true,
o = false;
try {
if (i = (t = t.call(r)).next, 0 === l) {
if (Object(t) !== t) return;
f = !1;
} else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0);
} catch (r) {
o = true, n = r;
} finally {
try {
if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return;
} finally {
if (o) throw n;
}
}
return a;
}
}
function _nonIterableRest() {
throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
}
function _nonIterableSpread() {
throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
}
function ownKeys(e, r) {
var t = Object.keys(e);
if (Object.getOwnPropertySymbols) {
var o = Object.getOwnPropertySymbols(e);
r && (o = o.filter(function (r) {
return Object.getOwnPropertyDescriptor(e, r).enumerable;
})), t.push.apply(t, o);
}
return t;
}
function _objectSpread2(e) {
for (var r = 1; r < arguments.length; r++) {
var t = null != arguments[r] ? arguments[r] : {};
r % 2 ? ownKeys(Object(t), true).forEach(function (r) {
_defineProperty(e, r, t[r]);
}) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) {
Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r));
});
}
return e;
}
function _objectWithoutProperties(e, t) {
if (null == e) return {};
var o,
r,
i = _objectWithoutPropertiesLoose(e, t);
if (Object.getOwnPropertySymbols) {
var s = Object.getOwnPropertySymbols(e);
for (r = 0; r < s.length; r++) o = s[r], t.includes(o) || {}.propertyIsEnumerable.call(e, o) && (i[o] = e[o]);
}
return i;
}
function _objectWithoutPropertiesLoose(r, e) {
if (null == r) return {};
var t = {};
for (var n in r) if ({}.hasOwnProperty.call(r, n)) {
if (e.includes(n)) continue;
t[n] = r[n];
}
return t;
}
function _possibleConstructorReturn(t, e) {
if (e && ("object" == typeof e || "function" == typeof e)) return e;
if (undefined !== e) throw new TypeError("Derived constructors may only return object or undefined");
return _assertThisInitialized(t);
}
function _setPrototypeOf(t, e) {
return _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function (t, e) {
return t.__proto__ = e, t;
}, _setPrototypeOf(t, e);
}
function _slicedToArray(r, e) {
return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest();
}
function _superPropBase(t, o) {
for (; !{}.hasOwnProperty.call(t, o) && null !== (t = _getPrototypeOf(t)););
return t;
}
function _superPropGet(t, o, e, r) {
var p = _get(_getPrototypeOf(t.prototype ), o, e);
return "function" == typeof p ? function (t) {
return p.apply(e, t);
} : p;
}
function _toConsumableArray(r) {
return _arrayWithoutHoles(r) || _iterableToArray(r) || _unsupportedIterableToArray(r) || _nonIterableSpread();
}
function _toPrimitive(t, r) {
if ("object" != typeof t || !t) return t;
var e = t[Symbol.toPrimitive];
if (undefined !== e) {
var i = e.call(t, r || "default");
if ("object" != typeof i) return i;
throw new TypeError("@@toPrimitive must return a primitive value.");
}
return ("string" === r ? String : Number)(t);
}
function _toPropertyKey(t) {
var i = _toPrimitive(t, "string");
return "symbol" == typeof i ? i : i + "";
}
function _unsupportedIterableToArray(r, a) {
if (r) {
if ("string" == typeof r) return _arrayLikeToArray(r, a);
var t = {}.toString.call(r).slice(8, -1);
return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : undefined;
}
}
var _materialDispose = function materialDispose(material) {
if (material instanceof Array) {
material.forEach(_materialDispose);
} else {
if (material.map) {
material.map.dispose();
}
material.dispose();
}
};
var _deallocate = function deallocate(obj) {
if (obj.geometry) {
obj.geometry.dispose();
}
if (obj.material) {
_materialDispose(obj.material);
}
if (obj.texture) {
obj.texture.dispose();
}
if (obj.children) {
obj.children.forEach(_deallocate);
}
};
var emptyObject = function emptyObject(obj) {
if (obj && obj.children) while (obj.children.length) {
var childObj = obj.children[0];
obj.remove(childObj);
_deallocate(childObj);
}
};
function linkKapsule (kapsulePropName, kapsuleType) {
var dummyK = new kapsuleType(); // To extract defaults
return {
linkProp: function linkProp(prop) {
// link property config
return {
"default": dummyK[prop](),
onChange: function onChange(v, state) {
state[kapsulePropName][prop](v);
},
triggerUpdate: false
};
},
linkMethod: function linkMethod(method) {
// link method pass-through
return function (state) {
var kapsuleInstance = state[kapsulePropName];
for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
args[_key - 1] = arguments[_key];
}
var returnVal = kapsuleInstance[method].apply(kapsuleInstance, args);
return returnVal === kapsuleInstance ? this // chain based on the parent object, not the inner kapsule
: returnVal;
};
}
};
}
var GLOBE_RADIUS = 100;
function getGlobeRadius() {
return GLOBE_RADIUS;
}
function polar2Cartesian(lat, lng) {
var relAltitude = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;
var phi = (90 - lat) * Math.PI / 180;
var theta = (90 - lng) * Math.PI / 180;
var r = GLOBE_RADIUS * (1 + relAltitude);
return {
x: r * Math.sin(phi) * Math.cos(theta),
y: r * Math.cos(phi),
z: r * Math.sin(phi) * Math.sin(theta)
};
}
function cartesian2Polar(_ref) {
var x = _ref.x,
y = _ref.y,
z = _ref.z;
var r = Math.sqrt(x * x + y * y + z * z);
var phi = Math.acos(y / r);
var theta = Math.atan2(z, x);
return {
lat: 90 - phi * 180 / Math.PI,
lng: 90 - theta * 180 / Math.PI - (theta < -Math.PI / 2 ? 360 : 0),
// keep within [-180, 180] boundaries
altitude: r / GLOBE_RADIUS - 1
};
}
function deg2Rad$1(deg) {
return deg * Math.PI / 180;
}
var THREE$h = window.THREE ? window.THREE // Prefer consumption from global THREE, if exists
: {
BackSide: BackSide,
BufferAttribute: BufferAttribute,
Color: Color,
Mesh: Mesh,
ShaderMaterial: ShaderMaterial
};
var vertexShader = "\nuniform float hollowRadius;\n\nvarying vec3 vVertexWorldPosition;\nvarying vec3 vVertexNormal;\nvarying float vCameraDistanceToObjCenter;\nvarying float vVertexAngularDistanceToHollowRadius;\n\nvoid main() { \n vVertexNormal\t= normalize(normalMatrix * normal);\n vVertexWorldPosition = (modelMatrix * vec4(position, 1.0)).xyz;\n \n vec4 objCenterViewPosition = modelViewMatrix * vec4(0.0, 0.0, 0.0, 1.0);\n vCameraDistanceToObjCenter = length(objCenterViewPosition);\n \n float edgeAngle = atan(hollowRadius / vCameraDistanceToObjCenter);\n float vertexAngle = acos(dot(normalize(modelViewMatrix * vec4(position, 1.0)), normalize(objCenterViewPosition)));\n vVertexAngularDistanceToHollowRadius = vertexAngle - edgeAngle;\n\n gl_Position\t= projectionMatrix * modelViewMatrix * vec4(position, 1.0);\n}";
var fragmentShader = "\nuniform vec3 color;\nuniform float coefficient;\nuniform float power;\nuniform float hollowRadius;\n\nvarying vec3 vVertexNormal;\nvarying vec3 vVertexWorldPosition;\nvarying float vCameraDistanceToObjCenter;\nvarying float vVertexAngularDistanceToHollowRadius;\n\nvoid main() {\n if (vCameraDistanceToObjCenter < hollowRadius) discard; // inside the hollowRadius\n if (vVertexAngularDistanceToHollowRadius < 0.0) discard; // frag position is within the hollow radius\n\n vec3 worldCameraToVertex = vVertexWorldPosition - cameraPosition;\n vec3 viewCameraToVertex\t= (viewMatrix * vec4(worldCameraToVertex, 0.0)).xyz;\n viewCameraToVertex = normalize(viewCameraToVertex);\n float intensity\t= pow(\n coefficient + dot(vVertexNormal, viewCameraToVertex),\n power\n );\n gl_FragColor = vec4(color, intensity);\n}";
// Based off: http://stemkoski.blogspot.fr/2013/07/shaders-in-threejs-glow-and-halo.html
function createGlowMaterial(coefficient, color, power, hollowRadius) {
return new THREE$h.ShaderMaterial({
depthWrite: false,
transparent: true,
vertexShader: vertexShader,
fragmentShader: fragmentShader,
uniforms: {
coefficient: {
value: coefficient
},
color: {
value: new THREE$h.Color(color)
},
power: {
value: power
},
hollowRadius: {
value: hollowRadius
}
}
});
}
function createGlowGeometry(geometry, size) {
var glowGeometry = geometry.clone();
// Resize vertex positions according to normals
var position = new Float32Array(geometry.attributes.position.count * 3);
for (var idx = 0, len = position.length; idx < len; idx++) {
var normal = geometry.attributes.normal.array[idx];
var curPos = geometry.attributes.position.array[idx];
position[idx] = curPos + normal * size;
}
glowGeometry.setAttribute('position', new THREE$h.BufferAttribute(position, 3));
return glowGeometry;
}
var GlowMesh = /*#__PURE__*/function (_THREE$Mesh) {
function GlowMesh(geometry) {
var _this;
var _ref = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {},
_ref$color = _ref.color,
color = _ref$color === undefined ? 'gold' : _ref$color,
_ref$size = _ref.size,
size = _ref$size === undefined ? 2 : _ref$size,
_ref$coefficient = _ref.coefficient,
coefficient = _ref$coefficient === undefined ? 0.5 : _ref$coefficient,
_ref$power = _ref.power,
power = _ref$power === undefined ? 1 : _ref$power,
_ref$hollowRadius = _ref.hollowRadius,
hollowRadius = _ref$hollowRadius === undefined ? 0 : _ref$hollowRadius,
_ref$backside = _ref.backside,
backside = _ref$backside === undefined ? true : _ref$backside;
_classCallCheck(this, GlowMesh);
_this = _callSuper(this, GlowMesh);
var glowGeometry = createGlowGeometry(geometry, size);
var glowMaterial = createGlowMaterial(coefficient, color, power, hollowRadius);
backside && (glowMaterial.side = THREE$h.BackSide);
_this.geometry = glowGeometry;
_this.material = glowMaterial;
return _this;
}
_inherits(GlowMesh, _THREE$Mesh);
return _createClass(GlowMesh);
}(THREE$h.Mesh);
var THREE$g = window.THREE ? window.THREE // Prefer consumption from global THREE, if exists
: {
Color: Color,
Group: Group,
LineBasicMaterial: LineBasicMaterial,
LineSegments: LineSegments,
Mesh: Mesh,
MeshPhongMaterial: MeshPhongMaterial,
SphereGeometry: SphereGeometry,
SRGBColorSpace: SRGBColorSpace,
TextureLoader: TextureLoader
};
//
var GlobeLayerKapsule = Kapsule({
props: {
globeImageUrl: {},
bumpImageUrl: {},
showGlobe: {
"default": true,
onChange: function onChange(showGlobe, state) {
state.globeGroup.visible = !!showGlobe;
},
triggerUpdate: false
},
showGraticules: {
"default": false,
onChange: function onChange(showGraticules, state) {
state.graticulesObj.visible = !!showGraticules;
},
triggerUpdate: false
},
showAtmosphere: {
"default": true,
onChange: function onChange(showAtmosphere, state) {
state.atmosphereObj && (state.atmosphereObj.visible = !!showAtmosphere);
},
triggerUpdate: false
},
atmosphereColor: {
"default": 'lightskyblue'
},
atmosphereAltitude: {
"default": 0.15
},
globeTileEngineUrl: {
onChange: function onChange(v, state) {
state.tileEngine.tileUrl = v;
},
triggerUpdate: false
},
globeTileEngineMaxLevel: {
"default": 17,
onChange: function onChange(v, state) {
state.tileEngine.maxLevel = v;
},
triggerUpdate: false
},
updatePov: {
onChange: function onChange(v, state) {
state.tileEngine.updatePov(v);
},
triggerUpdate: false
},
onReady: {
"default": function _default() {},
triggerUpdate: false
}
},
methods: {
globeMaterial: function globeMaterial(state, _globeMaterial) {
if (_globeMaterial !== undefined) {
state.globeObj.material = _globeMaterial || state.defaultGlobeMaterial;
return this;
}
return state.globeObj.material;
},
_destructor: function _destructor(state) {
emptyObject(state.globeObj);
emptyObject(state.tileEngine);
emptyObject(state.graticulesObj);
}
},
stateInit: function stateInit() {
// create globe
var globeGeometry = new THREE$g.SphereGeometry(GLOBE_RADIUS, 75, 75);
var defaultGlobeMaterial = new THREE$g.MeshPhongMaterial({
color: 0x000000
});
var globeObj = new THREE$g.Mesh(globeGeometry, defaultGlobeMaterial);
globeObj.rotation.y = -Math.PI / 2; // face prime meridian along Z axis
// Create empty tile engine
var tileEngine = new SlippyMap(GLOBE_RADIUS);
// Group including globe and tile engine
var globeGroup = new THREE$g.Group();
globeGroup.__globeObjType = 'globe'; // Add object type
globeGroup.add(globeObj);
globeGroup.add(tileEngine);
// create graticules
var graticulesObj = new THREE$g.LineSegments(new GeoJsonGeometry(geoGraticule10(), GLOBE_RADIUS, 2), new THREE$g.LineBasicMaterial({
color: 'lightgrey',
transparent: true,
opacity: 0.1
}));
return {
globeGroup: globeGroup,
globeObj: globeObj,
graticulesObj: graticulesObj,
defaultGlobeMaterial: defaultGlobeMaterial,
tileEngine: tileEngine
};
},
init: function init(threeObj, state) {
// Clear the scene
emptyObject(threeObj);
// Main three object to manipulate
state.scene = threeObj;
state.scene.add(state.globeGroup); // add globe
state.scene.add(state.graticulesObj); // add graticules
state.ready = false;
},
update: function update(state, changedProps) {
var globeMaterial = state.globeObj.material;
// Hide globeObj if it's representing tiles
state.globeObj.visible = !state.globeTileEngineUrl;
if (changedProps.hasOwnProperty('globeImageUrl')) {
if (!state.globeImageUrl) {
// Black globe if no image
!globeMaterial.color && (globeMaterial.color = new THREE$g.Color(0x000000));
} else {
new THREE$g.TextureLoader().load(state.globeImageUrl, function (texture) {
texture.colorSpace = THREE$g.SRGBColorSpace;
globeMaterial.map = texture;
globeMaterial.color = null;
globeMaterial.needsUpdate = true;
// ready when first globe image finishes loading (asynchronously to allow 1 frame to load texture)
!state.ready && (state.ready = true) && setTimeout(state.onReady);
});
}
}
if (changedProps.hasOwnProperty('bumpImageUrl')) {
if (!state.bumpImageUrl) {
globeMaterial.bumpMap = null;
globeMaterial.needsUpdate = true;
} else {
state.bumpImageUrl && new THREE$g.TextureLoader().load(state.bumpImageUrl, function (texture) {
globeMaterial.bumpMap = texture;
globeMaterial.needsUpdate = true;
});
}
}
if (changedProps.hasOwnProperty('atmosphereColor') || changedProps.hasOwnProperty('atmosphereAltitude')) {
if (state.atmosphereObj) {
// recycle previous atmosphere object
state.scene.remove(state.atmosphereObj);
emptyObject(state.atmosphereObj);
}
if (state.atmosphereColor && state.atmosphereAltitude) {
var obj = state.atmosphereObj = new GlowMesh(state.globeObj.geometry, {
color: state.atmosphereColor,
size: GLOBE_RADIUS * state.atmosphereAltitude,
hollowRadius: GLOBE_RADIUS,
coefficient: 0.1,
power: 3.5 // dispersion
});
obj.visible = !!state.showAtmosphere;
obj.__globeObjType = 'atmosphere'; // Add object type
state.scene.add(obj);
}
}
if (!state.ready && (!state.globeImageUrl || state.globeTileEngineUrl)) {
// ready immediately if there's no globe image
state.ready = true;
state.onReady();
}
}
});
var colorStr2Hex = function colorStr2Hex(str) {
return isNaN(str) ? parseInt(tinyColor(str).toHex(), 16) : str;
};
var colorAlpha = function colorAlpha(str) {
return str && isNaN(str) ? color(str).opacity : 1;
};
var color2ShaderArr = function color2ShaderArr(str) {
var includeAlpha = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
var sRGBColorSpace = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
var color;
var alpha = 1;
var rgbaMatch = /^rgba\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*,\s*([\d.eE+-]+)\s*\)$/.exec(str.trim().toLowerCase());
if (rgbaMatch) {
var _rgbaMatch$slice = rgbaMatch.slice(1),
_rgbaMatch$slice2 = _slicedToArray(_rgbaMatch$slice, 4),
r = _rgbaMatch$slice2[0],
g = _rgbaMatch$slice2[1],
b = _rgbaMatch$slice2[2],
a = _rgbaMatch$slice2[3];
color = new Color("rgb(".concat(+r, ",").concat(+g, ",").concat(+b, ")"));
alpha = Math.min(+a, 1);
} else {
color = new Color(str);
}
sRGBColorSpace && color.convertLinearToSRGB(); // vertexColors expects linear, but shaders expect sRGB
var rgbArr = color.toArray();
return includeAlpha ? [].concat(_toConsumableArray(rgbArr), [alpha]) : rgbArr;
};
function setMaterialOpacity(material, opacity, depthWrite) {
material.opacity = opacity;
material.transparent = opacity < 1;
material.depthWrite = opacity >= 1 ; // depthWrite=false recommended for transparent materials, to prevent transparency issues https://discourse.threejs.org/t/threejs-and-the-transparent-problem/11553/31
return material;
}
var THREE$f = window.THREE ? window.THREE // Prefer consumption from global THREE, if exists
: {
BufferAttribute: BufferAttribute
};
function array2BufferAttr(data) {
var itemSize = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1;
var ArrayClass = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : Float32Array;
if (itemSize === 1) {
// edge case handle for improved performance
return new THREE$f.BufferAttribute(new ArrayClass(data), itemSize);
}
var ba = new THREE$f.BufferAttribute(new ArrayClass(data.length * itemSize), itemSize);
for (var idx = 0, l = data.length; idx < l; idx++) {
ba.set(data[idx], idx * itemSize);
}
return ba;
}
function bufferAttr2Array(ba) {
var itemSize = ba.itemSize;
var res = [];
for (var i = 0; i < ba.count; i++) {
res.push(ba.array.slice(i * itemSize, (i + 1) * itemSize));
}
return res;
}
var _dataBindAttr = /*#__PURE__*/new WeakMap();
var _objBindAttr = /*#__PURE__*/new WeakMap();
var _removeDelay = /*#__PURE__*/new WeakMap();
var ThreeDigest = /*#__PURE__*/function (_DataBindMapper) {
function ThreeDigest(scene) {
var _this;
var _ref = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {},
_ref$dataBindAttr = _ref.dataBindAttr,
dataBindAttr = _ref$dataBindAttr === undefined ? '__data' : _ref$dataBindAttr,
_ref$objBindAttr = _ref.objBindAttr,
objBindAttr = _ref$objBindAttr === undefined ? '__threeObj' : _ref$objBindAttr,
_ref$removeDelay = _ref.removeDelay,
removeDelay = _ref$removeDelay === undefined ? 0 : _ref$removeDelay;
_classCallCheck(this, ThreeDigest);
_this = _callSuper(this, ThreeDigest);
_defineProperty(_this, "scene", undefined);
_classPrivateFieldInitSpec(_this, _dataBindAttr, undefined);
_classPrivateFieldInitSpec(_this, _objBindAttr, undefined);
_classPrivateFieldInitSpec(_this, _removeDelay, undefined);
_this.scene = scene;
_classPrivateFieldSet2(_dataBindAttr, _this, dataBindAttr);
_classPrivateFieldSet2(_objBindAttr, _this, objBindAttr);
_classPrivateFieldSet2(_removeDelay, _this, removeDelay);
_this.onRemoveObj(function () {});
return _this;
}
_inherits(ThreeDigest, _DataBindMapper);
return _createClass(ThreeDigest, [{
key: "onCreateObj",
value: function onCreateObj(fn) {
var _this2 = this;
_superPropGet(ThreeDigest, "onCreateObj", this)([function (d) {
var obj = fn(d);
d[_classPrivateFieldGet2(_objBindAttr, _this2)] = obj;
obj[_classPrivateFieldGet2(_dataBindAttr, _this2)] = d;
_this2.scene.add(obj);
return obj;
}]);
return this;
}
}, {
key: "onRemoveObj",
value: function onRemoveObj(fn) {
var _this3 = this;
_superPropGet(ThreeDigest, "onRemoveObj", this)([function (obj, dId) {
var d = _superPropGet(ThreeDigest, "getData", _this3)([obj]);
fn(obj, dId);
var removeFn = function removeFn() {
_this3.scene.remove(obj);
emptyObject(obj);
delete d[_classPrivateFieldGet2(_objBindAttr, _this3)];
};
_classPrivateFieldGet2(_removeDelay, _this3) ? setTimeout(removeFn, _classPrivateFieldGet2(_removeDelay, _this3)) : removeFn();
}]);
return this;
}
}]);
}(DataBindMapper);
var THREE$e = window.THREE ? window.THREE // Prefer consumption from global THREE, if exists
: {
BufferGeometry: BufferGeometry,
Color: Color,
CylinderGeometry: CylinderGeometry,
Matrix4: Matrix4,
Mesh: Mesh,
MeshLambertMaterial: MeshLambertMaterial,
Object3D: Object3D,
Vector3: Vector3
};
var bfg$2 = Object.assign({}, _bfg);
var BufferGeometryUtils$2 = bfg$2.BufferGeometryUtils || bfg$2;
//
var PointsLayerKapsule = Kapsule({
props: {
pointsData: {
"default": []
},
pointLat: {
"default": 'lat'
},
pointLng: {
"default": 'lng'
},
pointColor: {
"default": function _default() {
return '#ffffaa';
}
},
pointAltitude: {
"default": 0.1
},
// in units of globe radius
pointRadius: {
"default": 0.25
},
// in deg
pointResolution: {
"default": 12,
triggerUpdate: false
},
// how many slice segments in the cylinder's circumference
pointsMerge: {
"default": false
},
// boolean. Whether to merge all points into a single mesh for rendering performance
pointsTransitionDuration: {
"default": 1000,
triggerUpdate: false
} // ms
},
init: function init(threeObj, state, _ref) {
var tweenGroup = _ref.tweenGroup;
// Clear the scene
emptyObject(threeObj);
// Main three object to manipulate
state.scene = threeObj;
state.tweenGroup = tweenGroup;
state.dataMapper = new ThreeDigest(threeObj, {
objBindAttr: '__threeObjPoint'
});
},
update: function update(state, changedProps) {
// Data accessors
var latAccessor = accessorFn(state.pointLat);
var lngAccessor = accessorFn(state.pointLng);
var altitudeAccessor = accessorFn(state.pointAltitude);
var radiusAccessor = accessorFn(state.pointRadius);
var colorAccessor = accessorFn(state.pointColor);
// shared geometry
var pointGeometry = new THREE$e.CylinderGeometry(1, 1, 1, state.pointResolution);
pointGeometry.applyMatrix4(new THREE$e.Matrix4().makeRotationX(Math.PI / 2));
pointGeometry.applyMatrix4(new THREE$e.Matrix4().makeTranslation(0, 0, -0.5));
var pxPerDeg = 2 * Math.PI * GLOBE_RADIUS / 360;
var pointMaterials = {}; // indexed by color
if (!state.pointsMerge && changedProps.hasOwnProperty('pointsMerge')) {
emptyObject(state.scene); // Empty trailing merged objects
}
state.dataMapper.scene = state.pointsMerge ? new THREE$e.Object3D() : state.scene; // use fake scene if merging points
state.dataMapper.onCreateObj(createObj).onUpdateObj(updateObj).digest(state.pointsData);
if (state.pointsMerge) {
// merge points into a single mesh
var pointsGeometry = !state.pointsData.length ? new THREE$e.BufferGeometry() : (BufferGeometryUtils$2.mergeGeometries || BufferGeometryUtils$2.mergeBufferGeometries)(state.pointsData.map(function (d) {
var obj = state.dataMapper.getObj(d);
var geom = obj.geometry.clone();
// apply mesh world transform to vertices
obj.updateMatrix();
geom.applyMatrix4(obj.matrix);
// color vertices
var color = color2ShaderArr(colorAccessor(d));
geom.setAttribute('color', array2BufferAttr(Array(geom.getAttribute('position').count).fill(color), 4));
return geom;
}));
var points = new THREE$e.Mesh(pointsGeometry, new THREE$e.MeshLambertMaterial({
color: 0xffffff,
transparent: true,
vertexColors: true
}));
points.__globeObjType = 'points'; // Add object type
points.__data = state.pointsData; // Attach obj data
state.dataMapper.clear(); // Unbind merged points
emptyObject(state.scene);
state.scene.add(points);
}
//
function createObj() {
var obj = new THREE$e.Mesh(pointGeometry);
obj.__globeObjType = 'point'; // Add object type
return obj;
}
function updateObj(obj, d) {
var applyUpdate = function applyUpdate(td) {
var _obj$__currentTargetD = obj.__currentTargetD = td,
r = _obj$__currentTargetD.r,
alt = _obj$__currentTargetD.alt,
lat = _obj$__currentTargetD.lat,
lng = _obj$__currentTargetD.lng;
// position cylinder ground
Object.assign(obj.position, polar2Cartesian(lat, lng));
// orientate outwards
var globeCenter = state.pointsMerge ? new THREE$e.Vector3(0, 0, 0) : state.scene.localToWorld(new THREE$e.Vector3(0, 0, 0)); // translate from local to world coords
obj.lookAt(globeCenter);
// scale radius and altitude
obj.scale.x = obj.scale.y = Math.min(30, r) * pxPerDeg;
obj.scale.z = Math.max(alt * GLOBE_RADIUS, 0.1); // avoid non-invertible matrix
};
var targetD = {
alt: +altitudeAccessor(d),
r: +radiusAccessor(d),
lat: +latAccessor(d),
lng: +lngAccessor(d)
};
var currentTargetD = obj.__currentTargetD || Object.assign({}, targetD, {
alt: -1e-3
});
if (Object.keys(targetD).some(function (k) {
return currentTargetD[k] !== targetD[k];
})) {
if (state.pointsMerge || !state.pointsTransitionDuration || state.pointsTransitionDuration < 0) {
// set final position
applyUpdate(targetD);
} else {
// animate
state.tweenGroup.add(new Tween(currentTargetD).to(targetD, state.pointsTransitionDuration).easing(Easing.Quadratic.InOut).onUpdate(applyUpdate).start());
}
}
if (!state.pointsMerge) {
// Update materials on individual points
var color = colorAccessor(d);
var opacity = color ? colorAlpha(color) : 0;
var showCyl = !!opacity;
obj.visible = showCyl;
if (showCyl) {
if (!pointMaterials.hasOwnProperty(color)) {
pointMaterials[color] = new THREE$e.MeshLambertMaterial({
color: colorStr2Hex(color),
transparent: opacity < 1,
opacity: opacity
});
}
obj.material = pointMaterials[color];
}
}
}
}
});
var dashedLineShaders = function dashedLineShaders() {
return {
uniforms: {
// dash param defaults, all relative to full length
dashOffset: {
value: 0
},
dashSize: {
value: 1
},
gapSize: {
value: 0
},
dashTranslate: {
value: 0
} // used for animating the dash
},
vertexShader: "\n uniform float dashTranslate; \n\n attribute vec4 color;\n varying vec4 vColor;\n \n attribute float relDistance;\n varying float vRelDistance;\n\n void main() {\n // pass through colors and distances\n vColor = color;\n vRelDistance = relDistance + dashTranslate;\n gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);\n }\n ",
fragmentShader: "\n uniform float dashOffset; \n uniform float dashSize;\n uniform float gapSize; \n \n varying vec4 vColor;\n varying float vRelDistance;\n \n void main() {\n // ignore pixels in the gap\n if (vRelDistance < dashOffset) discard;\n if (mod(vRelDistance - dashOffset, dashSize + gapSize) > dashSize) discard;\n \n // set px color: [r, g, b, a], interpolated between vertices \n gl_FragColor = vColor; \n }\n "
};
};
var invisibleUndergroundShaderExtend = function invisibleUndergroundShaderExtend(shader) {
shader.uniforms.surfaceRadius = {
type: 'float',
value: 0
};
shader.vertexShader = ('attribute float surfaceRadius;\nvarying float vSurfaceRadius;\nvarying vec3 vPos;\n' + shader.vertexShader).replace('void main() {', ['void main() {', 'vSurfaceRadius = surfaceRadius;', 'vPos = position;'].join('\n'));
shader.fragmentShader = ('uniform float surfaceRadius;\nvarying float vSurfaceRadius;\nvarying vec3 vPos;\n' + shader.fragmentShader).replace('void main() {', ['void main() {', 'if (length(vPos) < max(surfaceRadius, vSurfaceRadius)) discard;'].join('\n'));
return shader;
};
var setRadiusShaderExtend = function setRadiusShaderExtend(shader) {
shader.vertexShader = "\n attribute float r;\n \n const float PI = 3.1415926535897932384626433832795;\n float toRad(in float a) {\n return a * PI / 180.0;\n }\n \n vec3 Polar2Cartesian(in vec3 c) { // [lat, lng, r]\n float phi = toRad(90.0 - c.x);\n float theta = toRad(90.0 - c.y);\n float r = c.z;\n return vec3( // x,y,z\n r * sin(phi) * cos(theta),\n r * cos(phi),\n r * sin(phi) * sin(theta)\n );\n }\n \n vec2 Cartesian2Polar(in vec3 p) {\n float r = sqrt(p.x * p.x + p.y * p.y + p.z * p.z);\n float phi = acos(p.y / r);\n float theta = atan(p.z, p.x);\n return vec2( // lat,lng\n 90.0 - phi * 180.0 / PI,\n 90.0 - theta * 180.0 / PI - (theta < -PI / 2.0 ? 360.0 : 0.0)\n );\n }\n ".concat(shader.vertexShader.replace('}', " \n vec3 pos = Polar2Cartesian(vec3(Cartesian2Polar(position), r));\n gl_Position = projectionMatrix * modelViewMatrix * vec4(pos, 1.0);\n }\n "), "\n ");
return shader;
};
//
var applyShaderExtensionToMaterial = function applyShaderExtensionToMaterial(material, extensionFn) {
material.onBeforeCompile = function (shader) {
material.userData.shader = extensionFn(shader);
};
return material;
};
var setExtendedMaterialUniforms = function setExtendedMaterialUniforms(material) {
var uniformsFn = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : function (u) {
return u;
};
if (material.userData.shader) {
uniformsFn(material.userData.shader.uniforms);
} else {
var curFn = material.onBeforeCompile;
material.onBeforeCompile = function (shader) {
curFn(shader);
uniformsFn(shader.uniforms);
};
}
};
var _excluded = ["stroke"];
var THREE$d = window.THREE ? window.THREE // Prefer consumption from global THREE, if exists
: {
BufferGeometry: BufferGeometry,
CubicBezierCurve3: CubicBezierCurve3,
Curve: Curve,
Group: Group,
Line: Line,
Mesh: Mesh,
NormalBlending: NormalBlending,
QuadraticBezierCurve3: QuadraticBezierCurve3,
ShaderMaterial: ShaderMaterial,
TubeGeometry: TubeGeometry,
Vector3: Vector3
};
var FrameTicker$2 = _FrameTicker["default"] || _FrameTicker;
//
var ArcsLayerKapsule = Kapsule({
props: {
arcsData: {
"default": []
},
arcStartLat: {
"default": 'startLat'
},
arcStartLng: {
"default": 'startLng'
},
arcEndLat: {
"default": 'endLat'
},
arcEndLng: {
"default": 'endLng'
},
arcColor: {
"default": function _default() {
return '#ffffaa';
}
},
// single color, array of colors or color interpolation fn
arcAltitude: {},
// in units of globe radius
arcAltitudeAutoScale: {
"default": 0.5
},
// scale altitude proportional to great-arc distance between the two points
arcStroke: {},
// in deg
arcCurveResolution: {
"default": 64,
triggerUpdate: false
},
// how many straight segments in the curve
arcCircularResolution: {
"default": 6,
triggerUpdate: false
},
// how many slice segments in the tube's circumference
arcDashLength: {
"default": 1
},
// in units of line length
arcDashGap: {
"default": 0
},
arcDashInitialGap: {
"default": 0
},
arcDashAnimateTime: {
"default": 0
},
// ms
arcsTransitionDuration: {
"default": 1000,
triggerUpdate: false
} // ms
},
methods: {
pauseAnimation: function pauseAnimation(state) {
var _state$ticker;
(_state$ticker = state.ticker) === null || _state$ticker === undefined || _state$ticker.pause();
},
resumeAnimation: function resumeAnimation(state) {
var _state$ticker2;
(_state$ticker2 = state.ticker) === null || _state$ticker2 === undefined || _state$ticker2.resume();
},
_destructor: function _destructor(state) {
var _state$ticker3;
state.sharedMaterial.dispose();
(_state$ticker3 = state.ticker) === null || _state$ticker3 === undefined || _state$ticker3.dispose();
}
},
stateInit: function stateInit(_ref) {
var tweenGroup = _ref.tweenGroup;
return {
tweenGroup: tweenGroup,
ticker: new FrameTicker$2(),
sharedMaterial: new THREE$d.ShaderMaterial(_objectSpread2(_objectSpread2({}, dashedLineShaders()), {}, {
transparent: true,
blending: THREE$d.NormalBlending
}))
};
},
init: function init(threeObj, state) {
// Clear the scene
emptyObject(threeObj);
// Main three object to manipulate
state.scene = threeObj;
state.dataMapper = new ThreeDigest(threeObj, {
objBindAttr: '__threeObjArc'
}).onCreateObj(function () {
var obj = new THREE$d.Group(); // populated in updateObj
obj.__globeObjType = 'arc'; // Add object type
return obj;
});
// Kick-off dash animations
state.ticker.onTick.add(function (_, timeDelta) {
state.dataMapper.entries().map(function (_ref2) {
var _ref3 = _slicedToArray(_ref2, 2),
obj = _ref3[1];
return obj;
}).filter(function (o) {
return o.children.length && o.children[0].material && o.children[0].__dashAnimateStep;
}).forEach(function (o) {
var obj = o.children[0];
var step = obj.__dashAnimateStep * timeDelta;
var curTranslate = obj.material.uniforms.dashTranslate.value % 1e9; // reset after 1B loops
obj.material.uniforms.dashTranslate.value = curTranslate + step;
});
});
},
update: function update(state) {
// Data accessors
var startLatAccessor = accessorFn(state.arcStartLat);
var startLngAccessor = accessorFn(state.arcStartLng);
var endLatAccessor = accessorFn(state.arcEndLat);
var endLngAccessor = accessorFn(state.arcEndLng);
var altitudeAccessor = accessorFn(state.arcAltitude);
var altitudeAutoScaleAccessor = accessorFn(state.arcAltitudeAutoScale);
var strokeAccessor = accessorFn(state.arcStroke);
var colorAccessor = accessorFn(state.arcColor);
var dashLengthAccessor = accessorFn(state.arcDashLength);
var dashGapAccessor = accessorFn(state.arcDashGap);
var dashInitialGapAccessor = accessorFn(state.arcDashInitialGap);
var dashAnimateTimeAccessor = accessorFn(state.arcDashAnimateTime);
state.dataMapper.onUpdateObj(function (group, arc) {
var stroke = strokeAccessor(arc);
var useTube = stroke !== null && stroke !== undefined;
if (!group.children.length || useTube !== (group.children[0].type === 'Mesh')) {
// create or swap object types
emptyObject(group);
var _obj = useTube ? new THREE$d.Mesh() : new THREE$d.Line(new THREE$d.BufferGeometry());
_obj.material = state.sharedMaterial.clone(); // Separate material instance per object to have dedicated uniforms (but shared shaders)
group.add(_obj);
}
var obj = group.children[0];
// set dash uniforms
Object.assign(obj.material.uniforms, {
dashSize: {
value: dashLengthAccessor(arc)
},
gapSize: {
value: dashGapAccessor(arc)
},
dashOffset: {
value: dashInitialGapAccessor(arc)
}
});
// set dash animation step
var dashAnimateTime = dashAnimateTimeAccessor(arc);
obj.__dashAnimateStep = dashAnimateTime > 0 ? 1000 / dashAnimateTime : 0; // per second
// calculate vertex colors (to create gradient)
var vertexColorArray = calcColorVertexArray(colorAccessor(arc),
// single, array of colors or interpolator
state.arcCurveResolution,
// numSegments
useTube ? state.arcCircularResolution + 1 : 1 // num vertices per segment
);
// calculate vertex relative distances (for dashed lines)
var vertexRelDistanceArray = calcVertexRelDistances(state.arcCurveResolution,
// numSegments
useTube ? state.arcCircularResolution + 1 : 1,
// num vertices per segment
true // run from end to start, to animate in the correct direction
);
obj.geometry.setAttribute('color', vertexColorArray);
obj.geometry.setAttribute('relDistance', vertexRelDistanceArray);
var applyUpdate = function applyUpdate(td) {
var _group$__currentTarge = group.__currentTargetD = td,
stroke = _group$__currentTarge.stroke,
curveD = _objectWithoutProperties(_group$__currentTarge, _excluded);
var curve = calcCurve(curveD);
if (useTube) {
obj.geometry && obj.geometry.dispose();
obj.geometry = new THREE$d.TubeGeometry(curve, state.arcCurveResolution, stroke / 2, state.arcCircularResolution);
obj.geometry.setAttribute('color', vertexColorArray);
obj.geometry.setAttribute('relDistance', vertexRelDistanceArray);
} else {
obj.geometry.setFromPoints(curve.getPoints(state.arcCurveResolution));
}
};
var targetD = {
stroke: stroke,
alt: altitudeAccessor(arc),
altAutoScale: +altitudeAutoScaleAccessor(arc),
startLat: +startLatAccessor(arc),
startLng: +startLngAccessor(arc),
endLat: +endLatAccessor(arc),
endLng: +endLngAccessor(arc)
};
var currentTargetD = group.__currentTargetD || Object.assign({}, targetD, {
altAutoScale: -1e-3
});
if (Object.keys(targetD).some(function (k) {
return currentTargetD[k] !== targetD[k];
})) {
if (!state.arcsTransitionDuration || state.arcsTransitionDuration < 0) {
// set final position
applyUpdate(targetD);
} else {
// animate
state.tweenGroup.add(new Tween(currentTargetD).to(targetD, state.arcsTransitionDuration).easing(Easing.Quadratic.InOut).onUpdate(applyUpdate).start());
}
}
}).digest(state.arcsData);
//
function calcCurve(_ref4) {
var alt = _ref4.alt,
altAutoScale = _ref4.altAutoScale,
startLat = _ref4.startLat,
startLng = _ref4.startLng,
endLat = _ref4.endLat,
endLng = _ref4.endLng;
var getVec = function getVec(_ref5) {
var _ref6 = _slicedToArray(_ref5, 3),
lng = _ref6[0],
lat = _ref6[1],
alt = _ref6[2];
var _polar2Cartesian = polar2Cartesian(lat, lng, alt),
x = _polar2Cartesian.x,
y = _polar2Cartesian.y,
z = _polar2Cartesian.z;
return new THREE$d.Vector3(x, y, z);
};
//calculate curve
var startPnt = [startLng, startLat];
var endPnt = [endLng, endLat];
var altitude = alt;
(altitude === null || altitude === undefined) && (
// by default set altitude proportional to the great-arc distance
altitude = geoDistance$1(startPnt, endPnt) / 2 * altAutoScale);
if (altitude) {
var interpolate = geoInterpolate(startPnt, endPnt);
var _map = [0.25, 0.75].map(function (t) {
return [].concat(_toConsumableArray(interpolate(t)), [altitude * 1.5]);
}),
_map2 = _slicedToArray(_map, 2),
m1Pnt = _map2[0],
m2Pnt = _map2[1];
var curve = _construct(THREE$d.CubicBezierCurve3, _toConsumableArray([startPnt, m1Pnt, m2Pnt, endPnt].map(getVec)));
//const mPnt = [...interpolate(0.5), altitude * 2];
//curve = new THREE.QuadraticBezierCurve3(...[startPnt, mPnt, endPnt].map(getVec));
return curve;
} else {
// ground line
var _alt = 0.001; // slightly above the ground to prevent occlusion
return calcSphereArc.apply(undefined, _toConsumableArray([[].concat(startPnt, [_alt]), [].concat(endPnt, [_alt])].map(getVec)));
}
//
function calcSphereArc(startVec, endVec) {
var angle = startVec.angleTo(endVec);
var getGreatCirclePoint = angle === 0 ? function () {
return startVec.clone();
} // points exactly overlap
: function (t) {
return new THREE$d.Vector3().addVectors(startVec.clone().multiplyScalar(Math.sin((1 - t) * angle)), endVec.clone().multiplyScalar(Math.sin(t * angle))).divideScalar(Math.sin(angle));
};
var sphereArc = new THREE$d.Curve();
sphereArc.getPoint = getGreatCirclePoint;
return sphereArc;
}
}
function calcColorVertexArray(colors, numSegments) {
var numVerticesPerSegment = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 1;
var numVerticesGroup = numSegments + 1; // one between every two segments and two at the ends
var getVertexColor;
if (colors instanceof Array || colors instanceof Function) {
var colorInterpolator = colors instanceof Array ? scaleLinear() // array of colors, interpolate at each step
.domain(colors.map(function (_, idx) {
return idx / (colors.length - 1);
})) // same number of stops as colors
.range(colors) : colors; // already interpolator fn
getVertexColor = function getVertexColor(t) {
return color2ShaderArr(colorInterpolator(t), true, true);
};
} else {
// single color, use constant
var vertexColor = color2ShaderArr(colors, true, true);
getVertexColor = function getVertexColor() {
return vertexColor;
};
}
var vertexColors = [];
for (var v = 0, l = numVerticesGroup; v < l; v++) {
var _vertexColor = getVertexColor(v / (l - 1));
for (var s = 0; s < numVerticesPerSegment; s++) {
vertexColors.push(_vertexColor);
}
}
return array2BufferAttr(vertexColors, 4);
}
function calcVertexRelDistances(numSegments) {
var numVerticesPerSegment = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1;
var invert = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
var numVerticesGroup = numSegments + 1; // one between every two segments and two at the ends
var vertexDistances = [];
for (var v = 0, l = numVerticesGroup; v < l; v++) {
var relDistance = v / (l - 1);
for (var s = 0; s < numVerticesPerSegment; s++) {
vertexDistances.push(relDistance);
}
}
invert && vert