Управление через общий контроллер

Lottie Web возвращает при загрузке анимации объект управления, через который осуществляется полный цикл взаимодействия с проигрыванием: запуск, остановка, навигация по кадрам, изменение скорости и направления, обработка событий и управление сегментами. При масштабировании интерфейсов с большим количеством анимаций возникает необходимость в единой точке управления, агрегирующей состояния и команды, обеспечивающей синхронизацию и предсказуемое поведение всех инстансов.

Объект, возвращаемый lottie.loadAnimation, содержит набор методов и свойств, которые представляют низкоуровневое управление:

  • управление воспроизведением (play, pause, stop)
  • навигация по времени (goToAndPlay, goToAndStop)
  • настройка параметров (setSpeed, setDirection, loop, autoplay)
  • работа с сегментами (playSegments)
  • доступ к метаданным (totalFrames, currentFrame, getDuration)
  • управление жизненным циклом (destroy)
  • обработка событий (addEventListener, removeEventListener)

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

Централизованное управление экземплярами

Основой архитектуры выступает реестр анимаций, в котором каждый экземпляр Lottie связывается с идентификатором:

class LottieController {
  constructor() {
    this.instances = new Map();
  }

  register(id, animation) {
    this.instances.set(id, animation);
  }

  unregister(id) {
    const instance = this.instances.get(id);
    if (instance) {
      instance.destroy();
      this.instances.delete(id);
    }
  }
}

Такой слой обеспечивает контроль жизненного цикла и предотвращает утечки памяти, возникающие при удалении DOM-элементов без корректного вызова destroy.

Унифицированные команды воспроизведения

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

Запуск и остановка

playAll() {
  this.instances.forEach(animation => {
    animation.play();
  });
}

pauseAll() {
  this.instances.forEach(animation => {
    animation.pause();
  });
}

stopAll() {
  this.instances.forEach(animation => {
    animation.stop();
  });
}

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

Управление скоростью и направлением

Параметры воспроизведения часто требуют согласованного изменения:

setSpeed(speed) {
  this.instances.forEach(animation => {
    animation.setSpeed(speed);
  });
}

setDirection(direction) {
  this.instances.forEach(animation => {
    animation.setDirection(direction);
  });
}

Изменение направления используется для реализации обратного воспроизведения, а управление скоростью — для адаптации анимаций под производительность устройства или контекст интерфейса.

Синхронизация по времени и кадрам

Для более точного контроля применяется работа с кадрами:

goToFrame(frame, isPlaying = false) {
  this.instances.forEach(animation => {
    if (isPlaying) {
      animation.goToAndPlay(frame, true);
    } else {
      animation.goToAndStop(frame, true);
    }
  });
}

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

Управление сегментами анимации

Lottie поддерживает воспроизведение частей анимации через сегменты:

playSegment(start, end) {
  this.instances.forEach(animation => {
    animation.playSegments([start, end], true);
  });
}

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

Подписка на события и агрегация состояния

Каждый экземпляр Lottie генерирует события: завершение анимации, загрузка DOM, цикл воспроизведения. При централизованном управлении требуется агрегация этих событий:

bindEvents(id) {
  const animation = this.instances.get(id);

  animation.addEventListener('complete', () => {
    this.onComplete(id);
  });

  animation.addEventListener('loopComplete', () => {
    this.onLoop(id);
  });
}

Дополнительный уровень абстракции позволяет реализовать глобальный event bus, который преобразует локальные события в системные сигналы.

Состояние и модель управления

Для сложных интерфейсов вводится единая модель состояния:

  • playing
  • paused
  • stopped
  • loading
  • completed

Каждый экземпляр синхронизируется с состоянием контроллера:

setState(state) {
  this.state = state;

  switch (state) {
    case 'playing':
      this.playAll();
      break;
    case 'paused':
      this.pauseAll();
      break;
    case 'stopped':
      this.stopAll();
      break;
  }
}

Такой подход уменьшает количество разрозненных управляющих вызовов и переводит систему в декларативную модель.

Масштабирование управления

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

createGroup(name, ids) {
  this.groups.set(name, new Set(ids));
}

playGroup(name) {
  const group = this.groups.get(name);

  group.forEach(id => {
    this.instances.get(id).play();
  });
}

Группы позволяют разделять анимации по логике интерфейса: блоки загрузки, интерактивные элементы, фоновые эффекты.

Контроль жизненного цикла и очистка ресурсов

Lottie-анимации привязаны к DOM и canvas/SVG-рендерерам. При динамических интерфейсах требуется централизованное освобождение ресурсов:

destroyAll() {
  this.instances.forEach(animation => {
    animation.destroy();
  });

  this.instances.clear();
  this.groups.clear();
}

Отсутствие такой процедуры приводит к накоплению неиспользуемых canvas-слоёв и подписок на события.

Декларативное управление поверх контроллера

Поверх императивного API Lottie строится декларативный слой описания:

const config = {
  animations: [
    { id: 'loader', action: 'play', speed: 1 },
    { id: 'button', action: 'stop' }
  ]
};

Обработка конфигурации выполняется контроллером:

apply(config) {
  config.animations.forEach(item => {
    const animation = this.instances.get(item.id);

    if (item.speed) {
      animation.setSpeed(item.speed);
    }

    animation[item.action]?.();
  });
}

Такой подход отделяет описание поведения от реализации управления.

Синхронизация с внешними системами

Контроллер часто интегрируется с UI-слоем или state manager. При этом Lottie становится визуальным рендерером состояния:

  • состояние приложения инициирует команды контроллера
  • контроллер транслирует их в Lottie API
  • события анимаций возвращаются в систему управления состоянием

Возникает двунаправленный поток данных, где контроллер выступает посредником между бизнес-логикой и визуальным уровнем.

Итоговая структура контроллера

Центральный контроллер объединяет:

  • реестр экземпляров
  • группы анимаций
  • управление состояниями
  • обработку событий
  • синхронизацию кадров
  • жизненный цикл ресурсов

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