UNPKG

@polygonjs/polygonjs

Version:

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

206 lines (185 loc) 6.3 kB
import {BaseInputEventNodeType} from '../../../nodes/event/_BaseInput'; import {SceneEventsDispatcher} from './EventsDispatcher'; import {EventData, EventType} from '../../../../core/event/EventData'; import {PointerEventType} from '../../../../core/event/PointerEventType'; import {CoreEventEmitter} from '../../../../core/event/CoreEventEmitter'; import {addToSetAtEntry} from '../../../../core/MapUtils'; import {ActorEvaluatorGenerator} from '../../../nodes/js/code/assemblers/actor/ActorEvaluatorGenerator'; import type {EventContext} from '../../../../core/event/EventContextType'; export abstract class BaseSceneEventsController< E extends Event, T extends BaseInputEventNodeType // JsNodeType extends BaseUserInputJsNodeType > { private _activeEventDatas: EventData[] = []; private _activeEventDataTypes: Set<string> = new Set(); protected _eventNodes: Set<T> = new Set(); protected _requireCanvasEventListeners: boolean = false; protected _actorEvaluators: Set<ActorEvaluatorGenerator> = new Set(); // protected _actorEventNames: Set<string> = new Set(); protected _actorEvaluatorsByEventNames: Map<string, Map<CoreEventEmitter, Set<ActorEvaluatorGenerator>>> = new Map(); constructor(protected dispatcher: SceneEventsDispatcher) {} registerEventNode(node: T) { this._eventNodes.add(node); this.updateViewerEventListeners(); } unregisterEventNode(node: T) { this._eventNodes.delete(node); this.updateViewerEventListeners(); } registerEvaluatorGenerator(evaluator: ActorEvaluatorGenerator) { this._actorEvaluators.add(evaluator); this._updateActorEvaluatorCache(); this.updateViewerEventListeners(); } unregisterEvaluatorGenerator(evaluator: ActorEvaluatorGenerator) { this._actorEvaluators.delete(evaluator); this._updateActorEvaluatorCache(); this.updateViewerEventListeners(); } private _updateActorEvaluatorCache() { // this._actorEventNames.clear(); this._actorEvaluatorsByEventNames.clear(); this._actorEvaluators.forEach((evaluator) => { const eventDatas = evaluator.eventDatas; if (eventDatas) { eventDatas.forEach((eventData) => { const eventName = eventData.type; const emitter = eventData.emitter; let mapForEventName = this._actorEvaluatorsByEventNames.get(eventName); if (!mapForEventName) { mapForEventName = new Map(); this._actorEvaluatorsByEventNames.set(eventName, mapForEventName); } addToSetAtEntry(mapForEventName, emitter, evaluator); }); } // const nodeEventNames = node.userInputEventNames(); // const emitter = node.eventEmitter(); // for (let eventName of nodeEventNames) { // // this._actorEventNames.add(eventName); // let mapForEventName = this._actorNodesByEventNames.get(eventName); // if (!mapForEventName) { // mapForEventName = new Map(); // this._actorNodesByEventNames.set(eventName, mapForEventName); // } // MapUtils.addToSetAtEntry(mapForEventName, emitter, node); // } }); } abstract type(): string; abstract acceptedEventTypes(): Set<string>; // abstract accepts_event(event: Event): boolean; processEvent(eventContext: EventContext<E>) { if (this._activeEventDatas.length == 0) { return; } const eventType = eventContext.event?.type; if (eventType) { // The check here if the eventType is active // is not necessary for canvas events (pointer, mouse, keyboard) // but currently necessary for scene events (such as tick) if (!this._activeEventDataTypes.has(eventType)) { return; } } this._eventNodes.forEach((node) => { node.processEvent(eventContext); }); } updateViewerEventListeners() { this._updateActiveEventTypes(); if (this._requireCanvasEventListeners) { this.dispatcher.scene.viewersRegister.traverseViewers((viewer) => { viewer.eventsController().updateEvents(this); }); } } activeEventDatas() { return this._activeEventDatas; } private _updateActiveEventTypes() { const _storeEventData = (eventData: EventData) => { this._activeEventDatas.push(eventData); this._activeEventDataTypes.add(eventData.type); }; const _reset = () => { this._activeEventDatas.splice(0, this._activeEventDatas.length); this._activeEventDataTypes.clear(); }; const _actorEventDatas = () => { let eventTypeByEmitter: Map<CoreEventEmitter, Set<EventType>> = new Map(); this._actorEvaluatorsByEventNames.forEach((mapForEventName, eventName) => { mapForEventName.forEach((nodes, emitter) => { nodes.forEach((node) => { addToSetAtEntry(eventTypeByEmitter, emitter, eventName); }); }); }); const eventDatas: EventData[] = []; eventTypeByEmitter.forEach((eventNames, emitter) => { for (const eventName of eventNames) { const eventData: EventData = { type: eventName, emitter, }; eventDatas.push(eventData); } }); return eventDatas; }; const _updateActorNodesEventData = () => { const actorEventDatas = _actorEventDatas(); if (actorEventDatas) { for (const data of actorEventDatas) { _storeEventData(data); } } }; const _updateEventNodesEventData = () => { const activeNodeEventTypesState: Set<EventData> = new Set(); this._eventNodes.forEach((node) => { if (node.parent()) { const nodeActiveEventDatas = node.activeEventDatas(); for (const data of nodeActiveEventDatas) { activeNodeEventTypesState.add(data); } } }); activeNodeEventTypesState.forEach((state, data) => { _storeEventData(data); }); }; _reset(); // we always need the pointermove and touchmove // in order to always update the cursor _storeEventData({ type: PointerEventType.pointermove, emitter: CoreEventEmitter.DOCUMENT, }); _storeEventData({ type: PointerEventType.touchmove, emitter: CoreEventEmitter.DOCUMENT, }); _updateActorNodesEventData(); _updateEventNodesEventData(); } } export type BaseSceneEventsControllerType = BaseSceneEventsController< Event, BaseInputEventNodeType // BaseUserInputJsNodeType >; export class BaseSceneEventsControllerClass extends BaseSceneEventsController< Event, BaseInputEventNodeType // BaseUserInputJsNodeType > { type() { return ''; } acceptedEventTypes(): Set<string> { return new Set<string>(); } }