Использование именованных маркеров

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


После экспорта из After Effects в JSON файл Lottie содержит секцию markers, если они были заданы в композиции. Каждый маркер описывает именованный участок времени.

Типичная структура:

"markers": [
  {
    "tm": 0,
    "dr": 30,
    "cm": "start"
  },
  {
    "tm": 30,
    "dr": 45,
    "cm": "loading"
  },
  {
    "tm": 75,
    "dr": 25,
    "cm": "success"
  }
]

Ключевые поля:

  • tm — момент начала маркера (в кадрах или времени, зависит от настройки композиции)
  • dr — длительность сегмента
  • cm — имя маркера (comment/label)

Именование маркеров становится основой для управления анимацией на уровне логики приложения.


Логика именованных маркеров

Использование строковых идентификаторов вместо числовых диапазонов решает несколько проблем:

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

Пример логических состояний:

  • idle
  • loading
  • success
  • error

Такая модель превращает анимацию в конечный автомат.


Загрузка и доступ к маркерам

После инициализации анимации через lottie.loadAnimation объект анимации содержит данные JSON, включая маркеры.

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

Доступ к маркерам:

animation.addEventListener('DOMLoaded', () => {
  console.log(animation.markers);
});

Каждый элемент массива содержит:

  • name (или cm в исходном JSON)
  • time
  • duration

Переход к маркеру по имени

Основной способ работы с именованными маркерами — переход к сегменту по его имени.

animation.goToAndPlay('loading', true);

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

  • true — значение трактуется как имя маркера
  • false — значение трактуется как кадр

Переход останавливается на границах маркера и воспроизводит сегмент.


Использование playSegments с именами маркеров

Метод playSegments позволяет проигрывать диапазоны, включая именованные маркеры.

animation.playSegments(['loading', 'success'], true);

Поведение:

  • первый аргумент — массив из двух маркеров
  • второй аргумент true активирует интерпретацию имен

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


Управление состояниями интерфейса через маркеры

Именованные маркеры часто используются как слой управления UI состояниями.

Пример модели:

function setState(state) {
  switch (state) {
    case 'idle':
      animation.goToAndStop('idle', true);
      break;
    case 'loading':
      animation.goToAndPlay('loading', true);
      break;
    case 'success':
      animation.playSegments(['loading', 'success'], true);
      break;
    case 'error':
      animation.goToAndPlay('error', true);
      break;
  }
}

Такой подход позволяет полностью абстрагироваться от кадров.


Синхронизация маркеров с логикой приложения

Именованные маркеры могут использоваться как триггеры событий.

animation.addEventListener('enterFrame', () => {
  const currentFrame = animation.currentFrame;

  animation.markers.forEach(marker => {
    if (currentFrame === marker.time) {
      console.log('Вход в маркер:', marker.name);
    }
  });
});

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


Динамическое управление анимацией

Именованные маркеры позволяют строить динамические сценарии:

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

Пример цепочки:

animation.goToAndPlay('loading', true);

animation.addEventListener('complete', () => {
  animation.goToAndPlay('success', true);
});

Ошибки при работе с именованными маркерами

Частые проблемы:

Несовпадение имени маркера

animation.goToAndPlay('Loadng', true); // ошибка: опечатка

Имена чувствительны к точному совпадению.


Отсутствие маркеров в JSON

Если экспорт не содержит секцию markers, вызовы по имени не работают:

animation.markers // undefined или []

Конфликт кадров и имен

При использовании false во втором аргументе:

animation.goToAndPlay('loading', false);

значение трактуется как кадр, что приводит к некорректному поведению.


Практика организации имен

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

  • префиксы состояний: state_idle, state_loading
  • действия: action_open, action_close
  • результаты: result_success, result_error

Это снижает риск конфликтов и повышает читаемость JSON.


Интеграция с компонентной архитектурой

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

class Loader {
  constructor(animation) {
    this.animation = animation;
  }

  setLoading(isLoading) {
    if (isLoading) {
      this.animation.goToAndPlay('loading', true);
    } else {
      this.animation.goToAndPlay('idle', true);
    }
  }
}

Такой подход делает анимацию реактивной по отношению к состоянию.


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

Именованные маркеры особенно эффективны в следующих случаях:

  • интерфейсы с состояниями загрузки
  • анимации кнопок с переходами hover/active
  • onboarding-последовательности
  • визуальные индикаторы статусов
  • микроинтеракции в SPA-приложениях

Ограничения подхода

Несмотря на гибкость, модель имеет ограничения:

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

Поведение при циклическом воспроизведении

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

animation.loop = true;
animation.goToAndPlay('loading', true);

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


Комбинация с сегментным управлением

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

animation.playSegments([10, 50], true);
animation.playSegments(['loading', 'success'], true);

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


Оптимизация архитектуры анимаций

При масштабных проектах используется принцип:

  • один JSON = набор состояний
  • каждый маркер = изолированное состояние
  • код не знает кадров, только имена

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