react-native-gesture-handler 2.6.0 → 2.6.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (177) hide show
  1. package/android/build.gradle +2 -2
  2. package/ios/RNGestureHandler.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
  3. package/ios/RNGestureHandler.xcodeproj/project.xcworkspace/xcuserdata/jakubpiasecki.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  4. package/ios/RNGestureHandler.xcodeproj/xcuserdata/jakubpiasecki.xcuserdatad/xcschemes/xcschememanagement.plist +19 -0
  5. package/lib/commonjs/EnableExperimentalWebImplementation.js +7 -0
  6. package/lib/commonjs/EnableExperimentalWebImplementation.js.map +1 -1
  7. package/lib/commonjs/RNGestureHandlerModule.js +1 -1
  8. package/lib/commonjs/RNGestureHandlerModule.js.map +1 -1
  9. package/lib/commonjs/RNGestureHandlerModule.macos.js +20 -9
  10. package/lib/commonjs/RNGestureHandlerModule.macos.js.map +1 -1
  11. package/lib/commonjs/RNGestureHandlerModule.web.js +23 -10
  12. package/lib/commonjs/RNGestureHandlerModule.web.js.map +1 -1
  13. package/lib/commonjs/components/GestureComponents.web.js +1 -1
  14. package/lib/commonjs/components/GestureComponents.web.js.map +1 -1
  15. package/lib/commonjs/fabric/RNGestureHandlerButtonNativeComponent.js +1 -5
  16. package/lib/commonjs/fabric/RNGestureHandlerButtonNativeComponent.js.map +1 -1
  17. package/lib/commonjs/fabric/RNGestureHandlerRootViewNativeComponent.js +1 -5
  18. package/lib/commonjs/fabric/RNGestureHandlerRootViewNativeComponent.js.map +1 -1
  19. package/lib/commonjs/handlers/gestures/GestureDetector.js.map +1 -1
  20. package/lib/commonjs/handlers/gestures/eventReceiver.js +14 -20
  21. package/lib/commonjs/handlers/gestures/eventReceiver.js.map +1 -1
  22. package/lib/commonjs/handlers/gestures/gestureStateManager.web.js +32 -0
  23. package/lib/commonjs/handlers/gestures/gestureStateManager.web.js.map +1 -0
  24. package/lib/commonjs/web/detectors/RotationGestureDetector.js +13 -17
  25. package/lib/commonjs/web/detectors/RotationGestureDetector.js.map +1 -1
  26. package/lib/commonjs/web/detectors/ScaleGestureDetector.js +3 -14
  27. package/lib/commonjs/web/detectors/ScaleGestureDetector.js.map +1 -1
  28. package/lib/commonjs/web/handlers/FlingGestureHandler.js +37 -12
  29. package/lib/commonjs/web/handlers/FlingGestureHandler.js.map +1 -1
  30. package/lib/commonjs/web/handlers/GestureHandler.js +282 -79
  31. package/lib/commonjs/web/handlers/GestureHandler.js.map +1 -1
  32. package/lib/commonjs/web/handlers/LongPressGestureHandler.js +23 -18
  33. package/lib/commonjs/web/handlers/LongPressGestureHandler.js.map +1 -1
  34. package/lib/commonjs/web/handlers/ManualGestureHandler.js +51 -0
  35. package/lib/commonjs/web/handlers/ManualGestureHandler.js.map +1 -0
  36. package/lib/commonjs/web/handlers/NativeViewGestureHandler.js +81 -22
  37. package/lib/commonjs/web/handlers/NativeViewGestureHandler.js.map +1 -1
  38. package/lib/commonjs/web/handlers/PanGestureHandler.js +57 -40
  39. package/lib/commonjs/web/handlers/PanGestureHandler.js.map +1 -1
  40. package/lib/commonjs/web/handlers/PinchGestureHandler.js +43 -34
  41. package/lib/commonjs/web/handlers/PinchGestureHandler.js.map +1 -1
  42. package/lib/commonjs/web/handlers/RotationGestureHandler.js +45 -39
  43. package/lib/commonjs/web/handlers/RotationGestureHandler.js.map +1 -1
  44. package/lib/commonjs/web/handlers/TapGestureHandler.js +52 -50
  45. package/lib/commonjs/web/handlers/TapGestureHandler.js.map +1 -1
  46. package/lib/commonjs/web/interfaces.js +22 -1
  47. package/lib/commonjs/web/interfaces.js.map +1 -1
  48. package/lib/commonjs/web/tools/EventManager.js +40 -96
  49. package/lib/commonjs/web/tools/EventManager.js.map +1 -1
  50. package/lib/commonjs/web/tools/GestureHandlerOrchestrator.js +109 -30
  51. package/lib/commonjs/web/tools/GestureHandlerOrchestrator.js.map +1 -1
  52. package/lib/commonjs/web/tools/InteractionManager.js +24 -10
  53. package/lib/commonjs/web/tools/InteractionManager.js.map +1 -1
  54. package/lib/commonjs/web/tools/NodeManager.js.map +1 -1
  55. package/lib/commonjs/web/tools/PointerEventManager.js +130 -0
  56. package/lib/commonjs/web/tools/PointerEventManager.js.map +1 -0
  57. package/lib/commonjs/web/tools/PointerTracker.js +97 -7
  58. package/lib/commonjs/web/tools/PointerTracker.js.map +1 -1
  59. package/lib/commonjs/web/tools/TouchEventManager.js +138 -0
  60. package/lib/commonjs/web/tools/TouchEventManager.js.map +1 -0
  61. package/lib/commonjs/web/utils.js +15 -0
  62. package/lib/commonjs/web/utils.js.map +1 -0
  63. package/lib/module/EnableExperimentalWebImplementation.js +5 -0
  64. package/lib/module/EnableExperimentalWebImplementation.js.map +1 -1
  65. package/lib/module/RNGestureHandlerModule.js +1 -1
  66. package/lib/module/RNGestureHandlerModule.js.map +1 -1
  67. package/lib/module/RNGestureHandlerModule.macos.js +19 -10
  68. package/lib/module/RNGestureHandlerModule.macos.js.map +1 -1
  69. package/lib/module/RNGestureHandlerModule.web.js +22 -11
  70. package/lib/module/RNGestureHandlerModule.web.js.map +1 -1
  71. package/lib/module/components/GestureComponents.web.js +1 -1
  72. package/lib/module/components/GestureComponents.web.js.map +1 -1
  73. package/lib/module/fabric/RNGestureHandlerButtonNativeComponent.js +1 -5
  74. package/lib/module/fabric/RNGestureHandlerButtonNativeComponent.js.map +1 -1
  75. package/lib/module/fabric/RNGestureHandlerRootViewNativeComponent.js +1 -4
  76. package/lib/module/fabric/RNGestureHandlerRootViewNativeComponent.js.map +1 -1
  77. package/lib/module/handlers/gestures/GestureDetector.js.map +1 -1
  78. package/lib/module/handlers/gestures/eventReceiver.js +14 -20
  79. package/lib/module/handlers/gestures/eventReceiver.js.map +1 -1
  80. package/lib/module/handlers/gestures/gestureStateManager.web.js +21 -0
  81. package/lib/module/handlers/gestures/gestureStateManager.web.js.map +1 -0
  82. package/lib/module/web/detectors/RotationGestureDetector.js +13 -17
  83. package/lib/module/web/detectors/RotationGestureDetector.js.map +1 -1
  84. package/lib/module/web/detectors/ScaleGestureDetector.js +3 -14
  85. package/lib/module/web/detectors/ScaleGestureDetector.js.map +1 -1
  86. package/lib/module/web/handlers/FlingGestureHandler.js +37 -12
  87. package/lib/module/web/handlers/FlingGestureHandler.js.map +1 -1
  88. package/lib/module/web/handlers/GestureHandler.js +276 -79
  89. package/lib/module/web/handlers/GestureHandler.js.map +1 -1
  90. package/lib/module/web/handlers/LongPressGestureHandler.js +23 -18
  91. package/lib/module/web/handlers/LongPressGestureHandler.js.map +1 -1
  92. package/lib/module/web/handlers/ManualGestureHandler.js +39 -0
  93. package/lib/module/web/handlers/ManualGestureHandler.js.map +1 -0
  94. package/lib/module/web/handlers/NativeViewGestureHandler.js +80 -22
  95. package/lib/module/web/handlers/NativeViewGestureHandler.js.map +1 -1
  96. package/lib/module/web/handlers/PanGestureHandler.js +57 -41
  97. package/lib/module/web/handlers/PanGestureHandler.js.map +1 -1
  98. package/lib/module/web/handlers/PinchGestureHandler.js +43 -33
  99. package/lib/module/web/handlers/PinchGestureHandler.js.map +1 -1
  100. package/lib/module/web/handlers/RotationGestureHandler.js +45 -38
  101. package/lib/module/web/handlers/RotationGestureHandler.js.map +1 -1
  102. package/lib/module/web/handlers/TapGestureHandler.js +52 -50
  103. package/lib/module/web/handlers/TapGestureHandler.js.map +1 -1
  104. package/lib/module/web/interfaces.js +19 -0
  105. package/lib/module/web/interfaces.js.map +1 -1
  106. package/lib/module/web/tools/EventManager.js +39 -95
  107. package/lib/module/web/tools/EventManager.js.map +1 -1
  108. package/lib/module/web/tools/GestureHandlerOrchestrator.js +107 -30
  109. package/lib/module/web/tools/GestureHandlerOrchestrator.js.map +1 -1
  110. package/lib/module/web/tools/InteractionManager.js +24 -10
  111. package/lib/module/web/tools/InteractionManager.js.map +1 -1
  112. package/lib/module/web/tools/NodeManager.js.map +1 -1
  113. package/lib/module/web/tools/PointerEventManager.js +116 -0
  114. package/lib/module/web/tools/PointerEventManager.js.map +1 -0
  115. package/lib/module/web/tools/PointerTracker.js +97 -7
  116. package/lib/module/web/tools/PointerTracker.js.map +1 -1
  117. package/lib/module/web/tools/TouchEventManager.js +124 -0
  118. package/lib/module/web/tools/TouchEventManager.js.map +1 -0
  119. package/lib/module/web/utils.js +8 -0
  120. package/lib/module/web/utils.js.map +1 -0
  121. package/lib/typescript/RNGestureHandlerModule.macos.d.ts +5 -2
  122. package/lib/typescript/RNGestureHandlerModule.web.d.ts +5 -2
  123. package/lib/typescript/components/touchables/TouchableNativeFeedback.android.d.ts +1 -1
  124. package/lib/typescript/fabric/RNGestureHandlerButtonNativeComponent.d.ts +3 -3
  125. package/lib/typescript/fabric/RNGestureHandlerRootViewNativeComponent.d.ts +3 -2
  126. package/lib/typescript/handlers/gestures/gestureStateManager.web.d.ts +4 -0
  127. package/lib/typescript/web/detectors/RotationGestureDetector.d.ts +7 -7
  128. package/lib/typescript/web/detectors/ScaleGestureDetector.d.ts +6 -7
  129. package/lib/typescript/web/handlers/FlingGestureHandler.d.ts +12 -10
  130. package/lib/typescript/web/handlers/GestureHandler.d.ts +41 -32
  131. package/lib/typescript/web/handlers/LongPressGestureHandler.d.ts +6 -9
  132. package/lib/typescript/web/handlers/ManualGestureHandler.d.ts +11 -0
  133. package/lib/typescript/web/handlers/NativeViewGestureHandler.d.ts +15 -6
  134. package/lib/typescript/web/handlers/PanGestureHandler.d.ts +15 -23
  135. package/lib/typescript/web/handlers/PinchGestureHandler.d.ts +11 -12
  136. package/lib/typescript/web/handlers/RotationGestureHandler.d.ts +12 -12
  137. package/lib/typescript/web/handlers/TapGestureHandler.d.ts +11 -14
  138. package/lib/typescript/web/interfaces.d.ts +50 -10
  139. package/lib/typescript/web/tools/EventManager.d.ts +28 -26
  140. package/lib/typescript/web/tools/GestureHandlerOrchestrator.d.ts +4 -2
  141. package/lib/typescript/web/tools/InteractionManager.d.ts +3 -0
  142. package/lib/typescript/web/tools/NodeManager.d.ts +3 -3
  143. package/lib/typescript/web/tools/PointerEventManager.d.ts +6 -0
  144. package/lib/typescript/web/tools/PointerTracker.d.ts +29 -5
  145. package/lib/typescript/web/tools/TouchEventManager.d.ts +6 -0
  146. package/lib/typescript/web/utils.d.ts +4 -0
  147. package/package.json +2 -2
  148. package/src/EnableExperimentalWebImplementation.ts +9 -0
  149. package/src/RNGestureHandlerModule.macos.ts +25 -10
  150. package/src/RNGestureHandlerModule.ts +4 -1
  151. package/src/RNGestureHandlerModule.web.ts +20 -7
  152. package/src/components/GestureComponents.web.tsx +1 -1
  153. package/src/fabric/RNGestureHandlerButtonNativeComponent.ts +2 -12
  154. package/src/fabric/RNGestureHandlerRootViewNativeComponent.ts +2 -8
  155. package/src/handlers/gestures/GestureDetector.tsx +0 -1
  156. package/src/handlers/gestures/eventReceiver.ts +23 -24
  157. package/src/handlers/gestures/gestureStateManager.web.ts +24 -0
  158. package/src/web/detectors/RotationGestureDetector.ts +20 -52
  159. package/src/web/detectors/ScaleGestureDetector.ts +9 -45
  160. package/src/web/handlers/FlingGestureHandler.ts +45 -22
  161. package/src/web/handlers/GestureHandler.ts +306 -97
  162. package/src/web/handlers/LongPressGestureHandler.ts +30 -24
  163. package/src/web/handlers/ManualGestureHandler.ts +39 -0
  164. package/src/web/handlers/NativeViewGestureHandler.ts +81 -24
  165. package/src/web/handlers/PanGestureHandler.ts +68 -53
  166. package/src/web/handlers/PinchGestureHandler.ts +47 -44
  167. package/src/web/handlers/RotationGestureHandler.ts +52 -51
  168. package/src/web/handlers/TapGestureHandler.ts +74 -56
  169. package/src/web/interfaces.ts +57 -10
  170. package/src/web/tools/EventManager.ts +58 -148
  171. package/src/web/tools/GestureHandlerOrchestrator.ts +115 -47
  172. package/src/web/tools/InteractionManager.ts +25 -9
  173. package/src/web/tools/NodeManager.ts +6 -6
  174. package/src/web/tools/PointerEventManager.ts +134 -0
  175. package/src/web/tools/PointerTracker.ts +120 -10
  176. package/src/web/tools/TouchEventManager.ts +167 -0
  177. package/src/web/utils.ts +8 -0
