till download files, everything works
This commit is contained in:
1 parent
ce893a4185
commit
ed1a580b09
6050 files changed
+768543
-177
No files matched your search
+89
@@ -0,0 +1,89 @@
|
||||
import { warning } from '../../../utils/errors.mjs';
|
||||
import { clamp } from '../../../utils/clamp.mjs';
|
||||
import { secondsToMilliseconds, millisecondsToSeconds } from '../../../utils/time-conversion.mjs';
|
||||
|
||||
const safeMin = 0.001;
|
||||
const minDuration = 0.01;
|
||||
const maxDuration = 10.0;
|
||||
const minDamping = 0.05;
|
||||
const maxDamping = 1;
|
||||
function findSpring({ duration = 800, bounce = 0.25, velocity = 0, mass = 1, }) {
|
||||
let envelope;
|
||||
let derivative;
|
||||
warning(duration <= secondsToMilliseconds(maxDuration), "Spring duration must be 10 seconds or less");
|
||||
let dampingRatio = 1 - bounce;
|
||||
/**
|
||||
* Restrict dampingRatio and duration to within acceptable ranges.
|
||||
*/
|
||||
dampingRatio = clamp(minDamping, maxDamping, dampingRatio);
|
||||
duration = clamp(minDuration, maxDuration, millisecondsToSeconds(duration));
|
||||
if (dampingRatio < 1) {
|
||||
/**
|
||||
* Underdamped spring
|
||||
*/
|
||||
envelope = (undampedFreq) => {
|
||||
const exponentialDecay = undampedFreq * dampingRatio;
|
||||
const delta = exponentialDecay * duration;
|
||||
const a = exponentialDecay - velocity;
|
||||
const b = calcAngularFreq(undampedFreq, dampingRatio);
|
||||
const c = Math.exp(-delta);
|
||||
return safeMin - (a / b) * c;
|
||||
};
|
||||
derivative = (undampedFreq) => {
|
||||
const exponentialDecay = undampedFreq * dampingRatio;
|
||||
const delta = exponentialDecay * duration;
|
||||
const d = delta * velocity + velocity;
|
||||
const e = Math.pow(dampingRatio, 2) * Math.pow(undampedFreq, 2) * duration;
|
||||
const f = Math.exp(-delta);
|
||||
const g = calcAngularFreq(Math.pow(undampedFreq, 2), dampingRatio);
|
||||
const factor = -envelope(undampedFreq) + safeMin > 0 ? -1 : 1;
|
||||
return (factor * ((d - e) * f)) / g;
|
||||
};
|
||||
}
|
||||
else {
|
||||
/**
|
||||
* Critically-damped spring
|
||||
*/
|
||||
envelope = (undampedFreq) => {
|
||||
const a = Math.exp(-undampedFreq * duration);
|
||||
const b = (undampedFreq - velocity) * duration + 1;
|
||||
return -safeMin + a * b;
|
||||
};
|
||||
derivative = (undampedFreq) => {
|
||||
const a = Math.exp(-undampedFreq * duration);
|
||||
const b = (velocity - undampedFreq) * (duration * duration);
|
||||
return a * b;
|
||||
};
|
||||
}
|
||||
const initialGuess = 5 / duration;
|
||||
const undampedFreq = approximateRoot(envelope, derivative, initialGuess);
|
||||
duration = secondsToMilliseconds(duration);
|
||||
if (isNaN(undampedFreq)) {
|
||||
return {
|
||||
stiffness: 100,
|
||||
damping: 10,
|
||||
duration,
|
||||
};
|
||||
}
|
||||
else {
|
||||
const stiffness = Math.pow(undampedFreq, 2) * mass;
|
||||
return {
|
||||
stiffness,
|
||||
damping: dampingRatio * 2 * Math.sqrt(mass * stiffness),
|
||||
duration,
|
||||
};
|
||||
}
|
||||
}
|
||||
const rootIterations = 12;
|
||||
function approximateRoot(envelope, derivative, initialGuess) {
|
||||
let result = initialGuess;
|
||||
for (let i = 1; i < rootIterations; i++) {
|
||||
result = result - envelope(result) / derivative(result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
function calcAngularFreq(undampedFreq, dampingRatio) {
|
||||
return undampedFreq * Math.sqrt(1 - dampingRatio * dampingRatio);
|
||||
}
|
||||
|
||||
export { calcAngularFreq, findSpring, maxDamping, maxDuration, minDamping, minDuration };
|
||||
+129
@@ -0,0 +1,129 @@
|
||||
import { millisecondsToSeconds, secondsToMilliseconds } from '../../../utils/time-conversion.mjs';
|
||||
import { calcGeneratorVelocity } from '../utils/velocity.mjs';
|
||||
import { findSpring, calcAngularFreq } from './find.mjs';
|
||||
|
||||
const durationKeys = ["duration", "bounce"];
|
||||
const physicsKeys = ["stiffness", "damping", "mass"];
|
||||
function isSpringType(options, keys) {
|
||||
return keys.some((key) => options[key] !== undefined);
|
||||
}
|
||||
function getSpringOptions(options) {
|
||||
let springOptions = {
|
||||
velocity: 0.0,
|
||||
stiffness: 100,
|
||||
damping: 10,
|
||||
mass: 1.0,
|
||||
isResolvedFromDuration: false,
|
||||
...options,
|
||||
};
|
||||
// stiffness/damping/mass overrides duration/bounce
|
||||
if (!isSpringType(options, physicsKeys) &&
|
||||
isSpringType(options, durationKeys)) {
|
||||
const derived = findSpring(options);
|
||||
springOptions = {
|
||||
...springOptions,
|
||||
...derived,
|
||||
mass: 1.0,
|
||||
};
|
||||
springOptions.isResolvedFromDuration = true;
|
||||
}
|
||||
return springOptions;
|
||||
}
|
||||
function spring({ keyframes, restDelta, restSpeed, ...options }) {
|
||||
const origin = keyframes[0];
|
||||
const target = keyframes[keyframes.length - 1];
|
||||
/**
|
||||
* This is the Iterator-spec return value. We ensure it's mutable rather than using a generator
|
||||
* to reduce GC during animation.
|
||||
*/
|
||||
const state = { done: false, value: origin };
|
||||
const { stiffness, damping, mass, duration, velocity, isResolvedFromDuration, } = getSpringOptions({
|
||||
...options,
|
||||
velocity: -millisecondsToSeconds(options.velocity || 0),
|
||||
});
|
||||
const initialVelocity = velocity || 0.0;
|
||||
const dampingRatio = damping / (2 * Math.sqrt(stiffness * mass));
|
||||
const initialDelta = target - origin;
|
||||
const undampedAngularFreq = millisecondsToSeconds(Math.sqrt(stiffness / mass));
|
||||
/**
|
||||
* If we're working on a granular scale, use smaller defaults for determining
|
||||
* when the spring is finished.
|
||||
*
|
||||
* These defaults have been selected emprically based on what strikes a good
|
||||
* ratio between feeling good and finishing as soon as changes are imperceptible.
|
||||
*/
|
||||
const isGranularScale = Math.abs(initialDelta) < 5;
|
||||
restSpeed || (restSpeed = isGranularScale ? 0.01 : 2);
|
||||
restDelta || (restDelta = isGranularScale ? 0.005 : 0.5);
|
||||
let resolveSpring;
|
||||
if (dampingRatio < 1) {
|
||||
const angularFreq = calcAngularFreq(undampedAngularFreq, dampingRatio);
|
||||
// Underdamped spring
|
||||
resolveSpring = (t) => {
|
||||
const envelope = Math.exp(-dampingRatio * undampedAngularFreq * t);
|
||||
return (target -
|
||||
envelope *
|
||||
(((initialVelocity +
|
||||
dampingRatio * undampedAngularFreq * initialDelta) /
|
||||
angularFreq) *
|
||||
Math.sin(angularFreq * t) +
|
||||
initialDelta * Math.cos(angularFreq * t)));
|
||||
};
|
||||
}
|
||||
else if (dampingRatio === 1) {
|
||||
// Critically damped spring
|
||||
resolveSpring = (t) => target -
|
||||
Math.exp(-undampedAngularFreq * t) *
|
||||
(initialDelta +
|
||||
(initialVelocity + undampedAngularFreq * initialDelta) * t);
|
||||
}
|
||||
else {
|
||||
// Overdamped spring
|
||||
const dampedAngularFreq = undampedAngularFreq * Math.sqrt(dampingRatio * dampingRatio - 1);
|
||||
resolveSpring = (t) => {
|
||||
const envelope = Math.exp(-dampingRatio * undampedAngularFreq * t);
|
||||
// When performing sinh or cosh values can hit Infinity so we cap them here
|
||||
const freqForT = Math.min(dampedAngularFreq * t, 300);
|
||||
return (target -
|
||||
(envelope *
|
||||
((initialVelocity +
|
||||
dampingRatio * undampedAngularFreq * initialDelta) *
|
||||
Math.sinh(freqForT) +
|
||||
dampedAngularFreq *
|
||||
initialDelta *
|
||||
Math.cosh(freqForT))) /
|
||||
dampedAngularFreq);
|
||||
};
|
||||
}
|
||||
return {
|
||||
calculatedDuration: isResolvedFromDuration ? duration || null : null,
|
||||
next: (t) => {
|
||||
const current = resolveSpring(t);
|
||||
if (!isResolvedFromDuration) {
|
||||
let currentVelocity = 0.0;
|
||||
/**
|
||||
* We only need to calculate velocity for under-damped springs
|
||||
* as over- and critically-damped springs can't overshoot, so
|
||||
* checking only for displacement is enough.
|
||||
*/
|
||||
if (dampingRatio < 1) {
|
||||
currentVelocity =
|
||||
t === 0
|
||||
? secondsToMilliseconds(initialVelocity)
|
||||
: calcGeneratorVelocity(resolveSpring, t, current);
|
||||
}
|
||||
const isBelowVelocityThreshold = Math.abs(currentVelocity) <= restSpeed;
|
||||
const isBelowDisplacementThreshold = Math.abs(target - current) <= restDelta;
|
||||
state.done =
|
||||
isBelowVelocityThreshold && isBelowDisplacementThreshold;
|
||||
}
|
||||
else {
|
||||
state.done = t >= duration;
|
||||
}
|
||||
state.value = state.done ? target : current;
|
||||
return state;
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export { spring };
|
||||
Reference in new issue
Block a user