feat(smart-app): implement complete mobile app MVP

- App.tsx: full navigation (Auth stack + Main tabs with 5 screens)
- Auth: LoginScreen, RegisterScreen, ForgotPasswordScreen
- HomeScreen: dashboard with IoT metrics, weather widget, alerts, quick actions, sensors
- MapScreen: interactive map with layer toggles (6 layers)
- MarketplaceScreen: categories (6), products (5), search
- ChatScreen: AI chat with quick prompts (4), bot responses
- ProfileScreen: user info, stats, menu (9 items), logout
- AlertsScreen: alert list with severity, acknowledge
- SensorsScreen: sensor list with type filters (6 types), search
- ZonesScreen: zone cards with stats
- SettingsScreen: language picker (FR/EN/ES/DE), privacy, about
- Stores: iotStore (sensors, zones, alerts), notificationStore, uiStore + i18n
- Hooks: useSensors, useAlerts, useNotifications, useLocation
- Components: Card, Button, LoadingSpinner, ErrorBoundary, Header
- Services: iotService, notificationService (with axios API client)
- Utils: formatters (temp, AQI, noise, dates), validators (email, password, IBAN)
- Theme: colors.ts with full design system (Blue Ocean palette)
- Ditto: fixed MongoDB connection, new JWT secrets, official gateway image
This commit is contained in:
Eric FELIXINE
2026-06-01 18:00:35 -04:00
parent 08ca495bde
commit e30ae8ed09
35578 changed files with 3703534 additions and 43 deletions

View File

@@ -0,0 +1,39 @@
// Gesture Handlers
import PanGestureHandler from './handlers/PanGestureHandler';
import TapGestureHandler from './handlers/TapGestureHandler';
import LongPressGestureHandler from './handlers/LongPressGestureHandler';
import PinchGestureHandler from './handlers/PinchGestureHandler';
import RotationGestureHandler from './handlers/RotationGestureHandler';
import FlingGestureHandler from './handlers/FlingGestureHandler';
import NativeViewGestureHandler from './handlers/NativeViewGestureHandler';
import ManualGestureHandler from './handlers/ManualGestureHandler';
import HoverGestureHandler from './handlers/HoverGestureHandler'; //Hammer Handlers
import HammerNativeViewGestureHandler from '../web_hammer/NativeViewGestureHandler';
import HammerPanGestureHandler from '../web_hammer/PanGestureHandler';
import HammerTapGestureHandler from '../web_hammer/TapGestureHandler';
import HammerLongPressGestureHandler from '../web_hammer/LongPressGestureHandler';
import HammerPinchGestureHandler from '../web_hammer/PinchGestureHandler';
import HammerRotationGestureHandler from '../web_hammer/RotationGestureHandler';
import HammerFlingGestureHandler from '../web_hammer/FlingGestureHandler';
export const Gestures = {
NativeViewGestureHandler,
PanGestureHandler,
TapGestureHandler,
LongPressGestureHandler,
PinchGestureHandler,
RotationGestureHandler,
FlingGestureHandler,
ManualGestureHandler,
HoverGestureHandler
};
export const HammerGestures = {
NativeViewGestureHandler: HammerNativeViewGestureHandler,
PanGestureHandler: HammerPanGestureHandler,
TapGestureHandler: HammerTapGestureHandler,
LongPressGestureHandler: HammerLongPressGestureHandler,
PinchGestureHandler: HammerPinchGestureHandler,
RotationGestureHandler: HammerRotationGestureHandler,
FlingGestureHandler: HammerFlingGestureHandler
};
//# sourceMappingURL=Gestures.js.map

View File

@@ -0,0 +1 @@
{"version":3,"sources":["Gestures.ts"],"names":["PanGestureHandler","TapGestureHandler","LongPressGestureHandler","PinchGestureHandler","RotationGestureHandler","FlingGestureHandler","NativeViewGestureHandler","ManualGestureHandler","HoverGestureHandler","HammerNativeViewGestureHandler","HammerPanGestureHandler","HammerTapGestureHandler","HammerLongPressGestureHandler","HammerPinchGestureHandler","HammerRotationGestureHandler","HammerFlingGestureHandler","Gestures","HammerGestures"],"mappings":"AAAA;AACA,OAAOA,iBAAP,MAA8B,8BAA9B;AACA,OAAOC,iBAAP,MAA8B,8BAA9B;AACA,OAAOC,uBAAP,MAAoC,oCAApC;AACA,OAAOC,mBAAP,MAAgC,gCAAhC;AACA,OAAOC,sBAAP,MAAmC,mCAAnC;AACA,OAAOC,mBAAP,MAAgC,gCAAhC;AACA,OAAOC,wBAAP,MAAqC,qCAArC;AACA,OAAOC,oBAAP,MAAiC,iCAAjC;AACA,OAAOC,mBAAP,MAAgC,gCAAhC,C,CAEA;;AACA,OAAOC,8BAAP,MAA2C,wCAA3C;AACA,OAAOC,uBAAP,MAAoC,iCAApC;AACA,OAAOC,uBAAP,MAAoC,iCAApC;AACA,OAAOC,6BAAP,MAA0C,uCAA1C;AACA,OAAOC,yBAAP,MAAsC,mCAAtC;AACA,OAAOC,4BAAP,MAAyC,sCAAzC;AACA,OAAOC,yBAAP,MAAsC,mCAAtC;AAEA,OAAO,MAAMC,QAAQ,GAAG;AACtBV,EAAAA,wBADsB;AAEtBN,EAAAA,iBAFsB;AAGtBC,EAAAA,iBAHsB;AAItBC,EAAAA,uBAJsB;AAKtBC,EAAAA,mBALsB;AAMtBC,EAAAA,sBANsB;AAOtBC,EAAAA,mBAPsB;AAQtBE,EAAAA,oBARsB;AAStBC,EAAAA;AATsB,CAAjB;AAYP,OAAO,MAAMS,cAAc,GAAG;AAC5BX,EAAAA,wBAAwB,EAAEG,8BADE;AAE5BT,EAAAA,iBAAiB,EAAEU,uBAFS;AAG5BT,EAAAA,iBAAiB,EAAEU,uBAHS;AAI5BT,EAAAA,uBAAuB,EAAEU,6BAJG;AAK5BT,EAAAA,mBAAmB,EAAEU,yBALO;AAM5BT,EAAAA,sBAAsB,EAAEU,4BANI;AAO5BT,EAAAA,mBAAmB,EAAEU;AAPO,CAAvB","sourcesContent":["// Gesture Handlers\nimport PanGestureHandler from './handlers/PanGestureHandler';\nimport TapGestureHandler from './handlers/TapGestureHandler';\nimport LongPressGestureHandler from './handlers/LongPressGestureHandler';\nimport PinchGestureHandler from './handlers/PinchGestureHandler';\nimport RotationGestureHandler from './handlers/RotationGestureHandler';\nimport FlingGestureHandler from './handlers/FlingGestureHandler';\nimport NativeViewGestureHandler from './handlers/NativeViewGestureHandler';\nimport ManualGestureHandler from './handlers/ManualGestureHandler';\nimport HoverGestureHandler from './handlers/HoverGestureHandler';\n\n//Hammer Handlers\nimport HammerNativeViewGestureHandler from '../web_hammer/NativeViewGestureHandler';\nimport HammerPanGestureHandler from '../web_hammer/PanGestureHandler';\nimport HammerTapGestureHandler from '../web_hammer/TapGestureHandler';\nimport HammerLongPressGestureHandler from '../web_hammer/LongPressGestureHandler';\nimport HammerPinchGestureHandler from '../web_hammer/PinchGestureHandler';\nimport HammerRotationGestureHandler from '../web_hammer/RotationGestureHandler';\nimport HammerFlingGestureHandler from '../web_hammer/FlingGestureHandler';\n\nexport const Gestures = {\n NativeViewGestureHandler,\n PanGestureHandler,\n TapGestureHandler,\n LongPressGestureHandler,\n PinchGestureHandler,\n RotationGestureHandler,\n FlingGestureHandler,\n ManualGestureHandler,\n HoverGestureHandler,\n};\n\nexport const HammerGestures = {\n NativeViewGestureHandler: HammerNativeViewGestureHandler,\n PanGestureHandler: HammerPanGestureHandler,\n TapGestureHandler: HammerTapGestureHandler,\n LongPressGestureHandler: HammerLongPressGestureHandler,\n PinchGestureHandler: HammerPinchGestureHandler,\n RotationGestureHandler: HammerRotationGestureHandler,\n FlingGestureHandler: HammerFlingGestureHandler,\n};\n"]}

View File

@@ -0,0 +1,3 @@
export const DEFAULT_TOUCH_SLOP = 15;
export const MINIMAL_FLING_VELOCITY = 0.1;
//# sourceMappingURL=constants.js.map

View File

@@ -0,0 +1 @@
{"version":3,"sources":["constants.ts"],"names":["DEFAULT_TOUCH_SLOP","MINIMAL_FLING_VELOCITY"],"mappings":"AAAA,OAAO,MAAMA,kBAAkB,GAAG,EAA3B;AACP,OAAO,MAAMC,sBAAsB,GAAG,GAA/B","sourcesContent":["export const DEFAULT_TOUCH_SLOP = 15;\nexport const MINIMAL_FLING_VELOCITY = 0.1;\n"]}

View File

