UNPKG

react-native-gesture-handler

Version:

Declarative API exposing native platform touch and gesture system to React Native

157 lines (130 loc) 4.04 kB
import { State } from '../../State'; import { DEFAULT_TOUCH_SLOP } from '../constants'; import { AdaptedEvent } from '../interfaces'; import GestureHandler from './GestureHandler'; import ScaleGestureDetector, { ScaleGestureListener, } from '../detectors/ScaleGestureDetector'; export default class PinchGestureHandler extends GestureHandler { private scale = 1; private velocity = 0; private startingSpan = 0; private spanSlop = DEFAULT_TOUCH_SLOP; private scaleDetectorListener: ScaleGestureListener = { onScaleBegin: (detector: ScaleGestureDetector): boolean => { this.startingSpan = detector.getCurrentSpan(); return true; }, onScale: (detector: ScaleGestureDetector): boolean => { const prevScaleFactor: number = 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: ScaleGestureDetector // eslint-disable-next-line @typescript-eslint/no-empty-function ): void => {}, }; private scaleGestureDetector: ScaleGestureDetector = new ScaleGestureDetector( this.scaleDetectorListener ); public init(ref: number, propsRef: React.RefObject<unknown>) { super.init(ref, propsRef); this.setShouldCancelWhenOutside(false); } protected transformNativeEvent() { return { focalX: this.scaleGestureDetector.getFocusX(), focalY: this.scaleGestureDetector.getFocusY(), velocity: this.velocity, scale: this.scale, }; } protected onPointerDown(event: AdaptedEvent): void { this.tracker.addToTracker(event); super.onPointerDown(event); this.tryToSendTouchEvent(event); } protected onPointerAdd(event: AdaptedEvent): void { this.tracker.addToTracker(event); super.onPointerAdd(event); this.tryBegin(); this.scaleGestureDetector.onTouchEvent(event, this.tracker); } protected onPointerUp(event: AdaptedEvent): void { 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(); } } protected onPointerRemove(event: AdaptedEvent): void { 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(); } } protected onPointerMove(event: AdaptedEvent): void { if (this.tracker.getTrackedPointersCount() < 2) { return; } this.tracker.track(event); this.scaleGestureDetector.onTouchEvent(event, this.tracker); super.onPointerMove(event); } protected onPointerOutOfBounds(event: AdaptedEvent): void { if (this.tracker.getTrackedPointersCount() < 2) { return; } this.tracker.track(event); this.scaleGestureDetector.onTouchEvent(event, this.tracker); super.onPointerOutOfBounds(event); } private tryBegin(): void { if (this.currentState !== State.UNDETERMINED) { return; } this.resetProgress(); this.begin(); } public activate(force?: boolean): void { if (this.currentState !== State.ACTIVE) { this.resetProgress(); } super.activate(force); } protected onReset(): void { this.resetProgress(); } protected resetProgress(): void { if (this.currentState === State.ACTIVE) { return; } this.velocity = 0; this.scale = 1; } }