Динамическое создание анимаций

Динамическая генерация анимаций в mo.js строится вокруг идеи программного создания объектов анимации в момент выполнения приложения. Вместо заранее определённых эффектов используются фабрики объектов, конфигурации, вычисляемые параметры и привязка к событиям интерфейса или логике приложения.

Основной принцип заключается в том, что каждая анимация рассматривается как объект, создаваемый и конфигурируемый в рантайме. Это позволяет строить системы визуальных эффектов, реагирующие на действия пользователя, состояние данных или внутренние события приложения.

Архитектура динамического создания

В mo.js ключевую роль играют классы Shape, Burst, Timeline и вспомогательные модули. Динамическое создание заключается в том, что экземпляры этих классов формируются внутри функций, обработчиков или генераторов.

Конфигурация не фиксируется заранее, а вычисляется на основе входных данных:

  • координаты события
  • случайные параметры
  • состояние DOM-элемента
  • временные метки
  • пользовательские данные

Такой подход позволяет формировать уникальные анимации без необходимости описывать их вручную для каждого случая.

Генерация анимаций через фабричные функции

Одним из базовых подходов является использование фабричных функций, возвращающих экземпляры анимаций.

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-событиям.