Атрибуты SVG

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

SVG-элементы описываются через набор числовых и строковых атрибутов:

  • геометрические: x, y, cx, cy, r, width, height
  • параметры пути: d
  • оформление: fill, stroke, stroke-width
  • визуальные свойства: opacity, visibility
  • координатные трансформации: transform

Особенность SVG заключается в том, что многие из этих атрибутов напрямую влияют на отрисовку и могут изменяться без перерасчёта DOM-структуры. Это делает их удобной целью для анимации.

Popmotion работает с такими значениями как с потоками данных, обновляя их на каждом кадре через requestAnimationFrame.

Работа Popmotion с SVG через styler

Основной механизм взаимодействия Popmotion с DOM и SVG — styler. Он создаёт абстракцию над элементом, позволяя задавать свойства без ручного вызова setAttribute.

import { styler, tween } from 'popmotion';

const circle = document.querySelector('circle');
const circleStyler = styler(circle);

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

circleStyler.set({ cx: 50, cy: 50, r: 20 });

Popmotion автоматически определяет, какие свойства относятся к SVG и корректно применяет их через атрибуты элемента, а не через CSS.

Ключевая особенность: styler синхронизирует состояние объекта и DOM без ручного управления атрибутами.

Анимация геометрических атрибутов

Наиболее частый сценарий — анимация координат и размеров SVG-элементов.

Движение круга

import { animate, styler } from 'popmotion';

const circle = document.querySelector('circle');
const circleStyler = styler(circle);

animate({
  from: { cx: 50, cy: 50 },
  to: { cx: 300, cy: 200 },
  duration: 1000,
  onUpdate: v => circleStyler.set(v)
});

В этом примере изменяются атрибуты cx и cy, определяющие положение круга.

Изменение радиуса

animate({
  from: { r: 10 },
  to: { r: 80 },
  duration: 600,
  onUpdate: v => circleStyler.set(v)
});

Изменение радиуса приводит к перерасчёту формы элемента без необходимости перерисовки всей сцены.

Интерполяция числовых SVG-атрибутов

Popmotion использует встроенные интерполяторы, которые автоматически определяют тип данных:

  • числа интерполируются линейно
  • цвета интерполируются в RGB- или HEX-пространстве
  • сложные структуры разбиваются на компоненты
animate({
  from: { opacity: 0 },
  to: { opacity: 1 },
  duration: 400,
  onUpdate: v => circleStyler.set(v)
});

Даже такие атрибуты, как stroke-width, могут участвовать в анимации без дополнительной обработки.

Работа с линиями и прямоугольниками

SVG-примитивы имеют набор специфичных атрибутов:

  • rect: x, y, width, height, rx, ry
  • line: x1, y1, x2, y2

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

const rect = document.querySelector('rect');
const rectStyler = styler(rect);

animate({
  from: { width: 50, height: 50 },
  to: { width: 200, height: 120 },
  duration: 800,
  onUpdate: v => rectStyler.set(v)
});

Изменение размеров происходит плавно, без необходимости вручную пересчитывать позиции.

Анимация пути (path)

Пути SVG (<path>) — наиболее гибкий, но и сложный тип элемента. Их атрибут d представляет собой строку команд, описывающих кривые и линии.

Popmotion напрямую не интерполирует строки d, но используется популярный подход через свойства обводки:

  • stroke-dasharray
  • stroke-dashoffset

Эффект “рисования линии”

const path = document.querySelector('path');
const pathStyler = styler(path);

const length = path.getTotalLength();

pathStyler.set({
  strokeDasharray: length,
  strokeDashoffset: length
});

animate({
  from: { progress: length },
  to: { progress: 0 },
  duration: 2000,
  onUpdate: v => pathStyler.set({
    strokeDashoffset: v.progress
  })
});

Так создаётся эффект постепенного прорисовывания линии.

SVG transform и атрибуты

SVG поддерживает трансформации через атрибут transform, который может включать:

  • translate
  • scale
  • rotate

Popmotion часто использует трансформации вместо прямого изменения координат, так как это дешевле для рендеринга.

Перемещение через transform

animate({
  from: { x: 0 },
  to: { x: 300 },
  duration: 1000,
  onUpdate: v => {
    circleStyler.set({
      x: v.x
    });
  }
});

Однако более производительный подход — использование transform-объекта:

circleStyler.set({
  translateX: 0
});

animate({
  from: 0,
  to: 300,
  onUpdate: v => {
    circleStyler.set({
      translateX: v
    });
  }
});

Причина предпочтения transform

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

Комбинирование нескольких атрибутов

Popmotion позволяет одновременно управлять множеством свойств SVG, что даёт возможность создавать сложные анимационные сцены.

animate({
  from: {
    cx: 50,
    cy: 50,
    r: 10,
    opacity: 0
  },
  to: {
    cx: 250,
    cy: 150,
    r: 60,
    opacity: 1
  },
  duration: 1200,
  onUpdate: v => circleStyler.set(v)
});

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

Синхронизация нескольких SVG-элементов

Popmotion позволяет синхронизировать несколько независимых стилизаций через общий источник значений.

const box = styler(document.querySelector('rect'));
const dot = styler(document.querySelector('circle'));

animate({
  from: 0,
  to: 1,
  duration: 1000,
  onUpdate: v => {
    box.set({ opacity: v });
    dot.set({ opacity: 1 - v });
  }
});

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

Особенности единиц измерения SVG

SVG допускает отсутствие единиц измерения для большинства числовых атрибутов. Это упрощает интерполяцию:

  • cx="100" интерпретируется как числовое значение
  • Popmotion работает с чистыми числами, не требуя парсинга строк

Если используются единицы (px, %), Popmotion применяет внутренние преобразования, но в SVG это встречается реже, чем в CSS.

Производительность анимаций SVG

SVG-анимации через Popmotion опираются на следующие принципы:

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

На практике наиболее затратными являются:

  • изменение d у path
  • массовое обновление сложных групп элементов
  • комбинированные фильтры (filter, feGaussianBlur)

Оптимизация достигается разбиением анимации на независимые потоки значений.

Поведение при завершении анимации

После завершения animate Popmotion фиксирует конечное состояние. SVG-элементы сохраняют итоговые атрибуты без дополнительного вмешательства.

animate({
  from: { r: 10 },
  to: { r: 50 },
  duration: 500,
  onUpdate: v => circleStyler.set(v)
});

После завершения r остаётся равным 50, и элемент сохраняет финальную форму.

Связь SVG-атрибутов и реактивных потоков Popmotion

SVG-атрибуты удобно рассматривать как реактивные переменные. Popmotion превращает их в поток значений, который обновляется с высокой частотой.

Каждое значение:

  • вычисляется на кадр
  • интерполируется между состояниями
  • применяется к DOM-атрибуту

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