В основе управления проигрыванием в Lottie Web лежит работа с
диапазонами кадров, которые формируют логические отрезки анимации.
Сегмент представляет собой пару значений
[startFrame, endFrame], ограничивающих часть композиции,
которую необходимо воспроизвести.
Такая модель позволяет разрезать одну композицию на независимые фрагменты и выстраивать из них последовательности без необходимости модификации исходного JSON.
Каждый сегмент задаётся двумя числами:
Внутренне Lottie интерпретирует их как диапазон временной шкалы композиции. Пример структуры:
const segment = [0, 30];
При этом важно учитывать, что сегменты работают в координатах исходной композиции, а не относительно уже обрезанного фрагмента.
В Lottie Web управление сегментами осуществляется через метод:
animation.playSegments([from, to], forceFlag);
где:
from — начальный кадрto — конечный кадрforceFlag — принудительный запуск (обрывает текущее
воспроизведение)Простейший пример:
animation.playSegments([0, 25], true);
Такой вызов инициирует проигрывание только указанного диапазона.
Сегменты начинают приобретать практическую ценность при объединении в цепочки. Типовая задача — воспроизведение нескольких отрезков один за другим.
const segments = [
[0, 30],
[30, 60],
[60, 90]
];
Для последовательного запуска применяется обработчик завершения:
let index = 0;
function playNextSegment() {
if (index >= segments.length) return;
const segment = segments[index];
animation.playSegments(segment, true);
}
animation.addEventListener('complete', () => {
index++;
playNextSegment();
});
playNextSegment();
Здесь используется событие complete, фиксирующее
окончание текущего сегмента и переключающее управление на следующий.
При работе с последовательностями сегментов важно учитывать направление воспроизведения. Lottie позволяет проигрывать сегменты в прямом и обратном направлении, если правильно задать границы.
animation.playSegments([60, 30], true);
Такой подход используется для обратных переходов или симметричных анимаций.
При усложнении логики последовательность превращается в управляемую очередь. В этом случае вводится структура, которая хранит состояние исполнения.
class SegmentQueue {
constructor(animation, segments) {
this.animation = animation;
this.segments = segments;
this.current = 0;
this.onCompl ete = this.onComplete.bind(this);
this.animation.addEventListener('complete', this.onComplete);
}
start() {
this.current = 0;
this.play();
}
play() {
const segment = this.segments[this.current];
this.animation.playSegments(segment, true);
}
onComplete() {
this.current++;
if (this.current < this.segments.length) {
this.play();
}
}
}
Использование:
const queue = new SegmentQueue(animation, [
[0, 20],
[20, 50],
[50, 120]
]);
queue.start();
Такой подход отделяет логику управления последовательностью от кода инициализации анимации.
В реальных сценариях последовательность сегментов редко является статичной. Часто требуется вмешательство в процессе выполнения.
queue.current = 0;
animation.stop();
queue.segments = [
[10, 40],
[40, 70]
];
При этом важно учитывать текущее состояние проигрывания, чтобы избежать рассинхронизации между визуальным состоянием и логикой очереди.
Сегментная модель часто используется как аналог конечного автомата. Каждый сегмент соответствует определённому состоянию интерфейса или сцены.
Пример структуры состояний:
const states = {
idle: [0, 15],
loading: [15, 45],
success: [45, 75],
error: [75, 105]
};
Переход между состояниями:
function setState(state) {
animation.playSegments(states[state], true);
}
Такой подход упрощает интеграцию анимации в UI-логику без привязки к временным характеристикам.
Для более гибкой композиции последовательностей часто используется обёртка над событиями, превращающая сегменты в асинхронный поток.
function playSegment(animation, segment) {
return new Promise(resolve => {
function handler() {
animation.removeEventListener('complete', handler);
resolve();
}
animation.addEventListener('complete', handler);
animation.playSegments(segment, true);
});
}
Использование:
async function runSequence() {
await playSegment(animation, [0, 30]);
await playSegment(animation, [30, 60]);
await playSegment(animation, [60, 90]);
}
Такой стиль позволяет выстраивать последовательности в линейной форме, близкой к синхронному коду.
При сложной анимационной логике сегменты объединяются в группы, формируя вложенные структуры.
const sequence = [
{
name: 'intro',
segments: [
[0, 20],
[20, 40]
]
},
{
name: 'main',
segments: [
[40, 80],
[80, 120]
]
}
];
Обход структуры:
async function playComplexSequence(sequence) {
for (const group of sequence) {
for (const segment of group.segments) {
await playSegment(animation, segment);
}
}
}
Сегменты часто используются в связке с пользовательскими событиями или состояниями интерфейса. В этом случае последовательность перестаёт быть линейной и становится реактивной.
button.addEventListener('click', () => {
animation.playSegments([0, 25], true);
});
form.addEventListener('submit', () => {
animation.playSegments([25, 60], true);
});
Каждое событие запускает соответствующий сегмент, формируя динамическую композицию.
Сегменты можно рассматривать как переиспользуемые блоки анимации. Один и тот же диапазон может участвовать в разных сценариях:
const segments = {
open: [0, 30],
hold: [30, 60],
close: [60, 90]
};
function openAnimation() {
animation.playSegments(segments.open, true);
}
function closeAnimation() {
animation.playSegments(segments.close, true);
}
Такой подход снижает зависимость от временных значений в логике приложения.
Ключевым аспектом при работе с последовательностями является контроль момента завершения сегмента. Основное событие:
animation.addEventListener('complete', callback);
Однако в сложных сценариях требуется фильтрация состояния, так как событие может срабатывать не только на сегментах, но и на полной композиции.
Распространённый подход — введение флага активности:
let isSegmentMode = false;
function play(segment) {
isSegmentMode = true;
animation.playSegments(segment, true);
}
animation.addEventListener('complete', () => {
if (!isSegmentMode) return;
// переход к следующему сегменту
});
При росте количества сегментов удобно рассматривать их как граф переходов:
const graph = {
start: { segment: [0, 20], next: 'loading' },
loading: { segment: [20, 60], next: 'success' },
success: { segment: [60, 100], next: null }
};
Исполнение:
let current = 'start';
function playNode(name) {
const node = graph[name];
animation.playSegments(node.segment, true);
animation.addEventListener('complete', function handler() {
animation.removeEventListener('complete', handler);
if (node.next) {
playNode(node.next);
}
});
}
playNode(current);
Такой подход превращает сегменты в управляемую систему переходов.
Некоторые сегменты требуют бесконечного повторения до наступления события:
animation.loop = true;
animation.playSegments([30, 60], true);
В этом случае завершение сегмента не наступает в привычном смысле, и
управление переходами должно учитывать состояние loop.
Сегменты могут изменять восприятие длительности анимации при изменении скорости:
animation.setSpeed(1.5);
animation.playSegments([0, 50], true);
Сокращение или растяжение временного диапазона влияет на плотность кадров внутри сегмента, но не на его границы.
При построении больших анимационных сценариев сегменты объединяются в многоуровневые конструкции:
Такая структура позволяет масштабировать управление Lottie-анимациями без модификации исходных файлов и без привязки к фиксированной временной шкале.