Отслеживание завершения

В библиотеке Vivus завершение анимации рассматривается как ключевое событие жизненного цикла SVG-рисования. Каждая анимация проходит последовательность кадров, после чего переходит в состояние завершённого рендера, когда все пути SVG полностью отрисованы в соответствии с выбранным типом анимации (delayed, oneByOne, sync).

Факт завершения не является побочным эффектом, а фиксированным состоянием экземпляра, которое может быть отловлено через callback-функции или косвенно определено через API состояния.


Callback завершения анимации

Основной способ отслеживания окончания работы Vivus — передача функции обратного вызова в конструктор экземпляра. Этот callback вызывается строго один раз после того, как все элементы SVG завершили отрисовку.

new Vivus('my-svg', {
  duration: 200,
  type: 'oneByOne'
}, function (obj) {
  // завершение анимации
});

Особенности механизма:

  • callback вызывается только при полном завершении анимации
  • не срабатывает при вызове stop()
  • срабатывает после финального кадра отрисовки
  • получает ссылку на текущий экземпляр Vivus

Внутренне это событие связано с достижением состояния, при котором прогресс анимации равен 1 (100%).


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

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

const animation = new Vivus('my-svg', {
  duration: 150
}, function () {
  console.log('done');
});

animation.reset();
animation.play();

При повторном запуске:

  • callback снова будет вызван после завершения нового цикла
  • каждый цикл анимации рассматривается как независимый
  • состояние завершения сбрасывается при reset()

Состояние экземпляра и косвенное отслеживание

Vivus не предоставляет полноценного event emitter API, однако состояние экземпляра позволяет отслеживать прогресс выполнения анимации.

Ключевые свойства:

  • isReady — SVG загружен и подготовлен к анимации
  • isPlaying — анимация находится в процессе выполнения
  • внутренний прогресс (не всегда публично документирован) используется для вычисления шага отрисовки

Типичный сценарий проверки:

if (!animation.isPlaying) {
  // анимация завершена или остановлена
}

Однако важно учитывать, что isPlaying = false не всегда означает завершение — это может быть остановка вручную.


Отличие завершения от остановки

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

Состояние Причина Callback
Завершение Достижение конца анимации вызывается
Stop Вызов stop() не вызывается
Reset Сброс прогресса не вызывается
animation.stop();   // прерывание без завершения
animation.reset();  // возврат к начальному состоянию
animation.play();   // новый цикл

Таким образом, завершение фиксируется только при естественном завершении прогресса.


Управление завершением через методы API

Хотя Vivus не предоставляет отдельного события onComplete, поведение можно контролировать через комбинацию методов:

play()

Запускает или возобновляет анимацию. Завершение фиксируется при достижении конца пути.

finish()

Принудительно завершает анимацию, мгновенно устанавливая финальное состояние SVG.

animation.finish();

Особенности:

  • callback завершения может не вызываться в зависимости от реализации
  • все пути SVG моментально считаются отрисованными
  • полезно для пропуска анимации

reset()

Сбрасывает состояние, возвращая SVG в исходный вид.

animation.reset();

После reset:

  • анимация считается незавершённой
  • callback может быть вызван при следующем завершении нового цикла

Отслеживание завершения через обёртку Promise

Для интеграции с современными асинхронными потоками часто используется обёртка над callback-механизмом Vivus, позволяющая трактовать завершение как Promise.

function vivusToPromise(svgId, options) {
  return new Promise(resolve => {
    new Vivus(svgId, options, function (instance) {
      resolve(instance);
    });
  });
}

Использование:

vivusToPromise('my-svg', {
  duration: 180
}).then(instance => {
  // завершено
});

Особенности такого подхода:

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

Завершение при нескольких экземплярах

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

const a1 = new Vivus('svg1', { duration: 100 }, onDone);
const a2 = new Vivus('svg2', { duration: 200 }, onDone);

Поведение:

  • каждый экземпляр имеет собственный callback завершения
  • завершение одного не влияет на другие
  • порядок завершения зависит от duration и сложности SVG

Для синхронизации используется внешний счётчик:

let completed = 0;

function onDone() {
  completed++;
  if (completed === 2) {
    // оба завершены
  }
}

Повторное завершение и циклы анимации

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

animation.play();  // завершение №1
animation.reset();
animation.play();  // завершение №2

Поведение системы:

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

Синхронизация завершения с логикой интерфейса

В сценариях UI-анимаций завершение часто используется как триггер перехода состояния интерфейса.

Типовые паттерны:

  • скрытие прелоадера после окончания отрисовки SVG
  • запуск следующей анимации после завершения текущей
  • активация интерактивных элементов после полной отрисовки
new Vivus('logo', {}, function () {
  document.querySelector('.content').classList.add('visible');
});

Особенность подхода:

  • логика привязывается к моменту полного завершения рендеринга SVG
  • исключается промежуточное состояние частичной отрисовки

Ограничения механизма завершения

Система отслеживания завершения в Vivus имеет ряд архитектурных ограничений:

  • отсутствует нативная система событий (addEventListener)
  • нет именованных событий типа complete
  • callback не может быть отписан после создания экземпляра
  • невозможна подписка на промежуточные стадии через тот же API завершения

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


Завершение в контексте типов анимации

Поведение завершения может незначительно отличаться в зависимости от выбранного режима:

  • delayed — завершение происходит после последовательной отрисовки каждого path с задержками
  • oneByOne — завершение фиксируется после последнего элемента в очереди
  • sync — завершение происходит одновременно для всех путей

Несмотря на различие внутренней логики, сигнал завершения унифицирован и не зависит от типа анимации.