pixi.js
Version:
<p align="center"> <a href="https://pixijs.com" target="_blank" rel="noopener noreferrer"> <img height="150" src="https://files.pixijs.download/branding/pixijs-logo-transparent-dark.svg?v=1" alt="PixiJS logo"> </a> </p> <br/> <p align="center">
1 lines • 63.3 kB
Source Map (JSON)
{"version":3,"file":"EventSystem.mjs","sources":["../../src/events/EventSystem.ts"],"sourcesContent":["import { ExtensionType } from '../extensions/Extensions';\nimport { EventBoundary } from './EventBoundary';\nimport { EventsTicker } from './EventTicker';\nimport { FederatedPointerEvent } from './FederatedPointerEvent';\nimport { FederatedWheelEvent } from './FederatedWheelEvent';\n\nimport type { ExtensionMetadata } from '../extensions/Extensions';\nimport type { PointData } from '../maths/point/PointData';\nimport type { System } from '../rendering/renderers/shared/system/System';\nimport type { Renderer } from '../rendering/renderers/types';\nimport type { PixiTouch } from './FederatedEvent';\nimport type { EventMode } from './FederatedEventTarget';\nimport type { FederatedMouseEvent } from './FederatedMouseEvent';\n\nconst MOUSE_POINTER_ID = 1;\nconst TOUCH_TO_POINTER: Record<string, string> = {\n touchstart: 'pointerdown',\n touchend: 'pointerup',\n touchendoutside: 'pointerupoutside',\n touchmove: 'pointermove',\n touchcancel: 'pointercancel',\n};\n\n/**\n * Options for configuring the PixiJS event system. These options control how the event system\n * handles different types of interactions and event propagation.\n * @example\n * ```ts\n * // Basic event system configuration\n * const app = new Application();\n * await app.init({\n * // Configure default interaction mode\n * eventMode: 'static',\n *\n * // Configure event features\n * eventFeatures: {\n * move: true, // Enable pointer movement events\n * globalMove: false, // Disable global move events\n * click: true, // Enable click events\n * wheel: true // Enable wheel/scroll events\n * }\n * });\n *\n * // Access event system after initialization\n * const eventSystem = app.renderer.events;\n * console.log(eventSystem.features); // Check enabled features\n * ```\n * @see {@link EventSystem} For the main event system implementation\n * @see {@link EventMode} For interaction mode details\n * @see {@link EventSystemFeatures} For all available feature options\n * @advanced\n * @category events\n */\nexport interface EventSystemOptions\n{\n /**\n * The default event mode for all display objects.\n * Controls how objects respond to interaction events.\n *\n * Possible values:\n * - `'none'`: No interaction events\n * - `'passive'`: Only container's children receive events (default)\n * - `'auto'`: Receives events when parent is interactive\n * - `'static'`: Standard interaction events\n * - `'dynamic'`: Like static but with additional synthetic events\n * @default 'passive'\n */\n eventMode?: EventMode;\n\n /**\n * Configuration for enabling/disabling specific event features.\n * Use this to optimize performance by turning off unused functionality.\n * @example\n * ```ts\n * const app = new Application();\n * await app.init({\n * eventFeatures: {\n * // Core interaction events\n * move: true, // Pointer/mouse/touch movement\n * click: true, // Click/tap events\n * wheel: true, // Mouse wheel/scroll events\n * // Global tracking\n * globalMove: false // Global pointer movement\n * }\n * });\n * ```\n */\n eventFeatures?: Partial<EventSystemFeatures>;\n}\n\n/**\n * The event features that are enabled by the EventSystem. These features control\n * different types of interaction events in your PixiJS application.\n * @example\n * ```ts\n * // Configure features during application initialization\n * const app = new Application();\n * await app.init({\n * eventFeatures: {\n * // Basic interaction events\n * move: true, // Enable pointer movement tracking\n * click: true, // Enable click/tap events\n * wheel: true, // Enable mouse wheel/scroll events\n * // Advanced features\n * globalMove: false // Disable global move tracking for performance\n * }\n * });\n *\n * // Or configure after initialization\n * app.renderer.events.features.move = false; // Disable movement events\n * app.renderer.events.features.globalMove = true; // Enable global tracking\n * ```\n * @since 7.2.0\n * @category events\n * @advanced\n */\nexport interface EventSystemFeatures\n{\n /**\n * Enables pointer events associated with pointer movement.\n *\n * When enabled, these events will fire:\n * - `pointermove` / `mousemove` / `touchmove`\n * - `pointerout` / `mouseout`\n * - `pointerover` / `mouseover`\n * @example\n * ```ts\n * // Enable movement events\n * app.renderer.events.features.move = true;\n *\n * // Listen for movement\n * sprite.on('pointermove', (event) => {\n * console.log('Pointer position:', event.global.x, event.global.y);\n * });\n * ```\n * @default true\n */\n move: boolean;\n\n /**\n * Enables global pointer move events that fire regardless of target.\n *\n * When enabled, these events will fire:\n * - `globalpointermove`\n * - `globalmousemove`\n * - `globaltouchmove`\n * @example\n * ```ts\n * // Enable global tracking\n * app.renderer.events.features.globalMove = true;\n *\n * // Track pointer globally\n * sprite.on('globalpointermove', (event) => {\n * // Fires even when pointer is not over sprite\n * console.log('Global position:', event.global.x, event.global.y);\n * });\n * ```\n * @default true\n */\n globalMove: boolean;\n /**\n * Enables pointer events associated with clicking/tapping.\n *\n * When enabled, these events will fire:\n * - `pointerdown` / `mousedown` / `touchstart` / `rightdown`\n * - `pointerup` / `mouseup` / `touchend` / `rightup`\n * - `pointerupoutside` / `mouseupoutside` / `touchendoutside` / `rightupoutside`\n * - `click` / `tap`\n * @example\n * ```ts\n * // Enable click events\n * app.renderer.events.features.click = true;\n *\n * // Handle clicks\n * sprite.on('click', (event) => {\n * console.log('Clicked at:', event.global.x, event.global.y);\n * });\n * ```\n * @default true\n */\n click: boolean;\n /**\n * Enables mouse wheel/scroll events.\n * @example\n * ```ts\n * // Enable wheel events\n * app.renderer.events.features.wheel = true;\n *\n * // Handle scrolling\n * sprite.on('wheel', (event) => {\n * // Zoom based on scroll direction\n * const scale = 1 + (event.deltaY / 1000);\n * sprite.scale.set(sprite.scale.x * scale);\n * });\n * ```\n * @default true\n */\n wheel: boolean;\n}\n\n/**\n * The system for handling UI events in PixiJS applications. This class manages mouse, touch, and pointer events,\n * normalizing them into a consistent event model.\n * @example\n * ```ts\n * // Access event system through renderer\n * const eventSystem = app.renderer.events;\n *\n * // Configure event features\n * eventSystem.features.globalMove = false; // Disable global move events\n * eventSystem.features.click = true; // Enable click events\n *\n * // Set custom cursor styles\n * eventSystem.cursorStyles.default = 'pointer';\n * eventSystem.cursorStyles.grab = 'grab';\n *\n * // Get current pointer position\n * const pointer = eventSystem.pointer;\n * console.log(pointer.global.x, pointer.global.y);\n * ```\n *\n * Features:\n * - Normalizes browser events into consistent format\n * - Supports mouse, touch, and pointer events\n * - Handles event delegation and bubbling\n * - Provides cursor management\n * - Configurable event features\n * @see {@link EventBoundary} For event propagation and handling\n * @see {@link FederatedEvent} For the base event class\n * @see {@link EventMode} For interaction modes\n * @category events\n * @standard\n */\nexport class EventSystem implements System<EventSystemOptions>\n{\n /** @ignore */\n public static extension: ExtensionMetadata = {\n name: 'events',\n type: [\n ExtensionType.WebGLSystem,\n ExtensionType.CanvasSystem,\n ExtensionType.WebGPUSystem,\n ],\n priority: -1,\n };\n\n /**\n * The event features that are enabled by the EventSystem\n * @since 7.2.0\n * @example\n * ```ts\n * import { EventSystem, EventSystemFeatures } from 'pixi.js';\n * // Access the default event features\n * EventSystem.defaultEventFeatures = {\n * // Enable pointer movement events\n * move: true,\n * // Enable global pointer move events\n * globalMove: true,\n * // Enable click events\n * click: true,\n * // Enable wheel events\n * wheel: true,\n * };\n * ```\n */\n public static defaultEventFeatures: EventSystemFeatures = {\n /** Enables pointer events associated with pointer movement. */\n move: true,\n /** Enables global pointer move events. */\n globalMove: true,\n /** Enables pointer events associated with clicking. */\n click: true,\n /** Enables wheel events. */\n wheel: true,\n };\n\n private static _defaultEventMode: EventMode;\n\n /**\n * The default interaction mode for all display objects.\n * @see Container.eventMode\n * @type {EventMode}\n * @readonly\n * @since 7.2.0\n */\n public static get defaultEventMode()\n {\n return this._defaultEventMode;\n }\n\n /**\n * The {@link EventBoundary} for the stage.\n *\n * The {@link EventBoundary#rootTarget rootTarget} of this root boundary is automatically set to\n * the last rendered object before any event processing is initiated. This means the main scene\n * needs to be rendered atleast once before UI events will start propagating.\n *\n * The root boundary should only be changed during initialization. Otherwise, any state held by the\n * event boundary may be lost (like hovered & pressed Containers).\n * @advanced\n */\n public readonly rootBoundary: EventBoundary;\n\n /**\n * Indicates whether the current device supports touch events according to the W3C Touch Events spec.\n * This is used to determine the appropriate event handling strategy.\n * @see {@link https://www.w3.org/TR/touch-events/} W3C Touch Events Specification\n * @readonly\n * @default 'ontouchstart' in globalThis\n */\n public readonly supportsTouchEvents = 'ontouchstart' in globalThis;\n\n /**\n * Indicates whether the current device supports pointer events according to the W3C Pointer Events spec.\n * Used to optimize event handling and provide more consistent cross-device interaction.\n * @see {@link https://www.w3.org/TR/pointerevents/} W3C Pointer Events Specification\n * @readonly\n * @default !!globalThis.PointerEvent\n */\n public readonly supportsPointerEvents = !!globalThis.PointerEvent;\n\n /**\n * Controls whether default browser actions are automatically prevented on pointer events.\n * When true, prevents default browser actions from occurring on pointer events.\n * @remarks\n * - Does not apply to pointer events for backwards compatibility\n * - preventDefault on pointer events stops mouse events from firing\n * - For every pointer event, there will always be either a mouse or touch event alongside it\n * - Setting this to false allows default browser actions (text selection, dragging images, etc.)\n * @example\n * ```ts\n * // Allow default browser actions\n * app.renderer.events.autoPreventDefault = false;\n *\n * // Block default actions (default)\n * app.renderer.events.autoPreventDefault = true;\n *\n * // Example with text selection\n * const text = new Text('Selectable text');\n * text.eventMode = 'static';\n * app.renderer.events.autoPreventDefault = false; // Allow text selection\n * ```\n * @default true\n */\n public autoPreventDefault: boolean;\n\n /**\n * Dictionary of custom cursor styles that can be used across the application.\n * Used to define how different cursor modes are handled when interacting with display objects.\n * @example\n * ```ts\n * // Access event system through renderer\n * const eventSystem = app.renderer.events;\n *\n * // Set string-based cursor styles\n * eventSystem.cursorStyles.default = 'pointer';\n * eventSystem.cursorStyles.hover = 'grab';\n * eventSystem.cursorStyles.drag = 'grabbing';\n *\n * // Use CSS object for complex styling\n * eventSystem.cursorStyles.custom = {\n * cursor: 'url(\"custom.png\") 2 2, auto',\n * userSelect: 'none'\n * };\n *\n * // Use a url for custom cursors\n * const defaultIcon = 'url(\\'https://pixijs.com/assets/bunny.png\\'),auto';\n * eventSystem.cursorStyles.icon = defaultIcon;\n *\n * // Use callback function for dynamic cursors\n * eventSystem.cursorStyles.dynamic = (mode) => {\n * // Update cursor based on mode\n * document.body.style.cursor = mode === 'hover'\n * ? 'pointer'\n * : 'default';\n * };\n *\n * // Apply cursor style to a sprite\n * sprite.cursor = 'hover'; // Will use the hover style defined above\n * sprite.cursor = 'icon'; // Will apply the icon cursor\n * sprite.cursor = 'custom'; // Will apply the custom CSS styles\n * sprite.cursor = 'drag'; // Will apply the grabbing cursor\n * sprite.cursor = 'default'; // Will apply the default pointer cursor\n * sprite.cursor = 'dynamic'; // Will call the dynamic function\n * ```\n * @remarks\n * - Strings are treated as CSS cursor values\n * - Objects are applied as CSS styles to the DOM element\n * - Functions are called directly for custom cursor handling\n * - Default styles for 'default' and 'pointer' are provided\n * @default\n * ```ts\n * {\n * default: 'inherit',\n * pointer: 'pointer' // Default cursor styles\n * }\n * ```\n */\n public cursorStyles: Record<string, string | ((mode: string) => void) | CSSStyleDeclaration>;\n\n /**\n * The DOM element to which the root event listeners are bound. This is automatically set to\n * the renderer's {@link Renderer#view view}.\n */\n public domElement: HTMLElement = null;\n\n /** The resolution used to convert between the DOM client space into world space. */\n public resolution = 1;\n\n /** The renderer managing this {@link EventSystem}. */\n public renderer: Renderer;\n\n /**\n * The event features that are enabled by the EventSystem\n * @since 7.2.0\n * @example\n * const app = new Application()\n * app.renderer.events.features.globalMove = false\n *\n * // to override all features use Object.assign\n * Object.assign(app.renderer.events.features, {\n * move: false,\n * globalMove: false,\n * click: false,\n * wheel: false,\n * })\n */\n public readonly features: EventSystemFeatures;\n\n private _currentCursor: string;\n private readonly _rootPointerEvent: FederatedPointerEvent;\n private readonly _rootWheelEvent: FederatedWheelEvent;\n private _eventsAdded: boolean;\n\n /**\n * @param {Renderer} renderer\n */\n constructor(renderer: Renderer)\n {\n this.renderer = renderer;\n this.rootBoundary = new EventBoundary(null);\n EventsTicker.init(this);\n\n this.autoPreventDefault = true;\n this._eventsAdded = false;\n\n this._rootPointerEvent = new FederatedPointerEvent(null);\n this._rootWheelEvent = new FederatedWheelEvent(null);\n\n this.cursorStyles = {\n default: 'inherit',\n pointer: 'pointer',\n };\n\n this.features = new Proxy({ ...EventSystem.defaultEventFeatures }, {\n set: (target, key, value) =>\n {\n if (key === 'globalMove')\n {\n this.rootBoundary.enableGlobalMoveEvents = value;\n }\n target[key as keyof EventSystemFeatures] = value;\n\n return true;\n }\n });\n\n this._onPointerDown = this._onPointerDown.bind(this);\n this._onPointerMove = this._onPointerMove.bind(this);\n this._onPointerUp = this._onPointerUp.bind(this);\n this._onPointerOverOut = this._onPointerOverOut.bind(this);\n this.onWheel = this.onWheel.bind(this);\n }\n\n /**\n * Runner init called, view is available at this point.\n * @ignore\n */\n public init(options: EventSystemOptions): void\n {\n const { canvas, resolution } = this.renderer;\n\n this.setTargetElement(canvas as HTMLCanvasElement);\n this.resolution = resolution;\n EventSystem._defaultEventMode = options.eventMode ?? 'passive';\n Object.assign(this.features, options.eventFeatures ?? {});\n this.rootBoundary.enableGlobalMoveEvents = this.features.globalMove;\n }\n\n /**\n * Handle changing resolution.\n * @ignore\n */\n public resolutionChange(resolution: number): void\n {\n this.resolution = resolution;\n }\n\n /** Destroys all event listeners and detaches the renderer. */\n public destroy(): void\n {\n this.setTargetElement(null);\n this.renderer = null;\n this._currentCursor = null;\n }\n\n /**\n * Sets the current cursor mode, handling any callbacks or CSS style changes.\n * The cursor can be a CSS cursor string, a custom callback function, or a key from the cursorStyles dictionary.\n * @param mode - Cursor mode to set. Can be:\n * - A CSS cursor string (e.g., 'pointer', 'grab')\n * - A key from the cursorStyles dictionary\n * - null/undefined to reset to default\n * @example\n * ```ts\n * // Using predefined cursor styles\n * app.renderer.events.setCursor('pointer'); // Set standard pointer cursor\n * app.renderer.events.setCursor('grab'); // Set grab cursor\n * app.renderer.events.setCursor(null); // Reset to default\n *\n * // Using custom cursor styles\n * app.renderer.events.cursorStyles.custom = 'url(\"cursor.png\"), auto';\n * app.renderer.events.setCursor('custom'); // Apply custom cursor\n *\n * // Using callback-based cursor\n * app.renderer.events.cursorStyles.dynamic = (mode) => {\n * document.body.style.cursor = mode === 'hover' ? 'pointer' : 'default';\n * };\n * app.renderer.events.setCursor('dynamic'); // Trigger cursor callback\n * ```\n * @remarks\n * - Has no effect on OffscreenCanvas except for callback-based cursors\n * - Caches current cursor to avoid unnecessary DOM updates\n * - Supports CSS cursor values, style objects, and callback functions\n * @see {@link EventSystem.cursorStyles} For defining custom cursor styles\n * @see {@link https://developer.mozilla.org/en-US/docs/Web/CSS/cursor} MDN Cursor Reference\n */\n public setCursor(mode: string): void\n {\n mode ||= 'default';\n let applyStyles = true;\n\n // offscreen canvas does not support setting styles, but cursor modes can be functions,\n // in order to handle pixi rendered cursors, so we can't bail\n if (globalThis.OffscreenCanvas && this.domElement instanceof OffscreenCanvas)\n {\n applyStyles = false;\n }\n // if the mode didn't actually change, bail early\n if (this._currentCursor === mode)\n {\n return;\n }\n this._currentCursor = mode;\n const style = this.cursorStyles[mode];\n\n // only do things if there is a cursor style for it\n if (style)\n {\n switch (typeof style)\n {\n case 'string':\n // string styles are handled as cursor CSS\n if (applyStyles)\n {\n this.domElement.style.cursor = style;\n }\n break;\n case 'function':\n // functions are just called, and passed the cursor mode\n style(mode);\n break;\n case 'object':\n // if it is an object, assume that it is a dictionary of CSS styles,\n // apply it to the interactionDOMElement\n if (applyStyles)\n {\n Object.assign(this.domElement.style, style);\n }\n break;\n }\n }\n else if (applyStyles && typeof mode === 'string' && !Object.prototype.hasOwnProperty.call(this.cursorStyles, mode))\n {\n // if it mode is a string (not a Symbol) and cursorStyles doesn't have any entry\n // for the mode, then assume that the dev wants it to be CSS for the cursor.\n this.domElement.style.cursor = mode;\n }\n }\n\n /**\n * The global pointer event instance containing the most recent pointer state.\n * This is useful for accessing pointer information without listening to events.\n * @example\n * ```ts\n * // Access current pointer position at any time\n * const eventSystem = app.renderer.events;\n * const pointer = eventSystem.pointer;\n *\n * // Get global coordinates\n * console.log('Position:', pointer.global.x, pointer.global.y);\n *\n * // Check button state\n * console.log('Buttons pressed:', pointer.buttons);\n *\n * // Get pointer type and pressure\n * console.log('Type:', pointer.pointerType);\n * console.log('Pressure:', pointer.pressure);\n * ```\n * @readonly\n * @since 7.2.0\n * @see {@link FederatedPointerEvent} For all available pointer properties\n */\n public get pointer(): Readonly<FederatedPointerEvent>\n {\n return this._rootPointerEvent;\n }\n\n /**\n * Event handler for pointer down events on {@link EventSystem#domElement this.domElement}.\n * @param nativeEvent - The native mouse/pointer/touch event.\n */\n private _onPointerDown(nativeEvent: MouseEvent | PointerEvent | TouchEvent): void\n {\n if (!this.features.click) return;\n this.rootBoundary.rootTarget = this.renderer.lastObjectRendered;\n\n const events = this._normalizeToPointerData(nativeEvent);\n\n /*\n * No need to prevent default on natural pointer events, as there are no side effects\n * Normalized events, however, may have the double mousedown/touchstart issue on the native android browser,\n * so still need to be prevented.\n */\n\n // Guaranteed that there will be at least one event in events, and all events must have the same pointer type\n\n if (this.autoPreventDefault && (events[0] as any).isNormalized)\n {\n const cancelable = nativeEvent.cancelable || !('cancelable' in nativeEvent);\n\n if (cancelable)\n {\n nativeEvent.preventDefault();\n }\n }\n\n for (let i = 0, j = events.length; i < j; i++)\n {\n const nativeEvent = events[i];\n const federatedEvent = this._bootstrapEvent(this._rootPointerEvent, nativeEvent);\n\n this.rootBoundary.mapEvent(federatedEvent);\n }\n\n this.setCursor(this.rootBoundary.cursor);\n }\n\n /**\n * Event handler for pointer move events on on {@link EventSystem#domElement this.domElement}.\n * @param nativeEvent - The native mouse/pointer/touch events.\n */\n private _onPointerMove(nativeEvent: MouseEvent | PointerEvent | TouchEvent): void\n {\n if (!this.features.move) return;\n this.rootBoundary.rootTarget = this.renderer.lastObjectRendered;\n\n EventsTicker.pointerMoved();\n\n const normalizedEvents = this._normalizeToPointerData(nativeEvent);\n\n for (let i = 0, j = normalizedEvents.length; i < j; i++)\n {\n const event = this._bootstrapEvent(this._rootPointerEvent, normalizedEvents[i]);\n\n this.rootBoundary.mapEvent(event);\n }\n\n this.setCursor(this.rootBoundary.cursor);\n }\n\n /**\n * Event handler for pointer up events on {@link EventSystem#domElement this.domElement}.\n * @param nativeEvent - The native mouse/pointer/touch event.\n */\n private _onPointerUp(nativeEvent: MouseEvent | PointerEvent | TouchEvent): void\n {\n if (!this.features.click) return;\n this.rootBoundary.rootTarget = this.renderer.lastObjectRendered;\n\n let target = nativeEvent.target;\n\n // if in shadow DOM use composedPath to access target\n if (nativeEvent.composedPath && nativeEvent.composedPath().length > 0)\n {\n target = nativeEvent.composedPath()[0];\n }\n\n const outside = target !== this.domElement ? 'outside' : '';\n const normalizedEvents = this._normalizeToPointerData(nativeEvent);\n\n for (let i = 0, j = normalizedEvents.length; i < j; i++)\n {\n const event = this._bootstrapEvent(this._rootPointerEvent, normalizedEvents[i]);\n\n event.type += outside;\n\n this.rootBoundary.mapEvent(event);\n }\n\n this.setCursor(this.rootBoundary.cursor);\n }\n\n /**\n * Event handler for pointer over & out events on {@link EventSystem#domElement this.domElement}.\n * @param nativeEvent - The native mouse/pointer/touch event.\n */\n private _onPointerOverOut(nativeEvent: MouseEvent | PointerEvent | TouchEvent): void\n {\n if (!this.features.click) return;\n this.rootBoundary.rootTarget = this.renderer.lastObjectRendered;\n\n const normalizedEvents = this._normalizeToPointerData(nativeEvent);\n\n for (let i = 0, j = normalizedEvents.length; i < j; i++)\n {\n const event = this._bootstrapEvent(this._rootPointerEvent, normalizedEvents[i]);\n\n this.rootBoundary.mapEvent(event);\n }\n\n this.setCursor(this.rootBoundary.cursor);\n }\n\n /**\n * Passive handler for `wheel` events on {@link EventSystem.domElement this.domElement}.\n * @param nativeEvent - The native wheel event.\n */\n protected onWheel(nativeEvent: WheelEvent): void\n {\n if (!this.features.wheel) return;\n const wheelEvent = this.normalizeWheelEvent(nativeEvent);\n\n this.rootBoundary.rootTarget = this.renderer.lastObjectRendered;\n this.rootBoundary.mapEvent(wheelEvent);\n }\n\n /**\n * Sets the {@link EventSystem#domElement domElement} and binds event listeners.\n * This method manages the DOM event bindings for the event system, allowing you to\n * change or remove the target element that receives input events.\n * > [!IMPORTANT] This will default to the canvas element of the renderer, so you\n * > should not need to call this unless you are using a custom element.\n * @param element - The new DOM element to bind events to, or null to remove all event bindings\n * @example\n * ```ts\n * // Set a new canvas element as the target\n * const canvas = document.createElement('canvas');\n * app.renderer.events.setTargetElement(canvas);\n *\n * // Remove all event bindings\n * app.renderer.events.setTargetElement(null);\n *\n * // Switch to a different canvas\n * const newCanvas = document.querySelector('#game-canvas');\n * app.renderer.events.setTargetElement(newCanvas);\n * ```\n * @remarks\n * - Automatically removes event listeners from previous element\n * - Required for the event system to function\n * - Safe to call multiple times\n * @see {@link EventSystem#domElement} The current DOM element\n * @see {@link EventsTicker} For the ticker system that tracks pointer movement\n */\n public setTargetElement(element: HTMLElement): void\n {\n this._removeEvents();\n this.domElement = element;\n EventsTicker.domElement = element;\n this._addEvents();\n }\n\n /** Register event listeners on {@link Renderer#domElement this.domElement}. */\n private _addEvents(): void\n {\n if (this._eventsAdded || !this.domElement)\n {\n return;\n }\n\n EventsTicker.addTickerListener();\n\n const style = this.domElement.style as CrossCSSStyleDeclaration;\n\n if (style)\n {\n if ((globalThis.navigator as any).msPointerEnabled)\n {\n style.msContentZooming = 'none';\n style.msTouchAction = 'none';\n }\n else if (this.supportsPointerEvents)\n {\n style.touchAction = 'none';\n }\n }\n\n /*\n * These events are added first, so that if pointer events are normalized, they are fired\n * in the same order as non-normalized events. ie. pointer event 1st, mouse / touch 2nd\n */\n if (this.supportsPointerEvents)\n {\n globalThis.document.addEventListener('pointermove', this._onPointerMove, true);\n this.domElement.addEventListener('pointerdown', this._onPointerDown, true);\n // pointerout is fired in addition to pointerup (for touch events) and pointercancel\n // we already handle those, so for the purposes of what we do in onPointerOut, we only\n // care about the pointerleave event\n this.domElement.addEventListener('pointerleave', this._onPointerOverOut, true);\n this.domElement.addEventListener('pointerover', this._onPointerOverOut, true);\n // globalThis.addEventListener('pointercancel', this.onPointerCancel, true);\n globalThis.addEventListener('pointerup', this._onPointerUp, true);\n }\n else\n {\n globalThis.document.addEventListener('mousemove', this._onPointerMove, true);\n this.domElement.addEventListener('mousedown', this._onPointerDown, true);\n this.domElement.addEventListener('mouseout', this._onPointerOverOut, true);\n this.domElement.addEventListener('mouseover', this._onPointerOverOut, true);\n globalThis.addEventListener('mouseup', this._onPointerUp, true);\n\n if (this.supportsTouchEvents)\n {\n this.domElement.addEventListener('touchstart', this._onPointerDown, true);\n // this.domElement.addEventListener('touchcancel', this.onPointerCancel, true);\n this.domElement.addEventListener('touchend', this._onPointerUp, true);\n this.domElement.addEventListener('touchmove', this._onPointerMove, true);\n }\n }\n\n this.domElement.addEventListener('wheel', this.onWheel, {\n passive: true,\n capture: true,\n });\n\n this._eventsAdded = true;\n }\n\n /** Unregister event listeners on {@link EventSystem#domElement this.domElement}. */\n private _removeEvents(): void\n {\n if (!this._eventsAdded || !this.domElement)\n {\n return;\n }\n\n EventsTicker.removeTickerListener();\n\n const style = this.domElement.style as CrossCSSStyleDeclaration;\n\n // offscreen canvas does not have style, so check first\n if (style)\n {\n if ((globalThis.navigator as any).msPointerEnabled)\n {\n style.msContentZooming = '';\n style.msTouchAction = '';\n }\n else if (this.supportsPointerEvents)\n {\n style.touchAction = '';\n }\n }\n\n if (this.supportsPointerEvents)\n {\n globalThis.document.removeEventListener('pointermove', this._onPointerMove, true);\n this.domElement.removeEventListener('pointerdown', this._onPointerDown, true);\n this.domElement.removeEventListener('pointerleave', this._onPointerOverOut, true);\n this.domElement.removeEventListener('pointerover', this._onPointerOverOut, true);\n // globalThis.removeEventListener('pointercancel', this.onPointerCancel, true);\n globalThis.removeEventListener('pointerup', this._onPointerUp, true);\n }\n else\n {\n globalThis.document.removeEventListener('mousemove', this._onPointerMove, true);\n this.domElement.removeEventListener('mousedown', this._onPointerDown, true);\n this.domElement.removeEventListener('mouseout', this._onPointerOverOut, true);\n this.domElement.removeEventListener('mouseover', this._onPointerOverOut, true);\n globalThis.removeEventListener('mouseup', this._onPointerUp, true);\n\n if (this.supportsTouchEvents)\n {\n this.domElement.removeEventListener('touchstart', this._onPointerDown, true);\n // this.domElement.removeEventListener('touchcancel', this.onPointerCancel, true);\n this.domElement.removeEventListener('touchend', this._onPointerUp, true);\n this.domElement.removeEventListener('touchmove', this._onPointerMove, true);\n }\n }\n\n this.domElement.removeEventListener('wheel', this.onWheel, true);\n\n this.domElement = null;\n this._eventsAdded = false;\n }\n\n /**\n * Maps coordinates from DOM/screen space into PixiJS normalized coordinates.\n * This takes into account the current scale, position, and resolution of the DOM element.\n * @param point - The point to store the mapped coordinates in\n * @param x - The x coordinate in DOM/client space\n * @param y - The y coordinate in DOM/client space\n * @example\n * ```ts\n * // Map mouse coordinates to PixiJS space\n * const point = new Point();\n * app.renderer.events.mapPositionToPoint(\n * point,\n * event.clientX,\n * event.clientY\n * );\n * console.log('Mapped position:', point.x, point.y);\n *\n * // Using with pointer events\n * sprite.on('pointermove', (event) => {\n * // event.global already contains mapped coordinates\n * console.log('Global:', event.global.x, event.global.y);\n *\n * // Map to local coordinates\n * const local = event.getLocalPosition(sprite);\n * console.log('Local:', local.x, local.y);\n * });\n * ```\n * @remarks\n * - Accounts for element scaling and positioning\n * - Adjusts for device pixel ratio/resolution\n */\n public mapPositionToPoint(point: PointData, x: number, y: number): void\n {\n const rect = this.domElement.isConnected\n ? this.domElement.getBoundingClientRect()\n : {\n x: 0,\n y: 0,\n width: (this.domElement as any).width,\n height: (this.domElement as any).height,\n left: 0,\n top: 0\n };\n\n const resolutionMultiplier = 1.0 / this.resolution;\n\n point.x = ((x - rect.left) * ((this.domElement as any).width / rect.width)) * resolutionMultiplier;\n point.y = ((y - rect.top) * ((this.domElement as any).height / rect.height)) * resolutionMultiplier;\n }\n\n /**\n * Ensures that the original event object contains all data that a regular pointer event would have\n * @param event - The original event data from a touch or mouse event\n * @returns An array containing a single normalized pointer event, in the case of a pointer\n * or mouse event, or a multiple normalized pointer events if there are multiple changed touches\n */\n private _normalizeToPointerData(event: TouchEvent | MouseEvent | PointerEvent): PointerEvent[]\n {\n const normalizedEvents = [];\n\n if (this.supportsTouchEvents && event instanceof TouchEvent)\n {\n for (let i = 0, li = event.changedTouches.length; i < li; i++)\n {\n const touch = event.changedTouches[i] as PixiTouch;\n\n if (typeof touch.button === 'undefined') touch.button = 0;\n if (typeof touch.buttons === 'undefined') touch.buttons = 1;\n if (typeof touch.isPrimary === 'undefined')\n {\n touch.isPrimary = event.touches.length === 1 && event.type === 'touchstart';\n }\n if (typeof touch.width === 'undefined') touch.width = touch.radiusX || 1;\n if (typeof touch.height === 'undefined') touch.height = touch.radiusY || 1;\n if (typeof touch.tiltX === 'undefined') touch.tiltX = 0;\n if (typeof touch.tiltY === 'undefined') touch.tiltY = 0;\n if (typeof touch.pointerType === 'undefined') touch.pointerType = 'touch';\n if (typeof touch.pointerId === 'undefined') touch.pointerId = touch.identifier || 0;\n if (typeof touch.pressure === 'undefined') touch.pressure = touch.force || 0.5;\n if (typeof touch.twist === 'undefined') touch.twist = 0;\n if (typeof touch.tangentialPressure === 'undefined') touch.tangentialPressure = 0;\n // TODO: Remove these, as layerX/Y is not a standard, is deprecated, has uneven\n // support, and the fill ins are not quite the same\n // offsetX/Y might be okay, but is not the same as clientX/Y when the canvas's top\n // left is not 0,0 on the page\n if (typeof touch.layerX === 'undefined') touch.layerX = touch.offsetX = touch.clientX;\n if (typeof touch.layerY === 'undefined') touch.layerY = touch.offsetY = touch.clientY;\n\n // mark the touch as normalized, just so that we know we did it\n touch.isNormalized = true;\n touch.type = event.type;\n\n normalizedEvents.push(touch);\n }\n }\n // apparently PointerEvent subclasses MouseEvent, so yay\n else if (!globalThis.MouseEvent\n || (event instanceof MouseEvent && (!this.supportsPointerEvents || !(event instanceof globalThis.PointerEvent))))\n {\n const tempEvent = event as PixiPointerEvent;\n\n if (typeof tempEvent.isPrimary === 'undefined') tempEvent.isPrimary = true;\n if (typeof tempEvent.width === 'undefined') tempEvent.width = 1;\n if (typeof tempEvent.height === 'undefined') tempEvent.height = 1;\n if (typeof tempEvent.tiltX === 'undefined') tempEvent.tiltX = 0;\n if (typeof tempEvent.tiltY === 'undefined') tempEvent.tiltY = 0;\n if (typeof tempEvent.pointerType === 'undefined') tempEvent.pointerType = 'mouse';\n if (typeof tempEvent.pointerId === 'undefined') tempEvent.pointerId = MOUSE_POINTER_ID;\n if (typeof tempEvent.pressure === 'undefined') tempEvent.pressure = 0.5;\n if (typeof tempEvent.twist === 'undefined') tempEvent.twist = 0;\n if (typeof tempEvent.tangentialPressure === 'undefined') tempEvent.tangentialPressure = 0;\n\n // mark the mouse event as normalized, just so that we know we did it\n tempEvent.isNormalized = true;\n\n normalizedEvents.push(tempEvent);\n }\n else\n {\n normalizedEvents.push(event);\n }\n\n return normalizedEvents as PointerEvent[];\n }\n\n /**\n * Normalizes the native {@link https://w3c.github.io/uievents/#interface-wheelevent WheelEvent}.\n *\n * The returned {@link FederatedWheelEvent} is a shared instance. It will not persist across\n * multiple native wheel events.\n * @param nativeEvent - The native wheel event that occurred on the canvas.\n * @returns A federated wheel event.\n */\n protected normalizeWheelEvent(nativeEvent: WheelEvent): FederatedWheelEvent\n {\n const event = this._rootWheelEvent;\n\n this._transferMouseData(event, nativeEvent);\n\n // When WheelEvent is triggered by scrolling with mouse wheel, reading WheelEvent.deltaMode\n // before deltaX/deltaY/deltaZ on Firefox will result in WheelEvent.DOM_DELTA_LINE (1),\n // while reading WheelEvent.deltaMode after deltaX/deltaY/deltaZ on Firefox or reading\n // in any order on other browsers will result in WheelEvent.DOM_DELTA_PIXEL (0).\n // Therefore, we need to read WheelEvent.deltaMode after deltaX/deltaY/deltaZ in order to\n // make its behavior more consistent across browsers.\n // @see https://github.com/pixijs/pixijs/issues/8970\n event.deltaX = nativeEvent.deltaX;\n event.deltaY = nativeEvent.deltaY;\n event.deltaZ = nativeEvent.deltaZ;\n event.deltaMode = nativeEvent.deltaMode;\n\n this.mapPositionToPoint(event.screen, nativeEvent.clientX, nativeEvent.clientY);\n event.global.copyFrom(event.screen);\n event.offset.copyFrom(event.screen);\n\n event.nativeEvent = nativeEvent;\n event.type = nativeEvent.type;\n\n return event;\n }\n\n /**\n * Normalizes the `nativeEvent` into a federateed {@link FederatedPointerEvent}.\n * @param event\n * @param nativeEvent\n */\n private _bootstrapEvent(event: FederatedPointerEvent, nativeEvent: PointerEvent): FederatedPointerEvent\n {\n event.originalEvent = null;\n event.nativeEvent = nativeEvent;\n\n event.pointerId = nativeEvent.pointerId;\n event.width = nativeEvent.width;\n event.height = nativeEvent.height;\n event.isPrimary = nativeEvent.isPrimary;\n event.pointerType = nativeEvent.pointerType;\n event.pressure = nativeEvent.pressure;\n event.tangentialPressure = nativeEvent.tangentialPressure;\n event.tiltX = nativeEvent.tiltX;\n event.tiltY = nativeEvent.tiltY;\n event.twist = nativeEvent.twist;\n this._transferMouseData(event, nativeEvent);\n\n this.mapPositionToPoint(event.screen, nativeEvent.clientX, nativeEvent.clientY);\n event.global.copyFrom(event.screen);// global = screen for top-level\n event.offset.copyFrom(event.screen);// EventBoundary recalculates using its rootTarget\n\n event.isTrusted = nativeEvent.isTrusted;\n if (event.type === 'pointerleave')\n {\n event.type = 'pointerout';\n }\n if (event.type.startsWith('mouse'))\n {\n event.type = event.type.replace('mouse', 'pointer');\n }\n if (event.type.startsWith('touch'))\n {\n event.type = TOUCH_TO_POINTER[event.type] || event.type;\n }\n\n return event;\n }\n\n /**\n * Transfers base & mouse event data from the `nativeEvent` to the federated event.\n * @param event\n * @param nativeEvent\n */\n private _transferMouseData(event: FederatedMouseEvent, nativeEvent: MouseEvent): void\n {\n event.isTrusted = nativeEvent.isTrusted;\n event.srcElement = nativeEvent.srcElement;\n event.timeStamp = performance.now();\n event.type = nativeEvent.type;\n\n event.altKey = nativeEvent.altKey;\n event.button = nativeEvent.button;\n event.buttons = nativeEvent.buttons;\n event.client.x = nativeEvent.clientX;\n event.client.y = nativeEvent.clientY;\n event.ctrlKey = nativeEvent.ctrlKey;\n event.metaKey = nativeEvent.metaKey;\n event.movement.x = nativeEvent.movementX;\n event.movement.y = nativeEvent.movementY;\n event.page.x = nativeEvent.pageX;\n event.page.y = nativeEvent.pageY;\n event.relatedTarget = null;\n event.shiftKey = nativeEvent.shiftKey;\n }\n}\n\ninterface CrossCSSStyleDeclaration extends CSSStyleDeclaration\n{\n msContentZooming: string;\n msTouchAction: string;\n}\n\ninterface PixiPointerEvent extends PointerEvent\n{\n isPrimary: boolean;\n width: number;\n height: number;\n tiltX: number;\n tiltY: number;\n pointerType: string;\n pointerId: number;\n pressure: number;\n twist: number;\n tangentialPressure: number;\n isNormalized: boolean;\n type: string;\n}\n"],"names":["nativeEvent"],"mappings":"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