UNPKG

react-native-gesture-handler

Version:

Experimental implementation of a new declarative API for gesture handling in react-native

164 lines (139 loc) 5.06 kB
import { AdaptedEvent, EventTypes, MouseButtons, PointerType, } from '../interfaces'; import EventManager from './EventManager'; import { isPointerInBounds } from '../utils'; export default class PointerEventManager extends EventManager { private trackedPointers = new Set<number>(); public setListeners(): void { this.view.addEventListener('pointerdown', (event: PointerEvent): void => { if (event.pointerType === PointerType.TOUCH) { return; } if ( !isPointerInBounds(this.view, { x: event.clientX, y: event.clientY }) ) { return; } const adaptedEvent: AdaptedEvent = this.mapEvent(event, EventTypes.DOWN); const target = event.target as HTMLElement; 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); } }); this.view.addEventListener('pointerup', (event: PointerEvent): void => { if (event.pointerType === PointerType.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: AdaptedEvent = this.mapEvent(event, EventTypes.UP); const target = event.target as HTMLElement; 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); } }); this.view.addEventListener('pointermove', (event: PointerEvent): void => { if (event.pointerType === PointerType.TOUCH) { return; } if ( event.pointerType === PointerType.MOUSE && event.buttons !== MouseButtons.LEFT ) { return; } const adaptedEvent: AdaptedEvent = this.mapEvent(event, EventTypes.MOVE); const inBounds: boolean = isPointerInBounds(this.view, { x: adaptedEvent.x, y: adaptedEvent.y, }); const pointerIndex: number = 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.OUT; this.onPointerOut(adaptedEvent); this.markAsOutOfBounds(adaptedEvent.pointerId); } else { this.onPointerOutOfBounds(adaptedEvent); } } }); this.view.addEventListener('pointercancel', (event: PointerEvent): void => { if (event.pointerType === PointerType.TOUCH) { return; } const adaptedEvent: AdaptedEvent = this.mapEvent( event, EventTypes.CANCEL ); this.onPointerCancel(adaptedEvent); this.markAsOutOfBounds(adaptedEvent.pointerId); this.activePointersCounter = 0; this.trackedPointers.clear(); }); this.view.addEventListener( 'lostpointercapture', (event: PointerEvent): void => { const adaptedEvent: 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(); } } ); } protected mapEvent(event: PointerEvent, eventType: EventTypes): AdaptedEvent { return { x: event.clientX, y: event.clientY, offsetX: event.offsetX, offsetY: event.offsetY, pointerId: event.pointerId, eventType: eventType, pointerType: event.pointerType as PointerType, buttons: event.buttons, time: event.timeStamp, }; } public resetManager(): void { super.resetManager(); this.trackedPointers.clear(); } }