zincjs 2.4.1-beta.3 → 2.4.1-beta.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +86 -70
- package/build/zinc.js +5 -5
- package/build/zinc.js.map +1 -1
- package/package.json +1 -1
- package/src/controls.js +71 -49
- package/src/loaders/GLTFToZincJSLoader.js +4 -1
- package/src/loaders/JSONLoader.js +2 -2
- package/src/loaders/primitivesLoader.js +60 -17
- package/src/minimap.js +48 -13
- package/src/primitives/geometry.js +2 -0
- package/src/primitives/glyph.js +11 -1
- package/src/primitives/glyphset.js +33 -7
- package/src/primitives/label.js +39 -24
- package/src/primitives/lines.js +2 -0
- package/src/primitives/lines2.js +76 -24
- package/src/primitives/lod.js +18 -4
- package/src/primitives/marker.js +6 -1
- package/src/primitives/markerCluster.js +5 -1
- package/src/primitives/pointset.js +33 -28
- package/src/primitives/texturePrimitive.js +12 -0
- package/src/primitives/textureSlides.js +24 -3
- package/src/primitives/textureVolume.js +2 -0
- package/src/primitives/tubeLines.js +4 -0
- package/src/primitives/zincObject.js +80 -10
- package/src/region.js +92 -37
- package/src/renderRequests.js +20 -0
- package/src/renderer.js +81 -9
- package/src/scene.js +133 -23
- package/src/sceneExporter.js +4 -0
- package/src/sceneLoader.js +114 -18
- package/src/textSprite.js +211 -0
- package/src/texture/texture.js +10 -0
- package/src/texture/textureArray.js +9 -0
- package/src/utilities.js +147 -47
package/package.json
CHANGED
package/src/controls.js
CHANGED
|
@@ -259,6 +259,7 @@ const CameraControls = function ( object, domElement, renderer, scene ) {
|
|
|
259
259
|
}
|
|
260
260
|
|
|
261
261
|
this.onResize = () => {
|
|
262
|
+
hasUpdated = true;
|
|
262
263
|
if (rect)
|
|
263
264
|
rect = undefined;
|
|
264
265
|
if (ndcControl)
|
|
@@ -355,6 +356,7 @@ const CameraControls = function ( object, domElement, renderer, scene ) {
|
|
|
355
356
|
}
|
|
356
357
|
|
|
357
358
|
const translateViewport = translation => {
|
|
359
|
+
hasUpdated = true;
|
|
358
360
|
_tempEye.copy(this.cameraObject.position).add(translation);
|
|
359
361
|
if (checkTravelDistance()) {
|
|
360
362
|
this.cameraObject.target.add(translation);
|
|
@@ -486,14 +488,17 @@ const CameraControls = function ( object, domElement, renderer, scene ) {
|
|
|
486
488
|
}
|
|
487
489
|
|
|
488
490
|
const onDocumentTouchEnd = event => {
|
|
489
|
-
const
|
|
491
|
+
const previousState = this._state;
|
|
490
492
|
this.touchZoomDistanceStart = this.touchZoomDistanceEnd = 0;
|
|
491
493
|
this.targetTouchId = -1;
|
|
492
494
|
this._state = STATE.NONE;
|
|
493
|
-
|
|
495
|
+
//A single finger tap, the lifted touch is in changedTouches
|
|
496
|
+
if (previousState === STATE.TOUCH_ROTATE && event.touches.length === 0 &&
|
|
497
|
+
event.changedTouches && event.changedTouches.length === 1 && rect) {
|
|
494
498
|
if (zincRayCaster !== undefined) {
|
|
495
|
-
|
|
496
|
-
|
|
499
|
+
const touch = event.changedTouches[0];
|
|
500
|
+
if (this.pointer_x_start==(touch.clientX- rect.left) && this.pointer_y_start==(touch.clientY- rect.top)) {
|
|
501
|
+
zincRayCaster.pick(this, touch.clientX, touch.clientY, this.renderer);
|
|
497
502
|
}
|
|
498
503
|
}
|
|
499
504
|
}
|
|
@@ -663,6 +668,7 @@ const CameraControls = function ( object, domElement, renderer, scene ) {
|
|
|
663
668
|
* @param {Number} Angle - Specify how much the camera shoudl rotate by.
|
|
664
669
|
*/
|
|
665
670
|
this.rotateAboutLookAtpoint = (axis, angle) => {
|
|
671
|
+
hasUpdated = true;
|
|
666
672
|
const returned_values = this.getVectorsFromRotateAboutLookAtPoints(axis, angle);
|
|
667
673
|
this.cameraObject.position.copy(returned_values.position);
|
|
668
674
|
this.updateDirectionalLight();
|
|
@@ -743,7 +749,7 @@ const CameraControls = function ( object, domElement, renderer, scene ) {
|
|
|
743
749
|
if (typeof this.cameraObject !== "undefined")
|
|
744
750
|
{
|
|
745
751
|
const height = rect.height;
|
|
746
|
-
const a = this.cameraObject.position
|
|
752
|
+
const a = _v.copy(this.cameraObject.position);
|
|
747
753
|
a.sub(this.cameraObject.target);
|
|
748
754
|
const dist = a.length();
|
|
749
755
|
const dy = 1.5 * delta_y/height;
|
|
@@ -786,6 +792,7 @@ const CameraControls = function ( object, domElement, renderer, scene ) {
|
|
|
786
792
|
* Force an update to the position of the directional light.
|
|
787
793
|
*/
|
|
788
794
|
this.updateDirectionalLight = () => {
|
|
795
|
+
hasUpdated = true;
|
|
789
796
|
if (this.directionalLight != 0) {
|
|
790
797
|
this.directionalLight.position.set(this.cameraObject.position.x,
|
|
791
798
|
this.cameraObject.position.y,
|
|
@@ -820,6 +827,7 @@ const CameraControls = function ( object, domElement, renderer, scene ) {
|
|
|
820
827
|
*/
|
|
821
828
|
this.disable = function () {
|
|
822
829
|
enabled = false;
|
|
830
|
+
this._state = STATE.NONE;
|
|
823
831
|
if (this.domElement && this.domElement.removeEventListener) {
|
|
824
832
|
this.domElement.removeEventListener( 'mousedown', onDocumentMouseDown, false );
|
|
825
833
|
this.domElement.removeEventListener( 'mousemove', onDocumentMouseMove, false );
|
|
@@ -984,6 +992,7 @@ const CameraControls = function ( object, domElement, renderer, scene ) {
|
|
|
984
992
|
* @param {Number} targetTimeFrame - bottom frame, top frame and the proportion.
|
|
985
993
|
*/
|
|
986
994
|
this.setCurrentTimeFrame = targetTimeFrame => {
|
|
995
|
+
hasUpdated = true;
|
|
987
996
|
if (numberOfCameraPoint > 2) {
|
|
988
997
|
inbuildTime = duration * targetTimeFrame / (numberOfCameraPoint - 1);
|
|
989
998
|
if (inbuildTime < 0.0)
|
|
@@ -1006,19 +1015,19 @@ const CameraControls = function ( object, domElement, renderer, scene ) {
|
|
|
1006
1015
|
const bottom_frame = time_frame[0];
|
|
1007
1016
|
const top_frame = time_frame[1];
|
|
1008
1017
|
const proportion = time_frame[2];
|
|
1009
|
-
const
|
|
1010
|
-
const
|
|
1011
|
-
const
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
this.cameraObject.
|
|
1016
|
-
this.cameraObject.target.set(top_pos[0], top_pos[1], top_pos[2]);
|
|
1018
|
+
const bottom = bottom_frame * 3;
|
|
1019
|
+
const top = top_frame * 3;
|
|
1020
|
+
const x = proportion * cameraPath[bottom] + (1.0 - proportion) * cameraPath[top];
|
|
1021
|
+
const y = proportion * cameraPath[bottom + 1] + (1.0 - proportion) * cameraPath[top + 1];
|
|
1022
|
+
const z = proportion * cameraPath[bottom + 2] + (1.0 - proportion) * cameraPath[top + 2];
|
|
1023
|
+
this.cameraObject.position.set(x, y, z);
|
|
1024
|
+
this.cameraObject.target.set(cameraPath[top], cameraPath[top + 1], cameraPath[top + 2]);
|
|
1017
1025
|
if (deviceOrientationControl)
|
|
1018
1026
|
this.cameraObject.lookAt( this.cameraObject.target );
|
|
1019
1027
|
if (updateLightWithPathFlag) {
|
|
1020
|
-
this.directionalLight.position.set(
|
|
1021
|
-
this.directionalLight.target.position.set(
|
|
1028
|
+
this.directionalLight.position.set(x, y, z);
|
|
1029
|
+
this.directionalLight.target.position.set(cameraPath[top], cameraPath[top + 1],
|
|
1030
|
+
cameraPath[top + 2]);
|
|
1022
1031
|
}
|
|
1023
1032
|
}
|
|
1024
1033
|
}
|
|
@@ -1028,6 +1037,7 @@ const CameraControls = function ( object, domElement, renderer, scene ) {
|
|
|
1028
1037
|
* Force recalculation of the current path.
|
|
1029
1038
|
*/
|
|
1030
1039
|
this.calculatePathNow = () => {
|
|
1040
|
+
hasUpdated = true;
|
|
1031
1041
|
updatePath(0.0);
|
|
1032
1042
|
}
|
|
1033
1043
|
|
|
@@ -1065,14 +1075,14 @@ const CameraControls = function ( object, domElement, renderer, scene ) {
|
|
|
1065
1075
|
} else if (currentMode === MODE.SMOOTH_CAMERA_TRANSITION && smoothCameraTransitionObject) {
|
|
1066
1076
|
smoothCameraTransitionObject.update(delta);
|
|
1067
1077
|
if (smoothCameraTransitionObject.isTransitionCompleted()) {
|
|
1068
|
-
smoothCameraTransitionObject
|
|
1078
|
+
smoothCameraTransitionObject = undefined;
|
|
1069
1079
|
currentMode = MODE.DEFAULT;
|
|
1070
1080
|
}
|
|
1071
1081
|
controlEnabled = false;
|
|
1072
|
-
} else if (currentMode === MODE.
|
|
1082
|
+
} else if (currentMode === MODE.ROTATE_TRANSITION && rotateCameraTransitionObject) {
|
|
1073
1083
|
rotateCameraTransitionObject.update(delta);
|
|
1074
1084
|
if (rotateCameraTransitionObject.isTransitionCompleted()) {
|
|
1075
|
-
rotateCameraTransitionObject
|
|
1085
|
+
rotateCameraTransitionObject = undefined;
|
|
1076
1086
|
currentMode = MODE.DEFAULT;
|
|
1077
1087
|
}
|
|
1078
1088
|
controlEnabled = false;
|
|
@@ -1183,6 +1193,7 @@ const CameraControls = function ( object, domElement, renderer, scene ) {
|
|
|
1183
1193
|
* Reset the viewport settings to the one provided by default viewport.
|
|
1184
1194
|
*/
|
|
1185
1195
|
this.resetView = () => {
|
|
1196
|
+
hasUpdated = true;
|
|
1186
1197
|
const viewport = viewports[defaultViewport];
|
|
1187
1198
|
this.cameraObject.near = viewport.nearPlane;
|
|
1188
1199
|
this.cameraObject.far = viewport.farPlane;
|
|
@@ -1354,7 +1365,7 @@ const CameraControls = function ( object, domElement, renderer, scene ) {
|
|
|
1354
1365
|
if (smoothCameraTransitionObject)
|
|
1355
1366
|
currentMode = MODE.SMOOTH_CAMERA_TRANSITION;
|
|
1356
1367
|
if (rotateCameraTransitionObject)
|
|
1357
|
-
currentMode = MODE.
|
|
1368
|
+
currentMode = MODE.ROTATE_TRANSITION;
|
|
1358
1369
|
}
|
|
1359
1370
|
|
|
1360
1371
|
/**
|
|
@@ -1379,7 +1390,7 @@ const CameraControls = function ( object, domElement, renderer, scene ) {
|
|
|
1379
1390
|
*/
|
|
1380
1391
|
this.isTransitioningCamera = () => {
|
|
1381
1392
|
return (currentMode === MODE.SMOOTH_CAMERA_TRANSITION ||
|
|
1382
|
-
currentMode === MODE.
|
|
1393
|
+
currentMode === MODE.ROTATE_TRANSITION);
|
|
1383
1394
|
}
|
|
1384
1395
|
|
|
1385
1396
|
/**
|
|
@@ -1488,10 +1499,8 @@ const CameraControls = function ( object, domElement, renderer, scene ) {
|
|
|
1488
1499
|
const SmoothCameraTransition = function(startingViewport, endingViewport, targetCameraIn, durationIn) {
|
|
1489
1500
|
const startingEyePosition = startingViewport.eyePosition;
|
|
1490
1501
|
const startingTargetPosition = startingViewport.targetPosition;
|
|
1491
|
-
const startingUp = startingViewport.upVector;
|
|
1492
1502
|
const endingEyePosition = endingViewport.eyePosition;
|
|
1493
1503
|
const endingTargetPosition = endingViewport.targetPosition;
|
|
1494
|
-
const endingUp = endingViewport.upVector;
|
|
1495
1504
|
const targetCamera = targetCameraIn;
|
|
1496
1505
|
let duration = durationIn;
|
|
1497
1506
|
let inbuildTime = 0;
|
|
@@ -1516,17 +1525,15 @@ const SmoothCameraTransition = function(startingViewport, endingViewport, target
|
|
|
1516
1525
|
|
|
1517
1526
|
const updateCameraSettings = () => {
|
|
1518
1527
|
const ratio = inbuildTime / duration;
|
|
1519
|
-
const
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
targetCamera.cameraObject.position.set( eyePosition[0], eyePosition[1], eyePosition[2]);
|
|
1529
|
-
targetCamera.cameraObject.target.set( targetPosition[0], targetPosition[1], targetPosition[2] );
|
|
1528
|
+
const start = 1.0 - ratio;
|
|
1529
|
+
targetCamera.cameraObject.position.set(
|
|
1530
|
+
startingEyePosition[0] * start + endingEyePosition[0] * ratio,
|
|
1531
|
+
startingEyePosition[1] * start + endingEyePosition[1] * ratio,
|
|
1532
|
+
startingEyePosition[2] * start + endingEyePosition[2] * ratio);
|
|
1533
|
+
targetCamera.cameraObject.target.set(
|
|
1534
|
+
startingTargetPosition[0] * start + endingTargetPosition[0] * ratio,
|
|
1535
|
+
startingTargetPosition[1] * start + endingTargetPosition[1] * ratio,
|
|
1536
|
+
startingTargetPosition[2] * start + endingTargetPosition[2] * ratio);
|
|
1530
1537
|
};
|
|
1531
1538
|
|
|
1532
1539
|
this.update = delta => {
|
|
@@ -1609,6 +1616,7 @@ const RayCaster = function (sceneIn, hostSceneIn, callbackFunctionIn, hoverCallb
|
|
|
1609
1616
|
let timeDiff = 0;
|
|
1610
1617
|
let pickedObjects = new Array();
|
|
1611
1618
|
let lastPosition = { zincCamera: undefined, x: -1 ,y: -1};
|
|
1619
|
+
let hoverFrameRequested = false;
|
|
1612
1620
|
let pickableObjects = undefined;
|
|
1613
1621
|
|
|
1614
1622
|
this.enable = () => {
|
|
@@ -1621,8 +1629,8 @@ const RayCaster = function (sceneIn, hostSceneIn, callbackFunctionIn, hoverCallb
|
|
|
1621
1629
|
|
|
1622
1630
|
this.getIntersectsObject = (zincCamera) => {
|
|
1623
1631
|
if (hostScene !== scene) {
|
|
1624
|
-
|
|
1625
|
-
|
|
1632
|
+
//Only the world matrices need to be up to date for raycasting
|
|
1633
|
+
scene.getThreeJSScene().updateMatrixWorld();
|
|
1626
1634
|
}
|
|
1627
1635
|
let objects = pickableObjects ? pickableObjects : scene.getPickableThreeJSObjects();
|
|
1628
1636
|
//Reset pickedObjects array
|
|
@@ -1669,6 +1677,8 @@ const RayCaster = function (sceneIn, hostSceneIn, callbackFunctionIn, hoverCallb
|
|
|
1669
1677
|
}
|
|
1670
1678
|
}
|
|
1671
1679
|
callbackFunction(pickedObjects, x, y);
|
|
1680
|
+
//The callback may have changed what is displayed
|
|
1681
|
+
hostScene?.invalidate?.();
|
|
1672
1682
|
}
|
|
1673
1683
|
}
|
|
1674
1684
|
|
|
@@ -1685,24 +1695,36 @@ const RayCaster = function (sceneIn, hostSceneIn, callbackFunctionIn, hoverCallb
|
|
|
1685
1695
|
lastHoveredEmpty = false;
|
|
1686
1696
|
}
|
|
1687
1697
|
hoverCallbackFunction(pickedObjects, x, y);
|
|
1698
|
+
//The callback may have changed what is displayed
|
|
1699
|
+
hostScene?.invalidate?.();
|
|
1688
1700
|
}
|
|
1689
1701
|
}
|
|
1690
1702
|
|
|
1691
1703
|
this.move = (zincCamera, x, y) => {
|
|
1692
1704
|
if (enabled && renderer && scene && zincCamera && hoverCallbackFunction) {
|
|
1705
|
+
lastPosition.zincCamera = zincCamera;
|
|
1706
|
+
lastPosition.x = x;
|
|
1707
|
+
lastPosition.y = y;
|
|
1693
1708
|
if (scene.displayMarkers) {
|
|
1694
|
-
|
|
1709
|
+
//Markers need responsive hovering, but there is no need to
|
|
1710
|
+
//raycast more than once per frame.
|
|
1711
|
+
if (typeof requestAnimationFrame !== 'function') {
|
|
1712
|
+
hovered(zincCamera, x, y);
|
|
1713
|
+
} else if (!hoverFrameRequested) {
|
|
1714
|
+
hoverFrameRequested = true;
|
|
1715
|
+
requestAnimationFrame(() => {
|
|
1716
|
+
hoverFrameRequested = false;
|
|
1717
|
+
hovered(lastPosition.zincCamera, lastPosition.x, lastPosition.y);
|
|
1718
|
+
});
|
|
1719
|
+
}
|
|
1695
1720
|
} else {
|
|
1696
|
-
lastPosition.zincCamera = zincCamera;
|
|
1697
|
-
lastPosition.x = x;
|
|
1698
|
-
lastPosition.y = y;
|
|
1699
1721
|
if (!awaiting) {
|
|
1700
1722
|
timeDiff = lastHoveredDate ? Date.now() - lastHoveredDate.getTime() : 250;
|
|
1701
1723
|
if (timeDiff >= 250) {
|
|
1702
1724
|
hovered(zincCamera, x, y);
|
|
1703
1725
|
} else {
|
|
1704
1726
|
awaiting = true;
|
|
1705
|
-
setTimeout(awaitMove(lastPosition), timeDiff);
|
|
1727
|
+
setTimeout(awaitMove(lastPosition), 250 - timeDiff);
|
|
1706
1728
|
}
|
|
1707
1729
|
}
|
|
1708
1730
|
}
|
|
@@ -1825,7 +1847,7 @@ Object.assign( StereoCameraZoomFixed.prototype, {
|
|
|
1825
1847
|
const projectionMatrix = camera.projectionMatrix.clone();
|
|
1826
1848
|
const eyeSep = 0.064 / 2;
|
|
1827
1849
|
const eyeSepOnProjection = eyeSep * near / focus;
|
|
1828
|
-
const ymax = near * Math.tan( THREE.
|
|
1850
|
+
const ymax = near * Math.tan( THREE.MathUtils.DEG2RAD * fov * 0.5 ) / camera.zoom;
|
|
1829
1851
|
let xmin, xmax;
|
|
1830
1852
|
|
|
1831
1853
|
// translate xOffset
|
|
@@ -1953,16 +1975,16 @@ const ModifiedDeviceOrientationControls = function ( object ) {
|
|
|
1953
1975
|
|
|
1954
1976
|
const q1 = new THREE.Quaternion( - Math.sqrt( 0.5 ), 0, 0, Math.sqrt( 0.5 ) ); // - PI/2 around the x-axis
|
|
1955
1977
|
|
|
1956
|
-
|
|
1978
|
+
const vector = new THREE.Vector3();
|
|
1979
|
+
|
|
1980
|
+
const quaternion = new THREE.Quaternion();
|
|
1957
1981
|
|
|
1958
|
-
|
|
1982
|
+
return (cameraObject, alpha, beta, gamma, orient) => {
|
|
1959
1983
|
|
|
1960
1984
|
vector.subVectors(cameraObject.target, cameraObject.position);
|
|
1961
1985
|
|
|
1962
1986
|
euler.set( beta, alpha, - gamma, 'YXZ' ); // 'ZXY' for the device, but 'YXZ' for us
|
|
1963
1987
|
|
|
1964
|
-
const quaternion = new THREE.Quaternion();
|
|
1965
|
-
|
|
1966
1988
|
quaternion.setFromEuler( euler ); // orient the device
|
|
1967
1989
|
|
|
1968
1990
|
quaternion.multiply( q1 ); // camera looks out the back of the device, not the top
|
|
@@ -2003,10 +2025,10 @@ const ModifiedDeviceOrientationControls = function ( object ) {
|
|
|
2003
2025
|
|
|
2004
2026
|
if ( scope.enabled === false ) return;
|
|
2005
2027
|
|
|
2006
|
-
const alpha = scope.deviceOrientation.alpha ? THREE.
|
|
2007
|
-
const beta = scope.deviceOrientation.beta ? THREE.
|
|
2008
|
-
const gamma = scope.deviceOrientation.gamma ? THREE.
|
|
2009
|
-
const orient = scope.screenOrientation ? THREE.
|
|
2028
|
+
const alpha = scope.deviceOrientation.alpha ? THREE.MathUtils.degToRad( scope.deviceOrientation.alpha ) : 0; // Z
|
|
2029
|
+
const beta = scope.deviceOrientation.beta ? THREE.MathUtils.degToRad( scope.deviceOrientation.beta ) : 0; // X'
|
|
2030
|
+
const gamma = scope.deviceOrientation.gamma ? THREE.MathUtils.degToRad( scope.deviceOrientation.gamma ) : 0; // Y''
|
|
2031
|
+
const orient = scope.screenOrientation ? THREE.MathUtils.degToRad( scope.screenOrientation ) : 0; // O
|
|
2010
2032
|
|
|
2011
2033
|
setObjectQuaternion( scope.object, alpha, beta, gamma, orient );
|
|
2012
2034
|
|
|
@@ -123,13 +123,16 @@ const GLTFToZincJSLoader = function () {
|
|
|
123
123
|
* @param {String} url - URL to the GLTF file
|
|
124
124
|
* @param {Function} finishCallback - Callback function which will be called
|
|
125
125
|
* once the glyphset is succssfully load in.
|
|
126
|
+
* @param {Function} isCancelled - Optional function returning true if this
|
|
127
|
+
* load has been cancelled, the loaded content will be discarded.
|
|
126
128
|
*/
|
|
127
|
-
this.load = (scene, region, url, finishCallback, allCompletedCallback, options) => {
|
|
129
|
+
this.load = (scene, region, url, finishCallback, allCompletedCallback, options, isCancelled) => {
|
|
128
130
|
const path = url.substring(0, url.lastIndexOf("/") + 1);
|
|
129
131
|
const filename = url.substring(url.lastIndexOf("/") + 1, url.length);
|
|
130
132
|
const loader = new GLTFLoader().setPath(path);
|
|
131
133
|
|
|
132
134
|
loader.load( filename, function ( gltf ) {
|
|
135
|
+
if (isCancelled && isCancelled()) return;
|
|
133
136
|
console.log(gltf)
|
|
134
137
|
_this.parseGLTFObjects(gltf.scene, region, 0, finishCallback);
|
|
135
138
|
_this.setCamera(scene);
|
|
@@ -302,7 +302,7 @@ Object.assign( JSONLoader.prototype, {
|
|
|
302
302
|
|
|
303
303
|
}
|
|
304
304
|
|
|
305
|
-
const attribute = new
|
|
305
|
+
const attribute = new BufferAttribute( array, 3 );
|
|
306
306
|
attribute.name = json.morphTargets[ i ].name;
|
|
307
307
|
morphPositions.push( attribute );
|
|
308
308
|
|
|
@@ -321,7 +321,7 @@ Object.assign( JSONLoader.prototype, {
|
|
|
321
321
|
const srcNormals = json.morphNormals[ i ].normals;
|
|
322
322
|
const array = Float32Array.from( srcNormals );
|
|
323
323
|
|
|
324
|
-
const attribute = new
|
|
324
|
+
const attribute = new BufferAttribute( array, 3 );
|
|
325
325
|
attribute.name = morphPositions[ i ].name;
|
|
326
326
|
morphNormals[ i ] = attribute;
|
|
327
327
|
|
|
@@ -6,8 +6,11 @@ const FileLoader = THREE.FileLoader;
|
|
|
6
6
|
const mergeGlyphData = (glyphData) => {
|
|
7
7
|
const merge = (glyphData1, glyphData2) => {
|
|
8
8
|
glyphData1.metadata.number_of_vertices += glyphData2.metadata.number_of_vertices;
|
|
9
|
-
if ('labels' in glyphData1) {
|
|
10
|
-
|
|
9
|
+
if ('labels' in glyphData1 && glyphData2.labels) {
|
|
10
|
+
const labels = glyphData2.labels;
|
|
11
|
+
for (let i = 0; i < labels.length; i++) {
|
|
12
|
+
glyphData1.labels.push(labels[i]);
|
|
13
|
+
}
|
|
11
14
|
}
|
|
12
15
|
const fields = ['axis1', 'axis2', 'axis3', 'colors', 'positions', 'scale'];
|
|
13
16
|
fields.forEach(field => {
|
|
@@ -42,12 +45,13 @@ const mergeGeometries = (geometries) => {
|
|
|
42
45
|
return undefined;
|
|
43
46
|
}
|
|
44
47
|
|
|
45
|
-
const IndexedSourcesHandler = function(urlIn, crossOrigin, onDownloadedCallback) {
|
|
48
|
+
const IndexedSourcesHandler = function(urlIn, crossOrigin, onDownloadedCallback, onErrorCallback) {
|
|
46
49
|
const fileLoader = new FileLoader();
|
|
47
50
|
const jsonLoader = new JSONLoader();
|
|
48
51
|
fileLoader.crossOrigin = crossOrigin;
|
|
49
52
|
const url = urlIn;
|
|
50
53
|
const onDownloaded = onDownloadedCallback;
|
|
54
|
+
const onDownloadError = onErrorCallback;
|
|
51
55
|
let data = undefined;
|
|
52
56
|
let downloading = false;
|
|
53
57
|
let finished = false;
|
|
@@ -100,6 +104,9 @@ const IndexedSourcesHandler = function(urlIn, crossOrigin, onDownloadedCallback)
|
|
|
100
104
|
items.forEach((item) => {
|
|
101
105
|
processItemError(item);
|
|
102
106
|
});
|
|
107
|
+
if (onDownloadError) {
|
|
108
|
+
onDownloadError(xhr);
|
|
109
|
+
}
|
|
103
110
|
}
|
|
104
111
|
}
|
|
105
112
|
|
|
@@ -124,7 +131,7 @@ const IndexedSourcesHandler = function(urlIn, crossOrigin, onDownloadedCallback)
|
|
|
124
131
|
if (data) {
|
|
125
132
|
processItemDownloaded(item);
|
|
126
133
|
} else {
|
|
127
|
-
processItemError(
|
|
134
|
+
processItemError(item);
|
|
128
135
|
}
|
|
129
136
|
} else if (downloading) {
|
|
130
137
|
//quene it up
|
|
@@ -132,32 +139,62 @@ const IndexedSourcesHandler = function(urlIn, crossOrigin, onDownloadedCallback)
|
|
|
132
139
|
} else {
|
|
133
140
|
items.push(item);
|
|
134
141
|
downloading = true;
|
|
135
|
-
fileLoader.load(url, onDownloaded, progressHandling, errorHandling);
|
|
142
|
+
fileLoader.load(url, onDownloaded, progressHandling(), errorHandling());
|
|
136
143
|
}
|
|
137
144
|
}
|
|
138
145
|
}
|
|
139
146
|
|
|
140
|
-
const MultiSourcesHandler = function(numberIn, onLoadCallback, options) {
|
|
147
|
+
const MultiSourcesHandler = function(numberIn, onLoadCallback, onErrorCallback, options) {
|
|
141
148
|
const allData = [];
|
|
142
149
|
const number = numberIn;
|
|
143
150
|
const onLoad = onLoadCallback;
|
|
151
|
+
const onError = onErrorCallback;
|
|
144
152
|
let totalDownloaded = 0;
|
|
145
|
-
|
|
153
|
+
let failure = undefined;
|
|
154
|
+
const isGlyphData = options?.isGlyphsets;
|
|
155
|
+
|
|
156
|
+
//Release whatever was downloaded successfully and report the first failure
|
|
157
|
+
const reportFailure = () => {
|
|
158
|
+
if (!isGlyphData) {
|
|
159
|
+
allData.forEach((data) => {
|
|
160
|
+
if (data) {
|
|
161
|
+
data[0]?.dispose?.();
|
|
162
|
+
data[1]?.forEach((material) => material.dispose());
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
if (onError) {
|
|
167
|
+
onError(...failure);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
this.itemFailed = (order, args) => {
|
|
172
|
+
if (!failure) {
|
|
173
|
+
failure = args;
|
|
174
|
+
}
|
|
175
|
+
totalDownloaded++;
|
|
176
|
+
if (totalDownloaded == number) {
|
|
177
|
+
reportFailure();
|
|
178
|
+
}
|
|
179
|
+
}
|
|
146
180
|
|
|
147
181
|
this.itemDownloaded = (order, args) => {
|
|
148
182
|
allData[order]= args;
|
|
149
183
|
totalDownloaded++;
|
|
150
184
|
if (totalDownloaded == number) {
|
|
151
|
-
if (
|
|
185
|
+
if (failure) {
|
|
186
|
+
reportFailure();
|
|
187
|
+
} else if (allData.length > 0) {
|
|
152
188
|
//Assume when item length is one then it is a glyphset otherwise geometry
|
|
153
189
|
if (!isGlyphData) {
|
|
154
190
|
const materials = allData[0][1];
|
|
155
191
|
const geometries = allData.map((data) => data[0]);
|
|
156
192
|
//All geometries will be merged into the first one
|
|
157
193
|
const geometry = mergeGeometries(geometries);
|
|
194
|
+
//mergeGeometries has disposed the source geometries,
|
|
195
|
+
//only the first set of materials is kept
|
|
158
196
|
for (let i = 1; i < number; i++) {
|
|
159
|
-
allData[
|
|
160
|
-
allData[order][1].forEach((material) => material.dispose());
|
|
197
|
+
allData[i][1]?.forEach((material) => material.dispose());
|
|
161
198
|
}
|
|
162
199
|
onLoad(geometry, materials);
|
|
163
200
|
} else {
|
|
@@ -186,7 +223,7 @@ const PrimitivesLoader = function () {
|
|
|
186
223
|
//Load the first file then the rest will be handled separately
|
|
187
224
|
const loadFromMultipleSources = (urls, onLoad, onProgress, onError, options) => {
|
|
188
225
|
const number = urls.length;
|
|
189
|
-
const msHandler = new MultiSourcesHandler(number, onLoad, options);
|
|
226
|
+
const msHandler = new MultiSourcesHandler(number, onLoad, onError, options);
|
|
190
227
|
//The order here will give us hint on the sequence on merging the primitives
|
|
191
228
|
let order = 0;
|
|
192
229
|
urls.forEach((url) => {
|
|
@@ -204,8 +241,10 @@ const PrimitivesLoader = function () {
|
|
|
204
241
|
if (!indexedLoader) {
|
|
205
242
|
if (MAX_DOWNLOAD > concurrentDownloads) {
|
|
206
243
|
const onLoadCallback = new onFinally(undefined, this, newOptions);
|
|
244
|
+
const onErrorCallback = new onFinally(undefined, this, {});
|
|
207
245
|
++concurrentDownloads;
|
|
208
|
-
indexedLoader = new IndexedSourcesHandler(url, this.crossOrigin, onLoadCallback
|
|
246
|
+
indexedLoader = new IndexedSourcesHandler(url, this.crossOrigin, onLoadCallback,
|
|
247
|
+
onErrorCallback);
|
|
209
248
|
indexedLoaders[url] = indexedLoader;
|
|
210
249
|
} else {
|
|
211
250
|
waitingList.push({
|
|
@@ -231,8 +270,8 @@ const PrimitivesLoader = function () {
|
|
|
231
270
|
if (MAX_DOWNLOAD > concurrentDownloads) {
|
|
232
271
|
++concurrentDownloads;
|
|
233
272
|
const onLoadCallback = new onFinally(onLoad, this, options);
|
|
234
|
-
const onErrorCallback = new onFinally(onError, this, options);
|
|
235
|
-
if (!options
|
|
273
|
+
const onErrorCallback = new onFinally(onError, this, options, true);
|
|
274
|
+
if (!options?.isGlyphsets) {
|
|
236
275
|
jsonloader.crossOrigin = this.crossOrigin;
|
|
237
276
|
jsonloader.load(url, onLoadCallback, onProgress, onErrorCallback);
|
|
238
277
|
} else {
|
|
@@ -279,11 +318,15 @@ const PrimitivesLoader = function () {
|
|
|
279
318
|
}
|
|
280
319
|
}
|
|
281
320
|
|
|
282
|
-
const onFinally = function(callback, loader, options) {
|
|
321
|
+
const onFinally = function(callback, loader, options, isError = false) {
|
|
283
322
|
return (...args) => {
|
|
284
323
|
--concurrentDownloads;
|
|
285
324
|
if (options?.msHandler) {
|
|
286
|
-
|
|
325
|
+
if (isError) {
|
|
326
|
+
options.msHandler.itemFailed(options.order, args);
|
|
327
|
+
} else {
|
|
328
|
+
options.msHandler.itemDownloaded(options.order, args);
|
|
329
|
+
}
|
|
287
330
|
} else if (options?.isHandler) {
|
|
288
331
|
options.isHandler.downloadCompleted(args);
|
|
289
332
|
} else {
|
|
@@ -297,7 +340,7 @@ const PrimitivesLoader = function () {
|
|
|
297
340
|
}
|
|
298
341
|
|
|
299
342
|
this.parse = data => {
|
|
300
|
-
return
|
|
343
|
+
return jsonloader.parse(data);
|
|
301
344
|
}
|
|
302
345
|
|
|
303
346
|
}
|
package/src/minimap.js
CHANGED
|
@@ -33,12 +33,34 @@ const Minimap = function (sceneIn) {
|
|
|
33
33
|
this.mask = new THREE.Mesh( geometry, material );
|
|
34
34
|
let _box = new THREE.Box3();
|
|
35
35
|
let _center = new THREE.Vector3();
|
|
36
|
+
const _coord = new THREE.Vector3();
|
|
37
|
+
const _lookAt = new THREE.Vector3();
|
|
38
|
+
const _target = new THREE.Vector3();
|
|
39
|
+
const _corners = [new THREE.Vector3(), new THREE.Vector3(),
|
|
40
|
+
new THREE.Vector3(), new THREE.Vector3()];
|
|
41
|
+
const _boundaryVertices = [_corners[0], _corners[1], _corners[2],
|
|
42
|
+
_corners[2], _corners[3], _corners[0]];
|
|
43
|
+
//State the minimap was last computed from, it only needs to be updated
|
|
44
|
+
//when the scene or the main camera changes.
|
|
45
|
+
const _lastBoundingBox = new THREE.Box3();
|
|
46
|
+
const _lastMatrixWorld = new THREE.Matrix4();
|
|
47
|
+
const _lastProjectionMatrix = new THREE.Matrix4();
|
|
48
|
+
let _lastNear = undefined;
|
|
49
|
+
let _cameraUpdated = false;
|
|
50
|
+
//Matrix4.equals treats NaN as different, e.g. with a zero sized canvas
|
|
51
|
+
const matrixEquals = (a, b) => {
|
|
52
|
+
for (let i = 0; i < 16; i++) {
|
|
53
|
+
if (!Object.is(a.elements[i], b.elements[i]))
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
return true;
|
|
57
|
+
}
|
|
36
58
|
|
|
37
59
|
this.getDiffFromNormalised = (x, y) => {
|
|
38
60
|
_box.setFromBufferAttribute(positionAttributes).getCenter(_center);
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
return
|
|
61
|
+
_coord.copy(_center).project(this.camera);
|
|
62
|
+
//Returns a new vector, the caller may keep it
|
|
63
|
+
return new THREE.Vector3(x, y, _coord.z).unproject(this.camera).sub(_center);
|
|
42
64
|
}
|
|
43
65
|
|
|
44
66
|
let setCurrentCameraSettings = (diameter, newViewport) => {
|
|
@@ -53,28 +75,41 @@ const Minimap = function (sceneIn) {
|
|
|
53
75
|
this.camera.up.set(newViewport.upVector[0], newViewport.upVector[1],
|
|
54
76
|
newViewport.upVector[2]);
|
|
55
77
|
if (newViewport.targetPosition)
|
|
56
|
-
this.camera.lookAt(
|
|
78
|
+
this.camera.lookAt(_lookAt.set(newViewport.targetPosition[0],
|
|
57
79
|
newViewport.targetPosition[1], newViewport.targetPosition[2]));
|
|
58
80
|
this.camera.zoom = 1 / diameter;
|
|
59
81
|
this.camera.updateProjectionMatrix();
|
|
60
82
|
}
|
|
61
83
|
|
|
62
84
|
this.getBoundary = () => {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
copyVector3sArray(positionAttributes, array);
|
|
85
|
+
const camera = targetScene.camera;
|
|
86
|
+
_target.copy(camera.target).project(camera);
|
|
87
|
+
_corners[0].set(-1, -1, _target.z).unproject(camera);
|
|
88
|
+
_corners[1].set(1, -1, _target.z).unproject(camera);
|
|
89
|
+
_corners[2].set(1, 1, _target.z).unproject(camera);
|
|
90
|
+
_corners[3].set(-1, 1, _target.z).unproject(camera);
|
|
91
|
+
copyVector3sArray(positionAttributes, _boundaryVertices);
|
|
71
92
|
}
|
|
72
93
|
|
|
73
94
|
this.updateCamera = () => {
|
|
95
|
+
const camera = targetScene.camera;
|
|
96
|
+
let boundingBox = targetScene.getBoundingBox();
|
|
97
|
+
//Nothing has changed since the last update
|
|
98
|
+
if (_cameraUpdated && boundingBox && boundingBox.equals(_lastBoundingBox) &&
|
|
99
|
+
_lastNear === camera.near &&
|
|
100
|
+
matrixEquals(_lastMatrixWorld, camera.matrixWorld) &&
|
|
101
|
+
matrixEquals(_lastProjectionMatrix, camera.projectionMatrix)) {
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
74
104
|
this.getBoundary();
|
|
105
|
+
_lastMatrixWorld.copy(camera.matrixWorld);
|
|
106
|
+
_lastProjectionMatrix.copy(camera.projectionMatrix);
|
|
107
|
+
_lastNear = camera.near;
|
|
108
|
+
_cameraUpdated = false;
|
|
75
109
|
let cameraControl = targetScene.getZincCameraControls();
|
|
76
|
-
let boundingBox = targetScene.getBoundingBox();
|
|
77
110
|
if (boundingBox) {
|
|
111
|
+
_lastBoundingBox.copy(boundingBox);
|
|
112
|
+
_cameraUpdated = true;
|
|
78
113
|
// enlarge radius to keep image within edge of window
|
|
79
114
|
const diameter = boundingBox.min.distanceTo(boundingBox.max);
|
|
80
115
|
const radius = diameter / 2.0;
|
|
@@ -99,6 +99,7 @@ const Geometry = function () {
|
|
|
99
99
|
* @param {Boolean} wireframe - Flag to turn on/off wireframe display.
|
|
100
100
|
*/
|
|
101
101
|
this.setWireframe = wireframe => {
|
|
102
|
+
this.requestRender();
|
|
102
103
|
this.morph.material.wireframe = wireframe;
|
|
103
104
|
}
|
|
104
105
|
|
|
@@ -106,6 +107,7 @@ const Geometry = function () {
|
|
|
106
107
|
* Edit Vertice in index.
|
|
107
108
|
*/
|
|
108
109
|
this.editVertices = function(coords, i) {
|
|
110
|
+
this.requestRender();
|
|
109
111
|
if (coords && coords.length) {
|
|
110
112
|
let mesh = this.getMorph();
|
|
111
113
|
const attribute = mesh.geometry.getAttribute("position");
|