@@ -0,0 +1,155 @@
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
import { EventTypes } from '../interfaces';
export default class RotationGestureDetector {
constructor(callbacks) {
_defineProperty(this, "onRotationBegin", void 0);
_defineProperty(this, "onRotation", void 0);
_defineProperty(this, "onRotationEnd", void 0);
_defineProperty(this, "currentTime", 0);
_defineProperty(this, "previousTime", 0);
_defineProperty(this, "previousAngle", 0);
_defineProperty(this, "rotation", 0);
_defineProperty(this, "anchorX", 0);
_defineProperty(this, "anchorY", 0);
_defineProperty(this, "isInProgress", false);
_defineProperty(this, "keyPointers", [NaN, NaN]);
this.onRotationBegin = callbacks.onRotationBegin;
this.onRotation = callbacks.onRotation;
this.onRotationEnd = callbacks.onRotationEnd;
}
updateCurrent(event, tracker) {
this.previousTime = this.currentTime;
this.currentTime = event.time;
const [firstPointerID, secondPointerID] = this.keyPointers;
const firstPointerX = tracker.getLastX(firstPointerID);
const firstPointerY = tracker.getLastY(firstPointerID);
const secondPointerX = tracker.getLastX(secondPointerID);
const secondPointerY = tracker.getLastY(secondPointerID);
const vectorX = secondPointerX - firstPointerX;
const vectorY = secondPointerY - firstPointerY;
this.anchorX = (firstPointerX + secondPointerX) / 2;
this.anchorY = (firstPointerY + secondPointerY) / 2; //Angle diff should be positive when rotating in clockwise direction
const angle = -Math.atan2(vectorY, vectorX);
this.rotation = Number.isNaN(this.previousAngle) ? 0 : this.previousAngle - angle;
this.previousAngle = angle;
if (this.rotation > Math.PI) {
this.rotation -= Math.PI;
} else if (this.rotation < -Math.PI) {
this.rotation += Math.PI;
}
if (this.rotation > Math.PI / 2) {
this.rotation -= Math.PI;
} else if (this.rotation < -Math.PI / 2) {
this.rotation += Math.PI;
}
}
finish() {
if (!this.isInProgress) {
return;
}
this.isInProgress = false;
this.keyPointers = [NaN, NaN];
this.onRotationEnd(this);
}
setKeyPointers(tracker) {
if (this.keyPointers[0] && this.keyPointers[1]) {
return;
}
const pointerIDs = tracker.getData().keys();
this.keyPointers[0] = pointerIDs.next().value;
this.keyPointers[1] = pointerIDs.next().value;
}
onTouchEvent(event, tracker) {
switch (event.eventType) {
case EventTypes.DOWN:
this.isInProgress = false;
break;
case EventTypes.ADDITIONAL_POINTER_DOWN:
if (this.isInProgress) {
break;
}
this.isInProgress = true;
this.previousTime = event.time;
this.previousAngle = NaN;
this.setKeyPointers(tracker);
this.updateCurrent(event, tracker);
this.onRotationBegin(this);
break;
case EventTypes.MOVE:
if (!this.isInProgress) {
break;
}
this.updateCurrent(event, tracker);
this.onRotation(this);
break;
case EventTypes.ADDITIONAL_POINTER_UP:
if (!this.isInProgress) {
break;
}
if (this.keyPointers.indexOf(event.pointerId) >= 0) {
this.finish();
}
break;
case EventTypes.UP:
if (this.isInProgress) {
this.finish();
}
break;
}
return true;
}
getTimeDelta() {
return this.currentTime + this.previousTime;
}
getAnchorX() {
return this.anchorX;
}
getAnchorY() {
return this.anchorY;
}
getRotation() {
return this.rotation;
}
reset() {
this.keyPointers = [NaN, NaN];
this.isInProgress = false;
}
}
//# sourceMappingURL=RotationGestureDetector.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,145 @@
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
import { DEFAULT_TOUCH_SLOP } from '../constants';
import { EventTypes } from '../interfaces';
export default class ScaleGestureDetector {
constructor(callbacks) {
_defineProperty(this, "onScaleBegin", void 0);
_defineProperty(this, "onScale", void 0);
_defineProperty(this, "onScaleEnd", void 0);
_defineProperty(this, "focusX", void 0);
_defineProperty(this, "focusY", void 0);
_defineProperty(this, "currentSpan", void 0);
_defineProperty(this, "prevSpan", void 0);
_defineProperty(this, "initialSpan", void 0);
_defineProperty(this, "currentTime", void 0);
_defineProperty(this, "prevTime", void 0);
_defineProperty(this, "inProgress", false);
_defineProperty(this, "spanSlop", void 0);
_defineProperty(this, "minSpan", void 0);
this.onScaleBegin = callbacks.onScaleBegin;
this.onScale = callbacks.onScale;
this.onScaleEnd = callbacks.onScaleEnd;
this.spanSlop = DEFAULT_TOUCH_SLOP * 2;
this.minSpan = 0;
}
onTouchEvent(event, tracker) {
this.currentTime = event.time;
const action = event.eventType;
const numOfPointers = tracker.getTrackedPointersCount();
const streamComplete = action === EventTypes.UP || action === EventTypes.ADDITIONAL_POINTER_UP || action === EventTypes.CANCEL;
if (action === EventTypes.DOWN || streamComplete) {
if (this.inProgress) {
this.onScaleEnd(this);
this.inProgress = false;
this.initialSpan = 0;
}
if (streamComplete) {
return true;
}
}
const configChanged = action === EventTypes.DOWN || action === EventTypes.ADDITIONAL_POINTER_UP || action === EventTypes.ADDITIONAL_POINTER_DOWN;
const pointerUp = action === EventTypes.ADDITIONAL_POINTER_UP;
const ignoredPointer = pointerUp ? event.pointerId : undefined; //Determine focal point
const div = pointerUp ? numOfPointers - 1 : numOfPointers;
const sumX = tracker.getSumX(ignoredPointer);
const sumY = tracker.getSumY(ignoredPointer);
const focusX = sumX / div;
const focusY = sumY / div; //Determine average deviation from focal point
let devSumX = 0;
let devSumY = 0;
tracker.getData().forEach((value, key) => {
if (key === ignoredPointer) {
return;
}
devSumX += Math.abs(value.lastX - focusX);
devSumY += Math.abs(value.lastY - focusY);
});
const devX = devSumX / div;
const devY = devSumY / div;
const spanX = devX * 2;
const spanY = devY * 2;
const span = Math.hypot(spanX, spanY); //Begin/end events
const wasInProgress = this.inProgress;
this.focusX = focusX;
this.focusY = focusY;
if (this.inProgress && (span < this.minSpan || configChanged)) {
this.onScaleEnd(this);
this.inProgress = false;
this.initialSpan = span;
}
if (configChanged) {
this.initialSpan = this.prevSpan = this.currentSpan = span;
}
if (!this.inProgress && span >= this.minSpan && (wasInProgress || Math.abs(span - this.initialSpan) > this.spanSlop)) {
this.prevSpan = this.currentSpan = span;
this.prevTime = this.currentTime;
this.inProgress = this.onScaleBegin(this);
} //Handle motion
if (action !== EventTypes.MOVE) {
return true;
}
this.currentSpan = span;
if (this.inProgress && !this.onScale(this)) {
return true;
}
this.prevSpan = this.currentSpan;
this.prevTime = this.currentTime;
return true;
}
getCurrentSpan() {
return this.currentSpan;
}
getFocusX() {
return this.focusX;
}
getFocusY() {
return this.focusY;
}
getTimeDelta() {
return this.currentTime - this.prevTime;
}
getScaleFactor(numOfPointers) {
if (numOfPointers < 2) {
return 1;
}
return this.prevSpan > 0 ? this.currentSpan / this.prevSpan : 1;
}
}
//# sourceMappingURL=ScaleGestureDetector.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,176 @@
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
import { State } from '../../State';
import { DiagonalDirections, Directions } from '../../Directions';
import GestureHandler from './GestureHandler';
import Vector from '../tools/Vector';
import { coneToDeviation } from '../utils';
const DEFAULT_MAX_DURATION_MS = 800;
const DEFAULT_MIN_VELOCITY = 700;
const DEFAULT_ALIGNMENT_CONE = 30;
const DEFAULT_DIRECTION = Directions.RIGHT;
const DEFAULT_NUMBER_OF_TOUCHES_REQUIRED = 1;
const AXIAL_DEVIATION_COSINE = coneToDeviation(DEFAULT_ALIGNMENT_CONE);
const DIAGONAL_DEVIATION_COSINE = coneToDeviation(90 - DEFAULT_ALIGNMENT_CONE);
export default class FlingGestureHandler extends GestureHandler {
constructor(...args) {
super(...args);
_defineProperty(this, "numberOfPointersRequired", DEFAULT_NUMBER_OF_TOUCHES_REQUIRED);
_defineProperty(this, "direction", DEFAULT_DIRECTION);
_defineProperty(this, "maxDurationMs", DEFAULT_MAX_DURATION_MS);
_defineProperty(this, "minVelocity", DEFAULT_MIN_VELOCITY);
_defineProperty(this, "delayTimeout", void 0);
_defineProperty(this, "maxNumberOfPointersSimultaneously", 0);
_defineProperty(this, "keyPointer", NaN);
}
init(ref, propsRef) {
super.init(ref, propsRef);
}
updateGestureConfig({
enabled = true,
...props
}) {
super.updateGestureConfig({
enabled: enabled,
...props
});
if (this.config.direction) {
this.direction = this.config.direction;
}
if (this.config.numberOfPointers) {
this.numberOfPointersRequired = this.config.numberOfPointers;
}
}
startFling() {
this.begin();
this.maxNumberOfPointersSimultaneously = 1;
this.delayTimeout = setTimeout(() => this.fail(), this.maxDurationMs);
}
tryEndFling() {
const velocityVector = Vector.fromVelocity(this.tracker, this.keyPointer);
const getAlignment = (direction, minimalAlignmentCosine) => {
return (direction & this.direction) === direction && velocityVector.isSimilar(Vector.fromDirection(direction), minimalAlignmentCosine);
};
const axialDirectionsList = Object.values(Directions);
const diagonalDirectionsList = Object.values(DiagonalDirections); // list of alignments to all activated directions
const axialAlignmentList = axialDirectionsList.map(direction => getAlignment(direction, AXIAL_DEVIATION_COSINE));
const diagonalAlignmentList = diagonalDirectionsList.map(direction => getAlignment(direction, DIAGONAL_DEVIATION_COSINE));
const isAligned = axialAlignmentList.some(Boolean) || diagonalAlignmentList.some(Boolean);
const isFast = velocityVector.magnitude > this.minVelocity;
if (this.maxNumberOfPointersSimultaneously === this.numberOfPointersRequired && isAligned && isFast) {
clearTimeout(this.delayTimeout);
this.activate();
return true;
}
return false;
}
endFling() {
if (!this.tryEndFling()) {
this.fail();
}
}
onPointerDown(event) {
if (!this.isButtonInConfig(event.button)) {
return;
}
this.tracker.addToTracker(event);
this.keyPointer = event.pointerId;
super.onPointerDown(event);
this.newPointerAction();
}
onPointerAdd(event) {
this.tracker.addToTracker(event);
super.onPointerAdd(event);
this.newPointerAction();
}
newPointerAction() {
if (this.currentState === State.UNDETERMINED) {
this.startFling();
}
if (this.currentState !== State.BEGAN) {
return;
}
this.tryEndFling();
if (this.tracker.getTrackedPointersCount() > this.maxNumberOfPointersSimultaneously) {
this.maxNumberOfPointersSimultaneously = this.tracker.getTrackedPointersCount();
}
}
pointerMoveAction(event) {
this.tracker.track(event);
if (this.currentState !== State.BEGAN) {
return;
}
this.tryEndFling();
}
onPointerMove(event) {
this.pointerMoveAction(event);
super.onPointerMove(event);
}
onPointerOutOfBounds(event) {
this.pointerMoveAction(event);
super.onPointerOutOfBounds(event);
}
onPointerUp(event) {
super.onPointerUp(event);
this.onUp(event);
this.keyPointer = NaN;
}
onPointerRemove(event) {
super.onPointerRemove(event);
this.onUp(event);
}
onUp(event) {
if (this.currentState === State.BEGAN) {
this.endFling();
}
this.tracker.removeFromTracker(event.pointerId);
}
activate(force) {
super.activate(force);
this.end();
}
resetConfig() {
super.resetConfig();
this.numberOfPointersRequired = DEFAULT_NUMBER_OF_TOUCHES_REQUIRED;
this.direction = DEFAULT_DIRECTION;
}
}
//# sourceMappingURL=FlingGestureHandler.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,791 @@
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
/* eslint-disable @typescript-eslint/no-empty-function */
import { State } from '../../State';
import { TouchEventType, EventTypes } from '../interfaces';
import GestureHandlerOrchestrator from '../tools/GestureHandlerOrchestrator';
import InteractionManager from '../tools/InteractionManager';
import PointerTracker from '../tools/PointerTracker';
import { MouseButton } from '../../handlers/gestureHandlerCommon';
import { PointerType } from '../../PointerType';
export default class GestureHandler {
// Orchestrator properties
constructor(delegate) {
_defineProperty(this, "lastSentState", null);
_defineProperty(this, "currentState", State.UNDETERMINED);
_defineProperty(this, "shouldCancelWhenOutside", false);
_defineProperty(this, "hasCustomActivationCriteria", false);
_defineProperty(this, "enabled", false);
_defineProperty(this, "viewRef", void 0);
_defineProperty(this, "propsRef", void 0);
_defineProperty(this, "handlerTag", void 0);
_defineProperty(this, "config", {
enabled: false
});
_defineProperty(this, "tracker", new PointerTracker());
_defineProperty(this, "activationIndex", 0);
_defineProperty(this, "awaiting", false);
_defineProperty(this, "active", false);
_defineProperty(this, "shouldResetProgress", false);
_defineProperty(this, "pointerType", PointerType.MOUSE);
_defineProperty(this, "delegate", void 0);
_defineProperty(this, "sendEvent", (newState, oldState) => {
const {
onGestureHandlerEvent,
onGestureHandlerStateChange
} = this.propsRef.current;
const resultEvent = this.transformEventData(newState, oldState); // In the new API oldState field has to be undefined, unless we send event state changed
// Here the order is flipped to avoid workarounds such as making backup of the state and setting it to undefined first, then changing it back
// Flipping order with setting oldState to undefined solves issue, when events were being sent twice instead of once
// However, this may cause trouble in the future (but for now we don't know that)
if (this.lastSentState !== newState) {
this.lastSentState = newState;
invokeNullableMethod(onGestureHandlerStateChange, resultEvent);
}
if (this.currentState === State.ACTIVE) {
resultEvent.nativeEvent.oldState = undefined;
invokeNullableMethod(onGestureHandlerEvent, resultEvent);
}
});
this.delegate = delegate;
} //
// Initializing handler
//
init(viewRef, propsRef) {
this.propsRef = propsRef;
this.viewRef = viewRef;
this.currentState = State.UNDETERMINED;
this.delegate.init(viewRef, this);
}
attachEventManager(manager) {
manager.setOnPointerDown(this.onPointerDown.bind(this));
manager.setOnPointerAdd(this.onPointerAdd.bind(this));
manager.setOnPointerUp(this.onPointerUp.bind(this));
manager.setOnPointerRemove(this.onPointerRemove.bind(this));
manager.setOnPointerMove(this.onPointerMove.bind(this));
manager.setOnPointerEnter(this.onPointerEnter.bind(this));
manager.setOnPointerLeave(this.onPointerLeave.bind(this));
manager.setOnPointerCancel(this.onPointerCancel.bind(this));
manager.setOnPointerOutOfBounds(this.onPointerOutOfBounds.bind(this));
manager.setOnPointerMoveOver(this.onPointerMoveOver.bind(this));
manager.setOnPointerMoveOut(this.onPointerMoveOut.bind(this));
manager.registerListeners();
} //
// Resetting handler
//
onCancel() {}
onReset() {}
resetProgress() {}
reset() {
this.tracker.resetTracker();
this.onReset();
this.resetProgress();
this.delegate.reset();
this.currentState = State.UNDETERMINED;
} //
// State logic
//
moveToState(newState, sendIfDisabled) {
if (this.currentState === newState) {
return;
}
const oldState = this.currentState;
this.currentState = newState;
if (this.tracker.getTrackedPointersCount() > 0 && this.config.needsPointerData && this.isFinished()) {
this.cancelTouches();
}
GestureHandlerOrchestrator.getInstance().onHandlerStateChange(this, newState, oldState, sendIfDisabled);
this.onStateChange(newState, oldState);
if (!this.enabled && this.isFinished()) {
this.currentState = State.UNDETERMINED;
}
}
onStateChange(_newState, _oldState) {}
begin() {
if (!this.checkHitSlop()) {
return;
}
if (this.currentState === State.UNDETERMINED) {
this.moveToState(State.BEGAN);
}
}
/**
* @param {boolean} sendIfDisabled - Used when handler becomes disabled. With this flag orchestrator will be forced to send fail event
*/
fail(sendIfDisabled) {
if (this.currentState === State.ACTIVE || this.currentState === State.BEGAN) {
// Here the order of calling the delegate and moveToState is important.
// At this point we can use currentState as previuos state, because immediately after changing cursor we call moveToState method.
this.delegate.onFail();
this.moveToState(State.FAILED, sendIfDisabled);
}
this.resetProgress();
}
/**
* @param {boolean} sendIfDisabled - Used when handler becomes disabled. With this flag orchestrator will be forced to send cancel event
*/
cancel(sendIfDisabled) {
if (this.currentState === State.ACTIVE || this.currentState === State.UNDETERMINED || this.currentState === State.BEGAN) {
this.onCancel(); // Same as above - order matters
this.delegate.onCancel();
this.moveToState(State.CANCELLED, sendIfDisabled);
}
}
activate(force = false) {
if ((this.config.manualActivation !== true || force) && (this.currentState === State.UNDETERMINED || this.currentState === State.BEGAN)) {
this.delegate.onActivate();
this.moveToState(State.ACTIVE);
}
}
end() {
if (this.currentState === State.BEGAN || this.currentState === State.ACTIVE) {
// Same as above - order matters
this.delegate.onEnd();
this.moveToState(State.END);
}
this.resetProgress();
} //
// Methods for orchestrator
//
isAwaiting() {
return this.awaiting;
}
setAwaiting(value) {
this.awaiting = value;
}
isActive() {
return this.active;
}
setActive(value) {
this.active = value;
}
getShouldResetProgress() {
return this.shouldResetProgress;
}
setShouldResetProgress(value) {
this.shouldResetProgress = value;
}
getActivationIndex() {
return this.activationIndex;
}
setActivationIndex(value) {
this.activationIndex = value;
}
shouldWaitForHandlerFailure(handler) {
if (handler === this) {
return false;
}
return InteractionManager.getInstance().shouldWaitForHandlerFailure(this, handler);
}
shouldRequireToWaitForFailure(handler) {
if (handler === this) {
return false;
}
return InteractionManager.getInstance().shouldRequireHandlerToWaitForFailure(this, handler);
}
shouldRecognizeSimultaneously(handler) {
if (handler === this) {
return true;
}
return InteractionManager.getInstance().shouldRecognizeSimultaneously(this, handler);
}
shouldBeCancelledByOther(handler) {
if (handler === this) {
return false;
}
return InteractionManager.getInstance().shouldHandlerBeCancelledBy(this, handler);
} //
// Event actions
//
onPointerDown(event) {
GestureHandlerOrchestrator.getInstance().recordHandlerIfNotPresent(this);
this.pointerType = event.pointerType;
if (this.pointerType === PointerType.TOUCH) {
GestureHandlerOrchestrator.getInstance().cancelMouseAndPenGestures(this);
}
if (this.config.needsPointerData) {
this.sendTouchEvent(event);
}
} // Adding another pointer to existing ones
onPointerAdd(event) {
if (this.config.needsPointerData) {
this.sendTouchEvent(event);
}
}
onPointerUp(event) {
if (this.config.needsPointerData) {
this.sendTouchEvent(event);
}
} // Removing pointer, when there is more than one pointers
onPointerRemove(event) {
if (this.config.needsPointerData) {
this.sendTouchEvent(event);
}
}
onPointerMove(event) {
this.tryToSendMoveEvent(false);
if (this.config.needsPointerData) {
this.sendTouchEvent(event);
}
}
onPointerLeave(event) {
if (this.shouldCancelWhenOutside) {
switch (this.currentState) {
case State.ACTIVE:
this.cancel();
break;
case State.BEGAN:
this.fail();
break;
}
return;
}
if (this.config.needsPointerData) {
this.sendTouchEvent(event);
}
}
onPointerEnter(event) {
if (this.config.needsPointerData) {
this.sendTouchEvent(event);
}
}
onPointerCancel(event) {
if (this.config.needsPointerData) {
this.sendTouchEvent(event);
}
this.cancel();
this.reset();
}
onPointerOutOfBounds(event) {
this.tryToSendMoveEvent(true);
if (this.config.needsPointerData) {
this.sendTouchEvent(event);
}
}
onPointerMoveOver(_event) {// used only by hover gesture handler atm
}
onPointerMoveOut(_event) {// used only by hover gesture handler atm
}
tryToSendMoveEvent(out) {
if (this.enabled && this.active && (!out || out && !this.shouldCancelWhenOutside)) {
this.sendEvent(this.currentState, this.currentState);
}
}
sendTouchEvent(event) {
if (!this.enabled) {
return;
}
const {
onGestureHandlerEvent
} = this.propsRef.current;
const touchEvent = this.transformTouchEvent(event);
if (touchEvent) {
invokeNullableMethod(onGestureHandlerEvent, touchEvent);
}
} //
// Events Sending
//
transformEventData(newState, oldState) {
return {
nativeEvent: {
numberOfPointers: this.tracker.getTrackedPointersCount(),
state: newState,
pointerInside: this.delegate.isPointerInBounds({
x: this.tracker.getLastAvgX(),
y: this.tracker.getLastAvgY()
}),
...this.transformNativeEvent(),
handlerTag: this.handlerTag,
target: this.viewRef,
oldState: newState !== oldState ? oldState : undefined,
pointerType: this.pointerType
},
timeStamp: Date.now()
};
}
transformTouchEvent(event) {
var _event$touchEventType;
const rect = this.delegate.measureView();
const all = [];
const changed = [];
const trackerData = this.tracker.getData(); // This if handles edge case where all pointers have been cancelled
// When pointercancel is triggered, reset method is called. This means that tracker will be reset after first pointer being cancelled
// The problem is, that handler will receive another pointercancel event from the rest of the pointers
// To avoid crashing, we don't send event if tracker tracks no pointers, i.e. has been reset
if (trackerData.size === 0 || !trackerData.has(event.pointerId)) {
return;
}
trackerData.forEach((element, key) => {
const id = this.tracker.getMappedTouchEventId(key);
all.push({
id: id,
x: element.lastX - rect.pageX,
y: element.lastY - rect.pageY,
absoluteX: element.lastX,
absoluteY: element.lastY
});
}); // Each pointer sends its own event, so we want changed touches to contain only the pointer that has changed.
// However, if the event is cancel, we want to cancel all pointers to avoid crashes
if (event.eventType !== EventTypes.CANCEL) {
changed.push({
id: this.tracker.getMappedTouchEventId(event.pointerId),
x: event.x - rect.pageX,
y: event.y - rect.pageY,
absoluteX: event.x,
absoluteY: event.y
});
} else {
trackerData.forEach((element, key) => {
const id = this.tracker.getMappedTouchEventId(key);
changed.push({
id: id,
x: element.lastX - rect.pageX,
y: element.lastY - rect.pageY,
absoluteX: element.lastX,
absoluteY: element.lastY
});
});
}
let eventType = TouchEventType.UNDETERMINED;
switch (event.eventType) {
case EventTypes.DOWN:
case EventTypes.ADDITIONAL_POINTER_DOWN:
eventType = TouchEventType.DOWN;
break;
case EventTypes.UP:
case EventTypes.ADDITIONAL_POINTER_UP:
eventType = TouchEventType.UP;
break;
case EventTypes.MOVE:
eventType = TouchEventType.MOVE;
break;
case EventTypes.CANCEL:
eventType = TouchEventType.CANCELLED;
break;
} // Here, when we receive up event, we want to decrease number of touches
// That's because we want handler to send information that there's one pointer less
// However, we still want this pointer to be present in allTouches array, so that its data can be accessed
let numberOfTouches = all.length;
if (event.eventType === EventTypes.UP || event.eventType === EventTypes.ADDITIONAL_POINTER_UP) {
--numberOfTouches;
}
return {
nativeEvent: {
handlerTag: this.handlerTag,
state: this.currentState,
eventType: (_event$touchEventType = event.touchEventType) !== null && _event$touchEventType !== void 0 ? _event$touchEventType : eventType,
changedTouches: changed,
allTouches: all,
numberOfTouches: numberOfTouches
},
timeStamp: Date.now()
};
}
cancelTouches() {
const rect = this.delegate.measureView();
const all = [];
const changed = [];
const trackerData = this.tracker.getData();
if (trackerData.size === 0) {
return;
}
trackerData.forEach((element, key) => {
const id = this.tracker.getMappedTouchEventId(key);
all.push({
id: id,
x: element.lastX - rect.pageX,
y: element.lastY - rect.pageY,
absoluteX: element.lastX,
absoluteY: element.lastY
});
changed.push({
id: id,
x: element.lastX - rect.pageX,
y: element.lastY - rect.pageY,
absoluteX: element.lastX,
absoluteY: element.lastY
});
});
const cancelEvent = {
nativeEvent: {
handlerTag: this.handlerTag,
state: this.currentState,
eventType: TouchEventType.CANCELLED,
changedTouches: changed,
allTouches: all,
numberOfTouches: all.length
},
timeStamp: Date.now()
};
const {
onGestureHandlerEvent
} = this.propsRef.current;
invokeNullableMethod(onGestureHandlerEvent, cancelEvent);
}
transformNativeEvent() {
// those properties are shared by most handlers and if not this method will be overriden
const rect = this.delegate.measureView();
return {
x: this.tracker.getLastAvgX() - rect.pageX,
y: this.tracker.getLastAvgY() - rect.pageY,
absoluteX: this.tracker.getLastAvgX(),
absoluteY: this.tracker.getLastAvgY()
};
} //
// Handling config
//
updateGestureConfig({
enabled = true,
...props
}) {
this.config = {
enabled: enabled,
...props
};
this.enabled = enabled;
if (this.config.shouldCancelWhenOutside !== undefined) {
this.setShouldCancelWhenOutside(this.config.shouldCancelWhenOutside);
}
this.validateHitSlops();
if (this.enabled) {
return;
}
switch (this.currentState) {
case State.ACTIVE:
this.fail(true);
break;
case State.UNDETERMINED:
GestureHandlerOrchestrator.getInstance().removeHandlerFromOrchestrator(this);
break;
default:
this.cancel(true);
break;
}
}
checkCustomActivationCriteria(criterias) {
for (const key in this.config) {
if (criterias.indexOf(key) >= 0) {
this.hasCustomActivationCriteria = true;
}
}
}
validateHitSlops() {
if (!this.config.hitSlop) {
return;
}
if (this.config.hitSlop.left !== undefined && this.config.hitSlop.right !== undefined && this.config.hitSlop.width !== undefined) {
throw new Error('HitSlop Error: Cannot define left, right and width at the same time');
}
if (this.config.hitSlop.width !== undefined && this.config.hitSlop.left === undefined && this.config.hitSlop.right === undefined) {
throw new Error('HitSlop Error: When width is defined, either left or right has to be defined');
}
if (this.config.hitSlop.height !== undefined && this.config.hitSlop.top !== undefined && this.config.hitSlop.bottom !== undefined) {
throw new Error('HitSlop Error: Cannot define top, bottom and height at the same time');
}
if (this.config.hitSlop.height !== undefined && this.config.hitSlop.top === undefined && this.config.hitSlop.bottom === undefined) {
throw new Error('HitSlop Error: When height is defined, either top or bottom has to be defined');
}
}
checkHitSlop() {
if (!this.config.hitSlop) {
return true;
}
const {
width,
height
} = this.delegate.measureView();
let left = 0;
let top = 0;
let right = width;
let bottom = height;
if (this.config.hitSlop.horizontal !== undefined) {
left -= this.config.hitSlop.horizontal;
right += this.config.hitSlop.horizontal;
}
if (this.config.hitSlop.vertical !== undefined) {
top -= this.config.hitSlop.vertical;
bottom += this.config.hitSlop.vertical;
}
if (this.config.hitSlop.left !== undefined) {
left = -this.config.hitSlop.left;
}
if (this.config.hitSlop.right !== undefined) {
right = width + this.config.hitSlop.right;
}
if (this.config.hitSlop.top !== undefined) {
top = -this.config.hitSlop.top;
}
if (this.config.hitSlop.bottom !== undefined) {
bottom = width + this.config.hitSlop.bottom;
}
if (this.config.hitSlop.width !== undefined) {
if (this.config.hitSlop.left !== undefined) {
right = left + this.config.hitSlop.width;
} else if (this.config.hitSlop.right !== undefined) {
left = right - this.config.hitSlop.width;
}
}
if (this.config.hitSlop.height !== undefined) {
if (this.config.hitSlop.top !== undefined) {
bottom = top + this.config.hitSlop.height;
} else if (this.config.hitSlop.bottom !== undefined) {
top = bottom - this.config.hitSlop.height;
}
}
const rect = this.delegate.measureView();
const offsetX = this.tracker.getLastX() - rect.pageX;
const offsetY = this.tracker.getLastY() - rect.pageY;
if (offsetX >= left && offsetX <= right && offsetY >= top && offsetY <= bottom) {
return true;
}
return false;
}
isButtonInConfig(mouseButton) {
return !mouseButton || !this.config.mouseButton && mouseButton === MouseButton.LEFT || this.config.mouseButton && mouseButton & this.config.mouseButton;
}
resetConfig() {}
onDestroy() {
this.delegate.destroy(this.config);
} //
// Getters and setters
//
getTag() {
return this.handlerTag;
}
setTag(tag) {
this.handlerTag = tag;
}
getConfig() {
return this.config;
}
getDelegate() {
return this.delegate;
}
getTracker() {
return this.tracker;
}
getTrackedPointersID() {
return this.tracker.getTrackedPointersID();
}
getState() {
return this.currentState;
}
isEnabled() {
return this.enabled;
}
isFinished() {
return this.currentState === State.END || this.currentState === State.FAILED || this.currentState === State.CANCELLED;
}
setShouldCancelWhenOutside(shouldCancel) {
this.shouldCancelWhenOutside = shouldCancel;
}
getShouldCancelWhenOutside() {
return this.shouldCancelWhenOutside;
}
getPointerType() {
return this.pointerType;
}
}
function invokeNullableMethod(method, event) {
if (!method) {
return;
}
if (typeof method === 'function') {
method(event);
return;
}
if ('__getHandler' in method && typeof method.__getHandler === 'function') {
const handler = method.__getHandler();
invokeNullableMethod(handler, event);
return;
}
if (!('__nodeConfig' in method)) {
return;
}
const {
argMapping
} = method.__nodeConfig;
if (!Array.isArray(argMapping)) {
return;
}
for (const [index, [key, value]] of argMapping.entries()) {
if (!(key in event.nativeEvent)) {
continue;
} // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
const nativeValue = event.nativeEvent[key]; // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
if (value !== null && value !== void 0 && value.setValue) {
//Reanimated API
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call
value.setValue(nativeValue);
} else {
//RN Animated API
method.__nodeConfig.argMapping[index] = [key, nativeValue];
}
}
return;
}
//# sourceMappingURL=GestureHandler.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,47 @@
import { State } from '../../State';
import GestureHandlerOrchestrator from '../tools/GestureHandlerOrchestrator';
import GestureHandler from './GestureHandler';
export default class HoverGestureHandler extends GestureHandler {
init(ref, propsRef) {
super.init(ref, propsRef);
}
updateGestureConfig({
enabled = true,
...props
}) {
super.updateGestureConfig({
enabled: enabled,
...props
});
}
onPointerMoveOver(event) {
GestureHandlerOrchestrator.getInstance().recordHandlerIfNotPresent(this);
this.tracker.addToTracker(event);
super.onPointerMoveOver(event);
if (this.getState() === State.UNDETERMINED) {
this.begin();
this.activate();
}
}
onPointerMoveOut(event) {
this.tracker.addToTracker(event);
super.onPointerMoveOut(event);
this.end();
}
onPointerMove(event) {
this.tracker.track(event);
super.onPointerMove(event);
}
onPointerCancel(event) {
super.onPointerCancel(event);
this.reset();
}
}
//# sourceMappingURL=HoverGestureHandler.js.map

