Переключение между рендерерами

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

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


Доступные рендереры

SVG-рендерер

SVG является наиболее часто используемым вариантом. Он строит DOM-дерево из SVG-элементов и управляет их атрибутами во время проигрывания анимации.

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

  • высокая четкость при масштабировании
  • доступность через DOM (возможность стилизации CSS)
  • значительная нагрузка на браузер при большом количестве слоев
  • чувствительность к сложным композициям

SVG подходит для интерфейсной анимации, иконок и умеренно сложных сцен.


Canvas-рендерер

Canvas-рендерер использует 2D контекст HTML5 Canvas. В отличие от SVG, он не создает DOM-структуру и рисует пиксели напрямую.

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

  • высокая производительность при большом количестве объектов
  • отсутствие DOM-накладных расходов
  • невозможность прямого доступа к отдельным элементам сцены
  • менее гибкая постобработка через CSS

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


HTML-рендерер

HTML-рендерер преобразует слои в HTML-элементы и использует CSS-трансформации.

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

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

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


Выбор рендерера при инициализации

Рендерер задается при создании экземпляра анимации через параметр renderer.

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

Возможные значения:

  • "svg"
  • "canvas"
  • "html"

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


Смена рендерера в процессе выполнения

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

Стандартный механизм переключения реализуется через уничтожение текущего экземпляра и создание нового.

Базовый паттерн переключения

let animation;

function createAnimation(rendererType) {
  animation = lottie.loadAnimation({
    container: document.getElementById('anim'),
    renderer: rendererType,
    loop: true,
    autoplay: true,
    path: 'animation.json'
  });
}

function switchRenderer(newRenderer) {
  if (animation) {
    animation.destroy();
  }

  createAnimation(newRenderer);
}

createAnimation('svg');

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

При смене рендерера происходит полная реконструкция графического слоя:

  • SVG → Canvas: DOM-дерево уничтожается, создается canvas-контекст
  • Canvas → SVG: пиксельный буфер заменяется структурой DOM
  • HTML → SVG/Canvas: пересоздание всей композиции

Состояние воспроизведения может быть сохранено вручную:

const currentFrame = animation.currentFrame;

animation.destroy();

animation = lottie.loadAnimation({
  container: document.getElementById('anim'),
  renderer: 'canvas',
  loop: true,
  autoplay: true,
  path: 'animation.json'
});

animation.addEventListener('DOMLoaded', () => {
  animation.goToAndStop(currentFrame, true);
});

Фабрика рендереров

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

function getRendererByEnvironment() {
  const isLowPowerDevice = navigator.hardwareConcurrency < 4;
  const isMobile = /Mobi|Android/i.test(navigator.userAgent);

  if (isLowPowerDevice || isMobile) {
    return 'canvas';
  }

  return 'svg';
}

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

Учет производительности при выборе рендерера

SVG демонстрирует деградацию производительности при:

  • большом количестве path-элементов
  • сложных морфинг-анимациях
  • множественных масках и слоях прозрачности

Canvas сохраняет стабильный FPS при:

  • высокой плотности объектов
  • интенсивной перерисовке сцены
  • длительных анимациях без взаимодействия с DOM

HTML рендерер чувствителен к:

  • глубокой вложенности элементов
  • частым изменениям transform и opacity
  • сложным композиционным эффектам

Управление пересозданием без потери состояния

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

function snapshotState(anim) {
  return {
    frame: anim.currentFrame,
    direction: anim.playDirection
  };
}

function restoreState(anim, state) {
  anim.goToAndStop(state.frame, true);

  if (state.direction === -1) {
    anim.setDirection(-1);
  }
}

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


Условное переключение в зависимости от FPS

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

let fpsSamples = [];

function measureFPS(callback) {
  let last = performance.now();

  function frame() {
    const now = performance.now();
    fpsSamples.push(1000 / (now - last));
    last = now;

    if (fpsSamples.length < 30) {
      requestAnimationFrame(frame);
    } else {
      const avg = fpsSamples.reduce((a, b) => a + b) / fpsSamples.length;
      callback(avg);
    }
  }

  requestAnimationFrame(frame);
}

measureFPS((fps) => {
  const renderer = fps < 40 ? 'canvas' : 'svg';

  lottie.loadAnimation({
    container: document.getElementById('anim'),
    renderer,
    loop: true,
    autoplay: true,
    path: 'animation.json'
  });
});

Поведение при повторной загрузке анимации

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

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

Важно учитывать отсутствие внутреннего кеширования рендерера между инстансами.


Типичные ограничения при смене рендерера

  • невозможность «горячей» замены движка без пересоздания
  • различия в визуальном результате между SVG и Canvas при сложных эффектах
  • различная поддержка blend modes и масок
  • отличия в субпиксельном сглаживании

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


Интеграционные сценарии

В системах с динамическим UI часто применяется комбинированная стратегия:

  • SVG для интерфейсных компонентов
  • Canvas для полноэкранных сцен
  • HTML для простых декоративных элементов

Управление осуществляется через централизованный менеджер анимаций, который пересоздает экземпляры при смене контекста отображения.