UNPKG

@shopify/react-native-skia

Version:

High-performance React Native Graphics using Skia

108 lines (95 loc) 3.63 kB
import type { DependencyList } from "react"; import { useCallback, useRef } from "react"; import type { Vector } from "../skia/types"; import { Platform } from "../Platform"; import type { ExtendedTouchInfo, TouchHandlers, TouchHandler, TouchInfo, } from "./types"; import { TouchType } from "./types"; const useInternalTouchHandler = ( handlers: TouchHandlers, deps: DependencyList = [], multiTouch = false ): TouchHandler => { const prevTouchInfoRef = useRef<{ [key: number]: TouchInfo | undefined }>({}); const prevVelocityRef = useRef<{ [key: number]: Vector | undefined }>({}); return useCallback((history: Array<Array<TouchInfo>>) => { // Process all items in the current touch history history.forEach((touches) => { // Enumerate touches for (let i = 0; i < touches.length; i++) { if (!multiTouch && i > 0) { break; } const touch = touches[i]; const prevTouch = prevTouchInfoRef.current[touch.id]; // Calculate the velocity from the previous touch. const timeDiffseconds = touch.timestamp - (prevTouchInfoRef.current[touch.id]?.timestamp ?? touch.timestamp); const distX = touch.x - (prevTouch?.x ?? touch.x); const distY = touch.y - (prevTouch?.y ?? touch.y); if ( touch.type !== TouchType.Start && touch.type !== TouchType.End && touch.type !== TouchType.Cancelled && timeDiffseconds > 0 ) { prevVelocityRef.current[touch.id] = { x: distX / timeDiffseconds / Platform.PixelRatio, y: distY / timeDiffseconds / Platform.PixelRatio, }; } const extendedTouchInfo: ExtendedTouchInfo = { ...touch, velocityX: prevVelocityRef.current[touch.id]?.x ?? 0, velocityY: prevVelocityRef.current[touch.id]?.y ?? 0, }; // Save previous touch prevTouchInfoRef.current[touch.id] = touch; if (touch.type === TouchType.Start) { delete prevVelocityRef.current[touch.id]; handlers.onStart && handlers.onStart(touch); } else if (touch.type === TouchType.Active) { handlers.onActive && handlers.onActive(extendedTouchInfo); } else { handlers.onEnd && handlers.onEnd(extendedTouchInfo); } } }); // eslint-disable-next-line react-hooks/exhaustive-deps }, deps); }; /** * Provides a callback for handling touch events in the Skia View. * This touch handler only handles single touches. * @param handlers Callbacks for the different touch states * @param deps optional Dependency array to update the handlers * @returns A function that can be used from within the onDraw callback to * update and handle touch events. Call it with the touches property from * the info object. */ export const useTouchHandler = ( handlers: TouchHandlers, deps: DependencyList = [] ): TouchHandler => { return useInternalTouchHandler(handlers, deps, false); }; /** * Provides a callback for handling touch events in the Skia View. * This touch handler handles multiple touches. * @param handlers Callbacks for the different touch states * @param deps optional Dependency array to update the handlers * @returns A function that can be used from within the onDraw callback to * update and handle touch events. Call it with the touches property from * the info object. */ export const useMultiTouchHandler = ( handlers: TouchHandlers, deps: DependencyList = [] ): TouchHandler => { return useInternalTouchHandler(handlers, deps, true); };