AnimTimingFunction

Тайминговая функция в анимации определяет, как изменяется прогресс отрисовки SVG-пути во времени. В контексте Vivus это механизм, который преобразует линейный прогресс анимации t ∈ [0, 1] в нелинейную кривую f(t), задающую реальную скорость прорисовки обводки.

Базовая модель анимации Vivus строится вокруг нормализованного времени:

t = currentFrame / totalFrames

Линейная интерпретация предполагает равномерное изменение состояния:

progress = t

Тайминговая функция вводит преобразование:

progress = f(t)

где f(t) — функция, определяющая ускорение или замедление анимации.

Ключевое свойство такой функции:

f(0) = 0
f(1) = 1

Это гарантирует корректное начало и завершение анимации без скачков.


Роль в механике прорисовки SVG

Vivus управляет анимацией через манипуляцию свойствами stroke-dasharray и stroke-dashoffset. Тайминговая функция влияет не на геометрию SVG, а на распределение кадров, в которых изменяется смещение штриха.

При линейной функции каждый сегмент пути отрисовывается равномерно. При нелинейной функции изменяется плотность “видимого” прогресса:

  • при ускорении начало анимации медленное, затем резкий рост
  • при замедлении начальный прогресс быстрый, затем плавное завершение
  • при S-образной кривой комбинируются оба эффекта

Формы тайминговых функций

Линейная функция

f(t) = t

Самая простая модель. Используется, когда требуется равномерная прорисовка без акцентов на фазах анимации.


Квадратическое ускорение

f(t) = t²

Создаёт эффект плавного старта с ускорением ближе к завершению. В SVG-анимации визуально усиливает “дорисовку” последних сегментов.


Квадратическое замедление

f(t) = 1 - (1 - t)²

Обеспечивает быстрый старт и плавное завершение. Часто используется для эффектов появления логотипов.


S-образная кривая (ease-in-out)

f(t) = 3t² - 2t³

Балансирует ускорение и замедление, создавая естественное восприятие движения.


Использование кастомной функции в Vivus

Vivus позволяет передавать собственную функцию тайминга через параметр animTimingFunction. Функция получает значение прогресса t и возвращает преобразованное значение.

const easeInOutCubic = function (t) {
  return t < 0.5
    ? 4 * t * t * t
    : 1 - Math.pow(-2 * t + 2, 3) / 2;
};

const svgAnimation = new Vivus('my-svg', {
  type: 'delayed',
  duration: 200,
  animTimingFunction: easeInOutCubic
});

Функция должна быть детерминированной и возвращать значения строго в диапазоне [0, 1], иначе поведение анимации становится непредсказуемым.


Влияние на типы анимации Vivus

Vivus поддерживает несколько режимов отрисовки путей:

  • delayed
  • oneByOne
  • sync

Тайминговая функция применяется поверх всех режимов, но эффект проявляется по-разному:

delayed

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

oneByOne

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

sync

Все пути анимируются одновременно, поэтому функция влияет на общую “кривую видимости” всей композиции SVG.


Интерполяция и дискретизация

Vivus работает не с непрерывной математической кривой, а с дискретными кадрами. Тайминговая функция применяется на каждом шаге цикла:

for each frame:
    t = frame / totalFrames
    adjusted = f(t)
    applyStrokeOffset(adjusted)

Чем больше значение duration, тем выше плотность дискретизации и тем точнее соответствует визуальный результат заданной функции.


Пользовательские кривые и ограничения

При проектировании кастомных функций учитываются следующие ограничения:

  • выход за пределы [0, 1] приводит к визуальным артефактам
  • отрицательные значения создают “обратную отрисовку”
  • резкие разрывы функции вызывают скачки stroke-offset

Пример некорректной функции:

f(t) = sin(t * 20)

Такое поведение приводит к многократным возвратам и повторной прорисовке сегментов.


Комбинирование с easing-таблицами

Вместо функции может использоваться предрасчитанная кривая (lookup table). В таком случае прогресс интерполируется между значениями массива.

curve = [0, 0.02, 0.05, 0.1, 0.18, ... , 1]

Vivus линейно интерполирует значения между ближайшими точками, создавая сложные нелинейные эффекты без вычислений на каждом кадре.


Производительность вычислений

Кастомные функции добавляют вычислительную нагрузку на каждый кадр анимации. При большом количестве SVG-путей оптимизация становится критичной.

Оптимизационные подходы:

  • кэширование значений f(t) для фиксированных duration
  • использование lookup tables вместо функций
  • минимизация математических операций внутри функции
  • отказ от тригонометрии в реальном времени

Связь с восприятием отрисовки SVG

Тайминговая функция напрямую влияет на визуальное восприятие структуры SVG. При изменении кривой:

  • меняется акцент на деталях пути
  • изменяется ощущение “тяжести” линий
  • создаётся эффект ручной прорисовки или механической трассировки

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


Составные функции

В сложных сценариях используется композиция функций:

f(t) = easeOut(easeIn(t))

Или через масштабирование времени:

f(t) = ease(t * k)

где k изменяет скорость “внутри” анимации, создавая эффект ускоренного или замедленного сегмента.


Поведение при повторном запуске анимации

При перезапуске Vivus функция применяется заново к полному диапазону [0, 1]. Это означает отсутствие накопления состояния между циклами, если не используется внешний контроллер прогресса.

При ручном управлении прогрессом:

vivus.setFrame(progress)

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


Практическая интерпретация кривых

Разные типы функций формируют разные визуальные сценарии:

  • линейная функция — техническая отрисовка схем
  • ease-in — эффект “построения структуры”
  • ease-out — эффект появления готового объекта
  • ease-in-out — имитация ручного рисования

Каждый вариант влияет на характер движения линии, несмотря на идентичную геометрию SVG-пути.