Библиотека Vivus строит анимацию SVG на основе управления параметром
прогресса от 0 до 1, где:
0 — начальное состояние (пути полностью скрыты через
stroke-dashoffset)1 — финальное состояние (контуры полностью
прорисованы)Внутри движка каждый SVG-path преобразуется в набор параметров:
getTotalLength)stroke-dasharraystroke-dashoffsetАнимация фактически сводится к изменению
stroke-dashoffset по времени.
Reverse в Vivus — это не отдельный тип анимации, а изменение направления изменения прогресса:
0 → 11 → 0При этом логика отрисовки остаётся той же, меняется только интерполяция прогресса.
Если в обычном режиме вычисление выглядит так:
offset = length * (1 - progress)
то в обратном режиме:
offset = length * progress
В экземпляре Vivus можно управлять направлением проигрывания:
const vivus = new Vivus('svg', {
type: 'delayed',
duration: 200
});
// обычное проигрывание
vivus.play(1);
// обратное проигрывание
vivus.play(-1);
Передача отрицательного значения изменяет направление временной шкалы.
Часто используется схема «вперёд-назад»:
const vivus = new Vivus('svg', {
type: 'oneByOne',
duration: 150,
onComplete: function () {
this.play(-1);
}
});
При завершении анимации она автоматически запускается в обратную сторону.
В случаях, когда требуется точная синхронизация:
vivus.setFrameProgress(1);
vivus.play(-1);
или:
vivus.setFrameProgress(0.5);
Такой подход используется при создании интерактивных компонентов, где направление зависит от UI-состояния.
При type: 'delayed' каждый path получает задержку. В
reverse:
Для oneByOne порядок отрисовки строго последовательный.
При reverse:
При sync все пути анимируются одновременно:
Reverse не всегда работает как «идеальное перемещение назад» в следующих случаях:
stroke-dasharray вручнуюselfDestroy: truelet direction = 1;
button.addEventListener('click', () => {
vivus.play(direction);
direction *= -1;
});
Модель используется для иконок:
const loop = function () {
vivus.play(1);
setTimeout(() => {
vivus.play(-1);
}, 2000);
};
Используется для декоративных SVG-анимаций.
element.addEventListener('mouseenter', () => {
vivus.play(1);
});
element.addEventListener('mouseleave', () => {
vivus.play(-1);
});
Создаёт эффект «проявления и исчезновения» контура.
forceRender используется для принудительного пересчёта и
перерисовки SVG-путей без запуска анимации.
Основная задача — синхронизация визуального состояния с внутренней моделью Vivus.
Если SVG изначально находится в display: none:
После отображения требуется:
vivus.forceRender();
При ресайзе:
window.addEventListener('resize', () => {
vivus.forceRender();
});
Если содержимое SVG заменяется через DOM:
Например:
document.querySelectorAll('path').forEach(p => {
p.setAttribute('stroke-width', 4);
});
vivus.forceRender();
При вызове выполняются следующие шаги:
path.getTotalLength()stroke-dasharraystroke-dashoffsetФактически происходит «переинициализация без пересоздания экземпляра».
| Метод | Поведение |
|---|---|
| play() | запускает анимацию |
| stop() | останавливает |
| reset() | сбрасывает прогресс |
| forceRender() | пересчитывает геометрию SVG |
forceRender не меняет состояние прогресса напрямую, а
только пересобирает визуальную модель.
При использовании reverse важно учитывать:
forceRender направление сохраняетсяТипичный сценарий:
vivus.play(-1);
setTimeout(() => {
vivus.forceRender();
vivus.play(-1);
}, 1000);
Если SVG ещё не доступен в DOM:
Постоянный вызов при каждом изменении размера окна приводит к:
Оптимизированный вариант:
let timeout;
window.addEventListener('resize', () => {
clearTimeout(timeout);
timeout = setTimeout(() => vivus.forceRender(), 150);
});
themeToggle.addEventListener('click', () => {
document.body.classList.toggle('dark');
vivus.forceRender();
vivus.play(-1);
});
container.innerHTML = newSVG;
const vivus = new Vivus('svg', {
type: 'delayed',
duration: 120
});
vivus.forceRender();
vivus.play(1);
slider.addEventListener('input', (e) => {
const value = e.target.value / 100;
vivus.setFrameProgress(value);
if (value < 0.2) {
vivus.play(-1);
}
});
При комбинировании reverse и forceRender возможны состояния:
Такие эффекты связаны с тем, что forceRender пересчитывает геометрию, не дожидаясь завершения текущего кадра анимации.