UNPKG

react-native-zoom-toolkit

Version:

Most complete set of pinch to zoom utilites for React Native

144 lines (140 loc) 4.74 kB
import { cancelAnimation, withTiming, useSharedValue, withDecay, runOnJS } from 'react-native-reanimated'; import { clamp } from '../utils/clamp'; import { useVector } from './useVector'; import { friction } from '../utils/friction'; import { getSwipeDirection } from '../utils/getSwipeDirection'; export const usePanCommons = options => { const { container, translate, offset, panMode, decay, boundFn, userCallbacks } = options; const { onSwipe, onGestureEnd, onOverPanning } = userCallbacks; const time = useSharedValue(0); const position = useVector(0, 0); const gestureEnd = useSharedValue(0); // Gimmick value to trigger onGestureEnd callback const isWithinBoundX = useSharedValue(true); const isWithinBoundY = useSharedValue(true); const onPanStart = e => { 'worklet'; userCallbacks.onPanStart && runOnJS(userCallbacks.onPanStart)(e); cancelAnimation(translate.x); cancelAnimation(translate.y); offset.x.value = translate.x.value; offset.y.value = translate.y.value; time.value = performance.now(); position.x.value = e.absoluteX; position.y.value = e.absoluteY; }; const onPanChange = e => { 'worklet'; const toX = e.translationX + offset.x.value; const toY = e.translationY + offset.y.value; const { x: boundX, y: boundY } = boundFn(); const exceedX = Math.max(0, Math.abs(toX) - boundX); const exceedY = Math.max(0, Math.abs(toY) - boundY); isWithinBoundX.value = exceedX === 0; isWithinBoundY.value = exceedY === 0; if ((exceedX > 0 || exceedY > 0) && onOverPanning) { const ex = Math.sign(toX) * exceedX; const ey = Math.sign(toY) * exceedY; onOverPanning(ex, ey); } // Simplify both free and clamp pan modes in one condition due to their similarity if (panMode !== 'friction') { const isFree = panMode === 'free'; translate.x.value = isFree ? toX : clamp(toX, -1 * boundX, boundX); translate.y.value = isFree ? toY : clamp(toY, -1 * boundY, boundY); return; } const overScrollFraction = Math.max(container.width.value, container.height.value) * 1.5; if (isWithinBoundX.value) { translate.x.value = toX; } else { const fraction = Math.abs(Math.abs(toX) - boundX) / overScrollFraction; const frictionX = friction(clamp(fraction, 0, 1)); translate.x.value += e.changeX * frictionX; } if (isWithinBoundY.value) { translate.y.value = toY; } else { const fraction = Math.abs(Math.abs(toY) - boundY) / overScrollFraction; const frictionY = friction(clamp(fraction, 0, 1)); translate.y.value += e.changeY * frictionY; } }; const onPanEnd = e => { 'worklet'; if (panMode === 'clamp' && onSwipe) { const boundaries = boundFn(); const direction = getSwipeDirection(e, { boundaries, time: time.value, position: { x: position.x.value, y: position.y.value }, translate: { x: translate.x.value, y: translate.y.value } }); if (direction !== undefined) { runOnJS(onSwipe)(direction); return; } } userCallbacks.onPanEnd && runOnJS(userCallbacks.onPanEnd)(e); const { x: boundX, y: boundY } = boundFn(); const clampX = [-1 * boundX, boundX]; const clampY = [-1 * boundY, boundY]; const toX = clamp(translate.x.value, -1 * boundX, boundX); const toY = clamp(translate.y.value, -1 * boundY, boundY); const decayX = decay && isWithinBoundX.value; const decayY = decay && isWithinBoundY.value; const decayConfigX = { velocity: e.velocityX, clamp: clampX }; const decayConfigY = { velocity: e.velocityY, clamp: clampY }; translate.x.value = decayX ? withDecay(decayConfigX) : withTiming(toX); translate.y.value = decayY ? withDecay(decayConfigY) : withTiming(toY); const restX = Math.abs(Math.abs(translate.x.value) - boundX); const restY = Math.abs(Math.abs(translate.y.value) - boundY); gestureEnd.value = restX > restY ? translate.x.value : translate.y.value; if (decayX || decayY) { const config = restX > restY ? decayConfigX : decayConfigY; gestureEnd.value = withDecay(config, finished => { finished && onGestureEnd && runOnJS(onGestureEnd)(); }); } else { const toValue = restX > restY ? toX : toY; gestureEnd.value = withTiming(toValue, undefined, finished => { finished && onGestureEnd && runOnJS(onGestureEnd)(); }); } }; return { onPanStart, onPanChange, onPanEnd }; }; //# sourceMappingURL=usePanCommons.js.map