react-native-gesture-handler 2.19.0 → 2.20.0

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.
Files changed (111) hide show
  1. package/android/build.gradle +7 -12
  2. package/android/fabric/src/main/java/com/swmansion/gesturehandler/ReactContextExtensions.kt +1 -1
  3. package/android/paper/src/main/java/com/swmansion/gesturehandler/ReactContextExtensions.kt +1 -1
  4. package/android/src/main/java/com/swmansion/gesturehandler/core/GestureUtils.kt +1 -0
  5. package/android/src/main/java/com/swmansion/gesturehandler/core/HoverGestureHandler.kt +11 -0
  6. package/android/src/main/java/com/swmansion/gesturehandler/core/PanGestureHandler.kt +8 -0
  7. package/android/src/main/java/com/swmansion/gesturehandler/core/StylusData.kt +103 -0
  8. package/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerButtonViewManager.kt +24 -15
  9. package/android/src/main/java/com/swmansion/gesturehandler/react/eventbuilders/HoverGestureHandlerEventDataBuilder.kt +7 -0
  10. package/android/src/main/java/com/swmansion/gesturehandler/react/eventbuilders/PanGestureHandlerEventDataBuilder.kt +7 -0
  11. package/android/src/main/jni/CMakeLists.txt +18 -9
  12. package/apple/Handlers/RNLongPressHandler.m +2 -0
  13. package/apple/Handlers/RNPanHandler.m +57 -7
  14. package/apple/Handlers/RNRotationHandler.m +1 -1
  15. package/apple/RNGHStylusData.h +77 -0
  16. package/apple/RNGHStylusData.m +37 -0
  17. package/apple/RNGestureHandlerButtonComponentView.mm +35 -0
  18. package/apple/RNGestureHandlerEvents.h +3 -1
  19. package/apple/RNGestureHandlerEvents.m +11 -3
  20. package/lib/commonjs/components/GestureButtons.js +5 -1
  21. package/lib/commonjs/components/GestureButtons.js.map +1 -1
  22. package/lib/commonjs/components/GestureComponents.js.map +1 -1
  23. package/lib/commonjs/components/Pressable/Pressable.js +5 -14
  24. package/lib/commonjs/components/Pressable/Pressable.js.map +1 -1
  25. package/lib/commonjs/components/Pressable/utils.js +1 -23
  26. package/lib/commonjs/components/Pressable/utils.js.map +1 -1
  27. package/lib/commonjs/handlers/GestureHandlerEventPayload.js +4 -0
  28. package/lib/commonjs/handlers/createHandler.js +2 -1
  29. package/lib/commonjs/handlers/createHandler.js.map +1 -1
  30. package/lib/commonjs/handlers/gestures/gesture.js.map +1 -1
  31. package/lib/commonjs/handlers/gestures/hoverGesture.js.map +1 -1
  32. package/lib/commonjs/jestUtils/jestUtils.js +12 -4
  33. package/lib/commonjs/jestUtils/jestUtils.js.map +1 -1
  34. package/lib/commonjs/web/handlers/GestureHandler.js +1 -3
  35. package/lib/commonjs/web/handlers/GestureHandler.js.map +1 -1
  36. package/lib/commonjs/web/handlers/HoverGestureHandler.js +18 -1
  37. package/lib/commonjs/web/handlers/HoverGestureHandler.js.map +1 -1
  38. package/lib/commonjs/web/handlers/PanGestureHandler.js +8 -1
  39. package/lib/commonjs/web/handlers/PanGestureHandler.js.map +1 -1
  40. package/lib/commonjs/web/interfaces.js.map +1 -1
  41. package/lib/commonjs/web/tools/EventManager.js.map +1 -1
  42. package/lib/commonjs/web/tools/GestureHandlerWebDelegate.js +0 -3
  43. package/lib/commonjs/web/tools/GestureHandlerWebDelegate.js.map +1 -1
  44. package/lib/commonjs/web/tools/PointerEventManager.js +3 -37
  45. package/lib/commonjs/web/tools/PointerEventManager.js.map +1 -1
  46. package/lib/commonjs/web/utils.js +173 -0
  47. package/lib/commonjs/web/utils.js.map +1 -1
  48. package/lib/module/components/GestureButtons.js +5 -1
  49. package/lib/module/components/GestureButtons.js.map +1 -1
  50. package/lib/module/components/GestureComponents.js.map +1 -1
  51. package/lib/module/components/Pressable/Pressable.js +7 -14
  52. package/lib/module/components/Pressable/Pressable.js.map +1 -1
  53. package/lib/module/components/Pressable/utils.js +1 -22
  54. package/lib/module/components/Pressable/utils.js.map +1 -1
  55. package/lib/module/handlers/GestureHandlerEventPayload.js +1 -1
  56. package/lib/module/handlers/createHandler.js +2 -1
  57. package/lib/module/handlers/createHandler.js.map +1 -1
  58. package/lib/module/handlers/gestures/gesture.js.map +1 -1
  59. package/lib/module/handlers/gestures/hoverGesture.js.map +1 -1
  60. package/lib/module/jestUtils/jestUtils.js +12 -4
  61. package/lib/module/jestUtils/jestUtils.js.map +1 -1
  62. package/lib/module/web/handlers/GestureHandler.js +1 -3
  63. package/lib/module/web/handlers/GestureHandler.js.map +1 -1
  64. package/lib/module/web/handlers/HoverGestureHandler.js +18 -1
  65. package/lib/module/web/handlers/HoverGestureHandler.js.map +1 -1
  66. package/lib/module/web/handlers/PanGestureHandler.js +8 -1
  67. package/lib/module/web/handlers/PanGestureHandler.js.map +1 -1
  68. package/lib/module/web/interfaces.js.map +1 -1
  69. package/lib/module/web/tools/EventManager.js.map +1 -1
  70. package/lib/module/web/tools/GestureHandlerWebDelegate.js +0 -2
  71. package/lib/module/web/tools/GestureHandlerWebDelegate.js.map +1 -1
  72. package/lib/module/web/tools/PointerEventManager.js +4 -38
  73. package/lib/module/web/tools/PointerEventManager.js.map +1 -1
  74. package/lib/module/web/utils.js +170 -0
  75. package/lib/module/web/utils.js.map +1 -1
  76. package/lib/typescript/components/GestureComponents.d.ts +1 -1
  77. package/lib/typescript/components/Pressable/utils.d.ts +3 -5
  78. package/lib/typescript/handlers/GestureHandlerEventPayload.d.ts +35 -0
  79. package/lib/typescript/handlers/gestures/gesture.d.ts +2 -2
  80. package/lib/typescript/handlers/gestures/hoverGesture.d.ts +1 -6
  81. package/lib/typescript/handlers/handlersRegistry.d.ts +1 -1
  82. package/lib/typescript/jestUtils/jestUtils.d.ts +1 -1
  83. package/lib/typescript/web/handlers/HoverGestureHandler.d.ts +2 -0
  84. package/lib/typescript/web/handlers/PanGestureHandler.d.ts +3 -1
  85. package/lib/typescript/web/interfaces.d.ts +8 -3
  86. package/lib/typescript/web/tools/EventManager.d.ts +2 -2
  87. package/lib/typescript/web/utils.d.ts +2 -1
  88. package/package.json +1 -1
  89. package/src/components/GestureButtons.tsx +2 -1
  90. package/src/components/GestureComponents.tsx +1 -1
  91. package/src/components/Pressable/Pressable.tsx +16 -29
  92. package/src/components/Pressable/utils.ts +5 -49
  93. package/src/handlers/GestureHandlerEventPayload.ts +42 -0
  94. package/src/handlers/createHandler.tsx +1 -0
  95. package/src/handlers/gestures/gesture.ts +3 -1
  96. package/src/handlers/gestures/hoverGesture.ts +1 -7
  97. package/src/jestUtils/jestUtils.ts +9 -1
  98. package/src/web/handlers/GestureHandler.ts +1 -1
  99. package/src/web/handlers/HoverGestureHandler.ts +16 -2
  100. package/src/web/handlers/PanGestureHandler.ts +10 -1
  101. package/src/web/interfaces.ts +9 -3
  102. package/src/web/tools/EventManager.ts +2 -4
  103. package/src/web/tools/GestureHandlerWebDelegate.ts +0 -2
  104. package/src/web/tools/PointerEventManager.ts +2 -38
  105. package/src/web/utils.ts +174 -1
  106. package/lib/commonjs/web/tools/TouchEventManager.js +0 -164
  107. package/lib/commonjs/web/tools/TouchEventManager.js.map +0 -1
  108. package/lib/module/web/tools/TouchEventManager.js +0 -149
  109. package/lib/module/web/tools/TouchEventManager.js.map +0 -1
  110. package/lib/typescript/web/tools/TouchEventManager.d.ts +0 -11
  111. package/src/web/tools/TouchEventManager.ts +0 -175
