react-native-reanimated
Version:
More powerful alternative to Animated library for React Native.
180 lines (167 loc) • 5.32 kB
JavaScript
function bisectRoot(_ref) {
'worklet';
let {
min,
max,
func,
maxIterations = 20
} = _ref;
const ACCURACY = 0.00005;
let idx = maxIterations;
let current = (max + min) / 2;
while (Math.abs(func(current)) > ACCURACY && idx > 0) {
idx -= 1;
if (func(current) < 0) {
min = current;
} else {
max = current;
}
current = (min + max) / 2;
}
return current;
}
export function initialCalculations() {
'worklet';
let mass = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
let config = arguments.length > 1 ? arguments[1] : undefined;
if (config.configIsInvalid) {
return {
zeta: 0,
omega0: 0,
omega1: 0
};
}
if (config.useDuration) {
const {
stiffness: k,
dampingRatio: zeta
} = config;
/** omega0 and omega1 denote angular frequency and natural angular frequency, see this link for formulas:
* https://courses.lumenlearning.com/suny-osuniversityphysics/chapter/15-5-damped-oscillations/
*/
const omega0 = Math.sqrt(k / mass);
const omega1 = omega0 * Math.sqrt(1 - zeta ** 2);
return {
zeta,
omega0,
omega1
};
} else {
const {
damping: c,
mass: m,
stiffness: k
} = config;
const zeta = c / (2 * Math.sqrt(k * m)); // damping ratio
const omega0 = Math.sqrt(k / m); // undamped angular frequency of the oscillator (rad/ms)
const omega1 = omega0 * Math.sqrt(1 - zeta ** 2); // exponential decay
return {
zeta,
omega0,
omega1
};
}
}
export function calculateNewMassToMatchDuration(x0, config, v0) {
'worklet';
if (config.configIsInvalid) {
return 0;
}
/** Use this formula: https://phys.libretexts.org/Bookshelves/University_Physics/Book%3A_University_Physics_(OpenStax)/Book%3A_University_Physics_I_-_Mechanics_Sound_Oscillations_and_Waves_(OpenStax)/15%3A_Oscillations/15.06%3A_Damped_Oscillations
* to find the asymptote and estimate the damping that gives us the expected duration
⎛ ⎛ c⎞ ⎞
⎜-⎜──⎟ ⋅ duration⎟
⎝ ⎝2m⎠ ⎠
A ⋅ e = threshold
Amplitude calculated using "Conservation of energy"
_________________
╱ 2 2
╱ m ⋅ v0 + k ⋅ x0
amplitude = ╱ ─────────────────
╲╱ k
And replace mass with damping ratio which is provided: m = (c^2)/(4 * k * zeta^2)
*/
const {
stiffness: k,
dampingRatio: zeta,
restSpeedThreshold: threshold,
duration
} = config;
const durationForMass = mass => {
'worklet';
const amplitude = (mass * v0 * v0 + k * x0 * x0) / (Math.exp(1 - 0.5 * zeta) * k);
const c = zeta * 2 * Math.sqrt(k * mass);
return 1000 * (-2 * mass / c) * Math.log(threshold * 0.01 / amplitude) - duration;
};
// Bisection turns out to be much faster than Newton's method in our case
return bisectRoot({
min: 0,
max: 100,
func: durationForMass
});
}
export function criticallyDampedSpringCalculations(animation, precalculatedValues) {
'worklet';
const {
toValue
} = animation;
const {
v0,
x0,
omega0,
t
} = precalculatedValues;
const criticallyDampedEnvelope = Math.exp(-omega0 * t);
const criticallyDampedPosition = toValue - criticallyDampedEnvelope * (x0 + (v0 + omega0 * x0) * t);
const criticallyDampedVelocity = criticallyDampedEnvelope * (v0 * (t * omega0 - 1) + t * x0 * omega0 * omega0);
return {
position: criticallyDampedPosition,
velocity: criticallyDampedVelocity
};
}
export function underDampedSpringCalculations(animation, precalculatedValues) {
'worklet';
const {
toValue,
current,
velocity
} = animation;
const {
zeta,
t,
omega0,
omega1
} = precalculatedValues;
const v0 = -velocity;
const x0 = toValue - current;
const sin1 = Math.sin(omega1 * t);
const cos1 = Math.cos(omega1 * t);
// under damped
const underDampedEnvelope = Math.exp(-zeta * omega0 * t);
const underDampedFrag1 = underDampedEnvelope * (sin1 * ((v0 + zeta * omega0 * x0) / omega1) + x0 * cos1);
const underDampedPosition = toValue - underDampedFrag1;
// This looks crazy -- it's actually just the derivative of the oscillation function
const underDampedVelocity = zeta * omega0 * underDampedFrag1 - underDampedEnvelope * (cos1 * (v0 + zeta * omega0 * x0) - omega1 * x0 * sin1);
return {
position: underDampedPosition,
velocity: underDampedVelocity
};
}
export function isAnimationTerminatingCalculation(animation, config) {
'worklet';
const {
toValue,
velocity,
startValue,
current
} = animation;
const isOvershooting = config.overshootClamping ? current > toValue && startValue < toValue || current < toValue && startValue > toValue : false;
const isVelocity = Math.abs(velocity) < config.restSpeedThreshold;
const isDisplacement = Math.abs(toValue - current) < config.restDisplacementThreshold;
return {
isOvershooting,
isVelocity,
isDisplacement
};
}
//# sourceMappingURL=springUtils.js.map