UNPKG

svelte-image-viewer

Version:

A couple of simple components for displaying content with pan and zoom capabilities.

74 lines (73 loc) 2.57 kB
/** * Smoothly animates a value towards a target using requestAnimationFrame. * * @param initialValue - The initial value to start from * @param smoothing - How quickly to approach the target (0-1, lower = smoother/slower) * @param threshold - Stop animating when within this distance of target * @returns Object with current value state and update function */ export function moveTowards(initialValue = 0, smoothing = 0.125, threshold = 0.00125) { const getInitialValue = typeof initialValue === "function" ? initialValue : () => initialValue; if (typeof window === "undefined") { return { get current() { return getInitialValue(); }, get target() { return getInitialValue(); }, set target(value) { void value; }, destroy() { void 0; }, }; } let currentValue = $state(getInitialValue()); let targetValue = $derived(getInitialValue()); $effect(() => (void targetValue, startAnimation())); let animationId = null; let lastTime = window.performance.now(); const animate = (currentTime) => { const deltaTime = currentTime - lastTime; lastTime = currentTime; // Normalise delta time to 60 fps. This ensures consistent animation speed regardless of frame rate const normalisedDelta = deltaTime / (50 / 3); const difference = targetValue - currentValue; // Check if we're close enough to the target if (Math.abs(difference) < threshold) { currentValue = targetValue; animationId = null; return; } // Smooth interpolation with frame-rate independence const step = difference * smoothing * normalisedDelta; currentValue += step; animationId = window.requestAnimationFrame(animate); }; const startAnimation = () => { if (animationId === null) { lastTime = window.performance.now(); animationId = window.requestAnimationFrame(animate); } }; const stopAnimation = () => { if (animationId !== null) { window.cancelAnimationFrame(animationId); animationId = null; } }; return { get current() { return currentValue; }, get target() { return targetValue; }, set target(value) { targetValue = value; }, destroy: stopAnimation, }; }