View File

@@ -0,0 +1 @@
{"version":3,"sources":["HoverGestureHandler.ts"],"names":["State","GestureHandlerOrchestrator","GestureHandler","HoverGestureHandler","init","ref","propsRef","updateGestureConfig","enabled","props","onPointerMoveOver","event","getInstance","recordHandlerIfNotPresent","tracker","addToTracker","getState","UNDETERMINED","begin","activate","onPointerMoveOut","end","onPointerMove","track","onPointerCancel","reset"],"mappings":"AAAA,SAASA,KAAT,QAAsB,aAAtB;AAEA,OAAOC,0BAAP,MAAuC,qCAAvC;AACA,OAAOC,cAAP,MAA2B,kBAA3B;AAEA,eAAe,MAAMC,mBAAN,SAAkCD,cAAlC,CAAiD;AACvDE,EAAAA,IAAI,CAACC,GAAD,EAAcC,QAAd,EAAkD;AAC3D,UAAMF,IAAN,CAAWC,GAAX,EAAgBC,QAAhB;AACD;;AAEMC,EAAAA,mBAAmB,CAAC;AAAEC,IAAAA,OAAO,GAAG,IAAZ;AAAkB,OAAGC;AAArB,GAAD,EAA6C;AACrE,UAAMF,mBAAN,CAA0B;AAAEC,MAAAA,OAAO,EAAEA,OAAX;AAAoB,SAAGC;AAAvB,KAA1B;AACD;;AAESC,EAAAA,iBAAiB,CAACC,KAAD,EAA4B;AACrDV,IAAAA,0BAA0B,CAACW,WAA3B,GAAyCC,yBAAzC,CAAmE,IAAnE;AAEA,SAAKC,OAAL,CAAaC,YAAb,CAA0BJ,KAA1B;AACA,UAAMD,iBAAN,CAAwBC,KAAxB;;AAEA,QAAI,KAAKK,QAAL,OAAoBhB,KAAK,CAACiB,YAA9B,EAA4C;AAC1C,WAAKC,KAAL;AACA,WAAKC,QAAL;AACD;AACF;;AAESC,EAAAA,gBAAgB,CAACT,KAAD,EAA4B;AACpD,SAAKG,OAAL,CAAaC,YAAb,CAA0BJ,KAA1B;AACA,UAAMS,gBAAN,CAAuBT,KAAvB;AAEA,SAAKU,GAAL;AACD;;AAESC,EAAAA,aAAa,CAACX,KAAD,EAA4B;AACjD,SAAKG,OAAL,CAAaS,KAAb,CAAmBZ,KAAnB;AACA,UAAMW,aAAN,CAAoBX,KAApB;AACD;;AAESa,EAAAA,eAAe,CAACb,KAAD,EAA4B;AACnD,UAAMa,eAAN,CAAsBb,KAAtB;AACA,SAAKc,KAAL;AACD;;AApC6D","sourcesContent":["import { State } from '../../State';\nimport { AdaptedEvent, Config } from '../interfaces';\nimport GestureHandlerOrchestrator from '../tools/GestureHandlerOrchestrator';\nimport GestureHandler from './GestureHandler';\n\nexport default class HoverGestureHandler extends GestureHandler {\n public init(ref: number, propsRef: React.RefObject<unknown>) {\n super.init(ref, propsRef);\n }\n\n public updateGestureConfig({ enabled = true, ...props }: Config): void {\n super.updateGestureConfig({ enabled: enabled, ...props });\n }\n\n protected onPointerMoveOver(event: AdaptedEvent): void {\n GestureHandlerOrchestrator.getInstance().recordHandlerIfNotPresent(this);\n\n this.tracker.addToTracker(event);\n super.onPointerMoveOver(event);\n\n if (this.getState() === State.UNDETERMINED) {\n this.begin();\n this.activate();\n }\n }\n\n protected onPointerMoveOut(event: AdaptedEvent): void {\n this.tracker.addToTracker(event);\n super.onPointerMoveOut(event);\n\n this.end();\n }\n\n protected onPointerMove(event: AdaptedEvent): void {\n this.tracker.track(event);\n super.onPointerMove(event);\n }\n\n protected onPointerCancel(event: AdaptedEvent): void {\n super.onPointerCancel(event);\n this.reset();\n }\n}\n"]}

View File

@@ -0,0 +1,2 @@
//# sourceMappingURL=IGestureHandler.js.map

View File

@@ -0,0 +1 @@
{"version":3,"sources":[],"names":[],"mappings":"","sourcesContent":[]}

View File

@@ -0,0 +1,139 @@
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
import { State } from '../../State';
import GestureHandler from './GestureHandler';
const DEFAULT_MIN_DURATION_MS = 500;
const DEFAULT_MAX_DIST_DP = 10;
const SCALING_FACTOR = 10;
export default class LongPressGestureHandler extends GestureHandler {
constructor(...args) {
super(...args);
_defineProperty(this, "minDurationMs", DEFAULT_MIN_DURATION_MS);
_defineProperty(this, "defaultMaxDistSq", DEFAULT_MAX_DIST_DP * SCALING_FACTOR);
_defineProperty(this, "maxDistSq", this.defaultMaxDistSq);
_defineProperty(this, "startX", 0);
_defineProperty(this, "startY", 0);
_defineProperty(this, "startTime", 0);
_defineProperty(this, "previousTime", 0);
_defineProperty(this, "activationTimeout", void 0);
}
init(ref, propsRef) {
if (this.config.enableContextMenu === undefined) {
this.config.enableContextMenu = false;
}
super.init(ref, propsRef);
}
transformNativeEvent() {
return { ...super.transformNativeEvent(),
duration: Date.now() - this.startTime
};
}
updateGestureConfig({
enabled = true,
...props
}) {
super.updateGestureConfig({
enabled: enabled,
...props
});
if (this.config.minDurationMs !== undefined) {
this.minDurationMs = this.config.minDurationMs;
}
if (this.config.maxDist !== undefined) {
this.maxDistSq = this.config.maxDist * this.config.maxDist;
}
}
resetConfig() {
super.resetConfig();
this.minDurationMs = DEFAULT_MIN_DURATION_MS;
this.maxDistSq = this.defaultMaxDistSq;
}
onStateChange(_newState, _oldState) {
clearTimeout(this.activationTimeout);
}
onPointerDown(event) {
if (!this.isButtonInConfig(event.button)) {
return;
}
this.tracker.addToTracker(event);
super.onPointerDown(event);
this.tryBegin(event);
this.tryActivate();
this.checkDistanceFail(event);
}
onPointerMove(event) {
super.onPointerMove(event);
this.tracker.track(event);
this.checkDistanceFail(event);
}
onPointerUp(event) {
super.onPointerUp(event);
this.tracker.removeFromTracker(event.pointerId);
if (this.currentState === State.ACTIVE) {
this.end();
} else {
this.fail();
}
}
tryBegin(event) {
if (this.currentState !== State.UNDETERMINED) {
return;
}
this.previousTime = Date.now();
this.startTime = this.previousTime;
this.begin();
this.startX = event.x;
this.startY = event.y;
}
tryActivate() {
if (this.minDurationMs > 0) {
this.activationTimeout = setTimeout(() => {
this.activate();
}, this.minDurationMs);
} else if (this.minDurationMs === 0) {
this.activate();
}
}
checkDistanceFail(event) {
const dx = event.x - this.startX;
const dy = event.y - this.startY;
const distSq = dx * dx + dy * dy;
if (distSq <= this.maxDistSq) {
return;
}
if (this.currentState === State.ACTIVE) {
this.cancel();
} else {
this.fail();
}
}
}
//# sourceMappingURL=LongPressGestureHandler.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,49 @@
import GestureHandler from './GestureHandler';
export default class ManualGestureHandler extends GestureHandler {
init(ref, propsRef) {
super.init(ref, propsRef);
}
updateGestureConfig({
enabled = true,
...props
}) {
super.updateGestureConfig({
enabled: enabled,
...props
});
}
onPointerDown(event) {
this.tracker.addToTracker(event);
super.onPointerDown(event);
this.begin();
}
onPointerAdd(event) {
this.tracker.addToTracker(event);
super.onPointerAdd(event);
}
onPointerMove(event) {
this.tracker.track(event);
super.onPointerMove(event);
}
onPointerOutOfBounds(event) {
this.tracker.track(event);
super.onPointerOutOfBounds(event);
}
onPointerUp(event) {
super.onPointerUp(event);
this.tracker.removeFromTracker(event.pointerId);
}
onPointerRemove(event) {
super.onPointerRemove(event);
this.tracker.removeFromTracker(event.pointerId);
}
}
//# sourceMappingURL=ManualGestureHandler.js.map

View File

@@ -0,0 +1 @@
{"version":3,"sources":["ManualGestureHandler.ts"],"names":["GestureHandler","ManualGestureHandler","init","ref","propsRef","updateGestureConfig","enabled","props","onPointerDown","event","tracker","addToTracker","begin","onPointerAdd","onPointerMove","track","onPointerOutOfBounds","onPointerUp","removeFromTracker","pointerId","onPointerRemove"],"mappings":"AACA,OAAOA,cAAP,MAA2B,kBAA3B;AAEA,eAAe,MAAMC,oBAAN,SAAmCD,cAAnC,CAAkD;AACxDE,EAAAA,IAAI,CAACC,GAAD,EAAcC,QAAd,EAAkD;AAC3D,UAAMF,IAAN,CAAWC,GAAX,EAAgBC,QAAhB;AACD;;AAEMC,EAAAA,mBAAmB,CAAC;AAAEC,IAAAA,OAAO,GAAG,IAAZ;AAAkB,OAAGC;AAArB,GAAD,EAA6C;AACrE,UAAMF,mBAAN,CAA0B;AAAEC,MAAAA,OAAO,EAAEA,OAAX;AAAoB,SAAGC;AAAvB,KAA1B;AACD;;AAESC,EAAAA,aAAa,CAACC,KAAD,EAA4B;AACjD,SAAKC,OAAL,CAAaC,YAAb,CAA0BF,KAA1B;AACA,UAAMD,aAAN,CAAoBC,KAApB;AACA,SAAKG,KAAL;AACD;;AAESC,EAAAA,YAAY,CAACJ,KAAD,EAA4B;AAChD,SAAKC,OAAL,CAAaC,YAAb,CAA0BF,KAA1B;AACA,UAAMI,YAAN,CAAmBJ,KAAnB;AACD;;AAESK,EAAAA,aAAa,CAACL,KAAD,EAA4B;AACjD,SAAKC,OAAL,CAAaK,KAAb,CAAmBN,KAAnB;AACA,UAAMK,aAAN,CAAoBL,KAApB;AACD;;AAESO,EAAAA,oBAAoB,CAACP,KAAD,EAA4B;AACxD,SAAKC,OAAL,CAAaK,KAAb,CAAmBN,KAAnB;AACA,UAAMO,oBAAN,CAA2BP,KAA3B;AACD;;AAESQ,EAAAA,WAAW,CAACR,KAAD,EAA4B;AAC/C,UAAMQ,WAAN,CAAkBR,KAAlB;AACA,SAAKC,OAAL,CAAaQ,iBAAb,CAA+BT,KAAK,CAACU,SAArC;AACD;;AAESC,EAAAA,eAAe,CAACX,KAAD,EAA4B;AACnD,UAAMW,eAAN,CAAsBX,KAAtB;AACA,SAAKC,OAAL,CAAaQ,iBAAb,CAA+BT,KAAK,CAACU,SAArC;AACD;;AAtC8D","sourcesContent":["import { AdaptedEvent, Config } from '../interfaces';\nimport GestureHandler from './GestureHandler';\n\nexport default class ManualGestureHandler extends GestureHandler {\n public init(ref: number, propsRef: React.RefObject<unknown>) {\n super.init(ref, propsRef);\n }\n\n public updateGestureConfig({ enabled = true, ...props }: Config): void {\n super.updateGestureConfig({ enabled: enabled, ...props });\n }\n\n protected onPointerDown(event: AdaptedEvent): void {\n this.tracker.addToTracker(event);\n super.onPointerDown(event);\n this.begin();\n }\n\n protected onPointerAdd(event: AdaptedEvent): void {\n this.tracker.addToTracker(event);\n super.onPointerAdd(event);\n }\n\n protected onPointerMove(event: AdaptedEvent): void {\n this.tracker.track(event);\n super.onPointerMove(event);\n }\n\n protected onPointerOutOfBounds(event: AdaptedEvent): void {\n this.tracker.track(event);\n super.onPointerOutOfBounds(event);\n }\n\n protected onPointerUp(event: AdaptedEvent): void {\n super.onPointerUp(event);\n this.tracker.removeFromTracker(event.pointerId);\n }\n\n protected onPointerRemove(event: AdaptedEvent): void {\n super.onPointerRemove(event);\n this.tracker.removeFromTracker(event.pointerId);\n }\n}\n"]}

View File

