UNPKG

react-native-zoom-toolkit

Version:

Smoothly zoom any image, video or component you want!

157 lines (153 loc) 5.5 kB
import { cancelAnimation, withTiming, useSharedValue, withDecay, runOnJS } from 'react-native-reanimated'; import { clamp } from '../utils/clamp'; import { friction } from '../utils/friction'; import { PanMode } from '../types'; import { useVector } from './useVector'; import { getSwipeDirection } from '../utils/getSwipeDirection'; const DECELERATION = 0.9955; export const usePanCommons = options => { const { container, detectorTranslate, translate, offset, panMode, scale, decay, boundFn, userCallbacks } = options; 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); cancelAnimation(detectorTranslate.x); cancelAnimation(detectorTranslate.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(scale.value); 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) && userCallbacks.onOverPanning) { const ex = Math.sign(toX) * exceedX; const ey = Math.sign(toY) * exceedY; userCallbacks.onOverPanning(ex, ey); } // Simplify both free and clamp pan modes in one condition due to their similarity if (panMode !== PanMode.FRICTION) { const isFree = panMode === PanMode.FREE; translate.x.value = isFree ? toX : clamp(toX, -1 * boundX, boundX); translate.y.value = isFree ? toY : clamp(toY, -1 * boundY, boundY); detectorTranslate.x.value = translate.x.value; detectorTranslate.y.value = translate.y.value; 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 === PanMode.CLAMP && userCallbacks.onSwipe) { const boundaries = boundFn(scale.value); 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(userCallbacks.onSwipe)(direction); return; } } userCallbacks.onPanEnd && runOnJS(userCallbacks.onPanEnd)(e); const { x: boundX, y: boundY } = boundFn(scale.value); 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, deceleration: DECELERATION }; const decayConfigY = { velocity: e.velocityY, clamp: clampY, deceleration: DECELERATION }; detectorTranslate.x.value = translate.x.value; detectorTranslate.x.value = decayX ? withDecay(decayConfigX) : withTiming(toX); translate.x.value = decayX ? withDecay(decayConfigX) : withTiming(toX); detectorTranslate.y.value = translate.y.value; detectorTranslate.y.value = decayY ? withDecay(decayConfigY) : withTiming(toY); translate.y.value = decayY ? withDecay(decayConfigY) : withTiming(toY); const restX = Math.max(0, Math.abs(translate.x.value) - boundX); const restY = Math.max(0, 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 => { if (finished && userCallbacks.onGestureEnd) { runOnJS(userCallbacks.onGestureEnd)(); } }); } else { const toValue = restX > restY ? toX : toY; gestureEnd.value = withTiming(toValue, undefined, finished => { if (finished && userCallbacks.onGestureEnd) { runOnJS(userCallbacks.onGestureEnd)(); } }); } }; return { onPanStart, onPanChange, onPanEnd }; }; //# sourceMappingURL=usePanCommons.js.map