three-globe
Advanced tools
Comparing version 1.6.4 to 1.7.0
@@ -11,6 +11,220 @@ 'use strict'; | ||
var tinyColor = _interopDefault(require('tinycolor2')); | ||
var dataJoint = _interopDefault(require('data-joint')); | ||
var FrameTicker = _interopDefault(require('frame-ticker')); | ||
var d3Scale = require('d3-scale'); | ||
var d3Hexbin = require('d3-hexbin'); | ||
var threeConicPolygonGeometry = require('three-conic-polygon-geometry'); | ||
const materialDispose = material => { | ||
function _classCallCheck(instance, Constructor) { | ||
if (!(instance instanceof Constructor)) { | ||
throw new TypeError("Cannot call a class as a function"); | ||
} | ||
} | ||
function _defineProperty(obj, key, value) { | ||
if (key in obj) { | ||
Object.defineProperty(obj, key, { | ||
value: value, | ||
enumerable: true, | ||
configurable: true, | ||
writable: true | ||
}); | ||
} else { | ||
obj[key] = value; | ||
} | ||
return obj; | ||
} | ||
function _objectSpread(target) { | ||
for (var i = 1; i < arguments.length; i++) { | ||
var source = arguments[i] != null ? arguments[i] : {}; | ||
var ownKeys = Object.keys(source); | ||
if (typeof Object.getOwnPropertySymbols === 'function') { | ||
ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { | ||
return Object.getOwnPropertyDescriptor(source, sym).enumerable; | ||
})); | ||
} | ||
ownKeys.forEach(function (key) { | ||
_defineProperty(target, key, source[key]); | ||
}); | ||
} | ||
return target; | ||
} | ||
function _inherits(subClass, superClass) { | ||
if (typeof superClass !== "function" && superClass !== null) { | ||
throw new TypeError("Super expression must either be null or a function"); | ||
} | ||
subClass.prototype = Object.create(superClass && superClass.prototype, { | ||
constructor: { | ||
value: subClass, | ||
writable: true, | ||
configurable: true | ||
} | ||
}); | ||
if (superClass) _setPrototypeOf(subClass, superClass); | ||
} | ||
function _getPrototypeOf(o) { | ||
_getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { | ||
return o.__proto__ || Object.getPrototypeOf(o); | ||
}; | ||
return _getPrototypeOf(o); | ||
} | ||
function _setPrototypeOf(o, p) { | ||
_setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { | ||
o.__proto__ = p; | ||
return o; | ||
}; | ||
return _setPrototypeOf(o, p); | ||
} | ||
function isNativeReflectConstruct() { | ||
if (typeof Reflect === "undefined" || !Reflect.construct) return false; | ||
if (Reflect.construct.sham) return false; | ||
if (typeof Proxy === "function") return true; | ||
try { | ||
Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); | ||
return true; | ||
} catch (e) { | ||
return false; | ||
} | ||
} | ||
function _construct(Parent, args, Class) { | ||
if (isNativeReflectConstruct()) { | ||
_construct = Reflect.construct; | ||
} else { | ||
_construct = function _construct(Parent, args, Class) { | ||
var a = [null]; | ||
a.push.apply(a, args); | ||
var Constructor = Function.bind.apply(Parent, a); | ||
var instance = new Constructor(); | ||
if (Class) _setPrototypeOf(instance, Class.prototype); | ||
return instance; | ||
}; | ||
} | ||
return _construct.apply(null, arguments); | ||
} | ||
function _objectWithoutPropertiesLoose(source, excluded) { | ||
if (source == null) return {}; | ||
var target = {}; | ||
var sourceKeys = Object.keys(source); | ||
var key, i; | ||
for (i = 0; i < sourceKeys.length; i++) { | ||
key = sourceKeys[i]; | ||
if (excluded.indexOf(key) >= 0) continue; | ||
target[key] = source[key]; | ||
} | ||
return target; | ||
} | ||
function _objectWithoutProperties(source, excluded) { | ||
if (source == null) return {}; | ||
var target = _objectWithoutPropertiesLoose(source, excluded); | ||
var key, i; | ||
if (Object.getOwnPropertySymbols) { | ||
var sourceSymbolKeys = Object.getOwnPropertySymbols(source); | ||
for (i = 0; i < sourceSymbolKeys.length; i++) { | ||
key = sourceSymbolKeys[i]; | ||
if (excluded.indexOf(key) >= 0) continue; | ||
if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; | ||
target[key] = source[key]; | ||
} | ||
} | ||
return target; | ||
} | ||
function _assertThisInitialized(self) { | ||
if (self === void 0) { | ||
throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); | ||
} | ||
return self; | ||
} | ||
function _possibleConstructorReturn(self, call) { | ||
if (call && (typeof call === "object" || typeof call === "function")) { | ||
return call; | ||
} | ||
return _assertThisInitialized(self); | ||
} | ||
function _slicedToArray(arr, i) { | ||
return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest(); | ||
} | ||
function _toConsumableArray(arr) { | ||
return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _nonIterableSpread(); | ||
} | ||
function _arrayWithoutHoles(arr) { | ||
if (Array.isArray(arr)) { | ||
for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) arr2[i] = arr[i]; | ||
return arr2; | ||
} | ||
} | ||
function _arrayWithHoles(arr) { | ||
if (Array.isArray(arr)) return arr; | ||
} | ||
function _iterableToArray(iter) { | ||
if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === "[object Arguments]") return Array.from(iter); | ||
} | ||
function _iterableToArrayLimit(arr, i) { | ||
var _arr = []; | ||
var _n = true; | ||
var _d = false; | ||
var _e = undefined; | ||
try { | ||
for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { | ||
_arr.push(_s.value); | ||
if (i && _arr.length === i) break; | ||
} | ||
} catch (err) { | ||
_d = true; | ||
_e = err; | ||
} finally { | ||
try { | ||
if (!_n && _i["return"] != null) _i["return"](); | ||
} finally { | ||
if (_d) throw _e; | ||
} | ||
} | ||
return _arr; | ||
} | ||
function _nonIterableSpread() { | ||
throw new TypeError("Invalid attempt to spread non-iterable instance"); | ||
} | ||
function _nonIterableRest() { | ||
throw new TypeError("Invalid attempt to destructure non-iterable instance"); | ||
} | ||
var materialDispose = function materialDispose(material) { | ||
if (material instanceof Array) { | ||
@@ -27,3 +241,3 @@ material.forEach(materialDispose); | ||
const deallocate = obj => { | ||
var deallocate = function deallocate(obj) { | ||
if (obj.geometry) { | ||
@@ -46,5 +260,5 @@ obj.geometry.dispose(); | ||
const emptyObject = obj => { | ||
var emptyObject = function emptyObject(obj) { | ||
while (obj.children.length) { | ||
const childObj = obj.children[0]; | ||
var childObj = obj.children[0]; | ||
obj.remove(childObj); | ||
@@ -56,22 +270,25 @@ deallocate(childObj); | ||
function linkKapsule (kapsulePropName, kapsuleType) { | ||
const dummyK = new kapsuleType(); // To extract defaults | ||
var dummyK = new kapsuleType(); // To extract defaults | ||
return { | ||
linkProp: function (prop) { | ||
linkProp: function linkProp(prop) { | ||
// link property config | ||
return { | ||
default: dummyK[prop](), | ||
onChange(v, state) { | ||
"default": dummyK[prop](), | ||
onChange: function onChange(v, state) { | ||
state[kapsulePropName][prop](v); | ||
}, | ||
triggerUpdate: false | ||
}; | ||
}, | ||
linkMethod: function (method) { | ||
linkMethod: function linkMethod(method) { | ||
// link method pass-through | ||
return function (state, ...args) { | ||
const kapsuleInstance = state[kapsulePropName]; | ||
const returnVal = kapsuleInstance[method](...args); | ||
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 | ||
@@ -84,8 +301,9 @@ : returnVal; | ||
const GLOBE_RADIUS = 100; | ||
var GLOBE_RADIUS = 100; | ||
function polar2Cartesian(lat, lng, relAltitude = 0) { | ||
const phi = (90 - lat) * Math.PI / 180; | ||
const theta = (90 - lng) * Math.PI / 180; | ||
const r = GLOBE_RADIUS * (1 + relAltitude); | ||
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 { | ||
@@ -98,10 +316,9 @@ x: r * Math.sin(phi) * Math.cos(theta), | ||
function cartesian2Polar({ | ||
x, | ||
y, | ||
z | ||
}) { | ||
const r = Math.sqrt(x * x + y * y + z * z); | ||
const phi = Math.acos(y / r); | ||
const theta = Math.atan2(z, x); | ||
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 { | ||
@@ -115,3 +332,3 @@ lat: 90 - phi * 180 / Math.PI, | ||
// from https://github.com/jdomingu/ThreeGeoJSON | ||
const THREE = window.THREE ? window.THREE // Prefer consumption from global THREE, if exists | ||
var THREE = window.THREE ? window.THREE // Prefer consumption from global THREE, if exists | ||
: { | ||
@@ -360,3 +577,3 @@ Geometry: three.Geometry, | ||
const THREE$1 = window.THREE ? window.THREE // Prefer consumption from global THREE, if exists | ||
var THREE$1 = window.THREE ? window.THREE // Prefer consumption from global THREE, if exists | ||
: { | ||
@@ -377,36 +594,30 @@ AdditiveBlending: three.AdditiveBlending, | ||
globeImageUrl: { | ||
onChange(_, state) { | ||
onChange: function onChange(_, state) { | ||
state.globeNeedsUpdate = true; | ||
} | ||
}, | ||
bumpImageUrl: { | ||
onChange(_, state) { | ||
onChange: function onChange(_, state) { | ||
state.globeNeedsUpdate = true; | ||
} | ||
}, | ||
showAtmosphere: { | ||
default: true, | ||
onChange(showAtmosphere, state) { | ||
"default": true, | ||
onChange: function onChange(showAtmosphere, state) { | ||
state.atmosphereObj.visible = !!showAtmosphere; | ||
}, | ||
triggerUpdate: false | ||
}, | ||
showGraticules: { | ||
default: false, | ||
onChange(showGraticules, state) { | ||
"default": false, | ||
onChange: function onChange(showGraticules, state) { | ||
state.graticulesObj.visible = !!showGraticules; | ||
}, | ||
triggerUpdate: false | ||
} | ||
}, | ||
stateInit: () => { | ||
stateInit: function stateInit() { | ||
// create globe | ||
const globeGeometry = new THREE$1.SphereGeometry(GLOBE_RADIUS, 75, 75); | ||
const globeObj = new THREE$1.Mesh(globeGeometry, new THREE$1.MeshPhongMaterial({ | ||
var globeGeometry = new THREE$1.SphereGeometry(GLOBE_RADIUS, 75, 75); | ||
var globeObj = new THREE$1.Mesh(globeGeometry, new THREE$1.MeshPhongMaterial({ | ||
color: 0x000000 | ||
@@ -419,5 +630,5 @@ })); | ||
let atmosphereObj; | ||
var atmosphereObj; | ||
{ | ||
const shaders = { | ||
var shaders = { | ||
uniforms: { | ||
@@ -431,21 +642,6 @@ coeficient: { | ||
}, | ||
vertexShader: ` | ||
varying vec3 vNormal; | ||
void main() { | ||
vNormal = normalize(normalMatrix * normal); | ||
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); | ||
} | ||
`, | ||
fragmentShader: ` | ||
uniform float coeficient; | ||
uniform float power; | ||
varying vec3 vNormal; | ||
void main() { | ||
float intensity = pow(coeficient - dot(vNormal, vec3(0, 0, 1.0)), power); | ||
gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0) * intensity; | ||
} | ||
` | ||
vertexShader: "\n varying vec3 vNormal;\n void main() {\n vNormal = normalize(normalMatrix * normal);\n gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);\n }\n ", | ||
fragmentShader: "\n uniform float\tcoeficient;\n uniform float\tpower;\n\n varying vec3 vNormal;\n void main() {\n float intensity = pow(coeficient - dot(vNormal, vec3(0, 0, 1.0)), power);\n gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0) * intensity;\n }\n " | ||
}; | ||
const material = new THREE$1.ShaderMaterial({ ...shaders, | ||
var material = new THREE$1.ShaderMaterial(_objectSpread({}, shaders, { | ||
side: THREE$1.BackSide, | ||
@@ -455,3 +651,3 @@ blending: THREE$1.AdditiveBlending, | ||
depthWrite: false | ||
}); | ||
})); | ||
atmosphereObj = new THREE$1.Mesh(globeGeometry, material); | ||
@@ -462,3 +658,3 @@ atmosphereObj.scale.set(1.1, 1.1, 1.1); | ||
let graticulesObj; | ||
var graticulesObj; | ||
{ | ||
@@ -478,9 +674,8 @@ // add graticules | ||
return { | ||
globeObj, | ||
atmosphereObj, | ||
graticulesObj | ||
globeObj: globeObj, | ||
atmosphereObj: atmosphereObj, | ||
graticulesObj: graticulesObj | ||
}; | ||
}, | ||
init(threeObj, state) { | ||
init: function init(threeObj, state) { | ||
// Clear the scene | ||
@@ -496,8 +691,7 @@ emptyObject(threeObj); // Main three object to manipulate | ||
}, | ||
update: function update(state) { | ||
var globeMaterial = state.globeObj.material; // Black globe if no image | ||
update(state) { | ||
const globeMaterial = state.globeObj.material; // Black globe if no image | ||
globeMaterial.color = new THREE$1.Color(0x000000); | ||
state.globeImageUrl && new THREE$1.TextureLoader().load(state.globeImageUrl, texture => { | ||
state.globeImageUrl && new THREE$1.TextureLoader().load(state.globeImageUrl, function (texture) { | ||
globeMaterial.map = texture; | ||
@@ -507,3 +701,3 @@ globeMaterial.color = null; | ||
}); | ||
state.bumpImageUrl && new THREE$1.TextureLoader().load(state.bumpImageUrl, texture => { | ||
state.bumpImageUrl && new THREE$1.TextureLoader().load(state.bumpImageUrl, function (texture) { | ||
globeMaterial.bumpMap = texture; | ||
@@ -513,119 +707,31 @@ globeMaterial.needsUpdate = true; | ||
} | ||
}); | ||
const colorStr2Hex = str => isNaN(str) ? parseInt(tinyColor(str).toHex(), 16) : str; | ||
var colorStr2Hex = function colorStr2Hex(str) { | ||
return isNaN(str) ? parseInt(tinyColor(str).toHex(), 16) : str; | ||
}; | ||
const colorAlpha = str => isNaN(str) ? tinyColor(str).getAlpha() : 1; | ||
var colorAlpha = function colorAlpha(str) { | ||
return isNaN(str) ? tinyColor(str).getAlpha() : 1; | ||
}; | ||
const color2ShaderArr = str => { | ||
const rgba = tinyColor(str).toRgb(); | ||
return [...['r', 'g', 'b'].map(d => rgba[d] / 255), rgba.a]; | ||
var color2ShaderArr = function color2ShaderArr(str) { | ||
var rgba = tinyColor(str).toRgb(); | ||
return [].concat(_toConsumableArray(['r', 'g', 'b'].map(function (d) { | ||
return rgba[d] / 255; | ||
})), [rgba.a]); | ||
}; | ||
function diffArrays(prev, next) { | ||
const prevSet = new Set(prev); | ||
const nextSet = new Set(next); | ||
const result = { | ||
enter: [], | ||
update: [], | ||
exit: [] | ||
}; | ||
new Set([...prevSet, ...nextSet]).forEach(item => { | ||
const type = !prevSet.has(item) ? 'enter' : !nextSet.has(item) ? 'exit' : 'update'; | ||
result[type].push(item); | ||
}); | ||
return result; | ||
function threeDigest(data, scene) { | ||
var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; | ||
return dataJoint(data, scene.children, function (obj) { | ||
return scene.add(obj); | ||
}, function (obj) { | ||
return scene.remove(obj); | ||
}, _objectSpread({ | ||
objBindAttr: '__threeObj' | ||
}, options)); | ||
} | ||
function dataBindDiff(data, existingObjs, { | ||
objBindAttr = '__obj', | ||
dataBindAttr = '__data' | ||
}) { | ||
const isObjValid = obj => obj.hasOwnProperty(dataBindAttr); | ||
const isDataBound = d => d.hasOwnProperty(objBindAttr) && !!d[objBindAttr]; | ||
const removeObjs = existingObjs.filter(obj => !isObjValid(obj)); | ||
const addData = data.filter(d => !isDataBound(d)); | ||
const prevD = existingObjs.filter(isObjValid).map(obj => obj[dataBindAttr]); | ||
const nextD = data.filter(isDataBound); | ||
const diff = diffArrays(prevD, nextD); | ||
diff.enter = diff.enter.concat(addData); | ||
diff.exit = diff.exit.concat(removeObjs.map(obj => ({ | ||
[objBindAttr]: obj | ||
}))); | ||
return diff; | ||
} | ||
function viewDigest(data, existingObjs, // list | ||
appendObj, // item => {...} function | ||
removeObj, // item => {...} function | ||
{ | ||
createObj = d => {}, | ||
updateObj = (obj, d) => {}, | ||
exitObj = obj => {}, | ||
objBindAttr = '__obj', | ||
dataBindAttr = '__data' | ||
}) { | ||
const { | ||
enter, | ||
update, | ||
exit | ||
} = dataBindDiff(data, existingObjs, { | ||
objBindAttr, | ||
dataBindAttr | ||
}); | ||
const newObjs = createObjs(enter); | ||
const pointsData = [...enter, ...update]; | ||
updateObjs(pointsData); // Add new points | ||
newObjs.forEach(appendObj); // Remove exiting points | ||
exit.forEach(d => { | ||
const obj = d[objBindAttr]; | ||
exitObj(obj); | ||
removeObj(obj); | ||
}); // | ||
function createObjs(data) { | ||
const newObjs = []; | ||
data.forEach(d => { | ||
const obj = createObj(d); | ||
if (obj) { | ||
obj[dataBindAttr] = d; | ||
d[objBindAttr] = obj; | ||
newObjs.push(obj); | ||
} | ||
}); | ||
return newObjs; | ||
} | ||
function updateObjs(data) { | ||
data.forEach(d => { | ||
const obj = d[objBindAttr]; | ||
if (obj) { | ||
obj[dataBindAttr] = d; | ||
updateObj(obj, d); | ||
} | ||
}); | ||
} | ||
} | ||
function threeDigest(data, scene, { | ||
createObj, | ||
updateObj, | ||
exitObj | ||
}) { | ||
return viewDigest(data, scene.children, obj => scene.add(obj), obj => scene.remove(obj), { | ||
objBindAttr: '__threeObj', | ||
createObj, | ||
updateObj, | ||
exitObj | ||
}); | ||
} | ||
const THREE$2 = window.THREE ? window.THREE // Prefer consumption from global THREE, if exists | ||
var THREE$2 = window.THREE ? window.THREE // Prefer consumption from global THREE, if exists | ||
: { | ||
@@ -647,23 +753,25 @@ Color: three.Color, | ||
pointsData: { | ||
default: [] | ||
"default": [] | ||
}, | ||
pointLat: { | ||
default: 'lat' | ||
"default": 'lat' | ||
}, | ||
pointLng: { | ||
default: 'lng' | ||
"default": 'lng' | ||
}, | ||
pointColor: { | ||
default: () => '#ffffaa' | ||
"default": function _default() { | ||
return '#ffffaa'; | ||
} | ||
}, | ||
pointAltitude: { | ||
default: 0.1 | ||
"default": 0.1 | ||
}, | ||
// in units of globe radius | ||
pointRadius: { | ||
default: 0.25 | ||
"default": 0.25 | ||
}, | ||
// in deg | ||
pointResolution: { | ||
default: 12, | ||
"default": 12, | ||
triggerUpdate: false | ||
@@ -673,7 +781,7 @@ }, | ||
pointsMerge: { | ||
default: false | ||
"default": false | ||
}, | ||
// boolean. Whether to merge all points into a single mesh for rendering performance | ||
pointsTransitionDuration: { | ||
default: 1000, | ||
"default": 1000, | ||
triggerUpdate: false // ms | ||
@@ -683,4 +791,3 @@ | ||
}, | ||
init(threeObj, state) { | ||
init: function init(threeObj, state) { | ||
// Clear the scene | ||
@@ -691,22 +798,21 @@ emptyObject(threeObj); // Main three object to manipulate | ||
}, | ||
update(state) { | ||
update: function update(state) { | ||
// Data accessors | ||
const latAccessor = accessorFn(state.pointLat); | ||
const lngAccessor = accessorFn(state.pointLng); | ||
const altitudeAccessor = accessorFn(state.pointAltitude); | ||
const radiusAccessor = accessorFn(state.pointRadius); | ||
const colorAccessor = accessorFn(state.pointColor); // shared geometry | ||
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 | ||
const pointGeometry = new THREE$2[state.pointsMerge ? 'CylinderGeometry' : 'CylinderBufferGeometry'](1, 1, 1, state.pointResolution); | ||
var pointGeometry = new THREE$2[state.pointsMerge ? 'CylinderGeometry' : 'CylinderBufferGeometry'](1, 1, 1, state.pointResolution); | ||
pointGeometry.applyMatrix(new THREE$2.Matrix4().makeRotationX(Math.PI / 2)); | ||
pointGeometry.applyMatrix(new THREE$2.Matrix4().makeTranslation(0, 0, -0.5)); | ||
const pxPerDeg = 2 * Math.PI * GLOBE_RADIUS / 360; | ||
const pointMaterials = {}; // indexed by color | ||
var pxPerDeg = 2 * Math.PI * GLOBE_RADIUS / 360; | ||
var pointMaterials = {}; // indexed by color | ||
const scene = state.pointsMerge ? new THREE$2.Object3D() : state.scene; // use fake scene if merging points | ||
var scene = state.pointsMerge ? new THREE$2.Object3D() : state.scene; // use fake scene if merging points | ||
threeDigest(state.pointsData, scene, { | ||
createObj, | ||
updateObj, | ||
createObj: createObj, | ||
updateObj: updateObj, | ||
exitObj: emptyObject | ||
@@ -717,14 +823,16 @@ }); | ||
// merge points into a single mesh | ||
const pointsGeometry = new THREE$2.Geometry(); | ||
state.pointsData.forEach(d => { | ||
const obj = d.__threeObj; | ||
var pointsGeometry = new THREE$2.Geometry(); | ||
state.pointsData.forEach(function (d) { | ||
var obj = d.__threeObj; | ||
d.__threeObj = undefined; // unbind merged points | ||
// color faces | ||
const color = new THREE$2.Color(colorAccessor(d)); | ||
obj.geometry.faces.forEach(face => face.color = color); | ||
var color = new THREE$2.Color(colorAccessor(d)); | ||
obj.geometry.faces.forEach(function (face) { | ||
return face.color = color; | ||
}); | ||
obj.updateMatrix(); | ||
pointsGeometry.merge(obj.geometry, obj.matrix); | ||
}); | ||
const points = new THREE$2.Mesh(pointsGeometry, new THREE$2.MeshBasicMaterial({ | ||
var points = new THREE$2.Mesh(pointsGeometry, new THREE$2.MeshBasicMaterial({ | ||
color: 0xffffff, | ||
@@ -743,3 +851,3 @@ vertexColors: THREE$2.FaceColors, | ||
function createObj() { | ||
const obj = new THREE$2.Mesh(pointGeometry); | ||
var obj = new THREE$2.Mesh(pointGeometry); | ||
obj.__globeObjType = 'point'; // Add object type | ||
@@ -751,8 +859,7 @@ | ||
function updateObj(obj, d) { | ||
const applyUpdate = ({ | ||
r, | ||
alt, | ||
lat, | ||
lng | ||
}) => { | ||
var applyUpdate = function applyUpdate(_ref) { | ||
var r = _ref.r, | ||
alt = _ref.alt, | ||
lat = _ref.lat, | ||
lng = _ref.lng; | ||
// position cylinder ground | ||
@@ -767,3 +874,3 @@ Object.assign(obj.position, polar2Cartesian(lat, lng)); // orientate outwards | ||
const targetD = { | ||
var targetD = { | ||
alt: altitudeAccessor(d), | ||
@@ -774,3 +881,3 @@ r: radiusAccessor(d), | ||
}; | ||
const currentTargetD = obj.__currentTargetD; | ||
var currentTargetD = obj.__currentTargetD; | ||
obj.__currentTargetD = targetD; | ||
@@ -790,4 +897,4 @@ | ||
// Update materials on individual points | ||
const color = colorAccessor(d); | ||
const opacity = colorAlpha(color); | ||
var color = colorAccessor(d); | ||
var opacity = colorAlpha(color); | ||
@@ -806,6 +913,5 @@ if (!pointMaterials.hasOwnProperty(color)) { | ||
} | ||
}); | ||
const THREE$3 = window.THREE ? window.THREE // Prefer consumption from global THREE, if exists | ||
var THREE$3 = window.THREE ? window.THREE // Prefer consumption from global THREE, if exists | ||
: { | ||
@@ -825,3 +931,3 @@ AdditiveBlending: three.AdditiveBlending, | ||
const gradientShaders = { | ||
var gradientShaders = { | ||
uniforms: { | ||
@@ -843,35 +949,4 @@ // dash param defaults, all relative to full length | ||
}, | ||
vertexShader: ` | ||
uniform float dashTranslate; | ||
attribute vec4 vertexColor; | ||
varying vec4 vColor; | ||
attribute float vertexRelDistance; | ||
varying float vRelDistance; | ||
void main() { | ||
// pass through colors and distances | ||
vColor = vertexColor; | ||
vRelDistance = vertexRelDistance + dashTranslate; | ||
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); | ||
} | ||
`, | ||
fragmentShader: ` | ||
uniform float dashOffset; | ||
uniform float dashSize; | ||
uniform float gapSize; | ||
varying vec4 vColor; | ||
varying float vRelDistance; | ||
void main() { | ||
// ignore pixels in the gap | ||
if (vRelDistance < dashOffset) discard; | ||
if (mod(vRelDistance - dashOffset, dashSize + gapSize) > dashSize) discard; | ||
// set px color: [r, g, b, a], interpolated between vertices | ||
gl_FragColor = vColor; | ||
} | ||
` | ||
vertexShader: "\n uniform float dashTranslate; \n\n attribute vec4 vertexColor;\n varying vec4 vColor;\n \n attribute float vertexRelDistance;\n varying float vRelDistance;\n\n void main() {\n // pass through colors and distances\n vColor = vertexColor;\n vRelDistance = vertexRelDistance + 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 " | ||
}; | ||
@@ -881,18 +956,20 @@ var ArcsLayerKapsule = Kapsule({ | ||
arcsData: { | ||
default: [] | ||
"default": [] | ||
}, | ||
arcStartLat: { | ||
default: 'startLat' | ||
"default": 'startLat' | ||
}, | ||
arcStartLng: { | ||
default: 'startLng' | ||
"default": 'startLng' | ||
}, | ||
arcEndLat: { | ||
default: 'endLat' | ||
"default": 'endLat' | ||
}, | ||
arcEndLng: { | ||
default: 'endLng' | ||
"default": 'endLng' | ||
}, | ||
arcColor: { | ||
default: () => '#ffffaa' | ||
"default": function _default() { | ||
return '#ffffaa'; | ||
} | ||
}, | ||
@@ -902,3 +979,3 @@ arcAltitude: {}, | ||
arcAltitudeAutoScale: { | ||
default: 0.5 | ||
"default": 0.5 | ||
}, | ||
@@ -909,3 +986,3 @@ // scale altitude proportional to great-arc distance between the two points | ||
arcCurveResolution: { | ||
default: 64, | ||
"default": 64, | ||
triggerUpdate: false | ||
@@ -915,3 +992,3 @@ }, | ||
arcCircularResolution: { | ||
default: 6, | ||
"default": 6, | ||
triggerUpdate: false | ||
@@ -921,17 +998,17 @@ }, | ||
arcDashLength: { | ||
default: 1 | ||
"default": 1 | ||
}, | ||
// in units of line length | ||
arcDashGap: { | ||
default: 0 | ||
"default": 0 | ||
}, | ||
arcDashInitialGap: { | ||
default: 0 | ||
"default": 0 | ||
}, | ||
arcDashAnimateTime: { | ||
default: 0 | ||
"default": 0 | ||
}, | ||
// ms | ||
arcsTransitionDuration: { | ||
default: 1000, | ||
"default": 1000, | ||
triggerUpdate: false // ms | ||
@@ -941,4 +1018,3 @@ | ||
}, | ||
init(threeObj, state) { | ||
init: function init(threeObj, state) { | ||
// Clear the scene | ||
@@ -949,7 +1025,9 @@ emptyObject(threeObj); // Main three object to manipulate | ||
new FrameTicker().onTick.add((_, timeDelta) => { | ||
state.arcsData.filter(d => d.__threeObj && d.__threeObj.material && d.__threeObj.__dashAnimateStep).forEach(d => { | ||
const obj = d.__threeObj; | ||
const step = obj.__dashAnimateStep * timeDelta; | ||
const curTranslate = obj.material.uniforms.dashTranslate.value % 1e9; // reset after 1B loops | ||
new FrameTicker().onTick.add(function (_, timeDelta) { | ||
state.arcsData.filter(function (d) { | ||
return d.__threeObj && d.__threeObj.material && d.__threeObj.__dashAnimateStep; | ||
}).forEach(function (d) { | ||
var obj = d.__threeObj; | ||
var step = obj.__dashAnimateStep * timeDelta; | ||
var curTranslate = obj.material.uniforms.dashTranslate.value % 1e9; // reset after 1B loops | ||
@@ -960,27 +1038,26 @@ obj.material.uniforms.dashTranslate.value = curTranslate + step; | ||
}, | ||
update(state) { | ||
update: function update(state) { | ||
// Data accessors | ||
const startLatAccessor = accessorFn(state.arcStartLat); | ||
const startLngAccessor = accessorFn(state.arcStartLng); | ||
const endLatAccessor = accessorFn(state.arcEndLat); | ||
const endLngAccessor = accessorFn(state.arcEndLng); | ||
const altitudeAccessor = accessorFn(state.arcAltitude); | ||
const altitudeAutoScaleAccessor = accessorFn(state.arcAltitudeAutoScale); | ||
const strokeAccessor = accessorFn(state.arcStroke); | ||
const colorAccessor = accessorFn(state.arcColor); | ||
const dashLengthAccessor = accessorFn(state.arcDashLength); | ||
const dashGapAccessor = accessorFn(state.arcDashGap); | ||
const dashInitialGapAccessor = accessorFn(state.arcDashInitialGap); | ||
const dashAnimateTimeAccessor = accessorFn(state.arcDashAnimateTime); | ||
const sharedMaterial = new THREE$3.ShaderMaterial({ ...gradientShaders, | ||
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); | ||
var sharedMaterial = new THREE$3.ShaderMaterial(_objectSpread({}, gradientShaders, { | ||
transparent: true, | ||
blending: THREE$3.AdditiveBlending | ||
}); | ||
})); | ||
threeDigest(state.arcsData, state.scene, { | ||
exitObj: emptyObject, | ||
createObj: arc => { | ||
const stroke = strokeAccessor(arc); | ||
const useTube = stroke !== null && stroke !== undefined; | ||
const obj = useTube ? new THREE$3.Mesh() : new THREE$3.Line(new THREE$3.BufferGeometry()); | ||
createObj: function createObj(arc) { | ||
var stroke = strokeAccessor(arc); | ||
var useTube = stroke !== null && stroke !== undefined; | ||
var obj = useTube ? new THREE$3.Mesh() : new THREE$3.Line(new THREE$3.BufferGeometry()); | ||
obj.material = sharedMaterial.clone(); // Separate material instance per object to have dedicated uniforms (but shared shaders) | ||
@@ -992,5 +1069,5 @@ | ||
}, | ||
updateObj: (obj, arc) => { | ||
const stroke = strokeAccessor(arc); | ||
const useTube = stroke !== null && stroke !== undefined; // set dash uniforms | ||
updateObj: function updateObj(obj, arc) { | ||
var stroke = strokeAccessor(arc); | ||
var useTube = stroke !== null && stroke !== undefined; // set dash uniforms | ||
@@ -1009,7 +1086,7 @@ Object.assign(obj.material.uniforms, { | ||
const dashAnimateTime = dashAnimateTimeAccessor(arc); | ||
var dashAnimateTime = dashAnimateTimeAccessor(arc); | ||
obj.__dashAnimateStep = dashAnimateTime > 0 ? 1000 / dashAnimateTime : 0; // per second | ||
// calculate vertex colors (to create gradient) | ||
const vertexColorArray = calcColorVertexArray(colorAccessor(arc), // single or array of colors | ||
var vertexColorArray = calcColorVertexArray(colorAccessor(arc), // single or array of colors | ||
state.arcCurveResolution, // numSegments | ||
@@ -1019,3 +1096,3 @@ useTube ? state.arcCircularResolution + 1 : 1 // num vertices per segment | ||
const vertexRelDistanceArray = calcVertexRelDistances(state.arcCurveResolution, // numSegments | ||
var vertexRelDistanceArray = calcVertexRelDistances(state.arcCurveResolution, // numSegments | ||
useTube ? state.arcCircularResolution + 1 : 1, // num vertices per segment | ||
@@ -1025,8 +1102,8 @@ true // run from end to start, to animate in the correct direction | ||
const applyUpdate = ({ | ||
stroke, | ||
...curveD | ||
}) => { | ||
const curve = calcCurve(curveD); | ||
var applyUpdate = function applyUpdate(_ref) { | ||
var stroke = _ref.stroke, | ||
curveD = _objectWithoutProperties(_ref, ["stroke"]); | ||
var curve = calcCurve(curveD); | ||
if (useTube) { | ||
@@ -1043,4 +1120,4 @@ obj.geometry && obj.geometry.dispose(); | ||
const targetD = { | ||
stroke, | ||
var targetD = { | ||
stroke: stroke, | ||
alt: altitudeAccessor(arc), | ||
@@ -1053,3 +1130,3 @@ altAutoScale: altitudeAutoScaleAccessor(arc), | ||
}; | ||
const currentTargetD = arc.__currentTargetD; | ||
var currentTargetD = arc.__currentTargetD; | ||
arc.__currentTargetD = targetD; | ||
@@ -1069,16 +1146,21 @@ | ||
function calcCurve({ | ||
alt, | ||
altAutoScale, | ||
startLat, | ||
startLng, | ||
endLat, | ||
endLng | ||
}) { | ||
const getVec = ([lng, lat, alt]) => { | ||
const { | ||
x, | ||
y, | ||
z | ||
} = polar2Cartesian(lat, lng, alt); | ||
function calcCurve(_ref2) { | ||
var alt = _ref2.alt, | ||
altAutoScale = _ref2.altAutoScale, | ||
startLat = _ref2.startLat, | ||
startLng = _ref2.startLng, | ||
endLat = _ref2.endLat, | ||
endLng = _ref2.endLng; | ||
var getVec = function getVec(_ref3) { | ||
var _ref4 = _slicedToArray(_ref3, 3), | ||
lng = _ref4[0], | ||
lat = _ref4[1], | ||
alt = _ref4[2]; | ||
var _polar2Cartesian = polar2Cartesian(lat, lng, alt), | ||
x = _polar2Cartesian.x, | ||
y = _polar2Cartesian.y, | ||
z = _polar2Cartesian.z; | ||
return new THREE$3.Vector3(x, y, z); | ||
@@ -1088,5 +1170,5 @@ }; //calculate curve | ||
const startPnt = [startLng, startLat]; | ||
const endPnt = [endLng, endLat]; | ||
let altitude = alt; | ||
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 | ||
@@ -1096,13 +1178,21 @@ altitude = d3Geo.geoDistance(startPnt, endPnt) / 2 * altAutoScale); | ||
if (altitude) { | ||
const interpolate = d3Geo.geoInterpolate(startPnt, endPnt); | ||
const [m1Pnt, m2Pnt] = [0.25, 0.75].map(t => [...interpolate(t), altitude * 1.5]); | ||
const curve = new THREE$3.CubicBezierCurve3(...[startPnt, m1Pnt, m2Pnt, endPnt].map(getVec)); //const mPnt = [...interpolate(0.5), altitude * 2]; | ||
var interpolate = d3Geo.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$3.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 | ||
const alt = 0.001; // slightly above the ground to prevent occlusion | ||
var _alt = 0.001; // slightly above the ground to prevent occlusion | ||
return calcSphereArc(...[[...startPnt, alt], [...endPnt, alt]].map(getVec)); | ||
return calcSphereArc.apply(void 0, _toConsumableArray([[].concat(startPnt, [_alt]), [].concat(endPnt, [_alt])].map(getVec))); | ||
} // | ||
@@ -1112,7 +1202,9 @@ | ||
function calcSphereArc(startVec, endVec) { | ||
const angle = startVec.angleTo(endVec); | ||
var angle = startVec.angleTo(endVec); | ||
const getGreatCirclePoint = t => new THREE$3.Vector3().addVectors(startVec.clone().multiplyScalar(Math.sin((1 - t) * angle)), endVec.clone().multiplyScalar(Math.sin(t * angle))).divideScalar(Math.sin(angle)); | ||
var getGreatCirclePoint = function getGreatCirclePoint(t) { | ||
return new THREE$3.Vector3().addVectors(startVec.clone().multiplyScalar(Math.sin((1 - t) * angle)), endVec.clone().multiplyScalar(Math.sin(t * angle))).divideScalar(Math.sin(angle)); | ||
}; | ||
const sphereArc = new THREE$3.Curve(); | ||
var sphereArc = new THREE$3.Curve(); | ||
sphereArc.getPoint = getGreatCirclePoint; | ||
@@ -1123,27 +1215,34 @@ return sphereArc; | ||
function calcColorVertexArray(colors, numSegments, numVerticesPerSegment = 1) { | ||
const numVerticesGroup = numSegments + 1; // one between every two segments and two at the ends | ||
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 | ||
let getVertexColor; | ||
var getVertexColor; | ||
if (colors instanceof Array) { | ||
// array of colors, interpolate at each step | ||
const colorScale = d3Scale.scaleLinear().domain(colors.map((_, idx) => idx / (colors.length - 1))) // same number of stops as colors | ||
var colorScale = d3Scale.scaleLinear().domain(colors.map(function (_, idx) { | ||
return idx / (colors.length - 1); | ||
})) // same number of stops as colors | ||
.range(colors); | ||
getVertexColor = t => color2ShaderArr(colorScale(t)); | ||
getVertexColor = function getVertexColor(t) { | ||
return color2ShaderArr(colorScale(t)); | ||
}; | ||
} else { | ||
// single color, use constant | ||
const vertexColor = color2ShaderArr(colors); | ||
var vertexColor = color2ShaderArr(colors); | ||
getVertexColor = () => vertexColor; | ||
getVertexColor = function getVertexColor() { | ||
return vertexColor; | ||
}; | ||
} | ||
const vertexColorArray = new THREE$3.Float32BufferAttribute(numVerticesGroup * 4 * numVerticesPerSegment, 4); | ||
var vertexColorArray = new THREE$3.Float32BufferAttribute(numVerticesGroup * 4 * numVerticesPerSegment, 4); | ||
for (let v = 0, l = numVerticesGroup; v < l; v++) { | ||
const vertexColor = getVertexColor(v / (l - 1)); | ||
for (var v = 0, l = numVerticesGroup; v < l; v++) { | ||
var _vertexColor = getVertexColor(v / (l - 1)); | ||
for (let s = 0; s < numVerticesPerSegment; s++) { | ||
vertexColorArray.set(vertexColor, (v * numVerticesPerSegment + s) * 4); | ||
for (var s = 0; s < numVerticesPerSegment; s++) { | ||
vertexColorArray.set(_vertexColor, (v * numVerticesPerSegment + s) * 4); | ||
} | ||
@@ -1155,14 +1254,16 @@ } | ||
function calcVertexRelDistances(numSegments, numVerticesPerSegment = 1, invert = false) { | ||
const numVerticesGroup = numSegments + 1; // one between every two segments and two at the ends | ||
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 | ||
const arrLen = numVerticesGroup * numVerticesPerSegment; | ||
const vertexDistanceArray = new THREE$3.Float32BufferAttribute(arrLen, 1); | ||
var arrLen = numVerticesGroup * numVerticesPerSegment; | ||
var vertexDistanceArray = new THREE$3.Float32BufferAttribute(arrLen, 1); | ||
for (let v = 0, l = numVerticesGroup; v < l; v++) { | ||
const relDistance = v / (l - 1); | ||
for (var v = 0, l = numVerticesGroup; v < l; v++) { | ||
var relDistance = v / (l - 1); | ||
for (let s = 0; s < numVerticesPerSegment; s++) { | ||
const idx = v * numVerticesPerSegment + s; | ||
const pos = invert ? arrLen - 1 - idx : idx; | ||
for (var s = 0; s < numVerticesPerSegment; s++) { | ||
var idx = v * numVerticesPerSegment + s; | ||
var pos = invert ? arrLen - 1 - idx : idx; | ||
vertexDistanceArray.setX(pos, relDistance); | ||
@@ -1175,9 +1276,336 @@ } | ||
} | ||
}); | ||
var THREE$4 = window.THREE ? window.THREE // Prefer consumption from global THREE, if exists | ||
: { | ||
Color: three.Color, | ||
CylinderGeometry: three.CylinderGeometry, | ||
CylinderBufferGeometry: three.CylinderBufferGeometry, | ||
FaceColors: three.FaceColors, | ||
Geometry: three.Geometry, | ||
Matrix4: three.Matrix4, | ||
Mesh: three.Mesh, | ||
MeshBasicMaterial: three.MeshBasicMaterial, | ||
MeshLambertMaterial: three.MeshLambertMaterial, | ||
Object3D: three.Object3D | ||
}; | ||
var HexBinLayerKapsule = Kapsule({ | ||
props: { | ||
hexBinPointsData: { | ||
"default": [] | ||
}, | ||
hexBinPointLat: { | ||
"default": 'lat' | ||
}, | ||
hexBinPointLng: { | ||
"default": 'lng' | ||
}, | ||
hexBinPointWeight: { | ||
"default": 1 | ||
}, | ||
hexRadius: { | ||
"default": 0.25 | ||
}, | ||
// in deg | ||
hexMargin: { | ||
"default": 0.2 | ||
}, | ||
// in fraction of diameter | ||
hexColor: { | ||
"default": function _default() { | ||
return '#ffffaa'; | ||
} | ||
}, | ||
hexAltitude: { | ||
"default": function _default(_ref) { | ||
var sumWeight = _ref.sumWeight; | ||
return sumWeight * 0.01; | ||
} | ||
}, | ||
// in units of globe radius | ||
hexBinMerge: { | ||
"default": false | ||
}, | ||
// boolean. Whether to merge all hex geometries into a single mesh for rendering performance | ||
hexTransitionDuration: { | ||
"default": 1000, | ||
triggerUpdate: false // ms | ||
} | ||
}, | ||
init: function init(threeObj, state) { | ||
// Clear the scene | ||
emptyObject(threeObj); // Main three object to manipulate | ||
state.scene = threeObj; | ||
}, | ||
update: function update(state) { | ||
// Accessors | ||
var latAccessor = accessorFn(state.hexBinPointLat); | ||
var lngAccessor = accessorFn(state.hexBinPointLng); | ||
var weightAccessor = accessorFn(state.hexBinPointWeight); | ||
var altitudeAccessor = accessorFn(state.hexAltitude); | ||
var colorAccessor = accessorFn(state.hexColor); | ||
var marginAccessor = accessorFn(state.hexMargin); | ||
var hexBins = d3Hexbin.hexbin().radius(state.hexRadius).y(latAccessor).x(function (d) { | ||
return lngAccessor(d) * Math.cos(latAccessor(d) * Math.PI / 180); | ||
})(state.hexBinPointsData).map(function (bin) { | ||
return { | ||
points: bin.map(function (d) { | ||
return d; | ||
}), | ||
center: { | ||
lat: bin.y, | ||
lng: bin.x / Math.cos(bin.y * Math.PI / 180) | ||
}, | ||
sumWeight: bin.reduce(function (agg, d) { | ||
return agg + weightAccessor(d); | ||
}, 0) | ||
}; | ||
}); // shared geometry | ||
var hexGeometry = new THREE$4[state.hexBinMerge ? 'CylinderGeometry' : 'CylinderBufferGeometry'](1, 1, 1, 6); | ||
hexGeometry.applyMatrix(new THREE$4.Matrix4().makeRotationX(Math.PI / 2)); | ||
hexGeometry.applyMatrix(new THREE$4.Matrix4().makeTranslation(0, 0, -0.5)); | ||
var pxPerDeg = 2 * Math.PI * GLOBE_RADIUS / 360; | ||
var hexMaterials = {}; // indexed by color | ||
var scene = state.hexBinMerge ? new THREE$4.Object3D() : state.scene; // use fake scene if merging hex points | ||
threeDigest(hexBins, scene, { | ||
createObj: createObj, | ||
updateObj: updateObj, | ||
exitObj: emptyObject, | ||
idAccessor: function idAccessor(d) { | ||
return "".concat(Math.round(d.center.lat * 1e6), "-").concat(Math.round(d.center.lng * 1e6)); | ||
} | ||
}); | ||
if (state.hexBinMerge) { | ||
// merge points into a single mesh | ||
var hexPointsGeometry = new THREE$4.Geometry(); | ||
hexBins.forEach(function (d) { | ||
var obj = d.__threeObj; | ||
d.__threeObj = undefined; // unbind merged points | ||
// color faces | ||
var color = new THREE$4.Color(colorAccessor(d)); | ||
obj.geometry.faces.forEach(function (face) { | ||
return face.color = color; | ||
}); | ||
obj.updateMatrix(); | ||
hexPointsGeometry.merge(obj.geometry, obj.matrix); | ||
}); | ||
var hexPoints = new THREE$4.Mesh(hexPointsGeometry, new THREE$4.MeshBasicMaterial({ | ||
color: 0xffffff, | ||
vertexColors: THREE$4.FaceColors, | ||
morphTargets: false | ||
})); | ||
hexPoints.__globeObjType = 'hexBinPoints'; // Add object type | ||
hexPoints.__data = hexBins; // Attach obj data | ||
state.scene.add(hexPoints); | ||
} // | ||
function createObj() { | ||
var obj = new THREE$4.Mesh(hexGeometry); | ||
obj.__globeObjType = 'hexbin'; // Add object type | ||
return obj; | ||
} | ||
function updateObj(obj, d) { | ||
var applyUpdate = function applyUpdate(_ref2) { | ||
var r = _ref2.r, | ||
alt = _ref2.alt, | ||
lat = _ref2.lat, | ||
lng = _ref2.lng; | ||
// position cylinder ground | ||
Object.assign(obj.position, polar2Cartesian(lat, lng)); // orientate outwards | ||
obj.lookAt(0, 0, 0); // 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: state.hexRadius * (1 - Math.max(0, Math.min(1, marginAccessor(d)))), | ||
lat: d.center.lat, | ||
lng: d.center.lng | ||
}; | ||
var currentTargetD = obj.__currentTargetD; | ||
obj.__currentTargetD = targetD; | ||
if (state.hexBinMerge || !state.hexTransitionDuration || state.hexTransitionDuration < 0) { | ||
// set final position | ||
applyUpdate(targetD); | ||
} else { | ||
// animate | ||
new TWEEN.Tween(currentTargetD || Object.assign({}, targetD, { | ||
alt: 0 | ||
})).to(targetD, state.hexTransitionDuration).easing(TWEEN.Easing.Quadratic.InOut).onUpdate(applyUpdate).start(); | ||
} | ||
if (!state.hexBinMerge) { | ||
// Update materials on individual hex points | ||
var color = colorAccessor(d); | ||
var opacity = colorAlpha(color); | ||
if (!hexMaterials.hasOwnProperty(color)) { | ||
hexMaterials[color] = new THREE$4.MeshLambertMaterial({ | ||
color: colorStr2Hex(color), | ||
transparent: opacity < 1, | ||
opacity: opacity | ||
}); | ||
} | ||
obj.material = hexMaterials[color]; | ||
} | ||
} | ||
} | ||
}); | ||
var THREE$5 = window.THREE ? window.THREE // Prefer consumption from global THREE, if exists | ||
: { | ||
DoubleSide: three.DoubleSide, | ||
Mesh: three.Mesh, | ||
MeshLambertMaterial: three.MeshLambertMaterial | ||
}; | ||
var PolygonsLayerKapsule = Kapsule({ | ||
props: { | ||
polygonsData: { | ||
"default": [] | ||
}, | ||
polygonGeoJsonGeometry: { | ||
"default": 'geometry' | ||
}, | ||
polygonSideColor: { | ||
"default": function _default() { | ||
return '#ffffaa'; | ||
} | ||
}, | ||
polygonCapColor: { | ||
"default": function _default() { | ||
return '#ffffaa'; | ||
} | ||
}, | ||
polygonAltitude: { | ||
"default": 0.1 | ||
}, | ||
// in units of globe radius | ||
polygonsTransitionDuration: { | ||
"default": 1000, | ||
triggerUpdate: false // ms | ||
} | ||
}, | ||
init: function init(threeObj, state) { | ||
// Clear the scene | ||
emptyObject(threeObj); // Main three object to manipulate | ||
state.scene = threeObj; | ||
}, | ||
update: function update(state) { | ||
// Data accessors | ||
var geoJsonAccessor = accessorFn(state.polygonGeoJsonGeometry); | ||
var altitudeAccessor = accessorFn(state.polygonAltitude); | ||
var capColorAccessor = accessorFn(state.polygonCapColor); | ||
var sideColorAccessor = accessorFn(state.polygonSideColor); | ||
var singlePolygons = []; | ||
state.polygonsData.forEach(function (polygon) { | ||
var objAttrs = { | ||
data: polygon, | ||
capColor: capColorAccessor(polygon), | ||
sideColor: sideColorAccessor(polygon), | ||
altitude: altitudeAccessor(polygon) | ||
}; | ||
var geoJson = geoJsonAccessor(polygon); | ||
var geoId = polygon.__id || "".concat(Math.round(Math.random() * 1e9)); // generate and stamp polygon ids to keep track in digest | ||
polygon.__id = geoId; | ||
if (geoJson.type === 'Polygon') { | ||
singlePolygons.push(_objectSpread({ | ||
id: "".concat(geoId, "_0"), | ||
coords: geoJson.coordinates | ||
}, objAttrs)); | ||
} else if (geoJson.type === 'MultiPolygon') { | ||
singlePolygons.push.apply(singlePolygons, _toConsumableArray(geoJson.coordinates.map(function (coords, idx) { | ||
return _objectSpread({ | ||
id: "".concat(geoId, "_").concat(idx), | ||
coords: coords | ||
}, objAttrs); | ||
}))); | ||
} else { | ||
console.warn("Unsupported GeoJson geometry type: ".concat(geoJson.type, ". Skipping geometry...")); | ||
} | ||
}); | ||
threeDigest(singlePolygons, state.scene, { | ||
idAccessor: function idAccessor(d) { | ||
return d.id; | ||
}, | ||
exitObj: emptyObject, | ||
createObj: function createObj() { | ||
var obj = new THREE$5.Mesh(undefined, [new THREE$5.MeshLambertMaterial({ | ||
side: THREE$5.DoubleSide, | ||
depthWrite: true | ||
}), // side material | ||
new THREE$5.MeshLambertMaterial({ | ||
side: THREE$5.DoubleSide, | ||
depthWrite: true | ||
}) // cap material | ||
]); | ||
obj.__globeObjType = 'polygon'; // Add object type | ||
return obj; | ||
}, | ||
updateObj: function updateObj(obj, _ref) { | ||
var coords = _ref.coords, | ||
capColor = _ref.capColor, | ||
sideColor = _ref.sideColor, | ||
altitude = _ref.altitude; | ||
// update materials | ||
[sideColor, capColor].forEach(function (color, materialIdx) { | ||
var opacity = colorAlpha(color); | ||
var material = obj.material[materialIdx]; | ||
material.color.set(colorStr2Hex(color)); | ||
material.transparent = opacity < 1; | ||
material.opacity = opacity; | ||
}); | ||
var applyUpdate = function applyUpdate(_ref2) { | ||
var alt = _ref2.alt; | ||
obj.geometry = new threeConicPolygonGeometry.ConicPolygonBufferGeometry(coords, GLOBE_RADIUS, GLOBE_RADIUS * (1 + alt), false); | ||
}; | ||
var targetD = { | ||
alt: altitude | ||
}; | ||
var currentTargetD = obj.__currentTargetD || { | ||
alt: 0 | ||
}; | ||
obj.__currentTargetD = targetD; | ||
if (!state.polygonsTransitionDuration || state.polygonsTransitionDuration < 0) { | ||
// set final position | ||
applyUpdate(targetD); | ||
} else { | ||
// animate | ||
new TWEEN.Tween(currentTargetD).to(targetD, state.polygonsTransitionDuration).easing(TWEEN.Easing.Quadratic.InOut).onUpdate(applyUpdate).start(); | ||
} | ||
} | ||
}); | ||
} | ||
}); | ||
var CustomLayerKapsule = Kapsule({ | ||
props: { | ||
customLayerData: { | ||
default: [] | ||
"default": [] | ||
}, | ||
@@ -1189,4 +1617,3 @@ customThreeObject: {}, | ||
}, | ||
init(threeObj, state) { | ||
init: function init(threeObj, state) { | ||
// Clear the scene | ||
@@ -1197,4 +1624,3 @@ emptyObject(threeObj); // Main three object to manipulate | ||
}, | ||
update(state) { | ||
update: function update(state) { | ||
if (!state.customThreeObjectUpdate) { | ||
@@ -1205,7 +1631,7 @@ emptyObject(state.scene); | ||
const customObjectAccessor = accessorFn(state.customThreeObject); | ||
const customObjectUpdateAccessor = accessorFn(state.customThreeObjectUpdate); | ||
var customObjectAccessor = accessorFn(state.customThreeObject); | ||
var customObjectUpdateAccessor = accessorFn(state.customThreeObjectUpdate); | ||
threeDigest(state.customLayerData, state.scene, { | ||
createObj: d => { | ||
let obj = customObjectAccessor(d, GLOBE_RADIUS); | ||
createObj: function createObj(d) { | ||
var obj = customObjectAccessor(d, GLOBE_RADIUS); | ||
@@ -1223,10 +1649,11 @@ if (obj) { | ||
}, | ||
updateObj: (obj, d) => customObjectUpdateAccessor(obj, d, GLOBE_RADIUS), | ||
updateObj: function updateObj(obj, d) { | ||
return customObjectUpdateAccessor(obj, d, GLOBE_RADIUS); | ||
}, | ||
exitObj: emptyObject | ||
}); | ||
} | ||
}); | ||
const THREE$4 = window.THREE ? window.THREE // Prefer consumption from global THREE, if exists | ||
var THREE$6 = window.THREE ? window.THREE // Prefer consumption from global THREE, if exists | ||
: { | ||
@@ -1238,30 +1665,46 @@ Group: three.Group, | ||
const bindGlobeLayer = linkKapsule('globeLayer', GlobeLayerKapsule); | ||
const linkedGlobeLayerProps = Object.assign(...['globeImageUrl', 'bumpImageUrl', 'showAtmosphere', 'showGraticules'].map(p => ({ | ||
[p]: bindGlobeLayer.linkProp(p) | ||
var bindGlobeLayer = linkKapsule('globeLayer', GlobeLayerKapsule); | ||
var linkedGlobeLayerProps = Object.assign.apply(Object, _toConsumableArray(['globeImageUrl', 'bumpImageUrl', 'showAtmosphere', 'showGraticules'].map(function (p) { | ||
return _defineProperty({}, p, bindGlobeLayer.linkProp(p)); | ||
}))); | ||
const bindPointsLayer = linkKapsule('pointsLayer', PointsLayerKapsule); | ||
const linkedPointsLayerProps = Object.assign(...['pointsData', 'pointLat', 'pointLng', 'pointColor', 'pointAltitude', 'pointRadius', 'pointResolution', 'pointsMerge', 'pointsTransitionDuration'].map(p => ({ | ||
[p]: bindPointsLayer.linkProp(p) | ||
var bindPointsLayer = linkKapsule('pointsLayer', PointsLayerKapsule); | ||
var linkedPointsLayerProps = Object.assign.apply(Object, _toConsumableArray(['pointsData', 'pointLat', 'pointLng', 'pointColor', 'pointAltitude', 'pointRadius', 'pointResolution', 'pointsMerge', 'pointsTransitionDuration'].map(function (p) { | ||
return _defineProperty({}, p, bindPointsLayer.linkProp(p)); | ||
}))); | ||
const bindArcsLayer = linkKapsule('arcsLayer', ArcsLayerKapsule); | ||
const linkedArcsLayerProps = Object.assign(...['arcsData', 'arcStartLat', 'arcStartLng', 'arcEndLat', 'arcEndLng', 'arcColor', 'arcAltitude', 'arcAltitudeAutoScale', 'arcStroke', 'arcCurveResolution', 'arcCircularResolution', 'arcDashLength', 'arcDashGap', 'arcDashInitialGap', 'arcDashAnimateTime', 'arcsTransitionDuration'].map(p => ({ | ||
[p]: bindArcsLayer.linkProp(p) | ||
var bindArcsLayer = linkKapsule('arcsLayer', ArcsLayerKapsule); | ||
var linkedArcsLayerProps = Object.assign.apply(Object, _toConsumableArray(['arcsData', 'arcStartLat', 'arcStartLng', 'arcEndLat', 'arcEndLng', 'arcColor', 'arcAltitude', 'arcAltitudeAutoScale', 'arcStroke', 'arcCurveResolution', 'arcCircularResolution', 'arcDashLength', 'arcDashGap', 'arcDashInitialGap', 'arcDashAnimateTime', 'arcsTransitionDuration'].map(function (p) { | ||
return _defineProperty({}, p, bindArcsLayer.linkProp(p)); | ||
}))); | ||
const bindCustomLayer = linkKapsule('customLayer', CustomLayerKapsule); | ||
const linkedCustomLayerProps = Object.assign(...['customLayerData', 'customThreeObject', 'customThreeObjectUpdate'].map(p => ({ | ||
[p]: bindCustomLayer.linkProp(p) | ||
var bindHexBinLayer = linkKapsule('hexBinLayer', HexBinLayerKapsule); | ||
var linkedHexBinLayerProps = Object.assign.apply(Object, _toConsumableArray(['hexBinPointsData', 'hexBinPointLat', 'hexBinPointLng', 'hexBinPointWeight', 'hexRadius', 'hexMargin', 'hexColor', 'hexAltitude', 'hexBinMerge', 'hexTransitionDuration'].map(function (p) { | ||
return _defineProperty({}, p, bindHexBinLayer.linkProp(p)); | ||
}))); | ||
var bindPolygonsLayer = linkKapsule('polygonsLayer', PolygonsLayerKapsule); | ||
var linkedPolygonsLayerProps = Object.assign.apply(Object, _toConsumableArray(['polygonsData', 'polygonGeoJsonGeometry', 'polygonCapColor', 'polygonSideColor', 'polygonAltitude', 'polygonsTransitionDuration'].map(function (p) { | ||
return _defineProperty({}, p, bindPolygonsLayer.linkProp(p)); | ||
}))); | ||
var bindCustomLayer = linkKapsule('customLayer', CustomLayerKapsule); | ||
var linkedCustomLayerProps = Object.assign.apply(Object, _toConsumableArray(['customLayerData', 'customThreeObject', 'customThreeObjectUpdate'].map(function (p) { | ||
return _defineProperty({}, p, bindCustomLayer.linkProp(p)); | ||
}))); // | ||
var Globe = Kapsule({ | ||
props: { ...linkedGlobeLayerProps, | ||
...linkedPointsLayerProps, | ||
...linkedArcsLayerProps, | ||
...linkedCustomLayerProps | ||
}, | ||
props: _objectSpread({}, linkedGlobeLayerProps, linkedPointsLayerProps, linkedArcsLayerProps, linkedHexBinLayerProps, linkedPolygonsLayerProps, linkedCustomLayerProps), | ||
methods: { | ||
getCoords: (state, ...args) => polar2Cartesian(...args), | ||
toGeoCoords: (state, ...args) => cartesian2Polar(...args) | ||
getCoords: function getCoords(state) { | ||
for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { | ||
args[_key - 1] = arguments[_key]; | ||
} | ||
return polar2Cartesian.apply(void 0, args); | ||
}, | ||
toGeoCoords: function toGeoCoords(state) { | ||
for (var _len2 = arguments.length, args = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) { | ||
args[_key2 - 1] = arguments[_key2]; | ||
} | ||
return cartesian2Polar.apply(void 0, args); | ||
} | ||
}, | ||
stateInit: () => { | ||
stateInit: function stateInit() { | ||
return { | ||
@@ -1271,2 +1714,4 @@ globeLayer: GlobeLayerKapsule(), | ||
arcsLayer: ArcsLayerKapsule(), | ||
hexBinLayer: HexBinLayerKapsule(), | ||
polygonsLayer: PolygonsLayerKapsule(), | ||
customLayer: CustomLayerKapsule(), | ||
@@ -1276,24 +1721,31 @@ animateIn: false | ||
}, | ||
init(threeObj, state, { | ||
animateIn = true | ||
}) { | ||
init: function init(threeObj, state, _ref7) { | ||
var _ref7$animateIn = _ref7.animateIn, | ||
animateIn = _ref7$animateIn === void 0 ? true : _ref7$animateIn; | ||
// Clear the scene | ||
emptyObject(threeObj); // Main three object to manipulate | ||
threeObj.add(state.scene = new THREE$4.Group()); // add globe layer group | ||
threeObj.add(state.scene = new THREE$6.Group()); // add globe layer group | ||
const globeG = new THREE$4.Group(); | ||
var globeG = new THREE$6.Group(); | ||
state.scene.add(globeG); | ||
state.globeLayer(globeG); // add points layer group | ||
const pointsG = new THREE$4.Group(); | ||
var pointsG = new THREE$6.Group(); | ||
state.scene.add(pointsG); | ||
state.pointsLayer(pointsG); // add arcs layer group | ||
const arcsG = new THREE$4.Group(); | ||
var arcsG = new THREE$6.Group(); | ||
state.scene.add(arcsG); | ||
state.arcsLayer(arcsG); // add custom layer group | ||
state.arcsLayer(arcsG); // add hexbin layer group | ||
const customG = new THREE$4.Group(); | ||
var hexBinG = new THREE$6.Group(); | ||
state.scene.add(hexBinG); | ||
state.hexBinLayer(hexBinG); // add polygons layer group | ||
var polygonsG = new THREE$6.Group(); | ||
state.scene.add(polygonsG); | ||
state.polygonsLayer(polygonsG); // add custom layer group | ||
var customG = new THREE$6.Group(); | ||
state.scene.add(customG); | ||
@@ -1315,6 +1767,5 @@ state.customLayer(customG); // animate build in, one time only | ||
}, | ||
update(state) { | ||
update: function update(state) { | ||
if (state.animateIn) { | ||
setTimeout(() => { | ||
setTimeout(function () { | ||
// Animate build-in just once | ||
@@ -1327,6 +1778,7 @@ state.animateIn = false; | ||
k: 1 | ||
}, 600).easing(TWEEN.Easing.Quadratic.Out).onUpdate(({ | ||
k | ||
}) => state.scene.scale.set(k, k, k)).start(); | ||
const rotAxis = new THREE$4.Vector3(0, 1, 0); | ||
}, 600).easing(TWEEN.Easing.Quadratic.Out).onUpdate(function (_ref8) { | ||
var k = _ref8.k; | ||
return state.scene.scale.set(k, k, k); | ||
}).start(); | ||
var rotAxis = new THREE$6.Vector3(0, 1, 0); | ||
new TWEEN.Tween({ | ||
@@ -1336,26 +1788,49 @@ rot: Math.PI * 2 | ||
rot: 0 | ||
}, 1200).easing(TWEEN.Easing.Quintic.Out).onUpdate(({ | ||
rot | ||
}) => state.scene.setRotationFromAxisAngle(rotAxis, rot)).start(); | ||
}, 1200).easing(TWEEN.Easing.Quintic.Out).onUpdate(function (_ref9) { | ||
var rot = _ref9.rot; | ||
return state.scene.setRotationFromAxisAngle(rotAxis, rot); | ||
}).start(); | ||
}, 600); // delay animation slightly to load globe texture | ||
} | ||
} | ||
}); | ||
function fromKapsule (kapsule, baseClass = Object, initKapsuleWithSelf = false) { | ||
class FromKapsule extends baseClass { | ||
constructor(...args) { | ||
super(...args); | ||
this.__kapsuleInstance = kapsule(...args)(...[...(initKapsuleWithSelf ? [this] : []), ...args]); | ||
function fromKapsule (kapsule) { | ||
var baseClass = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : Object; | ||
var initKapsuleWithSelf = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false; | ||
var FromKapsule = | ||
/*#__PURE__*/ | ||
function (_baseClass) { | ||
_inherits(FromKapsule, _baseClass); | ||
function FromKapsule() { | ||
var _getPrototypeOf2; | ||
var _this; | ||
_classCallCheck(this, FromKapsule); | ||
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { | ||
args[_key] = arguments[_key]; | ||
} | ||
_this = _possibleConstructorReturn(this, (_getPrototypeOf2 = _getPrototypeOf(FromKapsule)).call.apply(_getPrototypeOf2, [this].concat(args))); | ||
_this.__kapsuleInstance = kapsule.apply(void 0, args).apply(void 0, [].concat(_toConsumableArray(initKapsuleWithSelf ? [_assertThisInitialized(_this)] : []), args)); | ||
return _this; | ||
} | ||
} // attach kapsule props/methods to class prototype | ||
return FromKapsule; | ||
}(baseClass); // attach kapsule props/methods to class prototype | ||
Object.keys(kapsule()).forEach(m => FromKapsule.prototype[m] = function (...args) { | ||
const returnVal = this.__kapsuleInstance[m](...args); | ||
Object.keys(kapsule()).forEach(function (m) { | ||
return FromKapsule.prototype[m] = function () { | ||
var _this$__kapsuleInstan; | ||
return returnVal === this.__kapsuleInstance ? this // chain based on this class, not the kapsule obj | ||
: returnVal; | ||
var returnVal = (_this$__kapsuleInstan = this.__kapsuleInstance)[m].apply(_this$__kapsuleInstan, arguments); | ||
return returnVal === this.__kapsuleInstance ? this // chain based on this class, not the kapsule obj | ||
: returnVal; | ||
}; | ||
}); | ||
@@ -1362,0 +1837,0 @@ return FromKapsule; |
@@ -1,2 +0,2 @@ | ||
import { Geometry, Line, LineBasicMaterial, ParticleSystem, ParticleSystemMaterial, Vector3, AdditiveBlending, BackSide, Color, Mesh, MeshPhongMaterial, Object3D, ShaderMaterial, SphereGeometry, TextureLoader, CylinderGeometry, CylinderBufferGeometry, FaceColors, Matrix4, MeshBasicMaterial, MeshLambertMaterial, BufferGeometry, CubicBezierCurve3, Curve, Float32BufferAttribute, QuadraticBezierCurve3, TubeBufferGeometry, Group } from 'three'; | ||
import { Geometry, Line, LineBasicMaterial, ParticleSystem, ParticleSystemMaterial, Vector3, AdditiveBlending, BackSide, Color, Mesh, MeshPhongMaterial, Object3D, ShaderMaterial, SphereGeometry, TextureLoader, CylinderGeometry, CylinderBufferGeometry, FaceColors, Matrix4, MeshBasicMaterial, MeshLambertMaterial, BufferGeometry, CubicBezierCurve3, Curve, Float32BufferAttribute, QuadraticBezierCurve3, TubeBufferGeometry, DoubleSide, Group } from 'three'; | ||
import Kapsule from 'kapsule'; | ||
@@ -7,6 +7,220 @@ import TWEEN from '@tweenjs/tween.js'; | ||
import tinyColor from 'tinycolor2'; | ||
import dataJoint from 'data-joint'; | ||
import FrameTicker from 'frame-ticker'; | ||
import { scaleLinear } from 'd3-scale'; | ||
import { hexbin } from 'd3-hexbin'; | ||
import { ConicPolygonBufferGeometry } from 'three-conic-polygon-geometry'; | ||
const materialDispose = material => { | ||
function _classCallCheck(instance, Constructor) { | ||
if (!(instance instanceof Constructor)) { | ||
throw new TypeError("Cannot call a class as a function"); | ||
} | ||
} | ||
function _defineProperty(obj, key, value) { | ||
if (key in obj) { | ||
Object.defineProperty(obj, key, { | ||
value: value, | ||
enumerable: true, | ||
configurable: true, | ||
writable: true | ||
}); | ||
} else { | ||
obj[key] = value; | ||
} | ||
return obj; | ||
} | ||
function _objectSpread(target) { | ||
for (var i = 1; i < arguments.length; i++) { | ||
var source = arguments[i] != null ? arguments[i] : {}; | ||
var ownKeys = Object.keys(source); | ||
if (typeof Object.getOwnPropertySymbols === 'function') { | ||
ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { | ||
return Object.getOwnPropertyDescriptor(source, sym).enumerable; | ||
})); | ||
} | ||
ownKeys.forEach(function (key) { | ||
_defineProperty(target, key, source[key]); | ||
}); | ||
} | ||
return target; | ||
} | ||
function _inherits(subClass, superClass) { | ||
if (typeof superClass !== "function" && superClass !== null) { | ||
throw new TypeError("Super expression must either be null or a function"); | ||
} | ||
subClass.prototype = Object.create(superClass && superClass.prototype, { | ||
constructor: { | ||
value: subClass, | ||
writable: true, | ||
configurable: true | ||
} | ||
}); | ||
if (superClass) _setPrototypeOf(subClass, superClass); | ||
} | ||
function _getPrototypeOf(o) { | ||
_getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { | ||
return o.__proto__ || Object.getPrototypeOf(o); | ||
}; | ||
return _getPrototypeOf(o); | ||
} | ||
function _setPrototypeOf(o, p) { | ||
_setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { | ||
o.__proto__ = p; | ||
return o; | ||
}; | ||
return _setPrototypeOf(o, p); | ||
} | ||
function isNativeReflectConstruct() { | ||
if (typeof Reflect === "undefined" || !Reflect.construct) return false; | ||
if (Reflect.construct.sham) return false; | ||
if (typeof Proxy === "function") return true; | ||
try { | ||
Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); | ||
return true; | ||
} catch (e) { | ||
return false; | ||
} | ||
} | ||
function _construct(Parent, args, Class) { | ||
if (isNativeReflectConstruct()) { | ||
_construct = Reflect.construct; | ||
} else { | ||
_construct = function _construct(Parent, args, Class) { | ||
var a = [null]; | ||
a.push.apply(a, args); | ||
var Constructor = Function.bind.apply(Parent, a); | ||
var instance = new Constructor(); | ||
if (Class) _setPrototypeOf(instance, Class.prototype); | ||
return instance; | ||
}; | ||
} | ||
return _construct.apply(null, arguments); | ||
} | ||
function _objectWithoutPropertiesLoose(source, excluded) { | ||
if (source == null) return {}; | ||
var target = {}; | ||
var sourceKeys = Object.keys(source); | ||
var key, i; | ||
for (i = 0; i < sourceKeys.length; i++) { | ||
key = sourceKeys[i]; | ||
if (excluded.indexOf(key) >= 0) continue; | ||
target[key] = source[key]; | ||
} | ||
return target; | ||
} | ||
function _objectWithoutProperties(source, excluded) { | ||
if (source == null) return {}; | ||
var target = _objectWithoutPropertiesLoose(source, excluded); | ||
var key, i; | ||
if (Object.getOwnPropertySymbols) { | ||
var sourceSymbolKeys = Object.getOwnPropertySymbols(source); | ||
for (i = 0; i < sourceSymbolKeys.length; i++) { | ||
key = sourceSymbolKeys[i]; | ||
if (excluded.indexOf(key) >= 0) continue; | ||
if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; | ||
target[key] = source[key]; | ||
} | ||
} | ||
return target; | ||
} | ||
function _assertThisInitialized(self) { | ||
if (self === void 0) { | ||
throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); | ||
} | ||
return self; | ||
} | ||
function _possibleConstructorReturn(self, call) { | ||
if (call && (typeof call === "object" || typeof call === "function")) { | ||
return call; | ||
} | ||
return _assertThisInitialized(self); | ||
} | ||
function _slicedToArray(arr, i) { | ||
return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest(); | ||
} | ||
function _toConsumableArray(arr) { | ||
return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _nonIterableSpread(); | ||
} | ||
function _arrayWithoutHoles(arr) { | ||
if (Array.isArray(arr)) { | ||
for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) arr2[i] = arr[i]; | ||
return arr2; | ||
} | ||
} | ||
function _arrayWithHoles(arr) { | ||
if (Array.isArray(arr)) return arr; | ||
} | ||
function _iterableToArray(iter) { | ||
if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === "[object Arguments]") return Array.from(iter); | ||
} | ||
function _iterableToArrayLimit(arr, i) { | ||
var _arr = []; | ||
var _n = true; | ||
var _d = false; | ||
var _e = undefined; | ||
try { | ||
for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { | ||
_arr.push(_s.value); | ||
if (i && _arr.length === i) break; | ||
} | ||
} catch (err) { | ||
_d = true; | ||
_e = err; | ||
} finally { | ||
try { | ||
if (!_n && _i["return"] != null) _i["return"](); | ||
} finally { | ||
if (_d) throw _e; | ||
} | ||
} | ||
return _arr; | ||
} | ||
function _nonIterableSpread() { | ||
throw new TypeError("Invalid attempt to spread non-iterable instance"); | ||
} | ||
function _nonIterableRest() { | ||
throw new TypeError("Invalid attempt to destructure non-iterable instance"); | ||
} | ||
var materialDispose = function materialDispose(material) { | ||
if (material instanceof Array) { | ||
@@ -23,3 +237,3 @@ material.forEach(materialDispose); | ||
const deallocate = obj => { | ||
var deallocate = function deallocate(obj) { | ||
if (obj.geometry) { | ||
@@ -42,5 +256,5 @@ obj.geometry.dispose(); | ||
const emptyObject = obj => { | ||
var emptyObject = function emptyObject(obj) { | ||
while (obj.children.length) { | ||
const childObj = obj.children[0]; | ||
var childObj = obj.children[0]; | ||
obj.remove(childObj); | ||
@@ -52,22 +266,25 @@ deallocate(childObj); | ||
function linkKapsule (kapsulePropName, kapsuleType) { | ||
const dummyK = new kapsuleType(); // To extract defaults | ||
var dummyK = new kapsuleType(); // To extract defaults | ||
return { | ||
linkProp: function (prop) { | ||
linkProp: function linkProp(prop) { | ||
// link property config | ||
return { | ||
default: dummyK[prop](), | ||
onChange(v, state) { | ||
"default": dummyK[prop](), | ||
onChange: function onChange(v, state) { | ||
state[kapsulePropName][prop](v); | ||
}, | ||
triggerUpdate: false | ||
}; | ||
}, | ||
linkMethod: function (method) { | ||
linkMethod: function linkMethod(method) { | ||
// link method pass-through | ||
return function (state, ...args) { | ||
const kapsuleInstance = state[kapsulePropName]; | ||
const returnVal = kapsuleInstance[method](...args); | ||
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 | ||
@@ -80,8 +297,9 @@ : returnVal; | ||
const GLOBE_RADIUS = 100; | ||
var GLOBE_RADIUS = 100; | ||
function polar2Cartesian(lat, lng, relAltitude = 0) { | ||
const phi = (90 - lat) * Math.PI / 180; | ||
const theta = (90 - lng) * Math.PI / 180; | ||
const r = GLOBE_RADIUS * (1 + relAltitude); | ||
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 { | ||
@@ -94,10 +312,9 @@ x: r * Math.sin(phi) * Math.cos(theta), | ||
function cartesian2Polar({ | ||
x, | ||
y, | ||
z | ||
}) { | ||
const r = Math.sqrt(x * x + y * y + z * z); | ||
const phi = Math.acos(y / r); | ||
const theta = Math.atan2(z, x); | ||
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 { | ||
@@ -111,10 +328,10 @@ lat: 90 - phi * 180 / Math.PI, | ||
// from https://github.com/jdomingu/ThreeGeoJSON | ||
const THREE = window.THREE ? window.THREE // Prefer consumption from global THREE, if exists | ||
var THREE = window.THREE ? window.THREE // Prefer consumption from global THREE, if exists | ||
: { | ||
Geometry, | ||
Line, | ||
LineBasicMaterial, | ||
ParticleSystem, | ||
ParticleSystemMaterial, | ||
Vector3 | ||
Geometry: Geometry, | ||
Line: Line, | ||
LineBasicMaterial: LineBasicMaterial, | ||
ParticleSystem: ParticleSystem, | ||
ParticleSystemMaterial: ParticleSystemMaterial, | ||
Vector3: Vector3 | ||
}; | ||
@@ -356,13 +573,13 @@ /* Draw GeoJSON | ||
const THREE$1 = window.THREE ? window.THREE // Prefer consumption from global THREE, if exists | ||
var THREE$1 = window.THREE ? window.THREE // Prefer consumption from global THREE, if exists | ||
: { | ||
AdditiveBlending, | ||
BackSide, | ||
Color, | ||
Mesh, | ||
MeshPhongMaterial, | ||
Object3D, | ||
ShaderMaterial, | ||
SphereGeometry, | ||
TextureLoader | ||
AdditiveBlending: AdditiveBlending, | ||
BackSide: BackSide, | ||
Color: Color, | ||
Mesh: Mesh, | ||
MeshPhongMaterial: MeshPhongMaterial, | ||
Object3D: Object3D, | ||
ShaderMaterial: ShaderMaterial, | ||
SphereGeometry: SphereGeometry, | ||
TextureLoader: TextureLoader | ||
}; | ||
@@ -373,36 +590,30 @@ | ||
globeImageUrl: { | ||
onChange(_, state) { | ||
onChange: function onChange(_, state) { | ||
state.globeNeedsUpdate = true; | ||
} | ||
}, | ||
bumpImageUrl: { | ||
onChange(_, state) { | ||
onChange: function onChange(_, state) { | ||
state.globeNeedsUpdate = true; | ||
} | ||
}, | ||
showAtmosphere: { | ||
default: true, | ||
onChange(showAtmosphere, state) { | ||
"default": true, | ||
onChange: function onChange(showAtmosphere, state) { | ||
state.atmosphereObj.visible = !!showAtmosphere; | ||
}, | ||
triggerUpdate: false | ||
}, | ||
showGraticules: { | ||
default: false, | ||
onChange(showGraticules, state) { | ||
"default": false, | ||
onChange: function onChange(showGraticules, state) { | ||
state.graticulesObj.visible = !!showGraticules; | ||
}, | ||
triggerUpdate: false | ||
} | ||
}, | ||
stateInit: () => { | ||
stateInit: function stateInit() { | ||
// create globe | ||
const globeGeometry = new THREE$1.SphereGeometry(GLOBE_RADIUS, 75, 75); | ||
const globeObj = new THREE$1.Mesh(globeGeometry, new THREE$1.MeshPhongMaterial({ | ||
var globeGeometry = new THREE$1.SphereGeometry(GLOBE_RADIUS, 75, 75); | ||
var globeObj = new THREE$1.Mesh(globeGeometry, new THREE$1.MeshPhongMaterial({ | ||
color: 0x000000 | ||
@@ -415,5 +626,5 @@ })); | ||
let atmosphereObj; | ||
var atmosphereObj; | ||
{ | ||
const shaders = { | ||
var shaders = { | ||
uniforms: { | ||
@@ -427,21 +638,6 @@ coeficient: { | ||
}, | ||
vertexShader: ` | ||
varying vec3 vNormal; | ||
void main() { | ||
vNormal = normalize(normalMatrix * normal); | ||
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); | ||
} | ||
`, | ||
fragmentShader: ` | ||
uniform float coeficient; | ||
uniform float power; | ||
varying vec3 vNormal; | ||
void main() { | ||
float intensity = pow(coeficient - dot(vNormal, vec3(0, 0, 1.0)), power); | ||
gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0) * intensity; | ||
} | ||
` | ||
vertexShader: "\n varying vec3 vNormal;\n void main() {\n vNormal = normalize(normalMatrix * normal);\n gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);\n }\n ", | ||
fragmentShader: "\n uniform float\tcoeficient;\n uniform float\tpower;\n\n varying vec3 vNormal;\n void main() {\n float intensity = pow(coeficient - dot(vNormal, vec3(0, 0, 1.0)), power);\n gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0) * intensity;\n }\n " | ||
}; | ||
const material = new THREE$1.ShaderMaterial({ ...shaders, | ||
var material = new THREE$1.ShaderMaterial(_objectSpread({}, shaders, { | ||
side: THREE$1.BackSide, | ||
@@ -451,3 +647,3 @@ blending: THREE$1.AdditiveBlending, | ||
depthWrite: false | ||
}); | ||
})); | ||
atmosphereObj = new THREE$1.Mesh(globeGeometry, material); | ||
@@ -458,3 +654,3 @@ atmosphereObj.scale.set(1.1, 1.1, 1.1); | ||
let graticulesObj; | ||
var graticulesObj; | ||
{ | ||
@@ -474,9 +670,8 @@ // add graticules | ||
return { | ||
globeObj, | ||
atmosphereObj, | ||
graticulesObj | ||
globeObj: globeObj, | ||
atmosphereObj: atmosphereObj, | ||
graticulesObj: graticulesObj | ||
}; | ||
}, | ||
init(threeObj, state) { | ||
init: function init(threeObj, state) { | ||
// Clear the scene | ||
@@ -492,8 +687,7 @@ emptyObject(threeObj); // Main three object to manipulate | ||
}, | ||
update: function update(state) { | ||
var globeMaterial = state.globeObj.material; // Black globe if no image | ||
update(state) { | ||
const globeMaterial = state.globeObj.material; // Black globe if no image | ||
globeMaterial.color = new THREE$1.Color(0x000000); | ||
state.globeImageUrl && new THREE$1.TextureLoader().load(state.globeImageUrl, texture => { | ||
state.globeImageUrl && new THREE$1.TextureLoader().load(state.globeImageUrl, function (texture) { | ||
globeMaterial.map = texture; | ||
@@ -503,3 +697,3 @@ globeMaterial.color = null; | ||
}); | ||
state.bumpImageUrl && new THREE$1.TextureLoader().load(state.bumpImageUrl, texture => { | ||
state.bumpImageUrl && new THREE$1.TextureLoader().load(state.bumpImageUrl, function (texture) { | ||
globeMaterial.bumpMap = texture; | ||
@@ -509,130 +703,42 @@ globeMaterial.needsUpdate = true; | ||
} | ||
}); | ||
const colorStr2Hex = str => isNaN(str) ? parseInt(tinyColor(str).toHex(), 16) : str; | ||
var colorStr2Hex = function colorStr2Hex(str) { | ||
return isNaN(str) ? parseInt(tinyColor(str).toHex(), 16) : str; | ||
}; | ||
const colorAlpha = str => isNaN(str) ? tinyColor(str).getAlpha() : 1; | ||
var colorAlpha = function colorAlpha(str) { | ||
return isNaN(str) ? tinyColor(str).getAlpha() : 1; | ||
}; | ||
const color2ShaderArr = str => { | ||
const rgba = tinyColor(str).toRgb(); | ||
return [...['r', 'g', 'b'].map(d => rgba[d] / 255), rgba.a]; | ||
var color2ShaderArr = function color2ShaderArr(str) { | ||
var rgba = tinyColor(str).toRgb(); | ||
return [].concat(_toConsumableArray(['r', 'g', 'b'].map(function (d) { | ||
return rgba[d] / 255; | ||
})), [rgba.a]); | ||
}; | ||
function diffArrays(prev, next) { | ||
const prevSet = new Set(prev); | ||
const nextSet = new Set(next); | ||
const result = { | ||
enter: [], | ||
update: [], | ||
exit: [] | ||
}; | ||
new Set([...prevSet, ...nextSet]).forEach(item => { | ||
const type = !prevSet.has(item) ? 'enter' : !nextSet.has(item) ? 'exit' : 'update'; | ||
result[type].push(item); | ||
}); | ||
return result; | ||
function threeDigest(data, scene) { | ||
var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; | ||
return dataJoint(data, scene.children, function (obj) { | ||
return scene.add(obj); | ||
}, function (obj) { | ||
return scene.remove(obj); | ||
}, _objectSpread({ | ||
objBindAttr: '__threeObj' | ||
}, options)); | ||
} | ||
function dataBindDiff(data, existingObjs, { | ||
objBindAttr = '__obj', | ||
dataBindAttr = '__data' | ||
}) { | ||
const isObjValid = obj => obj.hasOwnProperty(dataBindAttr); | ||
const isDataBound = d => d.hasOwnProperty(objBindAttr) && !!d[objBindAttr]; | ||
const removeObjs = existingObjs.filter(obj => !isObjValid(obj)); | ||
const addData = data.filter(d => !isDataBound(d)); | ||
const prevD = existingObjs.filter(isObjValid).map(obj => obj[dataBindAttr]); | ||
const nextD = data.filter(isDataBound); | ||
const diff = diffArrays(prevD, nextD); | ||
diff.enter = diff.enter.concat(addData); | ||
diff.exit = diff.exit.concat(removeObjs.map(obj => ({ | ||
[objBindAttr]: obj | ||
}))); | ||
return diff; | ||
} | ||
function viewDigest(data, existingObjs, // list | ||
appendObj, // item => {...} function | ||
removeObj, // item => {...} function | ||
{ | ||
createObj = d => {}, | ||
updateObj = (obj, d) => {}, | ||
exitObj = obj => {}, | ||
objBindAttr = '__obj', | ||
dataBindAttr = '__data' | ||
}) { | ||
const { | ||
enter, | ||
update, | ||
exit | ||
} = dataBindDiff(data, existingObjs, { | ||
objBindAttr, | ||
dataBindAttr | ||
}); | ||
const newObjs = createObjs(enter); | ||
const pointsData = [...enter, ...update]; | ||
updateObjs(pointsData); // Add new points | ||
newObjs.forEach(appendObj); // Remove exiting points | ||
exit.forEach(d => { | ||
const obj = d[objBindAttr]; | ||
exitObj(obj); | ||
removeObj(obj); | ||
}); // | ||
function createObjs(data) { | ||
const newObjs = []; | ||
data.forEach(d => { | ||
const obj = createObj(d); | ||
if (obj) { | ||
obj[dataBindAttr] = d; | ||
d[objBindAttr] = obj; | ||
newObjs.push(obj); | ||
} | ||
}); | ||
return newObjs; | ||
} | ||
function updateObjs(data) { | ||
data.forEach(d => { | ||
const obj = d[objBindAttr]; | ||
if (obj) { | ||
obj[dataBindAttr] = d; | ||
updateObj(obj, d); | ||
} | ||
}); | ||
} | ||
} | ||
function threeDigest(data, scene, { | ||
createObj, | ||
updateObj, | ||
exitObj | ||
}) { | ||
return viewDigest(data, scene.children, obj => scene.add(obj), obj => scene.remove(obj), { | ||
objBindAttr: '__threeObj', | ||
createObj, | ||
updateObj, | ||
exitObj | ||
}); | ||
} | ||
const THREE$2 = window.THREE ? window.THREE // Prefer consumption from global THREE, if exists | ||
var THREE$2 = window.THREE ? window.THREE // Prefer consumption from global THREE, if exists | ||
: { | ||
Color, | ||
CylinderGeometry, | ||
CylinderBufferGeometry, | ||
FaceColors, | ||
Geometry, | ||
Matrix4, | ||
Mesh, | ||
MeshBasicMaterial, | ||
MeshLambertMaterial, | ||
Object3D | ||
Color: Color, | ||
CylinderGeometry: CylinderGeometry, | ||
CylinderBufferGeometry: CylinderBufferGeometry, | ||
FaceColors: FaceColors, | ||
Geometry: Geometry, | ||
Matrix4: Matrix4, | ||
Mesh: Mesh, | ||
MeshBasicMaterial: MeshBasicMaterial, | ||
MeshLambertMaterial: MeshLambertMaterial, | ||
Object3D: Object3D | ||
}; | ||
@@ -643,23 +749,25 @@ | ||
pointsData: { | ||
default: [] | ||
"default": [] | ||
}, | ||
pointLat: { | ||
default: 'lat' | ||
"default": 'lat' | ||
}, | ||
pointLng: { | ||
default: 'lng' | ||
"default": 'lng' | ||
}, | ||
pointColor: { | ||
default: () => '#ffffaa' | ||
"default": function _default() { | ||
return '#ffffaa'; | ||
} | ||
}, | ||
pointAltitude: { | ||
default: 0.1 | ||
"default": 0.1 | ||
}, | ||
// in units of globe radius | ||
pointRadius: { | ||
default: 0.25 | ||
"default": 0.25 | ||
}, | ||
// in deg | ||
pointResolution: { | ||
default: 12, | ||
"default": 12, | ||
triggerUpdate: false | ||
@@ -669,7 +777,7 @@ }, | ||
pointsMerge: { | ||
default: false | ||
"default": false | ||
}, | ||
// boolean. Whether to merge all points into a single mesh for rendering performance | ||
pointsTransitionDuration: { | ||
default: 1000, | ||
"default": 1000, | ||
triggerUpdate: false // ms | ||
@@ -679,4 +787,3 @@ | ||
}, | ||
init(threeObj, state) { | ||
init: function init(threeObj, state) { | ||
// Clear the scene | ||
@@ -687,22 +794,21 @@ emptyObject(threeObj); // Main three object to manipulate | ||
}, | ||
update(state) { | ||
update: function update(state) { | ||
// Data accessors | ||
const latAccessor = accessorFn(state.pointLat); | ||
const lngAccessor = accessorFn(state.pointLng); | ||
const altitudeAccessor = accessorFn(state.pointAltitude); | ||
const radiusAccessor = accessorFn(state.pointRadius); | ||
const colorAccessor = accessorFn(state.pointColor); // shared geometry | ||
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 | ||
const pointGeometry = new THREE$2[state.pointsMerge ? 'CylinderGeometry' : 'CylinderBufferGeometry'](1, 1, 1, state.pointResolution); | ||
var pointGeometry = new THREE$2[state.pointsMerge ? 'CylinderGeometry' : 'CylinderBufferGeometry'](1, 1, 1, state.pointResolution); | ||
pointGeometry.applyMatrix(new THREE$2.Matrix4().makeRotationX(Math.PI / 2)); | ||
pointGeometry.applyMatrix(new THREE$2.Matrix4().makeTranslation(0, 0, -0.5)); | ||
const pxPerDeg = 2 * Math.PI * GLOBE_RADIUS / 360; | ||
const pointMaterials = {}; // indexed by color | ||
var pxPerDeg = 2 * Math.PI * GLOBE_RADIUS / 360; | ||
var pointMaterials = {}; // indexed by color | ||
const scene = state.pointsMerge ? new THREE$2.Object3D() : state.scene; // use fake scene if merging points | ||
var scene = state.pointsMerge ? new THREE$2.Object3D() : state.scene; // use fake scene if merging points | ||
threeDigest(state.pointsData, scene, { | ||
createObj, | ||
updateObj, | ||
createObj: createObj, | ||
updateObj: updateObj, | ||
exitObj: emptyObject | ||
@@ -713,14 +819,16 @@ }); | ||
// merge points into a single mesh | ||
const pointsGeometry = new THREE$2.Geometry(); | ||
state.pointsData.forEach(d => { | ||
const obj = d.__threeObj; | ||
var pointsGeometry = new THREE$2.Geometry(); | ||
state.pointsData.forEach(function (d) { | ||
var obj = d.__threeObj; | ||
d.__threeObj = undefined; // unbind merged points | ||
// color faces | ||
const color = new THREE$2.Color(colorAccessor(d)); | ||
obj.geometry.faces.forEach(face => face.color = color); | ||
var color = new THREE$2.Color(colorAccessor(d)); | ||
obj.geometry.faces.forEach(function (face) { | ||
return face.color = color; | ||
}); | ||
obj.updateMatrix(); | ||
pointsGeometry.merge(obj.geometry, obj.matrix); | ||
}); | ||
const points = new THREE$2.Mesh(pointsGeometry, new THREE$2.MeshBasicMaterial({ | ||
var points = new THREE$2.Mesh(pointsGeometry, new THREE$2.MeshBasicMaterial({ | ||
color: 0xffffff, | ||
@@ -739,3 +847,3 @@ vertexColors: THREE$2.FaceColors, | ||
function createObj() { | ||
const obj = new THREE$2.Mesh(pointGeometry); | ||
var obj = new THREE$2.Mesh(pointGeometry); | ||
obj.__globeObjType = 'point'; // Add object type | ||
@@ -747,8 +855,7 @@ | ||
function updateObj(obj, d) { | ||
const applyUpdate = ({ | ||
r, | ||
alt, | ||
lat, | ||
lng | ||
}) => { | ||
var applyUpdate = function applyUpdate(_ref) { | ||
var r = _ref.r, | ||
alt = _ref.alt, | ||
lat = _ref.lat, | ||
lng = _ref.lng; | ||
// position cylinder ground | ||
@@ -763,3 +870,3 @@ Object.assign(obj.position, polar2Cartesian(lat, lng)); // orientate outwards | ||
const targetD = { | ||
var targetD = { | ||
alt: altitudeAccessor(d), | ||
@@ -770,3 +877,3 @@ r: radiusAccessor(d), | ||
}; | ||
const currentTargetD = obj.__currentTargetD; | ||
var currentTargetD = obj.__currentTargetD; | ||
obj.__currentTargetD = targetD; | ||
@@ -786,4 +893,4 @@ | ||
// Update materials on individual points | ||
const color = colorAccessor(d); | ||
const opacity = colorAlpha(color); | ||
var color = colorAccessor(d); | ||
var opacity = colorAlpha(color); | ||
@@ -802,21 +909,20 @@ if (!pointMaterials.hasOwnProperty(color)) { | ||
} | ||
}); | ||
const THREE$3 = window.THREE ? window.THREE // Prefer consumption from global THREE, if exists | ||
var THREE$3 = window.THREE ? window.THREE // Prefer consumption from global THREE, if exists | ||
: { | ||
AdditiveBlending, | ||
BufferGeometry, | ||
CubicBezierCurve3, | ||
Curve, | ||
Float32BufferAttribute, | ||
Line, | ||
Mesh, | ||
QuadraticBezierCurve3, | ||
ShaderMaterial, | ||
TubeBufferGeometry, | ||
Vector3 | ||
AdditiveBlending: AdditiveBlending, | ||
BufferGeometry: BufferGeometry, | ||
CubicBezierCurve3: CubicBezierCurve3, | ||
Curve: Curve, | ||
Float32BufferAttribute: Float32BufferAttribute, | ||
Line: Line, | ||
Mesh: Mesh, | ||
QuadraticBezierCurve3: QuadraticBezierCurve3, | ||
ShaderMaterial: ShaderMaterial, | ||
TubeBufferGeometry: TubeBufferGeometry, | ||
Vector3: Vector3 | ||
}; | ||
const gradientShaders = { | ||
var gradientShaders = { | ||
uniforms: { | ||
@@ -838,35 +944,4 @@ // dash param defaults, all relative to full length | ||
}, | ||
vertexShader: ` | ||
uniform float dashTranslate; | ||
attribute vec4 vertexColor; | ||
varying vec4 vColor; | ||
attribute float vertexRelDistance; | ||
varying float vRelDistance; | ||
void main() { | ||
// pass through colors and distances | ||
vColor = vertexColor; | ||
vRelDistance = vertexRelDistance + dashTranslate; | ||
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); | ||
} | ||
`, | ||
fragmentShader: ` | ||
uniform float dashOffset; | ||
uniform float dashSize; | ||
uniform float gapSize; | ||
varying vec4 vColor; | ||
varying float vRelDistance; | ||
void main() { | ||
// ignore pixels in the gap | ||
if (vRelDistance < dashOffset) discard; | ||
if (mod(vRelDistance - dashOffset, dashSize + gapSize) > dashSize) discard; | ||
// set px color: [r, g, b, a], interpolated between vertices | ||
gl_FragColor = vColor; | ||
} | ||
` | ||
vertexShader: "\n uniform float dashTranslate; \n\n attribute vec4 vertexColor;\n varying vec4 vColor;\n \n attribute float vertexRelDistance;\n varying float vRelDistance;\n\n void main() {\n // pass through colors and distances\n vColor = vertexColor;\n vRelDistance = vertexRelDistance + 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 " | ||
}; | ||
@@ -876,18 +951,20 @@ var ArcsLayerKapsule = Kapsule({ | ||
arcsData: { | ||
default: [] | ||
"default": [] | ||
}, | ||
arcStartLat: { | ||
default: 'startLat' | ||
"default": 'startLat' | ||
}, | ||
arcStartLng: { | ||
default: 'startLng' | ||
"default": 'startLng' | ||
}, | ||
arcEndLat: { | ||
default: 'endLat' | ||
"default": 'endLat' | ||
}, | ||
arcEndLng: { | ||
default: 'endLng' | ||
"default": 'endLng' | ||
}, | ||
arcColor: { | ||
default: () => '#ffffaa' | ||
"default": function _default() { | ||
return '#ffffaa'; | ||
} | ||
}, | ||
@@ -897,3 +974,3 @@ arcAltitude: {}, | ||
arcAltitudeAutoScale: { | ||
default: 0.5 | ||
"default": 0.5 | ||
}, | ||
@@ -904,3 +981,3 @@ // scale altitude proportional to great-arc distance between the two points | ||
arcCurveResolution: { | ||
default: 64, | ||
"default": 64, | ||
triggerUpdate: false | ||
@@ -910,3 +987,3 @@ }, | ||
arcCircularResolution: { | ||
default: 6, | ||
"default": 6, | ||
triggerUpdate: false | ||
@@ -916,17 +993,17 @@ }, | ||
arcDashLength: { | ||
default: 1 | ||
"default": 1 | ||
}, | ||
// in units of line length | ||
arcDashGap: { | ||
default: 0 | ||
"default": 0 | ||
}, | ||
arcDashInitialGap: { | ||
default: 0 | ||
"default": 0 | ||
}, | ||
arcDashAnimateTime: { | ||
default: 0 | ||
"default": 0 | ||
}, | ||
// ms | ||
arcsTransitionDuration: { | ||
default: 1000, | ||
"default": 1000, | ||
triggerUpdate: false // ms | ||
@@ -936,4 +1013,3 @@ | ||
}, | ||
init(threeObj, state) { | ||
init: function init(threeObj, state) { | ||
// Clear the scene | ||
@@ -944,7 +1020,9 @@ emptyObject(threeObj); // Main three object to manipulate | ||
new FrameTicker().onTick.add((_, timeDelta) => { | ||
state.arcsData.filter(d => d.__threeObj && d.__threeObj.material && d.__threeObj.__dashAnimateStep).forEach(d => { | ||
const obj = d.__threeObj; | ||
const step = obj.__dashAnimateStep * timeDelta; | ||
const curTranslate = obj.material.uniforms.dashTranslate.value % 1e9; // reset after 1B loops | ||
new FrameTicker().onTick.add(function (_, timeDelta) { | ||
state.arcsData.filter(function (d) { | ||
return d.__threeObj && d.__threeObj.material && d.__threeObj.__dashAnimateStep; | ||
}).forEach(function (d) { | ||
var obj = d.__threeObj; | ||
var step = obj.__dashAnimateStep * timeDelta; | ||
var curTranslate = obj.material.uniforms.dashTranslate.value % 1e9; // reset after 1B loops | ||
@@ -955,27 +1033,26 @@ obj.material.uniforms.dashTranslate.value = curTranslate + step; | ||
}, | ||
update(state) { | ||
update: function update(state) { | ||
// Data accessors | ||
const startLatAccessor = accessorFn(state.arcStartLat); | ||
const startLngAccessor = accessorFn(state.arcStartLng); | ||
const endLatAccessor = accessorFn(state.arcEndLat); | ||
const endLngAccessor = accessorFn(state.arcEndLng); | ||
const altitudeAccessor = accessorFn(state.arcAltitude); | ||
const altitudeAutoScaleAccessor = accessorFn(state.arcAltitudeAutoScale); | ||
const strokeAccessor = accessorFn(state.arcStroke); | ||
const colorAccessor = accessorFn(state.arcColor); | ||
const dashLengthAccessor = accessorFn(state.arcDashLength); | ||
const dashGapAccessor = accessorFn(state.arcDashGap); | ||
const dashInitialGapAccessor = accessorFn(state.arcDashInitialGap); | ||
const dashAnimateTimeAccessor = accessorFn(state.arcDashAnimateTime); | ||
const sharedMaterial = new THREE$3.ShaderMaterial({ ...gradientShaders, | ||
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); | ||
var sharedMaterial = new THREE$3.ShaderMaterial(_objectSpread({}, gradientShaders, { | ||
transparent: true, | ||
blending: THREE$3.AdditiveBlending | ||
}); | ||
})); | ||
threeDigest(state.arcsData, state.scene, { | ||
exitObj: emptyObject, | ||
createObj: arc => { | ||
const stroke = strokeAccessor(arc); | ||
const useTube = stroke !== null && stroke !== undefined; | ||
const obj = useTube ? new THREE$3.Mesh() : new THREE$3.Line(new THREE$3.BufferGeometry()); | ||
createObj: function createObj(arc) { | ||
var stroke = strokeAccessor(arc); | ||
var useTube = stroke !== null && stroke !== undefined; | ||
var obj = useTube ? new THREE$3.Mesh() : new THREE$3.Line(new THREE$3.BufferGeometry()); | ||
obj.material = sharedMaterial.clone(); // Separate material instance per object to have dedicated uniforms (but shared shaders) | ||
@@ -987,5 +1064,5 @@ | ||
}, | ||
updateObj: (obj, arc) => { | ||
const stroke = strokeAccessor(arc); | ||
const useTube = stroke !== null && stroke !== undefined; // set dash uniforms | ||
updateObj: function updateObj(obj, arc) { | ||
var stroke = strokeAccessor(arc); | ||
var useTube = stroke !== null && stroke !== undefined; // set dash uniforms | ||
@@ -1004,7 +1081,7 @@ Object.assign(obj.material.uniforms, { | ||
const dashAnimateTime = dashAnimateTimeAccessor(arc); | ||
var dashAnimateTime = dashAnimateTimeAccessor(arc); | ||
obj.__dashAnimateStep = dashAnimateTime > 0 ? 1000 / dashAnimateTime : 0; // per second | ||
// calculate vertex colors (to create gradient) | ||
const vertexColorArray = calcColorVertexArray(colorAccessor(arc), // single or array of colors | ||
var vertexColorArray = calcColorVertexArray(colorAccessor(arc), // single or array of colors | ||
state.arcCurveResolution, // numSegments | ||
@@ -1014,3 +1091,3 @@ useTube ? state.arcCircularResolution + 1 : 1 // num vertices per segment | ||
const vertexRelDistanceArray = calcVertexRelDistances(state.arcCurveResolution, // numSegments | ||
var vertexRelDistanceArray = calcVertexRelDistances(state.arcCurveResolution, // numSegments | ||
useTube ? state.arcCircularResolution + 1 : 1, // num vertices per segment | ||
@@ -1020,8 +1097,8 @@ true // run from end to start, to animate in the correct direction | ||
const applyUpdate = ({ | ||
stroke, | ||
...curveD | ||
}) => { | ||
const curve = calcCurve(curveD); | ||
var applyUpdate = function applyUpdate(_ref) { | ||
var stroke = _ref.stroke, | ||
curveD = _objectWithoutProperties(_ref, ["stroke"]); | ||
var curve = calcCurve(curveD); | ||
if (useTube) { | ||
@@ -1038,4 +1115,4 @@ obj.geometry && obj.geometry.dispose(); | ||
const targetD = { | ||
stroke, | ||
var targetD = { | ||
stroke: stroke, | ||
alt: altitudeAccessor(arc), | ||
@@ -1048,3 +1125,3 @@ altAutoScale: altitudeAutoScaleAccessor(arc), | ||
}; | ||
const currentTargetD = arc.__currentTargetD; | ||
var currentTargetD = arc.__currentTargetD; | ||
arc.__currentTargetD = targetD; | ||
@@ -1064,16 +1141,21 @@ | ||
function calcCurve({ | ||
alt, | ||
altAutoScale, | ||
startLat, | ||
startLng, | ||
endLat, | ||
endLng | ||
}) { | ||
const getVec = ([lng, lat, alt]) => { | ||
const { | ||
x, | ||
y, | ||
z | ||
} = polar2Cartesian(lat, lng, alt); | ||
function calcCurve(_ref2) { | ||
var alt = _ref2.alt, | ||
altAutoScale = _ref2.altAutoScale, | ||
startLat = _ref2.startLat, | ||
startLng = _ref2.startLng, | ||
endLat = _ref2.endLat, | ||
endLng = _ref2.endLng; | ||
var getVec = function getVec(_ref3) { | ||
var _ref4 = _slicedToArray(_ref3, 3), | ||
lng = _ref4[0], | ||
lat = _ref4[1], | ||
alt = _ref4[2]; | ||
var _polar2Cartesian = polar2Cartesian(lat, lng, alt), | ||
x = _polar2Cartesian.x, | ||
y = _polar2Cartesian.y, | ||
z = _polar2Cartesian.z; | ||
return new THREE$3.Vector3(x, y, z); | ||
@@ -1083,5 +1165,5 @@ }; //calculate curve | ||
const startPnt = [startLng, startLat]; | ||
const endPnt = [endLng, endLat]; | ||
let altitude = alt; | ||
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 | ||
@@ -1091,13 +1173,21 @@ altitude = geoDistance(startPnt, endPnt) / 2 * altAutoScale); | ||
if (altitude) { | ||
const interpolate = geoInterpolate(startPnt, endPnt); | ||
const [m1Pnt, m2Pnt] = [0.25, 0.75].map(t => [...interpolate(t), altitude * 1.5]); | ||
const curve = new THREE$3.CubicBezierCurve3(...[startPnt, m1Pnt, m2Pnt, endPnt].map(getVec)); //const mPnt = [...interpolate(0.5), altitude * 2]; | ||
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$3.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 | ||
const alt = 0.001; // slightly above the ground to prevent occlusion | ||
var _alt = 0.001; // slightly above the ground to prevent occlusion | ||
return calcSphereArc(...[[...startPnt, alt], [...endPnt, alt]].map(getVec)); | ||
return calcSphereArc.apply(void 0, _toConsumableArray([[].concat(startPnt, [_alt]), [].concat(endPnt, [_alt])].map(getVec))); | ||
} // | ||
@@ -1107,7 +1197,9 @@ | ||
function calcSphereArc(startVec, endVec) { | ||
const angle = startVec.angleTo(endVec); | ||
var angle = startVec.angleTo(endVec); | ||
const getGreatCirclePoint = t => new THREE$3.Vector3().addVectors(startVec.clone().multiplyScalar(Math.sin((1 - t) * angle)), endVec.clone().multiplyScalar(Math.sin(t * angle))).divideScalar(Math.sin(angle)); | ||
var getGreatCirclePoint = function getGreatCirclePoint(t) { | ||
return new THREE$3.Vector3().addVectors(startVec.clone().multiplyScalar(Math.sin((1 - t) * angle)), endVec.clone().multiplyScalar(Math.sin(t * angle))).divideScalar(Math.sin(angle)); | ||
}; | ||
const sphereArc = new THREE$3.Curve(); | ||
var sphereArc = new THREE$3.Curve(); | ||
sphereArc.getPoint = getGreatCirclePoint; | ||
@@ -1118,27 +1210,34 @@ return sphereArc; | ||
function calcColorVertexArray(colors, numSegments, numVerticesPerSegment = 1) { | ||
const numVerticesGroup = numSegments + 1; // one between every two segments and two at the ends | ||
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 | ||
let getVertexColor; | ||
var getVertexColor; | ||
if (colors instanceof Array) { | ||
// array of colors, interpolate at each step | ||
const colorScale = scaleLinear().domain(colors.map((_, idx) => idx / (colors.length - 1))) // same number of stops as colors | ||
var colorScale = scaleLinear().domain(colors.map(function (_, idx) { | ||
return idx / (colors.length - 1); | ||
})) // same number of stops as colors | ||
.range(colors); | ||
getVertexColor = t => color2ShaderArr(colorScale(t)); | ||
getVertexColor = function getVertexColor(t) { | ||
return color2ShaderArr(colorScale(t)); | ||
}; | ||
} else { | ||
// single color, use constant | ||
const vertexColor = color2ShaderArr(colors); | ||
var vertexColor = color2ShaderArr(colors); | ||
getVertexColor = () => vertexColor; | ||
getVertexColor = function getVertexColor() { | ||
return vertexColor; | ||
}; | ||
} | ||
const vertexColorArray = new THREE$3.Float32BufferAttribute(numVerticesGroup * 4 * numVerticesPerSegment, 4); | ||
var vertexColorArray = new THREE$3.Float32BufferAttribute(numVerticesGroup * 4 * numVerticesPerSegment, 4); | ||
for (let v = 0, l = numVerticesGroup; v < l; v++) { | ||
const vertexColor = getVertexColor(v / (l - 1)); | ||
for (var v = 0, l = numVerticesGroup; v < l; v++) { | ||
var _vertexColor = getVertexColor(v / (l - 1)); | ||
for (let s = 0; s < numVerticesPerSegment; s++) { | ||
vertexColorArray.set(vertexColor, (v * numVerticesPerSegment + s) * 4); | ||
for (var s = 0; s < numVerticesPerSegment; s++) { | ||
vertexColorArray.set(_vertexColor, (v * numVerticesPerSegment + s) * 4); | ||
} | ||
@@ -1150,14 +1249,16 @@ } | ||
function calcVertexRelDistances(numSegments, numVerticesPerSegment = 1, invert = false) { | ||
const numVerticesGroup = numSegments + 1; // one between every two segments and two at the ends | ||
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 | ||
const arrLen = numVerticesGroup * numVerticesPerSegment; | ||
const vertexDistanceArray = new THREE$3.Float32BufferAttribute(arrLen, 1); | ||
var arrLen = numVerticesGroup * numVerticesPerSegment; | ||
var vertexDistanceArray = new THREE$3.Float32BufferAttribute(arrLen, 1); | ||
for (let v = 0, l = numVerticesGroup; v < l; v++) { | ||
const relDistance = v / (l - 1); | ||
for (var v = 0, l = numVerticesGroup; v < l; v++) { | ||
var relDistance = v / (l - 1); | ||
for (let s = 0; s < numVerticesPerSegment; s++) { | ||
const idx = v * numVerticesPerSegment + s; | ||
const pos = invert ? arrLen - 1 - idx : idx; | ||
for (var s = 0; s < numVerticesPerSegment; s++) { | ||
var idx = v * numVerticesPerSegment + s; | ||
var pos = invert ? arrLen - 1 - idx : idx; | ||
vertexDistanceArray.setX(pos, relDistance); | ||
@@ -1170,9 +1271,336 @@ } | ||
} | ||
}); | ||
var THREE$4 = window.THREE ? window.THREE // Prefer consumption from global THREE, if exists | ||
: { | ||
Color: Color, | ||
CylinderGeometry: CylinderGeometry, | ||
CylinderBufferGeometry: CylinderBufferGeometry, | ||
FaceColors: FaceColors, | ||
Geometry: Geometry, | ||
Matrix4: Matrix4, | ||
Mesh: Mesh, | ||
MeshBasicMaterial: MeshBasicMaterial, | ||
MeshLambertMaterial: MeshLambertMaterial, | ||
Object3D: Object3D | ||
}; | ||
var HexBinLayerKapsule = Kapsule({ | ||
props: { | ||
hexBinPointsData: { | ||
"default": [] | ||
}, | ||
hexBinPointLat: { | ||
"default": 'lat' | ||
}, | ||
hexBinPointLng: { | ||
"default": 'lng' | ||
}, | ||
hexBinPointWeight: { | ||
"default": 1 | ||
}, | ||
hexRadius: { | ||
"default": 0.25 | ||
}, | ||
// in deg | ||
hexMargin: { | ||
"default": 0.2 | ||
}, | ||
// in fraction of diameter | ||
hexColor: { | ||
"default": function _default() { | ||
return '#ffffaa'; | ||
} | ||
}, | ||
hexAltitude: { | ||
"default": function _default(_ref) { | ||
var sumWeight = _ref.sumWeight; | ||
return sumWeight * 0.01; | ||
} | ||
}, | ||
// in units of globe radius | ||
hexBinMerge: { | ||
"default": false | ||
}, | ||
// boolean. Whether to merge all hex geometries into a single mesh for rendering performance | ||
hexTransitionDuration: { | ||
"default": 1000, | ||
triggerUpdate: false // ms | ||
} | ||
}, | ||
init: function init(threeObj, state) { | ||
// Clear the scene | ||
emptyObject(threeObj); // Main three object to manipulate | ||
state.scene = threeObj; | ||
}, | ||
update: function update(state) { | ||
// Accessors | ||
var latAccessor = accessorFn(state.hexBinPointLat); | ||
var lngAccessor = accessorFn(state.hexBinPointLng); | ||
var weightAccessor = accessorFn(state.hexBinPointWeight); | ||
var altitudeAccessor = accessorFn(state.hexAltitude); | ||
var colorAccessor = accessorFn(state.hexColor); | ||
var marginAccessor = accessorFn(state.hexMargin); | ||
var hexBins = hexbin().radius(state.hexRadius).y(latAccessor).x(function (d) { | ||
return lngAccessor(d) * Math.cos(latAccessor(d) * Math.PI / 180); | ||
})(state.hexBinPointsData).map(function (bin) { | ||
return { | ||
points: bin.map(function (d) { | ||
return d; | ||
}), | ||
center: { | ||
lat: bin.y, | ||
lng: bin.x / Math.cos(bin.y * Math.PI / 180) | ||
}, | ||
sumWeight: bin.reduce(function (agg, d) { | ||
return agg + weightAccessor(d); | ||
}, 0) | ||
}; | ||
}); // shared geometry | ||
var hexGeometry = new THREE$4[state.hexBinMerge ? 'CylinderGeometry' : 'CylinderBufferGeometry'](1, 1, 1, 6); | ||
hexGeometry.applyMatrix(new THREE$4.Matrix4().makeRotationX(Math.PI / 2)); | ||
hexGeometry.applyMatrix(new THREE$4.Matrix4().makeTranslation(0, 0, -0.5)); | ||
var pxPerDeg = 2 * Math.PI * GLOBE_RADIUS / 360; | ||
var hexMaterials = {}; // indexed by color | ||
var scene = state.hexBinMerge ? new THREE$4.Object3D() : state.scene; // use fake scene if merging hex points | ||
threeDigest(hexBins, scene, { | ||
createObj: createObj, | ||
updateObj: updateObj, | ||
exitObj: emptyObject, | ||
idAccessor: function idAccessor(d) { | ||
return "".concat(Math.round(d.center.lat * 1e6), "-").concat(Math.round(d.center.lng * 1e6)); | ||
} | ||
}); | ||
if (state.hexBinMerge) { | ||
// merge points into a single mesh | ||
var hexPointsGeometry = new THREE$4.Geometry(); | ||
hexBins.forEach(function (d) { | ||
var obj = d.__threeObj; | ||
d.__threeObj = undefined; // unbind merged points | ||
// color faces | ||
var color = new THREE$4.Color(colorAccessor(d)); | ||
obj.geometry.faces.forEach(function (face) { | ||
return face.color = color; | ||
}); | ||
obj.updateMatrix(); | ||
hexPointsGeometry.merge(obj.geometry, obj.matrix); | ||
}); | ||
var hexPoints = new THREE$4.Mesh(hexPointsGeometry, new THREE$4.MeshBasicMaterial({ | ||
color: 0xffffff, | ||
vertexColors: THREE$4.FaceColors, | ||
morphTargets: false | ||
})); | ||
hexPoints.__globeObjType = 'hexBinPoints'; // Add object type | ||
hexPoints.__data = hexBins; // Attach obj data | ||
state.scene.add(hexPoints); | ||
} // | ||
function createObj() { | ||
var obj = new THREE$4.Mesh(hexGeometry); | ||
obj.__globeObjType = 'hexbin'; // Add object type | ||
return obj; | ||
} | ||
function updateObj(obj, d) { | ||
var applyUpdate = function applyUpdate(_ref2) { | ||
var r = _ref2.r, | ||
alt = _ref2.alt, | ||
lat = _ref2.lat, | ||
lng = _ref2.lng; | ||
// position cylinder ground | ||
Object.assign(obj.position, polar2Cartesian(lat, lng)); // orientate outwards | ||
obj.lookAt(0, 0, 0); // 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: state.hexRadius * (1 - Math.max(0, Math.min(1, marginAccessor(d)))), | ||
lat: d.center.lat, | ||
lng: d.center.lng | ||
}; | ||
var currentTargetD = obj.__currentTargetD; | ||
obj.__currentTargetD = targetD; | ||
if (state.hexBinMerge || !state.hexTransitionDuration || state.hexTransitionDuration < 0) { | ||
// set final position | ||
applyUpdate(targetD); | ||
} else { | ||
// animate | ||
new TWEEN.Tween(currentTargetD || Object.assign({}, targetD, { | ||
alt: 0 | ||
})).to(targetD, state.hexTransitionDuration).easing(TWEEN.Easing.Quadratic.InOut).onUpdate(applyUpdate).start(); | ||
} | ||
if (!state.hexBinMerge) { | ||
// Update materials on individual hex points | ||
var color = colorAccessor(d); | ||
var opacity = colorAlpha(color); | ||
if (!hexMaterials.hasOwnProperty(color)) { | ||
hexMaterials[color] = new THREE$4.MeshLambertMaterial({ | ||
color: colorStr2Hex(color), | ||
transparent: opacity < 1, | ||
opacity: opacity | ||
}); | ||
} | ||
obj.material = hexMaterials[color]; | ||
} | ||
} | ||
} | ||
}); | ||
var THREE$5 = window.THREE ? window.THREE // Prefer consumption from global THREE, if exists | ||
: { | ||
DoubleSide: DoubleSide, | ||
Mesh: Mesh, | ||
MeshLambertMaterial: MeshLambertMaterial | ||
}; | ||
var PolygonsLayerKapsule = Kapsule({ | ||
props: { | ||
polygonsData: { | ||
"default": [] | ||
}, | ||
polygonGeoJsonGeometry: { | ||
"default": 'geometry' | ||
}, | ||
polygonSideColor: { | ||
"default": function _default() { | ||
return '#ffffaa'; | ||
} | ||
}, | ||
polygonCapColor: { | ||
"default": function _default() { | ||
return '#ffffaa'; | ||
} | ||
}, | ||
polygonAltitude: { | ||
"default": 0.1 | ||
}, | ||
// in units of globe radius | ||
polygonsTransitionDuration: { | ||
"default": 1000, | ||
triggerUpdate: false // ms | ||
} | ||
}, | ||
init: function init(threeObj, state) { | ||
// Clear the scene | ||
emptyObject(threeObj); // Main three object to manipulate | ||
state.scene = threeObj; | ||
}, | ||
update: function update(state) { | ||
// Data accessors | ||
var geoJsonAccessor = accessorFn(state.polygonGeoJsonGeometry); | ||
var altitudeAccessor = accessorFn(state.polygonAltitude); | ||
var capColorAccessor = accessorFn(state.polygonCapColor); | ||
var sideColorAccessor = accessorFn(state.polygonSideColor); | ||
var singlePolygons = []; | ||
state.polygonsData.forEach(function (polygon) { | ||
var objAttrs = { | ||
data: polygon, | ||
capColor: capColorAccessor(polygon), | ||
sideColor: sideColorAccessor(polygon), | ||
altitude: altitudeAccessor(polygon) | ||
}; | ||
var geoJson = geoJsonAccessor(polygon); | ||
var geoId = polygon.__id || "".concat(Math.round(Math.random() * 1e9)); // generate and stamp polygon ids to keep track in digest | ||
polygon.__id = geoId; | ||
if (geoJson.type === 'Polygon') { | ||
singlePolygons.push(_objectSpread({ | ||
id: "".concat(geoId, "_0"), | ||
coords: geoJson.coordinates | ||
}, objAttrs)); | ||
} else if (geoJson.type === 'MultiPolygon') { | ||
singlePolygons.push.apply(singlePolygons, _toConsumableArray(geoJson.coordinates.map(function (coords, idx) { | ||
return _objectSpread({ | ||
id: "".concat(geoId, "_").concat(idx), | ||
coords: coords | ||
}, objAttrs); | ||
}))); | ||
} else { | ||
console.warn("Unsupported GeoJson geometry type: ".concat(geoJson.type, ". Skipping geometry...")); | ||
} | ||
}); | ||
threeDigest(singlePolygons, state.scene, { | ||
idAccessor: function idAccessor(d) { | ||
return d.id; | ||
}, | ||
exitObj: emptyObject, | ||
createObj: function createObj() { | ||
var obj = new THREE$5.Mesh(undefined, [new THREE$5.MeshLambertMaterial({ | ||
side: THREE$5.DoubleSide, | ||
depthWrite: true | ||
}), // side material | ||
new THREE$5.MeshLambertMaterial({ | ||
side: THREE$5.DoubleSide, | ||
depthWrite: true | ||
}) // cap material | ||
]); | ||
obj.__globeObjType = 'polygon'; // Add object type | ||
return obj; | ||
}, | ||
updateObj: function updateObj(obj, _ref) { | ||
var coords = _ref.coords, | ||
capColor = _ref.capColor, | ||
sideColor = _ref.sideColor, | ||
altitude = _ref.altitude; | ||
// update materials | ||
[sideColor, capColor].forEach(function (color, materialIdx) { | ||
var opacity = colorAlpha(color); | ||
var material = obj.material[materialIdx]; | ||
material.color.set(colorStr2Hex(color)); | ||
material.transparent = opacity < 1; | ||
material.opacity = opacity; | ||
}); | ||
var applyUpdate = function applyUpdate(_ref2) { | ||
var alt = _ref2.alt; | ||
obj.geometry = new ConicPolygonBufferGeometry(coords, GLOBE_RADIUS, GLOBE_RADIUS * (1 + alt), false); | ||
}; | ||
var targetD = { | ||
alt: altitude | ||
}; | ||
var currentTargetD = obj.__currentTargetD || { | ||
alt: 0 | ||
}; | ||
obj.__currentTargetD = targetD; | ||
if (!state.polygonsTransitionDuration || state.polygonsTransitionDuration < 0) { | ||
// set final position | ||
applyUpdate(targetD); | ||
} else { | ||
// animate | ||
new TWEEN.Tween(currentTargetD).to(targetD, state.polygonsTransitionDuration).easing(TWEEN.Easing.Quadratic.InOut).onUpdate(applyUpdate).start(); | ||
} | ||
} | ||
}); | ||
} | ||
}); | ||
var CustomLayerKapsule = Kapsule({ | ||
props: { | ||
customLayerData: { | ||
default: [] | ||
"default": [] | ||
}, | ||
@@ -1184,4 +1612,3 @@ customThreeObject: {}, | ||
}, | ||
init(threeObj, state) { | ||
init: function init(threeObj, state) { | ||
// Clear the scene | ||
@@ -1192,4 +1619,3 @@ emptyObject(threeObj); // Main three object to manipulate | ||
}, | ||
update(state) { | ||
update: function update(state) { | ||
if (!state.customThreeObjectUpdate) { | ||
@@ -1200,7 +1626,7 @@ emptyObject(state.scene); | ||
const customObjectAccessor = accessorFn(state.customThreeObject); | ||
const customObjectUpdateAccessor = accessorFn(state.customThreeObjectUpdate); | ||
var customObjectAccessor = accessorFn(state.customThreeObject); | ||
var customObjectUpdateAccessor = accessorFn(state.customThreeObjectUpdate); | ||
threeDigest(state.customLayerData, state.scene, { | ||
createObj: d => { | ||
let obj = customObjectAccessor(d, GLOBE_RADIUS); | ||
createObj: function createObj(d) { | ||
var obj = customObjectAccessor(d, GLOBE_RADIUS); | ||
@@ -1218,44 +1644,61 @@ if (obj) { | ||
}, | ||
updateObj: (obj, d) => customObjectUpdateAccessor(obj, d, GLOBE_RADIUS), | ||
updateObj: function updateObj(obj, d) { | ||
return customObjectUpdateAccessor(obj, d, GLOBE_RADIUS); | ||
}, | ||
exitObj: emptyObject | ||
}); | ||
} | ||
}); | ||
const THREE$4 = window.THREE ? window.THREE // Prefer consumption from global THREE, if exists | ||
var THREE$6 = window.THREE ? window.THREE // Prefer consumption from global THREE, if exists | ||
: { | ||
Group, | ||
Vector3 | ||
Group: Group, | ||
Vector3: Vector3 | ||
}; | ||
// Expose config from layers | ||
const bindGlobeLayer = linkKapsule('globeLayer', GlobeLayerKapsule); | ||
const linkedGlobeLayerProps = Object.assign(...['globeImageUrl', 'bumpImageUrl', 'showAtmosphere', 'showGraticules'].map(p => ({ | ||
[p]: bindGlobeLayer.linkProp(p) | ||
var bindGlobeLayer = linkKapsule('globeLayer', GlobeLayerKapsule); | ||
var linkedGlobeLayerProps = Object.assign.apply(Object, _toConsumableArray(['globeImageUrl', 'bumpImageUrl', 'showAtmosphere', 'showGraticules'].map(function (p) { | ||
return _defineProperty({}, p, bindGlobeLayer.linkProp(p)); | ||
}))); | ||
const bindPointsLayer = linkKapsule('pointsLayer', PointsLayerKapsule); | ||
const linkedPointsLayerProps = Object.assign(...['pointsData', 'pointLat', 'pointLng', 'pointColor', 'pointAltitude', 'pointRadius', 'pointResolution', 'pointsMerge', 'pointsTransitionDuration'].map(p => ({ | ||
[p]: bindPointsLayer.linkProp(p) | ||
var bindPointsLayer = linkKapsule('pointsLayer', PointsLayerKapsule); | ||
var linkedPointsLayerProps = Object.assign.apply(Object, _toConsumableArray(['pointsData', 'pointLat', 'pointLng', 'pointColor', 'pointAltitude', 'pointRadius', 'pointResolution', 'pointsMerge', 'pointsTransitionDuration'].map(function (p) { | ||
return _defineProperty({}, p, bindPointsLayer.linkProp(p)); | ||
}))); | ||
const bindArcsLayer = linkKapsule('arcsLayer', ArcsLayerKapsule); | ||
const linkedArcsLayerProps = Object.assign(...['arcsData', 'arcStartLat', 'arcStartLng', 'arcEndLat', 'arcEndLng', 'arcColor', 'arcAltitude', 'arcAltitudeAutoScale', 'arcStroke', 'arcCurveResolution', 'arcCircularResolution', 'arcDashLength', 'arcDashGap', 'arcDashInitialGap', 'arcDashAnimateTime', 'arcsTransitionDuration'].map(p => ({ | ||
[p]: bindArcsLayer.linkProp(p) | ||
var bindArcsLayer = linkKapsule('arcsLayer', ArcsLayerKapsule); | ||
var linkedArcsLayerProps = Object.assign.apply(Object, _toConsumableArray(['arcsData', 'arcStartLat', 'arcStartLng', 'arcEndLat', 'arcEndLng', 'arcColor', 'arcAltitude', 'arcAltitudeAutoScale', 'arcStroke', 'arcCurveResolution', 'arcCircularResolution', 'arcDashLength', 'arcDashGap', 'arcDashInitialGap', 'arcDashAnimateTime', 'arcsTransitionDuration'].map(function (p) { | ||
return _defineProperty({}, p, bindArcsLayer.linkProp(p)); | ||
}))); | ||
const bindCustomLayer = linkKapsule('customLayer', CustomLayerKapsule); | ||
const linkedCustomLayerProps = Object.assign(...['customLayerData', 'customThreeObject', 'customThreeObjectUpdate'].map(p => ({ | ||
[p]: bindCustomLayer.linkProp(p) | ||
var bindHexBinLayer = linkKapsule('hexBinLayer', HexBinLayerKapsule); | ||
var linkedHexBinLayerProps = Object.assign.apply(Object, _toConsumableArray(['hexBinPointsData', 'hexBinPointLat', 'hexBinPointLng', 'hexBinPointWeight', 'hexRadius', 'hexMargin', 'hexColor', 'hexAltitude', 'hexBinMerge', 'hexTransitionDuration'].map(function (p) { | ||
return _defineProperty({}, p, bindHexBinLayer.linkProp(p)); | ||
}))); | ||
var bindPolygonsLayer = linkKapsule('polygonsLayer', PolygonsLayerKapsule); | ||
var linkedPolygonsLayerProps = Object.assign.apply(Object, _toConsumableArray(['polygonsData', 'polygonGeoJsonGeometry', 'polygonCapColor', 'polygonSideColor', 'polygonAltitude', 'polygonsTransitionDuration'].map(function (p) { | ||
return _defineProperty({}, p, bindPolygonsLayer.linkProp(p)); | ||
}))); | ||
var bindCustomLayer = linkKapsule('customLayer', CustomLayerKapsule); | ||
var linkedCustomLayerProps = Object.assign.apply(Object, _toConsumableArray(['customLayerData', 'customThreeObject', 'customThreeObjectUpdate'].map(function (p) { | ||
return _defineProperty({}, p, bindCustomLayer.linkProp(p)); | ||
}))); // | ||
var Globe = Kapsule({ | ||
props: { ...linkedGlobeLayerProps, | ||
...linkedPointsLayerProps, | ||
...linkedArcsLayerProps, | ||
...linkedCustomLayerProps | ||
}, | ||
props: _objectSpread({}, linkedGlobeLayerProps, linkedPointsLayerProps, linkedArcsLayerProps, linkedHexBinLayerProps, linkedPolygonsLayerProps, linkedCustomLayerProps), | ||
methods: { | ||
getCoords: (state, ...args) => polar2Cartesian(...args), | ||
toGeoCoords: (state, ...args) => cartesian2Polar(...args) | ||
getCoords: function getCoords(state) { | ||
for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { | ||
args[_key - 1] = arguments[_key]; | ||
} | ||
return polar2Cartesian.apply(void 0, args); | ||
}, | ||
toGeoCoords: function toGeoCoords(state) { | ||
for (var _len2 = arguments.length, args = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) { | ||
args[_key2 - 1] = arguments[_key2]; | ||
} | ||
return cartesian2Polar.apply(void 0, args); | ||
} | ||
}, | ||
stateInit: () => { | ||
stateInit: function stateInit() { | ||
return { | ||
@@ -1265,2 +1708,4 @@ globeLayer: GlobeLayerKapsule(), | ||
arcsLayer: ArcsLayerKapsule(), | ||
hexBinLayer: HexBinLayerKapsule(), | ||
polygonsLayer: PolygonsLayerKapsule(), | ||
customLayer: CustomLayerKapsule(), | ||
@@ -1270,24 +1715,31 @@ animateIn: false | ||
}, | ||
init(threeObj, state, { | ||
animateIn = true | ||
}) { | ||
init: function init(threeObj, state, _ref7) { | ||
var _ref7$animateIn = _ref7.animateIn, | ||
animateIn = _ref7$animateIn === void 0 ? true : _ref7$animateIn; | ||
// Clear the scene | ||
emptyObject(threeObj); // Main three object to manipulate | ||
threeObj.add(state.scene = new THREE$4.Group()); // add globe layer group | ||
threeObj.add(state.scene = new THREE$6.Group()); // add globe layer group | ||
const globeG = new THREE$4.Group(); | ||
var globeG = new THREE$6.Group(); | ||
state.scene.add(globeG); | ||
state.globeLayer(globeG); // add points layer group | ||
const pointsG = new THREE$4.Group(); | ||
var pointsG = new THREE$6.Group(); | ||
state.scene.add(pointsG); | ||
state.pointsLayer(pointsG); // add arcs layer group | ||
const arcsG = new THREE$4.Group(); | ||
var arcsG = new THREE$6.Group(); | ||
state.scene.add(arcsG); | ||
state.arcsLayer(arcsG); // add custom layer group | ||
state.arcsLayer(arcsG); // add hexbin layer group | ||
const customG = new THREE$4.Group(); | ||
var hexBinG = new THREE$6.Group(); | ||
state.scene.add(hexBinG); | ||
state.hexBinLayer(hexBinG); // add polygons layer group | ||
var polygonsG = new THREE$6.Group(); | ||
state.scene.add(polygonsG); | ||
state.polygonsLayer(polygonsG); // add custom layer group | ||
var customG = new THREE$6.Group(); | ||
state.scene.add(customG); | ||
@@ -1309,6 +1761,5 @@ state.customLayer(customG); // animate build in, one time only | ||
}, | ||
update(state) { | ||
update: function update(state) { | ||
if (state.animateIn) { | ||
setTimeout(() => { | ||
setTimeout(function () { | ||
// Animate build-in just once | ||
@@ -1321,6 +1772,7 @@ state.animateIn = false; | ||
k: 1 | ||
}, 600).easing(TWEEN.Easing.Quadratic.Out).onUpdate(({ | ||
k | ||
}) => state.scene.scale.set(k, k, k)).start(); | ||
const rotAxis = new THREE$4.Vector3(0, 1, 0); | ||
}, 600).easing(TWEEN.Easing.Quadratic.Out).onUpdate(function (_ref8) { | ||
var k = _ref8.k; | ||
return state.scene.scale.set(k, k, k); | ||
}).start(); | ||
var rotAxis = new THREE$6.Vector3(0, 1, 0); | ||
new TWEEN.Tween({ | ||
@@ -1330,26 +1782,49 @@ rot: Math.PI * 2 | ||
rot: 0 | ||
}, 1200).easing(TWEEN.Easing.Quintic.Out).onUpdate(({ | ||
rot | ||
}) => state.scene.setRotationFromAxisAngle(rotAxis, rot)).start(); | ||
}, 1200).easing(TWEEN.Easing.Quintic.Out).onUpdate(function (_ref9) { | ||
var rot = _ref9.rot; | ||
return state.scene.setRotationFromAxisAngle(rotAxis, rot); | ||
}).start(); | ||
}, 600); // delay animation slightly to load globe texture | ||
} | ||
} | ||
}); | ||
function fromKapsule (kapsule, baseClass = Object, initKapsuleWithSelf = false) { | ||
class FromKapsule extends baseClass { | ||
constructor(...args) { | ||
super(...args); | ||
this.__kapsuleInstance = kapsule(...args)(...[...(initKapsuleWithSelf ? [this] : []), ...args]); | ||
function fromKapsule (kapsule) { | ||
var baseClass = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : Object; | ||
var initKapsuleWithSelf = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false; | ||
var FromKapsule = | ||
/*#__PURE__*/ | ||
function (_baseClass) { | ||
_inherits(FromKapsule, _baseClass); | ||
function FromKapsule() { | ||
var _getPrototypeOf2; | ||
var _this; | ||
_classCallCheck(this, FromKapsule); | ||
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { | ||
args[_key] = arguments[_key]; | ||
} | ||
_this = _possibleConstructorReturn(this, (_getPrototypeOf2 = _getPrototypeOf(FromKapsule)).call.apply(_getPrototypeOf2, [this].concat(args))); | ||
_this.__kapsuleInstance = kapsule.apply(void 0, args).apply(void 0, [].concat(_toConsumableArray(initKapsuleWithSelf ? [_assertThisInitialized(_this)] : []), args)); | ||
return _this; | ||
} | ||
} // attach kapsule props/methods to class prototype | ||
return FromKapsule; | ||
}(baseClass); // attach kapsule props/methods to class prototype | ||
Object.keys(kapsule()).forEach(m => FromKapsule.prototype[m] = function (...args) { | ||
const returnVal = this.__kapsuleInstance[m](...args); | ||
Object.keys(kapsule()).forEach(function (m) { | ||
return FromKapsule.prototype[m] = function () { | ||
var _this$__kapsuleInstan; | ||
return returnVal === this.__kapsuleInstance ? this // chain based on this class, not the kapsule obj | ||
: returnVal; | ||
var returnVal = (_this$__kapsuleInstan = this.__kapsuleInstance)[m].apply(_this$__kapsuleInstan, arguments); | ||
return returnVal === this.__kapsuleInstance ? this // chain based on this class, not the kapsule obj | ||
: returnVal; | ||
}; | ||
}); | ||
@@ -1356,0 +1831,0 @@ return FromKapsule; |
{ | ||
"name": "three-globe", | ||
"version": "1.6.4", | ||
"version": "1.7.0", | ||
"description": "Globe data visualization as a ThreeJS reusable 3D object", | ||
@@ -40,9 +40,13 @@ "unpkg": "dist/three-globe.min.js", | ||
"dependencies": { | ||
"@tweenjs/tween.js": "^17.3.0", | ||
"@tweenjs/tween.js": "^17.4.0", | ||
"accessor-fn": "^1.2.2", | ||
"d3-geo": "^1.11.3", | ||
"d3-hexbin": "^0.2.2", | ||
"d3-scale": "^3.0.0", | ||
"data-joint": "^1.1.0", | ||
"earcut": "^2.1.5", | ||
"frame-ticker": "^1.0.3", | ||
"index-array-by": "^1.2.3", | ||
"kapsule": "^1.10.0", | ||
"three-conic-polygon-geometry": "^1.1.0", | ||
"tinycolor2": "^1.4.1" | ||
@@ -54,14 +58,13 @@ }, | ||
"devDependencies": { | ||
"@babel/core": "^7.4.3", | ||
"@babel/plugin-proposal-class-properties": "^7.4.0", | ||
"@babel/plugin-proposal-object-rest-spread": "^7.4.3", | ||
"@babel/preset-env": "^7.4.3", | ||
"@babel/core": "^7.4.5", | ||
"@babel/plugin-proposal-class-properties": "^7.4.4", | ||
"@babel/plugin-proposal-object-rest-spread": "^7.4.4", | ||
"@babel/preset-env": "^7.4.5", | ||
"rimraf": "^2.6.3", | ||
"rollup": "^1.10.0", | ||
"rollup": "^1.12.4", | ||
"rollup-plugin-babel": "^4.3.2", | ||
"rollup-plugin-commonjs": "^9.3.4", | ||
"rollup-plugin-node-resolve": "^4.2.3", | ||
"rollup-watch": "^4.3.1", | ||
"terser": "^3.17.0" | ||
"rollup-plugin-commonjs": "^10.0.0", | ||
"rollup-plugin-node-resolve": "^5.0.0", | ||
"terser": "^4.0.0" | ||
} | ||
} |
@@ -86,2 +86,26 @@ # ThreeJS Globe Visualization | ||
### Polygons Layer | ||
| Method | Description | Default | | ||
| --- | --- | :--: | | ||
| <b>polygonsData</b>([<i>array</i>]) | Getter/setter for the list of polygon shapes to represent in the polygons map layer. Each polygon is displayed as a shaped cone that extrudes from the surface of the globe. | `[]` | | ||
| <b>polygonGeoJsonGeometry</b>([<i>str</i> or <i>fn</i>]) | Polygon object accessor function or attribute for the GeoJson geometry specification of the polygon's shape. The returned value should have a minimum of two fields: `type` and `coordinates`. Only GeoJson geometries of type `Polygon` or `MultiPolygon` are supported. Other types will be skipped. | `geometry` | | ||
| <b>polygonCapColor</b>([<i>str</i> or <i>fn</i>]) | Polygon object accessor function or attribute for the color of the top surface. | `() => '#ffffaa'` | | ||
| <b>polygonSideColor</b>([<i>str</i> or <i>fn</i>]) | Polygon object accessor function or attribute for the color of the cone sides. | `() => '#ffffaa'` | | ||
| <b>polygonAltitude</b>([<i>num</i>, <i>str</i> or <i>fn</i>]) | Polygon object accessor function, attribute or a numeric constant for the polygon cone's altitude in terms of globe radius units (`0` = 0 altitude (flat polygon), `1` = globe radius). | `0.1` | | ||
| <b>polygonsTransitionDuration</b>([<i>num</i>]) | Getter/setter for duration (ms) of the transition to animate polygon altitude changes. A value of `0` will size the cone immediately to their final altitude. New polygons are animated by rising them from the ground up. | `1000` | | ||
### Hex Bin Layer | ||
| Method | Description | Default | | ||
| --- | --- | :--: | | ||
| <b>hexBinPointsData</b>([<i>array</i>]) | Getter/setter for the list of points to aggregate using the hex bin map layer. Each point is added to an hexagonal prism 3D object that represents all the points within a tesselated portion of the space. | `[]` | | ||
| <b>hexBinPointLat</b>([<i>num</i>, <i>str</i> or <i>fn</i>]) | Point object accessor function, attribute or a numeric constant for the latitude coordinate. | `lat` | | ||
| <b>hexBinPointLng</b>([<i>num</i>, <i>str</i> or <i>fn</i>]) | Point object accessor function, attribute or a numeric constant for the longitude coordinate. | `lng` | | ||
| <b>hexBinPointWeight</b>([<i>num</i>, <i>str</i> or <i>fn</i>]) | Point object accessor function, attribute or a numeric constant for the weight of the point. Weights for points in the same bin are summed and determine the hexagon default altitude. | `1` | | ||
| <b>hexRadius</b>([<i>num</i>]) | The radius of the hexagons that tesselate the globe's surface. The radius is specified in terms of degrees of the globe's great circle perimeter. | `0.25` | | ||
| <b>hexMargin</b>([<i>num</i> or <i>fn</i>]) | The radial margin of each hexagon. Margins above 0 will create gaps between hexagons and serve only a visual purpose, as the data points within the margin will still contribute to the hexagon's data. The margin is specified in terms of fraction of the hexagon's surface diameter. Values below `0` or above `1` are disadvised. This property also supports using a callback method based on the hexagon's aggregated data, following the syntax: `hexMargin(({ points, sumWeight, center: { lat, lng }}) => ...)`. The method should return a numeric constant. | `0.2` | | ||
| <b>hexAltitude</b>([<i>num</i> or <i>fn</i>]) | The altitude of each hexagon, in terms of globe radius units (`0` = 0 altitude (flat hexagon), `1` = globe radius). This property also supports using a callback method based on the hexagon's aggregated data, following the syntax: `hexAltitude(({ points, sumWeight, center: { lat, lng }}) => ...)`. The method should return a numeric constant. | `({ sumWeight }) => sumWeight * 0.01` | | ||
| <b>hexColor</b>([<i>fn</i>]) | Callback function for each hexagon's color. The function should follow the signature: `hexColor(({ points, sumWeight, center: { lat, lng }}) => ...)` and return a color string. | `() => '#ffffaa'` | | ||
| <b>hexBinMerge</b>([<i>boolean</i>]) | Getter/setter for whether to merge all the hexagon meshes into a single ThreeJS object, for improved rendering performance. Visually both options are equivalent, setting this option only affects the internal organization of the ThreeJS objects. | `false` | | ||
| <b>hexTransitionDuration</b>([<i>num</i>]) | Getter/setter for duration (ms) of the transition to animate hexagon changes related to geometry modifications (altitude, radius). A value of `0` will move the objects immediately to their final position. New objects are animated by scaling them from the ground up. Only works if `hexBinMerge=false`. | `1000` | | ||
### Custom Layer | ||
@@ -100,1 +124,6 @@ | Method | Description | Default | | ||
| <b>toGeoCoords</b>({ <i>x</i>, <i>y</i>, <i>z</i>) | Utility method to translate cartesian coordinates to the geographic domain. Given a set of 3D cartesian coordinates `{x, y, z}`, returns the equivalent `{lat, lng, altitude}` spherical coordinates. Altitude is defined in terms of globe radius units. || | ||
## Giving Back | ||
[![paypal](https://www.paypalobjects.com/en_US/i/btn/btn_donate_SM.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=L398E7PKP47E8¤cy_code=USD&source=url) If this project has helped you and you'd like to contribute back, you can always [buy me a ☕](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=L398E7PKP47E8¤cy_code=USD&source=url)! | ||
@@ -16,5 +16,5 @@ import { | ||
import { emptyObject } from './gc'; | ||
import linkKapsule from './kapsule-link.js'; | ||
import { polar2Cartesian, cartesian2Polar } from './coordTranslate'; | ||
import { emptyObject } from './utils/gc'; | ||
import linkKapsule from './utils/kapsule-link.js'; | ||
import { polar2Cartesian, cartesian2Polar } from './utils/coordTranslate'; | ||
@@ -24,2 +24,4 @@ import GlobeLayerKapsule from './layers/globe'; | ||
import ArcsLayerKapsule from './layers/arcs'; | ||
import HexBinLayerKapsule from './layers/hexbin'; | ||
import PolygonsLayerKapsule from './layers/polygons'; | ||
import CustomLayerKapsule from './layers/custom'; | ||
@@ -71,2 +73,26 @@ | ||
const bindHexBinLayer = linkKapsule('hexBinLayer', HexBinLayerKapsule); | ||
const linkedHexBinLayerProps = Object.assign(...[ | ||
'hexBinPointsData', | ||
'hexBinPointLat', | ||
'hexBinPointLng', | ||
'hexBinPointWeight', | ||
'hexRadius', | ||
'hexMargin', | ||
'hexColor', | ||
'hexAltitude', | ||
'hexBinMerge', | ||
'hexTransitionDuration' | ||
].map(p => ({ [p]: bindHexBinLayer.linkProp(p)}))); | ||
const bindPolygonsLayer = linkKapsule('polygonsLayer', PolygonsLayerKapsule); | ||
const linkedPolygonsLayerProps = Object.assign(...[ | ||
'polygonsData', | ||
'polygonGeoJsonGeometry', | ||
'polygonCapColor', | ||
'polygonSideColor', | ||
'polygonAltitude', | ||
'polygonsTransitionDuration' | ||
].map(p => ({ [p]: bindPolygonsLayer.linkProp(p)}))); | ||
const bindCustomLayer = linkKapsule('customLayer', CustomLayerKapsule); | ||
@@ -86,2 +112,4 @@ const linkedCustomLayerProps = Object.assign(...[ | ||
...linkedArcsLayerProps, | ||
...linkedHexBinLayerProps, | ||
...linkedPolygonsLayerProps, | ||
...linkedCustomLayerProps | ||
@@ -100,2 +128,4 @@ }, | ||
arcsLayer: ArcsLayerKapsule(), | ||
hexBinLayer: HexBinLayerKapsule(), | ||
polygonsLayer: PolygonsLayerKapsule(), | ||
customLayer: CustomLayerKapsule(), | ||
@@ -128,2 +158,12 @@ animateIn: false | ||
// add hexbin layer group | ||
const hexBinG = new THREE.Group(); | ||
state.scene.add(hexBinG); | ||
state.hexBinLayer(hexBinG); | ||
// add polygons layer group | ||
const polygonsG = new THREE.Group(); | ||
state.scene.add(polygonsG); | ||
state.polygonsLayer(polygonsG); | ||
// add custom layer group | ||
@@ -130,0 +170,0 @@ const customG = new THREE.Group(); |
@@ -38,6 +38,6 @@ import { | ||
import { threeDigest } from '../digest'; | ||
import { emptyObject } from '../gc'; | ||
import { color2ShaderArr } from '../color-utils'; | ||
import { polar2Cartesian } from '../coordTranslate'; | ||
import threeDigest from '../utils/digest'; | ||
import { emptyObject } from '../utils/gc'; | ||
import { color2ShaderArr } from '../utils/color-utils'; | ||
import { polar2Cartesian } from '../utils/coordTranslate'; | ||
@@ -44,0 +44,0 @@ // |
import Kapsule from 'kapsule'; | ||
import accessorFn from 'accessor-fn'; | ||
import { emptyObject } from '../gc'; | ||
import { emptyObject } from '../utils/gc'; | ||
import { GLOBE_RADIUS } from '../constants'; | ||
import { threeDigest } from '../digest'; | ||
import threeDigest from '../utils/digest'; | ||
@@ -8,0 +8,0 @@ // |
@@ -30,4 +30,4 @@ import { | ||
import drawThreeGeo from '../third-party/ThreeGeoJSON/threeGeoJSON'; | ||
import { emptyObject } from '../gc'; | ||
import drawThreeGeo from '../utils/third-party/ThreeGeoJSON/threeGeoJSON'; | ||
import { emptyObject } from '../utils/gc'; | ||
import { GLOBE_RADIUS } from '../constants'; | ||
@@ -34,0 +34,0 @@ |
@@ -33,6 +33,6 @@ import { | ||
import { colorStr2Hex, colorAlpha } from '../color-utils'; | ||
import { emptyObject } from '../gc'; | ||
import { threeDigest } from '../digest'; | ||
import { polar2Cartesian } from '../coordTranslate'; | ||
import { colorStr2Hex, colorAlpha } from '../utils/color-utils'; | ||
import { emptyObject } from '../utils/gc'; | ||
import threeDigest from '../utils/digest'; | ||
import { polar2Cartesian } from '../utils/coordTranslate'; | ||
import { GLOBE_RADIUS } from '../constants'; | ||
@@ -39,0 +39,0 @@ |
import { Group as ThreeGroup } from 'three'; | ||
import Globe from './globe-kapsule.js'; | ||
import fromKapsule from './kapsule-class.js'; | ||
import fromKapsule from './utils/kapsule-class.js'; | ||
export default fromKapsule(Globe, ThreeGroup, true); |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
4340682
10
41622
38
11029
128
13
+ Addedd3-hexbin@^0.2.2
+ Addeddata-joint@^1.1.0
+ Addedearcut@^2.1.5
+ Added@turf/boolean-point-in-polygon@7.1.0(transitive)
+ Added@turf/helpers@7.1.0(transitive)
+ Added@turf/invariant@7.1.0(transitive)
+ Added@types/geojson@7946.0.15(transitive)
+ Addedd3-array@3.2.4(transitive)
+ Addedd3-delaunay@6.0.4(transitive)
+ Addedd3-geo@3.1.1(transitive)
+ Addedd3-geo-voronoi@2.1.0(transitive)
+ Addedd3-hexbin@0.2.2(transitive)
+ Addedd3-scale@4.0.2(transitive)
+ Addedd3-tricontour@1.0.2(transitive)
+ Addeddata-joint@1.3.1(transitive)
+ Addeddelaunator@5.0.1(transitive)
+ Addedearcut@2.2.43.0.0(transitive)
+ Addedpoint-in-polygon-hao@1.2.3(transitive)
+ Addedrobust-predicates@3.0.2(transitive)
+ Addedthree-conic-polygon-geometry@1.6.6(transitive)
+ Addedtslib@2.8.1(transitive)
Updated@tweenjs/tween.js@^17.4.0