@eva/plugin-worker 2.0.1-beta.27 → 2.0.1-beta.28
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/plugin-worker.cjs.js +1308 -3
- package/dist/plugin-worker.esm.js +1308 -3
- package/package.json +2 -2
|
@@ -9,14 +9,35 @@ function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'defau
|
|
|
9
9
|
|
|
10
10
|
var EventEmitter__default = /*#__PURE__*/_interopDefaultLegacy(EventEmitter);
|
|
11
11
|
|
|
12
|
+
/**
|
|
13
|
+
* 事件时钟类
|
|
14
|
+
*
|
|
15
|
+
* EventsTicker 用于在指针静止时自动触发指针事件,
|
|
16
|
+
* 确保即使指针不移动,移动的对象也能正确触发悬停测试。
|
|
17
|
+
* 这对于实现动态对象的鼠标交互至关重要。
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```typescript
|
|
21
|
+
* EventsTicker.init(eventSystem);
|
|
22
|
+
* EventsTicker.addTickerListener();
|
|
23
|
+
* EventsTicker.pointerMoved(); // 标记指针已移动
|
|
24
|
+
* ```
|
|
25
|
+
*
|
|
26
|
+
* @since 7.2.0
|
|
27
|
+
*/
|
|
12
28
|
class EventsTickerClass {
|
|
13
29
|
constructor() {
|
|
30
|
+
/** 触发模拟事件的频率(毫秒) */
|
|
14
31
|
this.interactionFrequency = 10;
|
|
15
32
|
this._deltaTime = 0;
|
|
16
33
|
this._didMove = false;
|
|
17
34
|
this._tickerAdded = false;
|
|
18
35
|
this._pauseUpdate = true;
|
|
19
36
|
}
|
|
37
|
+
/**
|
|
38
|
+
* Initializes the event ticker.
|
|
39
|
+
* @param events - The event system.
|
|
40
|
+
*/
|
|
20
41
|
init(events) {
|
|
21
42
|
this.removeTickerListener();
|
|
22
43
|
this.events = events;
|
|
@@ -26,12 +47,14 @@ class EventsTickerClass {
|
|
|
26
47
|
this._tickerAdded = false;
|
|
27
48
|
this._pauseUpdate = true;
|
|
28
49
|
}
|
|
50
|
+
/** Whether to pause the update checks or not. */
|
|
29
51
|
get pauseUpdate() {
|
|
30
52
|
return this._pauseUpdate;
|
|
31
53
|
}
|
|
32
54
|
set pauseUpdate(paused) {
|
|
33
55
|
this._pauseUpdate = paused;
|
|
34
56
|
}
|
|
57
|
+
/** Adds the ticker listener. */
|
|
35
58
|
addTickerListener() {
|
|
36
59
|
if (this._tickerAdded || !this.domElement) {
|
|
37
60
|
return;
|
|
@@ -39,6 +62,7 @@ class EventsTickerClass {
|
|
|
39
62
|
pixi_js.Ticker.system.add(this._tickerUpdate, this, pixi_js.UPDATE_PRIORITY.INTERACTION);
|
|
40
63
|
this._tickerAdded = true;
|
|
41
64
|
}
|
|
65
|
+
/** Removes the ticker listener. */
|
|
42
66
|
removeTickerListener() {
|
|
43
67
|
if (!this._tickerAdded) {
|
|
44
68
|
return;
|
|
@@ -46,17 +70,21 @@ class EventsTickerClass {
|
|
|
46
70
|
pixi_js.Ticker.system.remove(this._tickerUpdate, this);
|
|
47
71
|
this._tickerAdded = false;
|
|
48
72
|
}
|
|
73
|
+
/** Sets flag to not fire extra events when the user has already moved there mouse */
|
|
49
74
|
pointerMoved() {
|
|
50
75
|
this._didMove = true;
|
|
51
76
|
}
|
|
77
|
+
/** Updates the state of interactive objects. */
|
|
52
78
|
_update() {
|
|
53
79
|
if (!this.domElement || this._pauseUpdate) {
|
|
54
80
|
return;
|
|
55
81
|
}
|
|
82
|
+
// if the user move the mouse this check has already been done using the mouse move!
|
|
56
83
|
if (this._didMove) {
|
|
57
84
|
this._didMove = false;
|
|
58
85
|
return;
|
|
59
86
|
}
|
|
87
|
+
// eslint-disable-next-line dot-notation
|
|
60
88
|
const rootPointerEvent = this.events['_rootPointerEvent'];
|
|
61
89
|
if (this.events.supportsTouchEvents && rootPointerEvent.pointerType === 'touch') {
|
|
62
90
|
return;
|
|
@@ -68,6 +96,13 @@ class EventsTickerClass {
|
|
|
68
96
|
pointerId: rootPointerEvent.pointerId,
|
|
69
97
|
}));
|
|
70
98
|
}
|
|
99
|
+
/**
|
|
100
|
+
* Updates the state of interactive objects if at least {@link interactionFrequency}
|
|
101
|
+
* milliseconds have passed since the last invocation.
|
|
102
|
+
*
|
|
103
|
+
* Invoked by a throttled ticker update from {@link Ticker.system}.
|
|
104
|
+
* @param ticker - The throttled ticker.
|
|
105
|
+
*/
|
|
71
106
|
_tickerUpdate(ticker) {
|
|
72
107
|
this._deltaTime += ticker.deltaTime;
|
|
73
108
|
if (this._deltaTime < this.interactionFrequency) {
|
|
@@ -79,17 +114,64 @@ class EventsTickerClass {
|
|
|
79
114
|
}
|
|
80
115
|
const EventsTicker = new EventsTickerClass();
|
|
81
116
|
|
|
117
|
+
/**
|
|
118
|
+
* 联合事件类
|
|
119
|
+
*
|
|
120
|
+
* FederatedEvent 是一个兼容 DOM 的合成事件实现,
|
|
121
|
+
* 代表原始的 FederatedEvent 或原生 DOM 事件进行传播。
|
|
122
|
+
* 它提供了统一的事件接口,抹平了不同浏览器和设备之间的差异。
|
|
123
|
+
*
|
|
124
|
+
* 主要特性:
|
|
125
|
+
* - 兼容 DOM Event API
|
|
126
|
+
* - 支持事件冒泡和捕获
|
|
127
|
+
* - 提供事件传播控制
|
|
128
|
+
* - 记录事件路径
|
|
129
|
+
*
|
|
130
|
+
* @typeParam N - 持有的原生事件类型
|
|
131
|
+
*
|
|
132
|
+
* @example
|
|
133
|
+
* ```typescript
|
|
134
|
+
* sprite.on('pointerdown', (event: FederatedPointerEvent) => {
|
|
135
|
+
* console.log('Clicked at:', event.global.x, event.global.y);
|
|
136
|
+
* event.stopPropagation(); // 停止事件传播
|
|
137
|
+
* });
|
|
138
|
+
* ```
|
|
139
|
+
*/
|
|
82
140
|
class FederatedEvent {
|
|
141
|
+
/**
|
|
142
|
+
* @param manager - The event boundary which manages this event. Propagation can only occur
|
|
143
|
+
* within the boundary's jurisdiction.
|
|
144
|
+
*/
|
|
83
145
|
constructor(manager) {
|
|
146
|
+
/** 事件是否冒泡(仅在传播前设置有效) */
|
|
84
147
|
this.bubbles = true;
|
|
148
|
+
/** @deprecated 自 7.0.0 起弃用 */
|
|
85
149
|
this.cancelBubble = true;
|
|
150
|
+
/**
|
|
151
|
+
* 事件是否可以被取消
|
|
152
|
+
* @readonly
|
|
153
|
+
*/
|
|
86
154
|
this.cancelable = false;
|
|
155
|
+
/**
|
|
156
|
+
* Flag added for compatibility with DOM {@code Event}. It is not used in the Federated Events
|
|
157
|
+
* API.
|
|
158
|
+
* @see https://dom.spec.whatwg.org/#dom-event-composed
|
|
159
|
+
*/
|
|
87
160
|
this.composed = false;
|
|
161
|
+
/** Flags whether the default response of the user agent was prevent through this event. */
|
|
88
162
|
this.defaultPrevented = false;
|
|
163
|
+
/**
|
|
164
|
+
* The propagation phase.
|
|
165
|
+
* @default {@link FederatedEvent.NONE}
|
|
166
|
+
*/
|
|
89
167
|
this.eventPhase = FederatedEvent.prototype.NONE;
|
|
168
|
+
/** Flags whether propagation was stopped. */
|
|
90
169
|
this.propagationStopped = false;
|
|
170
|
+
/** Flags whether propagation was immediately stopped. */
|
|
91
171
|
this.propagationImmediatelyStopped = false;
|
|
172
|
+
/** The coordinates of the event relative to the nearest DOM layer. This is a non-standard property. */
|
|
92
173
|
this.layer = new pixi_js.Point();
|
|
174
|
+
/** The coordinates of the event relative to the DOM document. This is a non-standard property. */
|
|
93
175
|
this.page = new pixi_js.Point();
|
|
94
176
|
this.NONE = 0;
|
|
95
177
|
this.CAPTURING_PHASE = 1;
|
|
@@ -97,147 +179,373 @@ class FederatedEvent {
|
|
|
97
179
|
this.BUBBLING_PHASE = 3;
|
|
98
180
|
this.manager = manager;
|
|
99
181
|
}
|
|
182
|
+
/** @readonly */
|
|
100
183
|
get layerX() {
|
|
101
184
|
return this.layer.x;
|
|
102
185
|
}
|
|
186
|
+
/** @readonly */
|
|
103
187
|
get layerY() {
|
|
104
188
|
return this.layer.y;
|
|
105
189
|
}
|
|
190
|
+
/** @readonly */
|
|
106
191
|
get pageX() {
|
|
107
192
|
return this.page.x;
|
|
108
193
|
}
|
|
194
|
+
/** @readonly */
|
|
109
195
|
get pageY() {
|
|
110
196
|
return this.page.y;
|
|
111
197
|
}
|
|
198
|
+
/**
|
|
199
|
+
* Fallback for the deprecated @code{InteractionEvent.data}.
|
|
200
|
+
* @deprecated since 7.0.0
|
|
201
|
+
*/
|
|
112
202
|
get data() {
|
|
113
203
|
return this;
|
|
114
204
|
}
|
|
205
|
+
/** The propagation path for this event. Alias for {@link EventBoundary.propagationPath}. */
|
|
115
206
|
composedPath() {
|
|
207
|
+
// Find the propagation path if it isn't cached or if the target has changed since since
|
|
208
|
+
// the last evaluation.
|
|
116
209
|
if (this.manager && (!this.path || this.path[this.path.length - 1] !== this.target)) {
|
|
117
210
|
this.path = this.target ? this.manager.propagationPath(this.target) : [];
|
|
118
211
|
}
|
|
119
212
|
return this.path;
|
|
120
213
|
}
|
|
214
|
+
/**
|
|
215
|
+
* Unimplemented method included for implementing the DOM interface {@code Event}. It will throw an {@code Error}.
|
|
216
|
+
* @deprecated
|
|
217
|
+
* @param _type
|
|
218
|
+
* @param _bubbles
|
|
219
|
+
* @param _cancelable
|
|
220
|
+
*/
|
|
121
221
|
initEvent(_type, _bubbles, _cancelable) {
|
|
122
222
|
throw new Error('initEvent() is a legacy DOM API. It is not implemented in the Federated Events API.');
|
|
123
223
|
}
|
|
224
|
+
/**
|
|
225
|
+
* Unimplemented method included for implementing the DOM interface {@code UIEvent}. It will throw an {@code Error}.
|
|
226
|
+
* @deprecated
|
|
227
|
+
* @param _typeArg
|
|
228
|
+
* @param _bubblesArg
|
|
229
|
+
* @param _cancelableArg
|
|
230
|
+
* @param _viewArg
|
|
231
|
+
* @param _detailArg
|
|
232
|
+
*/
|
|
124
233
|
initUIEvent(_typeArg, _bubblesArg, _cancelableArg, _viewArg, _detailArg) {
|
|
125
234
|
throw new Error('initUIEvent() is a legacy DOM API. It is not implemented in the Federated Events API.');
|
|
126
235
|
}
|
|
236
|
+
/** Prevent default behavior of PixiJS and the user agent. */
|
|
127
237
|
preventDefault() {
|
|
128
238
|
if (this.nativeEvent instanceof Event && this.nativeEvent.cancelable) {
|
|
129
239
|
this.nativeEvent.preventDefault();
|
|
130
240
|
}
|
|
131
241
|
this.defaultPrevented = true;
|
|
132
242
|
}
|
|
243
|
+
/**
|
|
244
|
+
* Stop this event from propagating to any addition listeners, including on the
|
|
245
|
+
* {@link FederatedEventTarget.currentTarget currentTarget} and also the following
|
|
246
|
+
* event targets on the propagation path.
|
|
247
|
+
*/
|
|
133
248
|
stopImmediatePropagation() {
|
|
134
249
|
this.propagationImmediatelyStopped = true;
|
|
135
250
|
}
|
|
251
|
+
/**
|
|
252
|
+
* Stop this event from propagating to the next {@link FederatedEventTarget}. The rest of the listeners
|
|
253
|
+
* on the {@link FederatedEventTarget.currentTarget currentTarget} will still be notified.
|
|
254
|
+
*/
|
|
136
255
|
stopPropagation() {
|
|
137
256
|
this.propagationStopped = true;
|
|
138
257
|
}
|
|
139
258
|
}
|
|
140
259
|
|
|
260
|
+
/**
|
|
261
|
+
* A {@link FederatedEvent} for mouse events.
|
|
262
|
+
* @memberof events
|
|
263
|
+
*/
|
|
141
264
|
class FederatedMouseEvent extends FederatedEvent {
|
|
142
265
|
constructor() {
|
|
143
266
|
super(...arguments);
|
|
267
|
+
/** The coordinates of the mouse event relative to the canvas. */
|
|
144
268
|
this.client = new pixi_js.Point();
|
|
269
|
+
/** The movement in this pointer relative to the last `mousemove` event. */
|
|
145
270
|
this.movement = new pixi_js.Point();
|
|
271
|
+
/** The offset of the pointer coordinates w.r.t. target Container in world space. This is not supported at the moment. */
|
|
146
272
|
this.offset = new pixi_js.Point();
|
|
273
|
+
/** The pointer coordinates in world space. */
|
|
147
274
|
this.global = new pixi_js.Point();
|
|
275
|
+
/**
|
|
276
|
+
* The pointer coordinates in the renderer's {@link Renderer.screen screen}. This has slightly
|
|
277
|
+
* different semantics than native PointerEvent screenX/screenY.
|
|
278
|
+
*/
|
|
148
279
|
this.screen = new pixi_js.Point();
|
|
149
280
|
}
|
|
281
|
+
/** @readonly */
|
|
150
282
|
get clientX() {
|
|
151
283
|
return this.client.x;
|
|
152
284
|
}
|
|
285
|
+
/** @readonly */
|
|
153
286
|
get clientY() {
|
|
154
287
|
return this.client.y;
|
|
155
288
|
}
|
|
289
|
+
/**
|
|
290
|
+
* Alias for {@link FederatedMouseEvent.clientX this.clientX}.
|
|
291
|
+
* @readonly
|
|
292
|
+
*/
|
|
156
293
|
get x() {
|
|
157
294
|
return this.clientX;
|
|
158
295
|
}
|
|
296
|
+
/**
|
|
297
|
+
* Alias for {@link FederatedMouseEvent.clientY this.clientY}.
|
|
298
|
+
* @readonly
|
|
299
|
+
*/
|
|
159
300
|
get y() {
|
|
160
301
|
return this.clientY;
|
|
161
302
|
}
|
|
303
|
+
/** @readonly */
|
|
162
304
|
get movementX() {
|
|
163
305
|
return this.movement.x;
|
|
164
306
|
}
|
|
307
|
+
/** @readonly */
|
|
165
308
|
get movementY() {
|
|
166
309
|
return this.movement.y;
|
|
167
310
|
}
|
|
311
|
+
/** @readonly */
|
|
168
312
|
get offsetX() {
|
|
169
313
|
return this.offset.x;
|
|
170
314
|
}
|
|
315
|
+
/** @readonly */
|
|
171
316
|
get offsetY() {
|
|
172
317
|
return this.offset.y;
|
|
173
318
|
}
|
|
319
|
+
/** @readonly */
|
|
174
320
|
get globalX() {
|
|
175
321
|
return this.global.x;
|
|
176
322
|
}
|
|
323
|
+
/** @readonly */
|
|
177
324
|
get globalY() {
|
|
178
325
|
return this.global.y;
|
|
179
326
|
}
|
|
327
|
+
/**
|
|
328
|
+
* The pointer coordinates in the renderer's screen. Alias for {@code screen.x}.
|
|
329
|
+
* @readonly
|
|
330
|
+
*/
|
|
180
331
|
get screenX() {
|
|
181
332
|
return this.screen.x;
|
|
182
333
|
}
|
|
334
|
+
/**
|
|
335
|
+
* The pointer coordinates in the renderer's screen. Alias for {@code screen.y}.
|
|
336
|
+
* @readonly
|
|
337
|
+
*/
|
|
183
338
|
get screenY() {
|
|
184
339
|
return this.screen.y;
|
|
185
340
|
}
|
|
341
|
+
/**
|
|
342
|
+
* This will return the local coordinates of the specified container for this InteractionData
|
|
343
|
+
* @param {Container} container - The Container that you would like the local
|
|
344
|
+
* coords off
|
|
345
|
+
* @param {PointData} point - A Point object in which to store the value, optional (otherwise
|
|
346
|
+
* will create a new point)
|
|
347
|
+
* @param {PointData} globalPos - A Point object containing your custom global coords, optional
|
|
348
|
+
* (otherwise will use the current global coords)
|
|
349
|
+
* @returns - A point containing the coordinates of the InteractionData position relative
|
|
350
|
+
* to the Container
|
|
351
|
+
*/
|
|
186
352
|
getLocalPosition(container, point, globalPos) {
|
|
187
353
|
return container.worldTransform.applyInverse(globalPos || this.global, point);
|
|
188
354
|
}
|
|
355
|
+
/**
|
|
356
|
+
* Whether the modifier key was pressed when this event natively occurred.
|
|
357
|
+
* @param key - The modifier key.
|
|
358
|
+
*/
|
|
189
359
|
getModifierState(key) {
|
|
190
360
|
return 'getModifierState' in this.nativeEvent && this.nativeEvent.getModifierState(key);
|
|
191
361
|
}
|
|
362
|
+
/**
|
|
363
|
+
* Not supported.
|
|
364
|
+
* @param _typeArg
|
|
365
|
+
* @param _canBubbleArg
|
|
366
|
+
* @param _cancelableArg
|
|
367
|
+
* @param _viewArg
|
|
368
|
+
* @param _detailArg
|
|
369
|
+
* @param _screenXArg
|
|
370
|
+
* @param _screenYArg
|
|
371
|
+
* @param _clientXArg
|
|
372
|
+
* @param _clientYArg
|
|
373
|
+
* @param _ctrlKeyArg
|
|
374
|
+
* @param _altKeyArg
|
|
375
|
+
* @param _shiftKeyArg
|
|
376
|
+
* @param _metaKeyArg
|
|
377
|
+
* @param _buttonArg
|
|
378
|
+
* @param _relatedTargetArg
|
|
379
|
+
* @deprecated since 7.0.0
|
|
380
|
+
*/
|
|
381
|
+
// eslint-disable-next-line max-params
|
|
192
382
|
initMouseEvent(_typeArg, _canBubbleArg, _cancelableArg, _viewArg, _detailArg, _screenXArg, _screenYArg, _clientXArg, _clientYArg, _ctrlKeyArg, _altKeyArg, _shiftKeyArg, _metaKeyArg, _buttonArg, _relatedTargetArg) {
|
|
193
383
|
throw new Error('Method not implemented.');
|
|
194
384
|
}
|
|
195
385
|
}
|
|
196
386
|
|
|
387
|
+
/**
|
|
388
|
+
* A {@link FederatedEvent} for pointer events.
|
|
389
|
+
* @memberof events
|
|
390
|
+
*/
|
|
197
391
|
class FederatedPointerEvent extends FederatedMouseEvent {
|
|
198
392
|
constructor() {
|
|
199
393
|
super(...arguments);
|
|
394
|
+
/**
|
|
395
|
+
* The width of the pointer's contact along the x-axis, measured in CSS pixels.
|
|
396
|
+
* radiusX of TouchEvents will be represented by this value.
|
|
397
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/API/PointerEvent/width
|
|
398
|
+
*/
|
|
200
399
|
this.width = 0;
|
|
400
|
+
/**
|
|
401
|
+
* The height of the pointer's contact along the y-axis, measured in CSS pixels.
|
|
402
|
+
* radiusY of TouchEvents will be represented by this value.
|
|
403
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/API/PointerEvent/height
|
|
404
|
+
*/
|
|
201
405
|
this.height = 0;
|
|
406
|
+
/**
|
|
407
|
+
* Indicates whether or not the pointer device that created the event is the primary pointer.
|
|
408
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/API/PointerEvent/isPrimary
|
|
409
|
+
*/
|
|
202
410
|
this.isPrimary = false;
|
|
203
411
|
}
|
|
412
|
+
// Only included for completeness for now
|
|
204
413
|
getCoalescedEvents() {
|
|
205
414
|
if (this.type === 'pointermove' || this.type === 'mousemove' || this.type === 'touchmove') {
|
|
206
415
|
return [this];
|
|
207
416
|
}
|
|
208
417
|
return [];
|
|
209
418
|
}
|
|
419
|
+
// Only included for completeness for now
|
|
210
420
|
getPredictedEvents() {
|
|
211
421
|
throw new Error('getPredictedEvents is not supported!');
|
|
212
422
|
}
|
|
213
423
|
}
|
|
214
424
|
|
|
425
|
+
/**
|
|
426
|
+
* A {@link FederatedEvent} for wheel events.
|
|
427
|
+
* @memberof events
|
|
428
|
+
*/
|
|
215
429
|
class FederatedWheelEvent extends FederatedMouseEvent {
|
|
216
430
|
constructor() {
|
|
217
431
|
super(...arguments);
|
|
432
|
+
/** Units specified in pixels. */
|
|
218
433
|
this.DOM_DELTA_PIXEL = 0;
|
|
434
|
+
/** Units specified in lines. */
|
|
219
435
|
this.DOM_DELTA_LINE = 1;
|
|
436
|
+
/** Units specified in pages. */
|
|
220
437
|
this.DOM_DELTA_PAGE = 2;
|
|
221
438
|
}
|
|
222
439
|
}
|
|
440
|
+
/** Units specified in pixels. */
|
|
223
441
|
FederatedWheelEvent.DOM_DELTA_PIXEL = 0;
|
|
442
|
+
/** Units specified in lines. */
|
|
224
443
|
FederatedWheelEvent.DOM_DELTA_LINE = 1;
|
|
444
|
+
/** Units specified in pages. */
|
|
225
445
|
FederatedWheelEvent.DOM_DELTA_PAGE = 2;
|
|
226
446
|
|
|
447
|
+
// The maximum iterations used in propagation. This prevent infinite loops.
|
|
227
448
|
const PROPAGATION_LIMIT = 2048;
|
|
228
449
|
const tempHitLocation = new pixi_js.Point();
|
|
229
450
|
const tempLocalMapping = new pixi_js.Point();
|
|
451
|
+
/**
|
|
452
|
+
* Event boundaries are "barriers" where events coming from an upstream scene are modified before downstream propagation.
|
|
453
|
+
*
|
|
454
|
+
* ## Root event boundary
|
|
455
|
+
*
|
|
456
|
+
* The {@link EventSystem#rootBoundary rootBoundary} handles events coming from the <canvas />.
|
|
457
|
+
* {@link EventSystem} handles the normalization from native {@link https://dom.spec.whatwg.org/#event Events}
|
|
458
|
+
* into {@link FederatedEvent FederatedEvents}. The rootBoundary then does the hit-testing and event dispatch
|
|
459
|
+
* for the upstream normalized event.
|
|
460
|
+
*
|
|
461
|
+
* ## Additional event boundaries
|
|
462
|
+
*
|
|
463
|
+
* An additional event boundary may be desired within an application's scene graph. For example, if a portion of the scene is
|
|
464
|
+
* is flat with many children at one level - a spatial hash maybe needed to accelerate hit testing. In this scenario, the
|
|
465
|
+
* container can be detached from the scene and glued using a custom event boundary.
|
|
466
|
+
*
|
|
467
|
+
* ```ts
|
|
468
|
+
* import { Container } from 'pixi.js';
|
|
469
|
+
* import { EventBoundary } from 'pixi.js';
|
|
470
|
+
* import { SpatialHash } from 'pixi-spatial-hash';
|
|
471
|
+
*
|
|
472
|
+
* class HashedHitTestingEventBoundary
|
|
473
|
+
* {
|
|
474
|
+
* private spatialHash: SpatialHash;
|
|
475
|
+
*
|
|
476
|
+
* constructor(scene: Container, spatialHash: SpatialHash)
|
|
477
|
+
* {
|
|
478
|
+
* super(scene);
|
|
479
|
+
* this.spatialHash = spatialHash;
|
|
480
|
+
* }
|
|
481
|
+
*
|
|
482
|
+
* hitTestRecursive(...)
|
|
483
|
+
* {
|
|
484
|
+
* // TODO: If target === this.rootTarget, then use spatial hash to get a
|
|
485
|
+
* // list of possible children that match the given (x,y) coordinates.
|
|
486
|
+
* }
|
|
487
|
+
* }
|
|
488
|
+
*
|
|
489
|
+
* class VastScene extends Container
|
|
490
|
+
* {
|
|
491
|
+
* protected eventBoundary: EventBoundary;
|
|
492
|
+
* protected scene: Container;
|
|
493
|
+
* protected spatialHash: SpatialHash;
|
|
494
|
+
*
|
|
495
|
+
* constructor()
|
|
496
|
+
* {
|
|
497
|
+
* this.scene = new Container();
|
|
498
|
+
* this.spatialHash = new SpatialHash();
|
|
499
|
+
* this.eventBoundary = new HashedHitTestingEventBoundary(this.scene, this.spatialHash);
|
|
500
|
+
*
|
|
501
|
+
* // Populate this.scene with a ton of children, while updating this.spatialHash
|
|
502
|
+
* }
|
|
503
|
+
* }
|
|
504
|
+
* ```
|
|
505
|
+
* @memberof events
|
|
506
|
+
*/
|
|
230
507
|
class EventBoundary {
|
|
508
|
+
/**
|
|
509
|
+
* @param rootTarget - The holder of the event boundary.
|
|
510
|
+
*/
|
|
231
511
|
constructor(rootTarget) {
|
|
512
|
+
/**
|
|
513
|
+
* Emits events after they were dispatched into the scene graph.
|
|
514
|
+
*
|
|
515
|
+
* This can be used for global events listening, regardless of the scene graph being used. It should
|
|
516
|
+
* not be used by interactive libraries for normal use.
|
|
517
|
+
*
|
|
518
|
+
* Special events that do not bubble all the way to the root target are not emitted from here,
|
|
519
|
+
* e.g. pointerenter, pointerleave, click.
|
|
520
|
+
*/
|
|
232
521
|
this.dispatch = new EventEmitter__default();
|
|
522
|
+
/**
|
|
523
|
+
* This flag would emit `pointermove`, `touchmove`, and `mousemove` events on all Containers.
|
|
524
|
+
*
|
|
525
|
+
* The `moveOnAll` semantics mirror those of earlier versions of PixiJS. This was disabled in favor of
|
|
526
|
+
* the Pointer Event API's approach.
|
|
527
|
+
*/
|
|
233
528
|
this.moveOnAll = false;
|
|
529
|
+
/** Enables the global move events. `globalpointermove`, `globaltouchmove`, and `globalmousemove` */
|
|
234
530
|
this.enableGlobalMoveEvents = true;
|
|
531
|
+
/**
|
|
532
|
+
* State object for mapping methods.
|
|
533
|
+
* @see EventBoundary#trackingData
|
|
534
|
+
*/
|
|
235
535
|
this.mappingState = {
|
|
236
536
|
trackingData: {},
|
|
237
537
|
};
|
|
538
|
+
/**
|
|
539
|
+
* The event pool maps event constructors to an free pool of instances of those specific events.
|
|
540
|
+
* @see EventBoundary#allocateEvent
|
|
541
|
+
* @see EventBoundary#freeEvent
|
|
542
|
+
*/
|
|
238
543
|
this.eventPool = new Map();
|
|
544
|
+
/** Every interactive element gathered from the scene. Only used in `pointermove` */
|
|
239
545
|
this._allInteractiveElements = [];
|
|
546
|
+
/** Every element that passed the hit test. Only used in `pointermove` */
|
|
240
547
|
this._hitElements = [];
|
|
548
|
+
/** Whether or not to collect all the interactive elements from the scene. Enabled in `pointermove` */
|
|
241
549
|
this._isPointerMoveEvent = false;
|
|
242
550
|
this.rootTarget = rootTarget;
|
|
243
551
|
this.hitPruneFn = this.hitPruneFn.bind(this);
|
|
@@ -259,6 +567,18 @@ class EventBoundary {
|
|
|
259
567
|
this.addEventMapping('pointerupoutside', this.mapPointerUpOutside);
|
|
260
568
|
this.addEventMapping('wheel', this.mapWheel);
|
|
261
569
|
}
|
|
570
|
+
/**
|
|
571
|
+
* Adds an event mapping for the event `type` handled by `fn`.
|
|
572
|
+
*
|
|
573
|
+
* Event mappings can be used to implement additional or custom events. They take an event
|
|
574
|
+
* coming from the upstream scene (or directly from the {@link EventSystem}) and dispatch new downstream events
|
|
575
|
+
* generally trickling down and bubbling up to {@link EventBoundary.rootTarget this.rootTarget}.
|
|
576
|
+
*
|
|
577
|
+
* To modify the semantics of existing events, the built-in mapping methods of EventBoundary should be overridden
|
|
578
|
+
* instead.
|
|
579
|
+
* @param type - The type of upstream event to map.
|
|
580
|
+
* @param fn - The mapping method. The context of this function must be bound manually, if desired.
|
|
581
|
+
*/
|
|
262
582
|
addEventMapping(type, fn) {
|
|
263
583
|
if (!this.mappingTable[type]) {
|
|
264
584
|
this.mappingTable[type] = [];
|
|
@@ -269,12 +589,21 @@ class EventBoundary {
|
|
|
269
589
|
});
|
|
270
590
|
this.mappingTable[type].sort((a, b) => a.priority - b.priority);
|
|
271
591
|
}
|
|
592
|
+
/**
|
|
593
|
+
* Dispatches the given event
|
|
594
|
+
* @param e - The event to dispatch.
|
|
595
|
+
* @param type - The type of event to dispatch. Defaults to `e.type`.
|
|
596
|
+
*/
|
|
272
597
|
dispatchEvent(e, type) {
|
|
273
598
|
e.propagationStopped = false;
|
|
274
599
|
e.propagationImmediatelyStopped = false;
|
|
275
600
|
this.propagate(e, type);
|
|
276
601
|
this.dispatch.emit(type || e.type, e);
|
|
277
602
|
}
|
|
603
|
+
/**
|
|
604
|
+
* Maps the given upstream event through the event boundary and propagates it downstream.
|
|
605
|
+
* @param e - The event to map.
|
|
606
|
+
*/
|
|
278
607
|
mapEvent(e) {
|
|
279
608
|
if (!this.rootTarget) {
|
|
280
609
|
return;
|
|
@@ -286,21 +615,39 @@ class EventBoundary {
|
|
|
286
615
|
}
|
|
287
616
|
}
|
|
288
617
|
else {
|
|
618
|
+
// #if _DEBUG
|
|
289
619
|
pixi_js.warn(`[EventBoundary]: Event mapping not defined for ${e.type}`);
|
|
620
|
+
// #endif
|
|
290
621
|
}
|
|
291
622
|
}
|
|
623
|
+
/**
|
|
624
|
+
* Finds the Container that is the target of a event at the given coordinates.
|
|
625
|
+
*
|
|
626
|
+
* The passed (x,y) coordinates are in the world space above this event boundary.
|
|
627
|
+
* @param x - The x coordinate of the event.
|
|
628
|
+
* @param y - The y coordinate of the event.
|
|
629
|
+
*/
|
|
292
630
|
hitTest(x, y) {
|
|
293
631
|
EventsTicker.pauseUpdate = true;
|
|
632
|
+
// if we are using global move events, we need to hit test the whole scene graph
|
|
294
633
|
const useMove = this._isPointerMoveEvent && this.enableGlobalMoveEvents;
|
|
295
634
|
const fn = useMove ? 'hitTestMoveRecursive' : 'hitTestRecursive';
|
|
296
635
|
const invertedPath = this[fn](this.rootTarget, this.rootTarget.eventMode, tempHitLocation.set(x, y), this.hitTestFn, this.hitPruneFn);
|
|
297
636
|
return invertedPath && invertedPath[0];
|
|
298
637
|
}
|
|
638
|
+
/**
|
|
639
|
+
* Propagate the passed event from from {@link EventBoundary.rootTarget this.rootTarget} to its
|
|
640
|
+
* target {@code e.target}.
|
|
641
|
+
* @param e - The event to propagate.
|
|
642
|
+
* @param type - The type of event to propagate. Defaults to `e.type`.
|
|
643
|
+
*/
|
|
299
644
|
propagate(e, type) {
|
|
300
645
|
if (!e.target) {
|
|
646
|
+
// This usually occurs when the scene graph is not interactive.
|
|
301
647
|
return;
|
|
302
648
|
}
|
|
303
649
|
const composedPath = e.composedPath();
|
|
650
|
+
// Capturing phase
|
|
304
651
|
e.eventPhase = e.CAPTURING_PHASE;
|
|
305
652
|
for (let i = 0, j = composedPath.length - 1; i < j; i++) {
|
|
306
653
|
e.currentTarget = composedPath[i];
|
|
@@ -308,11 +655,13 @@ class EventBoundary {
|
|
|
308
655
|
if (e.propagationStopped || e.propagationImmediatelyStopped)
|
|
309
656
|
return;
|
|
310
657
|
}
|
|
658
|
+
// At target phase
|
|
311
659
|
e.eventPhase = e.AT_TARGET;
|
|
312
660
|
e.currentTarget = e.target;
|
|
313
661
|
this.notifyTarget(e, type);
|
|
314
662
|
if (e.propagationStopped || e.propagationImmediatelyStopped)
|
|
315
663
|
return;
|
|
664
|
+
// Bubbling phase
|
|
316
665
|
e.eventPhase = e.BUBBLING_PHASE;
|
|
317
666
|
for (let i = composedPath.length - 2; i >= 0; i--) {
|
|
318
667
|
e.currentTarget = composedPath[i];
|
|
@@ -321,11 +670,21 @@ class EventBoundary {
|
|
|
321
670
|
return;
|
|
322
671
|
}
|
|
323
672
|
}
|
|
673
|
+
/**
|
|
674
|
+
* Emits the event {@code e} to all interactive containers. The event is propagated in the bubbling phase always.
|
|
675
|
+
*
|
|
676
|
+
* This is used in the `globalpointermove` event.
|
|
677
|
+
* @param e - The emitted event.
|
|
678
|
+
* @param type - The listeners to notify.
|
|
679
|
+
* @param targets - The targets to notify.
|
|
680
|
+
*/
|
|
324
681
|
all(e, type, targets = this._allInteractiveElements) {
|
|
325
682
|
if (targets.length === 0)
|
|
326
683
|
return;
|
|
327
684
|
e.eventPhase = e.BUBBLING_PHASE;
|
|
328
685
|
const events = Array.isArray(type) ? type : [type];
|
|
686
|
+
// loop through all interactive elements and notify them of the event
|
|
687
|
+
// loop through targets backwards
|
|
329
688
|
for (let i = targets.length - 1; i >= 0; i--) {
|
|
330
689
|
events.forEach(event => {
|
|
331
690
|
e.currentTarget = targets[i];
|
|
@@ -333,6 +692,11 @@ class EventBoundary {
|
|
|
333
692
|
});
|
|
334
693
|
}
|
|
335
694
|
}
|
|
695
|
+
/**
|
|
696
|
+
* Finds the propagation path from {@link EventBoundary.rootTarget rootTarget} to the passed
|
|
697
|
+
* {@code target}. The last element in the path is {@code target}.
|
|
698
|
+
* @param target - The target to find the propagation path to.
|
|
699
|
+
*/
|
|
336
700
|
propagationPath(target) {
|
|
337
701
|
const propagationPath = [target];
|
|
338
702
|
for (let i = 0; i < PROPAGATION_LIMIT && target !== this.rootTarget && target.parent; i++) {
|
|
@@ -347,6 +711,7 @@ class EventBoundary {
|
|
|
347
711
|
}
|
|
348
712
|
hitTestMoveRecursive(currentTarget, eventMode, location, testFn, pruneFn, ignore = false) {
|
|
349
713
|
let shouldReturn = false;
|
|
714
|
+
// only bail out early if it is not interactive
|
|
350
715
|
if (this._interactivePrune(currentTarget))
|
|
351
716
|
return null;
|
|
352
717
|
if (currentTarget.eventMode === 'dynamic' || eventMode === 'dynamic') {
|
|
@@ -358,15 +723,21 @@ class EventBoundary {
|
|
|
358
723
|
const child = children[i];
|
|
359
724
|
const nestedHit = this.hitTestMoveRecursive(child, this._isInteractive(eventMode) ? eventMode : child.eventMode, location, testFn, pruneFn, ignore || pruneFn(currentTarget, location));
|
|
360
725
|
if (nestedHit) {
|
|
726
|
+
// Its a good idea to check if a child has lost its parent.
|
|
727
|
+
// this means it has been removed whilst looping so its best
|
|
361
728
|
if (nestedHit.length > 0 && !nestedHit[nestedHit.length - 1].parent) {
|
|
362
729
|
continue;
|
|
363
730
|
}
|
|
731
|
+
// Only add the current hit-test target to the hit-test chain if the chain
|
|
732
|
+
// has already started (i.e. the event target has been found) or if the current
|
|
733
|
+
// target is interactive (i.e. it becomes the event target).
|
|
364
734
|
const isInteractive = currentTarget.isInteractive();
|
|
365
735
|
if (nestedHit.length > 0 || isInteractive) {
|
|
366
736
|
if (isInteractive)
|
|
367
737
|
this._allInteractiveElements.push(currentTarget);
|
|
368
738
|
nestedHit.push(currentTarget);
|
|
369
739
|
}
|
|
740
|
+
// store all hit elements to be returned once we have traversed the whole tree
|
|
370
741
|
if (this._hitElements.length === 0)
|
|
371
742
|
this._hitElements = nestedHit;
|
|
372
743
|
shouldReturn = true;
|
|
@@ -377,22 +748,43 @@ class EventBoundary {
|
|
|
377
748
|
const isInteractiveTarget = currentTarget.isInteractive();
|
|
378
749
|
if (isInteractiveTarget && isInteractiveTarget)
|
|
379
750
|
this._allInteractiveElements.push(currentTarget);
|
|
751
|
+
// we don't carry on hit testing something once we have found a hit,
|
|
752
|
+
// now only care about gathering the interactive elements
|
|
380
753
|
if (ignore || this._hitElements.length > 0)
|
|
381
754
|
return null;
|
|
382
755
|
if (shouldReturn)
|
|
383
756
|
return this._hitElements;
|
|
757
|
+
// Finally, hit test this Container itself.
|
|
384
758
|
if (isInteractiveMode && !pruneFn(currentTarget, location) && testFn(currentTarget, location)) {
|
|
759
|
+
// The current hit-test target is the event's target only if it is interactive. Otherwise,
|
|
760
|
+
// the first interactive ancestor will be the event's target.
|
|
385
761
|
return isInteractiveTarget ? [currentTarget] : [];
|
|
386
762
|
}
|
|
387
763
|
return null;
|
|
388
764
|
}
|
|
765
|
+
/**
|
|
766
|
+
* Recursive implementation for {@link EventBoundary.hitTest hitTest}.
|
|
767
|
+
* @param currentTarget - The Container that is to be hit tested.
|
|
768
|
+
* @param eventMode - The event mode for the `currentTarget` or one of its parents.
|
|
769
|
+
* @param location - The location that is being tested for overlap.
|
|
770
|
+
* @param testFn - Callback that determines whether the target passes hit testing. This callback
|
|
771
|
+
* can assume that `pruneFn` failed to prune the container.
|
|
772
|
+
* @param pruneFn - Callback that determiness whether the target and all of its children
|
|
773
|
+
* cannot pass the hit test. It is used as a preliminary optimization to prune entire subtrees
|
|
774
|
+
* of the scene graph.
|
|
775
|
+
* @returns An array holding the hit testing target and all its ancestors in order. The first element
|
|
776
|
+
* is the target itself and the last is {@link EventBoundary.rootTarget rootTarget}. This is the opposite
|
|
777
|
+
* order w.r.t. the propagation path. If no hit testing target is found, null is returned.
|
|
778
|
+
*/
|
|
389
779
|
hitTestRecursive(currentTarget, eventMode, location, testFn, pruneFn) {
|
|
780
|
+
// Attempt to prune this Container and its subtree as an optimization.
|
|
390
781
|
if (this._interactivePrune(currentTarget) || pruneFn(currentTarget, location)) {
|
|
391
782
|
return null;
|
|
392
783
|
}
|
|
393
784
|
if (currentTarget.eventMode === 'dynamic' || eventMode === 'dynamic') {
|
|
394
785
|
EventsTicker.pauseUpdate = false;
|
|
395
786
|
}
|
|
787
|
+
// Find a child that passes the hit testing and return one, if any.
|
|
396
788
|
if (currentTarget.interactiveChildren && currentTarget.children) {
|
|
397
789
|
const children = currentTarget.children;
|
|
398
790
|
const relativeLocation = location;
|
|
@@ -400,9 +792,14 @@ class EventBoundary {
|
|
|
400
792
|
const child = children[i];
|
|
401
793
|
const nestedHit = this.hitTestRecursive(child, this._isInteractive(eventMode) ? eventMode : child.eventMode, relativeLocation, testFn, pruneFn);
|
|
402
794
|
if (nestedHit) {
|
|
795
|
+
// Its a good idea to check if a child has lost its parent.
|
|
796
|
+
// this means it has been removed whilst looping so its best
|
|
403
797
|
if (nestedHit.length > 0 && !nestedHit[nestedHit.length - 1].parent) {
|
|
404
798
|
continue;
|
|
405
799
|
}
|
|
800
|
+
// Only add the current hit-test target to the hit-test chain if the chain
|
|
801
|
+
// has already started (i.e. the event target has been found) or if the current
|
|
802
|
+
// target is interactive (i.e. it becomes the event target).
|
|
406
803
|
const isInteractive = currentTarget.isInteractive();
|
|
407
804
|
if (nestedHit.length > 0 || isInteractive)
|
|
408
805
|
nestedHit.push(currentTarget);
|
|
@@ -412,7 +809,10 @@ class EventBoundary {
|
|
|
412
809
|
}
|
|
413
810
|
const isInteractiveMode = this._isInteractive(eventMode);
|
|
414
811
|
const isInteractiveTarget = currentTarget.isInteractive();
|
|
812
|
+
// Finally, hit test this Container itself.
|
|
415
813
|
if (isInteractiveMode && testFn(currentTarget, location)) {
|
|
814
|
+
// The current hit-test target is the event's target only if it is interactive. Otherwise,
|
|
815
|
+
// the first interactive ancestor will be the event's target.
|
|
416
816
|
return isInteractiveTarget ? [currentTarget] : [];
|
|
417
817
|
}
|
|
418
818
|
return null;
|
|
@@ -421,17 +821,28 @@ class EventBoundary {
|
|
|
421
821
|
return int === 'static' || int === 'dynamic';
|
|
422
822
|
}
|
|
423
823
|
_interactivePrune(container) {
|
|
824
|
+
// If container is a mask, invisible, or not renderable then it cannot be hit directly.
|
|
424
825
|
if (!container || !container.visible || !container.renderable || !container.measurable) {
|
|
425
826
|
return true;
|
|
426
827
|
}
|
|
828
|
+
// If this Container is none then it cannot be hit by anything.
|
|
427
829
|
if (container.eventMode === 'none') {
|
|
428
830
|
return true;
|
|
429
831
|
}
|
|
832
|
+
// If this Container is passive and it has no interactive children then it cannot be hit
|
|
430
833
|
if (container.eventMode === 'passive' && !container.interactiveChildren) {
|
|
431
834
|
return true;
|
|
432
835
|
}
|
|
433
836
|
return false;
|
|
434
837
|
}
|
|
838
|
+
/**
|
|
839
|
+
* Checks whether the container or any of its children cannot pass the hit test at all.
|
|
840
|
+
*
|
|
841
|
+
* {@link EventBoundary}'s implementation uses the {@link Container.hitArea hitArea}
|
|
842
|
+
* and {@link Container._maskEffect} for pruning.
|
|
843
|
+
* @param container - The container to prune.
|
|
844
|
+
* @param location - The location to test for overlap.
|
|
845
|
+
*/
|
|
435
846
|
hitPruneFn(container, location) {
|
|
436
847
|
if (container.hitArea) {
|
|
437
848
|
container.worldTransform.applyInverse(location, tempLocalMapping);
|
|
@@ -452,8 +863,15 @@ class EventBoundary {
|
|
|
452
863
|
}
|
|
453
864
|
return false;
|
|
454
865
|
}
|
|
866
|
+
/**
|
|
867
|
+
* Checks whether the container passes hit testing for the given location.
|
|
868
|
+
* @param container - The container to test.
|
|
869
|
+
* @param location - The location to test for overlap.
|
|
870
|
+
* @returns - Whether `container` passes hit testing for `location`.
|
|
871
|
+
*/
|
|
455
872
|
hitTestFn(container, location) {
|
|
456
873
|
var _a;
|
|
874
|
+
// If the container failed pruning with a hitArea, then it must pass it.
|
|
457
875
|
if (container.hitArea) {
|
|
458
876
|
return true;
|
|
459
877
|
}
|
|
@@ -461,14 +879,24 @@ class EventBoundary {
|
|
|
461
879
|
container.worldTransform.applyInverse(location, tempLocalMapping);
|
|
462
880
|
return container.containsPoint(tempLocalMapping);
|
|
463
881
|
}
|
|
882
|
+
// TODO: Should we hit test based on bounds?
|
|
464
883
|
return false;
|
|
465
884
|
}
|
|
885
|
+
/**
|
|
886
|
+
* Notify all the listeners to the event's `currentTarget`.
|
|
887
|
+
*
|
|
888
|
+
* If the `currentTarget` contains the property `on<type>`, then it is called here,
|
|
889
|
+
* simulating the behavior from version 6.x and prior.
|
|
890
|
+
* @param e - The event passed to the target.
|
|
891
|
+
* @param type - The type of event to notify. Defaults to `e.type`.
|
|
892
|
+
*/
|
|
466
893
|
notifyTarget(e, type) {
|
|
467
894
|
var _a;
|
|
468
895
|
if (!e.currentTarget.isInteractive()) {
|
|
469
896
|
return;
|
|
470
897
|
}
|
|
471
898
|
type = type !== null && type !== void 0 ? type : e.type;
|
|
899
|
+
// call the `on${type}` for the current target if it exists
|
|
472
900
|
const handlerKey = `on${type}`;
|
|
473
901
|
(_a = e.currentTarget[handlerKey]) === null || _a === void 0 ? void 0 : _a(e);
|
|
474
902
|
const key = e.eventPhase === e.CAPTURING_PHASE || e.eventPhase === e.AT_TARGET ? `${type}capture` : type;
|
|
@@ -477,9 +905,17 @@ class EventBoundary {
|
|
|
477
905
|
this._notifyListeners(e, type);
|
|
478
906
|
}
|
|
479
907
|
}
|
|
908
|
+
/**
|
|
909
|
+
* Maps the upstream `pointerdown` events to a downstream `pointerdown` event.
|
|
910
|
+
*
|
|
911
|
+
* `touchstart`, `rightdown`, `mousedown` events are also dispatched for specific pointer types.
|
|
912
|
+
* @param from - The upstream `pointerdown` event.
|
|
913
|
+
*/
|
|
480
914
|
mapPointerDown(from) {
|
|
481
915
|
if (!(from instanceof FederatedPointerEvent)) {
|
|
916
|
+
// #if _DEBUG
|
|
482
917
|
pixi_js.warn('EventBoundary cannot map a non-pointer event as a pointer event');
|
|
918
|
+
// #endif
|
|
483
919
|
return;
|
|
484
920
|
}
|
|
485
921
|
const e = this.createPointerEvent(from);
|
|
@@ -495,10 +931,19 @@ class EventBoundary {
|
|
|
495
931
|
trackingData.pressTargetsByButton[from.button] = e.composedPath();
|
|
496
932
|
this.freeEvent(e);
|
|
497
933
|
}
|
|
934
|
+
/**
|
|
935
|
+
* Maps the upstream `pointermove` to downstream `pointerout`, `pointerover`, and `pointermove` events, in that order.
|
|
936
|
+
*
|
|
937
|
+
* The tracking data for the specific pointer has an updated `overTarget`. `mouseout`, `mouseover`,
|
|
938
|
+
* `mousemove`, and `touchmove` events are fired as well for specific pointer types.
|
|
939
|
+
* @param from - The upstream `pointermove` event.
|
|
940
|
+
*/
|
|
498
941
|
mapPointerMove(from) {
|
|
499
942
|
var _a, _b, _c;
|
|
500
943
|
if (!(from instanceof FederatedPointerEvent)) {
|
|
944
|
+
// #if _DEBUG
|
|
501
945
|
pixi_js.warn('EventBoundary cannot map a non-pointer event as a pointer event');
|
|
946
|
+
// #endif
|
|
502
947
|
return;
|
|
503
948
|
}
|
|
504
949
|
this._allInteractiveElements.length = 0;
|
|
@@ -509,12 +954,16 @@ class EventBoundary {
|
|
|
509
954
|
const isMouse = e.pointerType === 'mouse' || e.pointerType === 'pen';
|
|
510
955
|
const trackingData = this.trackingData(from.pointerId);
|
|
511
956
|
const outTarget = this.findMountedTarget(trackingData.overTargets);
|
|
957
|
+
// First pointerout/pointerleave
|
|
512
958
|
if (((_a = trackingData.overTargets) === null || _a === void 0 ? void 0 : _a.length) > 0 && outTarget !== e.target) {
|
|
959
|
+
// pointerout always occurs on the overTarget when the pointer hovers over another element.
|
|
513
960
|
const outType = from.type === 'mousemove' ? 'mouseout' : 'pointerout';
|
|
514
961
|
const outEvent = this.createPointerEvent(from, outType, outTarget);
|
|
515
962
|
this.dispatchEvent(outEvent, 'pointerout');
|
|
516
963
|
if (isMouse)
|
|
517
964
|
this.dispatchEvent(outEvent, 'mouseout');
|
|
965
|
+
// If the pointer exits overTarget and its descendants, then a pointerleave event is also fired. This event
|
|
966
|
+
// is dispatched to all ancestors that no longer capture the pointer.
|
|
518
967
|
if (!e.composedPath().includes(outTarget)) {
|
|
519
968
|
const leaveEvent = this.createPointerEvent(from, 'pointerleave', outTarget);
|
|
520
969
|
leaveEvent.eventPhase = leaveEvent.AT_TARGET;
|
|
@@ -529,18 +978,23 @@ class EventBoundary {
|
|
|
529
978
|
}
|
|
530
979
|
this.freeEvent(outEvent);
|
|
531
980
|
}
|
|
981
|
+
// Then pointerover
|
|
532
982
|
if (outTarget !== e.target) {
|
|
983
|
+
// pointerover always occurs on the new overTarget
|
|
533
984
|
const overType = from.type === 'mousemove' ? 'mouseover' : 'pointerover';
|
|
534
|
-
const overEvent = this.clonePointerEvent(e, overType);
|
|
985
|
+
const overEvent = this.clonePointerEvent(e, overType); // clone faster
|
|
535
986
|
this.dispatchEvent(overEvent, 'pointerover');
|
|
536
987
|
if (isMouse)
|
|
537
988
|
this.dispatchEvent(overEvent, 'mouseover');
|
|
989
|
+
// Probe whether the newly hovered Container is an ancestor of the original overTarget.
|
|
538
990
|
let overTargetAncestor = outTarget === null || outTarget === void 0 ? void 0 : outTarget.parent;
|
|
539
991
|
while (overTargetAncestor && overTargetAncestor !== this.rootTarget.parent) {
|
|
540
992
|
if (overTargetAncestor === e.target)
|
|
541
993
|
break;
|
|
542
994
|
overTargetAncestor = overTargetAncestor.parent;
|
|
543
995
|
}
|
|
996
|
+
// The pointer has entered a non-ancestor of the original overTarget. This means we need a pointerentered
|
|
997
|
+
// event.
|
|
544
998
|
const didPointerEnter = !overTargetAncestor || overTargetAncestor === this.rootTarget.parent;
|
|
545
999
|
if (didPointerEnter) {
|
|
546
1000
|
const enterEvent = this.clonePointerEvent(e, 'pointerenter');
|
|
@@ -560,6 +1014,7 @@ class EventBoundary {
|
|
|
560
1014
|
const allowGlobalPointerEvents = (_b = this.enableGlobalMoveEvents) !== null && _b !== void 0 ? _b : true;
|
|
561
1015
|
this.moveOnAll ? allMethods.push('pointermove') : this.dispatchEvent(e, 'pointermove');
|
|
562
1016
|
allowGlobalPointerEvents && allMethods.push('globalpointermove');
|
|
1017
|
+
// Then pointermove
|
|
563
1018
|
if (e.pointerType === 'touch') {
|
|
564
1019
|
this.moveOnAll ? allMethods.splice(1, 0, 'touchmove') : this.dispatchEvent(e, 'touchmove');
|
|
565
1020
|
allowGlobalPointerEvents && allMethods.push('globaltouchmove');
|
|
@@ -577,10 +1032,18 @@ class EventBoundary {
|
|
|
577
1032
|
trackingData.overTargets = e.composedPath();
|
|
578
1033
|
this.freeEvent(e);
|
|
579
1034
|
}
|
|
1035
|
+
/**
|
|
1036
|
+
* Maps the upstream `pointerover` to downstream `pointerover` and `pointerenter` events, in that order.
|
|
1037
|
+
*
|
|
1038
|
+
* The tracking data for the specific pointer gets a new `overTarget`.
|
|
1039
|
+
* @param from - The upstream `pointerover` event.
|
|
1040
|
+
*/
|
|
580
1041
|
mapPointerOver(from) {
|
|
581
1042
|
var _a;
|
|
582
1043
|
if (!(from instanceof FederatedPointerEvent)) {
|
|
1044
|
+
// #if _DEBUG
|
|
583
1045
|
pixi_js.warn('EventBoundary cannot map a non-pointer event as a pointer event');
|
|
1046
|
+
// #endif
|
|
584
1047
|
return;
|
|
585
1048
|
}
|
|
586
1049
|
const trackingData = this.trackingData(from.pointerId);
|
|
@@ -591,6 +1054,7 @@ class EventBoundary {
|
|
|
591
1054
|
this.dispatchEvent(e, 'mouseover');
|
|
592
1055
|
if (e.pointerType === 'mouse')
|
|
593
1056
|
this.cursor = (_a = e.target) === null || _a === void 0 ? void 0 : _a.cursor;
|
|
1057
|
+
// pointerenter events must be fired since the pointer entered from upstream.
|
|
594
1058
|
const enterEvent = this.clonePointerEvent(e, 'pointerenter');
|
|
595
1059
|
enterEvent.eventPhase = enterEvent.AT_TARGET;
|
|
596
1060
|
while (enterEvent.target && enterEvent.target !== this.rootTarget.parent) {
|
|
@@ -604,19 +1068,30 @@ class EventBoundary {
|
|
|
604
1068
|
this.freeEvent(e);
|
|
605
1069
|
this.freeEvent(enterEvent);
|
|
606
1070
|
}
|
|
1071
|
+
/**
|
|
1072
|
+
* Maps the upstream `pointerout` to downstream `pointerout`, `pointerleave` events, in that order.
|
|
1073
|
+
*
|
|
1074
|
+
* The tracking data for the specific pointer is cleared of a `overTarget`.
|
|
1075
|
+
* @param from - The upstream `pointerout` event.
|
|
1076
|
+
*/
|
|
607
1077
|
mapPointerOut(from) {
|
|
608
1078
|
if (!(from instanceof FederatedPointerEvent)) {
|
|
1079
|
+
// #if _DEBUG
|
|
609
1080
|
pixi_js.warn('EventBoundary cannot map a non-pointer event as a pointer event');
|
|
1081
|
+
// #endif
|
|
610
1082
|
return;
|
|
611
1083
|
}
|
|
612
1084
|
const trackingData = this.trackingData(from.pointerId);
|
|
613
1085
|
if (trackingData.overTargets) {
|
|
614
1086
|
const isMouse = from.pointerType === 'mouse' || from.pointerType === 'pen';
|
|
615
1087
|
const outTarget = this.findMountedTarget(trackingData.overTargets);
|
|
1088
|
+
// pointerout first
|
|
616
1089
|
const outEvent = this.createPointerEvent(from, 'pointerout', outTarget);
|
|
617
1090
|
this.dispatchEvent(outEvent);
|
|
618
1091
|
if (isMouse)
|
|
619
1092
|
this.dispatchEvent(outEvent, 'mouseout');
|
|
1093
|
+
// pointerleave(s) are also dispatched b/c the pointer must've left rootTarget and its descendants to
|
|
1094
|
+
// get an upstream pointerout event (upstream events do not know rootTarget has descendants).
|
|
620
1095
|
const leaveEvent = this.createPointerEvent(from, 'pointerleave', outTarget);
|
|
621
1096
|
leaveEvent.eventPhase = leaveEvent.AT_TARGET;
|
|
622
1097
|
while (leaveEvent.target && leaveEvent.target !== this.rootTarget.parent) {
|
|
@@ -632,9 +1107,21 @@ class EventBoundary {
|
|
|
632
1107
|
}
|
|
633
1108
|
this.cursor = null;
|
|
634
1109
|
}
|
|
1110
|
+
/**
|
|
1111
|
+
* Maps the upstream `pointerup` event to downstream `pointerup`, `pointerupoutside`,
|
|
1112
|
+
* and `click`/`rightclick`/`pointertap` events, in that order.
|
|
1113
|
+
*
|
|
1114
|
+
* The `pointerupoutside` event bubbles from the original `pointerdown` target to the most specific
|
|
1115
|
+
* ancestor of the `pointerdown` and `pointerup` targets, which is also the `click` event's target. `touchend`,
|
|
1116
|
+
* `rightup`, `mouseup`, `touchendoutside`, `rightupoutside`, `mouseupoutside`, and `tap` are fired as well for
|
|
1117
|
+
* specific pointer types.
|
|
1118
|
+
* @param from - The upstream `pointerup` event.
|
|
1119
|
+
*/
|
|
635
1120
|
mapPointerUp(from) {
|
|
636
1121
|
if (!(from instanceof FederatedPointerEvent)) {
|
|
1122
|
+
// #if _DEBUG
|
|
637
1123
|
pixi_js.warn('EventBoundary cannot map a non-pointer event as a pointer event');
|
|
1124
|
+
// #endif
|
|
638
1125
|
return;
|
|
639
1126
|
}
|
|
640
1127
|
const now = performance.now();
|
|
@@ -650,6 +1137,8 @@ class EventBoundary {
|
|
|
650
1137
|
const trackingData = this.trackingData(from.pointerId);
|
|
651
1138
|
const pressTarget = this.findMountedTarget(trackingData.pressTargetsByButton[from.button]);
|
|
652
1139
|
let clickTarget = pressTarget;
|
|
1140
|
+
// pointerupoutside only bubbles. It only bubbles upto the parent that doesn't contain
|
|
1141
|
+
// the pointerup location.
|
|
653
1142
|
if (pressTarget && !e.composedPath().includes(pressTarget)) {
|
|
654
1143
|
let currentTarget = pressTarget;
|
|
655
1144
|
while (currentTarget && !e.composedPath().includes(currentTarget)) {
|
|
@@ -665,8 +1154,11 @@ class EventBoundary {
|
|
|
665
1154
|
currentTarget = currentTarget.parent;
|
|
666
1155
|
}
|
|
667
1156
|
delete trackingData.pressTargetsByButton[from.button];
|
|
1157
|
+
// currentTarget is the most specific ancestor holding both the pointerdown and pointerup
|
|
1158
|
+
// targets. That is - it's our click target!
|
|
668
1159
|
clickTarget = currentTarget;
|
|
669
1160
|
}
|
|
1161
|
+
// click!
|
|
670
1162
|
if (clickTarget) {
|
|
671
1163
|
const clickEvent = this.clonePointerEvent(e, 'click');
|
|
672
1164
|
clickEvent.target = clickTarget;
|
|
@@ -700,9 +1192,22 @@ class EventBoundary {
|
|
|
700
1192
|
}
|
|
701
1193
|
this.freeEvent(e);
|
|
702
1194
|
}
|
|
1195
|
+
/**
|
|
1196
|
+
* Maps the upstream `pointerupoutside` event to a downstream `pointerupoutside` event, bubbling from the original
|
|
1197
|
+
* `pointerdown` target to `rootTarget`.
|
|
1198
|
+
*
|
|
1199
|
+
* (The most specific ancestor of the `pointerdown` event and the `pointerup` event must the
|
|
1200
|
+
* `{@link EventBoundary}'s root because the `pointerup` event occurred outside of the boundary.)
|
|
1201
|
+
*
|
|
1202
|
+
* `touchendoutside`, `mouseupoutside`, and `rightupoutside` events are fired as well for specific pointer
|
|
1203
|
+
* types. The tracking data for the specific pointer is cleared of a `pressTarget`.
|
|
1204
|
+
* @param from - The upstream `pointerupoutside` event.
|
|
1205
|
+
*/
|
|
703
1206
|
mapPointerUpOutside(from) {
|
|
704
1207
|
if (!(from instanceof FederatedPointerEvent)) {
|
|
1208
|
+
// #if _DEBUG
|
|
705
1209
|
pixi_js.warn('EventBoundary cannot map a non-pointer event as a pointer event');
|
|
1210
|
+
// #endif
|
|
706
1211
|
return;
|
|
707
1212
|
}
|
|
708
1213
|
const trackingData = this.trackingData(from.pointerId);
|
|
@@ -725,21 +1230,37 @@ class EventBoundary {
|
|
|
725
1230
|
}
|
|
726
1231
|
this.freeEvent(e);
|
|
727
1232
|
}
|
|
1233
|
+
/**
|
|
1234
|
+
* Maps the upstream `wheel` event to a downstream `wheel` event.
|
|
1235
|
+
* @param from - The upstream `wheel` event.
|
|
1236
|
+
*/
|
|
728
1237
|
mapWheel(from) {
|
|
729
1238
|
if (!(from instanceof FederatedWheelEvent)) {
|
|
1239
|
+
// #if _DEBUG
|
|
730
1240
|
pixi_js.warn('EventBoundary cannot map a non-wheel event as a wheel event');
|
|
1241
|
+
// #endif
|
|
731
1242
|
return;
|
|
732
1243
|
}
|
|
733
1244
|
const wheelEvent = this.createWheelEvent(from);
|
|
734
1245
|
this.dispatchEvent(wheelEvent);
|
|
735
1246
|
this.freeEvent(wheelEvent);
|
|
736
1247
|
}
|
|
1248
|
+
/**
|
|
1249
|
+
* Finds the most specific event-target in the given propagation path that is still mounted in the scene graph.
|
|
1250
|
+
*
|
|
1251
|
+
* This is used to find the correct `pointerup` and `pointerout` target in the case that the original `pointerdown`
|
|
1252
|
+
* or `pointerover` target was unmounted from the scene graph.
|
|
1253
|
+
* @param propagationPath - The propagation path was valid in the past.
|
|
1254
|
+
* @returns - The most specific event-target still mounted at the same location in the scene graph.
|
|
1255
|
+
*/
|
|
737
1256
|
findMountedTarget(propagationPath) {
|
|
738
1257
|
if (!propagationPath) {
|
|
739
1258
|
return null;
|
|
740
1259
|
}
|
|
741
1260
|
let currentTarget = propagationPath[0];
|
|
742
1261
|
for (let i = 1; i < propagationPath.length; i++) {
|
|
1262
|
+
// Set currentTarget to the next target in the path only if it is still attached to the
|
|
1263
|
+
// scene graph (i.e. parent still points to the expected ancestor).
|
|
743
1264
|
if (propagationPath[i].parent === currentTarget) {
|
|
744
1265
|
currentTarget = propagationPath[i];
|
|
745
1266
|
}
|
|
@@ -749,6 +1270,14 @@ class EventBoundary {
|
|
|
749
1270
|
}
|
|
750
1271
|
return currentTarget;
|
|
751
1272
|
}
|
|
1273
|
+
/**
|
|
1274
|
+
* Creates an event whose {@code originalEvent} is {@code from}, with an optional `type` and `target` override.
|
|
1275
|
+
*
|
|
1276
|
+
* The event is allocated using {@link EventBoundary#allocateEvent this.allocateEvent}.
|
|
1277
|
+
* @param from - The {@code originalEvent} for the returned event.
|
|
1278
|
+
* @param [type=from.type] - The type of the returned event.
|
|
1279
|
+
* @param target - The target of the returned event.
|
|
1280
|
+
*/
|
|
752
1281
|
createPointerEvent(from, type, target) {
|
|
753
1282
|
var _a;
|
|
754
1283
|
const event = this.allocateEvent(FederatedPointerEvent);
|
|
@@ -763,6 +1292,12 @@ class EventBoundary {
|
|
|
763
1292
|
}
|
|
764
1293
|
return event;
|
|
765
1294
|
}
|
|
1295
|
+
/**
|
|
1296
|
+
* Creates a wheel event whose {@code originalEvent} is {@code from}.
|
|
1297
|
+
*
|
|
1298
|
+
* The event is allocated using {@link EventBoundary#allocateEvent this.allocateEvent}.
|
|
1299
|
+
* @param from - The upstream wheel event.
|
|
1300
|
+
*/
|
|
766
1301
|
createWheelEvent(from) {
|
|
767
1302
|
const event = this.allocateEvent(FederatedWheelEvent);
|
|
768
1303
|
this.copyWheelData(from, event);
|
|
@@ -773,6 +1308,13 @@ class EventBoundary {
|
|
|
773
1308
|
event.target = this.hitTest(event.global.x, event.global.y);
|
|
774
1309
|
return event;
|
|
775
1310
|
}
|
|
1311
|
+
/**
|
|
1312
|
+
* Clones the event {@code from}, with an optional {@code type} override.
|
|
1313
|
+
*
|
|
1314
|
+
* The event is allocated using {@link EventBoundary#allocateEvent this.allocateEvent}.
|
|
1315
|
+
* @param from - The event to clone.
|
|
1316
|
+
* @param [type=from.type] - The type of the returned event.
|
|
1317
|
+
*/
|
|
776
1318
|
clonePointerEvent(from, type) {
|
|
777
1319
|
const event = this.allocateEvent(FederatedPointerEvent);
|
|
778
1320
|
event.nativeEvent = from.nativeEvent;
|
|
@@ -780,17 +1322,45 @@ class EventBoundary {
|
|
|
780
1322
|
this.copyPointerData(from, event);
|
|
781
1323
|
this.copyMouseData(from, event);
|
|
782
1324
|
this.copyData(from, event);
|
|
1325
|
+
// copy propagation path for perf
|
|
783
1326
|
event.target = from.target;
|
|
784
1327
|
event.path = from.composedPath().slice();
|
|
785
1328
|
event.type = type !== null && type !== void 0 ? type : event.type;
|
|
786
1329
|
return event;
|
|
787
1330
|
}
|
|
1331
|
+
/**
|
|
1332
|
+
* Copies wheel {@link FederatedWheelEvent} data from {@code from} into {@code to}.
|
|
1333
|
+
*
|
|
1334
|
+
* The following properties are copied:
|
|
1335
|
+
* + deltaMode
|
|
1336
|
+
* + deltaX
|
|
1337
|
+
* + deltaY
|
|
1338
|
+
* + deltaZ
|
|
1339
|
+
* @param from - The event to copy data from.
|
|
1340
|
+
* @param to - The event to copy data into.
|
|
1341
|
+
*/
|
|
788
1342
|
copyWheelData(from, to) {
|
|
789
1343
|
to.deltaMode = from.deltaMode;
|
|
790
1344
|
to.deltaX = from.deltaX;
|
|
791
1345
|
to.deltaY = from.deltaY;
|
|
792
1346
|
to.deltaZ = from.deltaZ;
|
|
793
1347
|
}
|
|
1348
|
+
/**
|
|
1349
|
+
* Copies pointer {@link FederatedPointerEvent} data from {@code from} into {@code to}.
|
|
1350
|
+
*
|
|
1351
|
+
* The following properties are copied:
|
|
1352
|
+
* + pointerId
|
|
1353
|
+
* + width
|
|
1354
|
+
* + height
|
|
1355
|
+
* + isPrimary
|
|
1356
|
+
* + pointerType
|
|
1357
|
+
* + pressure
|
|
1358
|
+
* + tangentialPressure
|
|
1359
|
+
* + tiltX
|
|
1360
|
+
* + tiltY
|
|
1361
|
+
* @param from - The event to copy data from.
|
|
1362
|
+
* @param to - The event to copy data into.
|
|
1363
|
+
*/
|
|
794
1364
|
copyPointerData(from, to) {
|
|
795
1365
|
if (!(from instanceof FederatedPointerEvent && to instanceof FederatedPointerEvent))
|
|
796
1366
|
return;
|
|
@@ -805,6 +1375,28 @@ class EventBoundary {
|
|
|
805
1375
|
to.tiltY = from.tiltY;
|
|
806
1376
|
to.twist = from.twist;
|
|
807
1377
|
}
|
|
1378
|
+
/**
|
|
1379
|
+
* Copies mouse {@link FederatedMouseEvent} data from {@code from} to {@code to}.
|
|
1380
|
+
*
|
|
1381
|
+
* The following properties are copied:
|
|
1382
|
+
* + altKey
|
|
1383
|
+
* + button
|
|
1384
|
+
* + buttons
|
|
1385
|
+
* + clientX
|
|
1386
|
+
* + clientY
|
|
1387
|
+
* + metaKey
|
|
1388
|
+
* + movementX
|
|
1389
|
+
* + movementY
|
|
1390
|
+
* + pageX
|
|
1391
|
+
* + pageY
|
|
1392
|
+
* + x
|
|
1393
|
+
* + y
|
|
1394
|
+
* + screen
|
|
1395
|
+
* + shiftKey
|
|
1396
|
+
* + global
|
|
1397
|
+
* @param from - The event to copy data from.
|
|
1398
|
+
* @param to - The event to copy data into.
|
|
1399
|
+
*/
|
|
808
1400
|
copyMouseData(from, to) {
|
|
809
1401
|
if (!(from instanceof FederatedMouseEvent && to instanceof FederatedMouseEvent))
|
|
810
1402
|
return;
|
|
@@ -819,6 +1411,17 @@ class EventBoundary {
|
|
|
819
1411
|
to.shiftKey = from.shiftKey;
|
|
820
1412
|
to.global.copyFrom(from.global);
|
|
821
1413
|
}
|
|
1414
|
+
/**
|
|
1415
|
+
* Copies base {@link FederatedEvent} data from {@code from} into {@code to}.
|
|
1416
|
+
*
|
|
1417
|
+
* The following properties are copied:
|
|
1418
|
+
* + isTrusted
|
|
1419
|
+
* + srcElement
|
|
1420
|
+
* + timeStamp
|
|
1421
|
+
* + type
|
|
1422
|
+
* @param from - The event to copy data from.
|
|
1423
|
+
* @param to - The event to copy data into.
|
|
1424
|
+
*/
|
|
822
1425
|
copyData(from, to) {
|
|
823
1426
|
to.isTrusted = from.isTrusted;
|
|
824
1427
|
to.srcElement = from.srcElement;
|
|
@@ -830,6 +1433,11 @@ class EventBoundary {
|
|
|
830
1433
|
to.layer.copyFrom(from.layer);
|
|
831
1434
|
to.page.copyFrom(from.page);
|
|
832
1435
|
}
|
|
1436
|
+
/**
|
|
1437
|
+
* @param id - The pointer ID.
|
|
1438
|
+
* @returns The tracking data stored for the given pointer. If no data exists, a blank
|
|
1439
|
+
* state will be created.
|
|
1440
|
+
*/
|
|
833
1441
|
trackingData(id) {
|
|
834
1442
|
if (!this.mappingState.trackingData[id]) {
|
|
835
1443
|
this.mappingState.trackingData[id] = {
|
|
@@ -840,6 +1448,13 @@ class EventBoundary {
|
|
|
840
1448
|
}
|
|
841
1449
|
return this.mappingState.trackingData[id];
|
|
842
1450
|
}
|
|
1451
|
+
/**
|
|
1452
|
+
* Allocate a specific type of event from {@link EventBoundary#eventPool this.eventPool}.
|
|
1453
|
+
*
|
|
1454
|
+
* This allocation is constructor-agnostic, as long as it only takes one argument - this event
|
|
1455
|
+
* boundary.
|
|
1456
|
+
* @param constructor - The event's constructor.
|
|
1457
|
+
*/
|
|
843
1458
|
allocateEvent(constructor) {
|
|
844
1459
|
if (!this.eventPool.has(constructor)) {
|
|
845
1460
|
this.eventPool.set(constructor, []);
|
|
@@ -852,6 +1467,17 @@ class EventBoundary {
|
|
|
852
1467
|
event.target = null;
|
|
853
1468
|
return event;
|
|
854
1469
|
}
|
|
1470
|
+
/**
|
|
1471
|
+
* Frees the event and puts it back into the event pool.
|
|
1472
|
+
*
|
|
1473
|
+
* It is illegal to reuse the event until it is allocated again, using `this.allocateEvent`.
|
|
1474
|
+
*
|
|
1475
|
+
* It is also advised that events not allocated from {@link EventBoundary#allocateEvent this.allocateEvent}
|
|
1476
|
+
* not be freed. This is because of the possibility that the same event is freed twice, which can cause
|
|
1477
|
+
* it to be allocated twice & result in overwriting.
|
|
1478
|
+
* @param event - The event to be freed.
|
|
1479
|
+
* @throws Error if the event is managed by another event boundary.
|
|
1480
|
+
*/
|
|
855
1481
|
freeEvent(event) {
|
|
856
1482
|
if (event.manager !== this)
|
|
857
1483
|
throw new Error('It is illegal to free an event not managed by this EventBoundary!');
|
|
@@ -861,6 +1487,12 @@ class EventBoundary {
|
|
|
861
1487
|
}
|
|
862
1488
|
this.eventPool.get(constructor).push(event);
|
|
863
1489
|
}
|
|
1490
|
+
/**
|
|
1491
|
+
* Similar to {@link EventEmitter.emit}, except it stops if the `propagationImmediatelyStopped` flag
|
|
1492
|
+
* is set on the event.
|
|
1493
|
+
* @param e - The event to call each listener with.
|
|
1494
|
+
* @param type - The event key.
|
|
1495
|
+
*/
|
|
864
1496
|
_notifyListeners(e, type) {
|
|
865
1497
|
const listeners = e.currentTarget._events[type];
|
|
866
1498
|
if (!listeners)
|
|
@@ -887,11 +1519,47 @@ const TOUCH_TO_POINTER = {
|
|
|
887
1519
|
touchmove: 'pointermove',
|
|
888
1520
|
touchcancel: 'pointercancel',
|
|
889
1521
|
};
|
|
1522
|
+
/**
|
|
1523
|
+
* 事件系统类
|
|
1524
|
+
*
|
|
1525
|
+
* EventSystem 负责处理所有 UI 交互事件(鼠标、触摸、指针等)。
|
|
1526
|
+
* 它将原生 DOM 事件转换为统一的 FederatedEvent,
|
|
1527
|
+
* 并通过事件边界(EventBoundary)将事件传播到场景图中的对象。
|
|
1528
|
+
*
|
|
1529
|
+
* 支持的事件类型:
|
|
1530
|
+
* - 指针事件:pointerdown、pointermove、pointerup 等
|
|
1531
|
+
* - 鼠标事件:mousedown、mousemove、mouseup 等
|
|
1532
|
+
* - 触摸事件:touchstart、touchmove、touchend 等
|
|
1533
|
+
* - 滚轮事件:wheel
|
|
1534
|
+
*
|
|
1535
|
+
* @example
|
|
1536
|
+
* ```typescript
|
|
1537
|
+
* const eventSystem = new EventSystem(renderer);
|
|
1538
|
+
* eventSystem.init({
|
|
1539
|
+
* eventMode: 'passive',
|
|
1540
|
+
* eventFeatures: {
|
|
1541
|
+
* move: true,
|
|
1542
|
+
* click: true,
|
|
1543
|
+
* wheel: true
|
|
1544
|
+
* }
|
|
1545
|
+
* });
|
|
1546
|
+
* ```
|
|
1547
|
+
*/
|
|
890
1548
|
class EventSystem {
|
|
1549
|
+
/**
|
|
1550
|
+
* @param {Renderer} renderer
|
|
1551
|
+
*/
|
|
891
1552
|
constructor(renderer) {
|
|
1553
|
+
/** Does the device support touch events https://www.w3.org/TR/touch-events/ */
|
|
892
1554
|
this.supportsTouchEvents = 'ontouchstart' in globalThis;
|
|
1555
|
+
/** Does the device support pointer events https://www.w3.org/Submission/pointer-events/ */
|
|
893
1556
|
this.supportsPointerEvents = !!globalThis.PointerEvent;
|
|
1557
|
+
/**
|
|
1558
|
+
* The DOM element to which the root event listeners are bound. This is automatically set to
|
|
1559
|
+
* the renderer's {@link Renderer#view view}.
|
|
1560
|
+
*/
|
|
894
1561
|
this.domElement = null;
|
|
1562
|
+
/** The resolution used to convert between the DOM client space into world space. */
|
|
895
1563
|
this.resolution = 1;
|
|
896
1564
|
this.renderer = renderer;
|
|
897
1565
|
this.rootBoundary = new EventBoundary(null);
|
|
@@ -919,9 +1587,20 @@ class EventSystem {
|
|
|
919
1587
|
this._onPointerOverOut = this._onPointerOverOut.bind(this);
|
|
920
1588
|
this.onWheel = this.onWheel.bind(this);
|
|
921
1589
|
}
|
|
1590
|
+
/**
|
|
1591
|
+
* The default interaction mode for all display objects.
|
|
1592
|
+
* @see Container.eventMode
|
|
1593
|
+
* @type {EventMode}
|
|
1594
|
+
* @readonly
|
|
1595
|
+
* @since 7.2.0
|
|
1596
|
+
*/
|
|
922
1597
|
static get defaultEventMode() {
|
|
923
1598
|
return this._defaultEventMode;
|
|
924
1599
|
}
|
|
1600
|
+
/**
|
|
1601
|
+
* Runner init called, view is available at this point.
|
|
1602
|
+
* @ignore
|
|
1603
|
+
*/
|
|
925
1604
|
init(options) {
|
|
926
1605
|
var _a, _b;
|
|
927
1606
|
const { canvas, resolution } = this.renderer;
|
|
@@ -931,38 +1610,55 @@ class EventSystem {
|
|
|
931
1610
|
Object.assign(this.features, (_b = options.eventFeatures) !== null && _b !== void 0 ? _b : {});
|
|
932
1611
|
this.rootBoundary.enableGlobalMoveEvents = this.features.globalMove;
|
|
933
1612
|
}
|
|
1613
|
+
/**
|
|
1614
|
+
* Handle changing resolution.
|
|
1615
|
+
* @ignore
|
|
1616
|
+
*/
|
|
934
1617
|
resolutionChange(resolution) {
|
|
935
1618
|
this.resolution = resolution;
|
|
936
1619
|
}
|
|
1620
|
+
/** Destroys all event listeners and detaches the renderer. */
|
|
937
1621
|
destroy() {
|
|
938
1622
|
this.setTargetElement(null);
|
|
939
1623
|
this.renderer = null;
|
|
940
1624
|
this._currentCursor = null;
|
|
941
1625
|
}
|
|
1626
|
+
/**
|
|
1627
|
+
* Sets the current cursor mode, handling any callbacks or CSS style changes.
|
|
1628
|
+
* @param mode - cursor mode, a key from the cursorStyles dictionary
|
|
1629
|
+
*/
|
|
942
1630
|
setCursor(mode) {
|
|
943
1631
|
if (!mode) {
|
|
944
1632
|
mode = 'default';
|
|
945
1633
|
}
|
|
946
1634
|
let applyStyles = true;
|
|
1635
|
+
// offscreen canvas does not support setting styles, but cursor modes can be functions,
|
|
1636
|
+
// in order to handle pixi rendered cursors, so we can't bail
|
|
947
1637
|
if (globalThis.OffscreenCanvas && this.domElement instanceof OffscreenCanvas) {
|
|
948
1638
|
applyStyles = false;
|
|
949
1639
|
}
|
|
1640
|
+
// if the mode didn't actually change, bail early
|
|
950
1641
|
if (this._currentCursor === mode) {
|
|
951
1642
|
return;
|
|
952
1643
|
}
|
|
953
1644
|
this._currentCursor = mode;
|
|
954
1645
|
const style = this.cursorStyles[mode];
|
|
1646
|
+
// only do things if there is a cursor style for it
|
|
955
1647
|
if (style) {
|
|
956
1648
|
switch (typeof style) {
|
|
957
1649
|
case 'string':
|
|
1650
|
+
// string styles are handled as cursor CSS
|
|
958
1651
|
if (applyStyles) {
|
|
959
1652
|
this.domElement.style.cursor = style;
|
|
960
1653
|
}
|
|
961
1654
|
break;
|
|
962
1655
|
case 'function':
|
|
1656
|
+
// functions are just called, and passed the cursor mode
|
|
963
1657
|
style(mode);
|
|
964
1658
|
break;
|
|
965
1659
|
case 'object':
|
|
1660
|
+
// if it is an object, assume that it is a dictionary of CSS styles,
|
|
1661
|
+
// apply it to the interactionDOMElement
|
|
966
1662
|
if (applyStyles) {
|
|
967
1663
|
Object.assign(this.domElement.style, style);
|
|
968
1664
|
}
|
|
@@ -972,17 +1668,34 @@ class EventSystem {
|
|
|
972
1668
|
else if (applyStyles &&
|
|
973
1669
|
typeof mode === 'string' &&
|
|
974
1670
|
!Object.prototype.hasOwnProperty.call(this.cursorStyles, mode)) {
|
|
1671
|
+
// if it mode is a string (not a Symbol) and cursorStyles doesn't have any entry
|
|
1672
|
+
// for the mode, then assume that the dev wants it to be CSS for the cursor.
|
|
975
1673
|
this.domElement.style.cursor = mode;
|
|
976
1674
|
}
|
|
977
1675
|
}
|
|
1676
|
+
/**
|
|
1677
|
+
* The global pointer event.
|
|
1678
|
+
* Useful for getting the pointer position without listening to events.
|
|
1679
|
+
* @since 7.2.0
|
|
1680
|
+
*/
|
|
978
1681
|
get pointer() {
|
|
979
1682
|
return this._rootPointerEvent;
|
|
980
1683
|
}
|
|
1684
|
+
/**
|
|
1685
|
+
* Event handler for pointer down events on {@link EventSystem#domElement this.domElement}.
|
|
1686
|
+
* @param nativeEvent - The native mouse/pointer/touch event.
|
|
1687
|
+
*/
|
|
981
1688
|
_onPointerDown(nativeEvent) {
|
|
982
1689
|
if (!this.features.click)
|
|
983
1690
|
return;
|
|
984
1691
|
this.rootBoundary.rootTarget = this.renderer.lastObjectRendered;
|
|
985
1692
|
const events = this._normalizeToPointerData(nativeEvent);
|
|
1693
|
+
/*
|
|
1694
|
+
* No need to prevent default on natural pointer events, as there are no side effects
|
|
1695
|
+
* Normalized events, however, may have the double mousedown/touchstart issue on the native android browser,
|
|
1696
|
+
* so still need to be prevented.
|
|
1697
|
+
*/
|
|
1698
|
+
// Guaranteed that there will be at least one event in events, and all events must have the same pointer type
|
|
986
1699
|
if (this.autoPreventDefault && events[0].isNormalized) {
|
|
987
1700
|
const cancelable = nativeEvent.cancelable || !('cancelable' in nativeEvent);
|
|
988
1701
|
if (cancelable) {
|
|
@@ -997,6 +1710,10 @@ class EventSystem {
|
|
|
997
1710
|
}
|
|
998
1711
|
this.setCursor(this.rootBoundary.cursor);
|
|
999
1712
|
}
|
|
1713
|
+
/**
|
|
1714
|
+
* Event handler for pointer move events on on {@link EventSystem#domElement this.domElement}.
|
|
1715
|
+
* @param nativeEvent - The native mouse/pointer/touch events.
|
|
1716
|
+
*/
|
|
1000
1717
|
_onPointerMove(nativeEvent) {
|
|
1001
1718
|
if (!this.features.move)
|
|
1002
1719
|
return;
|
|
@@ -1009,6 +1726,10 @@ class EventSystem {
|
|
|
1009
1726
|
}
|
|
1010
1727
|
this.setCursor(this.rootBoundary.cursor);
|
|
1011
1728
|
}
|
|
1729
|
+
/**
|
|
1730
|
+
* Event handler for pointer up events on {@link EventSystem#domElement this.domElement}.
|
|
1731
|
+
* @param nativeEvent - The native mouse/pointer/touch event.
|
|
1732
|
+
*/
|
|
1012
1733
|
_onPointerUp(nativeEvent) {
|
|
1013
1734
|
if (!this.features.click)
|
|
1014
1735
|
return;
|
|
@@ -1022,6 +1743,10 @@ class EventSystem {
|
|
|
1022
1743
|
}
|
|
1023
1744
|
this.setCursor(this.rootBoundary.cursor);
|
|
1024
1745
|
}
|
|
1746
|
+
/**
|
|
1747
|
+
* Event handler for pointer over & out events on {@link EventSystem#domElement this.domElement}.
|
|
1748
|
+
* @param nativeEvent - The native mouse/pointer/touch event.
|
|
1749
|
+
*/
|
|
1025
1750
|
_onPointerOverOut(nativeEvent) {
|
|
1026
1751
|
if (!this.features.click)
|
|
1027
1752
|
return;
|
|
@@ -1033,6 +1758,10 @@ class EventSystem {
|
|
|
1033
1758
|
}
|
|
1034
1759
|
this.setCursor(this.rootBoundary.cursor);
|
|
1035
1760
|
}
|
|
1761
|
+
/**
|
|
1762
|
+
* Passive handler for `wheel` events on {@link EventSystem.domElement this.domElement}.
|
|
1763
|
+
* @param nativeEvent - The native wheel event.
|
|
1764
|
+
*/
|
|
1036
1765
|
onWheel(nativeEvent) {
|
|
1037
1766
|
if (!this.features.wheel)
|
|
1038
1767
|
return;
|
|
@@ -1040,12 +1769,19 @@ class EventSystem {
|
|
|
1040
1769
|
this.rootBoundary.rootTarget = this.renderer.lastObjectRendered;
|
|
1041
1770
|
this.rootBoundary.mapEvent(wheelEvent);
|
|
1042
1771
|
}
|
|
1772
|
+
/**
|
|
1773
|
+
* Sets the {@link EventSystem#domElement domElement} and binds event listeners.
|
|
1774
|
+
*
|
|
1775
|
+
* To deregister the current DOM element without setting a new one, pass {@code null}.
|
|
1776
|
+
* @param element - The new DOM element.
|
|
1777
|
+
*/
|
|
1043
1778
|
setTargetElement(element) {
|
|
1044
1779
|
this._removeEvents();
|
|
1045
1780
|
this.domElement = element;
|
|
1046
1781
|
EventsTicker.domElement = element;
|
|
1047
1782
|
this._addEvents();
|
|
1048
1783
|
}
|
|
1784
|
+
/** Register event listeners on {@link Renderer#domElement this.domElement}. */
|
|
1049
1785
|
_addEvents() {
|
|
1050
1786
|
if (this._eventsAdded || !this.domElement) {
|
|
1051
1787
|
return;
|
|
@@ -1068,6 +1804,10 @@ class EventSystem {
|
|
|
1068
1804
|
id = key;
|
|
1069
1805
|
}
|
|
1070
1806
|
}
|
|
1807
|
+
/*
|
|
1808
|
+
* These events are added first, so that if pointer events are normalized, they are fired
|
|
1809
|
+
* in the same order as non-normalized events. ie. pointer event 1st, mouse / touch 2nd
|
|
1810
|
+
*/
|
|
1071
1811
|
EventSystem.eventsHandler[id] = {
|
|
1072
1812
|
pointermove: this._onPointerMove.bind(this),
|
|
1073
1813
|
pointerdown: this._onPointerDown.bind(this),
|
|
@@ -1086,12 +1826,14 @@ class EventSystem {
|
|
|
1086
1826
|
EventSystem.eventsHandler[id]['wheel'] = this.onWheel.bind(this);
|
|
1087
1827
|
this._eventsAdded = true;
|
|
1088
1828
|
}
|
|
1829
|
+
/** Unregister event listeners on {@link EventSystem#domElement this.domElement}. */
|
|
1089
1830
|
_removeEvents() {
|
|
1090
1831
|
if (!this._eventsAdded || !this.domElement) {
|
|
1091
1832
|
return;
|
|
1092
1833
|
}
|
|
1093
1834
|
EventsTicker.removeTickerListener();
|
|
1094
1835
|
const style = this.domElement.style;
|
|
1836
|
+
// offscreen canvas does not have style, so check first
|
|
1095
1837
|
if (style) {
|
|
1096
1838
|
if (globalThis.navigator.msPointerEnabled) {
|
|
1097
1839
|
style.msContentZooming = '';
|
|
@@ -1104,6 +1846,14 @@ class EventSystem {
|
|
|
1104
1846
|
this.domElement = null;
|
|
1105
1847
|
this._eventsAdded = false;
|
|
1106
1848
|
}
|
|
1849
|
+
/**
|
|
1850
|
+
* Maps x and y coords from a DOM object and maps them correctly to the PixiJS view. The
|
|
1851
|
+
* resulting value is stored in the point. This takes into account the fact that the DOM
|
|
1852
|
+
* element could be scaled and positioned anywhere on the screen.
|
|
1853
|
+
* @param {PointData} point - the point that the result will be stored in
|
|
1854
|
+
* @param {number} x - the x coord of the position to map
|
|
1855
|
+
* @param {number} y - the y coord of the position to map
|
|
1856
|
+
*/
|
|
1107
1857
|
mapPositionToPoint(point, x, y, e) {
|
|
1108
1858
|
const resolutionMultiplier = 1.0 / this.resolution;
|
|
1109
1859
|
const rect = e.canvasRect || {
|
|
@@ -1118,12 +1868,34 @@ class EventSystem {
|
|
|
1118
1868
|
point.x = (x - rect.left) * (domElement.width / rect.width) * resolutionMultiplier;
|
|
1119
1869
|
point.y = (y - rect.top) * (domElement.height / rect.height) * resolutionMultiplier;
|
|
1120
1870
|
}
|
|
1871
|
+
/**
|
|
1872
|
+
* Ensures that the original event object contains all data that a regular pointer event would have
|
|
1873
|
+
* @param event - The original event data from a touch or mouse event
|
|
1874
|
+
* @returns An array containing a single normalized pointer event, in the case of a pointer
|
|
1875
|
+
* or mouse event, or a multiple normalized pointer events if there are multiple changed touches
|
|
1876
|
+
*/
|
|
1121
1877
|
_normalizeToPointerData(event) {
|
|
1878
|
+
// @ts-ignore
|
|
1122
1879
|
return event.normalizedEvents;
|
|
1123
1880
|
}
|
|
1881
|
+
/**
|
|
1882
|
+
* Normalizes the native {@link https://w3c.github.io/uievents/#interface-wheelevent WheelEvent}.
|
|
1883
|
+
*
|
|
1884
|
+
* The returned {@link FederatedWheelEvent} is a shared instance. It will not persist across
|
|
1885
|
+
* multiple native wheel events.
|
|
1886
|
+
* @param nativeEvent - The native wheel event that occurred on the canvas.
|
|
1887
|
+
* @returns A federated wheel event.
|
|
1888
|
+
*/
|
|
1124
1889
|
normalizeWheelEvent(nativeEvent) {
|
|
1125
1890
|
const event = this._rootWheelEvent;
|
|
1126
1891
|
this._transferMouseData(event, nativeEvent);
|
|
1892
|
+
// When WheelEvent is triggered by scrolling with mouse wheel, reading WheelEvent.deltaMode
|
|
1893
|
+
// before deltaX/deltaY/deltaZ on Firefox will result in WheelEvent.DOM_DELTA_LINE (1),
|
|
1894
|
+
// while reading WheelEvent.deltaMode after deltaX/deltaY/deltaZ on Firefox or reading
|
|
1895
|
+
// in any order on other browsers will result in WheelEvent.DOM_DELTA_PIXEL (0).
|
|
1896
|
+
// Therefore, we need to read WheelEvent.deltaMode after deltaX/deltaY/deltaZ in order to
|
|
1897
|
+
// make its behavior more consistent across browsers.
|
|
1898
|
+
// @see https://github.com/pixijs/pixijs/issues/8970
|
|
1127
1899
|
event.deltaX = nativeEvent.deltaX;
|
|
1128
1900
|
event.deltaY = nativeEvent.deltaY;
|
|
1129
1901
|
event.deltaZ = nativeEvent.deltaZ;
|
|
@@ -1135,6 +1907,11 @@ class EventSystem {
|
|
|
1135
1907
|
event.type = nativeEvent.type;
|
|
1136
1908
|
return event;
|
|
1137
1909
|
}
|
|
1910
|
+
/**
|
|
1911
|
+
* Normalizes the `nativeEvent` into a federateed {@link FederatedPointerEvent}.
|
|
1912
|
+
* @param event
|
|
1913
|
+
* @param nativeEvent
|
|
1914
|
+
*/
|
|
1138
1915
|
_bootstrapEvent(event, nativeEvent, nEvent) {
|
|
1139
1916
|
event.originalEvent = null;
|
|
1140
1917
|
event.nativeEvent = nativeEvent;
|
|
@@ -1150,8 +1927,8 @@ class EventSystem {
|
|
|
1150
1927
|
event.twist = nativeEvent.twist;
|
|
1151
1928
|
this._transferMouseData(event, nativeEvent);
|
|
1152
1929
|
this.mapPositionToPoint(event.screen, nativeEvent.clientX, nativeEvent.clientY, nEvent);
|
|
1153
|
-
event.global.copyFrom(event.screen);
|
|
1154
|
-
event.offset.copyFrom(event.screen);
|
|
1930
|
+
event.global.copyFrom(event.screen); // global = screen for top-level
|
|
1931
|
+
event.offset.copyFrom(event.screen); // EventBoundary recalculates using its rootTarget
|
|
1155
1932
|
event.isTrusted = nativeEvent.isTrusted;
|
|
1156
1933
|
if (event.type === 'pointerleave') {
|
|
1157
1934
|
event.type = 'pointerout';
|
|
@@ -1164,6 +1941,11 @@ class EventSystem {
|
|
|
1164
1941
|
}
|
|
1165
1942
|
return event;
|
|
1166
1943
|
}
|
|
1944
|
+
/**
|
|
1945
|
+
* Transfers base & mouse event data from the {@code nativeEvent} to the federated event.
|
|
1946
|
+
* @param event
|
|
1947
|
+
* @param nativeEvent
|
|
1948
|
+
*/
|
|
1167
1949
|
_transferMouseData(event, nativeEvent) {
|
|
1168
1950
|
event.isTrusted = nativeEvent.isTrusted;
|
|
1169
1951
|
event.srcElement = nativeEvent.srcElement;
|
|
@@ -1184,61 +1966,397 @@ class EventSystem {
|
|
|
1184
1966
|
event.shiftKey = nativeEvent.shiftKey;
|
|
1185
1967
|
}
|
|
1186
1968
|
}
|
|
1969
|
+
/** @ignore */
|
|
1187
1970
|
EventSystem.extension = {
|
|
1188
1971
|
name: 'events',
|
|
1189
1972
|
type: [pixi_js.ExtensionType.WebGLSystem, pixi_js.ExtensionType.CanvasSystem, pixi_js.ExtensionType.WebGPUSystem],
|
|
1190
1973
|
priority: -1,
|
|
1191
1974
|
};
|
|
1975
|
+
/** 画布映射表 */
|
|
1192
1976
|
EventSystem.canvasMap = {};
|
|
1977
|
+
/** 事件处理器映射表 */
|
|
1193
1978
|
EventSystem.eventsHandler = {};
|
|
1979
|
+
/**
|
|
1980
|
+
* 事件系统的默认功能配置
|
|
1981
|
+
* @since 7.2.0
|
|
1982
|
+
*/
|
|
1194
1983
|
EventSystem.defaultEventFeatures = {
|
|
1984
|
+
/** 启用指针移动相关事件 */
|
|
1195
1985
|
move: true,
|
|
1986
|
+
/** 启用全局指针移动事件 */
|
|
1196
1987
|
globalMove: true,
|
|
1988
|
+
/** 启用点击相关事件 */
|
|
1197
1989
|
click: true,
|
|
1990
|
+
/** 启用滚轮事件 */
|
|
1198
1991
|
wheel: true,
|
|
1199
1992
|
};
|
|
1200
1993
|
|
|
1201
1994
|
const FederatedContainer = {
|
|
1995
|
+
/**
|
|
1996
|
+
* Property-based event handler for the `click` event.
|
|
1997
|
+
* @memberof scene.Container#
|
|
1998
|
+
* @default null
|
|
1999
|
+
* @example
|
|
2000
|
+
* this.onclick = (event) => {
|
|
2001
|
+
* //some function here that happens on click
|
|
2002
|
+
* }
|
|
2003
|
+
*/
|
|
1202
2004
|
onclick: null,
|
|
2005
|
+
/**
|
|
2006
|
+
* Property-based event handler for the `mousedown` event.
|
|
2007
|
+
* @memberof scene.Container#
|
|
2008
|
+
* @default null
|
|
2009
|
+
* @example
|
|
2010
|
+
* this.onmousedown = (event) => {
|
|
2011
|
+
* //some function here that happens on mousedown
|
|
2012
|
+
* }
|
|
2013
|
+
*/
|
|
1203
2014
|
onmousedown: null,
|
|
2015
|
+
/**
|
|
2016
|
+
* Property-based event handler for the `mouseenter` event.
|
|
2017
|
+
* @memberof scene.Container#
|
|
2018
|
+
* @default null
|
|
2019
|
+
* @example
|
|
2020
|
+
* this.onmouseenter = (event) => {
|
|
2021
|
+
* //some function here that happens on mouseenter
|
|
2022
|
+
* }
|
|
2023
|
+
*/
|
|
1204
2024
|
onmouseenter: null,
|
|
2025
|
+
/**
|
|
2026
|
+
* Property-based event handler for the `mouseleave` event.
|
|
2027
|
+
* @memberof scene.Container#
|
|
2028
|
+
* @default null
|
|
2029
|
+
* @example
|
|
2030
|
+
* this.onmouseleave = (event) => {
|
|
2031
|
+
* //some function here that happens on mouseleave
|
|
2032
|
+
* }
|
|
2033
|
+
*/
|
|
1205
2034
|
onmouseleave: null,
|
|
2035
|
+
/**
|
|
2036
|
+
* Property-based event handler for the `mousemove` event.
|
|
2037
|
+
* @memberof scene.Container#
|
|
2038
|
+
* @default null
|
|
2039
|
+
* @example
|
|
2040
|
+
* this.onmousemove = (event) => {
|
|
2041
|
+
* //some function here that happens on mousemove
|
|
2042
|
+
* }
|
|
2043
|
+
*/
|
|
1206
2044
|
onmousemove: null,
|
|
2045
|
+
/**
|
|
2046
|
+
* Property-based event handler for the `globalmousemove` event.
|
|
2047
|
+
* @memberof scene.Container#
|
|
2048
|
+
* @default null
|
|
2049
|
+
* @example
|
|
2050
|
+
* this.onglobalmousemove = (event) => {
|
|
2051
|
+
* //some function here that happens on globalmousemove
|
|
2052
|
+
* }
|
|
2053
|
+
*/
|
|
1207
2054
|
onglobalmousemove: null,
|
|
2055
|
+
/**
|
|
2056
|
+
* Property-based event handler for the `mouseout` event.
|
|
2057
|
+
* @memberof scene.Container#
|
|
2058
|
+
* @default null
|
|
2059
|
+
* @example
|
|
2060
|
+
* this.onmouseout = (event) => {
|
|
2061
|
+
* //some function here that happens on mouseout
|
|
2062
|
+
* }
|
|
2063
|
+
*/
|
|
1208
2064
|
onmouseout: null,
|
|
2065
|
+
/**
|
|
2066
|
+
* Property-based event handler for the `mouseover` event.
|
|
2067
|
+
* @memberof scene.Container#
|
|
2068
|
+
* @default null
|
|
2069
|
+
* @example
|
|
2070
|
+
* this.onmouseover = (event) => {
|
|
2071
|
+
* //some function here that happens on mouseover
|
|
2072
|
+
* }
|
|
2073
|
+
*/
|
|
1209
2074
|
onmouseover: null,
|
|
2075
|
+
/**
|
|
2076
|
+
* Property-based event handler for the `mouseup` event.
|
|
2077
|
+
* @memberof scene.Container#
|
|
2078
|
+
* @default null
|
|
2079
|
+
* @example
|
|
2080
|
+
* this.onmouseup = (event) => {
|
|
2081
|
+
* //some function here that happens on mouseup
|
|
2082
|
+
* }
|
|
2083
|
+
*/
|
|
1210
2084
|
onmouseup: null,
|
|
2085
|
+
/**
|
|
2086
|
+
* Property-based event handler for the `mouseupoutside` event.
|
|
2087
|
+
* @memberof scene.Container#
|
|
2088
|
+
* @default null
|
|
2089
|
+
* @example
|
|
2090
|
+
* this.onmouseupoutside = (event) => {
|
|
2091
|
+
* //some function here that happens on mouseupoutside
|
|
2092
|
+
* }
|
|
2093
|
+
*/
|
|
1211
2094
|
onmouseupoutside: null,
|
|
2095
|
+
/**
|
|
2096
|
+
* Property-based event handler for the `pointercancel` event.
|
|
2097
|
+
* @memberof scene.Container#
|
|
2098
|
+
* @default null
|
|
2099
|
+
* @example
|
|
2100
|
+
* this.onpointercancel = (event) => {
|
|
2101
|
+
* //some function here that happens on pointercancel
|
|
2102
|
+
* }
|
|
2103
|
+
*/
|
|
1212
2104
|
onpointercancel: null,
|
|
2105
|
+
/**
|
|
2106
|
+
* Property-based event handler for the `pointerdown` event.
|
|
2107
|
+
* @memberof scene.Container#
|
|
2108
|
+
* @default null
|
|
2109
|
+
* @example
|
|
2110
|
+
* this.onpointerdown = (event) => {
|
|
2111
|
+
* //some function here that happens on pointerdown
|
|
2112
|
+
* }
|
|
2113
|
+
*/
|
|
1213
2114
|
onpointerdown: null,
|
|
2115
|
+
/**
|
|
2116
|
+
* Property-based event handler for the `pointerenter` event.
|
|
2117
|
+
* @memberof scene.Container#
|
|
2118
|
+
* @default null
|
|
2119
|
+
* @example
|
|
2120
|
+
* this.onpointerenter = (event) => {
|
|
2121
|
+
* //some function here that happens on pointerenter
|
|
2122
|
+
* }
|
|
2123
|
+
*/
|
|
1214
2124
|
onpointerenter: null,
|
|
2125
|
+
/**
|
|
2126
|
+
* Property-based event handler for the `pointerleave` event.
|
|
2127
|
+
* @memberof scene.Container#
|
|
2128
|
+
* @default null
|
|
2129
|
+
* @example
|
|
2130
|
+
* this.onpointerleave = (event) => {
|
|
2131
|
+
* //some function here that happens on pointerleave
|
|
2132
|
+
* }
|
|
2133
|
+
*/
|
|
1215
2134
|
onpointerleave: null,
|
|
2135
|
+
/**
|
|
2136
|
+
* Property-based event handler for the `pointermove` event.
|
|
2137
|
+
* @memberof scene.Container#
|
|
2138
|
+
* @default null
|
|
2139
|
+
* @example
|
|
2140
|
+
* this.onpointermove = (event) => {
|
|
2141
|
+
* //some function here that happens on pointermove
|
|
2142
|
+
* }
|
|
2143
|
+
*/
|
|
1216
2144
|
onpointermove: null,
|
|
2145
|
+
/**
|
|
2146
|
+
* Property-based event handler for the `globalpointermove` event.
|
|
2147
|
+
* @memberof scene.Container#
|
|
2148
|
+
* @default null
|
|
2149
|
+
* @example
|
|
2150
|
+
* this.onglobalpointermove = (event) => {
|
|
2151
|
+
* //some function here that happens on globalpointermove
|
|
2152
|
+
* }
|
|
2153
|
+
*/
|
|
1217
2154
|
onglobalpointermove: null,
|
|
2155
|
+
/**
|
|
2156
|
+
* Property-based event handler for the `pointerout` event.
|
|
2157
|
+
* @memberof scene.Container#
|
|
2158
|
+
* @default null
|
|
2159
|
+
* @example
|
|
2160
|
+
* this.onpointerout = (event) => {
|
|
2161
|
+
* //some function here that happens on pointerout
|
|
2162
|
+
* }
|
|
2163
|
+
*/
|
|
1218
2164
|
onpointerout: null,
|
|
2165
|
+
/**
|
|
2166
|
+
* Property-based event handler for the `pointerover` event.
|
|
2167
|
+
* @memberof scene.Container#
|
|
2168
|
+
* @default null
|
|
2169
|
+
* @example
|
|
2170
|
+
* this.onpointerover = (event) => {
|
|
2171
|
+
* //some function here that happens on pointerover
|
|
2172
|
+
* }
|
|
2173
|
+
*/
|
|
1219
2174
|
onpointerover: null,
|
|
2175
|
+
/**
|
|
2176
|
+
* Property-based event handler for the `pointertap` event.
|
|
2177
|
+
* @memberof scene.Container#
|
|
2178
|
+
* @default null
|
|
2179
|
+
* @example
|
|
2180
|
+
* this.onpointertap = (event) => {
|
|
2181
|
+
* //some function here that happens on pointertap
|
|
2182
|
+
* }
|
|
2183
|
+
*/
|
|
1220
2184
|
onpointertap: null,
|
|
2185
|
+
/**
|
|
2186
|
+
* Property-based event handler for the `pointerup` event.
|
|
2187
|
+
* @memberof scene.Container#
|
|
2188
|
+
* @default null
|
|
2189
|
+
* @example
|
|
2190
|
+
* this.onpointerup = (event) => {
|
|
2191
|
+
* //some function here that happens on pointerup
|
|
2192
|
+
* }
|
|
2193
|
+
*/
|
|
1221
2194
|
onpointerup: null,
|
|
2195
|
+
/**
|
|
2196
|
+
* Property-based event handler for the `pointerupoutside` event.
|
|
2197
|
+
* @memberof scene.Container#
|
|
2198
|
+
* @default null
|
|
2199
|
+
* @example
|
|
2200
|
+
* this.onpointerupoutside = (event) => {
|
|
2201
|
+
* //some function here that happens on pointerupoutside
|
|
2202
|
+
* }
|
|
2203
|
+
*/
|
|
1222
2204
|
onpointerupoutside: null,
|
|
2205
|
+
/**
|
|
2206
|
+
* Property-based event handler for the `rightclick` event.
|
|
2207
|
+
* @memberof scene.Container#
|
|
2208
|
+
* @default null
|
|
2209
|
+
* @example
|
|
2210
|
+
* this.onrightclick = (event) => {
|
|
2211
|
+
* //some function here that happens on rightclick
|
|
2212
|
+
* }
|
|
2213
|
+
*/
|
|
1223
2214
|
onrightclick: null,
|
|
2215
|
+
/**
|
|
2216
|
+
* Property-based event handler for the `rightdown` event.
|
|
2217
|
+
* @memberof scene.Container#
|
|
2218
|
+
* @default null
|
|
2219
|
+
* @example
|
|
2220
|
+
* this.onrightdown = (event) => {
|
|
2221
|
+
* //some function here that happens on rightdown
|
|
2222
|
+
* }
|
|
2223
|
+
*/
|
|
1224
2224
|
onrightdown: null,
|
|
2225
|
+
/**
|
|
2226
|
+
* Property-based event handler for the `rightup` event.
|
|
2227
|
+
* @memberof scene.Container#
|
|
2228
|
+
* @default null
|
|
2229
|
+
* @example
|
|
2230
|
+
* this.onrightup = (event) => {
|
|
2231
|
+
* //some function here that happens on rightup
|
|
2232
|
+
* }
|
|
2233
|
+
*/
|
|
1225
2234
|
onrightup: null,
|
|
2235
|
+
/**
|
|
2236
|
+
* Property-based event handler for the `rightupoutside` event.
|
|
2237
|
+
* @memberof scene.Container#
|
|
2238
|
+
* @default null
|
|
2239
|
+
* @example
|
|
2240
|
+
* this.onrightupoutside = (event) => {
|
|
2241
|
+
* //some function here that happens on rightupoutside
|
|
2242
|
+
* }
|
|
2243
|
+
*/
|
|
1226
2244
|
onrightupoutside: null,
|
|
2245
|
+
/**
|
|
2246
|
+
* Property-based event handler for the `tap` event.
|
|
2247
|
+
* @memberof scene.Container#
|
|
2248
|
+
* @default null
|
|
2249
|
+
* @example
|
|
2250
|
+
* this.ontap = (event) => {
|
|
2251
|
+
* //some function here that happens on tap
|
|
2252
|
+
* }
|
|
2253
|
+
*/
|
|
1227
2254
|
ontap: null,
|
|
2255
|
+
/**
|
|
2256
|
+
* Property-based event handler for the `touchcancel` event.
|
|
2257
|
+
* @memberof scene.Container#
|
|
2258
|
+
* @default null
|
|
2259
|
+
* @example
|
|
2260
|
+
* this.ontouchcancel = (event) => {
|
|
2261
|
+
* //some function here that happens on touchcancel
|
|
2262
|
+
* }
|
|
2263
|
+
*/
|
|
1228
2264
|
ontouchcancel: null,
|
|
2265
|
+
/**
|
|
2266
|
+
* Property-based event handler for the `touchend` event.
|
|
2267
|
+
* @memberof scene.Container#
|
|
2268
|
+
* @default null
|
|
2269
|
+
* @example
|
|
2270
|
+
* this.ontouchend = (event) => {
|
|
2271
|
+
* //some function here that happens on touchend
|
|
2272
|
+
* }
|
|
2273
|
+
*/
|
|
1229
2274
|
ontouchend: null,
|
|
2275
|
+
/**
|
|
2276
|
+
* Property-based event handler for the `touchendoutside` event.
|
|
2277
|
+
* @memberof scene.Container#
|
|
2278
|
+
* @default null
|
|
2279
|
+
* @example
|
|
2280
|
+
* this.ontouchendoutside = (event) => {
|
|
2281
|
+
* //some function here that happens on touchendoutside
|
|
2282
|
+
* }
|
|
2283
|
+
*/
|
|
1230
2284
|
ontouchendoutside: null,
|
|
2285
|
+
/**
|
|
2286
|
+
* Property-based event handler for the `touchmove` event.
|
|
2287
|
+
* @memberof scene.Container#
|
|
2288
|
+
* @default null
|
|
2289
|
+
* @example
|
|
2290
|
+
* this.ontouchmove = (event) => {
|
|
2291
|
+
* //some function here that happens on touchmove
|
|
2292
|
+
* }
|
|
2293
|
+
*/
|
|
1231
2294
|
ontouchmove: null,
|
|
2295
|
+
/**
|
|
2296
|
+
* Property-based event handler for the `globaltouchmove` event.
|
|
2297
|
+
* @memberof scene.Container#
|
|
2298
|
+
* @default null
|
|
2299
|
+
* @example
|
|
2300
|
+
* this.onglobaltouchmove = (event) => {
|
|
2301
|
+
* //some function here that happens on globaltouchmove
|
|
2302
|
+
* }
|
|
2303
|
+
*/
|
|
1232
2304
|
onglobaltouchmove: null,
|
|
2305
|
+
/**
|
|
2306
|
+
* Property-based event handler for the `touchstart` event.
|
|
2307
|
+
* @memberof scene.Container#
|
|
2308
|
+
* @default null
|
|
2309
|
+
* @example
|
|
2310
|
+
* this.ontouchstart = (event) => {
|
|
2311
|
+
* //some function here that happens on touchstart
|
|
2312
|
+
* }
|
|
2313
|
+
*/
|
|
1233
2314
|
ontouchstart: null,
|
|
2315
|
+
/**
|
|
2316
|
+
* Property-based event handler for the `wheel` event.
|
|
2317
|
+
* @memberof scene.Container#
|
|
2318
|
+
* @default null
|
|
2319
|
+
* @example
|
|
2320
|
+
* this.onwheel = (event) => {
|
|
2321
|
+
* //some function here that happens on wheel
|
|
2322
|
+
* }
|
|
2323
|
+
*/
|
|
1234
2324
|
onwheel: null,
|
|
2325
|
+
/**
|
|
2326
|
+
* Enable interaction events for the Container. Touch, pointer and mouse
|
|
2327
|
+
* @memberof scene.Container#
|
|
2328
|
+
*/
|
|
1235
2329
|
get interactive() {
|
|
1236
2330
|
return this.eventMode === 'dynamic' || this.eventMode === 'static';
|
|
1237
2331
|
},
|
|
1238
2332
|
set interactive(value) {
|
|
1239
2333
|
this.eventMode = value ? 'static' : 'passive';
|
|
1240
2334
|
},
|
|
2335
|
+
/**
|
|
2336
|
+
* @ignore
|
|
2337
|
+
*/
|
|
1241
2338
|
_internalEventMode: undefined,
|
|
2339
|
+
/**
|
|
2340
|
+
* Enable interaction events for the Container. Touch, pointer and mouse.
|
|
2341
|
+
* There are 5 types of interaction settings:
|
|
2342
|
+
* - `'none'`: Ignores all interaction events, even on its children.
|
|
2343
|
+
* - `'passive'`: **(default)** Does not emit events and ignores all hit testing on itself and non-interactive children.
|
|
2344
|
+
* Interactive children will still emit events.
|
|
2345
|
+
* - `'auto'`: Does not emit events but is hit tested if parent is interactive. Same as `interactive = false` in v7
|
|
2346
|
+
* - `'static'`: Emit events and is hit tested. Same as `interaction = true` in v7
|
|
2347
|
+
* - `'dynamic'`: Emits events and is hit tested but will also receive mock interaction events fired from a ticker to
|
|
2348
|
+
* allow for interaction when the mouse isn't moving
|
|
2349
|
+
* @example
|
|
2350
|
+
* import { Sprite } from 'pixi.js';
|
|
2351
|
+
*
|
|
2352
|
+
* const sprite = new Sprite(texture);
|
|
2353
|
+
* sprite.eventMode = 'static';
|
|
2354
|
+
* sprite.on('tap', (event) => {
|
|
2355
|
+
* // Handle event
|
|
2356
|
+
* });
|
|
2357
|
+
* @memberof scene.Container#
|
|
2358
|
+
* @since 7.2.0
|
|
2359
|
+
*/
|
|
1242
2360
|
get eventMode() {
|
|
1243
2361
|
var _a;
|
|
1244
2362
|
return (_a = this._internalEventMode) !== null && _a !== void 0 ? _a : EventSystem.defaultEventMode;
|
|
@@ -1246,11 +2364,84 @@ const FederatedContainer = {
|
|
|
1246
2364
|
set eventMode(value) {
|
|
1247
2365
|
this._internalEventMode = value;
|
|
1248
2366
|
},
|
|
2367
|
+
/**
|
|
2368
|
+
* Determines if the container is interactive or not
|
|
2369
|
+
* @returns {boolean} Whether the container is interactive or not
|
|
2370
|
+
* @memberof scene.Container#
|
|
2371
|
+
* @since 7.2.0
|
|
2372
|
+
* @example
|
|
2373
|
+
* import { Sprite } from 'pixi.js';
|
|
2374
|
+
*
|
|
2375
|
+
* const sprite = new Sprite(texture);
|
|
2376
|
+
* sprite.eventMode = 'static';
|
|
2377
|
+
* sprite.isInteractive(); // true
|
|
2378
|
+
*
|
|
2379
|
+
* sprite.eventMode = 'dynamic';
|
|
2380
|
+
* sprite.isInteractive(); // true
|
|
2381
|
+
*
|
|
2382
|
+
* sprite.eventMode = 'none';
|
|
2383
|
+
* sprite.isInteractive(); // false
|
|
2384
|
+
*
|
|
2385
|
+
* sprite.eventMode = 'passive';
|
|
2386
|
+
* sprite.isInteractive(); // false
|
|
2387
|
+
*
|
|
2388
|
+
* sprite.eventMode = 'auto';
|
|
2389
|
+
* sprite.isInteractive(); // false
|
|
2390
|
+
*/
|
|
1249
2391
|
isInteractive() {
|
|
1250
2392
|
return this.eventMode === 'static' || this.eventMode === 'dynamic';
|
|
1251
2393
|
},
|
|
2394
|
+
/**
|
|
2395
|
+
* Determines if the children to the container can be clicked/touched
|
|
2396
|
+
* Setting this to false allows PixiJS to bypass a recursive `hitTest` function
|
|
2397
|
+
* @memberof scene.Container#
|
|
2398
|
+
*/
|
|
1252
2399
|
interactiveChildren: true,
|
|
2400
|
+
/**
|
|
2401
|
+
* Interaction shape. Children will be hit first, then this shape will be checked.
|
|
2402
|
+
* Setting this will cause this shape to be checked in hit tests rather than the container's bounds.
|
|
2403
|
+
* @example
|
|
2404
|
+
* import { Rectangle, Sprite } from 'pixi.js';
|
|
2405
|
+
*
|
|
2406
|
+
* const sprite = new Sprite(texture);
|
|
2407
|
+
* sprite.interactive = true;
|
|
2408
|
+
* sprite.hitArea = new Rectangle(0, 0, 100, 100);
|
|
2409
|
+
* @member {IHitArea}
|
|
2410
|
+
* @memberof scene.Container#
|
|
2411
|
+
*/
|
|
1253
2412
|
hitArea: null,
|
|
2413
|
+
/**
|
|
2414
|
+
* Unlike `on` or `addListener` which are methods from EventEmitter, `addEventListener`
|
|
2415
|
+
* seeks to be compatible with the DOM's `addEventListener` with support for options.
|
|
2416
|
+
* @memberof scene.Container
|
|
2417
|
+
* @param type - The type of event to listen to.
|
|
2418
|
+
* @param listener - The listener callback or object.
|
|
2419
|
+
* @param options - Listener options, used for capture phase.
|
|
2420
|
+
* @example
|
|
2421
|
+
* // Tell the user whether they did a single, double, triple, or nth click.
|
|
2422
|
+
* button.addEventListener('click', {
|
|
2423
|
+
* handleEvent(e): {
|
|
2424
|
+
* let prefix;
|
|
2425
|
+
*
|
|
2426
|
+
* switch (e.detail) {
|
|
2427
|
+
* case 1: prefix = 'single'; break;
|
|
2428
|
+
* case 2: prefix = 'double'; break;
|
|
2429
|
+
* case 3: prefix = 'triple'; break;
|
|
2430
|
+
* default: prefix = e.detail + 'th'; break;
|
|
2431
|
+
* }
|
|
2432
|
+
*
|
|
2433
|
+
* console.log('That was a ' + prefix + 'click');
|
|
2434
|
+
* }
|
|
2435
|
+
* });
|
|
2436
|
+
*
|
|
2437
|
+
* // But skip the first click!
|
|
2438
|
+
* button.parent.addEventListener('click', function blockClickOnce(e) {
|
|
2439
|
+
* e.stopImmediatePropagation();
|
|
2440
|
+
* button.parent.removeEventListener('click', blockClickOnce, true);
|
|
2441
|
+
* }, {
|
|
2442
|
+
* capture: true,
|
|
2443
|
+
* });
|
|
2444
|
+
*/
|
|
1254
2445
|
addEventListener(type, listener, options) {
|
|
1255
2446
|
const capture = (typeof options === 'boolean' && options) || (typeof options === 'object' && options.capture);
|
|
1256
2447
|
const signal = typeof options === 'object' ? options.signal : undefined;
|
|
@@ -1271,6 +2462,14 @@ const FederatedContainer = {
|
|
|
1271
2462
|
emitter.on(type, listenerFn, context);
|
|
1272
2463
|
}
|
|
1273
2464
|
},
|
|
2465
|
+
/**
|
|
2466
|
+
* Unlike `off` or `removeListener` which are methods from EventEmitter, `removeEventListener`
|
|
2467
|
+
* seeks to be compatible with the DOM's `removeEventListener` with support for options.
|
|
2468
|
+
* @memberof scene.Container
|
|
2469
|
+
* @param type - The type of event the listener is bound to.
|
|
2470
|
+
* @param listener - The listener callback or object.
|
|
2471
|
+
* @param options - The original listener options. This is required to deregister a capture phase listener.
|
|
2472
|
+
*/
|
|
1274
2473
|
removeEventListener(type, listener, options) {
|
|
1275
2474
|
const capture = (typeof options === 'boolean' && options) || (typeof options === 'object' && options.capture);
|
|
1276
2475
|
const context = typeof listener === 'function' ? undefined : listener;
|
|
@@ -1278,6 +2477,17 @@ const FederatedContainer = {
|
|
|
1278
2477
|
listener = typeof listener === 'function' ? listener : listener.handleEvent;
|
|
1279
2478
|
this.off(type, listener, context);
|
|
1280
2479
|
},
|
|
2480
|
+
/**
|
|
2481
|
+
* Dispatch the event on this {@link Container} using the event's {@link EventBoundary}.
|
|
2482
|
+
*
|
|
2483
|
+
* The target of the event is set to `this` and the `defaultPrevented` flag is cleared before dispatch.
|
|
2484
|
+
* @memberof scene.Container
|
|
2485
|
+
* @param e - The event to dispatch.
|
|
2486
|
+
* @returns Whether the {@link FederatedEvent.preventDefault preventDefault}() method was not invoked.
|
|
2487
|
+
* @example
|
|
2488
|
+
* // Reuse a click event!
|
|
2489
|
+
* button.dispatchEvent(clickEvent);
|
|
2490
|
+
*/
|
|
1281
2491
|
dispatchEvent(e) {
|
|
1282
2492
|
if (!(e instanceof FederatedEvent)) {
|
|
1283
2493
|
throw new Error('Container cannot propagate events outside of the Federated Events API');
|
|
@@ -1290,6 +2500,101 @@ const FederatedContainer = {
|
|
|
1290
2500
|
},
|
|
1291
2501
|
};
|
|
1292
2502
|
|
|
2503
|
+
/* eslint-disable max-len */
|
|
2504
|
+
/**
|
|
2505
|
+
* PixiJS is primarily a rendering system, but it also includes support for interactivity.
|
|
2506
|
+
* Adding support for mouse and touch events to your project is simple and consistent.
|
|
2507
|
+
*
|
|
2508
|
+
* The new event-based system that replaced InteractionManager from v6 has expanded the definition of what a
|
|
2509
|
+
* Container means to be interactive. With this we have introduced `eventMode` which allows you to control
|
|
2510
|
+
* how an object responds to interaction events.
|
|
2511
|
+
* This is similar to the `interactive` property in v6 but with more options.
|
|
2512
|
+
*
|
|
2513
|
+
* <details id="enabling-interaction">
|
|
2514
|
+
* <summary>Enabling Interaction</summary>
|
|
2515
|
+
*
|
|
2516
|
+
* Any Container-derived object (Sprite, Container, etc.) can become interactive simply by setting its `eventMode` property to any of
|
|
2517
|
+
* the {@link events.EventMode} values. Doing so will cause the object to emit interaction events that can be responded to in order to drive your project's behavior.
|
|
2518
|
+
*
|
|
2519
|
+
* Check out the [interaction example code](/examples/events/click).
|
|
2520
|
+
*
|
|
2521
|
+
* Container-derived objects are based on {@link https://www.npmjs.com/package/eventemitter3|EventEmitter3}
|
|
2522
|
+
* so you can use `on()`, `once()`, `off()` to listen to events.
|
|
2523
|
+
*
|
|
2524
|
+
* For example to respond to clicks and taps, bind to an object ike so:
|
|
2525
|
+
*
|
|
2526
|
+
* ```javascript
|
|
2527
|
+
* let sprite = Sprite.from('/some/texture.png');
|
|
2528
|
+
*
|
|
2529
|
+
* sprite.eventMode = 'static'; // similar to `sprite.interactive = true` in v6
|
|
2530
|
+
* sprite.on('pointerdown', (event) => { alert('clicked!'); });
|
|
2531
|
+
* ```
|
|
2532
|
+
*
|
|
2533
|
+
* Check out the **EventTypes** section below for the full list of interaction events supported.
|
|
2534
|
+
* </details>
|
|
2535
|
+
*
|
|
2536
|
+
* <details id="event-modes">
|
|
2537
|
+
* <summary>Event Modes</summary>
|
|
2538
|
+
*
|
|
2539
|
+
* The new event-based system that replaced InteractionManager from v6 has expanded the definition of what a Container
|
|
2540
|
+
* means to be interactive. With this we have introduced `eventMode` which allows you to control how an object responds
|
|
2541
|
+
* to interaction events. This is similar to the `interactive` property in v6 but with more options.
|
|
2542
|
+
*
|
|
2543
|
+
* | event mode | Description |
|
|
2544
|
+
* |---|---|
|
|
2545
|
+
* | `none` | Ignores all interaction events, similar to CSS's `pointer-events: none`, good optimization for non-interactive children |
|
|
2546
|
+
* | `passive` | Does not emit events and ignores hit testing on itself but does allow for events and hit testing only its interactive children. If you want to be compatible with v6, set this as your default `eventMode` (see options in Renderer, Application, etc) |
|
|
2547
|
+
* | `auto` | Does not emit events and but is hit tested if parent is interactive. Same as `interactive = false` in v7 |
|
|
2548
|
+
* | `static` | Emit events and is hit tested. Same as `interaction = true` in v7, useful for objects like buttons that do not move. |
|
|
2549
|
+
* | `dynamic` | Emits events and is hit tested but will also receive mock interaction events fired from a ticker to allow for interaction when the mouse isn't moving. This is useful for elements that independently moving or animating. |
|
|
2550
|
+
* </details>
|
|
2551
|
+
*
|
|
2552
|
+
* <details id="event-types">
|
|
2553
|
+
* <summary>Event Types</summary>
|
|
2554
|
+
*
|
|
2555
|
+
* Pixi supports the following event types for interactive objects:
|
|
2556
|
+
*
|
|
2557
|
+
* | Event Type | Fired When |
|
|
2558
|
+
* |---|---|
|
|
2559
|
+
* | `pointercancel` | Pointer device button is released outside the display object
|
|
2560
|
+
* that initially registered a pointerdown. |
|
|
2561
|
+
* | `pointerdown` | Pointer device button is pressed on the display object. |
|
|
2562
|
+
* | `pointerenter` | Pointer device enters the display object. |
|
|
2563
|
+
* | `pointerleave` | Pointer device leaves the display object. |
|
|
2564
|
+
* | `pointermove` | Pointer device is moved while over the display object. |
|
|
2565
|
+
* | `globalpointermove` | Pointer device is moved, regardless of hit-testing the current object. |
|
|
2566
|
+
* | `pointerout` | Pointer device is moved off the display object. |
|
|
2567
|
+
* | `pointerover` | Pointer device is moved onto the display object. |
|
|
2568
|
+
* | `pointertap` | Pointer device is tapped twice on the display object. |
|
|
2569
|
+
* | `pointerup` | Pointer device button is released over the display object. |
|
|
2570
|
+
* | `pointerupoutside` | Pointer device button is released outside the display object
|
|
2571
|
+
* that initially registered a pointerdown. |
|
|
2572
|
+
* | `mousedown ` | Mouse button is pressed on the display object. |
|
|
2573
|
+
* | `mouseenter` | Mouse cursor enters the display object. |
|
|
2574
|
+
* | `mouseleave` | Mouse cursor leaves the display object. |
|
|
2575
|
+
* | `mousemove ` | Mouse cursor is moved while over the display object. |
|
|
2576
|
+
* | `globalmousemove` | Mouse is moved, regardless of hit-testing the current object. |
|
|
2577
|
+
* | `mouseout ` | Mouse cursor is moved off the display object. |
|
|
2578
|
+
* | `mouseover ` | Mouse cursor is moved onto the display object. |
|
|
2579
|
+
* | `mouseup ` | Mouse button is released over the display object. |
|
|
2580
|
+
* | `mouseupoutside ` | Mouse button is released outside the display object that initially registered a mousedown. |
|
|
2581
|
+
* | `click ` | Mouse button is clicked (pressed and released) over the display object. |
|
|
2582
|
+
* | `touchcancel ` | Touch point is removed outside of the display object that initially registered a touchstart. |
|
|
2583
|
+
* | `touchend ` | Touch point is removed from the display object. |
|
|
2584
|
+
* | `touchendoutside ` | Touch point is removed outside of the display object that initially registered a touchstart. |
|
|
2585
|
+
* | `touchmove ` | Touch point is moved along the display object. |
|
|
2586
|
+
* | `globaltouchmove` | Touch point is moved, regardless of hit-testing the current object. |
|
|
2587
|
+
* | `touchstart ` | Touch point is placed on the display object. |
|
|
2588
|
+
* | `tap ` | Touch point is tapped twice on the display object. |
|
|
2589
|
+
* | `wheel ` | Mouse wheel is spun over the display object. |
|
|
2590
|
+
* | `rightclick ` | Right mouse button is clicked (pressed and released) over the display object. |
|
|
2591
|
+
* | `rightdown ` | Right mouse button is pressed on the display object. |
|
|
2592
|
+
* | `rightup ` | Right mouse button is released over the display object. |
|
|
2593
|
+
* | `rightupoutside ` | Right mouse button is released outside the display object that initially registered a rightdown. |
|
|
2594
|
+
* </details>
|
|
2595
|
+
* @namespace events
|
|
2596
|
+
*/
|
|
2597
|
+
/* eslint-enable max-len */
|
|
1293
2598
|
const init = () => {
|
|
1294
2599
|
pixi_js.extensions.add(EventSystem);
|
|
1295
2600
|
pixi_js.extensions.mixin(pixi_js.Container, FederatedContainer);
|