@@ -0,0 +1,162 @@
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
import { Platform } from 'react-native';
import { State } from '../../State';
import { DEFAULT_TOUCH_SLOP } from '../constants';
import GestureHandler from './GestureHandler';
export default class NativeViewGestureHandler extends GestureHandler {
constructor(...args) {
super(...args);
_defineProperty(this, "buttonRole", void 0);
_defineProperty(this, "shouldActivateOnStart", false);
_defineProperty(this, "disallowInterruption", false);
_defineProperty(this, "startX", 0);
_defineProperty(this, "startY", 0);
_defineProperty(this, "minDistSq", DEFAULT_TOUCH_SLOP * DEFAULT_TOUCH_SLOP);
}
init(ref, propsRef) {
super.init(ref, propsRef);
this.setShouldCancelWhenOutside(true);
if (Platform.OS !== 'web') {
return;
}
const view = this.delegate.getView();
view.style['touchAction'] = 'auto'; //@ts-ignore Turns on defualt touch behavior on Safari
view.style['WebkitTouchCallout'] = 'auto';
this.buttonRole = view.getAttribute('role') === 'button';
}
updateGestureConfig({
enabled = true,
...props
}) {
super.updateGestureConfig({
enabled: enabled,
...props
});
if (this.config.shouldActivateOnStart !== undefined) {
this.shouldActivateOnStart = this.config.shouldActivateOnStart;
}
if (this.config.disallowInterruption !== undefined) {
this.disallowInterruption = this.config.disallowInterruption;
}
}
resetConfig() {
super.resetConfig();
}
onPointerDown(event) {
this.tracker.addToTracker(event);
super.onPointerDown(event);
this.newPointerAction();
}
onPointerAdd(event) {
this.tracker.addToTracker(event);
super.onPointerAdd(event);
this.newPointerAction();
}
newPointerAction() {
this.startX = this.tracker.getLastAvgX();
this.startY = this.tracker.getLastAvgY();
if (this.currentState !== State.UNDETERMINED) {
return;
}
this.begin();
if (this.buttonRole) {
this.activate();
}
}
onPointerMove(event) {
this.tracker.track(event);
const dx = this.startX - this.tracker.getLastAvgX();
const dy = this.startY - this.tracker.getLastAvgY();
const distSq = dx * dx + dy * dy;
if (distSq >= this.minDistSq) {
if (this.buttonRole && this.currentState === State.ACTIVE) {
this.cancel();
} else if (!this.buttonRole && this.currentState === State.BEGAN) {
this.activate();
}
}
}
onPointerLeave() {
if (this.currentState === State.BEGAN || this.currentState === State.ACTIVE) {
this.cancel();
}
}
onPointerUp(event) {
super.onPointerUp(event);
this.onUp(event);
}
onPointerRemove(event) {
super.onPointerRemove(event);
this.onUp(event);
}
onUp(event) {
this.tracker.removeFromTracker(event.pointerId);
if (this.tracker.getTrackedPointersCount() === 0) {
if (this.currentState === State.ACTIVE) {
this.end();
} else {
this.fail();
}
}
}
shouldRecognizeSimultaneously(handler) {
if (super.shouldRecognizeSimultaneously(handler)) {
return true;
}
if (handler instanceof NativeViewGestureHandler && handler.getState() === State.ACTIVE && handler.disallowsInterruption()) {
return false;
}
const canBeInterrupted = !this.disallowInterruption;
if (this.currentState === State.ACTIVE && handler.getState() === State.ACTIVE && canBeInterrupted) {
return false;
}
return this.currentState === State.ACTIVE && canBeInterrupted && handler.getTag() > 0;
}
shouldBeCancelledByOther(_handler) {
return !this.disallowInterruption;
}
disallowsInterruption() {
return this.disallowInterruption;
}
isButton() {
return this.buttonRole;
}
}
//# sourceMappingURL=NativeViewGestureHandler.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,439 @@
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
import { State } from '../../State';
import { DEFAULT_TOUCH_SLOP } from '../constants';
import GestureHandler from './GestureHandler';
const DEFAULT_MIN_POINTERS = 1;
const DEFAULT_MAX_POINTERS = 10;
const DEFAULT_MIN_DIST_SQ = DEFAULT_TOUCH_SLOP * DEFAULT_TOUCH_SLOP;
export default class PanGestureHandler extends GestureHandler {
constructor(...args) {
super(...args);
_defineProperty(this, "customActivationProperties", ['activeOffsetXStart', 'activeOffsetXEnd', 'failOffsetXStart', 'failOffsetXEnd', 'activeOffsetYStart', 'activeOffsetYEnd', 'failOffsetYStart', 'failOffsetYEnd', 'minVelocityX', 'minVelocityY', 'minVelocity']);
_defineProperty(this, "velocityX", 0);
_defineProperty(this, "velocityY", 0);
_defineProperty(this, "minDistSq", DEFAULT_MIN_DIST_SQ);
_defineProperty(this, "activeOffsetXStart", -Number.MAX_SAFE_INTEGER);
_defineProperty(this, "activeOffsetXEnd", Number.MIN_SAFE_INTEGER);
_defineProperty(this, "failOffsetXStart", Number.MIN_SAFE_INTEGER);
_defineProperty(this, "failOffsetXEnd", Number.MAX_SAFE_INTEGER);
_defineProperty(this, "activeOffsetYStart", Number.MAX_SAFE_INTEGER);
_defineProperty(this, "activeOffsetYEnd", Number.MIN_SAFE_INTEGER);
_defineProperty(this, "failOffsetYStart", Number.MIN_SAFE_INTEGER);
_defineProperty(this, "failOffsetYEnd", Number.MAX_SAFE_INTEGER);
_defineProperty(this, "minVelocityX", Number.MAX_SAFE_INTEGER);
_defineProperty(this, "minVelocityY", Number.MAX_SAFE_INTEGER);
_defineProperty(this, "minVelocitySq", Number.MAX_SAFE_INTEGER);
_defineProperty(this, "minPointers", DEFAULT_MIN_POINTERS);
_defineProperty(this, "maxPointers", DEFAULT_MAX_POINTERS);
_defineProperty(this, "startX", 0);
_defineProperty(this, "startY", 0);
_defineProperty(this, "offsetX", 0);
_defineProperty(this, "offsetY", 0);
_defineProperty(this, "lastX", 0);
_defineProperty(this, "lastY", 0);
_defineProperty(this, "activateAfterLongPress", 0);
_defineProperty(this, "activationTimeout", 0);
}
init(ref, propsRef) {
super.init(ref, propsRef);
}
updateGestureConfig({
enabled = true,
...props
}) {
this.resetConfig();
super.updateGestureConfig({
enabled: enabled,
...props
});
this.checkCustomActivationCriteria(this.customActivationProperties);
if (this.config.minDist !== undefined) {
this.minDistSq = this.config.minDist * this.config.minDist;
} else if (this.hasCustomActivationCriteria) {
this.minDistSq = Number.MAX_SAFE_INTEGER;
}
if (this.config.minPointers !== undefined) {
this.minPointers = this.config.minPointers;
}
if (this.config.maxPointers !== undefined) {
this.maxPointers = this.config.maxPointers;
}
if (this.config.minVelocity !== undefined) {
this.minVelocityX = this.config.minVelocity;
this.minVelocityY = this.config.minVelocity;
}
if (this.config.minVelocityX !== undefined) {
this.minVelocityX = this.config.minVelocityX;
}
if (this.config.minVelocityY !== undefined) {
this.minVelocityY = this.config.minVelocityY;
}
if (this.config.activateAfterLongPress !== undefined) {
this.activateAfterLongPress = this.config.activateAfterLongPress;
}
if (this.config.activeOffsetXStart !== undefined) {
this.activeOffsetXStart = this.config.activeOffsetXStart;
if (this.config.activeOffsetXEnd === undefined) {
this.activeOffsetXEnd = Number.MAX_SAFE_INTEGER;
}
}
if (this.config.activeOffsetXEnd !== undefined) {
this.activeOffsetXEnd = this.config.activeOffsetXEnd;
if (this.config.activeOffsetXStart === undefined) {
this.activeOffsetXStart = Number.MIN_SAFE_INTEGER;
}
}
if (this.config.failOffsetXStart !== undefined) {
this.failOffsetXStart = this.config.failOffsetXStart;
if (this.config.failOffsetXEnd === undefined) {
this.failOffsetXEnd = Number.MAX_SAFE_INTEGER;
}
}
if (this.config.failOffsetXEnd !== undefined) {
this.failOffsetXEnd = this.config.failOffsetXEnd;
if (this.config.failOffsetXStart === undefined) {
this.failOffsetXStart = Number.MIN_SAFE_INTEGER;
}
}
if (this.config.activeOffsetYStart !== undefined) {
this.activeOffsetYStart = this.config.activeOffsetYStart;
if (this.config.activeOffsetYEnd === undefined) {
this.activeOffsetYEnd = Number.MAX_SAFE_INTEGER;
}
}
if (this.config.activeOffsetYEnd !== undefined) {
this.activeOffsetYEnd = this.config.activeOffsetYEnd;
if (this.config.activeOffsetYStart === undefined) {
this.activeOffsetYStart = Number.MIN_SAFE_INTEGER;
}
}
if (this.config.failOffsetYStart !== undefined) {
this.failOffsetYStart = this.config.failOffsetYStart;
if (this.config.failOffsetYEnd === undefined) {
this.failOffsetYEnd = Number.MAX_SAFE_INTEGER;
}
}
if (this.config.failOffsetYEnd !== undefined) {
this.failOffsetYEnd = this.config.failOffsetYEnd;
if (this.config.failOffsetYStart === undefined) {
this.failOffsetYStart = Number.MIN_SAFE_INTEGER;
}
}
}
resetConfig() {
super.resetConfig();
this.activeOffsetXStart = -Number.MAX_SAFE_INTEGER;
this.activeOffsetXEnd = Number.MIN_SAFE_INTEGER;
this.failOffsetXStart = Number.MIN_SAFE_INTEGER;
this.failOffsetXEnd = Number.MAX_SAFE_INTEGER;
this.activeOffsetYStart = Number.MAX_SAFE_INTEGER;
this.activeOffsetYEnd = Number.MIN_SAFE_INTEGER;
this.failOffsetYStart = Number.MIN_SAFE_INTEGER;
this.failOffsetYEnd = Number.MAX_SAFE_INTEGER;
this.minVelocityX = Number.MAX_SAFE_INTEGER;
this.minVelocityY = Number.MAX_SAFE_INTEGER;
this.minVelocitySq = Number.MAX_SAFE_INTEGER;
this.minDistSq = DEFAULT_MIN_DIST_SQ;
this.minPointers = DEFAULT_MIN_POINTERS;
this.maxPointers = DEFAULT_MAX_POINTERS;
this.activateAfterLongPress = 0;
}
transformNativeEvent() {
const translationX = this.getTranslationX();
const translationY = this.getTranslationY();
return { ...super.transformNativeEvent(),
translationX: isNaN(translationX) ? 0 : translationX,
translationY: isNaN(translationY) ? 0 : translationY,
velocityX: this.velocityX,
velocityY: this.velocityY
};
}
getTranslationX() {
return this.lastX - this.startX + this.offsetX;
}
getTranslationY() {
return this.lastY - this.startY + this.offsetY;
}
clearActivationTimeout() {
clearTimeout(this.activationTimeout);
} //EventsHandling
onPointerDown(event) {
if (!this.isButtonInConfig(event.button)) {
return;
}
this.tracker.addToTracker(event);
super.onPointerDown(event);
this.lastX = this.tracker.getLastAvgX();
this.lastY = this.tracker.getLastAvgY();
this.startX = this.lastX;
this.startY = this.lastY;
this.tryBegin(event);
this.checkBegan();
}
onPointerAdd(event) {
this.tracker.addToTracker(event);
super.onPointerAdd(event);
this.tryBegin(event);
this.offsetX += this.lastX - this.startX;
this.offsetY += this.lastY - this.startY;
this.lastX = this.tracker.getLastAvgX();
this.lastY = this.tracker.getLastAvgY();
this.startX = this.lastX;
this.startY = this.lastY;
if (this.tracker.getTrackedPointersCount() > this.maxPointers) {
if (this.currentState === State.ACTIVE) {
this.cancel();
} else {
this.fail();
}
} else {
this.checkBegan();
}
}
onPointerUp(event) {
super.onPointerUp(event);
if (this.currentState === State.ACTIVE) {
this.lastX = this.tracker.getLastAvgX();
this.lastY = this.tracker.getLastAvgY();
}
this.tracker.removeFromTracker(event.pointerId);
if (this.currentState === State.ACTIVE) {
this.end();
} else {
this.resetProgress();
this.fail();
}
}
onPointerRemove(event) {
super.onPointerRemove(event);
this.tracker.removeFromTracker(event.pointerId);
this.offsetX += this.lastX - this.startX;
this.offsetY += this.lastY - this.startY;
this.lastX = this.tracker.getLastAvgX();
this.lastY = this.tracker.getLastAvgY();
this.startX = this.lastX;
this.startY = this.lastY;
if (!(this.currentState === State.ACTIVE && this.tracker.getTrackedPointersCount() < this.minPointers)) {
this.checkBegan();
}
}
onPointerMove(event) {
this.tracker.track(event);
this.lastX = this.tracker.getLastAvgX();
this.lastY = this.tracker.getLastAvgY();
this.velocityX = this.tracker.getVelocityX(event.pointerId);
this.velocityY = this.tracker.getVelocityY(event.pointerId);
this.checkBegan();
super.onPointerMove(event);
}
onPointerOutOfBounds(event) {
if (this.getShouldCancelWhenOutside()) {
return;
}
this.tracker.track(event);
this.lastX = this.tracker.getLastAvgX();
this.lastY = this.tracker.getLastAvgY();
this.velocityX = this.tracker.getVelocityX(event.pointerId);
this.velocityY = this.tracker.getVelocityY(event.pointerId);
this.checkBegan();
if (this.currentState === State.ACTIVE) {
super.onPointerOutOfBounds(event);
}
}
shouldActivate() {
const dx = this.getTranslationX();
if (this.activeOffsetXStart !== Number.MAX_SAFE_INTEGER && dx < this.activeOffsetXStart) {
return true;
}
if (this.activeOffsetXEnd !== Number.MIN_SAFE_INTEGER && dx > this.activeOffsetXEnd) {
return true;
}
const dy = this.getTranslationY();
if (this.activeOffsetYStart !== Number.MAX_SAFE_INTEGER && dy < this.activeOffsetYStart) {
return true;
}
if (this.activeOffsetYEnd !== Number.MIN_SAFE_INTEGER && dy > this.activeOffsetYEnd) {
return true;
}
const distanceSq = dx * dx + dy * dy;
if (this.minDistSq !== Number.MAX_SAFE_INTEGER && distanceSq >= this.minDistSq) {
return true;
}
const vx = this.velocityX;
if (this.minVelocityX !== Number.MAX_SAFE_INTEGER && (this.minVelocityX < 0 && vx <= this.minVelocityX || this.minVelocityX >= 0 && this.minVelocityX <= vx)) {
return true;
}
const vy = this.velocityY;
if (this.minVelocityY !== Number.MAX_SAFE_INTEGER && (this.minVelocityY < 0 && vy <= this.minVelocityY || this.minVelocityY >= 0 && this.minVelocityY <= vy)) {
return true;
}
const velocitySq = vx * vx + vy * vy;
return this.minVelocitySq !== Number.MAX_SAFE_INTEGER && velocitySq >= this.minVelocitySq;
}
shouldFail() {
const dx = this.getTranslationX();
const dy = this.getTranslationY();
const distanceSq = dx * dx + dy * dy;
if (this.activateAfterLongPress > 0 && distanceSq > DEFAULT_MIN_DIST_SQ) {
this.clearActivationTimeout();
return true;
}
if (this.failOffsetXStart !== Number.MIN_SAFE_INTEGER && dx < this.failOffsetXStart) {
return true;
}
if (this.failOffsetXEnd !== Number.MAX_SAFE_INTEGER && dx > this.failOffsetXEnd) {
return true;
}
if (this.failOffsetYStart !== Number.MIN_SAFE_INTEGER && dy < this.failOffsetYStart) {
return true;
}
return this.failOffsetYEnd !== Number.MAX_SAFE_INTEGER && dy > this.failOffsetYEnd;
}
tryBegin(event) {
if (this.currentState === State.UNDETERMINED && this.tracker.getTrackedPointersCount() >= this.minPointers) {
this.resetProgress();
this.offsetX = 0;
this.offsetY = 0;
this.velocityX = 0;
this.velocityY = 0;
this.begin();
if (this.activateAfterLongPress > 0) {
this.activationTimeout = setTimeout(() => {
this.activate();
}, this.activateAfterLongPress);
}
} else {
this.velocityX = this.tracker.getVelocityX(event.pointerId);
this.velocityY = this.tracker.getVelocityY(event.pointerId);
}
}
checkBegan() {
if (this.currentState === State.BEGAN) {
if (this.shouldFail()) {
this.fail();
} else if (this.shouldActivate()) {
this.activate();
}
}
}
activate(force = false) {
if (this.currentState !== State.ACTIVE) {
this.resetProgress();
}
super.activate(force);
}
onCancel() {
this.clearActivationTimeout();
}
onReset() {
this.clearActivationTimeout();
}
resetProgress() {
if (this.currentState === State.ACTIVE) {
return;
}
this.startX = this.lastX;
this.startY = this.lastY;
}
}
//# sourceMappingURL=PanGestureHandler.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,159 @@
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
import { State } from '../../State';
import { DEFAULT_TOUCH_SLOP } from '../constants';
import GestureHandler from './GestureHandler';
import ScaleGestureDetector from '../detectors/ScaleGestureDetector';
export default class PinchGestureHandler extends GestureHandler {
constructor(...args) {
super(...args);
_defineProperty(this, "scale", 1);
_defineProperty(this, "velocity", 0);
_defineProperty(this, "startingSpan", 0);
_defineProperty(this, "spanSlop", DEFAULT_TOUCH_SLOP);
_defineProperty(this, "scaleDetectorListener", {
onScaleBegin: detector => {
this.startingSpan = detector.getCurrentSpan();
return true;
},
onScale: detector => {
const prevScaleFactor = this.scale;
this.scale *= detector.getScaleFactor(this.tracker.getTrackedPointersCount());
const delta = detector.getTimeDelta();
if (delta > 0) {
this.velocity = (this.scale - prevScaleFactor) / delta;
}
if (Math.abs(this.startingSpan - detector.getCurrentSpan()) >= this.spanSlop && this.currentState === State.BEGAN) {
this.activate();
}
return true;
},
onScaleEnd: _detector => {}
});
_defineProperty(this, "scaleGestureDetector", new ScaleGestureDetector(this.scaleDetectorListener));
}
init(ref, propsRef) {
super.init(ref, propsRef);
this.setShouldCancelWhenOutside(false);
}
updateGestureConfig({
enabled = true,
...props
}) {
super.updateGestureConfig({
enabled: enabled,
...props
});
}
transformNativeEvent() {
return {
focalX: this.scaleGestureDetector.getFocusX(),
focalY: this.scaleGestureDetector.getFocusY(),
velocity: this.velocity,
scale: this.scale
};
}
onPointerDown(event) {
this.tracker.addToTracker(event);
super.onPointerDown(event);
}
onPointerAdd(event) {
this.tracker.addToTracker(event);
super.onPointerAdd(event);
this.tryBegin();
this.scaleGestureDetector.onTouchEvent(event, this.tracker);
}
onPointerUp(event) {
super.onPointerUp(event);
this.tracker.removeFromTracker(event.pointerId);
if (this.currentState !== State.ACTIVE) {
return;
}
this.scaleGestureDetector.onTouchEvent(event, this.tracker);
if (this.currentState === State.ACTIVE) {
this.end();
} else {
this.fail();
}
}
onPointerRemove(event) {
super.onPointerRemove(event);
this.scaleGestureDetector.onTouchEvent(event, this.tracker);
this.tracker.removeFromTracker(event.pointerId);
if (this.currentState === State.ACTIVE && this.tracker.getTrackedPointersCount() < 2) {
this.end();
}
}
onPointerMove(event) {
if (this.tracker.getTrackedPointersCount() < 2) {
return;
}
this.tracker.track(event);
this.scaleGestureDetector.onTouchEvent(event, this.tracker);
super.onPointerMove(event);
}
onPointerOutOfBounds(event) {
if (this.tracker.getTrackedPointersCount() < 2) {
return;
}
this.tracker.track(event);
this.scaleGestureDetector.onTouchEvent(event, this.tracker);
super.onPointerOutOfBounds(event);
}
tryBegin() {
if (this.currentState !== State.UNDETERMINED) {
return;
}
this.resetProgress();
this.begin();
}
activate(force) {
if (this.currentState !== State.ACTIVE) {
this.resetProgress();
}
super.activate(force);
}
onReset() {
this.resetProgress();
}
resetProgress() {
if (this.currentState === State.ACTIVE) {
return;
}
this.velocity = 0;
this.scale = 1;
}
}
//# sourceMappingURL=PinchGestureHandler.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,171 @@
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
import { State } from '../../State';
import GestureHandler from './GestureHandler';
import RotationGestureDetector from '../detectors/RotationGestureDetector';
const ROTATION_RECOGNITION_THRESHOLD = Math.PI / 36;
export default class RotationGestureHandler extends GestureHandler {
constructor(...args) {
super(...args);
_defineProperty(this, "rotation", 0);
_defineProperty(this, "velocity", 0);
_defineProperty(this, "cachedAnchorX", 0);
_defineProperty(this, "cachedAnchorY", 0);
_defineProperty(this, "rotationGestureListener", {
onRotationBegin: _detector => true,
onRotation: detector => {
const previousRotation = this.rotation;
this.rotation += detector.getRotation();
const delta = detector.getTimeDelta();
if (delta > 0) {
this.velocity = (this.rotation - previousRotation) / delta;
}
if (Math.abs(this.rotation) >= ROTATION_RECOGNITION_THRESHOLD && this.currentState === State.BEGAN) {
this.activate();
}
return true;
},
onRotationEnd: _detector => {
this.end();
}
});
_defineProperty(this, "rotationGestureDetector", new RotationGestureDetector(this.rotationGestureListener));
}
init(ref, propsRef) {
super.init(ref, propsRef);
this.setShouldCancelWhenOutside(false);
}
updateGestureConfig({
enabled = true,
...props
}) {
super.updateGestureConfig({
enabled: enabled,
...props
});
}
transformNativeEvent() {
return {
rotation: this.rotation ? this.rotation : 0,
anchorX: this.getAnchorX(),
anchorY: this.getAnchorY(),
velocity: this.velocity ? this.velocity : 0
};
}
getAnchorX() {
const anchorX = this.rotationGestureDetector.getAnchorX();
return anchorX ? anchorX : this.cachedAnchorX;
}
getAnchorY() {
const anchorY = this.rotationGestureDetector.getAnchorY();
return anchorY ? anchorY : this.cachedAnchorY;
}
onPointerDown(event) {
this.tracker.addToTracker(event);
super.onPointerDown(event);
}
onPointerAdd(event) {
this.tracker.addToTracker(event);
super.onPointerAdd(event);
this.tryBegin();
this.rotationGestureDetector.onTouchEvent(event, this.tracker);
}
onPointerMove(event) {
if (this.tracker.getTrackedPointersCount() < 2) {
return;
}
if (this.getAnchorX()) {
this.cachedAnchorX = this.getAnchorX();
}
if (this.getAnchorY()) {
this.cachedAnchorY = this.getAnchorY();
}
this.tracker.track(event);
this.rotationGestureDetector.onTouchEvent(event, this.tracker);
super.onPointerMove(event);
}
onPointerOutOfBounds(event) {
if (this.tracker.getTrackedPointersCount() < 2) {
return;
}
if (this.getAnchorX()) {
this.cachedAnchorX = this.getAnchorX();
}
if (this.getAnchorY()) {
this.cachedAnchorY = this.getAnchorY();
}
this.tracker.track(event);
this.rotationGestureDetector.onTouchEvent(event, this.tracker);
super.onPointerOutOfBounds(event);
}
onPointerUp(event) {
super.onPointerUp(event);
this.tracker.removeFromTracker(event.pointerId);
this.rotationGestureDetector.onTouchEvent(event, this.tracker);
if (this.currentState !== State.ACTIVE) {
return;
}
if (this.currentState === State.ACTIVE) {
this.end();
} else {
this.fail();
}
}
onPointerRemove(event) {
super.onPointerRemove(event);
this.rotationGestureDetector.onTouchEvent(event, this.tracker);
this.tracker.removeFromTracker(event.pointerId);
}
tryBegin() {
if (this.currentState !== State.UNDETERMINED) {
return;
}
this.begin();
}
activate(_force) {
super.activate();
}
onReset() {
if (this.currentState === State.ACTIVE) {
return;
}
this.rotation = 0;
this.velocity = 0;
this.rotationGestureDetector.reset();
}
}
//# sourceMappingURL=RotationGestureHandler.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,269 @@
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
import { State } from '../../State';
import { EventTypes } from '../interfaces';
import GestureHandler from './GestureHandler';
const DEFAULT_MAX_DURATION_MS = 500;
const DEFAULT_MAX_DELAY_MS = 500;
const DEFAULT_NUMBER_OF_TAPS = 1;
const DEFAULT_MIN_NUMBER_OF_POINTERS = 1;
export default class TapGestureHandler extends GestureHandler {
constructor(...args) {
super(...args);
_defineProperty(this, "maxDeltaX", Number.MIN_SAFE_INTEGER);
_defineProperty(this, "maxDeltaY", Number.MIN_SAFE_INTEGER);
_defineProperty(this, "maxDistSq", Number.MIN_SAFE_INTEGER);
_defineProperty(this, "maxDurationMs", DEFAULT_MAX_DURATION_MS);
_defineProperty(this, "maxDelayMs", DEFAULT_MAX_DELAY_MS);
_defineProperty(this, "numberOfTaps", DEFAULT_NUMBER_OF_TAPS);
_defineProperty(this, "minNumberOfPointers", DEFAULT_MIN_NUMBER_OF_POINTERS);
_defineProperty(this, "currentMaxNumberOfPointers", 1);
_defineProperty(this, "startX", 0);
_defineProperty(this, "startY", 0);
_defineProperty(this, "offsetX", 0);
_defineProperty(this, "offsetY", 0);
_defineProperty(this, "lastX", 0);
_defineProperty(this, "lastY", 0);
_defineProperty(this, "waitTimeout", void 0);
_defineProperty(this, "delayTimeout", void 0);
_defineProperty(this, "tapsSoFar", 0);
}
init(ref, propsRef) {
super.init(ref, propsRef);
}
updateGestureConfig({
enabled = true,
...props
}) {
super.updateGestureConfig({
enabled: enabled,
...props
});
if (this.config.numberOfTaps !== undefined) {
this.numberOfTaps = this.config.numberOfTaps;
}
if (this.config.maxDurationMs !== undefined) {
this.maxDurationMs = this.config.maxDurationMs;
}
if (this.config.maxDelayMs !== undefined) {
this.maxDelayMs = this.config.maxDelayMs;
}
if (this.config.maxDeltaX !== undefined) {
this.maxDeltaX = this.config.maxDeltaX;
}
if (this.config.maxDeltaY !== undefined) {
this.maxDeltaY = this.config.maxDeltaY;
}
if (this.config.maxDist !== undefined) {
this.maxDistSq = this.config.maxDist * this.config.maxDist;
}
if (this.config.minPointers !== undefined) {
this.minNumberOfPointers = this.config.minPointers;
}
}
resetConfig() {
super.resetConfig();
this.maxDeltaX = Number.MIN_SAFE_INTEGER;
this.maxDeltaY = Number.MIN_SAFE_INTEGER;
this.maxDistSq = Number.MIN_SAFE_INTEGER;
this.maxDurationMs = DEFAULT_MAX_DURATION_MS;
this.maxDelayMs = DEFAULT_MAX_DELAY_MS;
this.numberOfTaps = DEFAULT_NUMBER_OF_TAPS;
this.minNumberOfPointers = DEFAULT_MIN_NUMBER_OF_POINTERS;
}
clearTimeouts() {
clearTimeout(this.waitTimeout);
clearTimeout(this.delayTimeout);
}
startTap() {
this.clearTimeouts();
this.waitTimeout = setTimeout(() => this.fail(), this.maxDurationMs);
}
endTap() {
this.clearTimeouts();
if (++this.tapsSoFar === this.numberOfTaps && this.currentMaxNumberOfPointers >= this.minNumberOfPointers) {
this.activate();
} else {
this.delayTimeout = setTimeout(() => this.fail(), this.maxDelayMs);
}
} //Handling Events
onPointerDown(event) {
if (!this.isButtonInConfig(event.button)) {
return;
}
this.tracker.addToTracker(event);
super.onPointerDown(event);
this.trySettingPosition(event);
this.startX = event.x;
this.startY = event.y;
this.lastX = event.x;
this.lastY = event.y;
this.updateState(event);
}
onPointerAdd(event) {
super.onPointerAdd(event);
this.tracker.addToTracker(event);
this.trySettingPosition(event);
this.offsetX += this.lastX - this.startX;
this.offsetY += this.lastY - this.startY;
this.lastX = this.tracker.getLastAvgX();
this.lastY = this.tracker.getLastAvgY();
this.startX = this.tracker.getLastAvgX();
this.startY = this.tracker.getLastAvgY();
this.updateState(event);
}
onPointerUp(event) {
super.onPointerUp(event);
this.lastX = this.tracker.getLastAvgX();
this.lastY = this.tracker.getLastAvgY();
this.tracker.removeFromTracker(event.pointerId);
this.updateState(event);
}
onPointerRemove(event) {
super.onPointerRemove(event);
this.tracker.removeFromTracker(event.pointerId);
this.offsetX += this.lastX - this.startX;
this.offsetY += this.lastY = this.startY;
this.lastX = this.tracker.getLastAvgX();
this.lastY = this.tracker.getLastAvgY();
this.startX = this.lastX;
this.startY = this.lastY;
this.updateState(event);
}
onPointerMove(event) {
this.trySettingPosition(event);
this.tracker.track(event);
this.lastX = this.tracker.getLastAvgX();
this.lastY = this.tracker.getLastAvgY();
this.updateState(event);
super.onPointerMove(event);
}
onPointerOutOfBounds(event) {
this.trySettingPosition(event);
this.tracker.track(event);
this.lastX = this.tracker.getLastAvgX();
this.lastY = this.tracker.getLastAvgY();
this.updateState(event);
super.onPointerOutOfBounds(event);
}
updateState(event) {
if (this.currentMaxNumberOfPointers < this.tracker.getTrackedPointersCount()) {
this.currentMaxNumberOfPointers = this.tracker.getTrackedPointersCount();
}
if (this.shouldFail()) {
this.fail();
return;
}
switch (this.currentState) {
case State.UNDETERMINED:
if (event.eventType === EventTypes.DOWN) {
this.begin();
}
this.startTap();
break;
case State.BEGAN:
if (event.eventType === EventTypes.UP) {
this.endTap();
}
if (event.eventType === EventTypes.DOWN) {
this.startTap();
}
break;
default:
break;
}
}
trySettingPosition(event) {
if (this.currentState !== State.UNDETERMINED) {
return;
}
this.offsetX = 0;
this.offsetY = 0;
this.startX = event.x;
this.startY = event.y;
}
shouldFail() {
const dx = this.lastX - this.startX + this.offsetX;
if (this.maxDeltaX !== Number.MIN_SAFE_INTEGER && Math.abs(dx) > this.maxDeltaX) {
return true;
}
const dy = this.lastY - this.startY + this.offsetY;
if (this.maxDeltaY !== Number.MIN_SAFE_INTEGER && Math.abs(dy) > this.maxDeltaY) {
return true;
}
const distSq = dy * dy + dx * dx;
return this.maxDistSq !== Number.MIN_SAFE_INTEGER && distSq > this.maxDistSq;
}
activate() {
super.activate();
this.end();
}
onCancel() {
this.resetProgress();
this.clearTimeouts();
}
resetProgress() {
this.clearTimeouts();
this.tapsSoFar = 0;
this.currentMaxNumberOfPointers = 0;
}
}
//# sourceMappingURL=TapGestureHandler.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,23 @@
export let EventTypes;
(function (EventTypes) {
EventTypes[EventTypes["DOWN"] = 0] = "DOWN";
EventTypes[EventTypes["ADDITIONAL_POINTER_DOWN"] = 1] = "ADDITIONAL_POINTER_DOWN";
EventTypes[EventTypes["UP"] = 2] = "UP";
EventTypes[EventTypes["ADDITIONAL_POINTER_UP"] = 3] = "ADDITIONAL_POINTER_UP";
EventTypes[EventTypes["MOVE"] = 4] = "MOVE";
EventTypes[EventTypes["ENTER"] = 5] = "ENTER";
EventTypes[EventTypes["LEAVE"] = 6] = "LEAVE";
EventTypes[EventTypes["CANCEL"] = 7] = "CANCEL";
})(EventTypes || (EventTypes = {}));
export let TouchEventType;
(function (TouchEventType) {
TouchEventType[TouchEventType["UNDETERMINED"] = 0] = "UNDETERMINED";
TouchEventType[TouchEventType["DOWN"] = 1] = "DOWN";
TouchEventType[TouchEventType["MOVE"] = 2] = "MOVE";
TouchEventType[TouchEventType["UP"] = 3] = "UP";
TouchEventType[TouchEventType["CANCELLED"] = 4] = "CANCELLED";
})(TouchEventType || (TouchEventType = {}));
//# sourceMappingURL=interfaces.js.map

