@xeokit/xeokit-sdk 2.4.2-beta-14 → 2.4.2-beta-19

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xeokit/xeokit-sdk",
3
- "version": "2.4.2-beta-14",
3
+ "version": "2.4.2-beta-19",
4
4
  "description": "Web Programming Toolkit for 3D/2D BIM and AEC Graphics",
5
5
  "module": "./dist/xeokit-sdk.es.js",
6
6
  "main": "./dist/xeokit-sdk.cjs.js",
@@ -4,6 +4,87 @@ import {Frustum, frustumIntersectsAABB3, setFrustum} from "../../viewer/scene/ma
4
4
 
5
5
  /**
6
6
  * Picks a {@link Viewer}'s {@link Entity}s with a canvas-space 2D marquee box.
7
+ *
8
+ * [<img src="https://xeokit.github.io/xeokit-sdk/assets/images/MarqueeSelect.gif">](https://xeokit.github.io/xeokit-sdk/examples/picking/#marqueePick_select)
9
+ *
10
+ * * [[Example 1: Select Objects with Marquee](https://xeokit.github.io/xeokit-sdk/examples/picking/#marqueePick_select)]
11
+ * * [[Example 2: View-Fit Objects with Marquee](https://xeokit.github.io/xeokit-sdk/examples/picking/#marqueePick_viewFit)]
12
+ *
13
+ * # Usage
14
+ *
15
+ * In the example below, we
16
+ *
17
+ * 1. Create a {@link Viewer}, arrange the {@link Camera}
18
+ * 2. Use an {@link XKTLoaderPlugin} to load a BIM model,
19
+ * 3. Create a {@link ObjectsKdTree3} to automatically index the `Viewer's` {@link Entity}s for fast spatial lookup,
20
+ * 4. Create a `MarqueePicker` to pick {@link Entity}s in the {@link Viewer}, using the {@link ObjectsKdTree3} to accelerate picking
21
+ * 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.
22
+ *
23
+ * When the {@link MarqueePickerMouseControl} is active:
24
+ *
25
+ * * Long-click, drag and release on the canvas to define a marque box that picks {@link Entity}s.
26
+ * * Drag left-to-right to pick {@link Entity}s that intersect the box.
27
+ * * Drag right-to-left to pick {@link Entity}s that are fully inside the box.
28
+ * * On release, the `MarqueePicker` will fire a "picked" event with IDs of the picked {@link Entity}s, if any.
29
+ * * Handling that event, we mark the {@link Entity}s as selected.
30
+ * * Hold down CTRL to multi-pick.
31
+ *
32
+ * ````javascript
33
+ * import {
34
+ * Viewer,
35
+ * XKTLoaderPlugin,
36
+ * ObjectsKdTree3,
37
+ * MarqueePicker,
38
+ * MarqueePickerMouseControl
39
+ * } from "xeokit-sdk.es.js";
40
+ *
41
+ * // 1
42
+ *
43
+ * const viewer = new Viewer({
44
+ * canvasId: "myCanvas"
45
+ * });
46
+ *
47
+ * viewer.scene.camera.eye = [14.9, 14.3, 5.4];
48
+ * viewer.scene.camera.look = [6.5, 8.3, -4.1];
49
+ * viewer.scene.camera.up = [-0.28, 0.9, -0.3];
50
+ *
51
+ * // 2
52
+ *
53
+ * const xktLoader = new XKTLoaderPlugin(viewer);
54
+ *
55
+ * const sceneModel = xktLoader.load({
56
+ * id: "myModel",
57
+ * src: "../../assets/models/xkt/v8/ifc/HolterTower.ifc.xkt"
58
+ * });
59
+ *
60
+ * // 3
61
+ *
62
+ * const objectsKdTree3 = new ObjectsKdTree3({viewer});
63
+ *
64
+ * // 4
65
+ *
66
+ * const marqueePicker = new MarqueePicker({viewer, objectsKdTree3});
67
+ *
68
+ * // 5
69
+ *
70
+ * const marqueePickerMouseControl = new MarqueePickerMouseControl({marqueePicker});
71
+ *
72
+ * marqueePicker.on("clear", () => {
73
+ * viewer.scene.setObjectsSelected(viewer.scene.selectedObjectIds, false);
74
+ * });
75
+ *
76
+ * marqueePicker.on("picked", (objectIds) => {
77
+ * viewer.scene.setObjectsSelected(objectIds, true);
78
+ * });
79
+ *
80
+ * marqueePickerMouseControl.setActive(true);
81
+ * ````
82
+ *
83
+ * # Design Notes
84
+ *
85
+ * * The {@link ObjectsKdTree3} can be shared with any other components that want to use it to spatially search for {@link Entity}s.
86
+ * * The {@link MarqueePickerMouseControl} can be replaced with other types of controllers (i.e. touch), or used alongside them.
87
+ * * 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*.
7
88
  */