@@ -1,3 +1,5 @@
1
+ import { StylusData } from '../web/interfaces';
2
+
1
3
  export type FlingGestureHandlerEventPayload = {
2
4
  x: number;
3
5
  y: number;
@@ -120,6 +122,11 @@ export type PanGestureHandlerEventPayload = {
120
122
  * value is expressed in point units per second.
121
123
  */
122
124
  velocityY: number;
125
+
126
+ /**
127
+ * Object containing additional stylus data.
128
+ */
129
+ stylusData: StylusData | undefined;
123
130
  };
124
131
 
125
132
  export type PinchGestureHandlerEventPayload = {
@@ -182,3 +189,38 @@ export type RotationGestureHandlerEventPayload = {
182
189
  */
183
190
  velocity: number;
184
191
  };
192
+
193
+ export type HoverGestureHandlerEventPayload = {
194
+ /**
195
+ * X coordinate of the current position of the pointer relative to the view
196
+ * attached to the handler. Expressed in point units.
197
+ */
198
+ x: number;
199
+
200
+ /**
201
+ * Y coordinate of the current position of the pointer relative to the view
202
+ * attached to the handler. Expressed in point units.
203
+ */
204
+ y: number;
205
+
206
+ /**
207
+ * X coordinate of the current position of the pointer relative to the window.
208
+ * The value is expressed in point units. It is recommended to use it instead
209
+ * of `x` in cases when the original view can be transformed as an
210
+ * effect of the gesture.
211
+ */
212
+ absoluteX: number;
213
+
214
+ /**
215
+ * Y coordinate of the current position of the pointer relative to the window.
216
+ * The value is expressed in point units. It is recommended to use it instead
217
+ * of `y` in cases when the original view can be transformed as an
218
+ * effect of the gesture.
219
+ */
220
+ absoluteY: number;
221
+
222
+ /**
223
+ * Object containing additional stylus data.
224
+ */
225
+ stylusData: StylusData | undefined;
226
+ };
@@ -529,6 +529,7 @@ export default function createHandler<
529
529
  ? {
530
530
  handlerType: name,
531
531
  handlerTag: this.handlerTag,
532
+ enabled: this.props.enabled,
532
533
  }
533
534
  : {}),
534
535
  testID: this.props.testID ?? child.props.testID,
@@ -18,6 +18,7 @@ import type {
18
18
  RotationGestureHandlerEventPayload,
19
19
  TapGestureHandlerEventPayload,
20
20
  NativeViewGestureHandlerPayload,
21
+ HoverGestureHandlerEventPayload,
21
22
  } from '../GestureHandlerEventPayload';
22
23
  import { isRemoteDebuggingEnabled } from '../../utils';
23
24
 
@@ -31,7 +32,8 @@ export type GestureType =
31
32
  | BaseGesture<PinchGestureHandlerEventPayload>
32
33
  | BaseGesture<FlingGestureHandlerEventPayload>
33
34
  | BaseGesture<ForceTouchGestureHandlerEventPayload>
34
- | BaseGesture<NativeViewGestureHandlerPayload>;
35
+ | BaseGesture<NativeViewGestureHandlerPayload>
36
+ | BaseGesture<HoverGestureHandlerEventPayload>;
35
37
 
36
38
  export type GestureRef =
37
39
  | number
@@ -1,12 +1,6 @@
1
1
  import { BaseGestureConfig, ContinousBaseGesture } from './gesture';
2
2
  import { GestureUpdateEvent } from '../gestureHandlerCommon';
3
-
4
- export type HoverGestureHandlerEventPayload = {
5
- x: number;
6
- y: number;
7
- absoluteX: number;
8
- absoluteY: number;
9
- };
3
+ import type { HoverGestureHandlerEventPayload } from '../GestureHandlerEventPayload';
10
4
 
11
5
  export type HoverGestureChangeEventPayload = {
12
6
  changeX: number;
@@ -138,6 +138,7 @@ const handlersDefaultEvents: DefaultEventsMapping = {
138
138
  velocityX: 3,
139
139
  velocityY: 0,
140
140
  numberOfPointers: 1,
141
+ stylusData: undefined,
141
142
  },
142
143
  [pinchHandlerName]: {
143
144
  focalX: 0,
@@ -404,6 +405,7 @@ interface HandlerData {
404
405
  emitEvent: EventEmitter;
405
406
  handlerType: HandlerNames;
406
407
  handlerTag: number;
408
+ enabled: boolean | undefined;
407
409
  }
408
410
  function getHandlerData(
409
411
  componentOrGesture: ReactTestInstance | GestureType
@@ -416,6 +418,7 @@ function getHandlerData(
416
418
  },
417
419
  handlerType: gesture.handlerName as HandlerNames,
418
420
  handlerTag: gesture.handlerTag,
421
+ enabled: gesture.config.enabled,
419
422
  };
420
423
  }
421
424
  const gestureHandlerComponent = componentOrGesture;
@@ -425,6 +428,7 @@ function getHandlerData(
425
428
  },
426
429
  handlerType: gestureHandlerComponent.props.handlerType as HandlerNames,
427
430
  handlerTag: gestureHandlerComponent.props.handlerTag as number,
431
+ enabled: gestureHandlerComponent.props.enabled,
428
432
  };
429
433
  }
