Перемотка к определенному времени

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

В основе управления временем лежит концепция двух параллельных шкал:

  • кадры (frames) — дискретная система координат анимации
  • время (seconds / milliseconds) — непрерывная временная шкала

Каждая анимация имеет параметры:

  • totalFrames — общее количество кадров
  • totalTime — длительность в секундах
  • frameRate — частота кадров

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


Базовый механизм перемотки

Основные методы управления позицией воспроизведения:

  • goToAndStop(value, isFrame)
  • goToAndPlay(value, isFrame)

Ключевой параметр isFrame определяет интерпретацию первого аргумента:

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

Перемотка по кадрам

animation.goToAndStop(45, true);

Анимация будет установлена на 45-й кадр и остановлена.

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


Перемотка по времени

animation.goToAndStop(1.5, false);

Анимация устанавливается на отметку 1.5 секунды.

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


Преобразование времени в кадры

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

[ frame = time frameRate]

Пример:

const time = 2; // секунды
const frame = time * animation.frameRate;

animation.goToAndStop(frame, true);

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


Перемотка с учётом текущего состояния

У Lottie-анимации есть два ключевых свойства:

  • currentFrame
  • currentTime

Они позволяют получать текущую позицию и использовать её для относительной навигации.

Переход вперёд на N секунд

const step = 0.5;

const newTime = animation.currentTime + step;
animation.goToAndStop(newTime, false);

Переход назад на N кадров

const stepFrames = 10;

animation.goToAndStop(animation.currentFrame - stepFrames, true);

Ограничение диапазона перемотки

При программной навигации важно учитывать границы:

  • минимум: 0
  • максимум: totalFrames или totalTime

Пример безопасной перемотки:

function safeSeekTime(animation, time) {
  const clamped = Math.max(0, Math.min(time, animation.totalTime));
  animation.goToAndStop(clamped, false);
}

Аналогично для кадров:

function safeSeekFrame(animation, frame) {
  const clamped = Math.max(0, Math.min(frame, animation.totalFrames));
  animation.goToAndStop(clamped, true);
}

Мгновенная синхронизация с UI-слайдером

Одно из наиболее частых применений — привязка прогресса к input range.

slider.addEventListener('input', (e) => {
  const progress = e.target.value; // 0..1
  const frame = progress * animation.totalFrames;

  animation.goToAndStop(frame, true);
});

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


Перемотка с учётом субкадров

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

Метод:

animation.setSubframe(false);

После отключения субкадров перемотка становится строго дискретной по кадрам, что полезно для:

  • пиксель-арта
  • UI-индикаторов
  • синхронизации с шаговыми процессами

Использование goToAndPlay для перемотки с продолжением

Если требуется перемотать и продолжить воспроизведение:

animation.goToAndPlay(2, false);

Или по кадрам:

animation.goToAndPlay(60, true);

Поведение отличается от goToAndStop тем, что после установки позиции начинается автоматическое воспроизведение.


Привязка к внешним событиям

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

Пример: наведение мыши

button.addEventListener('mouseenter', () => {
  animation.goToAndPlay(0, true);
});

button.addEventListener('mouseleave', () => {
  animation.goToAndStop(0, true);
});

Пример: прокрутка страницы

window.addEventListener('scroll', () => {
  const scrollTop = window.scrollY;
  const maxScroll = document.body.scrollHeight - window.innerHeight;

  const progress = scrollTop / maxScroll;
  const frame = progress * animation.totalFrames;

  animation.goToAndStop(frame, true);
});

Точное позиционирование через нормализованный прогресс

Часто удобнее работать не с кадрами и секундами, а с нормализованным значением 0..1.

function seekByProgress(animation, progress) {
  const frame = progress * animation.totalFrames;
  animation.goToAndStop(frame, true);
}

Такой подход упрощает интеграцию с:

  • прогресс-барами
  • скролл-триггерами
  • системами состояний

Перемотка с учетом скорости анимации

При изменённой скорости (setSpeed) важно помнить, что:

  • currentTime отражает уже скорректированное время
  • goToAndStop работает в реальных единицах, но визуальная динамика зависит от speed
animation.setSpeed(2);

animation.goToAndStop(1, false);

Ускорение не влияет на позиционирование, только на дальнейшее воспроизведение.


Синхронизация нескольких анимаций

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

function syncAnimations(time) {
  animations.forEach(anim => {
    anim.goToAndStop(time, false);
  });
}

Если анимации имеют разную длительность:

function syncByProgress(progress) {
  animations.forEach(anim => {
    anim.goToAndStop(progress * anim.totalFrames, true);
  });
}

Погрешности и особенности интерполяции

При частых вызовах goToAndStop важно учитывать:

  • возможные микролаги при большом количестве вызовов
  • разницу между frame-based и time-based режимами
  • влияние браузерного рендеринга

Оптимизация достигается через:

  • throttling событий (scroll, mousemove)
  • использование requestAnimationFrame
  • переход на прогресс-ориентированную модель управления
let latestProgress = 0;

function render() {
  animation.goToAndStop(latestProgress * animation.totalFrames, true);
  requestAnimationFrame(render);
}

render();

Вычисление ближайшего кадра для дискретных переходов

При необходимости «снэппинга» к ближайшему кадру:

function snapToFrame(animation, frameRate, time) {
  const frame = Math.round(time * frameRate);
  animation.goToAndStop(frame, true);
}

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