@react-native-oh-tpl/react-native-gesture-handler 2.14.1-2.14.8 → 2.14.1-2.14.9
Sign up to get free protection for your applications and to get access to all the features.
- package/DrawerLayout/index.ts +2 -2
- package/Swipeable/index.ts +2 -2
- package/harmony/gesture_handler/BuildProfile.ets +17 -0
- package/harmony/gesture_handler/build-profile.json5 +19 -0
- package/harmony/gesture_handler/hvigorfile.ts +2 -0
- package/harmony/gesture_handler/index.ets +3 -0
- package/harmony/gesture_handler/oh-package-lock.json5 +18 -0
- package/harmony/gesture_handler/oh-package.json5 +12 -0
- package/harmony/gesture_handler/src/main/cpp/CMakeLists.txt +8 -0
- package/harmony/gesture_handler/src/main/cpp/GestureHandlerPackage.cpp +149 -0
- package/harmony/gesture_handler/src/main/cpp/GestureHandlerPackage.h +21 -0
- package/harmony/gesture_handler/src/main/cpp/RNGestureHandlerButtonComponentDescriptor.h +36 -0
- package/harmony/gesture_handler/src/main/cpp/RNGestureHandlerButtonJSIBinder.h +32 -0
- package/harmony/gesture_handler/src/main/cpp/RNGestureHandlerModule.cpp +22 -0
- package/harmony/gesture_handler/src/main/cpp/RNGestureHandlerModule.h +15 -0
- package/harmony/gesture_handler/src/main/cpp/RNGestureHandlerRootViewComponentDescriptor.h +36 -0
- package/harmony/gesture_handler/src/main/cpp/RNGestureHandlerRootViewJSIBinder.h +25 -0
- package/harmony/gesture_handler/src/main/cpp/componentInstances/RNGestureHandlerButtonComponentInstance.h +27 -0
- package/harmony/gesture_handler/src/main/cpp/componentInstances/RNGestureHandlerRootViewComponentInstance.h +234 -0
- package/harmony/gesture_handler/src/main/ets/core/CircularBuffer.ts +42 -0
- package/harmony/gesture_handler/src/main/ets/core/GestureHandler.ts +684 -0
- package/harmony/gesture_handler/src/main/ets/core/GestureHandlerOrchestrator.ts +335 -0
- package/harmony/gesture_handler/src/main/ets/core/GestureHandlerRegistry.ts +35 -0
- package/harmony/gesture_handler/src/main/ets/core/IncomingEvent.ts +78 -0
- package/harmony/gesture_handler/src/main/ets/core/InteractionManager.ts +144 -0
- package/harmony/gesture_handler/src/main/ets/core/LeastSquareSolver.ts +182 -0
- package/harmony/gesture_handler/src/main/ets/core/OutgoingEvent.ts +34 -0
- package/harmony/gesture_handler/src/main/ets/core/OutgoingEventDispatcher.ts +12 -0
- package/harmony/gesture_handler/src/main/ets/core/PointerTracker.ts +239 -0
- package/harmony/gesture_handler/src/main/ets/core/RNGHError.ts +5 -0
- package/harmony/gesture_handler/src/main/ets/core/RNGHLogger.ts +12 -0
- package/harmony/gesture_handler/src/main/ets/core/State.ts +47 -0
- package/harmony/gesture_handler/src/main/ets/core/Vector2D.ts +80 -0
- package/harmony/gesture_handler/src/main/ets/core/VelocityTracker.ts +106 -0
- package/harmony/gesture_handler/src/main/ets/core/View.ts +19 -0
- package/harmony/gesture_handler/src/main/ets/core/index.ts +13 -0
- package/harmony/gesture_handler/src/main/ets/detectors/ScaleGestureDetector.ts +169 -0
- package/harmony/gesture_handler/src/main/ets/gesture-handlers/FlingGestureHandler.ts +211 -0
- package/harmony/gesture_handler/src/main/ets/gesture-handlers/GestureHandlerFactory.ts +64 -0
- package/harmony/gesture_handler/src/main/ets/gesture-handlers/LongPressGestureHandler.ts +127 -0
- package/harmony/gesture_handler/src/main/ets/gesture-handlers/ManualGestureHandler.ts +42 -0
- package/harmony/gesture_handler/src/main/ets/gesture-handlers/NativeViewGestureHandler.ts +113 -0
- package/harmony/gesture_handler/src/main/ets/gesture-handlers/PanGestureHandler.ts +342 -0
- package/harmony/gesture_handler/src/main/ets/gesture-handlers/PinchGestureHandler.ts +159 -0
- package/harmony/gesture_handler/src/main/ets/gesture-handlers/RotationGestureHandler.ts +164 -0
- package/harmony/gesture_handler/src/main/ets/gesture-handlers/TapGestureHandler.ts +206 -0
- package/harmony/gesture_handler/src/main/ets/gesture-handlers/detectors/RotationGestureDetector.ts +167 -0
- package/harmony/gesture_handler/src/main/ets/gesture-handlers/index.ts +1 -0
- package/harmony/gesture_handler/src/main/ets/namespace/RNGestureHandlerModule.ts +24 -0
- package/harmony/gesture_handler/src/main/ets/namespace/components/RNGestureHandlerButton.ts +139 -0
- package/harmony/gesture_handler/src/main/ets/namespace/components/RNGestureHandlerRootView.ts +101 -0
- package/harmony/gesture_handler/src/main/ets/namespace/components/ts.ts +2 -0
- package/harmony/gesture_handler/src/main/ets/namespace/ts.ts +2 -0
- package/harmony/gesture_handler/src/main/ets/rnoh/GestureHandlerArkUIAdapter.ts +240 -0
- package/harmony/gesture_handler/src/main/ets/rnoh/GestureHandlerPackage.ts +22 -0
- package/harmony/gesture_handler/src/main/ets/rnoh/Logger.ts +49 -0
- package/harmony/gesture_handler/src/main/ets/rnoh/OutgoingEventDispatchers.ts +71 -0
- package/harmony/gesture_handler/src/main/ets/rnoh/RNGHRootTouchHandlerArkTS.ts +104 -0
- package/harmony/gesture_handler/src/main/ets/rnoh/RNGHRootTouchHandlerCAPI.ts +110 -0
- package/harmony/gesture_handler/src/main/ets/rnoh/RNGestureHandlerButton.ets +38 -0
- package/harmony/gesture_handler/src/main/ets/rnoh/RNGestureHandlerModule.ts +230 -0
- package/harmony/gesture_handler/src/main/ets/rnoh/RNGestureHandlerRootView.ets +53 -0
- package/harmony/gesture_handler/src/main/ets/rnoh/RNOHGestureResponder.ts +24 -0
- package/harmony/gesture_handler/src/main/ets/rnoh/RNOHScrollLocker.ts +32 -0
- package/harmony/gesture_handler/src/main/ets/rnoh/View.ts +119 -0
- package/harmony/gesture_handler/src/main/ets/rnoh/ViewRegistry.ts +95 -0
- package/harmony/gesture_handler/src/main/ets/rnoh/types.ts +25 -0
- package/harmony/gesture_handler/src/main/module.json5 +9 -0
- package/harmony/gesture_handler/src/main/resources/base/element/color.json +8 -0
- package/harmony/gesture_handler/src/main/resources/base/element/string.json +16 -0
- package/harmony/gesture_handler/src/main/resources/base/media/icon.png +0 -0
- package/harmony/gesture_handler/src/main/resources/base/profile/main_pages.json +5 -0
- package/harmony/gesture_handler/src/main/resources/en_US/element/string.json +16 -0
- package/harmony/gesture_handler/src/main/resources/zh_CN/element/string.json +16 -0
- package/harmony/gesture_handler/ts.ts +2 -0
- package/harmony/gesture_handler.har +0 -0
- package/lib/commonjs/RNGestureHandlerModule.js +3 -2
- package/lib/commonjs/RNGestureHandlerModule.js.map +1 -1
- package/lib/commonjs/components/GestureHandlerRootView.js +3 -3
- package/lib/commonjs/components/GestureHandlerRootView.js.map +1 -1
- package/lib/commonjs/handlers/createHandler.js +18 -15
- package/lib/commonjs/handlers/createHandler.js.map +1 -1
- package/lib/commonjs/index.js +8 -5
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/specs/NativeRNGestureHandlerModule.js +2 -1
- package/lib/commonjs/specs/NativeRNGestureHandlerModule.js.map +1 -1
- package/lib/commonjs/specs/RNGestureHandlerButtonNativeComponent.js +3 -2
- package/lib/commonjs/specs/RNGestureHandlerButtonNativeComponent.js.map +1 -1
- package/lib/commonjs/specs/RNGestureHandlerRootViewNativeComponent.js +3 -2
- package/lib/commonjs/specs/RNGestureHandlerRootViewNativeComponent.js.map +1 -1
- package/lib/module/RNGestureHandlerModule.js.map +1 -1
- package/lib/module/components/GestureHandlerRootView.js.map +1 -1
- package/lib/module/handlers/createHandler.js +15 -12
- package/lib/module/handlers/createHandler.js.map +1 -1
- package/lib/module/index.js +1 -3
- package/lib/module/index.js.map +1 -1
- package/lib/module/specs/NativeRNGestureHandlerModule.js.map +1 -1
- package/lib/module/specs/RNGestureHandlerButtonNativeComponent.js.map +1 -1
- package/lib/module/specs/RNGestureHandlerRootViewNativeComponent.js.map +1 -1
- package/lib/typescript/RNGestureHandlerModule.d.ts +2 -2
- package/lib/typescript/components/GestureHandlerRootView.d.ts +6 -6
- package/lib/typescript/handlers/createHandler.d.ts +11 -11
- package/lib/typescript/index.d.ts +43 -42
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/specs/NativeRNGestureHandlerModule.d.ts +14 -14
- package/lib/typescript/specs/RNGestureHandlerButtonNativeComponent.d.ts +14 -14
- package/lib/typescript/specs/RNGestureHandlerRootViewNativeComponent.d.ts +6 -6
- package/package.json +68 -69
- package/src/RNGestureHandlerModule.ts +4 -4
- package/src/components/GestureHandlerRootView.tsx +23 -23
- package/src/handlers/createHandler.tsx +534 -534
- package/src/index.ts +172 -172
- package/src/specs/NativeRNGestureHandlerModule.ts +26 -26
- package/src/specs/RNGestureHandlerButtonNativeComponent.ts +18 -18
- package/src/specs/RNGestureHandlerRootViewNativeComponent.ts +6 -6
@@ -0,0 +1,106 @@
|
|
1
|
+
import { IncomingEvent } from './IncomingEvent';
|
2
|
+
import { CircularBuffer } from './CircularBuffer';
|
3
|
+
import { LeastSquareSolver } from './LeastSquareSolver';
|
4
|
+
|
5
|
+
export interface TrackerElement {
|
6
|
+
lastX: number;
|
7
|
+
lastY: number;
|
8
|
+
timeStamp: number;
|
9
|
+
velocityX: number;
|
10
|
+
velocityY: number;
|
11
|
+
}
|
12
|
+
|
13
|
+
export class VelocityTracker {
|
14
|
+
private assumePointerMoveStoppedMilliseconds = 40;
|
15
|
+
private historySize = 20;
|
16
|
+
private horizonMilliseconds = 300;
|
17
|
+
private minSampleSize = 3;
|
18
|
+
|
19
|
+
private samples: CircularBuffer<IncomingEvent>;
|
20
|
+
|
21
|
+
constructor() {
|
22
|
+
this.samples = new CircularBuffer<IncomingEvent>(this.historySize);
|
23
|
+
}
|
24
|
+
|
25
|
+
public add(event: IncomingEvent): void {
|
26
|
+
this.samples.push(event);
|
27
|
+
}
|
28
|
+
|
29
|
+
/// Returns an estimate of the velocity of the object being tracked by the
|
30
|
+
/// tracker given the current information available to the tracker.
|
31
|
+
///
|
32
|
+
/// Information is added using [addPosition].
|
33
|
+
///
|
34
|
+
/// Returns null if there is no data on which to base an estimate.
|
35
|
+
private getVelocityEstimate(): [number, number] | null {
|
36
|
+
const x = [];
|
37
|
+
const y = [];
|
38
|
+
const w = [];
|
39
|
+
const time = [];
|
40
|
+
|
41
|
+
let sampleCount = 0;
|
42
|
+
let index = this.samples.size - 1;
|
43
|
+
const newestSample = this.samples.get(index);
|
44
|
+
if (!newestSample) {
|
45
|
+
return null;
|
46
|
+
}
|
47
|
+
|
48
|
+
let previousSample = newestSample;
|
49
|
+
|
50
|
+
// Starting with the most recent PointAtTime sample, iterate backwards while
|
51
|
+
// the samples represent continuous motion.
|
52
|
+
while (sampleCount < this.samples.size) {
|
53
|
+
const sample = this.samples.get(index);
|
54
|
+
|
55
|
+
const age = newestSample.time - sample.time;
|
56
|
+
const delta = Math.abs(sample.time - previousSample.time);
|
57
|
+
previousSample = sample;
|
58
|
+
|
59
|
+
if (
|
60
|
+
age > this.horizonMilliseconds ||
|
61
|
+
delta > this.assumePointerMoveStoppedMilliseconds
|
62
|
+
) {
|
63
|
+
break;
|
64
|
+
}
|
65
|
+
|
66
|
+
x.push(sample.x);
|
67
|
+
y.push(sample.y);
|
68
|
+
w.push(1);
|
69
|
+
time.push(-age);
|
70
|
+
|
71
|
+
sampleCount++;
|
72
|
+
index--;
|
73
|
+
}
|
74
|
+
|
75
|
+
if (sampleCount >= this.minSampleSize) {
|
76
|
+
const xSolver = new LeastSquareSolver(time, x, w);
|
77
|
+
const xFit = xSolver.solve(2);
|
78
|
+
|
79
|
+
if (xFit !== null) {
|
80
|
+
const ySolver = new LeastSquareSolver(time, y, w);
|
81
|
+
const yFit = ySolver.solve(2);
|
82
|
+
|
83
|
+
if (yFit !== null) {
|
84
|
+
const xVelocity = xFit.coefficients[1] * 1000;
|
85
|
+
const yVelocity = yFit.coefficients[1] * 1000;
|
86
|
+
|
87
|
+
return [xVelocity, yVelocity];
|
88
|
+
}
|
89
|
+
}
|
90
|
+
}
|
91
|
+
|
92
|
+
return null;
|
93
|
+
}
|
94
|
+
|
95
|
+
public getVelocity(): [number, number] {
|
96
|
+
const estimate = this.getVelocityEstimate();
|
97
|
+
if (estimate !== null) {
|
98
|
+
return estimate;
|
99
|
+
}
|
100
|
+
return [0, 0];
|
101
|
+
}
|
102
|
+
|
103
|
+
public reset(): void {
|
104
|
+
this.samples.clear();
|
105
|
+
}
|
106
|
+
}
|
@@ -0,0 +1,19 @@
|
|
1
|
+
export type Tag = number
|
2
|
+
|
3
|
+
export type BoundingBox = {
|
4
|
+
x: number;
|
5
|
+
y: number;
|
6
|
+
width: number;
|
7
|
+
height: number;
|
8
|
+
};
|
9
|
+
|
10
|
+
export interface View {
|
11
|
+
getTag(): Tag
|
12
|
+
|
13
|
+
isPositionInBounds({x, y}: {
|
14
|
+
x: number;
|
15
|
+
y: number
|
16
|
+
}): boolean
|
17
|
+
|
18
|
+
getBoundingRect(): BoundingBox
|
19
|
+
}
|
@@ -0,0 +1,13 @@
|
|
1
|
+
export * from "./OutgoingEventDispatcher"
|
2
|
+
export * from "./OutgoingEvent"
|
3
|
+
export * from "./RNGHLogger"
|
4
|
+
export * from "./View"
|
5
|
+
export * from "./Vector2D"
|
6
|
+
export * from "./GestureHandler"
|
7
|
+
export * from "./IncomingEvent"
|
8
|
+
export * from "./GestureHandlerOrchestrator"
|
9
|
+
export * from "./InteractionManager"
|
10
|
+
export * from "./PointerTracker"
|
11
|
+
export * from "./RNGHError"
|
12
|
+
export * from "./State"
|
13
|
+
export * from "./GestureHandlerRegistry"
|
@@ -0,0 +1,169 @@
|
|
1
|
+
import { DEFAULT_TOUCH_SLOP, IncomingEvent, EventType, PointerTracker } from '../core';
|
2
|
+
|
3
|
+
export interface ScaleGestureListener {
|
4
|
+
onScaleBegin: (detector: ScaleGestureDetector) => boolean;
|
5
|
+
onScale: (detector: ScaleGestureDetector) => boolean;
|
6
|
+
onScaleEnd: (detector: ScaleGestureDetector) => void;
|
7
|
+
}
|
8
|
+
|
9
|
+
export default class ScaleGestureDetector implements ScaleGestureListener {
|
10
|
+
public onScaleBegin: (detector: ScaleGestureDetector) => boolean;
|
11
|
+
public onScale: (detector: ScaleGestureDetector) => boolean;
|
12
|
+
public onScaleEnd: (detector: ScaleGestureDetector) => void;
|
13
|
+
|
14
|
+
private focusX!: number;
|
15
|
+
private focusY!: number;
|
16
|
+
|
17
|
+
private currentSpan!: number;
|
18
|
+
private prevSpan!: number;
|
19
|
+
private initialSpan!: number;
|
20
|
+
|
21
|
+
private currentTime!: number;
|
22
|
+
private prevTime!: number;
|
23
|
+
|
24
|
+
private inProgress = false;
|
25
|
+
|
26
|
+
private spanSlop: number;
|
27
|
+
private minSpan: number;
|
28
|
+
|
29
|
+
public constructor(callbacks: ScaleGestureListener) {
|
30
|
+
this.onScaleBegin = callbacks.onScaleBegin;
|
31
|
+
this.onScale = callbacks.onScale;
|
32
|
+
this.onScaleEnd = callbacks.onScaleEnd;
|
33
|
+
|
34
|
+
this.spanSlop = DEFAULT_TOUCH_SLOP * 2;
|
35
|
+
this.minSpan = 0;
|
36
|
+
}
|
37
|
+
|
38
|
+
public onTouchEvent(event: IncomingEvent, tracker: PointerTracker): boolean {
|
39
|
+
this.currentTime = event.time;
|
40
|
+
|
41
|
+
const action: EventType = event.eventType;
|
42
|
+
const numOfPointers = tracker.getTrackedPointersCount();
|
43
|
+
|
44
|
+
const streamComplete: boolean =
|
45
|
+
action === EventType.UP ||
|
46
|
+
action === EventType.ADDITIONAL_POINTER_UP ||
|
47
|
+
action === EventType.CANCEL;
|
48
|
+
|
49
|
+
if (action === EventType.DOWN || streamComplete) {
|
50
|
+
if (this.inProgress) {
|
51
|
+
this.onScaleEnd(this);
|
52
|
+
this.inProgress = false;
|
53
|
+
this.initialSpan = 0;
|
54
|
+
}
|
55
|
+
|
56
|
+
if (streamComplete) {
|
57
|
+
return true;
|
58
|
+
}
|
59
|
+
}
|
60
|
+
|
61
|
+
const configChanged: boolean =
|
62
|
+
action === EventType.DOWN ||
|
63
|
+
action === EventType.ADDITIONAL_POINTER_UP ||
|
64
|
+
action === EventType.ADDITIONAL_POINTER_DOWN;
|
65
|
+
|
66
|
+
const pointerUp = action === EventType.ADDITIONAL_POINTER_UP;
|
67
|
+
|
68
|
+
const ignoredPointer: number | undefined = pointerUp
|
69
|
+
? event.pointerId
|
70
|
+
: undefined;
|
71
|
+
|
72
|
+
//Determine focal point
|
73
|
+
|
74
|
+
const div: number = pointerUp ? numOfPointers - 1 : numOfPointers;
|
75
|
+
|
76
|
+
const sumX = tracker.getSumX(ignoredPointer);
|
77
|
+
const sumY = tracker.getSumY(ignoredPointer);
|
78
|
+
|
79
|
+
const focusX = sumX / div;
|
80
|
+
const focusY = sumY / div;
|
81
|
+
|
82
|
+
//Determine average deviation from focal point
|
83
|
+
|
84
|
+
let devSumX = 0;
|
85
|
+
let devSumY = 0;
|
86
|
+
|
87
|
+
tracker.getData().forEach((value, key) => {
|
88
|
+
if (key === ignoredPointer) {
|
89
|
+
return;
|
90
|
+
}
|
91
|
+
|
92
|
+
devSumX += Math.abs(value.lastX - focusX);
|
93
|
+
devSumY += Math.abs(value.lastY - focusY);
|
94
|
+
});
|
95
|
+
|
96
|
+
const devX: number = devSumX / div;
|
97
|
+
const devY: number = devSumY / div;
|
98
|
+
|
99
|
+
const spanX: number = devX * 2;
|
100
|
+
const spanY: number = devY * 2;
|
101
|
+
|
102
|
+
const span = Math.hypot(spanX, spanY);
|
103
|
+
|
104
|
+
//Begin/end events
|
105
|
+
const wasInProgress: boolean = this.inProgress;
|
106
|
+
this.focusX = focusX;
|
107
|
+
this.focusY = focusY;
|
108
|
+
|
109
|
+
if (this.inProgress && (span < this.minSpan || configChanged)) {
|
110
|
+
this.onScaleEnd(this);
|
111
|
+
this.inProgress = false;
|
112
|
+
this.initialSpan = span;
|
113
|
+
}
|
114
|
+
|
115
|
+
if (configChanged) {
|
116
|
+
this.initialSpan = this.prevSpan = this.currentSpan = span;
|
117
|
+
}
|
118
|
+
|
119
|
+
if (
|
120
|
+
!this.inProgress &&
|
121
|
+
span >= this.minSpan &&
|
122
|
+
(wasInProgress || Math.abs(span - this.initialSpan) > this.spanSlop)
|
123
|
+
) {
|
124
|
+
this.prevSpan = this.currentSpan = span;
|
125
|
+
this.prevTime = this.currentTime;
|
126
|
+
this.inProgress = this.onScaleBegin(this);
|
127
|
+
}
|
128
|
+
|
129
|
+
//Handle motion
|
130
|
+
if (action !== EventType.MOVE) {
|
131
|
+
return true;
|
132
|
+
}
|
133
|
+
|
134
|
+
this.currentSpan = span;
|
135
|
+
|
136
|
+
if (this.inProgress && !this.onScale(this)) {
|
137
|
+
return true;
|
138
|
+
}
|
139
|
+
|
140
|
+
this.prevSpan = this.currentSpan;
|
141
|
+
this.prevTime = this.currentTime;
|
142
|
+
|
143
|
+
return true;
|
144
|
+
}
|
145
|
+
|
146
|
+
public getCurrentSpan(): number {
|
147
|
+
return this.currentSpan;
|
148
|
+
}
|
149
|
+
|
150
|
+
public getFocusX(): number {
|
151
|
+
return this.focusX;
|
152
|
+
}
|
153
|
+
|
154
|
+
public getFocusY(): number {
|
155
|
+
return this.focusY;
|
156
|
+
}
|
157
|
+
|
158
|
+
public getTimeDelta(): number {
|
159
|
+
return this.currentTime - this.prevTime;
|
160
|
+
}
|
161
|
+
|
162
|
+
public getScaleFactor(numOfPointers: number): number {
|
163
|
+
if (numOfPointers < 2) {
|
164
|
+
return 1;
|
165
|
+
}
|
166
|
+
|
167
|
+
return this.prevSpan > 0 ? this.currentSpan / this.prevSpan : 1;
|
168
|
+
}
|
169
|
+
}
|
@@ -0,0 +1,211 @@
|
|
1
|
+
import {
|
2
|
+
GestureHandler,
|
3
|
+
State,
|
4
|
+
DiagonalDirections,
|
5
|
+
Directions,
|
6
|
+
Vector2D,
|
7
|
+
IncomingEvent,
|
8
|
+
GestureHandlerDependencies
|
9
|
+
} from '../core';
|
10
|
+
|
11
|
+
const DEFAULT_MAX_DURATION_MS = 800;
|
12
|
+
const DEFAULT_MIN_VELOCITY = 700;
|
13
|
+
/**
|
14
|
+
* DEFAULT_ALIGNMENT_CONE defines the angular tolerance for fling gestures in degrees.
|
15
|
+
* *
|
16
|
+
* *
|
17
|
+
* *
|
18
|
+
* *------------>
|
19
|
+
* *
|
20
|
+
* *
|
21
|
+
* *
|
22
|
+
*/
|
23
|
+
const DEFAULT_ALIGNMENT_CONE = 30;
|
24
|
+
const DEFAULT_DIRECTION: Directions = Directions.RIGHT;
|
25
|
+
const DEFAULT_NUMBER_OF_TOUCHES_REQUIRED = 1;
|
26
|
+
const AXIAL_DEVIATION_COSINE = coneToDeviation(DEFAULT_ALIGNMENT_CONE);
|
27
|
+
const DIAGONAL_DEVIATION_COSINE = coneToDeviation(90 - DEFAULT_ALIGNMENT_CONE);
|
28
|
+
|
29
|
+
export class FlingGestureHandler extends GestureHandler {
|
30
|
+
constructor(deps: GestureHandlerDependencies) {
|
31
|
+
super({ ...deps, logger: deps.logger.cloneWithPrefix("FlingGestureHandler") })
|
32
|
+
}
|
33
|
+
|
34
|
+
getDefaultConfig() {
|
35
|
+
return {}
|
36
|
+
}
|
37
|
+
|
38
|
+
private get direction(): Directions {
|
39
|
+
return this.config.direction ?? DEFAULT_DIRECTION
|
40
|
+
}
|
41
|
+
|
42
|
+
private get numberOfPointersRequired() {
|
43
|
+
return this.config.numberOfPointers ?? DEFAULT_NUMBER_OF_TOUCHES_REQUIRED
|
44
|
+
}
|
45
|
+
|
46
|
+
private get maxDurationMs() {
|
47
|
+
return this.config.maxDurationMs ?? DEFAULT_MAX_DURATION_MS
|
48
|
+
}
|
49
|
+
|
50
|
+
private get minVelocity() {
|
51
|
+
return this.config.minVelocity ?? DEFAULT_MIN_VELOCITY
|
52
|
+
}
|
53
|
+
|
54
|
+
private delayTimeout!: number;
|
55
|
+
private maxNumberOfPointersSimultaneously = 0;
|
56
|
+
private keyPointer = NaN;
|
57
|
+
|
58
|
+
private startFling(): void {
|
59
|
+
this.logger.info("startFling")
|
60
|
+
this.begin();
|
61
|
+
|
62
|
+
this.maxNumberOfPointersSimultaneously = 1;
|
63
|
+
|
64
|
+
this.delayTimeout = setTimeout(() => this.fail(), this.maxDurationMs);
|
65
|
+
}
|
66
|
+
|
67
|
+
private tryEndFling(): boolean {
|
68
|
+
const logger = this.logger.cloneWithPrefix("tryEndFling")
|
69
|
+
const velocityVector = this.tracker.getVelocity(this.keyPointer);
|
70
|
+
|
71
|
+
const getAlignment = (
|
72
|
+
direction: Directions | DiagonalDirections,
|
73
|
+
minimalAlignmentCosine: number
|
74
|
+
) => {
|
75
|
+
return (
|
76
|
+
(direction & this.direction) === direction &&
|
77
|
+
velocityVector.computeCosine(
|
78
|
+
Vector2D.fromDirection(direction),
|
79
|
+
) > minimalAlignmentCosine
|
80
|
+
);
|
81
|
+
};
|
82
|
+
|
83
|
+
const axialDirectionsList = Object.values(Directions);
|
84
|
+
const diagonalDirectionsList = Object.values(DiagonalDirections);
|
85
|
+
|
86
|
+
// list of alignments to all activated directions
|
87
|
+
const axialAlignmentList = axialDirectionsList.map((direction) =>
|
88
|
+
getAlignment(direction, AXIAL_DEVIATION_COSINE)
|
89
|
+
);
|
90
|
+
|
91
|
+
const diagonalAlignmentList = diagonalDirectionsList.map((direction) =>
|
92
|
+
getAlignment(direction, DIAGONAL_DEVIATION_COSINE)
|
93
|
+
);
|
94
|
+
|
95
|
+
const isAligned =
|
96
|
+
axialAlignmentList.some(Boolean) || diagonalAlignmentList.some(Boolean);
|
97
|
+
|
98
|
+
const isFast = velocityVector.magnitude > this.minVelocity;
|
99
|
+
|
100
|
+
if (
|
101
|
+
this.maxNumberOfPointersSimultaneously ===
|
102
|
+
this.numberOfPointersRequired &&
|
103
|
+
isAligned &&
|
104
|
+
isFast
|
105
|
+
) {
|
106
|
+
clearTimeout(this.delayTimeout);
|
107
|
+
this.activate();
|
108
|
+
|
109
|
+
return true;
|
110
|
+
}
|
111
|
+
|
112
|
+
return false;
|
113
|
+
}
|
114
|
+
|
115
|
+
private endFling() {
|
116
|
+
this.logger.info("endFling")
|
117
|
+
if (!this.tryEndFling()) {
|
118
|
+
this.fail();
|
119
|
+
}
|
120
|
+
}
|
121
|
+
|
122
|
+
public onPointerDown(event: IncomingEvent): void {
|
123
|
+
this.tracker.addToTracker(event);
|
124
|
+
this.keyPointer = event.pointerId;
|
125
|
+
|
126
|
+
super.onPointerDown(event);
|
127
|
+
this.newPointerAction();
|
128
|
+
}
|
129
|
+
|
130
|
+
public onAdditionalPointerAdd(event: IncomingEvent): void {
|
131
|
+
this.tracker.addToTracker(event);
|
132
|
+
super.onAdditionalPointerAdd(event);
|
133
|
+
this.newPointerAction();
|
134
|
+
}
|
135
|
+
|
136
|
+
private newPointerAction(): void {
|
137
|
+
if (this.currentState === State.UNDETERMINED) {
|
138
|
+
this.startFling();
|
139
|
+
}
|
140
|
+
|
141
|
+
if (this.currentState !== State.BEGAN) {
|
142
|
+
return;
|
143
|
+
}
|
144
|
+
|
145
|
+
this.tryEndFling();
|
146
|
+
|
147
|
+
if (
|
148
|
+
this.tracker.getTrackedPointersCount() >
|
149
|
+
this.maxNumberOfPointersSimultaneously
|
150
|
+
) {
|
151
|
+
this.maxNumberOfPointersSimultaneously =
|
152
|
+
this.tracker.getTrackedPointersCount();
|
153
|
+
}
|
154
|
+
}
|
155
|
+
|
156
|
+
private pointerMoveAction(event: IncomingEvent): void {
|
157
|
+
this.logger.cloneWithPrefix("pointerMoveAction").info(JSON.stringify(event))
|
158
|
+
this.tracker.track(event);
|
159
|
+
|
160
|
+
if (this.currentState !== State.BEGAN) {
|
161
|
+
return;
|
162
|
+
}
|
163
|
+
|
164
|
+
this.tryEndFling();
|
165
|
+
}
|
166
|
+
|
167
|
+
public onPointerMove(event: IncomingEvent): void {
|
168
|
+
this.pointerMoveAction(event);
|
169
|
+
super.onPointerMove(event);
|
170
|
+
}
|
171
|
+
|
172
|
+
public onPointerOutOfBounds(event: IncomingEvent): void {
|
173
|
+
this.pointerMoveAction(event);
|
174
|
+
super.onPointerOutOfBounds(event);
|
175
|
+
}
|
176
|
+
|
177
|
+
public onPointerUp(event: IncomingEvent): void {
|
178
|
+
super.onPointerUp(event);
|
179
|
+
this.onUp(event);
|
180
|
+
|
181
|
+
this.keyPointer = NaN;
|
182
|
+
}
|
183
|
+
|
184
|
+
public onAdditionalPointerRemove(event: IncomingEvent): void {
|
185
|
+
super.onAdditionalPointerRemove(event);
|
186
|
+
this.onUp(event);
|
187
|
+
}
|
188
|
+
|
189
|
+
private onUp(event: IncomingEvent): void {
|
190
|
+
const logger = this.logger.cloneWithPrefix("onUp")
|
191
|
+
logger.info("start")
|
192
|
+
if (this.currentState === State.BEGAN) {
|
193
|
+
this.endFling();
|
194
|
+
}
|
195
|
+
logger.info(`removeFromTracker: pointerId=${event.pointerId}`)
|
196
|
+
this.tracker.removeFromTracker(event.pointerId);
|
197
|
+
}
|
198
|
+
|
199
|
+
public activate(): void {
|
200
|
+
super.activate();
|
201
|
+
this.end();
|
202
|
+
}
|
203
|
+
}
|
204
|
+
|
205
|
+
function coneToDeviation(degrees: number) {
|
206
|
+
return Math.cos(degToRad(degrees / 2));
|
207
|
+
}
|
208
|
+
|
209
|
+
function degToRad(degrees: number) {
|
210
|
+
return (degrees * Math.PI) / 180;
|
211
|
+
}
|
@@ -0,0 +1,64 @@
|
|
1
|
+
import {
|
2
|
+
RNGHLogger,
|
3
|
+
InteractionManager,
|
4
|
+
RNGHError,
|
5
|
+
PointerTracker,
|
6
|
+
GestureHandler,
|
7
|
+
GestureHandlerDependencies,
|
8
|
+
ScrollLocker,
|
9
|
+
GestureHandlerOrchestrator,
|
10
|
+
RNGestureResponder
|
11
|
+
} from "../core"
|
12
|
+
import { TapGestureHandler } from './TapGestureHandler';
|
13
|
+
import { PanGestureHandler } from "./PanGestureHandler"
|
14
|
+
import { PinchGestureHandler } from "./PinchGestureHandler"
|
15
|
+
import { NativeViewGestureHandler } from "./NativeViewGestureHandler"
|
16
|
+
import { ManualGestureHandler } from './ManualGestureHandler';
|
17
|
+
import { LongPressGestureHandler } from "./LongPressGestureHandler"
|
18
|
+
import { FlingGestureHandler } from "./FlingGestureHandler"
|
19
|
+
import { RotationGestureHandler } from "./RotationGestureHandler"
|
20
|
+
|
21
|
+
export class GestureHandlerFactory {
|
22
|
+
private orchestrator: GestureHandlerOrchestrator
|
23
|
+
private logger: RNGHLogger
|
24
|
+
|
25
|
+
constructor(private cleanLogger: RNGHLogger, private scrollLocker: ScrollLocker, private interactionManager: InteractionManager, private rnGestureResponder: RNGestureResponder) {
|
26
|
+
this.logger = cleanLogger.cloneWithPrefix("Factory")
|
27
|
+
this.orchestrator = new GestureHandlerOrchestrator(cleanLogger.cloneWithPrefix("Orchestrator"))
|
28
|
+
}
|
29
|
+
|
30
|
+
create(handlerName: string, handlerTag: number): GestureHandler {
|
31
|
+
this.logger.info(`create ${handlerName} with handlerTag: ${handlerTag}`)
|
32
|
+
const deps: GestureHandlerDependencies = {
|
33
|
+
tracker: new PointerTracker(),
|
34
|
+
orchestrator: this.orchestrator,
|
35
|
+
handlerTag,
|
36
|
+
interactionManager: this.interactionManager,
|
37
|
+
logger: this.cleanLogger.cloneWithPrefix("GestureHandler"),
|
38
|
+
scrollLocker: this.scrollLocker,
|
39
|
+
rnGestureResponder: this.rnGestureResponder,
|
40
|
+
}
|
41
|
+
switch (handlerName) {
|
42
|
+
case "TapGestureHandler":
|
43
|
+
return new TapGestureHandler(deps)
|
44
|
+
case "PanGestureHandler":
|
45
|
+
return new PanGestureHandler(deps)
|
46
|
+
case "PinchGestureHandler":
|
47
|
+
return new PinchGestureHandler(deps)
|
48
|
+
case "NativeViewGestureHandler":
|
49
|
+
return new NativeViewGestureHandler(deps)
|
50
|
+
case "ManualGestureHandler":
|
51
|
+
return new ManualGestureHandler(deps)
|
52
|
+
case "LongPressGestureHandler":
|
53
|
+
return new LongPressGestureHandler(deps)
|
54
|
+
case "FlingGestureHandler":
|
55
|
+
return new FlingGestureHandler(deps)
|
56
|
+
case "RotationGestureHandler":
|
57
|
+
return new RotationGestureHandler(deps)
|
58
|
+
default:
|
59
|
+
const msg = `Unknown handler type: ${handlerName}`
|
60
|
+
this.logger.info(msg)
|
61
|
+
throw new RNGHError(msg)
|
62
|
+
}
|
63
|
+
}
|
64
|
+
}
|
@@ -0,0 +1,127 @@
|
|
1
|
+
import { GestureHandler, IncomingEvent, GestureConfig, State, GestureHandlerDependencies } from '../core';
|
2
|
+
|
3
|
+
const DEFAULT_MIN_DURATION_MS = 500;
|
4
|
+
const DEFAULT_MAX_DIST_DP = 10;
|
5
|
+
const SCALING_FACTOR = 10;
|
6
|
+
|
7
|
+
export class LongPressGestureHandler extends GestureHandler {
|
8
|
+
private minDurationMs = DEFAULT_MIN_DURATION_MS;
|
9
|
+
private defaultMaxDistSq = DEFAULT_MAX_DIST_DP * SCALING_FACTOR;
|
10
|
+
|
11
|
+
private maxDistSq = this.defaultMaxDistSq;
|
12
|
+
private startX = 0;
|
13
|
+
private startY = 0;
|
14
|
+
|
15
|
+
private startTime = 0;
|
16
|
+
private previousTime = 0;
|
17
|
+
|
18
|
+
private activationTimeout: number | undefined;
|
19
|
+
|
20
|
+
constructor(deps: GestureHandlerDependencies) {
|
21
|
+
super({...deps, logger: deps.logger.cloneWithPrefix("LongPressGestureHandler")})
|
22
|
+
}
|
23
|
+
|
24
|
+
public getDefaultConfig() {
|
25
|
+
return {}
|
26
|
+
}
|
27
|
+
|
28
|
+
protected transformNativeEvent() {
|
29
|
+
return {
|
30
|
+
...super.transformNativeEvent(),
|
31
|
+
duration: Date.now() - this.startTime,
|
32
|
+
};
|
33
|
+
}
|
34
|
+
|
35
|
+
public updateGestureConfig({ enabled = true, ...props }: GestureConfig): void {
|
36
|
+
super.updateGestureConfig({ enabled: enabled, ...props });
|
37
|
+
|
38
|
+
if (this.config.minDurationMs !== undefined) {
|
39
|
+
this.minDurationMs = this.config.minDurationMs;
|
40
|
+
}
|
41
|
+
|
42
|
+
if (this.config.maxDist !== undefined) {
|
43
|
+
this.maxDistSq = this.config.maxDist * this.config.maxDist;
|
44
|
+
}
|
45
|
+
}
|
46
|
+
|
47
|
+
|
48
|
+
|
49
|
+
protected resetConfig(): void {
|
50
|
+
super.resetConfig();
|
51
|
+
this.minDurationMs = DEFAULT_MIN_DURATION_MS;
|
52
|
+
this.maxDistSq = this.defaultMaxDistSq;
|
53
|
+
}
|
54
|
+
|
55
|
+
protected onStateChange(newState: State, oldState: State): void {
|
56
|
+
super.onStateChange(newState, oldState)
|
57
|
+
clearTimeout(this.activationTimeout);
|
58
|
+
}
|
59
|
+
|
60
|
+
public onPointerDown(event: IncomingEvent): void {
|
61
|
+
this.tracker.addToTracker(event);
|
62
|
+
super.onPointerDown(event);
|
63
|
+
this.tryBegin(event);
|
64
|
+
this.tryActivate();
|
65
|
+
this.checkDistanceFail(event);
|
66
|
+
}
|
67
|
+
|
68
|
+
public onPointerMove(event: IncomingEvent): void {
|
69
|
+
super.onPointerMove(event);
|
70
|
+
this.tracker.track(event);
|
71
|
+
this.checkDistanceFail(event);
|
72
|
+
}
|
73
|
+
|
74
|
+
public onPointerUp(event: IncomingEvent): void {
|
75
|
+
super.onPointerUp(event);
|
76
|
+
this.tracker.removeFromTracker(event.pointerId);
|
77
|
+
|
78
|
+
if (this.currentState === State.ACTIVE) {
|
79
|
+
this.end();
|
80
|
+
} else {
|
81
|
+
this.fail();
|
82
|
+
}
|
83
|
+
}
|
84
|
+
|
85
|
+
private tryBegin(event: IncomingEvent): void {
|
86
|
+
if (this.currentState !== State.UNDETERMINED) {
|
87
|
+
return;
|
88
|
+
}
|
89
|
+
|
90
|
+
this.previousTime = Date.now();
|
91
|
+
this.startTime = this.previousTime;
|
92
|
+
|
93
|
+
this.begin();
|
94
|
+
|
95
|
+
this.startX = event.x;
|
96
|
+
this.startY = event.y;
|
97
|
+
}
|
98
|
+
|
99
|
+
private tryActivate(): void {
|
100
|
+
if (this.minDurationMs > 0) {
|
101
|
+
if (this.activationTimeout) {
|
102
|
+
clearTimeout(this.activationTimeout)
|
103
|
+
}
|
104
|
+
this.activationTimeout = setTimeout(() => {
|
105
|
+
this.activate();
|
106
|
+
}, this.minDurationMs);
|
107
|
+
} else if (this.minDurationMs === 0) {
|
108
|
+
this.activate();
|
109
|
+
}
|
110
|
+
}
|
111
|
+
|
112
|
+
private checkDistanceFail(event: IncomingEvent): void {
|
113
|
+
const dx = event.x - this.startX;
|
114
|
+
const dy = event.y - this.startY;
|
115
|
+
const distSq = dx * dx + dy * dy;
|
116
|
+
|
117
|
+
if (distSq <= this.maxDistSq) {
|
118
|
+
return;
|
119
|
+
}
|
120
|
+
|
121
|
+
if (this.currentState === State.ACTIVE) {
|
122
|
+
this.cancel();
|
123
|
+
} else {
|
124
|
+
this.fail();
|
125
|
+
}
|
126
|
+
}
|
127
|
+
}
|