@@ -2,19 +2,26 @@ import GestureHandler from '../handlers/GestureHandler';
2
2
  import { Config, Handler } from '../interfaces';
3
3
 
4
4
  export default class InteractionManager {
5
+ private static instance: InteractionManager;
5
6
  private readonly waitForRelations: Map<number, number[]> = new Map();
6
7
  private readonly simultaneousRelations: Map<number, number[]> = new Map();
7
8
 
9
+ // Private becaues of singleton
10
+ // eslint-disable-next-line no-useless-constructor, @typescript-eslint/no-empty-function
11
+ private constructor() {}
12
+
8
13
  public configureInteractions(handler: GestureHandler, config: Config) {
9
14
  this.dropRelationsForHandlerWithTag(handler.getTag());
10
15
 
11
16
  if (config.waitFor) {
12
17
  const waitFor: number[] = [];
13
- config.waitFor.forEach((handler: Handler): void => {
14
- if (typeof handler === 'number') {
15
- waitFor.push(handler);
18
+ config.waitFor.forEach((otherHandler: Handler): void => {
19
+ // New API reference
20
+ if (typeof otherHandler === 'number') {
21
+ waitFor.push(otherHandler);
16
22
  } else {
17
- waitFor.push(handler.handlerTag);
23
+ // Old API reference
24
+ waitFor.push(otherHandler.handlerTag);
18
25
  }
19
26
  });
20
27
 
@@ -23,17 +30,16 @@ export default class InteractionManager {
23
30
 
24
31
  if (config.simultaneousHandlers) {
25
32
  const simultaneousHandlers: number[] = [];
26
- config.simultaneousHandlers.forEach((handler: Handler): void => {
27
- if (typeof handler === 'number') {
28
- simultaneousHandlers.push(handler);
33
+ config.simultaneousHandlers.forEach((otherHandler: Handler): void => {
34
+ if (typeof otherHandler === 'number') {
35
+ simultaneousHandlers.push(otherHandler);
29
36
  } else {
30
- simultaneousHandlers.push(handler.handlerTag);
37
+ simultaneousHandlers.push(otherHandler.handlerTag);
31
38
  }
32
39
  });
33
40
 
34
41
  this.simultaneousRelations.set(handler.getTag(), simultaneousHandlers);
35
42
  }
36
- handler.setInteractionManager(this);
37
43
  }
38
44
 
39
45
  public shouldWaitForHandlerFailure(
@@ -86,6 +92,7 @@ export default class InteractionManager {
86
92
  _handler: GestureHandler,
87
93
  _otherHandler: GestureHandler
88
94
  ): boolean {
95
+ //TODO: Implement logic
89
96
  return false;
90
97
  }
91
98
 
@@ -93,6 +100,7 @@ export default class InteractionManager {
93
100
  _handler: GestureHandler,
94
101
  _otherHandler: GestureHandler
95
102
  ): boolean {
103
+ //TODO: Implement logic
96
104
  return false;
97
105
  }
98
106
 
@@ -105,4 +113,12 @@ export default class InteractionManager {
105
113
  this.waitForRelations.clear();
106
114
  this.simultaneousRelations.clear();
107
115
  }
116
+
117
+ public static getInstance(): InteractionManager {
118
+ if (!this.instance) {
119
+ this.instance = new InteractionManager();
120
+ }
121
+
122
+ return this.instance;
123
+ }
108
124
  }
@@ -2,13 +2,13 @@ import { ValueOf } from '../../typeUtils';
2
2
  import { Gestures } from '../../RNGestureHandlerModule.web';
3
3
 
4
4
  // eslint-disable-next-line @typescript-eslint/no-extraneous-class
5
- export default class NodeManager {
5
+ export default abstract class NodeManager {
6
6
  private static gestures: Record<
7
7
  number,
8
8
  InstanceType<ValueOf<typeof Gestures>>
9
9
  > = {};
10
10
 
11
- static getHandler(tag: number) {
11
+ public static getHandler(tag: number) {
12
12
  if (tag in this.gestures) {
13
13
  return this.gestures[tag];
14
14
  }
@@ -16,10 +16,10 @@ export default class NodeManager {
16
16
  throw new Error(`No handler for tag ${tag}`);
17
17
  }
18
18
 
19
- static createGestureHandler(
19
+ public static createGestureHandler(
20
20
  handlerTag: number,
21
21
  handler: InstanceType<ValueOf<typeof Gestures>>
22
- ) {
22
+ ): void {
23
23
  if (handlerTag in this.gestures) {
24
24
  throw new Error(`Handler with tag ${handlerTag} already exists`);
25
25
  }
@@ -28,7 +28,7 @@ export default class NodeManager {
28
28
  this.gestures[handlerTag].setTag(handlerTag);
29
29
  }
30
30
 
31
- static dropGestureHandler(handlerTag: number) {
31
+ public static dropGestureHandler(handlerTag: number): void {
32
32
  if (!(handlerTag in this.gestures)) {
33
33
  return;
34
34
  }
@@ -37,7 +37,7 @@ export default class NodeManager {
37
37
  delete this.gestures[handlerTag];
38
38
  }
39
39
 
40
- static getNodes() {
40
+ public static getNodes() {
41
41
  return { ...this.gestures };
42
42
  }
43
43
  }
@@ -0,0 +1,134 @@
1
+ import {
2
+ AdaptedEvent,
3
+ EventTypes,
4
+ MouseButtons,
5
+ PointerType,
6
+ } from '../interfaces';
7
+ import EventManager from './EventManager';
8
+ import { isPointerInBounds } from '../utils';
9
+
10
+ export default class PointerEventManager extends EventManager {
11
+ public setListeners(): void {
12
+ this.view.addEventListener('pointerdown', (event: PointerEvent): void => {
13
+ if (event.pointerType === PointerType.TOUCH) {
14
+ return;
15
+ }
16
+ if (
17
+ !isPointerInBounds(this.view, { x: event.clientX, y: event.clientY })
18
+ ) {
19
+ return;
20
+ }
21
+
22
+ const adaptedEvent: AdaptedEvent = this.mapEvent(event, EventTypes.DOWN);
23
+ const target = event.target as HTMLElement;
24
+
25
+ target.setPointerCapture(adaptedEvent.pointerId);
26
+ this.markAsInBounds(adaptedEvent.pointerId);
27
+
28
+ if (++this.activePointersCounter > 1) {
29
+ adaptedEvent.eventType = EventTypes.ADDITIONAL_POINTER_DOWN;
30
+ this.onPointerAdd(adaptedEvent);
31
+ } else {
32
+ this.onPointerDown(adaptedEvent);
33
+ }
34
+ });
35
+
36
+ this.view.addEventListener('pointerup', (event: PointerEvent): void => {
37
+ if (event.pointerType === PointerType.TOUCH) {
38
+ return;
39
+ }
40
+
41
+ // When we call reset on gesture handlers, it also resets their event managers
42
+ // In some handlers (like RotationGestureHandler) reset is called before all pointers leave view
43
+ // This means, that activePointersCounter will be set to 0, while there are still remaining pointers on view
44
+ // Removing them will end in activePointersCounter going below 0, therefore handlers won't behave properly
45
+ if (this.activePointersCounter === 0) {
46
+ return;
47
+ }
48
+
49
+ const adaptedEvent: AdaptedEvent = this.mapEvent(event, EventTypes.UP);
50
+ const target = event.target as HTMLElement;
51
+
52
+ target.releasePointerCapture(adaptedEvent.pointerId);
53
+ this.markAsOutOfBounds(adaptedEvent.pointerId);
54
+
55
+ if (--this.activePointersCounter > 0) {
56
+ adaptedEvent.eventType = EventTypes.ADDITIONAL_POINTER_UP;
57
+ this.onPointerRemove(adaptedEvent);
58
+ } else {
59
+ this.onPointerUp(adaptedEvent);
60
+ }
61
+ });
62
+
63
+ this.view.addEventListener('pointermove', (event: PointerEvent): void => {
64
+ if (event.pointerType === PointerType.TOUCH) {
65
+ return;
66
+ }
67
+
68
+ if (
69
+ event.pointerType === PointerType.MOUSE &&
70
+ event.buttons !== MouseButtons.LEFT
71
+ ) {
72
+ return;
73
+ }
74
+
75
+ const adaptedEvent: AdaptedEvent = this.mapEvent(event, EventTypes.MOVE);
76
+
77
+ const inBounds: boolean = isPointerInBounds(this.view, {
78
+ x: adaptedEvent.x,
79
+ y: adaptedEvent.y,
80
+ });
81
+
82
+ const pointerIndex: number = this.pointersInBounds.indexOf(
83
+ adaptedEvent.pointerId
84
+ );
85
+
86
+ if (inBounds) {
87
+ if (pointerIndex < 0) {
88
+ adaptedEvent.eventType = EventTypes.ENTER;
89
+ this.onPointerEnter(adaptedEvent);
90
+ this.markAsInBounds(adaptedEvent.pointerId);
91
+ } else {
92
+ this.onPointerMove(adaptedEvent);
93
+ }
94
+ } else {
95
+ if (pointerIndex >= 0) {
96
+ adaptedEvent.eventType = EventTypes.OUT;
97
+ this.onPointerOut(adaptedEvent);
98
+ this.markAsOutOfBounds(adaptedEvent.pointerId);
99
+ } else {
100
+ this.onPointerOutOfBounds(adaptedEvent);
101
+ }
102
+ }
103
+ });
104
+
105
+ this.view.addEventListener('pointercancel', (event: PointerEvent): void => {
106
+ if (event.pointerType === PointerType.TOUCH) {
107
+ return;
108
+ }
109
+
110
+ const adaptedEvent: AdaptedEvent = this.mapEvent(
111
+ event,
112
+ EventTypes.CANCEL
113
+ );
114
+
115
+ this.onPointerCancel(adaptedEvent);
116
+ this.markAsOutOfBounds(adaptedEvent.pointerId);
117
+ this.activePointersCounter = 0;
118
+ });
119
+ }
120
+
121
+ protected mapEvent(event: PointerEvent, eventType: EventTypes): AdaptedEvent {
122
+ return {
123
+ x: event.clientX,
124
+ y: event.clientY,
125
+ offsetX: event.offsetX,
126
+ offsetY: event.offsetY,
127
+ pointerId: event.pointerId,
128
+ eventType: eventType,
129
+ pointerType: event.pointerType as PointerType,
130
+ buttons: event.buttons,
131
+ time: event.timeStamp,
132
+ };
133
+ }
134
+ }
@@ -1,6 +1,6 @@
1
- import { AdaptedPointerEvent } from '../interfaces';
1
+ import { AdaptedEvent } from '../interfaces';
2
2
 
3
- interface TrackerElement {
3
+ export interface TrackerElement {
4
4
  lastX: number;
5
5
  lastY: number;
6
6
 
@@ -10,7 +10,9 @@ interface TrackerElement {
10
10
  velocityY: number;
11
11
  }
12
12
 
13
+ // Used to scale velocity so that it is similar to velocity in Android/iOS
13
14
  const VELOCITY_FACTOR = 0.2;
15
+ const MAX_POINTERS = 20;
14
16
 
15
17
  export default class PointerTracker {
16
18
  private trackedPointers: Map<number, TrackerElement> = new Map<
@@ -18,11 +20,27 @@ export default class PointerTracker {
18
20
  TrackerElement
19
21
  >();
20
22
 
21
- public addToTracker(event: AdaptedPointerEvent): void {
23
+ private touchEventsIds: Map<number, number> = new Map<number, number>();
24
+
25
+ private lastMovedPointerId: number;
26
+
27
+ private cachedAverages: { x: number; y: number } = { x: 0, y: 0 };
28
+
29
+ public constructor() {
30
+ this.lastMovedPointerId = NaN;
31
+
32
+ for (let i = 0; i < MAX_POINTERS; ++i) {
33
+ this.touchEventsIds.set(i, NaN);
34
+ }
35
+ }
36
+
37
+ public addToTracker(event: AdaptedEvent): void {
22
38
  if (this.trackedPointers.has(event.pointerId)) {
23
39
  return;
24
40
  }
25
41
 
42
+ this.lastMovedPointerId = event.pointerId;
43
+
26
44
  const newElement: TrackerElement = {
27
45
  lastX: event.x,
28
46
  lastY: event.y,
@@ -32,13 +50,20 @@ export default class PointerTracker {
32
50
  };
33
51
 
34
52
  this.trackedPointers.set(event.pointerId, newElement);
53
+ this.mapTouchEventId(event.pointerId);
54
+
55
+ this.cachedAverages = {
56
+ x: this.getLastAvgX(),
57
+ y: this.getLastAvgY(),
58
+ };
35
59
  }
36
60
 
37
61
  public removeFromTracker(pointerId: number): void {
38
62
  this.trackedPointers.delete(pointerId);
63
+ this.removeMappedTouchId(pointerId);
39
64
  }
40
65
 
41
- public track(event: AdaptedPointerEvent): void {
66
+ public track(event: AdaptedEvent): void {
42
67
  const element: TrackerElement = this.trackedPointers.get(
43
68
  event.pointerId
44
69
  ) as TrackerElement;
@@ -47,6 +72,8 @@ export default class PointerTracker {
47
72
  return;
48
73
  }
49
74
 
75
+ this.lastMovedPointerId = event.pointerId;
76
+
50
77
  const dx = event.x - element.lastX;
51
78
  const dy = event.y - element.lastY;
52
79
  const dt = event.time - element.timeStamp;
@@ -58,6 +85,41 @@ export default class PointerTracker {
58
85
  element.lastY = event.y;
59
86
 
60
87
  this.trackedPointers.set(event.pointerId, element);
88
+
89
+ const avgX: number = this.getLastAvgX();
90
+ const avgY: number = this.getLastAvgY();
91
+
92
+ this.cachedAverages = {
93
+ x: avgX,
94
+ y: avgY,
95
+ };
96
+ }
97
+
98
+ //Mapping TouchEvents ID
99
+ private mapTouchEventId(id: number): void {
100
+ for (const [mappedId, touchId] of this.touchEventsIds) {
101
+ if (isNaN(touchId)) {
102
+ this.touchEventsIds.set(mappedId, id);
103
+ break;
104
+ }
105
+ }
106
+ }
107
+
108
+ private removeMappedTouchId(id: number): void {
109
+ const mappedId: number = this.getMappedTouchEventId(id);
110
+ if (!isNaN(mappedId)) {
111
+ this.touchEventsIds.set(mappedId, NaN);
112
+ }
113
+ }
114
+
115
+ public getMappedTouchEventId(touchEventId: number): number {
116
+ for (const [key, value] of this.touchEventsIds.entries()) {
117
+ if (value === touchEventId) {
118
+ return key;
119
+ }
120
+ }
121
+
122
+ return NaN;
61
123
  }
62
124
 
63
125
  public getVelocityX(pointerId: number): number {
@@ -66,17 +128,60 @@ export default class PointerTracker {
66
128
  public getVelocityY(pointerId: number): number {
67
129
  return this.trackedPointers.get(pointerId)?.velocityY as number;
68
130
  }
69
- public getLastX(pointerId: number): number {
70
- return this.trackedPointers.get(pointerId)?.lastX as number;
131
+
132
+ /**
133
+ * Returns X coordinate of last moved pointer
134
+ */
135
+ public getLastX(): number;
136
+
137
+ /**
138
+ *
139
+ * @param pointerId
140
+ * Returns X coordinate of given pointer
141
+ */
142
+ // eslint-disable-next-line @typescript-eslint/unified-signatures
143
+ public getLastX(pointerId: number): number;
144
+
145
+ public getLastX(pointerId?: number): number {
146
+ if (pointerId) {
147
+ return this.trackedPointers.get(pointerId)?.lastX as number;
148
+ } else {
149
+ return this.trackedPointers.get(this.lastMovedPointerId)?.lastX as number;
150
+ }
71
151
  }
72
- public getLastY(pointerId: number): number {
73
- return this.trackedPointers.get(pointerId)?.lastY as number;
152
+
153
+ /**
154
+ * Returns Y coordinate of last moved pointer
155
+ */
156
+ public getLastY(): number;
157
+
158
+ /**
159
+ *
160
+ * @param pointerId
161
+ * Returns Y coordinate of given pointer
162
+ */
163
+ // eslint-disable-next-line @typescript-eslint/unified-signatures
164
+ public getLastY(pointerId: number): number;
165
+
166
+ public getLastY(pointerId?: number): number {
167
+ if (pointerId) {
168
+ return this.trackedPointers.get(pointerId)?.lastY as number;
169
+ } else {
170
+ return this.trackedPointers.get(this.lastMovedPointerId)?.lastY as number;
171
+ }
74
172
  }
173
+
174
+ // Some handlers use these methods to send average values in native event.
175
+ // This may happen when pointers have already been removed from tracker (i.e. pointerup event).
176
+ // In situation when NaN would be sent as a response, we return cached value.
177
+ // That prevents handlers from crashing
75
178
  public getLastAvgX(): number {
76
- return this.getSumX() / this.trackedPointers.size;
179
+ const avgX: number = this.getSumX() / this.trackedPointers.size;
180
+ return isNaN(avgX) ? this.cachedAverages.x : avgX;
77
181
  }
78
182
  public getLastAvgY(): number {
79
- return this.getSumY() / this.trackedPointers.size;
183
+ const avgY: number = this.getSumY() / this.trackedPointers.size;
184
+ return isNaN(avgY) ? this.cachedAverages.y : avgY;
80
185
  }
81
186
  public getSumX(ignoredPointer?: number): number {
82
187
  let sumX = 0;
@@ -119,6 +224,11 @@ export default class PointerTracker {
119
224
 
120
225
  public resetTracker(): void {
121
226
  this.trackedPointers.clear();
227
+ this.lastMovedPointerId = NaN;
228
+
229
+ for (let i = 0; i < MAX_POINTERS; ++i) {
230
+ this.touchEventsIds.set(i, NaN);
231
+ }
122
232
  }
123
233
 
124
234
  public static shareCommonPointers(
@@ -0,0 +1,167 @@
1
+ import {
2
+ AdaptedEvent,
3
+ EventTypes,
4
+ MouseButtons,
5
+ PointerType,
6
+ TouchEventType,
7
+ } from '../interfaces';
8
+ import EventManager from './EventManager';
9
+ import { isPointerInBounds } from '../utils';
10
+
11
+ export default class TouchEventManager extends EventManager {
12
+ public setListeners(): void {
13
+ this.view.addEventListener('touchstart', (event: TouchEvent) => {
14
+ for (let i = 0; i < event.changedTouches.length; ++i) {
15
+ const adaptedEvent: AdaptedEvent = this.mapEvent(
16
+ event,
17
+ EventTypes.DOWN,
18
+ i,
19
+ TouchEventType.DOWN
20
+ );
21
+
22
+ // Here we skip stylus, because in case of anything different than touch we want to handle it by using PointerEvents
23
+ // If we leave stylus to send touch events, handlers will receive every action twice
24
+ if (
25
+ !isPointerInBounds(this.view, {
26
+ x: adaptedEvent.x,
27
+ y: adaptedEvent.y,
28
+ }) ||
29
+ //@ts-ignore touchType field does exist
30
+ event.changedTouches[i].touchType === 'stylus'
31
+ ) {
32
+ continue;
33
+ }
34
+
35
+ this.markAsInBounds(adaptedEvent.pointerId);
36
+
37
+ if (++this.activePointersCounter > 1) {
38
+ adaptedEvent.eventType = EventTypes.ADDITIONAL_POINTER_DOWN;
39
+ this.onPointerAdd(adaptedEvent);
40
+ } else {
41
+ this.onPointerDown(adaptedEvent);
42
+ }
43
+ }
44
+ });
45
+
46
+ this.view.addEventListener('touchmove', (event: TouchEvent) => {
47
+ for (let i = 0; i < event.changedTouches.length; ++i) {
48
+ const adaptedEvent: AdaptedEvent = this.mapEvent(
49
+ event,
50
+ EventTypes.MOVE,
51
+ i,
52
+ TouchEventType.MOVE
53
+ );
54
+ //@ts-ignore touchType field does exist
55
+ if (event.changedTouches[i].touchType === 'stylus') {
56
+ continue;
57
+ }
58
+
59
+ const inBounds: boolean = isPointerInBounds(this.view, {
60
+ x: adaptedEvent.x,
61
+ y: adaptedEvent.y,
62
+ });
63
+
64
+ const pointerIndex: number = this.pointersInBounds.indexOf(
65
+ adaptedEvent.pointerId
66
+ );
67
+
68
+ if (inBounds) {
69
+ if (pointerIndex < 0) {
70
+ adaptedEvent.eventType = EventTypes.ENTER;
71
+ this.onPointerEnter(adaptedEvent);
72
+ this.markAsInBounds(adaptedEvent.pointerId);
73
+ } else {
74
+ this.onPointerMove(adaptedEvent);
75
+ }
76
+ } else {
77
+ if (pointerIndex >= 0) {
78
+ adaptedEvent.eventType = EventTypes.OUT;
79
+ this.onPointerOut(adaptedEvent);
80
+ this.markAsOutOfBounds(adaptedEvent.pointerId);
81
+ } else {
82
+ this.onPointerOutOfBounds(adaptedEvent);
83
+ }
84
+ }
85
+ }
86
+ });
87
+
88
+ this.view.addEventListener('touchend', (event: TouchEvent) => {
89
+ for (let i = 0; i < event.changedTouches.length; ++i) {
90
+ // When we call reset on gesture handlers, it also resets their event managers
91
+ // In some handlers (like RotationGestureHandler) reset is called before all pointers leave view
92
+ // This means, that activePointersCounter will be set to 0, while there are still remaining pointers on view
93
+ // Removing them will end in activePointersCounter going below 0, therefore handlers won't behave properly
94
+ if (this.activePointersCounter === 0) {
95
+ break;
96
+ }
97
+
98
+ //@ts-ignore touchType field does exist
99
+ if (event.changedTouches[i].touchType === 'stylus') {
100
+ continue;
101
+ }
102
+
103
+ const adaptedEvent: AdaptedEvent = this.mapEvent(
104
+ event,
105
+ EventTypes.UP,
106
+ i,
107
+ TouchEventType.UP
108
+ );
109
+
110
+ this.markAsOutOfBounds(adaptedEvent.pointerId);
111
+
112
+ if (--this.activePointersCounter > 0) {
113
+ adaptedEvent.eventType = EventTypes.ADDITIONAL_POINTER_UP;
114
+ this.onPointerRemove(adaptedEvent);
115
+ } else {
116
+ this.onPointerUp(adaptedEvent);
117
+ }
118
+ }
119
+ });
120
+
121
+ this.view.addEventListener('touchcancel', (event: TouchEvent) => {
122
+ for (let i = 0; i < event.changedTouches.length; ++i) {
123
+ const adaptedEvent: AdaptedEvent = this.mapEvent(
124
+ event,
125
+ EventTypes.CANCEL,
126
+ i,
127
+ TouchEventType.CANCELLED
128
+ );
129
+
130
+ //@ts-ignore touchType field does exist
131
+ if (event.changedTouches[i].touchType === 'stylus') {
132
+ continue;
133
+ }
134
+
135
+ this.onPointerCancel(adaptedEvent);
136
+ this.markAsOutOfBounds(adaptedEvent.pointerId);
137
+ this.activePointersCounter = 0;
138
+ }
139
+ });
140
+ }
141
+
142
+ protected mapEvent(
143
+ event: TouchEvent,
144
+ eventType: EventTypes,
145
+ index: number,
146
+ touchEventType: TouchEventType
147
+ ): AdaptedEvent {
148
+ const rect = this.view.getBoundingClientRect();
149
+ const clientX = event.changedTouches[index].clientX;
150
+ const clientY = event.changedTouches[index].clientY;
151
+
152
+ return {
153
+ x: clientX,
154
+ y: clientY,
155
+ offsetX: clientX - rect.left,
156
+ offsetY: clientY - rect.top,
157
+ pointerId: event.changedTouches[index].identifier,
158
+ eventType: eventType,
159
+ pointerType: PointerType.TOUCH,
160
+ buttons: MouseButtons.NONE,
161
+ time: event.timeStamp,
162
+ allTouches: event.touches,
163
+ changedTouches: event.changedTouches,
164
+ touchEventType: touchEventType,
165
+ };
166
+ }
167
+ }
@@ -0,0 +1,8 @@
1
+ export function isPointerInBounds(
2
+ view: HTMLElement,
3
+ { x, y }: { x: number; y: number }
4
+ ): boolean {
5
+ const rect: DOMRect = view.getBoundingClientRect();
6
+
7
+ return x >= rect.left && x <= rect.right && y >= rect.top && y <= rect.bottom;
8
+ }