react-native-reanimated
Version:
More powerful alternative to Animated library for React Native.
189 lines (183 loc) • 6.99 kB
JavaScript
'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