@xeokit/xeokit-sdk 2.6.53 → 2.6.55
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/dist/xeokit-sdk.cjs.js +292 -44
- package/dist/xeokit-sdk.es.js +292 -44
- package/dist/xeokit-sdk.es5.js +221 -107
- package/dist/xeokit-sdk.min.cjs.js +3 -3
- package/dist/xeokit-sdk.min.es.js +3 -3
- package/dist/xeokit-sdk.min.es5.js +3 -3
- package/package.json +1 -1
- package/src/plugins/StoreyViewsPlugin/StoreyViewsPlugin.js +22 -12
- package/src/plugins/TreeViewPlugin/TreeViewPlugin.js +2 -2
- package/src/viewer/Viewer.js +5 -9
- package/src/viewer/scene/CameraControl/CameraControl.js +198 -2
- package/src/viewer/scene/CameraControl/lib/CameraUpdater.js +5 -4
- package/src/viewer/scene/CameraControl/lib/handlers/KeyboardPanRotateDollyHandler.js +0 -8
- package/src/viewer/scene/CameraControl/lib/handlers/MousePanRotateDollyHandler.js +27 -4
- package/src/viewer/scene/CameraControl/lib/handlers/MousePickHandler.js +7 -1
- package/src/viewer/scene/input/Input.js +24 -0
- package/src/viewer/scene/model/vbo/instancing/triangles/VBOInstancingTrianglesLayer.js +1 -1
- package/types/plugins/StoreyViewsPlugin/StoreyViewsPlugin.d.ts +3 -3
- package/types/viewer/scene/CameraControl/CameraControl.d.ts +23 -0
package/package.json
CHANGED
|
@@ -680,9 +680,10 @@ class StoreyViewsPlugin extends Plugin {
|
|
|
680
680
|
* @param {Number[]} worldPos 3D World-space position.
|
|
681
681
|
* @returns {String} ID of the storey containing the position, or null if the position falls outside all the storeys.
|
|
682
682
|
*/
|
|
683
|
-
getStoreyContainingWorldPos(worldPos) {
|
|
684
|
-
|
|
685
|
-
|
|
683
|
+
getStoreyContainingWorldPos(worldPos, modelId = null) {
|
|
684
|
+
const storeys = modelId ? this._filterStoreys(modelId) : this.storeys;
|
|
685
|
+
for (let storeyId in storeys) {
|
|
686
|
+
const storey = storeys[storeyId];
|
|
686
687
|
if (math.point3AABB3AbsoluteIntersect(storey.storeyAABB, worldPos)) {
|
|
687
688
|
return storeyId;
|
|
688
689
|
}
|
|
@@ -696,9 +697,10 @@ class StoreyViewsPlugin extends Plugin {
|
|
|
696
697
|
* @param {Number[]} worldPos 3D World-space position.
|
|
697
698
|
* @returns {String} ID of the storey containing the position, or null if the position falls outside all the storeys.
|
|
698
699
|
*/
|
|
699
|
-
getStoreyInVerticalRange(worldPos) {
|
|
700
|
-
|
|
701
|
-
|
|
700
|
+
getStoreyInVerticalRange(worldPos, modelId = null) {
|
|
701
|
+
const storeys = modelId ? this._filterStoreys(modelId) : this.storeys;
|
|
702
|
+
for (let storeyId in storeys) {
|
|
703
|
+
const storey = storeys[storeyId];
|
|
702
704
|
const aabb = [0, 0, 0, 0, 0, 0], pos = [0, 0, 0];
|
|
703
705
|
aabb[1] = storey.storeyAABB[1];
|
|
704
706
|
aabb[4] = storey.storeyAABB[4];
|
|
@@ -716,12 +718,14 @@ class StoreyViewsPlugin extends Plugin {
|
|
|
716
718
|
* @param {Number[]} worldPos 3D World-space position.
|
|
717
719
|
* @returns {String} ID of the lowest/highest story or null.
|
|
718
720
|
*/
|
|
719
|
-
isPositionAboveOrBelowBuilding(worldPos) {
|
|
720
|
-
const
|
|
721
|
+
isPositionAboveOrBelowBuilding(worldPos, modelId = null) {
|
|
722
|
+
const storeys = modelId ? this._filterStoreys(modelId) : this.storeys;
|
|
723
|
+
const keys = Object.keys(storeys);
|
|
724
|
+
if(keys.length <= 0) return null;
|
|
721
725
|
const ids = [keys[0], keys[keys.length - 1]];
|
|
722
|
-
if (worldPos[1] <
|
|
726
|
+
if (worldPos[1] < storeys[ids[0]].storeyAABB[1])
|
|
723
727
|
return ids[0];
|
|
724
|
-
else if (worldPos[1] >
|
|
728
|
+
else if (worldPos[1] > storeys[ids[1]].storeyAABB[4])
|
|
725
729
|
return ids[1];
|
|
726
730
|
return null;
|
|
727
731
|
}
|
|
@@ -845,8 +849,8 @@ class StoreyViewsPlugin extends Plugin {
|
|
|
845
849
|
|
|
846
850
|
if (storey1MetaObject && (storey1MetaObject.attributes && storey1MetaObject.attributes.elevation !== undefined) &&
|
|
847
851
|
storey2MetaObject && (storey2MetaObject.attributes && storey2MetaObject.attributes.elevation !== undefined)) {
|
|
848
|
-
const elevation1 = storey1MetaObject.attributes.elevation;
|
|
849
|
-
const elevation2 = storey2MetaObject.attributes.elevation;
|
|
852
|
+
const elevation1 = Number.parseFloat(storey1MetaObject.attributes.elevation);
|
|
853
|
+
const elevation2 = Number.parseFloat(storey2MetaObject.attributes.elevation);
|
|
850
854
|
if (elevation1 > elevation2) {
|
|
851
855
|
return -1;
|
|
852
856
|
}
|
|
@@ -865,6 +869,12 @@ class StoreyViewsPlugin extends Plugin {
|
|
|
865
869
|
}
|
|
866
870
|
});
|
|
867
871
|
}
|
|
872
|
+
|
|
873
|
+
_filterStoreys(modelId) {
|
|
874
|
+
return Object.fromEntries(
|
|
875
|
+
Object.entries(this.storeys).filter(([_, value]) => value.modelId === modelId)
|
|
876
|
+
);
|
|
877
|
+
}
|
|
868
878
|
}
|
|
869
879
|
|
|
870
880
|
export {StoreyViewsPlugin}
|
|
@@ -1235,8 +1235,8 @@ export class TreeViewPlugin extends Plugin {
|
|
|
1235
1235
|
|
|
1236
1236
|
if (storey1MetaObject && (storey1MetaObject.attributes && storey1MetaObject.attributes.elevation !== undefined) &&
|
|
1237
1237
|
storey2MetaObject && (storey2MetaObject.attributes && storey2MetaObject.attributes.elevation !== undefined)) {
|
|
1238
|
-
const elevation1 = storey1MetaObject.attributes.elevation;
|
|
1239
|
-
const elevation2 = storey2MetaObject.attributes.elevation;
|
|
1238
|
+
const elevation1 = Number.parseFloat(storey1MetaObject.attributes.elevation);
|
|
1239
|
+
const elevation2 = Number.parseFloat(storey2MetaObject.attributes.elevation);
|
|
1240
1240
|
if (elevation1 > elevation2) {
|
|
1241
1241
|
return -1;
|
|
1242
1242
|
}
|
package/src/viewer/Viewer.js
CHANGED
|
@@ -493,19 +493,15 @@ class Viewer {
|
|
|
493
493
|
|
|
494
494
|
for (let i = 0, len = pluginContainerElements.length; i < len; i++) {
|
|
495
495
|
const containerElement = pluginContainerElements[i];
|
|
496
|
-
//only calculate the scale for first plugin
|
|
497
|
-
//for all others keep the scale 1 otherwise it will keep multiplying the scale with the base scale of canvas
|
|
498
|
-
//resulting in increase/decreased size for the the canvas that is being overlapped
|
|
499
|
-
const scale = i == 0 ? snapshotCanvas.width / containerElement.clientWidth : 1;
|
|
500
|
-
const off = math.vec2([ 0, 0 ]);
|
|
501
|
-
transformToNode(canvas, containerElement, off);
|
|
502
496
|
await html2canvas(containerElement, {
|
|
503
497
|
canvas: snapshotCanvas,
|
|
504
498
|
backgroundColor: null,
|
|
505
|
-
|
|
506
|
-
y: off[1],
|
|
507
|
-
scale
|
|
499
|
+
scale: snapshotCanvas.width / containerElement.clientWidth
|
|
508
500
|
});
|
|
501
|
+
// Reverts translation and scaling applied to the snapshotCanvas's context
|
|
502
|
+
// by the html2canvas call (inside the ForeignObjectRenderer's constructor)
|
|
503
|
+
// (implemented to compensate XCD-153 issue)
|
|
504
|
+
snapshotCanvas.getContext("2d").resetTransform();
|
|
509
505
|
}
|
|
510
506
|
if (!params.includeGizmos) {
|
|
511
507
|
this.sendToPlugins("snapshotFinished");
|
|
@@ -459,6 +459,12 @@ const DEFAULT_SNAP_EDGE = true;
|
|
|
459
459
|
* keyMap[cameraControl.AXIS_VIEW_FRONT] = [input.KEY_NUM_4];
|
|
460
460
|
* keyMap[cameraControl.AXIS_VIEW_TOP] = [input.KEY_NUM_5];
|
|
461
461
|
* keyMap[cameraControl.AXIS_VIEW_BOTTOM] = [input.KEY_NUM_6];
|
|
462
|
+
* keyMap[cameraControl.MOUSE_PAN] = [[input.KEY_SHIFT, input.MOUSE_LEFT_BUTTON]];
|
|
463
|
+
* keyMap[cameraControl.MOUSE_ROTATE] = [
|
|
464
|
+
* [input.KEY_SHIFT, input.MOUSE_MIDDLE_BUTTON],
|
|
465
|
+
* [input.KEY_SHIFT, input.MOUSE_RIGHT_BUTTON]
|
|
466
|
+
* ]
|
|
467
|
+
* keyMap[cameraControl.MOUSE_DOLLY] = [[input.KEY_CTRL, input.MOUSE_RIGHT_BUTTON]];
|
|
462
468
|
*
|
|
463
469
|
* cameraControl.keyMap = keyMap;
|
|
464
470
|
* ````
|
|
@@ -477,6 +483,70 @@ const DEFAULT_SNAP_EDGE = true;
|
|
|
477
483
|
*
|
|
478
484
|
* * ````"qwerty"````
|
|
479
485
|
* * ````"azerty"````
|
|
486
|
+
*
|
|
487
|
+
* ## Basic Keyboard Mapping
|
|
488
|
+
* * ````"OR" Relation````
|
|
489
|
+
* Set multiple keys to trigger an action if any one is pressed:
|
|
490
|
+
*
|
|
491
|
+
* ````javascript
|
|
492
|
+
* keyMap[cameraControl.DOLLY_BACKWARDS] = [input.KEY_S, input.KEY_SUBTRACT];
|
|
493
|
+
* ````
|
|
494
|
+
*
|
|
495
|
+
* If either ````KEY_S```` or ````KEY_SUBTRACT```` is pressed, the camera will dolly backward.
|
|
496
|
+
*
|
|
497
|
+
* * ````"AND" Relation````
|
|
498
|
+
* To require all keys in a combination to be pressed:
|
|
499
|
+
*
|
|
500
|
+
* ````javascript
|
|
501
|
+
* keyMap[cameraControl.DOLLY_BACKWARDS] = [[input.KEY_S, input.KEY_SUBTRACT]];
|
|
502
|
+
* ````
|
|
503
|
+
*
|
|
504
|
+
* The camera will dolly backward if ````both KEY_S```` and ````KEY_SUBTRACT```` are pressed.
|
|
505
|
+
*
|
|
506
|
+
* * ````Mix "AND" and "OR" Relation````
|
|
507
|
+
* Use a combination of keys and groups for flexibility:
|
|
508
|
+
*
|
|
509
|
+
* ````javascript
|
|
510
|
+
* keyMap[cameraControl.DOLLY_BACKWARDS] = [
|
|
511
|
+
* [input.KEY_S, input.KEY_SUBTRACT], // 'And' group
|
|
512
|
+
* input.KEY_SHIFT // 'Or' with previous
|
|
513
|
+
* ];
|
|
514
|
+
* ````
|
|
515
|
+
*
|
|
516
|
+
* The camera will dolly backward if ````KEY_S```` + ````KEY_SUBTRACT```` are pressed together, or if ````KEY_SHIFT```` is pressed.
|
|
517
|
+
*
|
|
518
|
+
* ## Special Mouse Actions
|
|
519
|
+
* Certain actions support combinations with specific mouse buttons or events:
|
|
520
|
+
*
|
|
521
|
+
* * ````MOUSE_PAN````
|
|
522
|
+
* For panning with a key and mouse movement:
|
|
523
|
+
*
|
|
524
|
+
* ````javascript
|
|
525
|
+
* keyMap[cameraControl.MOUSE_PAN] = [[input.KEY_SHIFT, input.MOUSE_LEFT_BUTTON]];
|
|
526
|
+
* ````
|
|
527
|
+
*
|
|
528
|
+
* Panning is triggered by pressing ````KEY_SHIFT```` + ````MOUSE_LEFT_BUTTON```` while moving the mouse.
|
|
529
|
+
*
|
|
530
|
+
* * ````MOUSE_ROTATE````
|
|
531
|
+
* Similar to panning, rotation can be configured with key and mouse button combinations:
|
|
532
|
+
*
|
|
533
|
+
* ````javascript
|
|
534
|
+
* keyMap[cameraControl.MOUSE_ROTATE] = [[input.KEY_CTRL, input.MOUSE_LEFT_BUTTON]];
|
|
535
|
+
* ````
|
|
536
|
+
*
|
|
537
|
+
* Rotation is triggered by pressing ````KEY_CTRL```` + ````MOUSE_LEFT_BUTTON```` during mouse movement.
|
|
538
|
+
*
|
|
539
|
+
* * ````MOUSE_DOLLY````
|
|
540
|
+
* Dolly with mouse wheel scrolling and optional key combinations:
|
|
541
|
+
*
|
|
542
|
+
* ````javascript
|
|
543
|
+
* keyMap[cameraControl.MOUSE_DOLLY] = [[input.KEY_ALT]];
|
|
544
|
+
* ````
|
|
545
|
+
*
|
|
546
|
+
* Dolly action occurs when scrolling the mouse wheel with ````KEY_ALT```` held (no need to specify MOUSE_WHEEL).
|
|
547
|
+
*
|
|
548
|
+
* ## Special Mouse Actions
|
|
549
|
+
* Use ````input.MOUSE_LEFT_BUTTON````, ````input.MOUSE_MIDDLE_BUTTON````, and ````input.MOUSE_RIGHT_BUTTON```` in combinations only for camera movements involving the mouse.
|
|
480
550
|
*/
|
|
481
551
|
class CameraControl extends Component {
|
|
482
552
|
|
|
@@ -614,6 +684,27 @@ class CameraControl extends Component {
|
|
|
614
684
|
*/
|
|
615
685
|
this.AXIS_VIEW_BOTTOM = 17;
|
|
616
686
|
|
|
687
|
+
/**
|
|
688
|
+
* Identifies the XX action.
|
|
689
|
+
* @final
|
|
690
|
+
* @type {Number}
|
|
691
|
+
*/
|
|
692
|
+
this.MOUSE_PAN = 18;
|
|
693
|
+
|
|
694
|
+
/**
|
|
695
|
+
* Identifies the XX action.
|
|
696
|
+
* @final
|
|
697
|
+
* @type {Number}
|
|
698
|
+
*/
|
|
699
|
+
this.MOUSE_ROTATE = 19;
|
|
700
|
+
|
|
701
|
+
/**
|
|
702
|
+
* Identifies the XX action.
|
|
703
|
+
* @final
|
|
704
|
+
* @type {Number}
|
|
705
|
+
*/
|
|
706
|
+
this.MOUSE_DOLLY = 20;
|
|
707
|
+
|
|
617
708
|
this._keyMap = {}; // Maps key codes to the above actions
|
|
618
709
|
|
|
619
710
|
this.scene.canvas.canvas.oncontextmenu = (e) => {
|
|
@@ -729,6 +820,13 @@ class CameraControl extends Component {
|
|
|
729
820
|
new KeyboardPanRotateDollyHandler(this.scene, this._controllers, this._configs, this._states, this._updates)
|
|
730
821
|
];
|
|
731
822
|
|
|
823
|
+
this._cursors = {
|
|
824
|
+
dollyForward: "zoom-in",
|
|
825
|
+
dollyBackward: "zoom-out",
|
|
826
|
+
rotate: 'grabbing',
|
|
827
|
+
pan: 'move',
|
|
828
|
+
}
|
|
829
|
+
|
|
732
830
|
// Applies scheduled updates to the Camera on each Scene "tick" event
|
|
733
831
|
|
|
734
832
|
this._cameraUpdater = new CameraUpdater(this.scene, this._controllers, this._configs, this._states, this._updates);
|
|
@@ -802,6 +900,12 @@ class CameraControl extends Component {
|
|
|
802
900
|
keyMap[this.AXIS_VIEW_FRONT] = [input.KEY_NUM_4];
|
|
803
901
|
keyMap[this.AXIS_VIEW_TOP] = [input.KEY_NUM_5];
|
|
804
902
|
keyMap[this.AXIS_VIEW_BOTTOM] = [input.KEY_NUM_6];
|
|
903
|
+
keyMap[this.MOUSE_PAN] = [
|
|
904
|
+
[input.MOUSE_LEFT_BUTTON, input.KEY_SHIFT],
|
|
905
|
+
this._configs.panRightClick ? input.MOUSE_RIGHT_BUTTON : input.MOUSE_MIDDLE_BUTTON
|
|
906
|
+
]
|
|
907
|
+
keyMap[this.MOUSE_ROTATE] = [input.MOUSE_LEFT_BUTTON];
|
|
908
|
+
keyMap[this.MOUSE_DOLLY] = [];
|
|
805
909
|
break;
|
|
806
910
|
|
|
807
911
|
case "azerty":
|
|
@@ -823,6 +927,12 @@ class CameraControl extends Component {
|
|
|
823
927
|
keyMap[this.AXIS_VIEW_FRONT] = [input.KEY_NUM_4];
|
|
824
928
|
keyMap[this.AXIS_VIEW_TOP] = [input.KEY_NUM_5];
|
|
825
929
|
keyMap[this.AXIS_VIEW_BOTTOM] = [input.KEY_NUM_6];
|
|
930
|
+
keyMap[this.MOUSE_PAN] = [
|
|
931
|
+
[input.MOUSE_LEFT_BUTTON, input.KEY_SHIFT],
|
|
932
|
+
this._configs.panRightClick ? input.MOUSE_RIGHT_BUTTON : input.MOUSE_MIDDLE_BUTTON
|
|
933
|
+
]
|
|
934
|
+
keyMap[this.MOUSE_ROTATE] = [input.MOUSE_LEFT_BUTTON];
|
|
935
|
+
keyMap[this.MOUSE_DOLLY] = [];
|
|
826
936
|
break;
|
|
827
937
|
}
|
|
828
938
|
|
|
@@ -842,6 +952,44 @@ class CameraControl extends Component {
|
|
|
842
952
|
return this._keyMap;
|
|
843
953
|
}
|
|
844
954
|
|
|
955
|
+
_areAllKeysDown(keyDownMap, keys) {
|
|
956
|
+
if (!keys || keys.length <= 0) {
|
|
957
|
+
return true;
|
|
958
|
+
}
|
|
959
|
+
if (!keyDownMap) {
|
|
960
|
+
return false;
|
|
961
|
+
}
|
|
962
|
+
for (let i = 0, len = keys.length; i < len; i++) {
|
|
963
|
+
const key = keys[i];
|
|
964
|
+
if (!keyDownMap[key])
|
|
965
|
+
return false;
|
|
966
|
+
}
|
|
967
|
+
return true;
|
|
968
|
+
}
|
|
969
|
+
|
|
970
|
+
_isAnyOtherKeyDown(keyDownMap, keyMap) {
|
|
971
|
+
for (let i = 0, len = keyDownMap.length; i < len; i++) {
|
|
972
|
+
if (keyDownMap[i]) {
|
|
973
|
+
if (Array.isArray(keyMap)) {
|
|
974
|
+
if (keyMap.indexOf(i) < 0) return true;
|
|
975
|
+
}
|
|
976
|
+
else if (i !== keyMap) return true;
|
|
977
|
+
}
|
|
978
|
+
}
|
|
979
|
+
return false;
|
|
980
|
+
}
|
|
981
|
+
|
|
982
|
+
_isMouseAction(action) {
|
|
983
|
+
switch (action) {
|
|
984
|
+
case this.MOUSE_ROTATE:
|
|
985
|
+
case this.MOUSE_DOLLY:
|
|
986
|
+
case this.MOUSE_PAN:
|
|
987
|
+
return true;
|
|
988
|
+
default:
|
|
989
|
+
return false;
|
|
990
|
+
}
|
|
991
|
+
}
|
|
992
|
+
|
|
845
993
|
/**
|
|
846
994
|
* Returns true if any keys configured for the given action are down.
|
|
847
995
|
* @param action
|
|
@@ -853,14 +1001,21 @@ class CameraControl extends Component {
|
|
|
853
1001
|
if (!keys) {
|
|
854
1002
|
return false;
|
|
855
1003
|
}
|
|
1004
|
+
if (keys.length === 0 && this._isMouseAction(action)) return true;
|
|
856
1005
|
if (!keyDownMap) {
|
|
857
1006
|
keyDownMap = this.scene.input.keyDown;
|
|
858
1007
|
}
|
|
859
1008
|
for (let i = 0, len = keys.length; i < len; i++) {
|
|
860
1009
|
const key = keys[i];
|
|
861
|
-
if (
|
|
862
|
-
|
|
1010
|
+
if (!Array.isArray(key)) {
|
|
1011
|
+
if (keyDownMap[key] && !this._isAnyOtherKeyDown(keyDownMap, key))
|
|
1012
|
+
return true;
|
|
1013
|
+
}
|
|
1014
|
+
else {
|
|
1015
|
+
if (this._areAllKeysDown(keyDownMap, key) && !this._isAnyOtherKeyDown(keyDownMap, key))
|
|
1016
|
+
return true;
|
|
863
1017
|
}
|
|
1018
|
+
|
|
864
1019
|
}
|
|
865
1020
|
return false;
|
|
866
1021
|
}
|
|
@@ -1033,6 +1188,37 @@ class CameraControl extends Component {
|
|
|
1033
1188
|
this._configs.pointerEnabled = !!value;
|
|
1034
1189
|
}
|
|
1035
1190
|
|
|
1191
|
+
/**
|
|
1192
|
+
* Sets the cursor to be used when a particular action is being performed.
|
|
1193
|
+
*
|
|
1194
|
+
* Accepted actions are:
|
|
1195
|
+
*
|
|
1196
|
+
* * "dollyForward" - when the camera is dollying in the forward direction
|
|
1197
|
+
* * "dollyBackward" - when the camera is dollying in the backward direction
|
|
1198
|
+
* * "pan" - when the camera is being panned
|
|
1199
|
+
* * "rotate" - when the camera is being rotated
|
|
1200
|
+
*
|
|
1201
|
+
* @param {String} action
|
|
1202
|
+
* @param {String} style
|
|
1203
|
+
*/
|
|
1204
|
+
setCursorStyle(action, style) {
|
|
1205
|
+
if (Object.prototype.hasOwnProperty.call(this._cursors, action)) {
|
|
1206
|
+
this._cursors = { ...this._cursors, [action]: style };
|
|
1207
|
+
}
|
|
1208
|
+
else
|
|
1209
|
+
console.warn(`Action '${action}' is not valid for cursor styles.`);
|
|
1210
|
+
}
|
|
1211
|
+
|
|
1212
|
+
/**
|
|
1213
|
+
* Gets the current style for a particular action.
|
|
1214
|
+
*
|
|
1215
|
+
* @param {String} action To get the style for
|
|
1216
|
+
* @returns {String} style set on the cursor for action
|
|
1217
|
+
*/
|
|
1218
|
+
getCursorStyle(action) {
|
|
1219
|
+
return this._cursors[action] || null;
|
|
1220
|
+
}
|
|
1221
|
+
|
|
1036
1222
|
_reset() {
|
|
1037
1223
|
for (let i = 0, len = this._handlers.length; i < len; i++) {
|
|
1038
1224
|
const handler = this._handlers[i];
|
|
@@ -1296,6 +1482,16 @@ class CameraControl extends Component {
|
|
|
1296
1482
|
*/
|
|
1297
1483
|
set panRightClick(value) {
|
|
1298
1484
|
this._configs.panRightClick = value !== false;
|
|
1485
|
+
const panKeyMap = this._keyMap[this.MOUSE_PAN];
|
|
1486
|
+
if (panKeyMap && panKeyMap.length > 0) {
|
|
1487
|
+
const input = this.scene.input;
|
|
1488
|
+
for (let i = 0, len = panKeyMap.length; i < len; i++) {
|
|
1489
|
+
if (this._configs.panRightClick && panKeyMap[i] === input.MOUSE_MIDDLE_BUTTON)
|
|
1490
|
+
this._keyMap[this.MOUSE_PAN][i] = input.MOUSE_RIGHT_BUTTON;
|
|
1491
|
+
else if (!this._configs.panRightClick && panKeyMap[i] === input.MOUSE_RIGHT_BUTTON)
|
|
1492
|
+
this._keyMap[this.MOUSE_PAN][i] = input.MOUSE_MIDDLE_BUTTON;
|
|
1493
|
+
}
|
|
1494
|
+
}
|
|
1299
1495
|
}
|
|
1300
1496
|
|
|
1301
1497
|
/**
|
|
@@ -18,6 +18,7 @@ class CameraUpdater {
|
|
|
18
18
|
const pickController = controllers.pickController;
|
|
19
19
|
const pivotController = controllers.pivotController;
|
|
20
20
|
const panController = controllers.panController;
|
|
21
|
+
const cameraControl = controllers.cameraControl;
|
|
21
22
|
|
|
22
23
|
let countDown = SCALE_DOLLY_EACH_FRAME; // Decrements on each tick
|
|
23
24
|
let dollyDistFactor = 1.0; // Calculated when countDown is zero
|
|
@@ -142,7 +143,7 @@ class CameraUpdater {
|
|
|
142
143
|
updates.rotateDeltaX *= configs.rotationInertia;
|
|
143
144
|
updates.rotateDeltaY *= configs.rotationInertia;
|
|
144
145
|
|
|
145
|
-
cursorType =
|
|
146
|
+
cursorType = cameraControl._cursors.rotate;
|
|
146
147
|
}
|
|
147
148
|
|
|
148
149
|
//----------------------------------------------------------------------------------------------------------
|
|
@@ -208,7 +209,7 @@ class CameraUpdater {
|
|
|
208
209
|
camera.pan(vec);
|
|
209
210
|
}
|
|
210
211
|
|
|
211
|
-
cursorType =
|
|
212
|
+
cursorType = cameraControl._cursors.pan;
|
|
212
213
|
}
|
|
213
214
|
|
|
214
215
|
updates.panDeltaX *= configs.panInertia;
|
|
@@ -222,9 +223,9 @@ class CameraUpdater {
|
|
|
222
223
|
if (dollyDeltaForDist !== 0) {
|
|
223
224
|
|
|
224
225
|
if (dollyDeltaForDist < 0) {
|
|
225
|
-
cursorType =
|
|
226
|
+
cursorType = cameraControl._cursors.dollyForward;
|
|
226
227
|
} else {
|
|
227
|
-
cursorType =
|
|
228
|
+
cursorType = cameraControl._cursors.dollyBackward;
|
|
228
229
|
}
|
|
229
230
|
|
|
230
231
|
if (configs.firstPerson) {
|
|
@@ -26,10 +26,6 @@ class KeyboardPanRotateDollyHandler {
|
|
|
26
26
|
return;
|
|
27
27
|
}
|
|
28
28
|
keyDownMap[keyCode] = true;
|
|
29
|
-
|
|
30
|
-
if (keyCode === input.KEY_SHIFT) {
|
|
31
|
-
canvas.style.cursor = "move";
|
|
32
|
-
}
|
|
33
29
|
});
|
|
34
30
|
|
|
35
31
|
this._onSceneKeyUp = input.on("keyup", (keyCode) => {
|
|
@@ -38,10 +34,6 @@ class KeyboardPanRotateDollyHandler {
|
|
|
38
34
|
}
|
|
39
35
|
keyDownMap[keyCode] = false;
|
|
40
36
|
|
|
41
|
-
if (keyCode === input.KEY_SHIFT) {
|
|
42
|
-
canvas.style.cursor = null;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
37
|
if (controllers.pivotController.getPivoting()) {
|
|
46
38
|
controllers.pivotController.endPivot()
|
|
47
39
|
}
|
|
@@ -39,6 +39,7 @@ class MousePanRotateDollyHandler {
|
|
|
39
39
|
this._scene = scene;
|
|
40
40
|
|
|
41
41
|
const pickController = controllers.pickController;
|
|
42
|
+
const cameraControl = controllers.cameraControl;
|
|
42
43
|
|
|
43
44
|
let lastX = 0;
|
|
44
45
|
let lastY = 0;
|
|
@@ -77,7 +78,6 @@ class MousePanRotateDollyHandler {
|
|
|
77
78
|
});
|
|
78
79
|
|
|
79
80
|
function setMousedownState(pick = true) {
|
|
80
|
-
canvas.style.cursor = "move";
|
|
81
81
|
setMousedownPositions();
|
|
82
82
|
if (pick) {
|
|
83
83
|
setMousedownPick();
|
|
@@ -107,6 +107,15 @@ class MousePanRotateDollyHandler {
|
|
|
107
107
|
}
|
|
108
108
|
}
|
|
109
109
|
|
|
110
|
+
function isPanning() {
|
|
111
|
+
return cameraControl._isKeyDownForAction(cameraControl.MOUSE_PAN, keyDown);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function isRotating() {
|
|
115
|
+
return cameraControl._isKeyDownForAction(cameraControl.MOUSE_ROTATE, keyDown);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
|
|
110
119
|
canvas.addEventListener("mousedown", this._mouseDownHandler = (e) => {
|
|
111
120
|
|
|
112
121
|
if (!(configs.active && configs.pointerEnabled)) {
|
|
@@ -120,12 +129,14 @@ class MousePanRotateDollyHandler {
|
|
|
120
129
|
if (keyDown[scene.input.KEY_SHIFT] || configs.planView) {
|
|
121
130
|
|
|
122
131
|
mouseDownLeft = true;
|
|
132
|
+
keyDown[scene.input.MOUSE_LEFT_BUTTON] = true;
|
|
123
133
|
|
|
124
134
|
setMousedownState();
|
|
125
135
|
|
|
126
136
|
} else {
|
|
127
137
|
|
|
128
138
|
mouseDownLeft = true;
|
|
139
|
+
keyDown[scene.input.MOUSE_LEFT_BUTTON] = true;
|
|
129
140
|
|
|
130
141
|
setMousedownState(false);
|
|
131
142
|
}
|
|
@@ -135,6 +146,7 @@ class MousePanRotateDollyHandler {
|
|
|
135
146
|
case 2: // Middle/both buttons
|
|
136
147
|
|
|
137
148
|
mouseDownMiddle = true;
|
|
149
|
+
keyDown[scene.input.MOUSE_MIDDLE_BUTTON] = true;
|
|
138
150
|
|
|
139
151
|
setMousedownState();
|
|
140
152
|
|
|
@@ -143,6 +155,7 @@ class MousePanRotateDollyHandler {
|
|
|
143
155
|
case 3: // Right button
|
|
144
156
|
|
|
145
157
|
mouseDownRight = true;
|
|
158
|
+
keyDown[scene.input.MOUSE_RIGHT_BUTTON] = true;
|
|
146
159
|
|
|
147
160
|
if (configs.panRightClick) {
|
|
148
161
|
|
|
@@ -175,7 +188,8 @@ class MousePanRotateDollyHandler {
|
|
|
175
188
|
const x = states.pointerCanvasPos[0];
|
|
176
189
|
const y = states.pointerCanvasPos[1];
|
|
177
190
|
|
|
178
|
-
const panning =
|
|
191
|
+
const panning = isPanning();
|
|
192
|
+
const rotating = isRotating();
|
|
179
193
|
|
|
180
194
|
const xDelta = document.pointerLockElement ? e.movementX : (x - lastX);
|
|
181
195
|
const yDelta = document.pointerLockElement ? e.movementY : (y - lastY);
|
|
@@ -200,7 +214,7 @@ class MousePanRotateDollyHandler {
|
|
|
200
214
|
updates.panDeltaY += 0.5 * camera.ortho.scale * (yDelta / canvasHeight);
|
|
201
215
|
}
|
|
202
216
|
|
|
203
|
-
} else if (
|
|
217
|
+
} else if (rotating) {
|
|
204
218
|
|
|
205
219
|
if (!configs.planView) { // No rotating in plan-view mode
|
|
206
220
|
|
|
@@ -241,16 +255,25 @@ class MousePanRotateDollyHandler {
|
|
|
241
255
|
mouseDownLeft = false;
|
|
242
256
|
mouseDownMiddle = false;
|
|
243
257
|
mouseDownRight = false;
|
|
258
|
+
keyDown[scene.input.MOUSE_LEFT_BUTTON] = false;
|
|
259
|
+
keyDown[scene.input.MOUSE_MIDDLE_BUTTON] = false;
|
|
260
|
+
keyDown[scene.input.MOUSE_RIGHT_BUTTON] = false;
|
|
244
261
|
break;
|
|
245
262
|
case 2: // Middle/both buttons
|
|
246
263
|
mouseDownLeft = false;
|
|
247
264
|
mouseDownMiddle = false;
|
|
248
265
|
mouseDownRight = false;
|
|
266
|
+
keyDown[scene.input.MOUSE_LEFT_BUTTON] = false;
|
|
267
|
+
keyDown[scene.input.MOUSE_MIDDLE_BUTTON] = false;
|
|
268
|
+
keyDown[scene.input.MOUSE_RIGHT_BUTTON] = false;
|
|
249
269
|
break;
|
|
250
270
|
case 3: // Right button
|
|
251
271
|
mouseDownLeft = false;
|
|
252
272
|
mouseDownMiddle = false;
|
|
253
273
|
mouseDownRight = false;
|
|
274
|
+
keyDown[scene.input.MOUSE_LEFT_BUTTON] = false;
|
|
275
|
+
keyDown[scene.input.MOUSE_MIDDLE_BUTTON] = false;
|
|
276
|
+
keyDown[scene.input.MOUSE_RIGHT_BUTTON] = false;
|
|
254
277
|
break;
|
|
255
278
|
default:
|
|
256
279
|
break;
|
|
@@ -296,7 +319,7 @@ class MousePanRotateDollyHandler {
|
|
|
296
319
|
let secsNowLast = null;
|
|
297
320
|
|
|
298
321
|
canvas.addEventListener("wheel", this._mouseWheelHandler = (e) => {
|
|
299
|
-
if (!(configs.active && configs.pointerEnabled && configs.zoomOnMouseWheel)) {
|
|
322
|
+
if (!(configs.active && configs.pointerEnabled && configs.zoomOnMouseWheel && cameraControl._isKeyDownForAction(cameraControl.MOUSE_DOLLY, keyDown))) {
|
|
300
323
|
return;
|
|
301
324
|
}
|
|
302
325
|
const secsNow = performance.now() / 1000.0;
|
|
@@ -16,6 +16,7 @@ class MousePickHandler {
|
|
|
16
16
|
this._clicks = 0;
|
|
17
17
|
this._timeout = null;
|
|
18
18
|
this._lastPickedEntityId = null;
|
|
19
|
+
this._lastClickedWorldPos = null;
|
|
19
20
|
|
|
20
21
|
let leftDown = false;
|
|
21
22
|
let rightDown = false;
|
|
@@ -165,11 +166,16 @@ class MousePickHandler {
|
|
|
165
166
|
if (pickResult && pickResult.worldPos) {
|
|
166
167
|
pivotController.setPivotPos(pickResult.worldPos);
|
|
167
168
|
pivotController.startPivot();
|
|
169
|
+
this._lastClickedWorldPos = pickResult.worldPos.slice();
|
|
168
170
|
} else {
|
|
169
171
|
if (configs.smartPivot) {
|
|
170
172
|
pivotController.setCanvasPivotPos(states.pointerCanvasPos);
|
|
171
173
|
} else {
|
|
172
|
-
|
|
174
|
+
if (this._lastClickedWorldPos) {
|
|
175
|
+
pivotController.setPivotPos(this._lastClickedWorldPos);
|
|
176
|
+
} else {
|
|
177
|
+
pivotController.setPivotPos(scene.camera.look);
|
|
178
|
+
}
|
|
173
179
|
}
|
|
174
180
|
pivotController.startPivot();
|
|
175
181
|
}
|
|
@@ -937,6 +937,30 @@ class Input extends Component {
|
|
|
937
937
|
*/
|
|
938
938
|
this.KEY_SPACE = 32;
|
|
939
939
|
|
|
940
|
+
/**
|
|
941
|
+
* Code for the left mouse button.
|
|
942
|
+
* @property MOUSE_LEFT_BUTTON
|
|
943
|
+
* @final
|
|
944
|
+
* @type {Number}
|
|
945
|
+
*/
|
|
946
|
+
this.MOUSE_LEFT_BUTTON = 260;
|
|
947
|
+
|
|
948
|
+
/**
|
|
949
|
+
* Code for the middle mouse button.
|
|
950
|
+
* @property MOUSE_MIDDLE_BUTTON
|
|
951
|
+
* @final
|
|
952
|
+
* @type {Number}
|
|
953
|
+
*/
|
|
954
|
+
this.MOUSE_MIDDLE_BUTTON = 261;
|
|
955
|
+
|
|
956
|
+
/**
|
|
957
|
+
* Code for the right mouse button.
|
|
958
|
+
* @property MOUSE_RIGHT_BUTTON
|
|
959
|
+
* @final
|
|
960
|
+
* @type {Number}
|
|
961
|
+
*/
|
|
962
|
+
this.MOUSE_RIGHT_BUTTON = 262;
|
|
963
|
+
|
|
940
964
|
/**
|
|
941
965
|
* The canvas element that mouse and keyboards are bound to.
|
|
942
966
|
*
|
|
@@ -334,7 +334,7 @@ export class VBOInstancingTrianglesLayer {
|
|
|
334
334
|
state.indicesBuf = new ArrayBuf(gl, gl.ELEMENT_ARRAY_BUFFER, new Uint32Array(geometry.indices), geometry.indices.length, 1, gl.STATIC_DRAW);
|
|
335
335
|
state.numIndices = geometry.indices.length;
|
|
336
336
|
}
|
|
337
|
-
if (geometry.
|
|
337
|
+
if (geometry.edgeIndices && geometry.edgeIndices.length > 0) {
|
|
338
338
|
state.edgeIndicesBuf = new ArrayBuf(gl, gl.ELEMENT_ARRAY_BUFFER, new Uint32Array(geometry.edgeIndices), geometry.edgeIndices.length, 1, gl.STATIC_DRAW);
|
|
339
339
|
}
|
|
340
340
|
|
|
@@ -116,7 +116,7 @@ export declare class StoreyViewsPlugin extends Plugin {
|
|
|
116
116
|
* @param {Number[]} worldPos 3D World-space position.
|
|
117
117
|
* @returns {String} ID of the storey containing the position, or null if the position falls outside all the storeys.
|
|
118
118
|
*/
|
|
119
|
-
getStoreyContainingWorldPos(worldPos: number[]): string;
|
|
119
|
+
getStoreyContainingWorldPos(worldPos: number[], modelId: null | string): string;
|
|
120
120
|
|
|
121
121
|
/**
|
|
122
122
|
* Gets the ID of the storey which's bounding box contains the y point of the world position
|
|
@@ -124,7 +124,7 @@ export declare class StoreyViewsPlugin extends Plugin {
|
|
|
124
124
|
* @param {Number[]} worldPos 3D World-space position.
|
|
125
125
|
* @returns {String} ID of the storey containing the position, or null if the position falls outside all the storeys.
|
|
126
126
|
*/
|
|
127
|
-
getStoreyInVerticalRange(worldPos: number[]): string;
|
|
127
|
+
getStoreyInVerticalRange(worldPos: number[], modelId: null | string): string;
|
|
128
128
|
|
|
129
129
|
|
|
130
130
|
/**
|
|
@@ -133,7 +133,7 @@ export declare class StoreyViewsPlugin extends Plugin {
|
|
|
133
133
|
* @param {Number[]} worldPos 3D World-space position.
|
|
134
134
|
* @returns {String} ID of the lowest/highest story or null.
|
|
135
135
|
*/
|
|
136
|
-
isPositionAboveOrBelowBuilding(worldPos: number[]): string;
|
|
136
|
+
isPositionAboveOrBelowBuilding(worldPos: number[], modelId: null | string): string;
|
|
137
137
|
|
|
138
138
|
/**
|
|
139
139
|
* Converts a 3D World-space position to a 2D position within a StoreyMap image.
|