Skip to content

Commit

Permalink
Merge pull request #1265 from tmarti/event-tickify
Browse files Browse the repository at this point in the history
OPTIMIZATION: tickify `mousemove` and `mousewheel` events
  • Loading branch information
xeolabs authored Nov 26, 2023
2 parents 25a3920 + 5fe2397 commit 415cc31
Show file tree
Hide file tree
Showing 4 changed files with 121 additions and 69 deletions.
23 changes: 1 addition & 22 deletions src/viewer/scene/CameraControl/lib/controllers/PickController.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down Expand Up @@ -269,10 +252,6 @@ class PickController {

this._needFireEvents = 0;
}

destroy() {
this._scene.off(this._tickSub);
}
}

export {PickController};
93 changes: 48 additions & 45 deletions src/viewer/scene/CameraControl/lib/handlers/MousePickHandler.js
Original file line number Diff line number Diff line change
Expand Up @@ -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) => {

Expand Down
12 changes: 10 additions & 2 deletions src/viewer/scene/input/Input.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
62 changes: 62 additions & 0 deletions src/viewer/scene/scene/Scene.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down Expand Up @@ -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.
*/
Expand Down

0 comments on commit 415cc31

Please sign in to comment.