diff --git a/src/viewer/scene/CameraControl/lib/controllers/PickController.js b/src/viewer/scene/CameraControl/lib/controllers/PickController.js index 03cf954df7..201f15fd6a 100644 --- a/src/viewer/scene/CameraControl/lib/controllers/PickController.js +++ b/src/viewer/scene/CameraControl/lib/controllers/PickController.js @@ -70,29 +70,12 @@ class PickController { this._lastPickedEntityId = null; this._needFireEvents = 0; - - this._needToUpdate = false; - - this._tickSub = this._scene.on("tick", () => { - this.runUpdate(); - }); - } - - update() { - this._needToUpdate = true; } /** * Immediately attempts a pick, if scheduled. */ - runUpdate() { - - if (!this._needToUpdate) { - return; - } - - this._needToUpdate = false; - + update() { if (!this._configs.pointerEnabled) { return; } @@ -269,10 +252,6 @@ class PickController { this._needFireEvents = 0; } - - destroy() { - this._scene.off(this._tickSub); - } } export {PickController}; diff --git a/src/viewer/scene/CameraControl/lib/handlers/MousePickHandler.js b/src/viewer/scene/CameraControl/lib/handlers/MousePickHandler.js index ae07898a2d..cd8b955966 100644 --- a/src/viewer/scene/CameraControl/lib/handlers/MousePickHandler.js +++ b/src/viewer/scene/CameraControl/lib/handlers/MousePickHandler.js @@ -45,75 +45,78 @@ class MousePickHandler { } }; - canvas.addEventListener("mousemove", this._canvasMouseMoveHandler = (e) => { + const tickifiedMouseMoveFn = scene.tickify ( + this._canvasMouseMoveHandler = (e) => { + if (!(configs.active && configs.pointerEnabled)) { + return; + } - if (!(configs.active && configs.pointerEnabled)) { - return; - } + if (leftDown || rightDown) { + return; + } - if (leftDown || rightDown) { - return; - } + const hoverSubs = cameraControl.hasSubs("hover"); + const hoverEnterSubs = cameraControl.hasSubs("hoverEnter"); + const hoverOutSubs = cameraControl.hasSubs("hoverOut"); + const hoverOffSubs = cameraControl.hasSubs("hoverOff"); + const hoverSurfaceSubs = cameraControl.hasSubs("hoverSurface"); + const hoverSnapOrSurfaceSubs = cameraControl.hasSubs("hoverSnapOrSurface"); - const hoverSubs = cameraControl.hasSubs("hover"); - const hoverEnterSubs = cameraControl.hasSubs("hoverEnter"); - const hoverOutSubs = cameraControl.hasSubs("hoverOut"); - const hoverOffSubs = cameraControl.hasSubs("hoverOff"); - const hoverSurfaceSubs = cameraControl.hasSubs("hoverSurface"); - const hoverSnapOrSurfaceSubs = cameraControl.hasSubs("hoverSnapOrSurface"); + if (hoverSubs || hoverEnterSubs || hoverOutSubs || hoverOffSubs || hoverSurfaceSubs || hoverSnapOrSurfaceSubs) { - if (hoverSubs || hoverEnterSubs || hoverOutSubs || hoverOffSubs || hoverSurfaceSubs || hoverSnapOrSurfaceSubs) { + pickController.pickCursorPos = states.pointerCanvasPos; + pickController.schedulePickEntity = true; + pickController.schedulePickSurface = hoverSurfaceSubs; + pickController.scheduleSnapOrPick = hoverSnapOrSurfaceSubs - pickController.pickCursorPos = states.pointerCanvasPos; - pickController.schedulePickEntity = true; - pickController.schedulePickSurface = hoverSurfaceSubs; - pickController.scheduleSnapOrPick = hoverSnapOrSurfaceSubs + pickController.update(); - pickController.update(); + if (pickController.pickResult) { - if (pickController.pickResult) { + if (pickController.pickResult.entity) { + const pickedEntityId = pickController.pickResult.entity.id; - if (pickController.pickResult.entity) { - const pickedEntityId = pickController.pickResult.entity.id; + if (this._lastPickedEntityId !== pickedEntityId) { - if (this._lastPickedEntityId !== pickedEntityId) { + if (this._lastPickedEntityId !== undefined) { - if (this._lastPickedEntityId !== undefined) { + cameraControl.fire("hoverOut", { // Hovered off an entity + entity: scene.objects[this._lastPickedEntityId] + }, true); + } + + cameraControl.fire("hoverEnter", pickController.pickResult, true); // Hovering over a new entity - cameraControl.fire("hoverOut", { // Hovered off an entity - entity: scene.objects[this._lastPickedEntityId] - }, true); + this._lastPickedEntityId = pickedEntityId; } + } - cameraControl.fire("hoverEnter", pickController.pickResult, true); // Hovering over a new entity + cameraControl.fire("hover", pickController.pickResult, true); - this._lastPickedEntityId = pickedEntityId; + if (pickController.pickResult.worldPos || pickController.pickResult.snappedWorldPos) { // Hovering the surface of an entity + cameraControl.fire("hoverSurface", pickController.pickResult, true); } - } - cameraControl.fire("hover", pickController.pickResult, true); + } else { - if (pickController.pickResult.worldPos || pickController.pickResult.snappedWorldPos) { // Hovering the surface of an entity - cameraControl.fire("hoverSurface", pickController.pickResult, true); - } + if (this._lastPickedEntityId !== undefined) { - } else { + cameraControl.fire("hoverOut", { // Hovered off an entity + entity: scene.objects[this._lastPickedEntityId] + }, true); - if (this._lastPickedEntityId !== undefined) { + this._lastPickedEntityId = undefined; + } - cameraControl.fire("hoverOut", { // Hovered off an entity - entity: scene.objects[this._lastPickedEntityId] + cameraControl.fire("hoverOff", { // Not hovering on any entity + canvasPos: pickController.pickCursorPos }, true); - - this._lastPickedEntityId = undefined; } - - cameraControl.fire("hoverOff", { // Not hovering on any entity - canvasPos: pickController.pickCursorPos - }, true); } } - }); + ); + + canvas.addEventListener("mousemove", tickifiedMouseMoveFn); canvas.addEventListener('mousedown', this._canvasMouseDownHandler = (e) => { diff --git a/src/viewer/scene/input/Input.js b/src/viewer/scene/input/Input.js index 0dc17c82e2..bff22da8e6 100644 --- a/src/viewer/scene/input/Input.js +++ b/src/viewer/scene/input/Input.js @@ -1175,23 +1175,31 @@ class Input extends Component { } }); + const tickifedMouseMoveFn = this.scene.tickify( + () => this.fire("mousemove", this.mouseCanvasPos, true) + ); + this.element.addEventListener("mousemove", this._mouseMoveListener = (e) => { if (!this.enabled) { return; } this._getMouseCanvasPos(e); - this.fire("mousemove", this.mouseCanvasPos, true); + tickifedMouseMoveFn(); if (this.mouseover) { e.preventDefault(); } }); + const tickifiedMouseWheelFn = this.scene.tickify( + (delta) => { this.fire("mousewheel", delta, true); } + ); + this.element.addEventListener("wheel", this._mouseWheelListener = (e, d) => { if (!this.enabled) { return; } const delta = Math.max(-1, Math.min(1, -e.deltaY * 40)); - this.fire("mousewheel", delta, true); + tickifiedMouseWheelFn(delta); }, {passive: true}); // mouseclicked diff --git a/src/viewer/scene/scene/Scene.js b/src/viewer/scene/scene/Scene.js index fe599ef3fc..5f8e8a41d9 100644 --- a/src/viewer/scene/scene/Scene.js +++ b/src/viewer/scene/scene/Scene.js @@ -352,6 +352,11 @@ class Scene extends Component { throw "Mandatory config expected: valid canvasId or canvasElement"; } + /** + * @type {{[key: string]: {wrapperFunc: Function, tickSubId: string}}} + */ + this._tickifiedFunctions = {}; + const transparent = (!!cfg.transparent); const alphaDepthMask = (!!cfg.alphaDepthMask); @@ -2562,6 +2567,63 @@ class Scene extends Component { return changed; } + /** + * This method will "tickify" the provided `cb` function. + * + * This means, the function will be wrapped so: + * + * - it runs time-aligned to scene ticks + * - it runs maximum once per scene-tick + * + * @param {Function} cb The function to tickify + * @returns {Function)} + */ + tickify(cb) { + const cbString = cb.toString(); + + /** + * Check if the function is already tickified, and if so return the cached one. + */ + if (cbString in this._tickifiedFunctions) { + return this._tickifiedFunctions[cbString].wrapperFunc; + } + + let alreadyRun = 0; + let needToRun = 0; + + let lastArgs; + + /** + * The provided `cb` function is replaced with a "set-dirty" function + * + * @type {Function} + */ + const wrapperFunc = function (...args) { + lastArgs = args; + needToRun++; + }; + + /** + * An each scene tick, if the "dirty-flag" is set, run the `cb` function. + * + * This will make it run time-aligned to the scene tick. + */ + const tickSubId = this.on("tick", () => { + const tmp = needToRun; + if (tmp > alreadyRun) { + alreadyRun = tmp; + cb(...lastArgs); + } + }); + + /** + * And, store the list of subscribers. + */ + this._tickifiedFunctions[cbString] = { tickSubId, wrapperFunc }; + + return wrapperFunc; + } + /** * Destroys this Scene. */