8
89
  export class MarqueePicker extends Component {
9
90
 
@@ -4,6 +4,8 @@ import {MarqueePicker} from "./MarqueePicker";
4
4
  /**
5
5
  * Controls a {@link MarqueePicker} with mouse input.
6
6
  *
7
+ * See {@link MarqueePicker} for usage example.
8
+ *
7
9
  * When the MarqueePickerMouseControl is active:
8
10
  *
9
11
  * * Long-click, drag and release on the canvas to define a marque box that picks {@link Entity}s.
@@ -93,8 +93,8 @@ export class PointerLens {
93
93
  this._lensCanvasContext = this._lensCanvas.getContext('2d');
94
94
  this._canvasElement = this.viewer.scene.canvas.canvas;
95
95
 
96
- this._centerPos = null;
97
- this._cursorPos = null;
96
+ this._canvasPos = null;
97
+ this._snappedCanvasPos = null;
98
98
  this._lensPosToggle = true;
99
99
 
100
100
  this._zoomLevel = cfg.zoomLevel || 2;
@@ -117,14 +117,14 @@ export class PointerLens {
117
117
  if (!this._active || !this._visible) {
118
118
  return;
119
119
  }
120
- if (!this._centerPos) {
120
+ if (!this._canvasPos) {
121
121
  return;
122
122
  }
123
123
  const lensRect = this._lensContainer.getBoundingClientRect();
124
124
  const canvasRect = this._canvasElement.getBoundingClientRect();
125
125
  const pointerOnLens =
126
- this._centerPos[0] < lensRect.right && this._centerPos[0] > lensRect.left &&
127
- this._centerPos[1] < lensRect.bottom && this._centerPos[1] > lensRect.top;
126
+ this._canvasPos[0] < lensRect.right && this._canvasPos[0] > lensRect.left &&
127
+ this._canvasPos[1] < lensRect.bottom && this._canvasPos[1] > lensRect.top;
128
128
  this._lensContainer.style.marginLeft = `25px`;
129
129
  if (pointerOnLens) {
130
130
  if (this._lensPosToggle) {
@@ -138,8 +138,8 @@ export class PointerLens {
138
138
  const size = Math.max(this._lensCanvas.width, this._lensCanvas.height) / this._zoomLevel;
139
139
  this._lensCanvasContext.drawImage(
140
140
  this._canvasElement, // source canvas
141
- this._centerPos[0] - size / 2, // source x (zoom center)
142
- this._centerPos[1] - size / 2, // source y (zoom center)
141
+ this._canvasPos[0] - size / 2, // source x (zoom center)
142
+ this._canvasPos[1] - size / 2, // source y (zoom center)
143
143
  size, // source width
144
144
  size, // source height
145
145
  0, // destination x
@@ -153,9 +153,9 @@ export class PointerLens {
153
153
  (lensRect.top + lensRect.bottom) / 2
154
154
  ];
155
155
 
156
- if (this._cursorPos) {
157
- const deltaX = this._cursorPos[0] - this._centerPos[0];
158
- const deltaY = this._cursorPos[1] - this._centerPos[1];
156
+ if (this._snappedCanvasPos) {
157
+ const deltaX = this._snappedCanvasPos[0] - this._canvasPos[0];
158
+ const deltaY = this._snappedCanvasPos[1] - this._canvasPos[1];
159
159
 
160
160
  this._lensCursorDiv.style.marginLeft = `${centerLensCanvas[0] + deltaX * this._zoomLevel - 10}px`;
161
161
  this._lensCursorDiv.style.marginTop = `${centerLensCanvas[1] + deltaY * this._zoomLevel - 10}px`;
@@ -191,10 +191,10 @@ export class PointerLens {
191
191
 
192
192
  /**
193
193
  * Sets the canvas central position of the lens.
194
- * @param centerPos
194
+ * @param canvasPos
195
195
  */
196
- set centerPos(centerPos) {
197
- this._centerPos = centerPos;
196
+ set canvasPos(canvasPos) {
197
+ this._canvasPos = canvasPos;
198
198
  this.update();
199
199
  }
200
200
 
@@ -202,25 +202,25 @@ export class PointerLens {
202
202
  * Gets the canvas central position of the lens.
203
203
  * @returns {Number[]}
204
204
  */
205
- get centerPos() {
206
- return this._centerPos;
205
+ get canvasPos() {
206
+ return this._canvasPos;
207
207
  }
208
208
 
209
209
  /**
210
210
  * Sets the canvas coordinates of the pointer.
211
- * @param cursorPos
211
+ * @param snappedCanvasPos
212
212
  */
213
- set cursorPos(cursorPos) {
214
- this._cursorPos = cursorPos;
213
+ set snappedCanvasPos(snappedCanvasPos) {
214
+ this._snappedCanvasPos = snappedCanvasPos;
215
215
  this.update();
216
216
  }
217
217
 
218
218
  /**
219
- * Gets the canvas coordinates of the pointer.
219
+ * Gets the canvas coordinates of the snapped pointer.
220
220
  * @returns {Number[]}
221
221
  */
222
- get cursorPos() {
223
- return this._cursorPos;
222
+ get snappedCanvasPos() {
223
+ return this._snappedCanvasPos;
224
224
  }
225
225
 
226
226
  /**
@@ -7,6 +7,8 @@ const kdTreeDimLength = new Float32Array(3);
7
7
  * Automatically indexes a {@link Viewer}'s {@link Entity}s in a 3D k-d tree
8
8
  * to support fast collision detection with 3D World-space axis-aligned boundaries (AABBs) and frustums.
9
9
  *
10
+ * See {@link MarqueePicker} for usage example.
11
+ *
10
12
  * An ObjectsKdTree3 is configured with a Viewer, and will then automatically
11
13
  * keep itself populated with k-d nodes that contain the Viewer's Entitys.
12
14
  *
@@ -177,8 +177,8 @@ export class AngleMeasurementsMouseControl extends AngleMeasurementsControl {
177
177
  if (event.snappedToVertex || event.snappedToEdge) {
178
178
  if (pointerLens) {
179
179
  pointerLens.visible = true;
180
- pointerLens.centerPos = event.cursorPos || event.canvasPos;
181
- pointerLens.cursorPos = event.canvasPos;
180
+ pointerLens.canvasPos = event.canvasPos;
181
+ pointerLens.snappedCanvasPos = event.snappedCanvasPos || event.canvasPos;
182
182
  pointerLens.snapped = true;
183
183
  }
184
184
  this.markerDiv.style.background = "greenyellow";
@@ -186,21 +186,22 @@ export class AngleMeasurementsMouseControl extends AngleMeasurementsControl {
186
186
  } else {
187
187
  if (pointerLens) {
188
188
  pointerLens.visible = true;
189
- pointerLens.centerPos = event.cursorPos || event.canvasPos;
190
- pointerLens.cursorPos = event.canvasPos;
189
+ pointerLens.canvasPos = event.canvasPos;
190
+ pointerLens.snappedCanvasPos = event.canvasPos;
191
191
  pointerLens.snapped = false;
192
192
  }
193
193
  this.markerDiv.style.background = "pink";
194
194
  this.markerDiv.style.border = "2px solid red";
195
195
  }
196
+ const canvasPos = event.snappedCanvasPos || event.canvasPos;
196
197
  mouseHovering = true;
197
198
  mouseHoverEntity = event.entity;
198
199
  mouseWorldPos.set(event.worldPos);
199
- mouseHoverCanvasPos.set(event.canvasPos);
200
+ mouseHoverCanvasPos.set(canvasPos);
200
201
  switch (this._mouseState) {
201
202
  case MOUSE_FINDING_ORIGIN:
202
- this.markerDiv.style.marginLeft = `${event.canvasPos[0] - 5}px`;
203
- this.markerDiv.style.marginTop = `${event.canvasPos[1] - 5}px`;
203
+ this.markerDiv.style.marginLeft = `${canvasPos[0] - 5}px`;
204
+ this.markerDiv.style.marginTop = `${canvasPos[1] - 5}px`;
204
205
  break;
205
206
  case MOUSE_FINDING_CORNER:
206
207
  if (this._currentAngleMeasurement) {
@@ -316,8 +317,8 @@ export class AngleMeasurementsMouseControl extends AngleMeasurementsControl {
316
317
  mouseHovering = false;
317
318
  if (pointerLens) {
318
319
  pointerLens.visible = true;
319
- pointerLens.centerPos = event.cursorPos;
320
- pointerLens.cursorPos = event.cursorPos;
320
+ pointerLens.pointerPos = event.canvasPos;
321
+ pointerLens.snappedCanvasPos = event.snappedCanvasPos || event.canvasPos;
321
322
  pointerLens.snapped = false;
322
323
  }
323
324
  this.markerDiv.style.marginLeft = `-100px`;
@@ -181,18 +181,19 @@ export class DistanceMeasurementsMouseControl extends DistanceMeasurementsContro
181
181
  this._snapping
182
182
  ? "hoverSnapOrSurface"
183
183
  : "hoverSurface", event => {
184
+ const canvasPos = event.snappedCanvasPos || event.canvasPos;
184
185
  mouseHovering = true;
185
186
  pointerWorldPos.set(event.worldPos);
186
187
  pointerCanvasPos.set(event.canvasPos);
187
188
  if (this._mouseState === MOUSE_FIRST_CLICK_EXPECTED) {
188
- this._markerDiv.style.marginLeft = `${event.canvasPos[0] - 5}px`;
189
- this._markerDiv.style.marginTop = `${event.canvasPos[1] - 5}px`;
189
+ this._markerDiv.style.marginLeft = `${canvasPos[0] - 5}px`;
190
+ this._markerDiv.style.marginTop = `${canvasPos[1] - 5}px`;
190
191
  this._markerDiv.style.background = "pink";
191
192
  if (event.snappedToVertex || event.snappedToEdge) {
192
193
  if (this.pointerLens) {
193
194
  this.pointerLens.visible = true;
194
- this.pointerLens.centerPos = event.cursorPos || event.canvasPos;
195
- this.pointerLens.cursorPos = event.canvasPos;
195
+ this.pointerLens.canvasPos = event.canvasPos;
196
+ this.pointerLens.snappedCanvasPos = event.snappedCanvasPos || event.canvasPos;
196
197
  this.pointerLens.snapped = true;
197
198
  }
198
199
  this._markerDiv.style.background = "greenyellow";
@@ -200,8 +201,8 @@ export class DistanceMeasurementsMouseControl extends DistanceMeasurementsContro
200
201
  } else {
201
202
  if (this.pointerLens) {
202
203
  this.pointerLens.visible = true;
203
- this.pointerLens.centerPos = event.cursorPos || event.canvasPos;
204
- this.pointerLens.cursorPos = event.canvasPos;
204
+ this.pointerLens.canvasPos = event.canvasPos;
205
+ this.pointerLens.snappedCanvasPos = event.canvasPos;
205
206
  this.pointerLens.snapped = false;
206
207
  }
207
208
  this._markerDiv.style.background = "pink";
@@ -283,8 +284,8 @@ export class DistanceMeasurementsMouseControl extends DistanceMeasurementsContro
283
284
  : "hoverOff", event => {
284
285
  if (this.pointerLens) {
285
286
  this.pointerLens.visible = true;
286
- this.pointerLens.centerPos = event.cursorPos || event.canvasPos;
287
- this.pointerLens.cursorPos = event.canvasPos;
287
+ this.pointerLens.canvasPos = event.canvasPos;
288
+ this.pointerLens.snappedCanvasPos = event.snappedCanvasPos || event.canvasPos;
288
289
  }
289
290
  mouseHovering = false;
290
291
  this._markerDiv.style.marginLeft = `-100px`;
@@ -70,29 +70,12 @@ class PickController {
70
70
  this._lastPickedEntityId = null;
71
71
 
72
72
  this._needFireEvents = 0;
73
-
74
- this._needToUpdate = false;
75
-
76
- this._tickSub = this._scene.on("tick", () => {
77
- this.runUpdate();
78
- });
79
- }
80
-
81
- update() {
82
- this._needToUpdate = true;
83
73
  }
84
74
 
85
75
  /**
86
76
  * Immediately attempts a pick, if scheduled.
87
77
  */
88
- runUpdate() {
89
-
90
- if (!this._needToUpdate) {
91
- return;
92
- }
93
-
94
- this._needToUpdate = false;
95
-
78
+ update() {
96
79
  if (!this._configs.pointerEnabled) {
97
80
  return;
98
81
  }
@@ -109,13 +92,13 @@ class PickController {
109
92
  const hasHoverSurfaceSubs = this._cameraControl.hasSubs("hoverSurface");
110
93
 
111
94
  if (this.scheduleSnapOrPick) {
112
- const snapPickResult = this._scene.snapPick({
95
+ const snapPickResult = this._scene.pick({
113
96
  canvasPos: this.pickCursorPos,
114
97
  snapRadius: this._configs.snapRadius,
115
98
  snapToVertex: this._configs.snapToVertex,
116
99
  snapToEdge: this._configs.snapToEdge,
117
100
  });
118
- if (snapPickResult && snapPickResult.snappedWorldPos) {
101
+ if (snapPickResult && (snapPickResult.snappedToEdge || snapPickResult.snappedToVertex)) {
119
102
  this.snapPickResult = snapPickResult;
120
103
  this.snappedOrPicked = true;
121
104
  this._needFireEvents++;
@@ -197,14 +180,14 @@ class PickController {
197
180
 
198
181
  fireEvents() {
199
182
 
200
- if (this._needFireEvents == 0) {
183
+ if (this._needFireEvents === 0) {
201
184
  return;
202
185
  }
203
186
 
204
187
  if (this.hoveredSnappedOrSurfaceOff) {
205
188
  this._cameraControl.fire("hoverSnapOrSurfaceOff", {
206
189
  canvasPos: this.pickCursorPos,
207
- cursorPos : this.pickCursorPos
190
+ pointerPos : this.pickCursorPos
208
191
  }, true);
209
192
  }
210
193
 
@@ -213,9 +196,9 @@ class PickController {
213
196
  const pickResult = new PickResult();
214
197
  pickResult.snappedToVertex = this.snapPickResult.snappedToVertex;
215
198
  pickResult.snappedToEdge = this.snapPickResult.snappedToEdge;
216
- pickResult.worldPos = this.snapPickResult.snappedWorldPos;
217
- pickResult.cursorPos = this.pickCursorPos;
218
- pickResult.canvasPos = this.snapPickResult.snappedCanvasPos;
199
+ pickResult.worldPos = this.snapPickResult.worldPos;
200
+ pickResult.canvasPos = this.pickCursorPos
201
+ pickResult.snappedCanvasPos = this.snapPickResult.snappedCanvasPos;
219
202
  this._cameraControl.fire("hoverSnapOrSurface", pickResult, true);
220
203
  this.snapPickResult = null;
221
204
  } else {
@@ -269,10 +252,6 @@ class PickController {
269
252
 
270
253
  this._needFireEvents = 0;
271
254
  }
272
-
273
- destroy() {
274
- this._scene.off(this._tickSub);
275
- }
276
255
  }
277
256
 
278
257
  export {PickController};
@@ -45,75 +45,78 @@ class MousePickHandler {
45
45
  }
46
46
  };
47
47
 
48
- canvas.addEventListener("mousemove", this._canvasMouseMoveHandler = (e) => {
48
+ const tickifiedMouseMoveFn = scene.tickify (
49
+ this._canvasMouseMoveHandler = (e) => {
50
+ if (!(configs.active && configs.pointerEnabled)) {
51
+ return;
52
+ }
49
53
 
50
- if (!(configs.active && configs.pointerEnabled)) {
51
- return;
52
- }
54
+ if (leftDown || rightDown) {
55
+ return;
56
+ }
53
57
 
54
- if (leftDown || rightDown) {
55
- return;
56
- }
58
+ const hoverSubs = cameraControl.hasSubs("hover");
59
+ const hoverEnterSubs = cameraControl.hasSubs("hoverEnter");
60
+ const hoverOutSubs = cameraControl.hasSubs("hoverOut");
61
+ const hoverOffSubs = cameraControl.hasSubs("hoverOff");
62
+ const hoverSurfaceSubs = cameraControl.hasSubs("hoverSurface");
63
+ const hoverSnapOrSurfaceSubs = cameraControl.hasSubs("hoverSnapOrSurface");
57
64
 
58
- const hoverSubs = cameraControl.hasSubs("hover");
59
- const hoverEnterSubs = cameraControl.hasSubs("hoverEnter");
60
- const hoverOutSubs = cameraControl.hasSubs("hoverOut");
61
- const hoverOffSubs = cameraControl.hasSubs("hoverOff");
62
- const hoverSurfaceSubs = cameraControl.hasSubs("hoverSurface");
63
- const hoverSnapOrSurfaceSubs = cameraControl.hasSubs("hoverSnapOrSurface");
65
+ if (hoverSubs || hoverEnterSubs || hoverOutSubs || hoverOffSubs || hoverSurfaceSubs || hoverSnapOrSurfaceSubs) {
64
66
 
65
- if (hoverSubs || hoverEnterSubs || hoverOutSubs || hoverOffSubs || hoverSurfaceSubs || hoverSnapOrSurfaceSubs) {
67
+ pickController.pickCursorPos = states.pointerCanvasPos;
68
+ pickController.schedulePickEntity = true;
69
+ pickController.schedulePickSurface = hoverSurfaceSubs;
70
+ pickController.scheduleSnapOrPick = hoverSnapOrSurfaceSubs
66
71
 
67
- pickController.pickCursorPos = states.pointerCanvasPos;
68
- pickController.schedulePickEntity = true;
69
- pickController.schedulePickSurface = hoverSurfaceSubs;
70
- pickController.scheduleSnapOrPick = hoverSnapOrSurfaceSubs
72
+ pickController.update();
71
73
 
72
- pickController.update();
74
+ if (pickController.pickResult) {
73
75
 
74
- if (pickController.pickResult) {
76
+ if (pickController.pickResult.entity) {
77
+ const pickedEntityId = pickController.pickResult.entity.id;
75
78
 
76
- if (pickController.pickResult.entity) {
77
- const pickedEntityId = pickController.pickResult.entity.id;
79
+ if (this._lastPickedEntityId !== pickedEntityId) {
78
80
 
79
- if (this._lastPickedEntityId !== pickedEntityId) {
81
+ if (this._lastPickedEntityId !== undefined) {
80
82
 
81
- if (this._lastPickedEntityId !== undefined) {
83
+ cameraControl.fire("hoverOut", { // Hovered off an entity
84
+ entity: scene.objects[this._lastPickedEntityId]
85
+ }, true);
86
+ }
87
+
88
+ cameraControl.fire("hoverEnter", pickController.pickResult, true); // Hovering over a new entity
82
89
 
83
- cameraControl.fire("hoverOut", { // Hovered off an entity
84
- entity: scene.objects[this._lastPickedEntityId]
85
- }, true);
90
+ this._lastPickedEntityId = pickedEntityId;
86
91
  }
92
+ }
87
93
 
88
- cameraControl.fire("hoverEnter", pickController.pickResult, true); // Hovering over a new entity
94
+ cameraControl.fire("hover", pickController.pickResult, true);
89
95
 
90
- this._lastPickedEntityId = pickedEntityId;
96
+ if (pickController.pickResult.worldPos || pickController.pickResult.snappedWorldPos) { // Hovering the surface of an entity
97
+ cameraControl.fire("hoverSurface", pickController.pickResult, true);
91
98
  }
92
- }
93
99
 
94
- cameraControl.fire("hover", pickController.pickResult, true);
100
+ } else {
95
101
 
96
- if (pickController.pickResult.worldPos || pickController.pickResult.snappedWorldPos) { // Hovering the surface of an entity
97
- cameraControl.fire("hoverSurface", pickController.pickResult, true);
98
- }
102
+ if (this._lastPickedEntityId !== undefined) {
99
103
 
100
- } else {
104
+ cameraControl.fire("hoverOut", { // Hovered off an entity
105
+ entity: scene.objects[this._lastPickedEntityId]
106
+ }, true);
101
107
 
102
- if (this._lastPickedEntityId !== undefined) {
108
+ this._lastPickedEntityId = undefined;
109
+ }
103
110
 
104
- cameraControl.fire("hoverOut", { // Hovered off an entity
105
- entity: scene.objects[this._lastPickedEntityId]
111
+ cameraControl.fire("hoverOff", { // Not hovering on any entity
112
+ canvasPos: pickController.pickCursorPos
106
113
  }, true);
107
-
108
- this._lastPickedEntityId = undefined;
109
114
  }
110
-
111
- cameraControl.fire("hoverOff", { // Not hovering on any entity
112
- canvasPos: pickController.pickCursorPos
113
- }, true);
114
115
  }
115
116
  }
116
- });
117
+ );
118
+
119
+ canvas.addEventListener("mousemove", tickifiedMouseMoveFn);
117
120
 
118
121
  canvas.addEventListener('mousedown', this._canvasMouseDownHandler = (e) => {
119
122
 
@@ -1175,23 +1175,31 @@ class Input extends Component {
1175
1175
  }
1176
1176
  });
1177
1177
 
1178
+ const tickifedMouseMoveFn = this.scene.tickify(
1179
+ () => this.fire("mousemove", this.mouseCanvasPos, true)
1180
+ );
1181
+
1178
1182
  this.element.addEventListener("mousemove", this._mouseMoveListener = (e) => {
1179
1183
  if (!this.enabled) {
1180
1184
  return;
1181
1185
  }
1182
1186
  this._getMouseCanvasPos(e);
1183
- this.fire("mousemove", this.mouseCanvasPos, true);
1187
+ tickifedMouseMoveFn();
1184
1188
  if (this.mouseover) {
1185
1189
  e.preventDefault();
1186
1190
  }
1187
1191
  });
1188
1192
 
1193
+ const tickifiedMouseWheelFn = this.scene.tickify(
1194
+ (delta) => { this.fire("mousewheel", delta, true); }
1195
+ );
1196
+
1189
1197
  this.element.addEventListener("wheel", this._mouseWheelListener = (e, d) => {
1190
1198
  if (!this.enabled) {
1191
1199
  return;
1192
1200
  }
1193
1201
  const delta = Math.max(-1, Math.min(1, -e.deltaY * 40));
1194
- this.fire("mousewheel", delta, true);
1202
+ tickifiedMouseWheelFn(delta);
1195
1203
  }, {passive: true});
1196
1204
 
1197
1205
  // mouseclicked