@xeokit/xeokit-sdk 2.4.2-beta-14 → 2.4.2-beta-15
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 +206 -69
- package/dist/xeokit-sdk.es.js +206 -69
- package/dist/xeokit-sdk.es5.js +318 -209
- package/dist/xeokit-sdk.min.cjs.js +2 -2
- package/dist/xeokit-sdk.min.es.js +2 -2
- package/dist/xeokit-sdk.min.es5.js +2 -2
- package/package.json +1 -1
- package/src/extras/MarqueePicker/MarqueePicker.js +81 -0
- package/src/extras/MarqueePicker/MarqueePickerMouseControl.js +2 -0
- package/src/extras/collision/ObjectsKdTree3.js +2 -0
- package/src/viewer/scene/CameraControl/lib/controllers/PickController.js +1 -22
- package/src/viewer/scene/CameraControl/lib/handlers/MousePickHandler.js +48 -45
- package/src/viewer/scene/input/Input.js +10 -2
- package/src/viewer/scene/scene/Scene.js +62 -0
package/dist/xeokit-sdk.cjs.js
CHANGED
|
@@ -6653,6 +6653,8 @@ const kdTreeDimLength$1 = new Float32Array(3);
|
|
|
6653
6653
|
* Automatically indexes a {@link Viewer}'s {@link Entity}s in a 3D k-d tree
|
|
6654
6654
|
* to support fast collision detection with 3D World-space axis-aligned boundaries (AABBs) and frustums.
|
|
6655
6655
|
*
|
|
6656
|
+
* See {@link MarqueePicker} for usage example.
|
|
6657
|
+
*
|
|
6656
6658
|
* An ObjectsKdTree3 is configured with a Viewer, and will then automatically
|
|
6657
6659
|
* keep itself populated with k-d nodes that contain the Viewer's Entitys.
|
|
6658
6660
|
*
|
|
@@ -8581,6 +8583,87 @@ function frustumIntersectsAABB3(frustum, aabb) {
|
|
|
8581
8583
|
|
|
8582
8584
|
/**
|
|
8583
8585
|
* Picks a {@link Viewer}'s {@link Entity}s with a canvas-space 2D marquee box.
|
|
8586
|
+
*
|
|
8587
|
+
* [<img src="https://xeokit.github.io/xeokit-sdk/assets/images/MarqueeSelect.gif">](https://xeokit.github.io/xeokit-sdk/examples/picking/#marqueePick_select)
|
|
8588
|
+
*
|
|
8589
|
+
* * [[Example 1: Select Objects with Marquee](https://xeokit.github.io/xeokit-sdk/examples/picking/#marqueePick_select)]
|
|
8590
|
+
* * [[Example 2: View-Fit Objects with Marquee](https://xeokit.github.io/xeokit-sdk/examples/picking/#marqueePick_viewFit)]
|
|
8591
|
+
*
|
|
8592
|
+
* # Usage
|
|
8593
|
+
*
|
|
8594
|
+
* In the example below, we
|
|
8595
|
+
*
|
|
8596
|
+
* 1. Create a {@link Viewer}, arrange the {@link Camera}
|
|
8597
|
+
* 2. Use an {@link XKTLoaderPlugin} to load a BIM model,
|
|
8598
|
+
* 3. Create a {@link ObjectsKdTree3} to automatically index the `Viewer's` {@link Entity}s for fast spatial lookup,
|
|
8599
|
+
* 4. Create a `MarqueePicker` to pick {@link Entity}s in the {@link Viewer}, using the {@link ObjectsKdTree3} to accelerate picking
|
|
8600
|
+
* 5. Create a {@link MarqueePickerMouseControl} to perform the marquee-picking with the `MarqueePicker`, using mouse input to draw the marquee box on the `Viewer's` canvas.
|
|
8601
|
+
*
|
|
8602
|
+
* When the {@link MarqueePickerMouseControl} is active:
|
|
8603
|
+
*
|
|
8604
|
+
* * Long-click, drag and release on the canvas to define a marque box that picks {@link Entity}s.
|
|
8605
|
+
* * Drag left-to-right to pick {@link Entity}s that intersect the box.
|
|
8606
|
+
* * Drag right-to-left to pick {@link Entity}s that are fully inside the box.
|
|
8607
|
+
* * On release, the `MarqueePicker` will fire a "picked" event with IDs of the picked {@link Entity}s, if any.
|
|
8608
|
+
* * Handling that event, we mark the {@link Entity}s as selected.
|
|
8609
|
+
* * Hold down CTRL to multi-pick.
|
|
8610
|
+
*
|
|
8611
|
+
* ````javascript
|
|
8612
|
+
* import {
|
|
8613
|
+
* Viewer,
|
|
8614
|
+
* XKTLoaderPlugin,
|
|
8615
|
+
* ObjectsKdTree3,
|
|
8616
|
+
* MarqueePicker,
|
|
8617
|
+
* MarqueePickerMouseControl
|
|
8618
|
+
* } from "xeokit-sdk.es.js";
|
|
8619
|
+
*
|
|
8620
|
+
* // 1
|
|
8621
|
+
*
|
|
8622
|
+
* const viewer = new Viewer({
|
|
8623
|
+
* canvasId: "myCanvas"
|
|
8624
|
+
* });
|
|
8625
|
+
*
|
|
8626
|
+
* viewer.scene.camera.eye = [14.9, 14.3, 5.4];
|
|
8627
|
+
* viewer.scene.camera.look = [6.5, 8.3, -4.1];
|
|
8628
|
+
* viewer.scene.camera.up = [-0.28, 0.9, -0.3];
|
|
8629
|
+
*
|
|
8630
|
+
* // 2
|
|
8631
|
+
*
|
|
8632
|
+
* const xktLoader = new XKTLoaderPlugin(viewer);
|
|
8633
|
+
*
|
|
8634
|
+
* const sceneModel = xktLoader.load({
|
|
8635
|
+
* id: "myModel",
|
|
8636
|
+
* src: "../../assets/models/xkt/v8/ifc/HolterTower.ifc.xkt"
|
|
8637
|
+
* });
|
|
8638
|
+
*
|
|
8639
|
+
* // 3
|
|
8640
|
+
*
|
|
8641
|
+
* const objectsKdTree3 = new ObjectsKdTree3({viewer});
|
|
8642
|
+
*
|
|
8643
|
+
* // 4
|
|
8644
|
+
*
|
|
8645
|
+
* const marqueePicker = new MarqueePicker({viewer, objectsKdTree3});
|
|
8646
|
+
*
|
|
8647
|
+
* // 5
|
|
8648
|
+
*
|
|
8649
|
+
* const marqueePickerMouseControl = new MarqueePickerMouseControl({marqueePicker});
|
|
8650
|
+
*
|
|
8651
|
+
* marqueePicker.on("clear", () => {
|
|
8652
|
+
* viewer.scene.setObjectsSelected(viewer.scene.selectedObjectIds, false);
|
|
8653
|
+
* });
|
|
8654
|
+
*
|
|
8655
|
+
* marqueePicker.on("picked", (objectIds) => {
|
|
8656
|
+
* viewer.scene.setObjectsSelected(objectIds, true);
|
|
8657
|
+
* });
|
|
8658
|
+
*
|
|
8659
|
+
* marqueePickerMouseControl.setActive(true);
|
|
8660
|
+
* ````
|
|
8661
|
+
*
|
|
8662
|
+
* # Design Notes
|
|
8663
|
+
*
|
|
8664
|
+
* * The {@link ObjectsKdTree3} can be shared with any other components that want to use it to spatially search for {@link Entity}s.
|
|
8665
|
+
* * The {@link MarqueePickerMouseControl} can be replaced with other types of controllers (i.e. touch), or used alongside them.
|
|
8666
|
+
* * The `MarqueePicker` has no input handlers of its own, and provides an API through which to programmatically control marquee picking. By firing the "picked" events, `MarqueePicker` implements the *Blackboard Pattern*.
|
|
8584
8667
|
*/
|
|
8585
8668
|
class MarqueePicker extends Component {
|
|
8586
8669
|
|
|
@@ -8850,6 +8933,8 @@ MarqueePicker.PICK_MODE_INSIDE = 1;
|
|
|
8850
8933
|
/**
|
|
8851
8934
|
* Controls a {@link MarqueePicker} with mouse input.
|
|
8852
8935
|
*
|
|
8936
|
+
* See {@link MarqueePicker} for usage example.
|
|
8937
|
+
*
|
|
8853
8938
|
* When the MarqueePickerMouseControl is active:
|
|
8854
8939
|
*
|
|
8855
8940
|
* * Long-click, drag and release on the canvas to define a marque box that picks {@link Entity}s.
|
|
@@ -20018,23 +20103,31 @@ class Input extends Component {
|
|
|
20018
20103
|
}
|
|
20019
20104
|
});
|
|
20020
20105
|
|
|
20106
|
+
const tickifedMouseMoveFn = this.scene.tickify(
|
|
20107
|
+
() => this.fire("mousemove", this.mouseCanvasPos, true)
|
|
20108
|
+
);
|
|
20109
|
+
|
|
20021
20110
|
this.element.addEventListener("mousemove", this._mouseMoveListener = (e) => {
|
|
20022
20111
|
if (!this.enabled) {
|
|
20023
20112
|
return;
|
|
20024
20113
|
}
|
|
20025
20114
|
this._getMouseCanvasPos(e);
|
|
20026
|
-
|
|
20115
|
+
tickifedMouseMoveFn();
|
|
20027
20116
|
if (this.mouseover) {
|
|
20028
20117
|
e.preventDefault();
|
|
20029
20118
|
}
|
|
20030
20119
|
});
|
|
20031
20120
|
|
|
20121
|
+
const tickifiedMouseWheelFn = this.scene.tickify(
|
|
20122
|
+
(delta) => { this.fire("mousewheel", delta, true); }
|
|
20123
|
+
);
|
|
20124
|
+
|
|
20032
20125
|
this.element.addEventListener("wheel", this._mouseWheelListener = (e, d) => {
|
|
20033
20126
|
if (!this.enabled) {
|
|
20034
20127
|
return;
|
|
20035
20128
|
}
|
|
20036
20129
|
const delta = Math.max(-1, Math.min(1, -e.deltaY * 40));
|
|
20037
|
-
|
|
20130
|
+
tickifiedMouseWheelFn(delta);
|
|
20038
20131
|
}, {passive: true});
|
|
20039
20132
|
|
|
20040
20133
|
// mouseclicked
|
|
@@ -27858,6 +27951,11 @@ class Scene extends Component {
|
|
|
27858
27951
|
throw "Mandatory config expected: valid canvasId or canvasElement";
|
|
27859
27952
|
}
|
|
27860
27953
|
|
|
27954
|
+
/**
|
|
27955
|
+
* @type {{[key: string]: {wrapperFunc: Function, tickSubId: string}}}
|
|
27956
|
+
*/
|
|
27957
|
+
this._tickifiedFunctions = {};
|
|
27958
|
+
|
|
27861
27959
|
const transparent = (!!cfg.transparent);
|
|
27862
27960
|
const alphaDepthMask = (!!cfg.alphaDepthMask);
|
|
27863
27961
|
|
|
@@ -30020,6 +30118,63 @@ class Scene extends Component {
|
|
|
30020
30118
|
return changed;
|
|
30021
30119
|
}
|
|
30022
30120
|
|
|
30121
|
+
/**
|
|
30122
|
+
* This method will "tickify" the provided `cb` function.
|
|
30123
|
+
*
|
|
30124
|
+
* This means, the function will be wrapped so:
|
|
30125
|
+
*
|
|
30126
|
+
* - it runs time-aligned to scene ticks
|
|
30127
|
+
* - it runs maximum once per scene-tick
|
|
30128
|
+
*
|
|
30129
|
+
* @param {Function} cb The function to tickify
|
|
30130
|
+
* @returns {Function)}
|
|
30131
|
+
*/
|
|
30132
|
+
tickify(cb) {
|
|
30133
|
+
const cbString = cb.toString();
|
|
30134
|
+
|
|
30135
|
+
/**
|
|
30136
|
+
* Check if the function is already tickified, and if so return the cached one.
|
|
30137
|
+
*/
|
|
30138
|
+
if (cbString in this._tickifiedFunctions) {
|
|
30139
|
+
return this._tickifiedFunctions[cbString].wrapperFunc;
|
|
30140
|
+
}
|
|
30141
|
+
|
|
30142
|
+
let alreadyRun = 0;
|
|
30143
|
+
let needToRun = 0;
|
|
30144
|
+
|
|
30145
|
+
let lastArgs;
|
|
30146
|
+
|
|
30147
|
+
/**
|
|
30148
|
+
* The provided `cb` function is replaced with a "set-dirty" function
|
|
30149
|
+
*
|
|
30150
|
+
* @type {Function}
|
|
30151
|
+
*/
|
|
30152
|
+
const wrapperFunc = function (...args) {
|
|
30153
|
+
lastArgs = args;
|
|
30154
|
+
needToRun++;
|
|
30155
|
+
};
|
|
30156
|
+
|
|
30157
|
+
/**
|
|
30158
|
+
* An each scene tick, if the "dirty-flag" is set, run the `cb` function.
|
|
30159
|
+
*
|
|
30160
|
+
* This will make it run time-aligned to the scene tick.
|
|
30161
|
+
*/
|
|
30162
|
+
const tickSubId = this.on("tick", () => {
|
|
30163
|
+
const tmp = needToRun;
|
|
30164
|
+
if (tmp > alreadyRun) {
|
|
30165
|
+
alreadyRun = tmp;
|
|
30166
|
+
cb(...lastArgs);
|
|
30167
|
+
}
|
|
30168
|
+
});
|
|
30169
|
+
|
|
30170
|
+
/**
|
|
30171
|
+
* And, store the list of subscribers.
|
|
30172
|
+
*/
|
|
30173
|
+
this._tickifiedFunctions[cbString] = { tickSubId, wrapperFunc };
|
|
30174
|
+
|
|
30175
|
+
return wrapperFunc;
|
|
30176
|
+
}
|
|
30177
|
+
|
|
30023
30178
|
/**
|
|
30024
30179
|
* Destroys this Scene.
|
|
30025
30180
|
*/
|
|
@@ -87287,29 +87442,12 @@ class PickController {
|
|
|
87287
87442
|
this._lastPickedEntityId = null;
|
|
87288
87443
|
|
|
87289
87444
|
this._needFireEvents = 0;
|
|
87290
|
-
|
|
87291
|
-
this._needToUpdate = false;
|
|
87292
|
-
|
|
87293
|
-
this._tickSub = this._scene.on("tick", () => {
|
|
87294
|
-
this.runUpdate();
|
|
87295
|
-
});
|
|
87296
|
-
}
|
|
87297
|
-
|
|
87298
|
-
update() {
|
|
87299
|
-
this._needToUpdate = true;
|
|
87300
87445
|
}
|
|
87301
87446
|
|
|
87302
87447
|
/**
|
|
87303
87448
|
* Immediately attempts a pick, if scheduled.
|
|
87304
87449
|
*/
|
|
87305
|
-
|
|
87306
|
-
|
|
87307
|
-
if (!this._needToUpdate) {
|
|
87308
|
-
return;
|
|
87309
|
-
}
|
|
87310
|
-
|
|
87311
|
-
this._needToUpdate = false;
|
|
87312
|
-
|
|
87450
|
+
update() {
|
|
87313
87451
|
if (!this._configs.pointerEnabled) {
|
|
87314
87452
|
return;
|
|
87315
87453
|
}
|
|
@@ -87484,10 +87622,6 @@ class PickController {
|
|
|
87484
87622
|
|
|
87485
87623
|
this._needFireEvents = 0;
|
|
87486
87624
|
}
|
|
87487
|
-
|
|
87488
|
-
destroy() {
|
|
87489
|
-
this._scene.off(this._tickSub);
|
|
87490
|
-
}
|
|
87491
87625
|
}
|
|
87492
87626
|
|
|
87493
87627
|
/**
|
|
@@ -87982,75 +88116,78 @@ class MousePickHandler {
|
|
|
87982
88116
|
}
|
|
87983
88117
|
};
|
|
87984
88118
|
|
|
87985
|
-
|
|
88119
|
+
const tickifiedMouseMoveFn = scene.tickify (
|
|
88120
|
+
this._canvasMouseMoveHandler = (e) => {
|
|
88121
|
+
if (!(configs.active && configs.pointerEnabled)) {
|
|
88122
|
+
return;
|
|
88123
|
+
}
|
|
87986
88124
|
|
|
87987
|
-
|
|
87988
|
-
|
|
87989
|
-
|
|
88125
|
+
if (leftDown || rightDown) {
|
|
88126
|
+
return;
|
|
88127
|
+
}
|
|
87990
88128
|
|
|
87991
|
-
|
|
87992
|
-
|
|
87993
|
-
|
|
88129
|
+
const hoverSubs = cameraControl.hasSubs("hover");
|
|
88130
|
+
const hoverEnterSubs = cameraControl.hasSubs("hoverEnter");
|
|
88131
|
+
const hoverOutSubs = cameraControl.hasSubs("hoverOut");
|
|
88132
|
+
const hoverOffSubs = cameraControl.hasSubs("hoverOff");
|
|
88133
|
+
const hoverSurfaceSubs = cameraControl.hasSubs("hoverSurface");
|
|
88134
|
+
const hoverSnapOrSurfaceSubs = cameraControl.hasSubs("hoverSnapOrSurface");
|
|
87994
88135
|
|
|
87995
|
-
|
|
87996
|
-
const hoverEnterSubs = cameraControl.hasSubs("hoverEnter");
|
|
87997
|
-
const hoverOutSubs = cameraControl.hasSubs("hoverOut");
|
|
87998
|
-
const hoverOffSubs = cameraControl.hasSubs("hoverOff");
|
|
87999
|
-
const hoverSurfaceSubs = cameraControl.hasSubs("hoverSurface");
|
|
88000
|
-
const hoverSnapOrSurfaceSubs = cameraControl.hasSubs("hoverSnapOrSurface");
|
|
88136
|
+
if (hoverSubs || hoverEnterSubs || hoverOutSubs || hoverOffSubs || hoverSurfaceSubs || hoverSnapOrSurfaceSubs) {
|
|
88001
88137
|
|
|
88002
|
-
|
|
88138
|
+
pickController.pickCursorPos = states.pointerCanvasPos;
|
|
88139
|
+
pickController.schedulePickEntity = true;
|
|
88140
|
+
pickController.schedulePickSurface = hoverSurfaceSubs;
|
|
88141
|
+
pickController.scheduleSnapOrPick = hoverSnapOrSurfaceSubs;
|
|
88003
88142
|
|
|
88004
|
-
|
|
88005
|
-
pickController.schedulePickEntity = true;
|
|
88006
|
-
pickController.schedulePickSurface = hoverSurfaceSubs;
|
|
88007
|
-
pickController.scheduleSnapOrPick = hoverSnapOrSurfaceSubs;
|
|
88143
|
+
pickController.update();
|
|
88008
88144
|
|
|
88009
|
-
|
|
88145
|
+
if (pickController.pickResult) {
|
|
88010
88146
|
|
|
88011
|
-
|
|
88147
|
+
if (pickController.pickResult.entity) {
|
|
88148
|
+
const pickedEntityId = pickController.pickResult.entity.id;
|
|
88149
|
+
|
|
88150
|
+
if (this._lastPickedEntityId !== pickedEntityId) {
|
|
88012
88151
|
|
|
88013
|
-
|
|
88014
|
-
const pickedEntityId = pickController.pickResult.entity.id;
|
|
88152
|
+
if (this._lastPickedEntityId !== undefined) {
|
|
88015
88153
|
|
|
88016
|
-
|
|
88154
|
+
cameraControl.fire("hoverOut", { // Hovered off an entity
|
|
88155
|
+
entity: scene.objects[this._lastPickedEntityId]
|
|
88156
|
+
}, true);
|
|
88157
|
+
}
|
|
88017
88158
|
|
|
88018
|
-
|
|
88159
|
+
cameraControl.fire("hoverEnter", pickController.pickResult, true); // Hovering over a new entity
|
|
88019
88160
|
|
|
88020
|
-
|
|
88021
|
-
entity: scene.objects[this._lastPickedEntityId]
|
|
88022
|
-
}, true);
|
|
88161
|
+
this._lastPickedEntityId = pickedEntityId;
|
|
88023
88162
|
}
|
|
88163
|
+
}
|
|
88024
88164
|
|
|
88025
|
-
|
|
88165
|
+
cameraControl.fire("hover", pickController.pickResult, true);
|
|
88026
88166
|
|
|
88027
|
-
|
|
88167
|
+
if (pickController.pickResult.worldPos || pickController.pickResult.snappedWorldPos) { // Hovering the surface of an entity
|
|
88168
|
+
cameraControl.fire("hoverSurface", pickController.pickResult, true);
|
|
88028
88169
|
}
|
|
88029
|
-
}
|
|
88030
88170
|
|
|
88031
|
-
|
|
88171
|
+
} else {
|
|
88032
88172
|
|
|
88033
|
-
|
|
88034
|
-
cameraControl.fire("hoverSurface", pickController.pickResult, true);
|
|
88035
|
-
}
|
|
88173
|
+
if (this._lastPickedEntityId !== undefined) {
|
|
88036
88174
|
|
|
88037
|
-
|
|
88175
|
+
cameraControl.fire("hoverOut", { // Hovered off an entity
|
|
88176
|
+
entity: scene.objects[this._lastPickedEntityId]
|
|
88177
|
+
}, true);
|
|
88038
88178
|
|
|
88039
|
-
|
|
88179
|
+
this._lastPickedEntityId = undefined;
|
|
88180
|
+
}
|
|
88040
88181
|
|
|
88041
|
-
cameraControl.fire("
|
|
88042
|
-
|
|
88182
|
+
cameraControl.fire("hoverOff", { // Not hovering on any entity
|
|
88183
|
+
canvasPos: pickController.pickCursorPos
|
|
88043
88184
|
}, true);
|
|
88044
|
-
|
|
88045
|
-
this._lastPickedEntityId = undefined;
|
|
88046
88185
|
}
|
|
88047
|
-
|
|
88048
|
-
cameraControl.fire("hoverOff", { // Not hovering on any entity
|
|
88049
|
-
canvasPos: pickController.pickCursorPos
|
|
88050
|
-
}, true);
|
|
88051
88186
|
}
|
|
88052
88187
|
}
|
|
88053
|
-
|
|
88188
|
+
);
|
|
88189
|
+
|
|
88190
|
+
canvas.addEventListener("mousemove", tickifiedMouseMoveFn);
|
|
88054
88191
|
|
|
88055
88192
|
canvas.addEventListener('mousedown', this._canvasMouseDownHandler = (e) => {
|
|
88056
88193
|
|