Последовательное воспроизведение

В основе последовательного воспроизведения в Lottie Web лежит система событий экземпляра анимации. Каждый объект, созданный через lottie.loadAnimation, предоставляет API, позволяющее отслеживать жизненный цикл проигрывания.

Ключевым событием выступает complete, фиксирующее окончание полного цикла воспроизведения при loop: false.

const anim = lottie.loadAnimation({
  container: document.getElementById('anim'),
  renderer: 'svg',
  loop: false,
  autoplay: true,
  path: 'animation1.json'
});

anim.addEventListener('complete', () => {
  // переход к следующей анимации
});

Последовательная логика строится вокруг реакции на завершение текущего состояния экземпляра. Каждый новый шаг запускается только после получения сигнала о завершении текущего.

Базовая цепочка воспроизведения

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

function playAnimation(path, container, onComplete) {
  const anim = lottie.loadAnimation({
    container,
    renderer: 'svg',
    loop: false,
    autoplay: true,
    path
  });

  anim.addEventListener('complete', () => {
    anim.destroy();
    onComplete && onComplete();
  });
}

playAnimation('a1.json', document.getElementById('stage'), () => {
  playAnimation('a2.json', document.getElementById('stage'), () => {
    playAnimation('a3.json', document.getElementById('stage'));
  });
});

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

Управление очередью анимаций

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

const queue = [
  'anim1.json',
  'anim2.json',
  'anim3.json'
];

function playQueue(list, container) {
  let index = 0;

  function next() {
    if (index >= list.length) return;

    const anim = lottie.loadAnimation({
      container,
      renderer: 'svg',
      loop: false,
      autoplay: true,
      path: list[index]
    });

    anim.addEventListener('complete', () => {
      anim.destroy();
      index += 1;
      next();
    });
  }

  next();
}

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

Использование сегментов для последовательного проигрывания

Lottie Web поддерживает воспроизведение фрагментов таймлайна через playSegments. Это позволяет строить последовательность не из разных файлов, а из частей одной анимации.

const anim = lottie.loadAnimation({
  container: document.getElementById('stage'),
  renderer: 'svg',
  loop: false,
  autoplay: false,
  path: 'fullAnimation.json'
});

anim.playSegments([0, 60], true);

anim.addEventListener('complete', () => {
  anim.playSegments([60, 120], true);
});

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

Переключение сегментов как конечный автомат

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

const anim = lottie.loadAnimation({
  container: document.getElementById('stage'),
  renderer: 'svg',
  loop: false,
  autoplay: false,
  path: 'sequence.json'
});

const states = [
  [0, 50],
  [50, 100],
  [100, 150]
];

let stateIndex = 0;

function playState(index) {
  anim.playSegments(states[index], true);
}

anim.addEventListener('complete', () => {
  stateIndex += 1;
  if (stateIndex < states.length) {
    playState(stateIndex);
  }
});

playState(stateIndex);

Такой подход позволяет строить детерминированные последовательности без перегрузки DOM новыми экземплярами.

Асинхронная последовательность через Promise-обёртку

Интеграция с асинхронной логикой упрощается через оборачивание событий Lottie в Promise. Это позволяет использовать линейный поток выполнения.

function loadAndPlay(path, container) {
  return new Promise((resolve) => {
    const anim = lottie.loadAnimation({
      container,
      renderer: 'svg',
      loop: false,
      autoplay: true,
      path
    });

    anim.addEventListener('complete', () => {
      anim.destroy();
      resolve();
    });
  });
}

Последовательное выполнение выстраивается через цепочку then или через async/await.

async function runSequence() {
  await loadAndPlay('a1.json', document.getElementById('stage'));
  await loadAndPlay('a2.json', document.getElementById('stage'));
  await loadAndPlay('a3.json', document.getElementById('stage'));
}

runSequence();

Такой стиль устраняет необходимость ручного управления состоянием очереди и упрощает чтение логики.

Параллельная подготовка и последовательный запуск

При последовательном воспроизведении важно различать загрузку и запуск. JSON-анимации могут быть предзагружены, а затем последовательно воспроизведены без задержек на сеть.

const animations = ['a1.json', 'a2.json', 'a3.json'];
const cache = new Map();

function preload(path) {
  return fetch(path).then(res => res.json()).then(data => {
    cache.set(path, data);
  });
}

function playFromCache(path, container) {
  return new Promise((resolve) => {
    const anim = lottie.loadAnimation({
      container,
      renderer: 'svg',
      loop: false,
      autoplay: true,
      animationData: cache.get(path)
    });

    anim.addEventListener('complete', () => {
      anim.destroy();
      resolve();
    });
  });
}

Разделение подготовки и воспроизведения уменьшает задержки между этапами последовательности.

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

При последовательном воспроизведении в одном DOM-контейнере требуется корректное уничтожение предыдущего экземпляра. Несоблюдение этого приводит к наложению SVG-слоёв и утечкам памяти.

let currentAnim = null;

function play(path, container) {
  if (currentAnim) {
    currentAnim.destroy();
  }

  return new Promise((resolve) => {
    currentAnim = lottie.loadAnimation({
      container,
      renderer: 'svg',
      loop: false,
      autoplay: true,
      path
    });

    currentAnim.addEventListener('complete', () => {
      resolve();
    });
  });
}

Контроль над экземпляром обеспечивает стабильность при длинных последовательностях.

Последовательность с условными переходами

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

anim.addEventListener('complete', () => {
  const direction = Math.random() > 0.5 ? 'A' : 'B';

  if (direction === 'A') {
    playAnimation('a2.json', container);
  } else {
    playAnimation('b2.json', container);
  }
});

Такая структура превращает последовательное воспроизведение в управляемую систему сценариев.

Оптимизация длительных цепочек

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

  • повторное использование одного контейнера
  • минимизация пересоздания SVG-дерева
  • предзагрузка JSON
  • отключение autoplay при необходимости ручного контроля
  • явный destroy после завершения
anim.setSpeed(1);
anim.goToAndStop(0, true);

Контроль скорости и позиции кадра позволяет синхронизировать переходы между этапами без визуальных разрывов.

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

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

Состояния могут описываться структурой:

const flow = [
  { path: 'intro.json', next: 'main' },
  { path: 'main.json', next: 'outro' },
  { path: 'outro.json', next: null }
];

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