430
434
  type AllGestures =
@@ -466,9 +470,13 @@ export function fireGestureHandler<THandler extends AllGestures | AllHandlers>(
466
470
  componentOrGesture: ReactTestInstance | GestureType,
467
471
  eventList: Partial<GestureHandlerTestEvent<ExtractConfig<THandler>>>[] = []
468
472
  ): void {
469
- const { emitEvent, handlerType, handlerTag } =
473
+ const { emitEvent, handlerType, handlerTag, enabled } =
470
474
  getHandlerData(componentOrGesture);
471
475
 
476
+ if (enabled === false) {
477
+ return;
478
+ }
479
+
472
480
  let _ = fillMissingStatesTransitions(
473
481
  eventList,
474
482
  isDiscreteHandler(handlerType)
@@ -507,7 +507,7 @@ export default abstract class GestureHandler implements IGestureHandler {
507
507
  nativeEvent: {
508
508
  handlerTag: this.handlerTag,
509
509
  state: this.currentState,
510
- eventType: event.touchEventType ?? eventType,
510
+ eventType: eventType,
511
511
  changedTouches: changed,
512
512
  allTouches: all,
513
513
  numberOfTouches: numberOfTouches,
@@ -1,13 +1,22 @@
1
1
  import { State } from '../../State';
2
- import { AdaptedEvent, Config } from '../interfaces';
2
+ import { AdaptedEvent, Config, StylusData } from '../interfaces';
3
3
  import GestureHandlerOrchestrator from '../tools/GestureHandlerOrchestrator';
4
4
  import GestureHandler from './GestureHandler';
5
5
 
6
6
  export default class HoverGestureHandler extends GestureHandler {
7
+ private stylusData: StylusData | undefined;
8
+
7
9
  public init(ref: number, propsRef: React.RefObject<unknown>) {
8
10
  super.init(ref, propsRef);
9
11
  }
10
12
 
13
+ protected transformNativeEvent(): Record<string, unknown> {
14
+ return {
15
+ ...super.transformNativeEvent(),
16
+ stylusData: this.stylusData,
17
+ };
18
+ }
19
+
11
20
  public updateGestureConfig({ enabled = true, ...props }: Config): void {
12
21
  super.updateGestureConfig({ enabled: enabled, ...props });
13
22
  }
@@ -16,6 +25,7 @@ export default class HoverGestureHandler extends GestureHandler {
16
25
  GestureHandlerOrchestrator.getInstance().recordHandlerIfNotPresent(this);
17
26
 
18
27
  this.tracker.addToTracker(event);
28
+ this.stylusData = event.stylusData;
19
29
  super.onPointerMoveOver(event);
20
30
 
21
31
  if (this.getState() === State.UNDETERMINED) {
@@ -25,7 +35,9 @@ export default class HoverGestureHandler extends GestureHandler {
25
35
  }
26
36
 
27
37
  protected onPointerMoveOut(event: AdaptedEvent): void {
28
- this.tracker.addToTracker(event);
38
+ this.tracker.removeFromTracker(event.pointerId);
39
+ this.stylusData = event.stylusData;
40
+
29
41
  super.onPointerMoveOut(event);
30
42
 
31
43
  this.end();
@@ -33,6 +45,8 @@ export default class HoverGestureHandler extends GestureHandler {
33
45
 
34
46
  protected onPointerMove(event: AdaptedEvent): void {
35
47
  this.tracker.track(event);
48
+ this.stylusData = event.stylusData;
49
+
36
50
  super.onPointerMove(event);
37
51
  }
38
52
 
@@ -1,6 +1,6 @@
1
1
  import { State } from '../../State';
2
2
  import { DEFAULT_TOUCH_SLOP } from '../constants';
3
- import { AdaptedEvent, Config } from '../interfaces';
3
+ import { AdaptedEvent, Config, StylusData } from '../interfaces';
4
4
 
5
5
  import GestureHandler from './GestureHandler';
6
6
 
@@ -52,6 +52,8 @@ export default class PanGestureHandler extends GestureHandler {
52
52
  private lastX = 0;
53
53
  private lastY = 0;
54
54
 
55
+ private stylusData: StylusData | undefined;
56
+
55
57
  private activateAfterLongPress = 0;
56
58
  private activationTimeout = 0;
57
59
 
@@ -196,6 +198,7 @@ export default class PanGestureHandler extends GestureHandler {
196
198
  translationY: isNaN(translationY) ? 0 : translationY,
197
199
  velocityX: this.velocityX,
198
200
  velocityY: this.velocityY,
201
+ stylusData: this.stylusData,
199
202
  };
200
203
  }
201
204
 
@@ -217,6 +220,8 @@ export default class PanGestureHandler extends GestureHandler {
217
220
  }
218
221
 
219
222
  this.tracker.addToTracker(event);
223
+ this.stylusData = event.stylusData;
224
+
220
225
  super.onPointerDown(event);
221
226
 
222
227
  const lastCoords = this.tracker.getAbsoluteCoordsAverage();
@@ -259,6 +264,8 @@ export default class PanGestureHandler extends GestureHandler {
259
264
  }
260
265
 
261
266
  protected onPointerUp(event: AdaptedEvent): void {
267
+ this.stylusData = event.stylusData;
268
+
262
269
  super.onPointerUp(event);
263
270
  if (this.currentState === State.ACTIVE) {
264
271
  const lastCoords = this.tracker.getAbsoluteCoordsAverage();
@@ -306,6 +313,7 @@ export default class PanGestureHandler extends GestureHandler {
306
313
 
307
314
  protected onPointerMove(event: AdaptedEvent): void {
308
315
  this.tracker.track(event);
316
+ this.stylusData = event.stylusData;
309
317
 
310
318
  const lastCoords = this.tracker.getAbsoluteCoordsAverage();
311
319
  this.lastX = lastCoords.x;
@@ -326,6 +334,7 @@ export default class PanGestureHandler extends GestureHandler {
326
334
  }
327
335
 
328
336
  this.tracker.track(event);
337
+ this.stylusData = event.stylusData;
329
338
 
330
339
  const lastCoords = this.tracker.getAbsoluteCoordsAverage();
331
340
  this.lastX = lastCoords.x;
@@ -132,6 +132,14 @@ export interface PropsRef {
132
132
  onGestureHandlerStateChange: () => void;
133
133
  }
134
134
 
135
+ export interface StylusData {
136
+ tiltX: number;
137
+ tiltY: number;
138
+ azimuthAngle: number;
139
+ altitudeAngle: number;
140
+ pressure: number;
141
+ }
142
+
135
143
  export interface AdaptedEvent {
136
144
  x: number;
137
145
  y: number;
@@ -142,9 +150,7 @@ export interface AdaptedEvent {
142
150
  pointerType: PointerType;
143
151
  time: number;
144
152
  button?: MouseButton;
145
- allTouches?: TouchList;
146
- changedTouches?: TouchList;
147
- touchEventType?: TouchEventType;
153
+ stylusData?: StylusData;
148
154
  }
149
155
 
150
156
  export enum EventTypes {
@@ -1,5 +1,5 @@
1
1
  /* eslint-disable @typescript-eslint/no-empty-function */
2
- import { AdaptedEvent, EventTypes, TouchEventType } from '../interfaces';
2
+ import { AdaptedEvent, EventTypes } from '../interfaces';
3
3
 
4
4
  type PointerEventCallback = (event: AdaptedEvent) => void;
5
5
 
@@ -18,9 +18,7 @@ export default abstract class EventManager<T> {
18
18
 
19
19
  protected abstract mapEvent(
20
20
  event: Event,
21
- eventType: EventTypes,
22
- index?: number,
23
- touchEventType?: TouchEventType
21
+ eventType: EventTypes
24
22
  ): AdaptedEvent;
25
23
 
26
24
  protected onPointerDown(_event: AdaptedEvent): void {}
@@ -5,7 +5,6 @@ import {
5
5
  MeasureResult,
6
6
  } from './GestureHandlerDelegate';
7
7
  import PointerEventManager from './PointerEventManager';
8
- import TouchEventManager from './TouchEventManager';
9
8
  import { State } from '../../State';
10
9
  import { isPointerInBounds } from '../utils';
11
10
  import EventManager from './EventManager';
@@ -58,7 +57,6 @@ export class GestureHandlerWebDelegate
58
57
  this.setContextMenu(config.enabled);
59
58
 
60
59
  this.eventManagers.push(new PointerEventManager(this.view));
61
- this.eventManagers.push(new TouchEventManager(this.view));
62
60
  this.eventManagers.push(new KeyboardEventManager(this.view));
63
61
 
64
62
  this.eventManagers.forEach((manager) =>
@@ -4,15 +4,12 @@ import { AdaptedEvent, EventTypes, Point } from '../interfaces';
4
4
  import {
5
5
  PointerTypeMapping,
6
6
  calculateViewScale,
7
+ tryExtractStylusData,
7
8
  isPointerInBounds,
8
9
  } from '../utils';
9
10
  import { PointerType } from '../../PointerType';
10
11
 
11
12
  const POINTER_CAPTURE_EXCLUDE_LIST = new Set<string>(['SELECT', 'INPUT']);
12
- const PointerTypes = {
13
- Touch: 'touch',
14
- Stylus: 'pen',
15
- };
16
13
 
17
14
  export default class PointerEventManager extends EventManager<HTMLElement> {
18
15
  private trackedPointers = new Set<number>();
@@ -35,9 +32,6 @@ export default class PointerEventManager extends EventManager<HTMLElement> {
35
32
  }
36
33
 
37
34
  private pointerDownCallback = (event: PointerEvent) => {
38
- if (event.pointerType === PointerTypes.Touch) {
39
- return;
40
- }
41
35
  if (!isPointerInBounds(this.view, { x: event.clientX, y: event.clientY })) {
42
36
  return;
43
37
  }
@@ -61,10 +55,6 @@ export default class PointerEventManager extends EventManager<HTMLElement> {
61
55
  };
62
56
 
63
57
  private pointerUpCallback = (event: PointerEvent) => {
64
- if (event.pointerType === PointerTypes.Touch) {
65
- return;
66
- }
67
-
68
58
  // When we call reset on gesture handlers, it also resets their event managers
69
59
  // In some handlers (like RotationGestureHandler) reset is called before all pointers leave view
70
60
  // This means, that activePointersCounter will be set to 0, while there are still remaining pointers on view
@@ -92,21 +82,6 @@ export default class PointerEventManager extends EventManager<HTMLElement> {
92
82
  };
93
83
 
94
84
  private pointerMoveCallback = (event: PointerEvent) => {
95
- if (event.pointerType === PointerTypes.Touch) {
96
- return;
97
- }
98
-
99
- // Stylus triggers `pointermove` event when it detects changes in pressure. Since it is very sensitive to those changes,
100
- // it constantly sends events, even though there was no change in position. To fix that we check whether
101
- // pointer has actually moved and if not, we do not send event.
102
- if (
103
- event.pointerType === PointerTypes.Stylus &&
104
- event.x === this.lastPosition.x &&
105
- event.y === this.lastPosition.y
106
- ) {
107
- return;
108
- }
109
-
110
85
  const adaptedEvent: AdaptedEvent = this.mapEvent(event, EventTypes.MOVE);
111
86
  const target = event.target as HTMLElement;
112
87
 
@@ -161,10 +136,6 @@ export default class PointerEventManager extends EventManager<HTMLElement> {
161
136
  };
162
137
 
163
138
  private pointerCancelCallback = (event: PointerEvent) => {
164
- if (event.pointerType === PointerTypes.Touch) {
165
- return;
166
- }
167
-
168
139
  const adaptedEvent: AdaptedEvent = this.mapEvent(event, EventTypes.CANCEL);
169
140
 
170
141
  this.onPointerCancel(adaptedEvent);
@@ -174,20 +145,12 @@ export default class PointerEventManager extends EventManager<HTMLElement> {
174
145
  };
175
146
 
176
147
  private pointerEnterCallback = (event: PointerEvent) => {
177
- if (event.pointerType === PointerTypes.Touch) {
178
- return;
179
- }
180
-
181
148
  const adaptedEvent: AdaptedEvent = this.mapEvent(event, EventTypes.ENTER);
182
149
 
183
150
  this.onPointerMoveOver(adaptedEvent);
184
151
  };
185
152
 
186
153
  private pointerLeaveCallback = (event: PointerEvent) => {
187
- if (event.pointerType === PointerTypes.Touch) {
188
- return;
189
- }
190
-
191
154
  const adaptedEvent: AdaptedEvent = this.mapEvent(event, EventTypes.LEAVE);
192
155
 
193
156
  this.onPointerMoveOut(adaptedEvent);
@@ -252,6 +215,7 @@ export default class PointerEventManager extends EventManager<HTMLElement> {
252
215
  PointerTypeMapping.get(event.pointerType) ?? PointerType.OTHER,
253
216
  button: this.mouseButtonsMapper.get(event.button),
254
217
  time: event.timeStamp,
218
+ stylusData: tryExtractStylusData(event),
255
219
  };
256
220
  }
257
221
 
package/src/web/utils.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { PointerType } from '../PointerType';
2
- import { Point } from './interfaces';
2
+ import type { Point, StylusData } from './interfaces';
3
3
 
4
4
  export function isPointerInBounds(view: HTMLElement, { x, y }: Point): boolean {
5
5
  const rect: DOMRect = view.getBoundingClientRect();
@@ -54,3 +54,176 @@ export function calculateViewScale(view: HTMLElement) {
54
54
 
55
55
  return resultScales;
56
56
  }
57
+
58
+ export function tryExtractStylusData(
59
+ event: PointerEvent
60
+ ): StylusData | undefined {
61
+ const pointerType = PointerTypeMapping.get(event.pointerType);
62
+
63
+ if (pointerType !== PointerType.STYLUS) {
64
+ return;
65
+ }
66
+
67
+ // @ts-ignore This property exists (https://developer.mozilla.org/en-US/docs/Web/API/PointerEvent#instance_properties)
68
+ const eventAzimuthAngle: number | undefined = event.azimuthAngle;
69
+ // @ts-ignore This property exists (https://developer.mozilla.org/en-US/docs/Web/API/PointerEvent#instance_properties)
70
+ const eventAltitudeAngle: number | undefined = event.altitudeAngle;
71
+
72
+ if (event.tiltX === 0 && event.tiltY === 0) {
73
+ // If we are in this branch, it means that either tilt properties are not supported and we have to calculate them from altitude and azimuth angles,
74
+ // or stylus is perpendicular to the screen and we can use altitude / azimuth instead of tilt
75
+
76
+ // If azimuth and altitude are undefined in this branch, it means that we are either perpendicular to the screen,
77
+ // or that none of the position sets is supported. In that case, we can treat stylus as perpendicular
78
+ if (eventAzimuthAngle === undefined || eventAltitudeAngle === undefined) {
79
+ return {
80
+ tiltX: 0,
81
+ tiltY: 0,
82
+ azimuthAngle: Math.PI / 2,
83
+ altitudeAngle: Math.PI / 2,
84
+ pressure: event.pressure,
85
+ };
86
+ }
87
+
88
+ const { tiltX, tiltY } = spherical2tilt(
89
+ eventAltitudeAngle,
90
+ eventAzimuthAngle
91
+ );
92
+
93
+ return {
94
+ tiltX,
95
+ tiltY,
96
+ azimuthAngle: eventAzimuthAngle,
97
+ altitudeAngle: eventAltitudeAngle,
98
+ pressure: event.pressure,
99
+ };
100
+ }
101
+
102
+ const { altitudeAngle, azimuthAngle } = tilt2spherical(
103
+ event.tiltX,
104
+ event.tiltY
105
+ );
106
+
107
+ return {
108
+ tiltX: event.tiltX,
109
+ tiltY: event.tiltY,
110
+ azimuthAngle,
111
+ altitudeAngle,
112
+ pressure: event.pressure,
113
+ };
114
+ }
115
+
116
+ // `altitudeAngle` and `azimuthAngle` are experimental properties, which are not supported on Firefox and Safari.
117
+ // Given that, we use `tilt` properties and algorithm that converts one value to another.
118
+ //
119
+ // Source: https://w3c.github.io/pointerevents/#converting-between-tiltx-tilty-and-altitudeangle-azimuthangle
120
+ function tilt2spherical(tiltX: number, tiltY: number) {
121
+ const tiltXrad = (tiltX * Math.PI) / 180;
122
+ const tiltYrad = (tiltY * Math.PI) / 180;
123
+
124
+ // calculate azimuth angle
125
+ let azimuthAngle = 0;
126
+
127
+ if (tiltX === 0) {
128
+ if (tiltY > 0) {
129
+ azimuthAngle = Math.PI / 2;
130
+ } else if (tiltY < 0) {
131
+ azimuthAngle = (3 * Math.PI) / 2;
132
+ }
133
+ } else if (tiltY === 0) {
134
+ if (tiltX < 0) {
135
+ azimuthAngle = Math.PI;
136
+ }
137
+ } else if (Math.abs(tiltX) === 90 || Math.abs(tiltY) === 90) {
138
+ // not enough information to calculate azimuth
139
+ azimuthAngle = 0;
140
+ } else {
141
+ // Non-boundary case: neither tiltX nor tiltY is equal to 0 or +-90
142
+ const tanX = Math.tan(tiltXrad);
143
+ const tanY = Math.tan(tiltYrad);
144
+
145
+ azimuthAngle = Math.atan2(tanY, tanX);
146
+ if (azimuthAngle < 0) {
147
+ azimuthAngle += 2 * Math.PI;
148
+ }
149
+ }
150
+
151
+ // calculate altitude angle
152
+ let altitudeAngle = 0;
153
+
154
+ if (Math.abs(tiltX) === 90 || Math.abs(tiltY) === 90) {
155
+ altitudeAngle = 0;
156
+ } else if (tiltX === 0) {
157
+ altitudeAngle = Math.PI / 2 - Math.abs(tiltYrad);
158
+ } else if (tiltY === 0) {
159
+ altitudeAngle = Math.PI / 2 - Math.abs(tiltXrad);
160
+ } else {
161
+ // Non-boundary case: neither tiltX nor tiltY is equal to 0 or +-90
162
+ altitudeAngle = Math.atan(
163
+ 1.0 /
164
+ Math.sqrt(
165
+ Math.pow(Math.tan(tiltXrad), 2) + Math.pow(Math.tan(tiltYrad), 2)
166
+ )
167
+ );
168
+ }
169
+
170
+ return { altitudeAngle: altitudeAngle, azimuthAngle: azimuthAngle };
171
+ }
172
+
173
+ // If we are on a platform that doesn't support `tiltX` and `tiltY`, we have to calculate them from `altitude` and `azimuth` angles.
174
+ //
175
+ // Source: https://w3c.github.io/pointerevents/#converting-between-tiltx-tilty-and-altitudeangle-azimuthangle
176
+ function spherical2tilt(altitudeAngle: number, azimuthAngle: number) {
177
+ const radToDeg = 180 / Math.PI;
178
+
179
+ let tiltXrad = 0;
180
+ let tiltYrad = 0;
181
+
182
+ if (altitudeAngle === 0) {
183
+ // the pen is in the X-Y plane
184
+ if (azimuthAngle === 0 || azimuthAngle === 2 * Math.PI) {
185
+ // pen is on positive X axis
186
+ tiltXrad = Math.PI / 2;
187
+ }
188
+ if (azimuthAngle === Math.PI / 2) {
189
+ // pen is on positive Y axis
190
+ tiltYrad = Math.PI / 2;
191
+ }
192
+ if (azimuthAngle === Math.PI) {
193
+ // pen is on negative X axis
194
+ tiltXrad = -Math.PI / 2;
195
+ }
196
+ if (azimuthAngle === (3 * Math.PI) / 2) {
197
+ // pen is on negative Y axis
198
+ tiltYrad = -Math.PI / 2;
199
+ }
200
+ if (azimuthAngle > 0 && azimuthAngle < Math.PI / 2) {
201
+ tiltXrad = Math.PI / 2;
202
+ tiltYrad = Math.PI / 2;
203
+ }
204
+ if (azimuthAngle > Math.PI / 2 && azimuthAngle < Math.PI) {
205
+ tiltXrad = -Math.PI / 2;
206
+ tiltYrad = Math.PI / 2;
207
+ }
208
+ if (azimuthAngle > Math.PI && azimuthAngle < (3 * Math.PI) / 2) {
209
+ tiltXrad = -Math.PI / 2;
210
+ tiltYrad = -Math.PI / 2;
211
+ }
212
+ if (azimuthAngle > (3 * Math.PI) / 2 && azimuthAngle < 2 * Math.PI) {
213
+ tiltXrad = Math.PI / 2;
214
+ tiltYrad = -Math.PI / 2;
215
+ }
216
+ }
217
+
218
+ if (altitudeAngle !== 0) {
219
+ const tanAlt = Math.tan(altitudeAngle);
220
+
221
+ tiltXrad = Math.atan(Math.cos(azimuthAngle) / tanAlt);
222
+ tiltYrad = Math.atan(Math.sin(azimuthAngle) / tanAlt);
223
+ }
224
+
225
+ const tiltX = Math.round(tiltXrad * radToDeg);
226
+ const tiltY = Math.round(tiltYrad * radToDeg);
227
+
228
+ return { tiltX, tiltY };
229
+ }