View File

@@ -0,0 +1 @@
{"version":3,"sources":["interfaces.ts"],"names":["EventTypes","TouchEventType"],"mappings":"AAoJA,WAAYA,UAAZ;;WAAYA,U;AAAAA,EAAAA,U,CAAAA,U;AAAAA,EAAAA,U,CAAAA,U;AAAAA,EAAAA,U,CAAAA,U;AAAAA,EAAAA,U,CAAAA,U;AAAAA,EAAAA,U,CAAAA,U;AAAAA,EAAAA,U,CAAAA,U;AAAAA,EAAAA,U,CAAAA,U;AAAAA,EAAAA,U,CAAAA,U;GAAAA,U,KAAAA,U;;AAWZ,WAAYC,cAAZ;;WAAYA,c;AAAAA,EAAAA,c,CAAAA,c;AAAAA,EAAAA,c,CAAAA,c;AAAAA,EAAAA,c,CAAAA,c;AAAAA,EAAAA,c,CAAAA,c;AAAAA,EAAAA,c,CAAAA,c;GAAAA,c,KAAAA,c","sourcesContent":["import {\n UserSelect,\n ActiveCursor,\n MouseButton,\n TouchAction,\n} from '../handlers/gestureHandlerCommon';\nimport { Directions } from '../Directions';\nimport { State } from '../State';\nimport { PointerType } from '../PointerType';\n\nexport interface HitSlop {\n left?: number;\n right?: number;\n top?: number;\n bottom?: number;\n horizontal?: number;\n vertical?: number;\n width?: number;\n height?: number;\n}\n\nexport interface Handler {\n handlerTag: number;\n}\n\ntype ConfigArgs =\n | number\n | boolean\n | HitSlop\n | UserSelect\n | TouchAction\n | ActiveCursor\n | Directions\n | Handler[]\n | null\n | undefined;\n\nexport interface Config extends Record<string, ConfigArgs> {\n enabled?: boolean;\n simultaneousHandlers?: Handler[] | null;\n waitFor?: Handler[] | null;\n blocksHandlers?: Handler[] | null;\n hitSlop?: HitSlop;\n shouldCancelWhenOutside?: boolean;\n userSelect?: UserSelect;\n activeCursor?: ActiveCursor;\n mouseButton?: MouseButton;\n enableContextMenu?: boolean;\n touchAction?: TouchAction;\n manualActivation?: boolean;\n\n activateAfterLongPress?: number;\n failOffsetXStart?: number;\n failOffsetYStart?: number;\n failOffsetXEnd?: number;\n failOffsetYEnd?: number;\n activeOffsetXStart?: number;\n activeOffsetXEnd?: number;\n activeOffsetYStart?: number;\n activeOffsetYEnd?: number;\n minPointers?: number;\n maxPointers?: number;\n minDist?: number;\n minDistSq?: number;\n minVelocity?: number;\n minVelocityX?: number;\n minVelocityY?: number;\n minVelocitySq?: number;\n maxDist?: number;\n maxDistSq?: number;\n numberOfPointers?: number;\n minDurationMs?: number;\n numberOfTaps?: number;\n maxDurationMs?: number;\n maxDelayMs?: number;\n maxDeltaX?: number;\n maxDeltaY?: number;\n shouldActivateOnStart?: boolean;\n disallowInterruption?: boolean;\n direction?: Directions;\n}\n\ntype NativeEventArgs = number | State | boolean | undefined;\ninterface NativeEvent extends Record<string, NativeEventArgs> {\n numberOfPointers: number;\n state: State;\n pointerInside: boolean | undefined;\n handlerTag: number;\n target: number;\n oldState?: State;\n pointerType: PointerType;\n}\n\nexport interface Point {\n x: number;\n y: number;\n}\n\nexport interface PointerData {\n id: number;\n x: number;\n y: number;\n absoluteX: number;\n absoluteY: number;\n}\n\ntype TouchNativeArgs = number | State | TouchEventType | PointerData[];\n\ninterface NativeTouchEvent extends Record<string, TouchNativeArgs> {\n handlerTag: number;\n state: State;\n eventType: TouchEventType;\n changedTouches: PointerData[];\n allTouches: PointerData[];\n numberOfTouches: number;\n}\n\nexport interface ResultEvent extends Record<string, NativeEvent | number> {\n nativeEvent: NativeEvent;\n timeStamp: number;\n}\n\nexport interface ResultTouchEvent\n extends Record<string, NativeTouchEvent | number> {\n nativeEvent: NativeTouchEvent;\n timeStamp: number;\n}\n\nexport interface PropsRef {\n onGestureHandlerEvent: () => void;\n onGestureHandlerStateChange: () => void;\n}\n\nexport interface AdaptedEvent {\n x: number;\n y: number;\n offsetX: number;\n offsetY: number;\n pointerId: number;\n eventType: EventTypes;\n pointerType: PointerType;\n time: number;\n button?: MouseButton;\n allTouches?: TouchList;\n changedTouches?: TouchList;\n touchEventType?: TouchEventType;\n}\n\nexport enum EventTypes {\n DOWN,\n ADDITIONAL_POINTER_DOWN,\n UP,\n ADDITIONAL_POINTER_UP,\n MOVE,\n ENTER,\n LEAVE,\n CANCEL,\n}\n\nexport enum TouchEventType {\n UNDETERMINED,\n DOWN,\n MOVE,\n UP,\n CANCELLED,\n}\n"]}

View File

@@ -0,0 +1,50 @@
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
export default class CircularBuffer {
constructor(size) {
_defineProperty(this, "bufferSize", void 0);
_defineProperty(this, "buffer", void 0);
_defineProperty(this, "index", void 0);
_defineProperty(this, "actualSize", void 0);
this.bufferSize = size;
this.buffer = new Array(size);
this.index = 0;
this.actualSize = 0;
}
get size() {
return this.actualSize;
}
push(element) {
this.buffer[this.index] = element;
this.index = (this.index + 1) % this.bufferSize;
this.actualSize = Math.min(this.actualSize + 1, this.bufferSize);
}
get(at) {
if (this.actualSize === this.bufferSize) {
let index = (this.index + at) % this.bufferSize;
if (index < 0) {
index += this.bufferSize;
}
return this.buffer[index];
} else {
return this.buffer[at];
}
}
clear() {
this.buffer = new Array(this.bufferSize);
this.index = 0;
this.actualSize = 0;
}
}
//# sourceMappingURL=CircularBuffer.js.map

View File

@@ -0,0 +1 @@
{"version":3,"sources":["CircularBuffer.ts"],"names":["CircularBuffer","constructor","size","bufferSize","buffer","Array","index","actualSize","push","element","Math","min","get","at","clear"],"mappings":";;AAAA,eAAe,MAAMA,cAAN,CAAwB;AAMrCC,EAAAA,WAAW,CAACC,IAAD,EAAe;AAAA;;AAAA;;AAAA;;AAAA;;AACxB,SAAKC,UAAL,GAAkBD,IAAlB;AACA,SAAKE,MAAL,GAAc,IAAIC,KAAJ,CAAaH,IAAb,CAAd;AACA,SAAKI,KAAL,GAAa,CAAb;AACA,SAAKC,UAAL,GAAkB,CAAlB;AACD;;AAEc,MAAJL,IAAI,GAAW;AACxB,WAAO,KAAKK,UAAZ;AACD;;AAEMC,EAAAA,IAAI,CAACC,OAAD,EAAmB;AAC5B,SAAKL,MAAL,CAAY,KAAKE,KAAjB,IAA0BG,OAA1B;AACA,SAAKH,KAAL,GAAa,CAAC,KAAKA,KAAL,GAAa,CAAd,IAAmB,KAAKH,UAArC;AACA,SAAKI,UAAL,GAAkBG,IAAI,CAACC,GAAL,CAAS,KAAKJ,UAAL,GAAkB,CAA3B,EAA8B,KAAKJ,UAAnC,CAAlB;AACD;;AAEMS,EAAAA,GAAG,CAACC,EAAD,EAAgB;AACxB,QAAI,KAAKN,UAAL,KAAoB,KAAKJ,UAA7B,EAAyC;AACvC,UAAIG,KAAK,GAAG,CAAC,KAAKA,KAAL,GAAaO,EAAd,IAAoB,KAAKV,UAArC;;AACA,UAAIG,KAAK,GAAG,CAAZ,EAAe;AACbA,QAAAA,KAAK,IAAI,KAAKH,UAAd;AACD;;AAED,aAAO,KAAKC,MAAL,CAAYE,KAAZ,CAAP;AACD,KAPD,MAOO;AACL,aAAO,KAAKF,MAAL,CAAYS,EAAZ,CAAP;AACD;AACF;;AAEMC,EAAAA,KAAK,GAAS;AACnB,SAAKV,MAAL,GAAc,IAAIC,KAAJ,CAAa,KAAKF,UAAlB,CAAd;AACA,SAAKG,KAAL,GAAa,CAAb;AACA,SAAKC,UAAL,GAAkB,CAAlB;AACD;;AAxCoC","sourcesContent":["export default class CircularBuffer<T> {\n private bufferSize: number;\n private buffer: T[];\n private index: number;\n private actualSize: number;\n\n constructor(size: number) {\n this.bufferSize = size;\n this.buffer = new Array<T>(size);\n this.index = 0;\n this.actualSize = 0;\n }\n\n public get size(): number {\n return this.actualSize;\n }\n\n public push(element: T): void {\n this.buffer[this.index] = element;\n this.index = (this.index + 1) % this.bufferSize;\n this.actualSize = Math.min(this.actualSize + 1, this.bufferSize);\n }\n\n public get(at: number): T {\n if (this.actualSize === this.bufferSize) {\n let index = (this.index + at) % this.bufferSize;\n if (index < 0) {\n index += this.bufferSize;\n }\n\n return this.buffer[index];\n } else {\n return this.buffer[at];\n }\n }\n\n public clear(): void {\n this.buffer = new Array<T>(this.bufferSize);\n this.index = 0;\n this.actualSize = 0;\n }\n}\n"]}

View File

@@ -0,0 +1,118 @@
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
/* eslint-disable @typescript-eslint/no-empty-function */
export default class EventManager {
constructor(view) {
_defineProperty(this, "view", void 0);
_defineProperty(this, "pointersInBounds", []);
_defineProperty(this, "activePointersCounter", void 0);
this.view = view;
this.activePointersCounter = 0;
}
onPointerDown(_event) {}
onPointerAdd(_event) {}
onPointerUp(_event) {}
onPointerRemove(_event) {}
onPointerMove(_event) {}
onPointerLeave(_event) {} // called only when pointer is pressed (or touching)
onPointerEnter(_event) {} // called only when pointer is pressed (or touching)
onPointerCancel(_event) {// When pointer cancel is triggered and there are more pointers on the view, only one pointer is cancelled
// Because we want all pointers to be cancelled by that event, we are doing it manually by reseting handler and changing activePointersCounter to 0
// Events that correspond to removing the pointer (pointerup, touchend) have condition, that they don't perform any action when activePointersCounter
// is equal to 0. This prevents counter from going to negative values, when pointers are removed from view after one of them has been cancelled
}
onPointerOutOfBounds(_event) {}
onPointerMoveOver(_event) {}
onPointerMoveOut(_event) {}
setOnPointerDown(callback) {
this.onPointerDown = callback;
}
setOnPointerAdd(callback) {
this.onPointerAdd = callback;
}
setOnPointerUp(callback) {
this.onPointerUp = callback;
}
setOnPointerRemove(callback) {
this.onPointerRemove = callback;
}
setOnPointerMove(callback) {
this.onPointerMove = callback;
}
setOnPointerLeave(callback) {
this.onPointerLeave = callback;
}
setOnPointerEnter(callback) {
this.onPointerEnter = callback;
}
setOnPointerCancel(callback) {
this.onPointerCancel = callback;
}
setOnPointerOutOfBounds(callback) {
this.onPointerOutOfBounds = callback;
}
setOnPointerMoveOver(callback) {
this.onPointerMoveOver = callback;
}
setOnPointerMoveOut(callback) {
this.onPointerMoveOut = callback;
}
markAsInBounds(pointerId) {
if (this.pointersInBounds.indexOf(pointerId) >= 0) {
return;
}
this.pointersInBounds.push(pointerId);
}
markAsOutOfBounds(pointerId) {
const index = this.pointersInBounds.indexOf(pointerId);
if (index < 0) {
return;
}
this.pointersInBounds.splice(index, 1);
}
resetManager() {
// Reseting activePointersCounter is necessary to make gestures such as pinch work properly
// There are gestures that end when there is still one active pointer (like pinch/rotation)
// When these gestures end, they are reset, but they still receive events from pointer that is active
// This causes trouble, since only onPointerDown registers gesture in orchestrator, and while gestures receive
// Events from active pointer after they finished, next pointerdown event will be registered as additional pointer, not the first one
// This casues trouble like gestures getting stuck in END state, even though they should have gone to UNDETERMINED
this.activePointersCounter = 0;
this.pointersInBounds = [];
}
}
//# sourceMappingURL=EventManager.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,2 @@
export {};
//# sourceMappingURL=GestureHandlerDelegate.js.map

View File

