Каскадные значения в mo.js реализуются через механизм Stagger, который позволяет автоматически распределять параметры анимации по набору объектов, создавая последовательные, смещённые или волнообразные эффекты без ручного задания каждого значения.
Stagger работает как функция-генератор значений, возвращающая разные результаты в зависимости от индекса анимируемого объекта. Основная идея заключается в том, что один и тот же параметр превращается в серию значений, изменяющихся по заданному правилу.
В простейшем виде каскад формируется через числовой шаг:
x: 'stagger(10)'
Каждый следующий элемент получает значение, увеличенное на
фиксированный шаг. Если первый объект имеет x = 0, второй
получит x = 10, третий x = 20 и так далее.
Такой подход устраняет необходимость вручную задавать массивы значений и обеспечивает предсказуемую линейную последовательность.
В основе Stagger лежит индекс текущего элемента. При рендеринге коллекции анимаций каждому объекту передаётся индекс, который используется для вычисления итогового значения:
Линейная модель:
value(i) = start + i * step
Это делает Stagger универсальным инструментом для построения сеток движения, каскадных появлений и синхронизированных трансформаций.
В структуре объекта анимации Stagger применяется непосредственно к свойствам tween-объекта:
const timeline = new mojs.Timeline();
const burst = new mojs.Burst({
radius: { 0: 100 },
count: 10,
children: {
shape: 'circle',
fill: 'white',
x: 'stagger(15)',
delay: 'stagger(50)'
}
});
timeline.add(burst);
timeline.play();
В этом примере каждая частица получает собственное смещение по оси X и индивидуальную задержку запуска. Таким образом формируется каскадный взрыв, в котором элементы не появляются одновременно, а выстраиваются в последовательность.
Stagger поддерживает не только линейное распределение, но и работу с двумерными структурами. При наличии сеточного размещения элементов значения могут вычисляться по координатам:
Пример каскада по сетке:
x: 'stagger(20, { grid: [5, 5], from: 'center' })'
В этом случае значение определяется положением элемента в сетке 5×5. Центр становится точкой отсчёта, а значения расходятся симметрично в разные стороны.
Такой подход используется для создания радиальных волн, расширяющихся из центра композиции.
Параметр направления определяет порядок, в котором применяется каскад. Возможные варианты:
Логика направления влияет на восприятие движения. Например, при анимации появления интерфейсных элементов можно задать последовательность слева направо:
opacity: 'stagger(1, { direction: 1 })'
Обратное направление создаёт эффект сворачивания или исчезновения.
Stagger не заменяет базовое значение параметра, а модифицирует его. Это позволяет комбинировать фиксированные и динамические компоненты:
y: 50 + 'stagger(5)'
Здесь каждый элемент начинает с общей позиции y = 50,
после чего получает индивидуальное смещение. Такой подход используется
для построения ступенчатых структур и волнообразных движений.
Помимо строковой записи, Stagger может задаваться как функция, возвращающая вычисляемое значение:
x: function (i) {
return i * 12;
}
Такая форма даёт полный контроль над логикой распределения. В отличие от декларативной записи, функциональный вариант позволяет внедрять условные конструкции, математические преобразования и зависимости от внешнего состояния.
Линейный шаг является базовым случаем. Более сложные эффекты достигаются через нелинейные функции:
Пример ускоряющегося каскада:
scale: 'stagger(1, { modifier: function (v, i) {
return v * v;
}})'
В этом случае элементы увеличиваются неравномерно, создавая эффект ускорения или нарастания интенсивности.
Stagger активно используется для построения последовательных появлений элементов интерфейса. Типичный сценарий включает комбинацию opacity и transform:
children: {
opacity: 'stagger(1)',
y: 'stagger(20)',
delay: 'stagger(40)'
}
Каждый объект получает индивидуальное время старта и позицию, что формирует визуальный поток движения.
Такой подход позволяет создавать естественные переходы без резких скачков состояния.
Stagger может применяться одновременно к нескольким параметрам, создавая согласованные траектории движения:
children: {
x: 'stagger(10)',
y: 'stagger(10)',
rotate: 'stagger(15)'
}
При синхронном применении формируется диагональная структура движения, где каждый элемент следует собственной, но согласованной траектории.
Изменение шага напрямую влияет на визуальную плотность эффекта:
Регулировка шага позволяет управлять динамикой композиции без изменения количества объектов.
В Burst-анимациях Stagger становится ключевым инструментом формирования сложных разлётов:
new mojs.Burst({
count: 12,
radius: { 0: 120 },
children: {
shape: 'rect',
x: 'stagger(8)',
delay: 'stagger(30)',
duration: 600
}
});
Здесь создаётся эффект расширяющегося облака, в котором элементы не просто расходятся, а делают это с контролируемым смещением.
Stagger может сочетаться с функциями сглаживания, что изменяет характер каскада во времени. При этом распределение значений остаётся последовательным, но их восприятие изменяется за счёт временной интерполяции.
Типичный эффект — замедление в начале и ускорение в конце или наоборот, что усиливает ощущение физической правдоподобности движения.
Индекс элемента становится фундаментальной единицей управления визуальной иерархией. Более ранние элементы могут задавать направление восприятия всей анимации, в то время как последующие формируют завершение композиции.
Это особенно заметно в интерфейсных переходах, где последовательность появления определяет фокус внимания и структуру восприятия сцены.