В анимациях SVG, основанных на поэтапном раскрытии контуров, ключевым
элементом управления становится преобразование линейного времени в
нелинейный прогресс. Базовая модель предполагает нормализацию времени в
диапазон [0; 1], где 0 соответствует началу анимации, а 1 —
её завершению.
Линейная зависимость задаётся тривиально:
f(t) = t
Однако визуальное восприятие движения почти всегда требует иного характера изменения скорости: ускорения, замедления, инерции, «пружинного» эффекта. Именно это и формируют кастомные функции времени.
В контексте Vivus временная функция применяется для преобразования глобального прогресса анимации в локальный коэффициент отрисовки stroke-параметров SVG-пути.
Любая анимация построена на изменении параметра обводки:
stroke-dasharray задаёт структуру штрихаstroke-dashoffset управляет видимой частью линииФункционально это сводится к вычислению коэффициента заполнения пути:
p(t)
где p(t) — прогресс отрисовки.
При линейной функции:
p(t) = t
при кастомной:
p(t) = f(t)
Функция f(t) определяет характер движения по контуру
SVG.
Внутренняя логика анимации в Vivus строится вокруг цикла обновления кадра:
[0;1]Схематически:
t =
strokeOffset = length (1 - p)
Таким образом, функция времени напрямую определяет скорость визуального «прорисовывания» SVG-пути.
Самый простой вариант, обеспечивающий равномерную скорость:
f(t) = t
Поведение полностью предсказуемо, но визуально часто воспринимается как механическое.
Создаёт эффект плавного разгона:
f(t) = t^2
В начале движение почти незаметно, затем интенсивность резко возрастает.
Инвертированная квадратичная функция:
f(t) = 1 - (1 - t)^2
Используется для эффектов «доделывания» линии, когда основной объём отрисовки происходит быстро, а финал — плавный.
Более гибкое управление даёт кубическая интерполяция:
f(t) = t^3
или комбинации:
f(t) = 3t^2 - 2t^3
Такая форма часто используется как базовая easing-функция без резких скачков производной.
В Vivus поддерживается передача функции, которая принимает нормализованный прогресс и возвращает преобразованное значение.
Типовая структура:
new Vivus('my-svg', {
duration: 200,
animTimingFunction: function (t) {
return t;
}
});
Функция вызывается на каждом кадре, где t ∈ [0;1].
Поскольку анимация выполняется через
requestAnimationFrame, фактический прогресс
дискретизируется:
t_n = f()
где:
n — текущий кадрN — общее число кадровЧем более резкая функция f(t), тем сильнее визуально
заметны скачки при низкой частоте кадров.
Корректная временная функция должна сохранять область значений:
f(t) t
При выходе за границы возникают артефакты:
Обычно применяется нормализация:
f_{norm}(t) = (1, (0, f(t)))
Более сложные эффекты достигаются через композицию:
f(t) = a f_1(t) + (1 - a) f_2(t)
где a управляет вкладом каждой функции.
Пример гибридной модели:
f(t) = 3t^2 - 2t^3
Такая форма часто используется как универсальная easing-кривая.
Внутренне SVG-путь разбивается на сегменты, и прогресс функции времени распределяется по длине:
L_{drawn} = L_{total} f(t)
где:
L_total — полная длина путиL_drawn — текущая длина отображаемой частиЭто преобразуется в stroke-dashoffset, который визуально
«скрывает» или «раскрывает» линию.
Функция с медленным стартом и ускорением:
f(t) = t^2(3 - 2t)
f(t) =
f(t) = t + 0.05(2t)
Такие функции применяются для имитации живого движения линии, особенно в логотипах и декоративной графике.
В контексте SVG-анимаций вычисление функции времени выполняется на каждом кадре, что накладывает ограничения:
Сложные функции приводят к росту нагрузки на главный поток браузера, особенно при большом количестве одновременно анимируемых SVG-элементов.
Одна и та же геометрия SVG может восприниматься по-разному в зависимости от временной функции:
Таким образом, временная функция становится не вспомогательным параметром, а полноценным инструментом визуального дизайна анимации в Vivus