@@ -0,0 +1 @@
{"version":3,"sources":[],"names":[],"mappings":"","sourcesContent":[]}

View File

@@ -0,0 +1,334 @@
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
import { PointerType } from '../../PointerType';
import { State } from '../../State';
import PointerTracker from './PointerTracker';
export default class GestureHandlerOrchestrator {
// Private beacuse of Singleton
// eslint-disable-next-line no-useless-constructor, @typescript-eslint/no-empty-function
constructor() {
_defineProperty(this, "gestureHandlers", []);
_defineProperty(this, "awaitingHandlers", []);
_defineProperty(this, "awaitingHandlersTags", new Set());
_defineProperty(this, "handlingChangeSemaphore", 0);
_defineProperty(this, "activationIndex", 0);
}
scheduleFinishedHandlersCleanup() {
if (this.handlingChangeSemaphore === 0) {
this.cleanupFinishedHandlers();
}
}
cleanHandler(handler) {
handler.reset();
handler.setActive(false);
handler.setAwaiting(false);
handler.setActivationIndex(Number.MAX_VALUE);
}
removeHandlerFromOrchestrator(handler) {
const indexInGestureHandlers = this.gestureHandlers.indexOf(handler);
const indexInAwaitingHandlers = this.awaitingHandlers.indexOf(handler);
if (indexInGestureHandlers >= 0) {
this.gestureHandlers.splice(indexInGestureHandlers, 1);
}
if (indexInAwaitingHandlers >= 0) {
this.awaitingHandlers.splice(indexInAwaitingHandlers, 1);
this.awaitingHandlersTags.delete(handler.getTag());
}
}
cleanupFinishedHandlers() {
const handlersToRemove = new Set();
for (let i = this.gestureHandlers.length - 1; i >= 0; --i) {
const handler = this.gestureHandlers[i];
if (this.isFinished(handler.getState()) && !handler.isAwaiting()) {
this.cleanHandler(handler);
handlersToRemove.add(handler);
}
}
this.gestureHandlers = this.gestureHandlers.filter(handler => !handlersToRemove.has(handler));
}
hasOtherHandlerToWaitFor(handler) {
const hasToWaitFor = otherHandler => {
return !this.isFinished(otherHandler.getState()) && this.shouldHandlerWaitForOther(handler, otherHandler);
};
return this.gestureHandlers.some(hasToWaitFor);
}
shouldBeCancelledByFinishedHandler(handler) {
const shouldBeCancelled = otherHandler => {
return this.shouldHandlerWaitForOther(handler, otherHandler) && otherHandler.getState() === State.END;
};
return this.gestureHandlers.some(shouldBeCancelled);
}
tryActivate(handler) {
if (this.shouldBeCancelledByFinishedHandler(handler)) {
handler.cancel();
return;
}
if (this.hasOtherHandlerToWaitFor(handler)) {
this.addAwaitingHandler(handler);
return;
}
const handlerState = handler.getState();
if (handlerState === State.CANCELLED || handlerState === State.FAILED) {
return;
}
if (this.shouldActivate(handler)) {
this.makeActive(handler);
return;
}
if (handlerState === State.ACTIVE) {
handler.fail();
return;
}
if (handlerState === State.BEGAN) {
handler.cancel();
}
}
shouldActivate(handler) {
const shouldBeCancelledBy = otherHandler => {
return this.shouldHandlerBeCancelledBy(handler, otherHandler);
};
return !this.gestureHandlers.some(shouldBeCancelledBy);
}
cleanupAwaitingHandlers(handler) {
const shouldWait = otherHandler => {
return !otherHandler.isAwaiting() && this.shouldHandlerWaitForOther(otherHandler, handler);
};
for (const otherHandler of this.awaitingHandlers) {
if (shouldWait(otherHandler)) {
this.cleanHandler(otherHandler);
this.awaitingHandlersTags.delete(otherHandler.getTag());
}
}
this.awaitingHandlers = this.awaitingHandlers.filter(otherHandler => this.awaitingHandlersTags.has(otherHandler.getTag()));
}
onHandlerStateChange(handler, newState, oldState, sendIfDisabled) {
if (!handler.isEnabled() && !sendIfDisabled) {
return;
}
this.handlingChangeSemaphore += 1;
if (this.isFinished(newState)) {
for (const otherHandler of this.awaitingHandlers) {
if (!this.shouldHandlerWaitForOther(otherHandler, handler) || !this.awaitingHandlersTags.has(otherHandler.getTag())) {
continue;
}
if (newState !== State.END) {
this.tryActivate(otherHandler);
continue;
}
otherHandler.cancel();
if (otherHandler.getState() === State.END) {
// Handle edge case, where discrete gestures end immediately after activation thus
// their state is set to END and when the gesture they are waiting for activates they
// should be cancelled, however `cancel` was never sent as gestures were already in the END state.
// Send synthetic BEGAN -> CANCELLED to properly handle JS logic
otherHandler.sendEvent(State.CANCELLED, State.BEGAN);
}
otherHandler.setAwaiting(false);
}
}
if (newState === State.ACTIVE) {
this.tryActivate(handler);
} else if (oldState === State.ACTIVE || oldState === State.END) {
if (handler.isActive()) {
handler.sendEvent(newState, oldState);
} else if (oldState === State.ACTIVE && (newState === State.CANCELLED || newState === State.FAILED)) {
handler.sendEvent(newState, State.BEGAN);
}
} else if (oldState !== State.UNDETERMINED || newState !== State.CANCELLED) {
handler.sendEvent(newState, oldState);
}
this.handlingChangeSemaphore -= 1;
this.scheduleFinishedHandlersCleanup();
if (!this.awaitingHandlers.includes(handler)) {
this.cleanupAwaitingHandlers(handler);
}
}
makeActive(handler) {
const currentState = handler.getState();
handler.setActive(true);
handler.setShouldResetProgress(true);
handler.setActivationIndex(this.activationIndex++);
for (let i = this.gestureHandlers.length - 1; i >= 0; --i) {
if (this.shouldHandlerBeCancelledBy(this.gestureHandlers[i], handler)) {
this.gestureHandlers[i].cancel();
}
}
for (const otherHandler of this.awaitingHandlers) {
if (this.shouldHandlerBeCancelledBy(otherHandler, handler)) {
otherHandler.setAwaiting(false);
}
}
handler.sendEvent(State.ACTIVE, State.BEGAN);
if (currentState !== State.ACTIVE) {
handler.sendEvent(State.END, State.ACTIVE);
if (currentState !== State.END) {
handler.sendEvent(State.UNDETERMINED, State.END);
}
}
if (!handler.isAwaiting()) {
return;
}
handler.setAwaiting(false);
this.awaitingHandlers = this.awaitingHandlers.filter(otherHandler => otherHandler !== handler);
}
addAwaitingHandler(handler) {
if (this.awaitingHandlers.includes(handler)) {
return;
}
this.awaitingHandlers.push(handler);
this.awaitingHandlersTags.add(handler.getTag());
handler.setAwaiting(true);
handler.setActivationIndex(this.activationIndex++);
}
recordHandlerIfNotPresent(handler) {
if (this.gestureHandlers.includes(handler)) {
return;
}
this.gestureHandlers.push(handler);
handler.setActive(false);
handler.setAwaiting(false);
handler.setActivationIndex(Number.MAX_SAFE_INTEGER);
}
shouldHandlerWaitForOther(handler, otherHandler) {
return handler !== otherHandler && (handler.shouldWaitForHandlerFailure(otherHandler) || otherHandler.shouldRequireToWaitForFailure(handler));
}
canRunSimultaneously(gh1, gh2) {
return gh1 === gh2 || gh1.shouldRecognizeSimultaneously(gh2) || gh2.shouldRecognizeSimultaneously(gh1);
}
shouldHandlerBeCancelledBy(handler, otherHandler) {
if (this.canRunSimultaneously(handler, otherHandler)) {
return false;
}
if (handler.isAwaiting() || handler.getState() === State.ACTIVE) {
// For now it always returns false
return handler.shouldBeCancelledByOther(otherHandler);
}
const handlerPointers = handler.getTrackedPointersID();
const otherPointers = otherHandler.getTrackedPointersID();
if (!PointerTracker.shareCommonPointers(handlerPointers, otherPointers) && handler.getDelegate().getView() !== otherHandler.getDelegate().getView()) {
return this.checkOverlap(handler, otherHandler);
}
return true;
}
checkOverlap(handler, otherHandler) {
// If handlers don't have common pointers, default return value is false.
// However, if at least on pointer overlaps with both handlers, we return true
// This solves issue in overlapping parents example
// TODO: Find better way to handle that issue, for example by activation order and handler cancelling
const isPointerWithinBothBounds = pointer => {
const handlerX = handler.getTracker().getLastX(pointer);
const handlerY = handler.getTracker().getLastY(pointer);
const point = {
x: handlerX,
y: handlerY
};
return handler.getDelegate().isPointerInBounds(point) && otherHandler.getDelegate().isPointerInBounds(point);
};
const handlerPointers = handler.getTrackedPointersID();
const otherPointers = otherHandler.getTrackedPointersID();
return handlerPointers.some(isPointerWithinBothBounds) || otherPointers.some(isPointerWithinBothBounds);
}
isFinished(state) {
return state === State.END || state === State.FAILED || state === State.CANCELLED;
} // This function is called when handler receives touchdown event
// If handler is using mouse or pen as a pointer and any handler receives touch event,
// mouse/pen event dissappears - it doesn't send onPointerCancel nor onPointerUp (and others)
// This became a problem because handler was left at active state without any signal to end or fail
// To handle this, when new touch event is received, we loop through active handlers and check which type of
// pointer they're using. If there are any handler with mouse/pen as a pointer, we cancel them
cancelMouseAndPenGestures(currentHandler) {
this.gestureHandlers.forEach(handler => {
if (handler.getPointerType() !== PointerType.MOUSE && handler.getPointerType() !== PointerType.STYLUS) {
return;
}
if (handler !== currentHandler) {
handler.cancel();
} else {
// Handler that received touch event should have its pointer tracker reset
// This allows handler to smoothly change from mouse/pen to touch
// The drawback is, that when we try to use mouse/pen one more time, it doesn't send onPointerDown at the first time
// so it is required to click two times to get handler to work
//
// However, handler will receive manually created onPointerEnter that is triggered in EventManager in onPointerMove method.
// There may be possibility to use that fact to make handler respond properly to first mouse click
handler.getTracker().resetTracker();
}
});
}
static getInstance() {
if (!GestureHandlerOrchestrator.instance) {
GestureHandlerOrchestrator.instance = new GestureHandlerOrchestrator();
}
return GestureHandlerOrchestrator.instance;
}
}
_defineProperty(GestureHandlerOrchestrator, "instance", void 0);
//# sourceMappingURL=GestureHandlerOrchestrator.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,141 @@
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
import { findNodeHandle } from 'react-native';
import PointerEventManager from './PointerEventManager';
import TouchEventManager from './TouchEventManager';
import { State } from '../../State';
import { isPointerInBounds } from '../utils';
import { MouseButton } from '../../handlers/gestureHandlerCommon';
export class GestureHandlerWebDelegate {
constructor() {
_defineProperty(this, "view", void 0);
_defineProperty(this, "gestureHandler", void 0);
_defineProperty(this, "eventManagers", []);
}
getView() {
return this.view;
}
init(viewRef, handler) {
var _config$touchAction;
if (!viewRef) {
throw new Error(`Cannot find HTML Element for handler ${handler.getTag()}`);
}
this.gestureHandler = handler;
this.view = findNodeHandle(viewRef);
const config = handler.getConfig();
this.addContextMenuListeners(config);
if (!config.userSelect) {
this.view.style['webkitUserSelect'] = 'none';
this.view.style['userSelect'] = 'none';
} else {
this.view.style['webkitUserSelect'] = config.userSelect;
this.view.style['userSelect'] = config.userSelect;
}
this.view.style['touchAction'] = (_config$touchAction = config.touchAction) !== null && _config$touchAction !== void 0 ? _config$touchAction : 'none'; //@ts-ignore This one disables default events on Safari
this.view.style['WebkitTouchCallout'] = 'none';
this.eventManagers.push(new PointerEventManager(this.view));
this.eventManagers.push(new TouchEventManager(this.view));
this.eventManagers.forEach(manager => this.gestureHandler.attachEventManager(manager));
}
isPointerInBounds({
x,
y
}) {
return isPointerInBounds(this.view, {
x,
y
});
}
measureView() {
const rect = this.view.getBoundingClientRect();
return {
pageX: rect.left,
pageY: rect.top,
width: rect.width,
height: rect.height
};
}
reset() {
this.eventManagers.forEach(manager => manager.resetManager());
}
tryResetCursor() {
const config = this.gestureHandler.getConfig();
if (config.activeCursor && config.activeCursor !== 'auto' && this.gestureHandler.getState() === State.ACTIVE) {
this.view.style.cursor = 'auto';
}
}
shouldDisableContextMenu(config) {
return config.enableContextMenu === undefined && this.gestureHandler.isButtonInConfig(MouseButton.RIGHT) || config.enableContextMenu === false;
}
addContextMenuListeners(config) {
if (this.shouldDisableContextMenu(config)) {
this.view.addEventListener('contextmenu', this.disableContextMenu);
} else if (config.enableContextMenu) {
this.view.addEventListener('contextmenu', this.enableContextMenu);
}
}
removeContextMenuListeners(config) {
if (this.shouldDisableContextMenu(config)) {
this.view.removeEventListener('contextmenu', this.disableContextMenu);
} else if (config.enableContextMenu) {
this.view.removeEventListener('contextmenu', this.enableContextMenu);
}
}
disableContextMenu(e) {
e.preventDefault();
}
enableContextMenu(e) {
e.stopPropagation();
}
onBegin() {// no-op for now
}
onActivate() {
const config = this.gestureHandler.getConfig();
if ((!this.view.style.cursor || this.view.style.cursor === 'auto') && config.activeCursor) {
this.view.style.cursor = config.activeCursor;
}
}
onEnd() {
this.tryResetCursor();
}
onCancel() {
this.tryResetCursor();
}
onFail() {
this.tryResetCursor();
}
destroy(config) {
this.removeContextMenuListeners(config);
this.eventManagers.forEach(manager => {
manager.unregisterListeners();
});
}
}
//# sourceMappingURL=GestureHandlerWebDelegate.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,111 @@
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
import { State } from '../../State';
export default class InteractionManager {
// Private becaues of singleton
// eslint-disable-next-line no-useless-constructor, @typescript-eslint/no-empty-function
constructor() {
_defineProperty(this, "waitForRelations", new Map());
_defineProperty(this, "simultaneousRelations", new Map());
_defineProperty(this, "blocksHandlersRelations", new Map());
}
configureInteractions(handler, config) {
this.dropRelationsForHandlerWithTag(handler.getTag());
if (config.waitFor) {
const waitFor = [];
config.waitFor.forEach(otherHandler => {
// New API reference
if (typeof otherHandler === 'number') {
waitFor.push(otherHandler);
} else {
// Old API reference
waitFor.push(otherHandler.handlerTag);
}
});
this.waitForRelations.set(handler.getTag(), waitFor);
}
if (config.simultaneousHandlers) {
const simultaneousHandlers = [];
config.simultaneousHandlers.forEach(otherHandler => {
if (typeof otherHandler === 'number') {
simultaneousHandlers.push(otherHandler);
} else {
simultaneousHandlers.push(otherHandler.handlerTag);
}
});
this.simultaneousRelations.set(handler.getTag(), simultaneousHandlers);
}
if (config.blocksHandlers) {
const blocksHandlers = [];
config.blocksHandlers.forEach(otherHandler => {
if (typeof otherHandler === 'number') {
blocksHandlers.push(otherHandler);
} else {
blocksHandlers.push(otherHandler.handlerTag);
}
});
this.blocksHandlersRelations.set(handler.getTag(), blocksHandlers);
}
}
shouldWaitForHandlerFailure(handler, otherHandler) {
const waitFor = this.waitForRelations.get(handler.getTag());
return (waitFor === null || waitFor === void 0 ? void 0 : waitFor.find(tag => {
return tag === otherHandler.getTag();
})) !== undefined;
}
shouldRecognizeSimultaneously(handler, otherHandler) {
const simultaneousHandlers = this.simultaneousRelations.get(handler.getTag());
return (simultaneousHandlers === null || simultaneousHandlers === void 0 ? void 0 : simultaneousHandlers.find(tag => {
return tag === otherHandler.getTag();
})) !== undefined;
}
shouldRequireHandlerToWaitForFailure(handler, otherHandler) {
const waitFor = this.blocksHandlersRelations.get(handler.getTag());
return (waitFor === null || waitFor === void 0 ? void 0 : waitFor.find(tag => {
return tag === otherHandler.getTag();
})) !== undefined;
}
shouldHandlerBeCancelledBy(_handler, otherHandler) {
var _otherHandler$isButto;
// We check constructor name instead of using `instanceof` in order do avoid circular dependencies
const isNativeHandler = otherHandler.constructor.name === 'NativeViewGestureHandler';
const isActive = otherHandler.getState() === State.ACTIVE;
const isButton = ((_otherHandler$isButto = otherHandler.isButton) === null || _otherHandler$isButto === void 0 ? void 0 : _otherHandler$isButto.call(otherHandler)) === true;
return isNativeHandler && isActive && !isButton;
}
dropRelationsForHandlerWithTag(handlerTag) {
this.waitForRelations.delete(handlerTag);
this.simultaneousRelations.delete(handlerTag);
this.blocksHandlersRelations.delete(handlerTag);
}
reset() {
this.waitForRelations.clear();
this.simultaneousRelations.clear();
this.blocksHandlersRelations.clear();
}
static getInstance() {
if (!this.instance) {
this.instance = new InteractionManager();
}
return this.instance;
}
}
_defineProperty(InteractionManager, "instance", void 0);
//# sourceMappingURL=InteractionManager.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,195 @@
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
// Implementation taken from Flutter's LeastSquareSolver
// https://github.com/flutter/flutter/blob/master/packages/flutter/lib/src/gestures/lsq_solver.dart
class Vector {
constructor(length) {
_defineProperty(this, "offset", void 0);
_defineProperty(this, "length", void 0);
_defineProperty(this, "elements", void 0);
this.offset = 0;
this.length = length;
this.elements = new Array(length);
}
static fromVOL(values, offset, length) {
const result = new Vector(0);
result.offset = offset;
result.length = length;
result.elements = values;
return result;
}
get(index) {
return this.elements[this.offset + index];
}
set(index, value) {
this.elements[this.offset + index] = value;
}
dot(other) {
let result = 0;
for (let i = 0; i < this.length; i++) {
result += this.get(i) * other.get(i);
}
return result;
}
norm() {
return Math.sqrt(this.dot(this));
}
}
class Matrix {
constructor(rows, columns) {
_defineProperty(this, "columns", void 0);
_defineProperty(this, "elements", void 0);
this.columns = columns;
this.elements = new Array(rows * columns);
}
get(row, column) {
return this.elements[row * this.columns + column];
}
set(row, column, value) {
this.elements[row * this.columns + column] = value;
}
getRow(row) {
return Vector.fromVOL(this.elements, row * this.columns, this.columns);
}
} /// An nth degree polynomial fit to a dataset.
class PolynomialFit {
/// The polynomial coefficients of the fit.
///
/// For each `i`, the element `coefficients[i]` is the coefficient of
/// the `i`-th power of the variable.
/// Creates a polynomial fit of the given degree.
///
/// There are n + 1 coefficients in a fit of degree n.
constructor(degree) {
_defineProperty(this, "coefficients", void 0);
this.coefficients = new Array(degree + 1);
}
}
const precisionErrorTolerance = 1e-10; /// Uses the least-squares algorithm to fit a polynomial to a set of data.
export default class LeastSquareSolver {
/// The x-coordinates of each data point.
/// The y-coordinates of each data point.
/// The weight to use for each data point.
/// Creates a least-squares solver.
///
/// The [x], [y], and [w] arguments must not be null.
constructor(x, y, w) {
_defineProperty(this, "x", void 0);
_defineProperty(this, "y", void 0);
_defineProperty(this, "w", void 0);
this.x = x;
this.y = y;
this.w = w;
} /// Fits a polynomial of the given degree to the data points.
///
/// When there is not enough data to fit a curve null is returned.
solve(degree) {
if (degree > this.x.length) {
// Not enough data to fit a curve.
return null;
}
const result = new PolynomialFit(degree); // Shorthands for the purpose of notation equivalence to original C++ code.
const m = this.x.length;
const n = degree + 1; // Expand the X vector to a matrix A, pre-multiplied by the weights.
const a = new Matrix(n, m);
for (let h = 0; h < m; h++) {
a.set(0, h, this.w[h]);
for (let i = 1; i < n; i++) {
a.set(i, h, a.get(i - 1, h) * this.x[h]);
}
} // Apply the Gram-Schmidt process to A to obtain its QR decomposition.
// Orthonormal basis, column-major ordVectorer.
const q = new Matrix(n, m); // Upper triangular matrix, row-major order.
const r = new Matrix(n, m);
for (let j = 0; j < n; j += 1) {
for (let h = 0; h < m; h += 1) {
q.set(j, h, a.get(j, h));
}
for (let i = 0; i < j; i += 1) {
const dot = q.getRow(j).dot(q.getRow(i));
for (let h = 0; h < m; h += 1) {
q.set(j, h, q.get(j, h) - dot * q.get(i, h));
}
}
const norm = q.getRow(j).norm();
if (norm < precisionErrorTolerance) {
// Vectors are linearly dependent or zero so no solution.
return null;
}
const inverseNorm = 1.0 / norm;
for (let h = 0; h < m; h += 1) {
q.set(j, h, q.get(j, h) * inverseNorm);
}
for (let i = 0; i < n; i += 1) {
r.set(j, i, i < j ? 0.0 : q.getRow(j).dot(a.getRow(i)));
}
} // Solve R B = Qt W Y to find B. This is easy because R is upper triangular.
// We just work from bottom-right to top-left calculating B's coefficients.
const wy = new Vector(m);
for (let h = 0; h < m; h += 1) {
wy.set(h, this.y[h] * this.w[h]);
}
for (let i = n - 1; i >= 0; i -= 1) {
result.coefficients[i] = q.getRow(i).dot(wy);
for (let j = n - 1; j > i; j -= 1) {
result.coefficients[i] -= r.get(i, j) * result.coefficients[j];
}
result.coefficients[i] /= r.get(i, i);
}
return result;
}
}
//# sourceMappingURL=LeastSquareSolver.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,40 @@
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
// eslint-disable-next-line @typescript-eslint/no-extraneous-class
export default class NodeManager {
static getHandler(tag) {
if (tag in this.gestures) {
return this.gestures[tag];
}
throw new Error(`No handler for tag ${tag}`);
}
static createGestureHandler(handlerTag, handler) {
if (handlerTag in this.gestures) {
throw new Error(`Handler with tag ${handlerTag} already exists. Please ensure that no Gesture instance is used across multiple GestureDetectors.`);
}
this.gestures[handlerTag] = handler;
this.gestures[handlerTag].setTag(handlerTag);
}
static dropGestureHandler(handlerTag) {
if (!(handlerTag in this.gestures)) {
return;
}
this.gestures[handlerTag].onDestroy(); // eslint-disable-next-line @typescript-eslint/no-dynamic-delete
delete this.gestures[handlerTag];
}
static getNodes() {
return { ...this.gestures
};
}
}
_defineProperty(NodeManager, "gestures", {});
//# sourceMappingURL=NodeManager.js.map

