PerfectVector
Автор: Irene Kim7 мин чтения

Траектории SVG: движение собственного значка по кривой

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

На этой странице

Используйте animateMotion, чтобы перемещать элемент SVG по маршруту, и поместите внутрь mpath для ссылки на существующий контур. rotate="auto" поворачивает движущуюся графику вслед за направлением маршрута. По контуру движется локальное начало координат изображения, поэтому импортированному значку нужна намеренно выбранная опорная точка.

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

Отделяйте маршрут от изображения

Маршрут определяет, где движется значок. Значок определяет, что видит читатель. Справка MDN по animateMotion описывает элемент движения, а справка по mpath показывает повторное использование контура через ссылку.

В исходном примере ниже есть бирюзовая стрелка и золотая точка. Стрелка направлена вдоль положительной оси X, поэтому эффект автоматического поворота легко проверить. Изображение нарисовано вокруг (0, 0), а не далеко от начала большого экспортированного холста.

Сохраните это как motion.html и откройте в браузере. Сначала появится статичная эмблема. Нажмите Play для одного четырехсекундного прохода; Show static восстановит начальную иллюстрацию.

<!doctype html>
<meta charset="utf-8">
<title>Arrow following a curve</title>
<style>
  svg { display: block; width: min(100%, 800px); }
  .moving { display: none; }
  .playing .moving { display: inline; }
  .playing .still { display: none; }
</style>
 
<svg id="scene" viewBox="0 0 480 240"
     xmlns="http://www.w3.org/2000/svg"
     role="img" aria-label="An arrow emblem follows a curved route">
  <defs>
    <path id="route" d="M60 180 C160 20 300 20 420 180" />
    <g id="emblem">
      <path fill="#147d78"
            d="M-18-12 H4 V-22 L30 0 L4 22 V12 H-18 Z" />
      <circle cx="-7" cy="0" r="4" fill="#e5a340" />
    </g>
  </defs>
 
  <use href="#route" fill="none" stroke="#a9bab6" stroke-width="2" />
  <use class="still" href="#emblem" transform="translate(60 180)" />
  <g class="moving">
    <use href="#emblem" />
    <animateMotion id="motion" dur="4s" begin="indefinite"
                   fill="freeze" rotate="auto">
      <mpath href="#route" />
    </animateMotion>
  </g>
</svg>
 
<button id="play" type="button">Play</button>
<button id="stop" type="button">Show static</button>
<script>
  const scene = document.querySelector("#scene");
  const motion = document.querySelector("#motion");
  const preference = matchMedia("(prefers-reduced-motion: reduce)");
 
  function showStatic() {
    scene.pauseAnimations();
    scene.classList.remove("playing");
  }
 
  document.querySelector("#play").addEventListener("click", () => {
    if (preference.matches) return;
    scene.pauseAnimations();
    scene.setCurrentTime(0);
    scene.classList.add("playing");
    motion.beginElement();
    scene.unpauseAnimations();
  });
  document.querySelector("#stop").addEventListener("click", showStatic);
  preference.addEventListener("change", showStatic);
  showStatic();
</script>

Видимая серая кривая — отдельный use маршрута. Удалите этот use, если путь должен быть невидимым; сохраните определение в defs, чтобы анимация могла на него ссылаться. Элемент движения должен находиться внутри группы, чьи стрелка и точка должны двигаться вместе.

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

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

Исправьте значок, который уходит от маршрута

Движение применяется к системе координат элемента. Оно не находит автоматически визуальный центр логотипа. Если импортированные контуры занимают координаты вокруг (200, 120), движение содержащей их группы по маршруту сохраняет это смещение внутри группы.

Выберите точку изображения, которая должна касаться маршрута, затем переместите ее в (0, 0) внутри движущейся группы. Для опорной точки (200, 120) структура такая:

<g class="moving">
  <g transform="translate(-200 -120)">
    <!-- Place the original artwork paths here. -->
  </g>
  <animateMotion dur="4s" rotate="auto">
    <mpath href="#route" />
  </animateMotion>
</g>

Внутренний перенос подготавливает изображение; внешняя группа получает движение. Разделяйте эти задачи при добавлении масштаба или корректирующего поворота. Спецификация анимации SVG определяет движение как дополнительное преобразование, поэтому существующие преобразования по-прежнему влияют на конечное размещение.

Для значка разумной опорой может быть центр. Для транспортного средства может понадобиться точка контакта колеса; для указателя — его кончик. Центр ограничивающего прямоугольника — только начальное предположение. Проверьте нужную точку контакта в нескольких положениях на маршруте.

У неподвижного поворота есть собственная проблема центра вращения. Руководство по transform-origin SVG объясняет этот случай без добавления траектории движения.

