70 lines
2.2 KiB
TypeScript
70 lines
2.2 KiB
TypeScript
import { clamp } from "~/shared/general.utils";
|
|
|
|
export const linear = (progress: number): number => progress;
|
|
export const ease = (progress: number): number => -(Math.cos(Math.PI * progress) - 1) / 2;
|
|
|
|
export function useTween(ref: Ref<number>, animation: (progress: number) => number, then: () => void)
|
|
{
|
|
// State variables for animation
|
|
let initial = ref.value;
|
|
let current = ref.value;
|
|
let end = ref.value;
|
|
let animationFrame: number;
|
|
let stop = true;
|
|
let last = 0;
|
|
|
|
// Velocity tracking with sign preservation
|
|
let velocity = 0;
|
|
const velocityDecay = 0.92; // Slightly faster decay for more responsive feel
|
|
|
|
function loop(t: DOMHighResTimeStamp) {
|
|
// Cap the elapsed time to prevent jumps during lag or tab switches
|
|
const elapsed = Math.min(t - last, 32);
|
|
last = t;
|
|
|
|
// Update velocity considering the sign of the movement
|
|
velocity = velocity * velocityDecay + (end - current) * (1 - velocityDecay);
|
|
|
|
// Apply velocity to current position
|
|
// Normalize by elapsed time to maintain consistent speed regardless of frame rate
|
|
current = clamp(current + velocity * (elapsed / 16), initial, end);
|
|
|
|
if(current === end)
|
|
stop = true;
|
|
|
|
// Trigger callback
|
|
then();
|
|
|
|
// Continue animation if not stopped
|
|
if (!stop) {
|
|
animationFrame = requestAnimationFrame(loop);
|
|
}
|
|
}
|
|
|
|
return {
|
|
stop: () => {
|
|
cancelAnimationFrame(animationFrame);
|
|
stop = true;
|
|
velocity = 0; // Reset velocity when stopping
|
|
},
|
|
update: (target: number, duration: number) => {
|
|
if (stop) {
|
|
// Only reset initial position when starting a new animation
|
|
initial = current;
|
|
last = performance.now();
|
|
}
|
|
|
|
end = target;
|
|
|
|
if (stop) {
|
|
stop = false;
|
|
loop(performance.now());
|
|
}
|
|
},
|
|
refresh: () => {
|
|
current = ref.value;
|
|
velocity = 0; // Reset velocity on refresh
|
|
},
|
|
current: () => current,
|
|
};
|
|
} |