View File

@@ -0,0 +1 @@
{"version":3,"sources":["NodeManager.ts"],"names":["NodeManager","getHandler","tag","gestures","Error","createGestureHandler","handlerTag","handler","setTag","dropGestureHandler","onDestroy","getNodes"],"mappings":";;AAIA;AACA,eAAe,MAAeA,WAAf,CAA2B;AAMhB,SAAVC,UAAU,CAACC,GAAD,EAA+B;AACrD,QAAIA,GAAG,IAAI,KAAKC,QAAhB,EAA0B;AACxB,aAAO,KAAKA,QAAL,CAAcD,GAAd,CAAP;AACD;;AAED,UAAM,IAAIE,KAAJ,CAAW,sBAAqBF,GAAI,EAApC,CAAN;AACD;;AAEiC,SAApBG,oBAAoB,CAChCC,UADgC,EAEhCC,OAFgC,EAG1B;AACN,QAAID,UAAU,IAAI,KAAKH,QAAvB,EAAiC;AAC/B,YAAM,IAAIC,KAAJ,CACH,oBAAmBE,UAAW,mGAD3B,CAAN;AAGD;;AAED,SAAKH,QAAL,CAAcG,UAAd,IAA4BC,OAA5B;AACA,SAAKJ,QAAL,CAAcG,UAAd,EAA0BE,MAA1B,CAAiCF,UAAjC;AACD;;AAE+B,SAAlBG,kBAAkB,CAACH,UAAD,EAA2B;AACzD,QAAI,EAAEA,UAAU,IAAI,KAAKH,QAArB,CAAJ,EAAoC;AAClC;AACD;;AAED,SAAKA,QAAL,CAAcG,UAAd,EAA0BI,SAA1B,GALyD,CAOzD;;AACA,WAAO,KAAKP,QAAL,CAAcG,UAAd,CAAP;AACD;;AAEqB,SAARK,QAAQ,GAAG;AACvB,WAAO,EAAE,GAAG,KAAKR;AAAV,KAAP;AACD;;AAzCuC;;gBAAZH,W,cAIxB,E","sourcesContent":["import { ValueOf } from '../../typeUtils';\nimport { Gestures } from '../Gestures';\nimport type IGestureHandler from '../handlers/IGestureHandler';\n\n// eslint-disable-next-line @typescript-eslint/no-extraneous-class\nexport default abstract class NodeManager {\n private static gestures: Record<\n number,\n InstanceType<ValueOf<typeof Gestures>>\n > = {};\n\n public static getHandler(tag: number): IGestureHandler {\n if (tag in this.gestures) {\n return this.gestures[tag] as IGestureHandler;\n }\n\n throw new Error(`No handler for tag ${tag}`);\n }\n\n public static createGestureHandler(\n handlerTag: number,\n handler: InstanceType<ValueOf<typeof Gestures>>\n ): void {\n if (handlerTag in this.gestures) {\n throw new Error(\n `Handler with tag ${handlerTag} already exists. Please ensure that no Gesture instance is used across multiple GestureDetectors.`\n );\n }\n\n this.gestures[handlerTag] = handler;\n this.gestures[handlerTag].setTag(handlerTag);\n }\n\n public static dropGestureHandler(handlerTag: number): void {\n if (!(handlerTag in this.gestures)) {\n return;\n }\n\n this.gestures[handlerTag].onDestroy();\n\n // eslint-disable-next-line @typescript-eslint/no-dynamic-delete\n delete this.gestures[handlerTag];\n }\n\n public static getNodes() {\n return { ...this.gestures };\n }\n}\n"]}

View File

@@ -0,0 +1,241 @@
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
import EventManager from './EventManager';
import { MouseButton } from '../../handlers/gestureHandlerCommon';
import { EventTypes } from '../interfaces';
import { PointerTypeMapping, isPointerInBounds } from '../utils';
import { PointerType } from '../../PointerType';
const POINTER_CAPTURE_EXCLUDE_LIST = new Set(['SELECT', 'INPUT']);
const PointerTypes = {
Touch: 'touch',
Stylus: 'pen'
};
export default class PointerEventManager extends EventManager {
constructor(view) {
super(view);
_defineProperty(this, "trackedPointers", new Set());
_defineProperty(this, "mouseButtonsMapper", new Map());
_defineProperty(this, "lastPosition", void 0);
_defineProperty(this, "pointerDownCallback", event => {
if (event.pointerType === PointerTypes.Touch) {
return;
}
if (!isPointerInBounds(this.view, {
x: event.clientX,
y: event.clientY
})) {
return;
}
const adaptedEvent = this.mapEvent(event, EventTypes.DOWN);
const target = event.target;
if (!POINTER_CAPTURE_EXCLUDE_LIST.has(target.tagName)) {
target.setPointerCapture(adaptedEvent.pointerId);
}
this.markAsInBounds(adaptedEvent.pointerId);
this.trackedPointers.add(adaptedEvent.pointerId);
if (++this.activePointersCounter > 1) {
adaptedEvent.eventType = EventTypes.ADDITIONAL_POINTER_DOWN;
this.onPointerAdd(adaptedEvent);
} else {
this.onPointerDown(adaptedEvent);
}
});
_defineProperty(this, "pointerUpCallback", event => {
if (event.pointerType === PointerTypes.Touch) {
return;
} // When we call reset on gesture handlers, it also resets their event managers
// In some handlers (like RotationGestureHandler) reset is called before all pointers leave view
// This means, that activePointersCounter will be set to 0, while there are still remaining pointers on view
// Removing them will end in activePointersCounter going below 0, therefore handlers won't behave properly
if (this.activePointersCounter === 0) {
return;
}
const adaptedEvent = this.mapEvent(event, EventTypes.UP);
const target = event.target;
if (!POINTER_CAPTURE_EXCLUDE_LIST.has(target.tagName)) {
target.releasePointerCapture(adaptedEvent.pointerId);
}
this.markAsOutOfBounds(adaptedEvent.pointerId);
this.trackedPointers.delete(adaptedEvent.pointerId);
if (--this.activePointersCounter > 0) {
adaptedEvent.eventType = EventTypes.ADDITIONAL_POINTER_UP;
this.onPointerRemove(adaptedEvent);
} else {
this.onPointerUp(adaptedEvent);
}
});
_defineProperty(this, "pointerMoveCallback", event => {
if (event.pointerType === PointerTypes.Touch) {
return;
} // Stylus triggers `pointermove` event when it detects changes in pressure. Since it is very sensitive to those changes,
// it constantly sends events, even though there was no change in position. To fix that we check whether
// pointer has actually moved and if not, we do not send event.
if (event.pointerType === PointerTypes.Stylus && event.x === this.lastPosition.x && event.y === this.lastPosition.y) {
return;
}
const adaptedEvent = this.mapEvent(event, EventTypes.MOVE);
const target = event.target; // You may be wondering why are we setting pointer capture here, when we
// already set it in `pointerdown` handler. Well, that's a great question,
// for which I don't have an answer. Specification (https://www.w3.org/TR/pointerevents2/#dom-element-setpointercapture)
// says that the requirement for `setPointerCapture` to work is that pointer
// must be in 'active buttons state`, otherwise it will fail silently, which
// is lovely. Obviously, when `pointerdown` is fired, one of the buttons
// (when using mouse) is pressed, but that doesn't mean that `setPointerCapture`
// will succeed, for some reason. Since it fails silently, we don't actually know
// if it worked or not (there's `gotpointercapture` event, but the complexity of
// incorporating it here seems stupid), so we just call it again here, every time
// pointer moves until it succeeds.
// God, I do love web development.
if (!target.hasPointerCapture(event.pointerId) && !POINTER_CAPTURE_EXCLUDE_LIST.has(target.tagName)) {
target.setPointerCapture(event.pointerId);
}
const inBounds = isPointerInBounds(this.view, {
x: adaptedEvent.x,
y: adaptedEvent.y
});
const pointerIndex = this.pointersInBounds.indexOf(adaptedEvent.pointerId);
if (inBounds) {
if (pointerIndex < 0) {
adaptedEvent.eventType = EventTypes.ENTER;
this.onPointerEnter(adaptedEvent);
this.markAsInBounds(adaptedEvent.pointerId);
} else {
this.onPointerMove(adaptedEvent);
}
} else {
if (pointerIndex >= 0) {
adaptedEvent.eventType = EventTypes.LEAVE;
this.onPointerLeave(adaptedEvent);
this.markAsOutOfBounds(adaptedEvent.pointerId);
} else {
this.onPointerOutOfBounds(adaptedEvent);
}
}
this.lastPosition.x = event.x;
this.lastPosition.y = event.y;
});
_defineProperty(this, "pointerCancelCallback", event => {
if (event.pointerType === PointerTypes.Touch) {
return;
}
const adaptedEvent = this.mapEvent(event, EventTypes.CANCEL);
this.onPointerCancel(adaptedEvent);
this.markAsOutOfBounds(adaptedEvent.pointerId);
this.activePointersCounter = 0;
this.trackedPointers.clear();
});
_defineProperty(this, "pointerEnterCallback", event => {
if (event.pointerType === PointerTypes.Touch) {
return;
}
const adaptedEvent = this.mapEvent(event, EventTypes.ENTER);
this.onPointerMoveOver(adaptedEvent);
});
_defineProperty(this, "pointerLeaveCallback", event => {
if (event.pointerType === PointerTypes.Touch) {
return;
}
const adaptedEvent = this.mapEvent(event, EventTypes.LEAVE);
this.onPointerMoveOut(adaptedEvent);
});
_defineProperty(this, "lostPointerCaptureCallback", event => {
const adaptedEvent = this.mapEvent(event, EventTypes.CANCEL);
if (this.trackedPointers.has(adaptedEvent.pointerId)) {
// in some cases the `pointerup` event is not fired, but `lostpointercapture` is
// we simulate the `pointercancel` event here to make sure the gesture handler stops tracking it
this.onPointerCancel(adaptedEvent);
this.activePointersCounter = 0;
this.trackedPointers.clear();
}
});
this.mouseButtonsMapper.set(0, MouseButton.LEFT);
this.mouseButtonsMapper.set(1, MouseButton.MIDDLE);
this.mouseButtonsMapper.set(2, MouseButton.RIGHT);
this.mouseButtonsMapper.set(3, MouseButton.BUTTON_4);
this.mouseButtonsMapper.set(4, MouseButton.BUTTON_5);
this.lastPosition = {
x: -Infinity,
y: -Infinity
};
}
registerListeners() {
this.view.addEventListener('pointerdown', this.pointerDownCallback);
this.view.addEventListener('pointerup', this.pointerUpCallback);
this.view.addEventListener('pointermove', this.pointerMoveCallback);
this.view.addEventListener('pointercancel', this.pointerCancelCallback); // onPointerEnter and onPointerLeave are triggered by a custom logic responsible for
// handling shouldCancelWhenOutside flag, and are unreliable unless the pointer is down.
// We therefore use pointerenter and pointerleave events to handle the hover gesture,
// mapping them to onPointerMoveOver and onPointerMoveOut respectively.
this.view.addEventListener('pointerenter', this.pointerEnterCallback);
this.view.addEventListener('pointerleave', this.pointerLeaveCallback);
this.view.addEventListener('lostpointercapture', this.lostPointerCaptureCallback);
}
unregisterListeners() {
this.view.removeEventListener('pointerdown', this.pointerDownCallback);
this.view.removeEventListener('pointerup', this.pointerUpCallback);
this.view.removeEventListener('pointermove', this.pointerMoveCallback);
this.view.removeEventListener('pointercancel', this.pointerCancelCallback);
this.view.removeEventListener('pointerenter', this.pointerEnterCallback);
this.view.removeEventListener('pointerleave', this.pointerLeaveCallback);
this.view.removeEventListener('lostpointercapture', this.lostPointerCaptureCallback);
}
mapEvent(event, eventType) {
var _PointerTypeMapping$g;
return {
x: event.clientX,
y: event.clientY,
offsetX: event.offsetX,
offsetY: event.offsetY,
pointerId: event.pointerId,
eventType: eventType,
pointerType: (_PointerTypeMapping$g = PointerTypeMapping.get(event.pointerType)) !== null && _PointerTypeMapping$g !== void 0 ? _PointerTypeMapping$g : PointerType.OTHER,
button: this.mouseButtonsMapper.get(event.button),
time: event.timeStamp
};
}
resetManager() {
super.resetManager();
this.trackedPointers.clear();
}
}
//# sourceMappingURL=PointerEventManager.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,213 @@
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
import VelocityTracker from './VelocityTracker';
const MAX_POINTERS = 20;
export default class PointerTracker {
constructor() {
_defineProperty(this, "velocityTracker", new VelocityTracker());
_defineProperty(this, "trackedPointers", new Map());
_defineProperty(this, "touchEventsIds", new Map());
_defineProperty(this, "lastMovedPointerId", void 0);
_defineProperty(this, "cachedAverages", {
x: 0,
y: 0
});
this.lastMovedPointerId = NaN;
for (let i = 0; i < MAX_POINTERS; ++i) {
this.touchEventsIds.set(i, NaN);
}
}
addToTracker(event) {
if (this.trackedPointers.has(event.pointerId)) {
return;
}
this.lastMovedPointerId = event.pointerId;
const newElement = {
lastX: event.x,
lastY: event.y,
timeStamp: event.time,
velocityX: 0,
velocityY: 0
};
this.trackedPointers.set(event.pointerId, newElement);
this.mapTouchEventId(event.pointerId);
this.cachedAverages = {
x: this.getLastAvgX(),
y: this.getLastAvgY()
};
}
removeFromTracker(pointerId) {
this.trackedPointers.delete(pointerId);
this.removeMappedTouchId(pointerId);
}
track(event) {
const element = this.trackedPointers.get(event.pointerId);
if (!element) {
return;
}
this.lastMovedPointerId = event.pointerId;
this.velocityTracker.add(event);
const [velocityX, velocityY] = this.velocityTracker.getVelocity();
element.velocityX = velocityX;
element.velocityY = velocityY;
element.lastX = event.x;
element.lastY = event.y;
this.trackedPointers.set(event.pointerId, element);
const avgX = this.getLastAvgX();
const avgY = this.getLastAvgY();
this.cachedAverages = {
x: avgX,
y: avgY
};
} //Mapping TouchEvents ID
mapTouchEventId(id) {
for (const [mappedId, touchId] of this.touchEventsIds) {
if (isNaN(touchId)) {
this.touchEventsIds.set(mappedId, id);
break;
}
}
}
removeMappedTouchId(id) {
const mappedId = this.getMappedTouchEventId(id);
if (!isNaN(mappedId)) {
this.touchEventsIds.set(mappedId, NaN);
}
}
getMappedTouchEventId(touchEventId) {
for (const [key, value] of this.touchEventsIds.entries()) {
if (value === touchEventId) {
return key;
}
}
return NaN;
}
getVelocityX(pointerId) {
var _this$trackedPointers;
return (_this$trackedPointers = this.trackedPointers.get(pointerId)) === null || _this$trackedPointers === void 0 ? void 0 : _this$trackedPointers.velocityX;
}
getVelocityY(pointerId) {
var _this$trackedPointers2;
return (_this$trackedPointers2 = this.trackedPointers.get(pointerId)) === null || _this$trackedPointers2 === void 0 ? void 0 : _this$trackedPointers2.velocityY;
}
/**
* Returns X coordinate of last moved pointer
*/
getLastX(pointerId) {
if (pointerId !== undefined) {
var _this$trackedPointers3;
return (_this$trackedPointers3 = this.trackedPointers.get(pointerId)) === null || _this$trackedPointers3 === void 0 ? void 0 : _this$trackedPointers3.lastX;
} else {
var _this$trackedPointers4;
return (_this$trackedPointers4 = this.trackedPointers.get(this.lastMovedPointerId)) === null || _this$trackedPointers4 === void 0 ? void 0 : _this$trackedPointers4.lastX;
}
}
/**
* Returns Y coordinate of last moved pointer
*/
getLastY(pointerId) {
if (pointerId !== undefined) {
var _this$trackedPointers5;
return (_this$trackedPointers5 = this.trackedPointers.get(pointerId)) === null || _this$trackedPointers5 === void 0 ? void 0 : _this$trackedPointers5.lastY;
} else {
var _this$trackedPointers6;
return (_this$trackedPointers6 = this.trackedPointers.get(this.lastMovedPointerId)) === null || _this$trackedPointers6 === void 0 ? void 0 : _this$trackedPointers6.lastY;
}
} // Some handlers use these methods to send average values in native event.
// This may happen when pointers have already been removed from tracker (i.e. pointerup event).
// In situation when NaN would be sent as a response, we return cached value.
// That prevents handlers from crashing
getLastAvgX() {
const avgX = this.getSumX() / this.trackedPointers.size;
return isNaN(avgX) ? this.cachedAverages.x : avgX;
}
getLastAvgY() {
const avgY = this.getSumY() / this.trackedPointers.size;
return isNaN(avgY) ? this.cachedAverages.y : avgY;
}
getSumX(ignoredPointer) {
let sumX = 0;
this.trackedPointers.forEach((value, key) => {
if (key !== ignoredPointer) {
sumX += value.lastX;
}
});
return sumX;
}
getSumY(ignoredPointer) {
let sumY = 0;
this.trackedPointers.forEach((value, key) => {
if (key !== ignoredPointer) {
sumY += value.lastY;
}
});
return sumY;
}
getTrackedPointersCount() {
return this.trackedPointers.size;
}
getTrackedPointersID() {
const keys = [];
this.trackedPointers.forEach((_value, key) => {
keys.push(key);
});
return keys;
}
getData() {
return this.trackedPointers;
}
resetTracker() {
this.velocityTracker.reset();
this.trackedPointers.clear();
this.lastMovedPointerId = NaN;
for (let i = 0; i < MAX_POINTERS; ++i) {
this.touchEventsIds.set(i, NaN);
}
}
static shareCommonPointers(stPointers, ndPointers) {
return stPointers.some(pointerId => ndPointers.includes(pointerId));
}
}
//# sourceMappingURL=PointerTracker.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,145 @@
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
import { EventTypes, TouchEventType } from '../interfaces';
import EventManager from './EventManager';
import { isPointerInBounds } from '../utils';
import { PointerType } from '../../PointerType';
export default class TouchEventManager extends EventManager {
constructor(...args) {
super(...args);
_defineProperty(this, "touchStartCallback", event => {
for (let i = 0; i < event.changedTouches.length; ++i) {
const adaptedEvent = this.mapEvent(event, EventTypes.DOWN, i, TouchEventType.DOWN); // Here we skip stylus, because in case of anything different than touch we want to handle it by using PointerEvents
// If we leave stylus to send touch events, handlers will receive every action twice
if (!isPointerInBounds(this.view, {
x: adaptedEvent.x,
y: adaptedEvent.y
}) || //@ts-ignore touchType field does exist
event.changedTouches[i].touchType === 'stylus') {
continue;
}
this.markAsInBounds(adaptedEvent.pointerId);
if (++this.activePointersCounter > 1) {
adaptedEvent.eventType = EventTypes.ADDITIONAL_POINTER_DOWN;
this.onPointerAdd(adaptedEvent);
} else {
this.onPointerDown(adaptedEvent);
}
}
});
_defineProperty(this, "touchMoveCallback", event => {
for (let i = 0; i < event.changedTouches.length; ++i) {
const adaptedEvent = this.mapEvent(event, EventTypes.MOVE, i, TouchEventType.MOVE); //@ts-ignore touchType field does exist
if (event.changedTouches[i].touchType === 'stylus') {
continue;
}
const inBounds = isPointerInBounds(this.view, {
x: adaptedEvent.x,
y: adaptedEvent.y
});
const pointerIndex = this.pointersInBounds.indexOf(adaptedEvent.pointerId);
if (inBounds) {
if (pointerIndex < 0) {
adaptedEvent.eventType = EventTypes.ENTER;
this.onPointerEnter(adaptedEvent);
this.markAsInBounds(adaptedEvent.pointerId);
} else {
this.onPointerMove(adaptedEvent);
}
} else {
if (pointerIndex >= 0) {
adaptedEvent.eventType = EventTypes.LEAVE;
this.onPointerLeave(adaptedEvent);
this.markAsOutOfBounds(adaptedEvent.pointerId);
} else {
this.onPointerOutOfBounds(adaptedEvent);
}
}
}
});
_defineProperty(this, "touchEndCallback", event => {
for (let i = 0; i < event.changedTouches.length; ++i) {
// When we call reset on gesture handlers, it also resets their event managers
// In some handlers (like RotationGestureHandler) reset is called before all pointers leave view
// This means, that activePointersCounter will be set to 0, while there are still remaining pointers on view
// Removing them will end in activePointersCounter going below 0, therefore handlers won't behave properly
if (this.activePointersCounter === 0) {
break;
} //@ts-ignore touchType field does exist
if (event.changedTouches[i].touchType === 'stylus') {
continue;
}
const adaptedEvent = this.mapEvent(event, EventTypes.UP, i, TouchEventType.UP);
this.markAsOutOfBounds(adaptedEvent.pointerId);
if (--this.activePointersCounter > 0) {
adaptedEvent.eventType = EventTypes.ADDITIONAL_POINTER_UP;
this.onPointerRemove(adaptedEvent);
} else {
this.onPointerUp(adaptedEvent);
}
}
});
_defineProperty(this, "touchCancelCallback", event => {
for (let i = 0; i < event.changedTouches.length; ++i) {
const adaptedEvent = this.mapEvent(event, EventTypes.CANCEL, i, TouchEventType.CANCELLED); //@ts-ignore touchType field does exist
if (event.changedTouches[i].touchType === 'stylus') {
continue;
}
this.onPointerCancel(adaptedEvent);
this.markAsOutOfBounds(adaptedEvent.pointerId);
this.activePointersCounter = 0;
}
});
}
registerListeners() {
this.view.addEventListener('touchstart', this.touchStartCallback);
this.view.addEventListener('touchmove', this.touchMoveCallback);
this.view.addEventListener('touchend', this.touchEndCallback);
this.view.addEventListener('touchcancel', this.touchCancelCallback);
}
unregisterListeners() {
this.view.removeEventListener('touchstart', this.touchStartCallback);
this.view.removeEventListener('touchmove', this.touchMoveCallback);
this.view.removeEventListener('touchend', this.touchEndCallback);
this.view.removeEventListener('touchcancel', this.touchCancelCallback);
}
mapEvent(event, eventType, index, touchEventType) {
const rect = this.view.getBoundingClientRect();
const clientX = event.changedTouches[index].clientX;
const clientY = event.changedTouches[index].clientY;
return {
x: clientX,
y: clientY,
offsetX: clientX - rect.left,
offsetY: clientY - rect.top,
pointerId: event.changedTouches[index].identifier,
eventType: eventType,
pointerType: PointerType.TOUCH,
time: event.timeStamp,
allTouches: event.touches,
changedTouches: event.changedTouches,
touchEventType: touchEventType
};
}
}
//# sourceMappingURL=TouchEventManager.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,47 @@
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
import { DiagonalDirections, Directions } from '../../Directions';
import { MINIMAL_FLING_VELOCITY } from '../constants';
export default class Vector {
constructor(x, y) {
_defineProperty(this, "x", void 0);
_defineProperty(this, "y", void 0);
_defineProperty(this, "unitX", void 0);
_defineProperty(this, "unitY", void 0);
_defineProperty(this, "_magnitude", void 0);
this.x = x;
this.y = y;
this._magnitude = Math.hypot(this.x, this.y);
const isMagnitudeSufficient = this._magnitude > MINIMAL_FLING_VELOCITY;
this.unitX = isMagnitudeSufficient ? this.x / this._magnitude : 0;
this.unitY = isMagnitudeSufficient ? this.y / this._magnitude : 0;
}
static fromDirection(direction) {
return DirectionToVectorMappings.get(direction);
}
static fromVelocity(tracker, pointerId) {
return new Vector(tracker.getVelocityX(pointerId), tracker.getVelocityY(pointerId));
}
get magnitude() {
return this._magnitude;
}
computeSimilarity(vector) {
return this.unitX * vector.unitX + this.unitY * vector.unitY;
}
isSimilar(vector, threshold) {
return this.computeSimilarity(vector) > threshold;
}
}
const DirectionToVectorMappings = new Map([[Directions.LEFT, new Vector(-1, 0)], [Directions.RIGHT, new Vector(1, 0)], [Directions.UP, new Vector(0, -1)], [Directions.DOWN, new Vector(0, 1)], [DiagonalDirections.UP_RIGHT, new Vector(1, -1)], [DiagonalDirections.DOWN_RIGHT, new Vector(1, 1)], [DiagonalDirections.UP_LEFT, new Vector(-1, -1)], [DiagonalDirections.DOWN_LEFT, new Vector(-1, 1)]]);
//# sourceMappingURL=Vector.js.map

