@xeokit/xeokit-sdk 2.6.52 → 2.6.54
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 +263 -51
- package/dist/xeokit-sdk.es.js +263 -51
- package/dist/xeokit-sdk.es5.js +222 -127
- package/dist/xeokit-sdk.min.cjs.js +3 -3
- package/dist/xeokit-sdk.min.es.js +4 -4
- 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 +20 -19
- package/src/viewer/Viewer.js +5 -9
- package/src/viewer/scene/CameraControl/CameraControl.js +160 -2
- package/src/viewer/scene/CameraControl/lib/handlers/MousePanRotateDollyHandler.js +27 -3
- package/src/viewer/scene/CameraControl/lib/handlers/MousePickHandler.js +7 -1
- package/src/viewer/scene/input/Input.js +24 -0
- package/types/plugins/StoreyViewsPlugin/StoreyViewsPlugin.d.ts +3 -3
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}
|
|
@@ -1205,7 +1205,7 @@ export class TreeViewPlugin extends Plugin {
|
|
|
1205
1205
|
return;
|
|
1206
1206
|
}
|
|
1207
1207
|
const firstChild = children[0];
|
|
1208
|
-
if (this._hierarchy === "storeys" &&
|
|
1208
|
+
if ((this._hierarchy === "storeys" || this._hierarchy === "containment") && firstChild.type === "IfcBuildingStorey") {
|
|
1209
1209
|
children.sort(this._getSpatialSortFunc());
|
|
1210
1210
|
} else {
|
|
1211
1211
|
children.sort(this._alphaSortFunc);
|
|
@@ -1216,21 +1216,11 @@ export class TreeViewPlugin extends Plugin {
|
|
|
1216
1216
|
}
|
|
1217
1217
|
}
|
|
1218
1218
|
|
|
1219
|
-
_getSpatialSortFunc() {
|
|
1219
|
+
_getSpatialSortFunc() {
|
|
1220
1220
|
const viewer = this.viewer;
|
|
1221
1221
|
const scene = viewer.scene;
|
|
1222
1222
|
const camera = scene.camera;
|
|
1223
|
-
|
|
1224
|
-
return this._spatialSortFunc || (this._spatialSortFunc = (node1, node2) => {
|
|
1225
|
-
if (!node1.aabb || !node2.aabb) {
|
|
1226
|
-
// Sorting on lowest point of the AABB is likely more more robust when objects could overlap storeys
|
|
1227
|
-
if (!node1.aabb) {
|
|
1228
|
-
node1.aabb = scene.getAABB(metaScene.getObjectIDsInSubtree(node1.objectId));
|
|
1229
|
-
}
|
|
1230
|
-
if (!node2.aabb) {
|
|
1231
|
-
node2.aabb = scene.getAABB(metaScene.getObjectIDsInSubtree(node2.objectId));
|
|
1232
|
-
}
|
|
1233
|
-
}
|
|
1223
|
+
return this._spatialSortFunc || (this._spatialSortFunc = (storey1, storey2) => {
|
|
1234
1224
|
let idx = 0;
|
|
1235
1225
|
if (camera.xUp) {
|
|
1236
1226
|
idx = 0;
|
|
@@ -1239,13 +1229,24 @@ export class TreeViewPlugin extends Plugin {
|
|
|
1239
1229
|
} else {
|
|
1240
1230
|
idx = 2;
|
|
1241
1231
|
}
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1232
|
+
const metaScene = this.viewer.metaScene;
|
|
1233
|
+
const storey1MetaObject = metaScene.metaObjects[storey1.objectId];
|
|
1234
|
+
const storey2MetaObject = metaScene.metaObjects[storey2.objectId];
|
|
1235
|
+
|
|
1236
|
+
if (storey1MetaObject && (storey1MetaObject.attributes && storey1MetaObject.attributes.elevation !== undefined) &&
|
|
1237
|
+
storey2MetaObject && (storey2MetaObject.attributes && storey2MetaObject.attributes.elevation !== undefined)) {
|
|
1238
|
+
const elevation1 = Number.parseFloat(storey1MetaObject.attributes.elevation);
|
|
1239
|
+
const elevation2 = Number.parseFloat(storey2MetaObject.attributes.elevation);
|
|
1240
|
+
if (elevation1 > elevation2) {
|
|
1241
|
+
return -1;
|
|
1242
|
+
}
|
|
1243
|
+
if (elevation1 < elevation2) {
|
|
1244
|
+
return 1;
|
|
1245
|
+
}
|
|
1246
|
+
return 0;
|
|
1247
|
+
} else {
|
|
1248
|
+
return 0;
|
|
1247
1249
|
}
|
|
1248
|
-
return 0;
|
|
1249
1250
|
});
|
|
1250
1251
|
}
|
|
1251
1252
|
|
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) => {
|
|
@@ -802,6 +893,12 @@ class CameraControl extends Component {
|
|
|
802
893
|
keyMap[this.AXIS_VIEW_FRONT] = [input.KEY_NUM_4];
|
|
803
894
|
keyMap[this.AXIS_VIEW_TOP] = [input.KEY_NUM_5];
|
|
804
895
|
keyMap[this.AXIS_VIEW_BOTTOM] = [input.KEY_NUM_6];
|
|
896
|
+
keyMap[this.MOUSE_PAN] = [
|
|
897
|
+
[input.MOUSE_LEFT_BUTTON, input.KEY_SHIFT],
|
|
898
|
+
this._configs.panRightClick ? input.MOUSE_RIGHT_BUTTON : input.MOUSE_MIDDLE_BUTTON
|
|
899
|
+
]
|
|
900
|
+
keyMap[this.MOUSE_ROTATE] = [input.MOUSE_LEFT_BUTTON];
|
|
901
|
+
keyMap[this.MOUSE_DOLLY] = [];
|
|
805
902
|
break;
|
|
806
903
|
|
|
807
904
|
case "azerty":
|
|
@@ -823,6 +920,12 @@ class CameraControl extends Component {
|
|
|
823
920
|
keyMap[this.AXIS_VIEW_FRONT] = [input.KEY_NUM_4];
|
|
824
921
|
keyMap[this.AXIS_VIEW_TOP] = [input.KEY_NUM_5];
|
|
825
922
|
keyMap[this.AXIS_VIEW_BOTTOM] = [input.KEY_NUM_6];
|
|
923
|
+
keyMap[this.MOUSE_PAN] = [
|
|
924
|
+
[input.MOUSE_LEFT_BUTTON, input.KEY_SHIFT],
|
|
925
|
+
this._configs.panRightClick ? input.MOUSE_RIGHT_BUTTON : input.MOUSE_MIDDLE_BUTTON
|
|
926
|
+
]
|
|
927
|
+
keyMap[this.MOUSE_ROTATE] = [input.MOUSE_LEFT_BUTTON];
|
|
928
|
+
keyMap[this.MOUSE_DOLLY] = [];
|
|
826
929
|
break;
|
|
827
930
|
}
|
|
828
931
|
|
|
@@ -842,6 +945,44 @@ class CameraControl extends Component {
|
|
|
842
945
|
return this._keyMap;
|
|
843
946
|
}
|
|
844
947
|
|
|
948
|
+
_areAllKeysDown(keyDownMap, keys) {
|
|
949
|
+
if (!keys || keys.length <= 0) {
|
|
950
|
+
return true;
|
|
951
|
+
}
|
|
952
|
+
if (!keyDownMap) {
|
|
953
|
+
return false;
|
|
954
|
+
}
|
|
955
|
+
for (let i = 0, len = keys.length; i < len; i++) {
|
|
956
|
+
const key = keys[i];
|
|
957
|
+
if (!keyDownMap[key])
|
|
958
|
+
return false;
|
|
959
|
+
}
|
|
960
|
+
return true;
|
|
961
|
+
}
|
|
962
|
+
|
|
963
|
+
_isAnyOtherKeyDown(keyDownMap, keyMap) {
|
|
964
|
+
for (let i = 0, len = keyDownMap.length; i < len; i++) {
|
|
965
|
+
if (keyDownMap[i]) {
|
|
966
|
+
if (Array.isArray(keyMap)) {
|
|
967
|
+
if (keyMap.indexOf(i) < 0) return true;
|
|
968
|
+
}
|
|
969
|
+
else if (i !== keyMap) return true;
|
|
970
|
+
}
|
|
971
|
+
}
|
|
972
|
+
return false;
|
|
973
|
+
}
|
|
974
|
+
|
|
975
|
+
_isMouseAction(action) {
|
|
976
|
+
switch (action) {
|
|
977
|
+
case this.MOUSE_ROTATE:
|
|
978
|
+
case this.MOUSE_DOLLY:
|
|
979
|
+
case this.MOUSE_PAN:
|
|
980
|
+
return true;
|
|
981
|
+
default:
|
|
982
|
+
return false;
|
|
983
|
+
}
|
|
984
|
+
}
|
|
985
|
+
|
|
845
986
|
/**
|
|
846
987
|
* Returns true if any keys configured for the given action are down.
|
|
847
988
|
* @param action
|
|
@@ -853,14 +994,21 @@ class CameraControl extends Component {
|
|
|
853
994
|
if (!keys) {
|
|
854
995
|
return false;
|
|
855
996
|
}
|
|
997
|
+
if (keys.length === 0 && this._isMouseAction(action)) return true;
|
|
856
998
|
if (!keyDownMap) {
|
|
857
999
|
keyDownMap = this.scene.input.keyDown;
|
|
858
1000
|
}
|
|
859
1001
|
for (let i = 0, len = keys.length; i < len; i++) {
|
|
860
1002
|
const key = keys[i];
|
|
861
|
-
if (
|
|
862
|
-
|
|
1003
|
+
if (!Array.isArray(key)) {
|
|
1004
|
+
if (keyDownMap[key] && !this._isAnyOtherKeyDown(keyDownMap, key))
|
|
1005
|
+
return true;
|
|
1006
|
+
}
|
|
1007
|
+
else {
|
|
1008
|
+
if (this._areAllKeysDown(keyDownMap, key) && !this._isAnyOtherKeyDown(keyDownMap, key))
|
|
1009
|
+
return true;
|
|
863
1010
|
}
|
|
1011
|
+
|
|
864
1012
|
}
|
|
865
1013
|
return false;
|
|
866
1014
|
}
|
|
@@ -1296,6 +1444,16 @@ class CameraControl extends Component {
|
|
|
1296
1444
|
*/
|
|
1297
1445
|
set panRightClick(value) {
|
|
1298
1446
|
this._configs.panRightClick = value !== false;
|
|
1447
|
+
const panKeyMap = this._keyMap[this.MOUSE_PAN];
|
|
1448
|
+
if (panKeyMap && panKeyMap.length > 0) {
|
|
1449
|
+
const input = this.scene.input;
|
|
1450
|
+
for (let i = 0, len = panKeyMap.length; i < len; i++) {
|
|
1451
|
+
if (this._configs.panRightClick && panKeyMap[i] === input.MOUSE_MIDDLE_BUTTON)
|
|
1452
|
+
this._keyMap[this.MOUSE_PAN][i] = input.MOUSE_RIGHT_BUTTON;
|
|
1453
|
+
else if (!this._configs.panRightClick && panKeyMap[i] === input.MOUSE_RIGHT_BUTTON)
|
|
1454
|
+
this._keyMap[this.MOUSE_PAN][i] = input.MOUSE_MIDDLE_BUTTON;
|
|
1455
|
+
}
|
|
1456
|
+
}
|
|
1299
1457
|
}
|
|
1300
1458
|
|
|
1301
1459
|
/**
|
|
@@ -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;
|
|
@@ -107,6 +108,15 @@ class MousePanRotateDollyHandler {
|
|
|
107
108
|
}
|
|
108
109
|
}
|
|
109
110
|
|
|
111
|
+
function isPanning() {
|
|
112
|
+
return cameraControl._isKeyDownForAction(cameraControl.MOUSE_PAN, keyDown);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function isRotating() {
|
|
116
|
+
return cameraControl._isKeyDownForAction(cameraControl.MOUSE_ROTATE, keyDown);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
|
|
110
120
|
canvas.addEventListener("mousedown", this._mouseDownHandler = (e) => {
|
|
111
121
|
|
|
112
122
|
if (!(configs.active && configs.pointerEnabled)) {
|
|
@@ -120,12 +130,14 @@ class MousePanRotateDollyHandler {
|
|
|
120
130
|
if (keyDown[scene.input.KEY_SHIFT] || configs.planView) {
|
|
121
131
|
|
|
122
132
|
mouseDownLeft = true;
|
|
133
|
+
keyDown[scene.input.MOUSE_LEFT_BUTTON] = true;
|
|
123
134
|
|
|
124
135
|
setMousedownState();
|
|
125
136
|
|
|
126
137
|
} else {
|
|
127
138
|
|
|
128
139
|
mouseDownLeft = true;
|
|
140
|
+
keyDown[scene.input.MOUSE_LEFT_BUTTON] = true;
|
|
129
141
|
|
|
130
142
|
setMousedownState(false);
|
|
131
143
|
}
|
|
@@ -135,6 +147,7 @@ class MousePanRotateDollyHandler {
|
|
|
135
147
|
case 2: // Middle/both buttons
|
|
136
148
|
|
|
137
149
|
mouseDownMiddle = true;
|
|
150
|
+
keyDown[scene.input.MOUSE_MIDDLE_BUTTON] = true;
|
|
138
151
|
|
|
139
152
|
setMousedownState();
|
|
140
153
|
|
|
@@ -143,6 +156,7 @@ class MousePanRotateDollyHandler {
|
|
|
143
156
|
case 3: // Right button
|
|
144
157
|
|
|
145
158
|
mouseDownRight = true;
|
|
159
|
+
keyDown[scene.input.MOUSE_RIGHT_BUTTON] = true;
|
|
146
160
|
|
|
147
161
|
if (configs.panRightClick) {
|
|
148
162
|
|
|
@@ -175,7 +189,8 @@ class MousePanRotateDollyHandler {
|
|
|
175
189
|
const x = states.pointerCanvasPos[0];
|
|
176
190
|
const y = states.pointerCanvasPos[1];
|
|
177
191
|
|
|
178
|
-
const panning =
|
|
192
|
+
const panning = isPanning();
|
|
193
|
+
const rotating = isRotating();
|
|
179
194
|
|
|
180
195
|
const xDelta = document.pointerLockElement ? e.movementX : (x - lastX);
|
|
181
196
|
const yDelta = document.pointerLockElement ? e.movementY : (y - lastY);
|
|
@@ -200,7 +215,7 @@ class MousePanRotateDollyHandler {
|
|
|
200
215
|
updates.panDeltaY += 0.5 * camera.ortho.scale * (yDelta / canvasHeight);
|
|
201
216
|
}
|
|
202
217
|
|
|
203
|
-
} else if (
|
|
218
|
+
} else if (rotating) {
|
|
204
219
|
|
|
205
220
|
if (!configs.planView) { // No rotating in plan-view mode
|
|
206
221
|
|
|
@@ -241,16 +256,25 @@ class MousePanRotateDollyHandler {
|
|
|
241
256
|
mouseDownLeft = false;
|
|
242
257
|
mouseDownMiddle = false;
|
|
243
258
|
mouseDownRight = false;
|
|
259
|
+
keyDown[scene.input.MOUSE_LEFT_BUTTON] = false;
|
|
260
|
+
keyDown[scene.input.MOUSE_MIDDLE_BUTTON] = false;
|
|
261
|
+
keyDown[scene.input.MOUSE_RIGHT_BUTTON] = false;
|
|
244
262
|
break;
|
|
245
263
|
case 2: // Middle/both buttons
|
|
246
264
|
mouseDownLeft = false;
|
|
247
265
|
mouseDownMiddle = false;
|
|
248
266
|
mouseDownRight = false;
|
|
267
|
+
keyDown[scene.input.MOUSE_LEFT_BUTTON] = false;
|
|
268
|
+
keyDown[scene.input.MOUSE_MIDDLE_BUTTON] = false;
|
|
269
|
+
keyDown[scene.input.MOUSE_RIGHT_BUTTON] = false;
|
|
249
270
|
break;
|
|
250
271
|
case 3: // Right button
|
|
251
272
|
mouseDownLeft = false;
|
|
252
273
|
mouseDownMiddle = false;
|
|
253
274
|
mouseDownRight = false;
|
|
275
|
+
keyDown[scene.input.MOUSE_LEFT_BUTTON] = false;
|
|
276
|
+
keyDown[scene.input.MOUSE_MIDDLE_BUTTON] = false;
|
|
277
|
+
keyDown[scene.input.MOUSE_RIGHT_BUTTON] = false;
|
|
254
278
|
break;
|
|
255
279
|
default:
|
|
256
280
|
break;
|
|
@@ -296,7 +320,7 @@ class MousePanRotateDollyHandler {
|
|
|
296
320
|
let secsNowLast = null;
|
|
297
321
|
|
|
298
322
|
canvas.addEventListener("wheel", this._mouseWheelHandler = (e) => {
|
|
299
|
-
if (!(configs.active && configs.pointerEnabled && configs.zoomOnMouseWheel)) {
|
|
323
|
+
if (!(configs.active && configs.pointerEnabled && configs.zoomOnMouseWheel && cameraControl._isKeyDownForAction(cameraControl.MOUSE_DOLLY, keyDown))) {
|
|
300
324
|
return;
|
|
301
325
|
}
|
|
302
326
|
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
|
*
|
|
@@ -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.
|