UNPKG

@studiometa/js-toolkit

Version:

A set of useful little bits of JavaScript to boost your project! 🚀

115 lines (114 loc) • 3.2 kB
import { cubicBezier } from "@motionone/easing"; import { lerp, map, clamp01, damp, inertiaFinalValue, spring } from "./math/index.js"; import { isDefined, isArray, isNumber } from "./is.js"; import { noop, noopValue as linear } from "./noop.js"; import { useRaf } from "../services/RafService.js"; let id = 0; const DEFAULT_PROGRESS_PRECISION = 1 / 1e4; function normalizeEase(ease) { if (!isDefined(ease)) { return linear; } if (isArray(ease)) { return cubicBezier(...ease); } return ease; } function tween(callback, options = {}) { const raf = useRaf(); let progressValue = 0; let easedProgress = 0; let velocity = 0; const isSmooth = isDefined(options.smooth) && (isNumber(options.smooth) || options.smooth); const isSpring = isDefined(options.spring) && (isNumber(options.spring) || options.spring); const stiffness = isNumber(options.spring) ? options.spring : 0.1; const mass = isNumber(options.mass) ? options.mass : 1; const damping = isNumber(options.smooth) ? options.smooth : 0.1; const precision = options.precision ?? DEFAULT_PROGRESS_PRECISION; const ease = normalizeEase(options.easing); let delay = options.delay ?? 0; delay *= 1e3; let duration = options.duration ?? 1; duration *= 1e3; let startTime = getStartTime(); let endTime = getEndTime(startTime); const key = `tw-${id}`; id += 1; const { onStart = noop, onProgress = noop, onFinish = noop } = options; let isRunning = false; function pause() { isRunning = false; raf.remove(key); } function progress(newProgress) { if (!isDefined(newProgress)) { return easedProgress; } let shouldStop = false; progressValue = newProgress; if (isSpring) { [easedProgress, velocity] = spring( progressValue, easedProgress, velocity, stiffness, damping, mass, precision ); } else { easedProgress = isSmooth ? damp(progressValue, easedProgress, damping, precision) : ease(progressValue); } if (Math.abs(1 - easedProgress) < precision) { progressValue = 1; easedProgress = 1; shouldStop = true; } callback(easedProgress); onProgress(easedProgress); if (shouldStop) { pause(); requestAnimationFrame(() => onFinish(easedProgress)); } return easedProgress; } function tick(props) { progress(clamp01(map(props.time, startTime, endTime, 0, 1))); } function getStartTime() { return performance.now() + delay; } function getEndTime(time) { return isSmooth ? inertiaFinalValue(time, 1) : time + duration; } function start() { onStart(0); startTime = getStartTime(); endTime = getEndTime(startTime); progressValue = 0; easedProgress = 0; isRunning = true; raf.add(key, tick); } function play() { if (isRunning) { return; } startTime = getStartTime() - lerp(0, duration, progressValue); endTime = getEndTime(startTime); isRunning = true; raf.add(key, tick); } return { start, finish: () => progress(1), pause, play, progress }; } export { normalizeEase, tween }; //# sourceMappingURL=tween.js.map