View File

@@ -0,0 +1 @@
{"version":3,"sources":["Vector.ts"],"names":["DiagonalDirections","Directions","MINIMAL_FLING_VELOCITY","Vector","constructor","x","y","_magnitude","Math","hypot","isMagnitudeSufficient","unitX","unitY","fromDirection","direction","DirectionToVectorMappings","get","fromVelocity","tracker","pointerId","getVelocityX","getVelocityY","magnitude","computeSimilarity","vector","isSimilar","threshold","Map","LEFT","RIGHT","UP","DOWN","UP_RIGHT","DOWN_RIGHT","UP_LEFT","DOWN_LEFT"],"mappings":";;AAAA,SAASA,kBAAT,EAA6BC,UAA7B,QAA+C,kBAA/C;AACA,SAASC,sBAAT,QAAuC,cAAvC;AAGA,eAAe,MAAMC,MAAN,CAAa;AAO1BC,EAAAA,WAAW,CAACC,CAAD,EAAYC,CAAZ,EAAuB;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAChC,SAAKD,CAAL,GAASA,CAAT;AACA,SAAKC,CAAL,GAASA,CAAT;AAEA,SAAKC,UAAL,GAAkBC,IAAI,CAACC,KAAL,CAAW,KAAKJ,CAAhB,EAAmB,KAAKC,CAAxB,CAAlB;AACA,UAAMI,qBAAqB,GAAG,KAAKH,UAAL,GAAkBL,sBAAhD;AAEA,SAAKS,KAAL,GAAaD,qBAAqB,GAAG,KAAKL,CAAL,GAAS,KAAKE,UAAjB,GAA8B,CAAhE;AACA,SAAKK,KAAL,GAAaF,qBAAqB,GAAG,KAAKJ,CAAL,GAAS,KAAKC,UAAjB,GAA8B,CAAhE;AACD;;AAEmB,SAAbM,aAAa,CAACC,SAAD,EAAqD;AACvE,WAAOC,yBAAyB,CAACC,GAA1B,CAA8BF,SAA9B,CAAP;AACD;;AAEkB,SAAZG,YAAY,CAACC,OAAD,EAA0BC,SAA1B,EAA6C;AAC9D,WAAO,IAAIhB,MAAJ,CACLe,OAAO,CAACE,YAAR,CAAqBD,SAArB,CADK,EAELD,OAAO,CAACG,YAAR,CAAqBF,SAArB,CAFK,CAAP;AAID;;AAEY,MAATG,SAAS,GAAG;AACd,WAAO,KAAKf,UAAZ;AACD;;AAEDgB,EAAAA,iBAAiB,CAACC,MAAD,EAAiB;AAChC,WAAO,KAAKb,KAAL,GAAaa,MAAM,CAACb,KAApB,GAA4B,KAAKC,KAAL,GAAaY,MAAM,CAACZ,KAAvD;AACD;;AAEDa,EAAAA,SAAS,CAACD,MAAD,EAAiBE,SAAjB,EAAoC;AAC3C,WAAO,KAAKH,iBAAL,CAAuBC,MAAvB,IAAiCE,SAAxC;AACD;;AAvCyB;AA0C5B,MAAMX,yBAAyB,GAAG,IAAIY,GAAJ,CAGhC,CACA,CAAC1B,UAAU,CAAC2B,IAAZ,EAAkB,IAAIzB,MAAJ,CAAW,CAAC,CAAZ,EAAe,CAAf,CAAlB,CADA,EAEA,CAACF,UAAU,CAAC4B,KAAZ,EAAmB,IAAI1B,MAAJ,CAAW,CAAX,EAAc,CAAd,CAAnB,CAFA,EAGA,CAACF,UAAU,CAAC6B,EAAZ,EAAgB,IAAI3B,MAAJ,CAAW,CAAX,EAAc,CAAC,CAAf,CAAhB,CAHA,EAIA,CAACF,UAAU,CAAC8B,IAAZ,EAAkB,IAAI5B,MAAJ,CAAW,CAAX,EAAc,CAAd,CAAlB,CAJA,EAMA,CAACH,kBAAkB,CAACgC,QAApB,EAA8B,IAAI7B,MAAJ,CAAW,CAAX,EAAc,CAAC,CAAf,CAA9B,CANA,EAOA,CAACH,kBAAkB,CAACiC,UAApB,EAAgC,IAAI9B,MAAJ,CAAW,CAAX,EAAc,CAAd,CAAhC,CAPA,EAQA,CAACH,kBAAkB,CAACkC,OAApB,EAA6B,IAAI/B,MAAJ,CAAW,CAAC,CAAZ,EAAe,CAAC,CAAhB,CAA7B,CARA,EASA,CAACH,kBAAkB,CAACmC,SAApB,EAA+B,IAAIhC,MAAJ,CAAW,CAAC,CAAZ,EAAe,CAAf,CAA/B,CATA,CAHgC,CAAlC","sourcesContent":["import { DiagonalDirections, Directions } from '../../Directions';\nimport { MINIMAL_FLING_VELOCITY } from '../constants';\nimport PointerTracker from './PointerTracker';\n\nexport default class Vector {\n private readonly x;\n private readonly y;\n private readonly unitX;\n private readonly unitY;\n private readonly _magnitude;\n\n constructor(x: number, y: number) {\n this.x = x;\n this.y = y;\n\n this._magnitude = Math.hypot(this.x, this.y);\n const isMagnitudeSufficient = this._magnitude > MINIMAL_FLING_VELOCITY;\n\n this.unitX = isMagnitudeSufficient ? this.x / this._magnitude : 0;\n this.unitY = isMagnitudeSufficient ? this.y / this._magnitude : 0;\n }\n\n static fromDirection(direction: Directions | DiagonalDirections): Vector {\n return DirectionToVectorMappings.get(direction)!;\n }\n\n static fromVelocity(tracker: PointerTracker, pointerId: number) {\n return new Vector(\n tracker.getVelocityX(pointerId),\n tracker.getVelocityY(pointerId)\n );\n }\n\n get magnitude() {\n return this._magnitude;\n }\n\n computeSimilarity(vector: Vector) {\n return this.unitX * vector.unitX + this.unitY * vector.unitY;\n }\n\n isSimilar(vector: Vector, threshold: number) {\n return this.computeSimilarity(vector) > threshold;\n }\n}\n\nconst DirectionToVectorMappings = new Map<\n Directions | DiagonalDirections,\n Vector\n>([\n [Directions.LEFT, new Vector(-1, 0)],\n [Directions.RIGHT, new Vector(1, 0)],\n [Directions.UP, new Vector(0, -1)],\n [Directions.DOWN, new Vector(0, 1)],\n\n [DiagonalDirections.UP_RIGHT, new Vector(1, -1)],\n [DiagonalDirections.DOWN_RIGHT, new Vector(1, 1)],\n [DiagonalDirections.UP_LEFT, new Vector(-1, -1)],\n [DiagonalDirections.DOWN_LEFT, new Vector(-1, 1)],\n]);\n"]}

View File

@@ -0,0 +1,98 @@
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
import CircularBuffer from './CircularBuffer';
import LeastSquareSolver from './LeastSquareSolver';
export default class VelocityTracker {
constructor() {
_defineProperty(this, "assumePointerMoveStoppedMilliseconds", 40);
_defineProperty(this, "historySize", 20);
_defineProperty(this, "horizonMilliseconds", 300);
_defineProperty(this, "minSampleSize", 3);
_defineProperty(this, "samples", void 0);
this.samples = new CircularBuffer(this.historySize);
}
add(event) {
this.samples.push(event);
} /// Returns an estimate of the velocity of the object being tracked by the
/// tracker given the current information available to the tracker.
///
/// Information is added using [addPosition].
///
/// Returns null if there is no data on which to base an estimate.
getVelocityEstimate() {
const x = [];
const y = [];
const w = [];
const time = [];
let sampleCount = 0;
let index = this.samples.size - 1;
const newestSample = this.samples.get(index);
if (!newestSample) {
return null;
}
let previousSample = newestSample; // Starting with the most recent PointAtTime sample, iterate backwards while
// the samples represent continuous motion.
while (sampleCount < this.samples.size) {
const sample = this.samples.get(index);
const age = newestSample.time - sample.time;
const delta = Math.abs(sample.time - previousSample.time);
previousSample = sample;
if (age > this.horizonMilliseconds || delta > this.assumePointerMoveStoppedMilliseconds) {
break;
}
x.push(sample.x);
y.push(sample.y);
w.push(1);
time.push(-age);
sampleCount++;
index--;
}
if (sampleCount >= this.minSampleSize) {
const xSolver = new LeastSquareSolver(time, x, w);
const xFit = xSolver.solve(2);
if (xFit !== null) {
const ySolver = new LeastSquareSolver(time, y, w);
const yFit = ySolver.solve(2);
if (yFit !== null) {
const xVelocity = xFit.coefficients[1] * 1000;
const yVelocity = yFit.coefficients[1] * 1000;
return [xVelocity, yVelocity];
}
}
}
return null;
}
getVelocity() {
const estimate = this.getVelocityEstimate();
if (estimate !== null) {
return estimate;
}
return [0, 0];
}
reset() {
this.samples.clear();
}
}
//# sourceMappingURL=VelocityTracker.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,12 @@
import { PointerType } from '../PointerType';
export function isPointerInBounds(view, {
x,
y
}) {
const rect = view.getBoundingClientRect();
return x >= rect.left && x <= rect.right && y >= rect.top && y <= rect.bottom;
}
export const PointerTypeMapping = new Map([['mouse', PointerType.MOUSE], ['touch', PointerType.TOUCH], ['pen', PointerType.STYLUS], ['none', PointerType.OTHER]]);
export const degToRad = degrees => degrees * Math.PI / 180;
export const coneToDeviation = degrees => Math.cos(degToRad(degrees / 2));
//# sourceMappingURL=utils.js.map

View File

@@ -0,0 +1 @@
{"version":3,"sources":["utils.ts"],"names":["PointerType","isPointerInBounds","view","x","y","rect","getBoundingClientRect","left","right","top","bottom","PointerTypeMapping","Map","MOUSE","TOUCH","STYLUS","OTHER","degToRad","degrees","Math","PI","coneToDeviation","cos"],"mappings":"AAAA,SAASA,WAAT,QAA4B,gBAA5B;AAGA,OAAO,SAASC,iBAAT,CAA2BC,IAA3B,EAA8C;AAAEC,EAAAA,CAAF;AAAKC,EAAAA;AAAL,CAA9C,EAAwE;AAC7E,QAAMC,IAAa,GAAGH,IAAI,CAACI,qBAAL,EAAtB;AAEA,SAAOH,CAAC,IAAIE,IAAI,CAACE,IAAV,IAAkBJ,CAAC,IAAIE,IAAI,CAACG,KAA5B,IAAqCJ,CAAC,IAAIC,IAAI,CAACI,GAA/C,IAAsDL,CAAC,IAAIC,IAAI,CAACK,MAAvE;AACD;AAED,OAAO,MAAMC,kBAAkB,GAAG,IAAIC,GAAJ,CAA6B,CAC7D,CAAC,OAAD,EAAUZ,WAAW,CAACa,KAAtB,CAD6D,EAE7D,CAAC,OAAD,EAAUb,WAAW,CAACc,KAAtB,CAF6D,EAG7D,CAAC,KAAD,EAAQd,WAAW,CAACe,MAApB,CAH6D,EAI7D,CAAC,MAAD,EAASf,WAAW,CAACgB,KAArB,CAJ6D,CAA7B,CAA3B;AAOP,OAAO,MAAMC,QAAQ,GAAIC,OAAD,IAAsBA,OAAO,GAAGC,IAAI,CAACC,EAAhB,GAAsB,GAA5D;AAEP,OAAO,MAAMC,eAAe,GAAIH,OAAD,IAC7BC,IAAI,CAACG,GAAL,CAASL,QAAQ,CAACC,OAAO,GAAG,CAAX,CAAjB,CADK","sourcesContent":["import { PointerType } from '../PointerType';\nimport { Point } from './interfaces';\n\nexport function isPointerInBounds(view: HTMLElement, { x, y }: Point): boolean {\n const rect: DOMRect = view.getBoundingClientRect();\n\n return x >= rect.left && x <= rect.right && y >= rect.top && y <= rect.bottom;\n}\n\nexport const PointerTypeMapping = new Map<string, PointerType>([\n ['mouse', PointerType.MOUSE],\n ['touch', PointerType.TOUCH],\n ['pen', PointerType.STYLUS],\n ['none', PointerType.OTHER],\n]);\n\nexport const degToRad = (degrees: number) => (degrees * Math.PI) / 180;\n\nexport const coneToDeviation = (degrees: number) =>\n Math.cos(degToRad(degrees / 2));\n"]}