Линейная анимация

Принцип линейного прорисовывания контура

Линейная анимация SVG в контексте Vivus строится вокруг поэтапного увеличения видимой части контура, когда путь «рисуется» от начала до конца с равномерной скоростью. Базовая идея заключается в управлении свойствами stroke-dasharray и stroke-dashoffset, которые позволяют имитировать процесс рисования линии.

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

Ключевой момент — равномерное изменение видимой части контура во времени без ускорений и замедлений. Это отличает линейную анимацию от easing-моделей, где скорость изменяется по кривой.

Математическая основа эффекта прорисовки

Для любого SVG path вычисляется его полная длина:

const length = path.getTotalLength();

После этого применяются параметры:

  • stroke-dasharray = length
  • stroke-dashoffset = length

На старте весь путь скрыт, так как смещение совпадает с длиной. Далее значение stroke-dashoffset уменьшается до нуля.

Линейность достигается тем, что изменение offset происходит равномерно:

offset(t) = L - (L * t / T)

где:

  • L — длина пути
  • T — длительность анимации
  • t — текущее время

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

Базовая реализация линейной анимации

Несмотря на то, что Vivus абстрагирует работу с path, понимание низкоуровневой механики важно для настройки поведения.

Простейшая реализация:

const path = document.querySelector("path");
const length = path.getTotalLength();

path.style.strokeDasharray = length;
path.style.strokeDashoffset = length;

let start = null;
const duration = 2000;

function animate(timestamp) {
  if (!start) start = timestamp;

  const progress = timestamp - start;
  const percent = Math.min(progress / duration, 1);

  path.style.strokeDashoffset = length * (1 - percent);

  if (progress < duration) {
    requestAnimationFrame(animate);
  }
}

requestAnimationFrame(animate);

В этом примере используется строго линейное изменение прогресса без нелинейных функций интерполяции.

Линейность в контексте Vivus

В Vivus линейная анимация чаще всего проявляется через режимы рисования, где отсутствует перераспределение времени между сегментами пути.

Основные параметры, влияющие на линейное поведение:

  • duration — общая длительность анимации
  • type — способ распределения отрисовки
  • animTimingFunction — функция интерполяции (в некоторых реализациях кастомизируется)
  • selfDestroy — управление очисткой после завершения

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

Режимы анимации и их влияние на линейность

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

1. Последовательная прорисовка (delayed)

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

new Vivus('svg', {
  type: 'delayed',
  duration: 200
});

Особенность:

  • сегменты запускаются последовательно
  • внутри сегмента движение равномерное
  • создаётся эффект «очереди рисования»

2. Одновременная прорисовка (sync)

Все пути начинают и заканчивают анимацию одновременно.

new Vivus('svg', {
  type: 'sync',
  duration: 200
});

Особенность:

  • глобально линейное распределение времени
  • визуально равномерное заполнение всей сцены
  • подходит для схем и иконок

3. Независимая анимация (oneByOne)

Каждый сегмент имеет свою фазу, но внутри неё сохраняется линейное изменение.

new Vivus('svg', {
  type: 'oneByOne',
  duration: 200
});

Особенность:

  • строгая последовательность элементов
  • линейность сохраняется только локально

Роль requestAnimationFrame в линейной анимации

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

Без него возможны:

  • скачки прогресса
  • неравномерное движение
  • рассинхронизация времени

Принцип:

каждый кадр = одинаковый временной шаг

что критично для сохранения линейного восприятия движения.

Интерполяция и отказ от easing-функций

Линейная анимация определяется отсутствием нелинейной интерполяции. В терминах анимации это означает:

progress = time / duration

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

  • ease-in
  • ease-out
  • cubic-bezier

Любое отклонение от линейной интерполяции приводит к изменению скорости прорисовки и нарушает равномерность.

Особенности работы с несколькими путями

SVG-документы часто содержат множество path-элементов. При линейной анимации важно учитывать:

  • одинаковую длину путей не требуется
  • каждый path имеет собственную длину
  • синхронизация происходит через общий таймер

Пример логики:

paths.forEach(path => {
  const length = path.getTotalLength();
  path.style.strokeDasharray = length;
  path.style.strokeDashoffset = length;
});

Далее единый прогресс применяется ко всем элементам одновременно.

Оптимизация линейной анимации

При большом количестве элементов возникает нагрузка на браузер. Линейная анимация требует:

  • минимизации пересчёта layout
  • использования transform вместо layout-свойств
  • кэширования длины пути

Критический момент:

getTotalLength()

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

Типичные ошибки при реализации линейной анимации

  1. Повторный расчёт длины пути в цикле анимации
  2. Использование setInterval вместо requestAnimationFrame
  3. Применение easing-функций при заявленной линейности
  4. Несогласованность времени между сегментами
  5. Изменение SVG DOM во время анимации

Каждая из этих ошибок приводит к нарушению равномерного движения и визуальным рывкам.

Визуальные сценарии применения

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

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

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

Поведение при масштабировании SVG

SVG сохраняет геометрическую корректность при масштабировании, однако длина пути остаётся константой в координатах документа.

Это означает:

  • линейная анимация не зависит от размера экрана
  • скорость визуального эффекта сохраняется
  • stroke-width может влиять на восприятие, но не на расчёт

При адаптивных интерфейсах это обеспечивает стабильность эффекта.