onProgress — это один из ключевых хуков жизненного цикла
анимации в библиотеке mo.js, предназначенный для отслеживания текущего
состояния проигрывания. Он вызывается на каждом кадре анимации и
предоставляет информацию о степени её выполнения.
В основе работы onProgress лежит идея
нормализованного прогресса, представленного числом от
0 до 1:
0 — анимация только началась1 — анимация полностью завершенаЭтот параметр позволяет синхронизировать любые вычисления или изменения состояния с текущим кадром анимации.
onProgress задаётся как функция в конфигурации
анимации:
const tween = new mojs.Tween({
duration: 1000,
onProgress(progress) {
console.log(progress);
}
});
Аргументы:
progress — число (Number) в диапазоне
[0, 1]Каждый объект анимации в mo.js управляется внутренним таймлайном. На каждом кадре:
durationonProgressВажно учитывать, что значение progress уже
преобразовано easing-функцией, если она
используется.
При задании easing-функции onProgress получает не
линейное значение времени, а результат её применения:
const tween = new mojs.Tween({
duration: 1000,
easing: 'cubic.out',
onProgress(p) {
console.log(p); // уже с учётом easing
}
});
Следствие: Если требуется линейный прогресс, необходимо либо не использовать easing, либо вычислять его вручную.
const box = document.querySelector('.box');
new mojs.Tween({
duration: 1000,
onProgress(p) {
box.style.transform = `translateX(${p * 300}px)`;
}
}).play();
Здесь p напрямую используется для интерполяции положения
элемента.
let progressValue = 0;
const tween = new mojs.Tween({
duration: 1000,
onProgress(p) {
progressValue = p;
}
});
const anotherTween = new mojs.Tween({
duration: 1000,
onProgress() {
console.log(progressValue);
}
});
Общий прогресс может служить связующим звеном между разными анимациями.
onProgress(p) {
const scale = 1 + Math.sin(p * Math.PI);
element.style.transform = `scale(${scale})`;
}
Использование математических функций позволяет создавать сложные визуальные эффекты.
onUpdateВ mo.js существуют похожие механизмы, однако:
onProgress — работает с нормализованным значением
[0, 1]onUpdate — чаще используется внутри специализированных
модулей (например, mojs.Html, mojs.Shape)onProgress более универсален и применяется на уровне
базового Tween.
Поскольку onProgress вызывается на каждом кадре
(≈60 раз в секунду):
Пример оптимизации:
const el = document.querySelector('.box');
new mojs.Tween({
onProgress(p) {
el.style.opacity = p;
}
});
Вместо поиска элемента на каждом кадре.
Иногда требуется реагировать не на весь диапазон [0,1],
а на его часть:
onProgress(p) {
if (p > 0.5) {
console.log('Вторая половина анимации');
}
}
Для более точного контроля используется нормализация:
onProgress(p) {
const local = (p - 0.5) * 2; // диапазон [0,1] во второй половине
if (p >= 0.5) {
console.log(local);
}
}
Внутренне mo.js использует requestAnimationFrame,
поэтому:
onProgress синхронизирован с браузерным циклом
отрисовкиПри повторном вызове .play():
progress снова начинается с 0onProgress вызывается зановоПри использовании .pause() и .resume():
progress продолжается с текущего
состоянияВ составе Timeline:
const timeline = new mojs.Timeline();
timeline.add(
new mojs.Tween({
duration: 1000,
onProgress(p) {
console.log('Tween 1:', p);
}
}),
new mojs.Tween({
duration: 500,
onProgress(p) {
console.log('Tween 2:', p);
}
})
);
timeline.play();
Каждый tween получает собственный progress, независимо
от общей шкалы таймлайна.
Для анализа поведения анимации:
onProgress(p) {
console.log(p.toFixed(2));
}
Ограничение количества знаков после запятой улучшает читаемость логов.
onProgress часто используется как входной параметр для
функций:
onProgress(p) {
const y = Math.sin(p * Math.PI * 2) * 50;
element.style.transform = `translateY(${y}px)`;
}
Создаётся плавное колебательное движение.
progress не всегда строго равно 1
на последнем кадре из-за особенностей таймингаfunction lerp(start, end, t) {
return start + (end - start) * t;
}
onProgress(p) {
const value = lerp(10, 100, p);
element.style.width = `${value}px`;
}
onProgress(p) {
const mapped = p * 2 - 1; // диапазон [-1, 1]
console.log(mapped);
}
onProgress(p) {
element.style.opacity = p > 0.3 ? 1 : 0;
}
onProgress удобно использовать для синхронизации с:
onProgress(p) {
state.animationProgress = p;
}
При изменении duration:
onProgress остаётся прежнейprogressКороткая длительность → быстрый рост значения Длинная длительность → плавный рост
Несколько эффектов можно комбинировать:
onProgress(p) {
const x = p * 200;
const scale = 1 + p;
element.style.transform = `
translateX(${x}px)
scale(${scale})
`;
}
progress фактически является:
progress = elapsedTime / duration
с учётом easing-функции.
При использовании .reverse():
progress изменяется от 1 к
0tween.reverse();
Для критичных вычислений иногда используют ограничение:
onProgress(p) {
p = Math.min(Math.max(p, 0), 1);
}
Хотя в нормальных условиях mo.js уже гарантирует этот диапазон.
При повторении (repeat):
progress сбрасывается на 0 при каждом
циклеonProgress вызывается заново для каждой итерацииПри наличии delay:
onProgress не вызывается до начала анимацииВ больших проектах onProgress часто выступает как:
Такой подход делает onProgress не просто инструментом
отслеживания, а полноценным механизмом управления динамикой
интерфейса.