Динамическая генерация анимаций в mo.js строится вокруг идеи программного создания объектов анимации в момент выполнения приложения. Вместо заранее определённых эффектов используются фабрики объектов, конфигурации, вычисляемые параметры и привязка к событиям интерфейса или логике приложения.
Основной принцип заключается в том, что каждая анимация рассматривается как объект, создаваемый и конфигурируемый в рантайме. Это позволяет строить системы визуальных эффектов, реагирующие на действия пользователя, состояние данных или внутренние события приложения.
В mo.js ключевую роль играют классы Shape,
Burst, Timeline и вспомогательные модули.
Динамическое создание заключается в том, что экземпляры этих классов
формируются внутри функций, обработчиков или генераторов.
Конфигурация не фиксируется заранее, а вычисляется на основе входных данных:
Такой подход позволяет формировать уникальные анимации без необходимости описывать их вручную для каждого случая.
Одним из базовых подходов является использование фабричных функций, возвращающих экземпляры анимаций.
const createCircleAnimation = (x, y, color) => {
return new mojs.Shape({
shape: 'circle',
left: 0,
top: 0,
x,
y,
radius: { 0: 60 },
fill: color,
opacity: { 1: 0 },
duration: 800,
easing: 'cubic.out'
});
};
Фабрика позволяет централизовать логику создания эффектов и изменять их поведение в зависимости от параметров. Это особенно важно при работе с интерактивными интерфейсами, где анимации должны быть контекстно-зависимыми.
Динамическое создание часто используется вместе с обработчиками событий. Анимация создаётся только в момент возникновения события, что снижает нагрузку и повышает гибкость.
document.addEventListener('click', (e) => {
const anim = new mojs.Shape({
shape: 'circle',
left: 0,
top: 0,
x: e.pageX,
y: e.pageY,
radius: { 0: 50 },
fill: '#4A90E2',
opacity: { 1: 0 },
duration: 600
});
anim.play();
});
Каждое событие создаёт новый экземпляр анимации, что делает поведение системы непредсказуемым в хорошем смысле — визуальный отклик становится уникальным для каждого взаимодействия.
Динамическая генерация часто опирается на псевдослучайные значения. Это позволяет создавать вариативные эффекты без усложнения логики.
const randomRange = (min, max) => Math.random() * (max - min) + min;
const createBurst = (x, y) => {
return new mojs.Burst({
left: 0,
top: 0,
x,
y,
radius: { 0: randomRange(80, 140) },
count: Math.floor(randomRange(5, 12)),
children: {
shape: 'circle',
radius: { 6: 0 },
fill: ['#F44336', '#FF9800', '#FFEB3B'],
duration: randomRange(600, 1200)
}
});
};
Случайность применяется не только к геометрии, но и к длительности, цветам, количеству элементов и кривым easing, что позволяет создавать визуально насыщенные эффекты при минимальном коде.
mo.js поддерживает композицию через Timeline, что
позволяет динамически собирать сложные сцены из нескольких анимаций.
const createExplosionTimeline = (x, y) => {
const burst = new mojs.Burst({
left: 0,
top: 0,
x,
y,
radius: { 0: 120 },
count: 10,
children: {
shape: 'circle',
fill: '#FF5252',
radius: { 8: 0 }
}
});
const shockwave = new mojs.Shape({
shape: 'circle',
left: 0,
top: 0,
x,
y,
stroke: '#FF5252',
strokeWidth: { 10: 0 },
radius: { 0: 100 },
opacity: { 0.6: 0 },
duration: 700
});
return new mojs.Timeline({
children: [burst, shockwave]
});
};
Такая структура позволяет формировать сложные эффекты как набор независимых компонентов, которые могут комбинироваться в различных конфигурациях.
Важной особенностью динамического подхода является отложенное создание объектов. Анимация не должна существовать до момента, когда она действительно нужна.
const animations = new Map();
function getAnimation(id, x, y) {
if (!animations.has(id)) {
animations.set(id, new mojs.Shape({
shape: 'rect',
x,
y,
radius: { 0: 40 },
fill: '#29B6F6',
duration: 500
}));
}
return animations.get(id);
}
Такой подход используется для переиспользования эффектов и контроля над количеством создаваемых объектов.
mo.js позволяет изменять параметры анимации на этапе создания, что даёт возможность строить адаптивные эффекты.
function createAdaptiveShape(state) {
return new mojs.Shape({
shape: state.type === 'alert' ? 'circle' : 'rect',
fill: state.active ? '#66BB6A' : '#EF5350',
radius: state.active ? { 20: 80 } : { 10: 40 },
duration: state.duration || 600
});
}
Таким образом анимации становятся частью логики приложения, а не отдельным визуальным слоем.
Динамическое создание особенно эффективно при визуализации данных. Каждый элемент данных может порождать собственную анимацию.
const data = [10, 40, 25, 60];
data.forEach((value, index) => {
new mojs.Shape({
shape: 'circle',
left: 0,
top: 0,
x: index * 80,
y: 0,
radius: { 0: value },
fill: '#42A5F5',
duration: 800 + value * 5
}).play();
});
Такой подход используется для создания интерактивных графиков и визуальных представлений, где каждый элемент данных влияет на поведение анимации.
Контекст определяет параметры анимации: позицию, масштаб, интенсивность и тип эффекта. Это позволяет привязывать визуальные реакции к структуре интерфейса.
function createContextEffect(element) {
const rect = element.getBoundingClientRect();
return new mojs.Shape({
shape: 'circle',
left: 0,
top: 0,
x: rect.left + rect.width / 2,
y: rect.top + rect.height / 2,
radius: { 0: rect.width },
fill: 'rgba(0,0,0,0.2)',
duration: 500
});
}
Контекстное создание используется для эффектов наведения, активации элементов и визуального отклика интерфейса.
При увеличении сложности интерфейса динамическое создание анимаций требует централизованного управления. Формируется слой генераторов, отвечающих за различные типы эффектов.
const AnimationFactory = {
pulse: (x, y) => new mojs.Shape({
shape: 'circle',
x,
y,
radius: { 10: 50 },
opacity: { 1: 0 },
duration: 700
}),
line: (x, y) => new mojs.Shape({
shape: 'line',
x,
y,
stroke: '#000',
strokeWidth: { 2: 0 },
duration: 500
})
};
Такая структура позволяет расширять систему без изменения существующей логики.
Каждая динамически созданная анимация проходит цикл: создание, запуск, завершение и удаление. Контроль жизненного цикла предотвращает утечки памяти и перегрузку интерфейса.
function playAndDestroy(anim) {
anim
.then(() => {
anim.el && anim.el.remove && anim.el.remove();
})
.play();
}
Управление жизненным циклом особенно важно при массовой генерации эффектов, например при движении мыши или частых кликах.
Динамическое создание может быть связано с изменением состояния приложения. При обновлении состояния автоматически создаются новые эффекты.
let state = { level: 1 };
function updateState(newState) {
state = { ...state, ...newState };
new mojs.Shape({
shape: 'polygon',
radius: state.level * 20,
fill: '#AB47BC',
duration: 600
}).play();
}
Такой подход позволяет связывать визуальные эффекты с логикой приложения без жёсткой привязки к DOM-событиям.