Анимация произвольных значений в mo.js строится вокруг идеи
независимого tween-движка, который может интерполировать любые числовые
и часть строковых параметров во времени. В отличие от классических
CSS-анимаций, здесь нет ограничения на DOM-свойства: объектом анимации
становится любое пользовательское состояние, а управление осуществляется
через onUpdate.
В основе лежит класс mojs.Tween, который управляет
переходом значения от начального состояния к конечному в течение
заданного времени.
Ключевые параметры:
duration — длительность анимацииdelay — задержка стартаeasing — функция плавностиonUpdate — функция, вызываемая на каждом шагеonComplete — завершение анимацииПростейшая форма анимации числового значения:
const tween = new mojs.Tween({
duration: 1000,
easing: 'linear',
onUpdate: (progress) => {
const value = 100 * progress;
console.log(value);
}
});
tween.play();
Здесь progress изменяется от 0 до 1, а любое значение
вычисляется вручную.
Чаще используется подход с явным заданием начального и конечного состояния. В этом случае mo.js сам интерполирует значения.
const state = { x: 0 };
const tween = new mojs.Tween({
duration: 1200,
easing: 'ease.out',
onUpdate: (p) => {
state.x = 0 + (300 - 0) * p;
}
});
tween.play();
Такой подход удобен при анимации виртуальных объектов, не связанных напрямую с DOM.
Произвольные значения часто группируются в объект, чтобы управлять несколькими параметрами одновременно.
const box = {
x: 0,
y: 0,
scale: 1
};
const tween = new mojs.Tween({
duration: 1500,
easing: 'cubic.out',
onUpdate: (p) => {
box.x = 0 + 400 * p;
box.y = 0 + 200 * p;
box.scale = 1 + 1.5 * p;
}
});
Подобный подход позволяет полностью отделить модель состояния от визуализации.
mo.js поддерживает интерполяцию цветов в формате HEX, RGB и HSL. Это особенно важно при анимации UI-состояний.
const colors = {
from: '#ff0000',
to: '#00ffcc'
};
const tween = new mojs.Tween({
duration: 2000,
easing: 'linear',
onUpdate: (p) => {
const color = mojs.interpolate(colors.from, colors.to, p);
document.body.style.background = color;
}
});
Внутренняя функция интерполяции позволяет плавно переходить между цветовыми пространствами без ручного разложения компонентов.
Произвольные значения не ограничиваются простыми числами. Часто анимируются массивы или сложные структуры.
const points = [
{ x: 0, y: 0 },
{ x: 50, y: 100 },
{ x: 100, y: 0 }
];
const tween = new mojs.Tween({
duration: 1000,
easing: 'quad.inOut',
onUpdate: (p) => {
const animated = points.map(pt => ({
x: pt.x + (pt.x * 2) * p,
y: pt.y + (pt.y * 2) * p
}));
draw(animated);
}
});
Такой подход используется в процедурной графике и динамических визуализациях.
Функция easing определяет характер изменения значения. mo.js предоставляет набор встроенных кривых:
linearquad.in, quad.out,
quad.inOutcubic.in, cubic.outbounce.outelastic.outПример влияния easing на произвольную величину:
const tween = new mojs.Tween({
duration: 1000,
easing: 'elastic.out',
onUpdate: (p) => {
const value = Math.sin(p * Math.PI * 2) * 50 * p;
updatePosition(value);
}
});
Комбинация easing и пользовательской формулы позволяет создавать сложные нелинейные движения.
Анимация произвольных значений часто используется как слой управления сценой, где mo.js не управляет DOM напрямую, а обновляет модель:
const scene = {
camera: { zoom: 1 },
light: { intensity: 0.5 }
};
const tween = new mojs.Tween({
duration: 2000,
easing: 'expo.inOut',
onUpdate: (p) => {
scene.camera.zoom = 1 + 2 * p;
scene.light.intensity = 0.5 + 0.5 * p;
}
});
Такой подход характерен для WebGL-сцен и canvas-рендеринга, где состояние отделено от отрисовки.
Произвольные значения удобно комбинировать через несколько tween-ов, работающих параллельно или последовательно.
const tweenA = new mojs.Tween({
duration: 800,
onUpdate: (p) => {
state.a = p;
}
});
const tweenB = new mojs.Tween({
duration: 1200,
onUpdate: (p) => {
state.b = p;
}
});
tweenA.play();
tweenB.play();
При необходимости синхронизации используется
mojs.Timeline, который координирует несколько анимаций.
Произвольные значения становятся полезными только при связке с рендерингом:
const canvas = document.querySelector('canvas');
const ctx = canvas.getContext('2d');
const state = { radius: 10 };
const tween = new mojs.Tween({
duration: 1500,
easing: 'sine.inOut',
onUpdate: (p) => {
state.radius = 10 + 80 * p;
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.beginPath();
ctx.arc(150, 150, state.radius, 0, Math.PI * 2);
ctx.fill();
}
});
tween.play();
Таким образом tween выступает источником времени, а не визуальным объектом.
Произвольные значения легко разворачиваются в обратную анимацию:
const tween = new mojs.Tween({
duration: 1000,
isYoyo: true,
repeat: 2,
onUpdate: (p) => {
state.value = p;
}
});
Это позволяет строить циклические изменения состояний без дополнительной логики.
В сложных случаях значение вычисляется как комбинация нескольких функций:
const tween = new mojs.Tween({
duration: 2000,
easing: 'linear',
onUpdate: (p) => {
const wave = Math.sin(p * Math.PI * 4);
const envelope = p;
state.signal = wave * envelope;
}
});
Такой подход используется при создании процедурных эффектов, колебаний и визуальных сигналов.
Архитектурно анимация произвольных значений в mo.js формирует слой
временной параметризации, где tween отвечает только за генерацию
p ∈ [0,1], а вся логика преобразования ложится на
прикладной код.
const model = {
progress: 0
};
const tween = new mojs.Tween({
duration: 1000,
onUpdate: (p) => {
model.progress = p;
render(model);
}
});
Такой подход позволяет масштабировать анимационные системы до сложных интерактивных приложений без привязки к DOM-анимации.