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, который преобразует локальные события в системные сигналы.
Для сложных интерфейсов вводится единая модель состояния:
Каждый экземпляр синхронизируется с состоянием контроллера:
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-анимаций в управляемую систему, где визуальные эффекты подчиняются единой логике исполнения и синхронизации.