Выберите, должно ли изображение поворачиваться

Нужный результатНастройка движенияПодготовка изображения
Стрелка следует направлению кривойrotate="auto"Направьте ее вперед вдоль положительной оси X
Значок остается вертикальным при движенииrotate="0"Сохраните нужную фиксированную ориентацию в его локальном изображении
Изображение направлено против направления маршрутаrotate="auto-reverse"Проверьте направление вперед у исходника перед использованием

Эти значения описаны в справке MDN по повороту при движении. auto-reverse меняет направление ориентации, а не порядок прохождения маршрута.

Если исходник направлен вверх, auto не знает, что вверх означает вперед. Поверните внутреннюю группу изображения, чтобы она указывала вдоль положительной оси X, затем примените движение к внешней группе. Не поворачивайте сам маршрут только ради исправления локальной ориентации значка.

Острые углы маршрута могут давать резкие смены направления. Изогнутый маршрут — более подходящая отправная точка, если нужен визуально плавный поворот. Также оставьте место вокруг маршрута: значок может выступать за центральную линию пути и обрезаться возле края области просмотра SVG.

Проверьте начало, середину и конец

Мы открыли тот же маршрут и эмблему в Chrome и использовали небольшой тестовый стенд, чтобы остановить временную шкалу SVG на 0, 2 и 4 секундах. Значок начинал снизу слева, проходил возле вершины и завершал движение снизу справа. При auto его ориентация менялась вдоль кривой. При повороте 0 положение в середине было тем же, но стрелка оставалась горизонтальной.

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

Для собственного изображения:

  1. Проверьте точку контакта в начале маршрута. Исправьте смещения исходника перед настройкой времени.
  2. Остановите движение возле изгибов и убедитесь, что нужная часть эмблемы следует линии.
  3. Сравните автоматический и фиксированный поворот. Выбирайте исходя из изображения, особенно если оно содержит текст.
  4. Проверьте конечное положение на обрезку и убедитесь, что повторное воспроизведение правильно начинается.
  5. Проверьте реальный контекст передачи. Этот пример использует встроенный SVG внутри HTML-страницы с управлением через JavaScript.

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

Добавьте полезный статичный вариант

Пример начинается со статичного use эмблемы, а движение запускается только после нажатия кнопки Play. Если JavaScript не работает, статичное изображение остается видимым. Когда активна настройка уменьшения движения, обработчик оставляет его в этом состоянии.

Медиафункция prefers-reduced-motion позволяет странице реагировать на предпочтение пользователя относительно движения. Здесь JavaScript считывает эту настройку перед запуском движения SVG и восстанавливает статичную версию, если предпочтение меняется.

Мы также проверили статичную ветку явным переключателем предпросмотра уменьшенного движения в тестовом стенде: он скрывал анимированную группу и показывал эмблему в начальном положении. Этот переключатель проверял нашу логику запасного варианта; он не менял настройку доступности компьютера.

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

Подготовьте собственный мотив перед анимацией

Если ваш мотив существует только в PNG или JPG, PerfectVector может помочь восстановить редактируемую SVG-графику перед созданием движения. Проверьте восстановленный силуэт и небольшие отверстия, сгруппируйте части, которые должны двигаться вместе, и выберите опорную точку. PerfectVector дает исходную геометрию; маршрут, время и поведение движения создаются отдельно.

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

Для собственного знака только в растре попробуйте изображение в PerfectVector, проверьте контуры и мелкие детали, затем проверьте этот SVG в начале, середине и конце маршрута. Сохраните статичную версию рядом с анимированной.

Частые вопросы

Почему значок движется рядом с контуром, а не по нему? Изображение может быть смещено относительно локального начала координат. Выберите точку, которая должна следовать маршруту, и перенесите ее в ноль внутри движущейся группы. Проверьте результат в начале и на изгибе.

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

Можно ли удалить видимую направляющую линию? Да. Сохраните определение маршрута и его ID, но удалите отдельный элемент, рисующий направляющую. Движение по-прежнему может ссылаться на контур через mpath.

Источники

  1. MDN animateMotion — Описывает траектории движения, значения поворота и равномерное движение по умолчанию.
  2. MDN mpath — Объясняет ссылку на существующий маршрут внутри элемента движения.
  3. SVG animation specification — Определяет преобразования движения и их связь с координатами изображения.
  4. MDN rotate attribute — Описывает фиксированную, автоматическую и обратную ориентацию при движении.
  5. MDN reduced-motion preference — Объясняет определение предпочтения пользователя относительно движения.

Ещё из блога

Начните с более чистого SVG,
который проще редактировать