UNPKG

@polygonjs/polygonjs

Version:

node-based WebGL 3D engine https://polygonjs.com

125 lines (124 loc) 5.09 kB
"use strict"; import { BaseRayObjectIntersectionsController } from "./_BaseRayObjectIntersectionsController"; import { filterObjectsWithMatchButtonConfig, buttonConfigFromEvent, propertyMatchesButtonConfig } from "./Common"; import { pushOnArrayAtEntry } from "../../../../../core/MapUtils"; import { ParamConfig } from "../../../../nodes/utils/params/ParamsConfig"; import { MouseButton } from "../../../../../core/MouseButton"; import { CursorMoveMonitor } from "../../../../../core/CursorMoveMonitor"; const _buttonConfig = { button: MouseButton.LEFT, ctrl: false, shift: false, alt: false }; export const DEFAULT_LONG_PRESS_DURATION = 500; function hasPropertiesWithCursorMoveLessThan(options, distance) { for (const option of options) { if (distance < option.longPress.maxCursorMoveDistance) { return true; } } return false; } export const DEFAULT_MAX_CURSOR_MOVE_DISTANCE = 0.05; export function LongPressParamConfig(Base) { return class Mixin extends Base { constructor() { super(...arguments); /** @param press duration (in milliseconds) */ this.duration = ParamConfig.INTEGER(DEFAULT_LONG_PRESS_DURATION, { range: [0, 1e3], rangeLocked: [true, false] }); /** @param max cursor move distance */ this.maxCursorMoveDistance = ParamConfig.FLOAT(DEFAULT_MAX_CURSOR_MOVE_DISTANCE, { range: [0, 1], rangeLocked: [true, false] }); } }; } export class RayObjectIntersectionsLongPressController extends BaseRayObjectIntersectionsController { constructor() { super(...arguments); this._propertiesListByObject = /* @__PURE__ */ new Map(); this._intersectedStateOnPointerdownByObject = /* @__PURE__ */ new Map(); this._intersectedStateOnTimeoutByObject = /* @__PURE__ */ new Map(); this._objectsMatchingEventConfig = []; this._objectsByLongPressDuration = /* @__PURE__ */ new Map(); this._timerByDuration = /* @__PURE__ */ new Map(); this._cursorMoveMonitor = new CursorMoveMonitor(); this._bound = { pointerup: this._onPointerup.bind(this) // pointermove: this._onPointermove.bind(this), }; } onPointerdown(event) { if (this._objects.length == 0) { return; } filterObjectsWithMatchButtonConfig( event, this._objects, this._propertiesListByObject, this._objectsMatchingEventConfig ); if (this._objectsMatchingEventConfig.length == 0) { return; } document.addEventListener("pointerup", this._bound.pointerup); document.addEventListener("touchend", this._bound.pointerup); this._cursorMoveMonitor.addPointermoveEventListener( this._scene.eventsDispatcher.pointerEventsController.cursor() ); this._objectsByLongPressDuration.clear(); this._timerByDuration.clear(); this._setIntersectedState(this._objectsMatchingEventConfig, this._intersectedStateOnPointerdownByObject); const _groupIntersectedObjectsByDuration = () => { const objects = this._objects; for (const object of objects) { const propertiesList = this._propertiesListByObject.get(object); if (propertiesList) { const isIntersecting = this._intersectedStateOnPointerdownByObject.get(object); if (isIntersecting == true) { for (const properties of propertiesList) { pushOnArrayAtEntry(this._objectsByLongPressDuration, properties.longPress.duration, object); } } } } }; _groupIntersectedObjectsByDuration(); buttonConfigFromEvent(event, _buttonConfig); this._objectsByLongPressDuration.forEach((objects, duration) => { const wrappedTriggeredMethod = () => { const movedCursorDistance = this._cursorMoveMonitor.movedCursorDistance(); this._timerByDuration.delete(duration); this._setIntersectedState(this._objects, this._intersectedStateOnTimeoutByObject); for (const object of objects) { const propertiesList = this._propertiesListByObject.get(object); if (propertiesList && hasPropertiesWithCursorMoveLessThan(propertiesList, movedCursorDistance)) { const isIntersecting = this._intersectedStateOnTimeoutByObject.get(object); if (isIntersecting) { for (const properties of propertiesList) { if (movedCursorDistance < properties.longPress.maxCursorMoveDistance && propertyMatchesButtonConfig(properties.config, _buttonConfig)) { properties.longPress.callback(); } } } } } }; const timer = setTimeout(wrappedTriggeredMethod, duration); this._timerByDuration.set(duration, timer); }); } _onPointerup() { document.removeEventListener("pointerup", this._bound.pointerup); document.removeEventListener("touchend", this._bound.pointerup); this._cursorMoveMonitor.removeEventListener(); this._timerByDuration.forEach((timer, duration) => { clearTimeout(timer); }); this._timerByDuration.clear(); } }