UNPKG

react-native-reanimated

Version:

More powerful alternative to Animated library for React Native.

189 lines (183 loc) • 6.99 kB
'use strict'; import { RNScreensTurboModule } from "./RNScreensTurboModule.js"; import { applyStyle, applyStyleForBelowTopScreen } from "./styleUpdater.js"; const BASE_VELOCITY = 400; const ADDITIONAL_VELOCITY_FACTOR_X = 400; const ADDITIONAL_VELOCITY_FACTOR_Y = 500; const ADDITIONAL_VELOCITY_FACTOR_XY = 600; function computeEasingProgress(startingTimestamp, distance, velocity) { 'worklet'; if (Math.abs(distance) < 1) { return 1; } const elapsedTime = (_getAnimationTimestamp() - startingTimestamp) / 1000; const currentPosition = velocity * elapsedTime; const progress = currentPosition / distance; return progress; } function easing(x) { 'worklet'; // based on https://easings.net/#easeOutQuart return 1 - Math.pow(1 - x, 5); } function computeProgress(screenTransitionConfig, event, isTransitionCanceled) { 'worklet'; const screenDimensions = screenTransitionConfig.screenDimensions; const progressX = Math.abs(event.translationX / screenDimensions.width); const progressY = Math.abs(event.translationY / screenDimensions.height); const maxProgress = Math.max(progressX, progressY); const progress = isTransitionCanceled ? maxProgress / 2 : maxProgress; return progress; } function maybeScheduleNextFrame(step, didScreenReachDestination, screenTransitionConfig, event, isTransitionCanceled) { 'worklet'; if (!didScreenReachDestination) { const stackTag = screenTransitionConfig.stackTag; const progress = computeProgress(screenTransitionConfig, event, isTransitionCanceled); RNScreensTurboModule.updateTransition(stackTag, progress); requestAnimationFrame(step); } else { screenTransitionConfig.onFinishAnimation?.(); } } export function getSwipeSimulator(event, screenTransitionConfig, lockAxis) { 'worklet'; const screenDimensions = screenTransitionConfig.screenDimensions; const startTimestamp = _getAnimationTimestamp(); const { isTransitionCanceled } = screenTransitionConfig; const startingPosition = { x: event.translationX, y: event.translationY }; const direction = { x: Math.sign(event.translationX), y: Math.sign(event.translationY) }; const finalPosition = isTransitionCanceled ? { x: 0, y: 0 } : { x: direction.x * screenDimensions.width, y: direction.y * screenDimensions.height }; const distance = { x: Math.abs(finalPosition.x - startingPosition.x), y: Math.abs(finalPosition.y - startingPosition.y) }; const didScreenReachDestination = { x: false, y: false }; const velocity = { x: BASE_VELOCITY, y: BASE_VELOCITY }; if (lockAxis === 'x') { velocity.y = 0; velocity.x += ADDITIONAL_VELOCITY_FACTOR_X * distance.x / screenDimensions.width; } else if (lockAxis === 'y') { velocity.x = 0; velocity.y += ADDITIONAL_VELOCITY_FACTOR_Y * distance.y / screenDimensions.height; } else { const euclideanDistance = Math.sqrt(distance.x ** 2 + distance.y ** 2); const screenDiagonal = Math.sqrt(screenDimensions.width ** 2 + screenDimensions.height ** 2); const velocityVectorLength = BASE_VELOCITY + ADDITIONAL_VELOCITY_FACTOR_XY * euclideanDistance / screenDiagonal; if (Math.abs(startingPosition.x) > Math.abs(startingPosition.y)) { velocity.x = velocityVectorLength; velocity.y = velocityVectorLength * Math.abs(startingPosition.y / startingPosition.x); } else { velocity.x = velocityVectorLength * Math.abs(startingPosition.x / startingPosition.y); velocity.y = velocityVectorLength; } } if (isTransitionCanceled) { function didScreenReachDestinationCheck() { if (lockAxis === 'x') { return didScreenReachDestination.x; } else if (lockAxis === 'y') { return didScreenReachDestination.y; } else { return didScreenReachDestination.x && didScreenReachDestination.y; } } function restoreOriginalStyleForBelowTopScreen() { event.translationX = direction.x * screenDimensions.width; event.translationY = direction.y * screenDimensions.height; applyStyleForBelowTopScreen(screenTransitionConfig, event); } const computeFrame = () => { const progress = { x: computeEasingProgress(startTimestamp, distance.x, velocity.x), y: computeEasingProgress(startTimestamp, distance.y, velocity.y) }; event.translationX = startingPosition.x - direction.x * distance.x * easing(progress.x); event.translationY = startingPosition.y - direction.y * distance.y * easing(progress.y); if (direction.x > 0) { if (event.translationX <= 0) { didScreenReachDestination.x = true; event.translationX = 0; } } else { if (event.translationX >= 0) { didScreenReachDestination.x = true; event.translationX = 0; } } if (direction.y > 0) { if (event.translationY <= 0) { didScreenReachDestination.y = true; event.translationY = 0; } } else { if (event.translationY >= 0) { didScreenReachDestination.y = true; event.translationY = 0; } } applyStyle(screenTransitionConfig, event); const finished = didScreenReachDestinationCheck(); if (finished) { restoreOriginalStyleForBelowTopScreen(); } maybeScheduleNextFrame(computeFrame, finished, screenTransitionConfig, event, isTransitionCanceled); }; return computeFrame; } else { const computeFrame = () => { const progress = { x: computeEasingProgress(startTimestamp, distance.x, velocity.x), y: computeEasingProgress(startTimestamp, distance.y, velocity.y) }; event.translationX = startingPosition.x + direction.x * distance.x * easing(progress.x); event.translationY = startingPosition.y + direction.y * distance.y * easing(progress.y); if (direction.x > 0) { if (event.translationX >= screenDimensions.width) { didScreenReachDestination.x = true; event.translationX = screenDimensions.width; } } else { if (event.translationX <= -screenDimensions.width) { didScreenReachDestination.x = true; event.translationX = -screenDimensions.width; } } if (direction.y > 0) { if (event.translationY >= screenDimensions.height) { didScreenReachDestination.y = true; event.translationY = screenDimensions.height; } } else { if (event.translationY <= -screenDimensions.height) { didScreenReachDestination.y = true; event.translationY = -screenDimensions.height; } } applyStyle(screenTransitionConfig, event); maybeScheduleNextFrame(computeFrame, didScreenReachDestination.x || didScreenReachDestination.y, screenTransitionConfig, event, isTransitionCanceled); }; return computeFrame; } } //# sourceMappingURL=swipeSimulator.js.map