Перевод статьи A Guide to SVG Animations (SMIL) с сайта css-tricks.com, автор — Сара Суайдан. Публикуется с разрешения автора.
Перед вами гостевой постинг Сары Суайдан. Сара — мастер докапываться до самых глубин классных веб-новинок, подробно и понятно разбирая их до основания. Здесь она погружается в недра SMIL (и смежных технологий) и синтаксиса анимаций, встроенного в сам SVG, и делится с нами этим внушительным руководством.
- Введение
- Зачем использовать SVG-анимации?
- Браузерная поддержка и варианты для подстраховки
- Указание целевого объекта анимации с помощью xlink:href
- Указание целевого свойства анимации с помощью attributeName и attributeType
- Анимация атрибута элемента от одного значения до другого в течение отрезка времени и указание конечного состояния: from , by , to , dur и fill
- Перезапуск анимаций с помощью restart
- Именование и синхронизация анимаций
- Зацикливание анимаций с repeatCount
- Ограничение времени повторения с помощью repeatDur
- Синхронизация анимаций на основе количества повторений
- Управление значениями ключевого кадра анимации: keyTimes и values
- Управление темпом анимации с помощью произвольной функции плавности: calcMode и keySplines
- Относительные и накопительные анимации: additive и accumulate
- Указание времени конца анимации с помощью end
- Задание интервалов анимации с помощью нескольких значений begin и end
- Ограничение активной длительности элемента с помощью min и max
- Пример : морфинг контуров
- Анимация по произвольной траектории: элемент Задание траектории движения с помощью атрибута path Атрибут path задает траекторию движения. Он задается в том же формате и интерпретируется тем же образом, что атрибут d элемента path . Эффект анимации движения по траектории заключается в наложении дополнительной матрицы трансформации поверх текущей матрицы трансформации объекта, вызывающей сдвиг по осям X и Y в текущей системе координат пользователя на значения X и Y, рассчитываемые для каждого момента времени. Другими словами, заданная траектория отсчитывается относительно текущего положения элемента, используя данные траектории для перемещения объекта на позицию на этой траектории. Для нашего круга мы зададим анимацию по траектории, которая будет выглядеть примерно так: Вот код, требующийся для движения круга по этой траектории: Я хочу особо обратить ваше внимание на координаты в данных пути. Путь начинается с перемещения (M) в точку с координатами (0, 0), прежде чем начать рисовать кривую (c) в другую точку. Важно отметить, что точка (0, 0) в данном случае — это позиция нашего круга, неважно, где он находится, а НЕ верхний левый угол системы координат. Как я отметила выше, координаты в атрибуте path отсчитываются относительно текущего положения элемента! Результат вышеприведенного кода следующий: Если вы укажете путь, начинающийся с другой точки, а не (0, 0), круг рывком перескочит на расстояние, заданное координатами начальной точки. Например, предположим, что вы рисуете путь в Illustrator с последующим экспортом его в виде траектории движения (так я делала это в первый раз). Экспортированный путь будет выглядеть как-то так: Начальной точкой пути в этом случае будет (100.4, 102.2). Если бы мы использовали этот путь как траекторию движения, круг сначала «прыгнул» бы на примерно 100 единиц вправо и 102 единицы вниз, и лишь затем начал бы движение относительно нового положения. Так что не забывайте об этом при подготовке траекторий для ваших анимаций. Если используются атрибуты from , by , to и values , то они указывают форму на текущем холсте, представляющую собой траекторию движения. Указание траектории движения с помощью элемента Есть и другой способ задания траектории движения. Вместо использования относительного атрибута path , можно ссылаться на внешний путь с помощью элемента . Элемент , дочерний по отношению к элементу , будет указывать на внешний путь с помощью атрибута xlink:href . с траекторией движения может быть указан в любом месте документа; он даже может быть буквально лишь объявлен внутри элемента и вообще не отображаться на холсте. В следующем примере траектория отображается, потому что в большинстве случаев вы захотите показать путь, по которому элемент движется. Заметьте, что, согласно спецификации: Различные точки (x, y) формы предоставляют вспомогательные матрицы трансформации поверх текущей матрицы трансформации для указанного объекта, которые вызывают смещение по осям X и Y в текущей пользовательской системе координат на значение (x,y) формы, вычисляемое в зависимости от времени. Таким образом, указанный объект сдвигается с течением времени на смещение траектории движения относительно начала текущей пользовательской системы координат. Вспомогательные матрицы трансформации применяются поверх любых трансформаций, задаваемых свойством transform целевого элемента, и любых анимаций этого атрибута, заданных элементами animateTransform для целевого элемента. Опять же, позиция круга «умножается» или «трансформируется» на координаты из данных пути. В следующем примере, у нас есть путь посередине холста. Круг позиционируется в начало пути. Но всё же, когда движение по траектории используется, круг не начинает движение из текущего положения. Смотрите пример для лучшего объяснения. Кликните по кругу, чтобы анимировать его. Видите, как круг движется по тому же самому контуру, но в другом месте? Это потому, что позиция круга трансформируется (сдвигается) на значения из данных траектории. Один способ обойти это — начинать с положения круга в точке (0, 0), так что трансформация по данным пути передвинет его куда нужно, и всё заработает как ожидалось. Другой способ — применить трансформацию, которая «обнулит» координаты круга перед тем, как задействовать траекторию. Вот модифицированная версия примера выше, использующая замкнутую траекторию и бесконечно зацикленную анимацию. Правила приоритета для Поскольку один и тот же эффект можно реализовать с animateMotion более чем одним способом, нужны правила, по которым одни значения могут перекрывать другие. Правила перекрытия для animateMotion таковы: При задании траектории движения, элемент mpath перекрывает атрибут path , который перекрывает values , а тот перекрывает from , by и to . При определении точек, соответствующих атрибуту keyTimes , атрибут keyPoints перекрывает path , который перекрывает values , а тот перекрывает from , by и to . Задание ориентации элемента относительно траектории движения rotate В нашем предыдущем примере, элемент, который мы анимировали вдоль траектории, был кругом. Но что, если бы мы анимировали элемент, для которого важна ориентация, например, иконку машинки? Иконка машинки в следующем примере создана Freepik. В этом примере я заменила круг группой с ID, равным «car», содержащей элемент, образующий группу. Затем, чтобы избежать вышеописанных проблем с движением по траектории, я применила трансформацию, сдвигающую машинку в определенную точку, так что в итоге начальной позицией оказывается точка (0, 0). Значения внутри трансформации на самом деле являются координатами точки, где начинает рисоваться первый контур машинки (сразу после команды M). Затем машинка начинает двигаться по траектории. Но… вот как выглядит это движение: Ориентация машинки фиксирована, и не соответствует направлению движения. Чтобы изменить это, мы будем использовать атрибут rotate . У атрибута rotate может быть одно из трех значений: auto : указывает, что объект будет поворачиваться с течением времени на угол направления (т.е. по касательному вектору направления) траектории движения. auto-reverse : указывает, что объект будет поворачиваться с течением времени на угол направления (т.е. по касательному вектору направления) траектории движения плюс 180 градусов. число: указывает, что к целевому элементу применена постоянная трансформация вращения, указанное число задает угол поворота в градусах. Чтобы исправить ориентацию машинки в примере выше, мы начнем с задания вращению значения auto . Получим вот такой результат: Если вы хотите, чтобы машинка «ездила» снаружи контура, значение auto-reverse решает задачу. Это выглядит лучше, но у нас осталась проблема: машинка выглядит так, будто ездит по траектории задним ходом! Чтобы изменить это, нам придется перевернуть ее по ее оси Y. Это можно сделать путем масштабирования ее по этой оси с коэффициентом -1. Так что, если мы применим трансформацию к g с ID, равным car , машинка «поедет» вперед, как задумано. Трансформация масштабирования просто добавляется последовательно с ранее примененной трансформацией сдвига. И окончательный демо-пример выглядит так: Управление расстоянием, пройденным анимацией по траектории, с помощью keyPoints Атрибут keyPoints дает возможность указывать продвижение по траектории для каждого значения, указанного в keyTimes . Если он задан, keyPoints заставляет keyTimes применяться к значениям из keyPoints , а не к точкам, перечисленным в атрибуте values или точкам в атрибуте path . keyPoints принимает разделенный точками с запятой список значений с плавающей точкой от 0 до 1 и указывает, как далеко по траектории должен продвинуться объект в момент времени, заданный в соответствующем значении keyTimes . Расчет расстояния определяется алгоритмами браузера. Каждое значение продвижения в списке соответствует одному значению из списка в атрибуте keyTimes . Если задан список keyPoints , в нем должно быть ровно столько же значений, сколько в списке keyTimes . Важный момент, который здесь надо отметить — задание значения linear для calcMode , чтобы keyPoints заработал. Кажется, что по логике он должен работать и со значением paced , если ваши ключевые точки смещены то взад, то вперед, но с ним он не работает. Вот пример Амелии Беллами-Ройдз (чей профиль на Codepen вам стоило бы изучить полностью), использующий keyPoints для имитации поведения, при котором движение по траектории начинается с предустановленным отступом, поскольку по умолчанию в SMIL у нас сейчас нет такой возможности (прим. перев.: здесь тоже оригинальный пример заменен переведенным вариантом). Движение текста по произвольной траектории Движение текста по произвольной траектории отличается от движения других SVG-элементов по траекториям. Для анимации текста вам понадобится элемент , а не элемент . Во-первых, начнем с позиционирования текста вдоль траектории. Это можно сделать, вложив элемент . Текст, который будет размещен вдоль траектории, будет определен внутри элемента , а не как непосредственный потомок элемента Затем textPath должен сослаться на фактический путь, который мы хотим использовать, в точности как в предыдущих примерах. Путь, на который мы ссылаемся, тоже может либо отображаться на холсте, либо определяться внутри . Посмотрите код следующего демо-примера. Чтобы анимировать текст вдоль траектории, мы используем элемент для анимации атрибута startOffset . startOffset представляет собой отступ текста относительно пути. 0% — начало пути; 100% соответствуют его концу. Так что если, например, задать отступ в 50%, текст будет начинаться посередине траектории. Думаю, вы уже догадались, что это нам дает. Анимируя startOffset , мы создадим эффект текста, движущегося по траектории. Взгляните на код следующего демо. Анимация трансформаций: элемент Атрибут type служит для указания типа трансформации, которую анимируют. У него может быть одно из пяти значений: translate , scale , rotate , skewX и skewY . Атрибуты from , by и to принимают значения в том же синтаксисе, который подходит для данного типа трансформации: Для type=»translate» каждое отдельное значение выражается как [,] (сдвиг по каждой оси). Для type=»scale» каждое отдельное значение выражается как [,] (масштаб по каждой оси). Для type=»rotate» каждое отдельное значение выражается как [ ] (угол поворота и координаты центра вращения). Для type=»skewX» and type=»skewY» каждое отдельное значение выражается как (угол наклона). Если вы не очень знакомы с функциями SVG-атрибута transform , то ради краткости этой статьи, а также потому, что подробности его синтаксиса и работы выходят далеко за рамки этой статьи, я советую вам прочитать статью о них, которую я написала чуть раньше: «Разбираемся с системами координат и трансформациями в SVG (часть 2): атрибут transform» — прежде чем продолжать изучение этого руководства. Вернемся к предыдущему примеру, где мы вращали розовый прямоугольник с помощью элемента . Код для вращения выглядит так: Атрибуты from и to указывают угол поворота (начальный и конечный) и центр вращения. Конечно, в них обоих центр вращения остается тем же самым. Если вы не укажете центр, им станет верхний левый угол SVG-холста. Вот живой пример для вышеприведенного кода: Вот еще один забавный пример с одним animateTransform за авторством Габриэля: See the Pen Orbit by Gabriel (@guerreiro) on CodePen. Анимация одной отдельной трансформации очень проста, однако, всё может стать куда сложнее и запутаннее, когда дело дойдет до множественных трансформаций, особенно с учетом того, что один animateTransform может перекрывать другой, так что вместо наложения или последовательного применения эффектов вы можете получить полную противоположность. Так уж устроены системы координат и трансформации в SVG (снова рекомендую обратиться к ранее упомянутой статье). Примеров масса, но они выходят за рамки статьи. Для трансформирования SVG-графики я советую использовать CSS-трансформации. Браузеры вовсю стараются, чтобы те идеально работали с SVG, так что, возможно, вам вообще не понадобится никакой SMIL для анимации трансформаций в SVG. Элемент Элемент set предоставляет простое средство для задания значения атрибуту на определенный отрезок времени. Он поддерживает все типы атрибутов, включая те, которые по своей логике не могут быть интерполированы, напр. строки и булевы значения. Элемент set не поддерживает относительных/накопительных анимации: относительные и накопительные атрибуты недопустимы и игнорируются, даже если указаны. Поскольку используется для выставления элемента в определенное значение в определенный момент и отрезок времени, для него доступны не все атрибуты, упомянутые для предыдущих анимационных элементов. Например, у него нет атрибутов from или by , потому что изменяемое значение не меняется со временем постепенно. Для set вы можете указать целевой элемент, имя и тип атрибута, значение to и время анимации, которым можно управлять с помощью следующих атрибутов: begin , dur , end , min , max , restart , repeatCount , repeatDur и fill . Вот пример, который меняет цвет вращающегося прямоугольника на синий, когда по нему кликают. Цвет остается синим в течение 3 секунд, а затем возвращается к исходному цвету. Каждый раз при клике по прямоугольнику запускается анимация set , и цвет меняется на три секунды. Элементы, атрибуты и свойства, которые можно анимировать Не все SVG-атрибуты можно анимировать, и не все из тех, которые можно анимировать, можно анимировать всеми анимационными элементами. За полным списком анимируемых атрибутов и таблицей, показывающей, какой из этих атрибутов можно анимировать каким элементом, пожалуйста, обратитесь к этому разделу спецификации SVG-анимаций. В заключение У SMIL огромный потенциал, и я едва затронула поверхность и лишь коснулась основ и технических моментов того, как он работает в SVG. Можно создать множество очень впечатляющих эффектов, особенно с морфингом и преобразованием форм. Предела фантазии нет. Не бойтесь экспериментировать! И не забывайте делиться тем, что делаете, с сообществом; мы будем счастливы видеть, чего вы смогли достичь. Спасибо за чтение! Эта статья была обновлена по результатам дискуссии в комментариях. Спасибо за важные дополнения, Амелия. =) P.S. Это тоже может быть интересно: Если вам понравилась статья, поделитесь ей! Анимация движения В этом уроке мы заглянем внутрь svg файла и познакомимся с анимацией движения объектов. Использовать будем SMIL анимацию. p, blockquote 1,0,0,0,0 —> p, blockquote 2,0,0,0,0 —> Подробно познакомиться с SMIL 3.0 можно на сайте . p, blockquote 3,0,0,0,0 —> Пример простейшей SVG анимации (SMIL) В этом уроке мы будем использовать только конструкцию , а вот рассмотрим позже. p, blockquote 5,0,0,0,0 —> Двигать объекты на пустом экране скучно, поэтому давайте создадим простую иллюстрацию и на ней потренируемся. Рисунок совы на фоне луны ночью как раз подойдет. Результат получится такой . p, blockquote 6,0,0,0,0 —> SMIL анимация не работает в MS EDGE (увы). Работа проверялась в Firefox и Chrome. Шаг 1. Рисуем иллюстрацию для svg анимации Итак, запускайте редактор и задайте в свойствах документа альбомную ориентацию (shift+ctrl+D). Начнем рисовать с неба. Нарисуйте прямоугольник и задайте любой градиент, подойдет как радиальный так и линейный . В качестве цвета можно выбрать любой темно-синий цвет, все-таки у нас ночь. p, blockquote 8,0,0,0,0 —> p, blockquote 9,0,0,0,0 —> В нижней части рисунка добавьте прямоугольник. Он должен занимать менее половины рисунка. Верхнюю сторону прямоугольника сделайте в виде дуги. Для этого оконтуриваем объект Контур-оконтурить объект . После этого достаточно потянуть мышку вверх и мы получим дугу. Таким образом мы получили холм. p, blockquote 10,0,0,0,0 —> p, blockquote 11,0,1,0,0 —> Звезды получить проще всего. Рисуем несколько кругов белого цвета и дублируем необходимое количество раз. p, blockquote 12,0,0,0,0 —> p, blockquote 13,0,0,0,0 —> Для создания изображения тумана рисуем несколько кругов, накладываем их друг на друга, выделяем и применяем операцию Сумма Ctrl+. Для тумана лучше задать радиальный градиент. p, blockquote 14,0,0,0,0 —> p, blockquote 15,0,0,0,0 —> Полученное облако дублируем пару раз, изменяем размер и отражаем по горизонтали. Затем размещаем за холмом. p, blockquote 16,0,0,0,0 —> p, blockquote 17,0,0,0,0 —> С помощью инструмента кривые Безье рисуем контур произвольного дерева и задаем заливку черным цветом (дерево можно создать и с помощью векторизации растрового изображения реального дерева). p, blockquote 18,0,0,0,0 —> p, blockquote 19,0,0,0,0 —> Далее сова. Нарисуйте контур совы и задайте заливку цветом чуть более светлым чем небо. p, blockquote 20,0,0,0,0 —> p, blockquote 21,0,0,0,0 —> Сова должна быть едва видна. Контур совы можно нарисовать из пары эллипсов. После оконтуривания эллипсов придаем им нужную форму. p, blockquote 22,1,0,0,0 —> p, blockquote 23,0,0,0,0 —> Вот что у меня получилось. p, blockquote 24,0,0,0,0 —> p, blockquote 25,0,0,0,0 —> Последний объект это Луна. Здесь все просто. Рисуем круг белого цвета. p, blockquote 26,0,0,0,0 —> p, blockquote 27,0,0,0,0 —> И с помощью Page Down опускаем его за туман. p, blockquote 28,0,0,0,0 —> p, blockquote 29,0,0,0,0 —> Все, иллюстрация готова. Можно заняться анимацией. p, blockquote 30,0,0,0,0 —> Шаг 2. Анимация луны p, blockquote 31,0,0,0,0 —> Для создания анимации предварительно необходимо выяснить id окружности. Наша луна будет подниматься вверх пока не окажется за совой, освещая ее сзади. Для это открываем окно объектов Объект- объекты. Далее выделяем наш белый круг и в панели объектов находим его id. В моем случае это circle1327. p, blockquote 32,0,0,0,0 —> p, blockquote 33,0,0,1,0 —> Затем выясняем координаты центра окружности. Для этого открываем окно xml редактора, находим по id нашу окружность (левое окно) и в правом окне находим cx и cy. Скорее всего числа будут нецелыми. Лучше изменить значения на целые- так удобнее. p, blockquote 34,0,0,0,0 —> p, blockquote 35,0,0,0,0 —> Теперь сохраняем свою работу как простой svg документ- Файл- сохранить файл. Тип файла- простой svg. p, blockquote 36,0,0,0,0 —> Далее открываем наш файл в блокноте и добавляем в начало svg документа указание на использование пространства имен (возможно в safari не сработает) p, blockquote 37,0,0,0,0 —> Нужная строка (8) выделена. p, blockquote 38,0,0,0,0 —> Теперь ищем по id нашу окружность. Для этого воспользуйтесь поиском в блокноте p, blockquote 39,0,0,0,0 —> Отлично , осталось добавить после тега окружности следующую конструкцию. p, blockquote 40,0,0,0,0 —> Это описание анимации svg графики. Небольшой комментарий p, blockquote 41,0,0,0,0 —> Первая строка ( xlink …) связывает анимацию с объектом по его id. В последующих строках задается: p, blockquote 42,0,0,0,0 —> имя изменяемой величины ( attributeName ), продолжительность анимации ( dur ), начальное и конечное значение величины ( from — to ), условие начала анимации (в моем случае через 1 секунду begin=1s ) в каком состоянии должен находится объект после окончания анимации ( fill=»freeze» « заморозить» состояние) Конструкцию animate добавляем для двух анимируемых атрибутов- отдельно для cx и отдельно для cy. Все, готово, осталось посмотреть результат . p, blockquote 43,0,0,0,0 —> p, blockquote 44,0,0,0,1 —> Анимация SVG-элемента path Думаю многие видели обзоры игровых консолей нового поколения от Polygon (Vox Media). Это те, где консоли отрисовывались в стиле blueprint’ов: Stroke-dasharray interpolation, теория Вообще техника подобной анимации линий не нова, просто до недавнего времени SVG и всё, что с ним связано, на мой взгляд, было несправедливо предано забвению, но к счастью ситуация меняется. Итак, трюк с анимацией элемента path возможен благодаря свойству stroke-dasharray элемента path . Это свойство позволяет задавать параметры пунктирной линии, а именно длину штриха и промежутка между штрихами. Если задать длину штриха равной всей длине линии, то получим обыкновенную сплошную линию. Если же задать длину штриха равной нулю, а длину промежутка опять-таки равной всей длине линии, то получим невидимую линию. А постепенно увеличивая длину штриха при длине промежутка, равной длине всей линии, мы можем имитировать её отрисовку. При таком подходе отрисовка будет происходить от начала линии. Если же вдруг необходимо отрисовывать с конца, то нужно использовать ещё одно свойство: stroke-dashoffset. Это свойство определяет смещение для первого штриха. Таким образом, уменьшая смещение и увеличивая длину штриха, получим отрисовку с конца линии. Ребята из Vox Media использовали гибридный вариант (который, на мой взгляд, избыточен), кстати почитать о том, как они это делали, можно (и нужно) в их блоге: Polygon feature design: SVG animations for fun and profit. Реализация SVG анимации В Vox Media предлагают использовать requestAnimationFrame для плавности анимации, но у нас немного другие цели, так что мы пойдём более простым путём, воспользуемся библиотекой D3.js и реализованной в ней анимацией на основе длительности. Вот собственно рабочий код, использовавшийся для анимации консоли из начала статьи. В функции transition(path) мы используем transition.attrTween(name, tween), который вызывает интерполятор, определённый в функции tweenDash() . Для вычисления длины используется метод getTotalLength(), определённый для элементов SVG path . Затем с помощью d3.interpolateString(a, b) задаётся интерполятор свойства stroke-dasharray , который выполнит интерполяцию значений от stroke-dasharray: 0,l; до stroke-dasharray: l,l; (здесь первое значение задаёт длину штриха, а второе длину промежутка). Посмотреть на то как это работает можно на bl.ocks.org: PlayStation 4: SVG animation. Думаю вы заметили, что часть элементов отображается постоянно, это происходит потому, что они нарисованы не с помощью path . Вообще подготовка и оптимизация векторных изображений для web это довольно обширная тема с массой нюансов, тянущая на отдельную статью. Движение вдоль элемента path У path есть ещё один весьма полезный метод — getPointAtLength(distance in float). Он позволяет получить координаты точки, находящейся на заданной дистанции от начала линии. С помощью него можно реализовать движение какого-либо маркера вдоль линии, и, что немаловажно, плавное вращение за счёт вычисления касательной к имеющейся линии. Начнём просто с движения вдоль линии, пока без вращения. Здесь pathStartPoint(path) вытаскивает координаты начала линии из атрибута d элемента path . В translateAlong(path) с помощью интерполятора задаются координаты нашего маркера. Пример можно посмотреть здесь: Marker animation along SVG path element with D3.js. А ещё можно объединить анимацию отрисовки линии и движение маркера, выглядеть это может следующим образом: Marker animation along SVG path element with D3.js II. Усложним задачу, добавим вращение (ну и поменяем маркер с круга на что-нибудь поинтереснее). В качестве маркера у нас будет ракета с шириной 48 и длиной 24 . Поскольку по умолчанию точкой привязки маркера является левый верхний угол, нам необходимо смещать его, чтобы привязка была к центру маркера. Также необходимо учитывать это при вращении, ведь оно тоже по умолчанию происходит вокруг левого верхнего угла. Со смещением вроде разобрались. Теперь перейдём непосредственно к вращению, здесь нам поможет определение касательной, угол будем определять с помощью арктангенса. Функция translateAlong(path) , определяющая интерполятор будет выглядеть следующим образом: Где и для чего это можно использовать Во-первых, для достижения интересного эффекта с точки зрения дизайна. Можно отображать объекты по мере скроллинга, можно делать анимацию текста, правда надо учитывать что по умолчанию каждая буква — это отдельный элемент path , да много чего можно придумать. А можно использовать с практической точки зрения, например для анимации движения по маршрутам на схемах и планах (анимация стрелочек и прочее). А ещё для инфографики, тут масса вариантов, если грамотно использовать можно весьма эффективно управлять вниманием читателя. На этом всё. Пробуйте, экспериментируйте, созидайте — всё в ваших руках. И пусть в наступившем году вам сопутствует удача. UPD: Ещё статьи на эту тему: SVG drawing animation Animated line drawing in SVG Animating Vectors with SVG
- Задание траектории движения с помощью атрибута path
- Указание траектории движения с помощью элемента
- Правила приоритета для Поскольку один и тот же эффект можно реализовать с animateMotion более чем одним способом, нужны правила, по которым одни значения могут перекрывать другие. Правила перекрытия для animateMotion таковы: При задании траектории движения, элемент mpath перекрывает атрибут path , который перекрывает values , а тот перекрывает from , by и to . При определении точек, соответствующих атрибуту keyTimes , атрибут keyPoints перекрывает path , который перекрывает values , а тот перекрывает from , by и to . Задание ориентации элемента относительно траектории движения rotate В нашем предыдущем примере, элемент, который мы анимировали вдоль траектории, был кругом. Но что, если бы мы анимировали элемент, для которого важна ориентация, например, иконку машинки? Иконка машинки в следующем примере создана Freepik. В этом примере я заменила круг группой с ID, равным «car», содержащей элемент, образующий группу. Затем, чтобы избежать вышеописанных проблем с движением по траектории, я применила трансформацию, сдвигающую машинку в определенную точку, так что в итоге начальной позицией оказывается точка (0, 0). Значения внутри трансформации на самом деле являются координатами точки, где начинает рисоваться первый контур машинки (сразу после команды M). Затем машинка начинает двигаться по траектории. Но… вот как выглядит это движение: Ориентация машинки фиксирована, и не соответствует направлению движения. Чтобы изменить это, мы будем использовать атрибут rotate . У атрибута rotate может быть одно из трех значений: auto : указывает, что объект будет поворачиваться с течением времени на угол направления (т.е. по касательному вектору направления) траектории движения. auto-reverse : указывает, что объект будет поворачиваться с течением времени на угол направления (т.е. по касательному вектору направления) траектории движения плюс 180 градусов. число: указывает, что к целевому элементу применена постоянная трансформация вращения, указанное число задает угол поворота в градусах. Чтобы исправить ориентацию машинки в примере выше, мы начнем с задания вращению значения auto . Получим вот такой результат: Если вы хотите, чтобы машинка «ездила» снаружи контура, значение auto-reverse решает задачу. Это выглядит лучше, но у нас осталась проблема: машинка выглядит так, будто ездит по траектории задним ходом! Чтобы изменить это, нам придется перевернуть ее по ее оси Y. Это можно сделать путем масштабирования ее по этой оси с коэффициентом -1. Так что, если мы применим трансформацию к g с ID, равным car , машинка «поедет» вперед, как задумано. Трансформация масштабирования просто добавляется последовательно с ранее примененной трансформацией сдвига. И окончательный демо-пример выглядит так: Управление расстоянием, пройденным анимацией по траектории, с помощью keyPoints Атрибут keyPoints дает возможность указывать продвижение по траектории для каждого значения, указанного в keyTimes . Если он задан, keyPoints заставляет keyTimes применяться к значениям из keyPoints , а не к точкам, перечисленным в атрибуте values или точкам в атрибуте path . keyPoints принимает разделенный точками с запятой список значений с плавающей точкой от 0 до 1 и указывает, как далеко по траектории должен продвинуться объект в момент времени, заданный в соответствующем значении keyTimes . Расчет расстояния определяется алгоритмами браузера. Каждое значение продвижения в списке соответствует одному значению из списка в атрибуте keyTimes . Если задан список keyPoints , в нем должно быть ровно столько же значений, сколько в списке keyTimes . Важный момент, который здесь надо отметить — задание значения linear для calcMode , чтобы keyPoints заработал. Кажется, что по логике он должен работать и со значением paced , если ваши ключевые точки смещены то взад, то вперед, но с ним он не работает. Вот пример Амелии Беллами-Ройдз (чей профиль на Codepen вам стоило бы изучить полностью), использующий keyPoints для имитации поведения, при котором движение по траектории начинается с предустановленным отступом, поскольку по умолчанию в SMIL у нас сейчас нет такой возможности (прим. перев.: здесь тоже оригинальный пример заменен переведенным вариантом). Движение текста по произвольной траектории Движение текста по произвольной траектории отличается от движения других SVG-элементов по траекториям. Для анимации текста вам понадобится элемент , а не элемент . Во-первых, начнем с позиционирования текста вдоль траектории. Это можно сделать, вложив элемент . Текст, который будет размещен вдоль траектории, будет определен внутри элемента , а не как непосредственный потомок элемента Затем textPath должен сослаться на фактический путь, который мы хотим использовать, в точности как в предыдущих примерах. Путь, на который мы ссылаемся, тоже может либо отображаться на холсте, либо определяться внутри . Посмотрите код следующего демо-примера. Чтобы анимировать текст вдоль траектории, мы используем элемент для анимации атрибута startOffset . startOffset представляет собой отступ текста относительно пути. 0% — начало пути; 100% соответствуют его концу. Так что если, например, задать отступ в 50%, текст будет начинаться посередине траектории. Думаю, вы уже догадались, что это нам дает. Анимируя startOffset , мы создадим эффект текста, движущегося по траектории. Взгляните на код следующего демо. Анимация трансформаций: элемент Атрибут type служит для указания типа трансформации, которую анимируют. У него может быть одно из пяти значений: translate , scale , rotate , skewX и skewY . Атрибуты from , by и to принимают значения в том же синтаксисе, который подходит для данного типа трансформации: Для type=»translate» каждое отдельное значение выражается как [,] (сдвиг по каждой оси). Для type=»scale» каждое отдельное значение выражается как [,] (масштаб по каждой оси). Для type=»rotate» каждое отдельное значение выражается как [ ] (угол поворота и координаты центра вращения). Для type=»skewX» and type=»skewY» каждое отдельное значение выражается как (угол наклона). Если вы не очень знакомы с функциями SVG-атрибута transform , то ради краткости этой статьи, а также потому, что подробности его синтаксиса и работы выходят далеко за рамки этой статьи, я советую вам прочитать статью о них, которую я написала чуть раньше: «Разбираемся с системами координат и трансформациями в SVG (часть 2): атрибут transform» — прежде чем продолжать изучение этого руководства. Вернемся к предыдущему примеру, где мы вращали розовый прямоугольник с помощью элемента . Код для вращения выглядит так: Атрибуты from и to указывают угол поворота (начальный и конечный) и центр вращения. Конечно, в них обоих центр вращения остается тем же самым. Если вы не укажете центр, им станет верхний левый угол SVG-холста. Вот живой пример для вышеприведенного кода: Вот еще один забавный пример с одним animateTransform за авторством Габриэля: See the Pen Orbit by Gabriel (@guerreiro) on CodePen. Анимация одной отдельной трансформации очень проста, однако, всё может стать куда сложнее и запутаннее, когда дело дойдет до множественных трансформаций, особенно с учетом того, что один animateTransform может перекрывать другой, так что вместо наложения или последовательного применения эффектов вы можете получить полную противоположность. Так уж устроены системы координат и трансформации в SVG (снова рекомендую обратиться к ранее упомянутой статье). Примеров масса, но они выходят за рамки статьи. Для трансформирования SVG-графики я советую использовать CSS-трансформации. Браузеры вовсю стараются, чтобы те идеально работали с SVG, так что, возможно, вам вообще не понадобится никакой SMIL для анимации трансформаций в SVG. Элемент Элемент set предоставляет простое средство для задания значения атрибуту на определенный отрезок времени. Он поддерживает все типы атрибутов, включая те, которые по своей логике не могут быть интерполированы, напр. строки и булевы значения. Элемент set не поддерживает относительных/накопительных анимации: относительные и накопительные атрибуты недопустимы и игнорируются, даже если указаны. Поскольку используется для выставления элемента в определенное значение в определенный момент и отрезок времени, для него доступны не все атрибуты, упомянутые для предыдущих анимационных элементов. Например, у него нет атрибутов from или by , потому что изменяемое значение не меняется со временем постепенно. Для set вы можете указать целевой элемент, имя и тип атрибута, значение to и время анимации, которым можно управлять с помощью следующих атрибутов: begin , dur , end , min , max , restart , repeatCount , repeatDur и fill . Вот пример, который меняет цвет вращающегося прямоугольника на синий, когда по нему кликают. Цвет остается синим в течение 3 секунд, а затем возвращается к исходному цвету. Каждый раз при клике по прямоугольнику запускается анимация set , и цвет меняется на три секунды. Элементы, атрибуты и свойства, которые можно анимировать Не все SVG-атрибуты можно анимировать, и не все из тех, которые можно анимировать, можно анимировать всеми анимационными элементами. За полным списком анимируемых атрибутов и таблицей, показывающей, какой из этих атрибутов можно анимировать каким элементом, пожалуйста, обратитесь к этому разделу спецификации SVG-анимаций. В заключение У SMIL огромный потенциал, и я едва затронула поверхность и лишь коснулась основ и технических моментов того, как он работает в SVG. Можно создать множество очень впечатляющих эффектов, особенно с морфингом и преобразованием форм. Предела фантазии нет. Не бойтесь экспериментировать! И не забывайте делиться тем, что делаете, с сообществом; мы будем счастливы видеть, чего вы смогли достичь. Спасибо за чтение! Эта статья была обновлена по результатам дискуссии в комментариях. Спасибо за важные дополнения, Амелия. =) P.S. Это тоже может быть интересно: Если вам понравилась статья, поделитесь ей! Анимация движения В этом уроке мы заглянем внутрь svg файла и познакомимся с анимацией движения объектов. Использовать будем SMIL анимацию. p, blockquote 1,0,0,0,0 —> p, blockquote 2,0,0,0,0 —> Подробно познакомиться с SMIL 3.0 можно на сайте . p, blockquote 3,0,0,0,0 —> Пример простейшей SVG анимации (SMIL) В этом уроке мы будем использовать только конструкцию , а вот рассмотрим позже. p, blockquote 5,0,0,0,0 —> Двигать объекты на пустом экране скучно, поэтому давайте создадим простую иллюстрацию и на ней потренируемся. Рисунок совы на фоне луны ночью как раз подойдет. Результат получится такой . p, blockquote 6,0,0,0,0 —> SMIL анимация не работает в MS EDGE (увы). Работа проверялась в Firefox и Chrome. Шаг 1. Рисуем иллюстрацию для svg анимации Итак, запускайте редактор и задайте в свойствах документа альбомную ориентацию (shift+ctrl+D). Начнем рисовать с неба. Нарисуйте прямоугольник и задайте любой градиент, подойдет как радиальный так и линейный . В качестве цвета можно выбрать любой темно-синий цвет, все-таки у нас ночь. p, blockquote 8,0,0,0,0 —> p, blockquote 9,0,0,0,0 —> В нижней части рисунка добавьте прямоугольник. Он должен занимать менее половины рисунка. Верхнюю сторону прямоугольника сделайте в виде дуги. Для этого оконтуриваем объект Контур-оконтурить объект . После этого достаточно потянуть мышку вверх и мы получим дугу. Таким образом мы получили холм. p, blockquote 10,0,0,0,0 —> p, blockquote 11,0,1,0,0 —> Звезды получить проще всего. Рисуем несколько кругов белого цвета и дублируем необходимое количество раз. p, blockquote 12,0,0,0,0 —> p, blockquote 13,0,0,0,0 —> Для создания изображения тумана рисуем несколько кругов, накладываем их друг на друга, выделяем и применяем операцию Сумма Ctrl+. Для тумана лучше задать радиальный градиент. p, blockquote 14,0,0,0,0 —> p, blockquote 15,0,0,0,0 —> Полученное облако дублируем пару раз, изменяем размер и отражаем по горизонтали. Затем размещаем за холмом. p, blockquote 16,0,0,0,0 —> p, blockquote 17,0,0,0,0 —> С помощью инструмента кривые Безье рисуем контур произвольного дерева и задаем заливку черным цветом (дерево можно создать и с помощью векторизации растрового изображения реального дерева). p, blockquote 18,0,0,0,0 —> p, blockquote 19,0,0,0,0 —> Далее сова. Нарисуйте контур совы и задайте заливку цветом чуть более светлым чем небо. p, blockquote 20,0,0,0,0 —> p, blockquote 21,0,0,0,0 —> Сова должна быть едва видна. Контур совы можно нарисовать из пары эллипсов. После оконтуривания эллипсов придаем им нужную форму. p, blockquote 22,1,0,0,0 —> p, blockquote 23,0,0,0,0 —> Вот что у меня получилось. p, blockquote 24,0,0,0,0 —> p, blockquote 25,0,0,0,0 —> Последний объект это Луна. Здесь все просто. Рисуем круг белого цвета. p, blockquote 26,0,0,0,0 —> p, blockquote 27,0,0,0,0 —> И с помощью Page Down опускаем его за туман. p, blockquote 28,0,0,0,0 —> p, blockquote 29,0,0,0,0 —> Все, иллюстрация готова. Можно заняться анимацией. p, blockquote 30,0,0,0,0 —> Шаг 2. Анимация луны p, blockquote 31,0,0,0,0 —> Для создания анимации предварительно необходимо выяснить id окружности. Наша луна будет подниматься вверх пока не окажется за совой, освещая ее сзади. Для это открываем окно объектов Объект- объекты. Далее выделяем наш белый круг и в панели объектов находим его id. В моем случае это circle1327. p, blockquote 32,0,0,0,0 —> p, blockquote 33,0,0,1,0 —> Затем выясняем координаты центра окружности. Для этого открываем окно xml редактора, находим по id нашу окружность (левое окно) и в правом окне находим cx и cy. Скорее всего числа будут нецелыми. Лучше изменить значения на целые- так удобнее. p, blockquote 34,0,0,0,0 —> p, blockquote 35,0,0,0,0 —> Теперь сохраняем свою работу как простой svg документ- Файл- сохранить файл. Тип файла- простой svg. p, blockquote 36,0,0,0,0 —> Далее открываем наш файл в блокноте и добавляем в начало svg документа указание на использование пространства имен (возможно в safari не сработает) p, blockquote 37,0,0,0,0 —> Нужная строка (8) выделена. p, blockquote 38,0,0,0,0 —> Теперь ищем по id нашу окружность. Для этого воспользуйтесь поиском в блокноте p, blockquote 39,0,0,0,0 —> Отлично , осталось добавить после тега окружности следующую конструкцию. p, blockquote 40,0,0,0,0 —> Это описание анимации svg графики. Небольшой комментарий p, blockquote 41,0,0,0,0 —> Первая строка ( xlink …) связывает анимацию с объектом по его id. В последующих строках задается: p, blockquote 42,0,0,0,0 —> имя изменяемой величины ( attributeName ), продолжительность анимации ( dur ), начальное и конечное значение величины ( from — to ), условие начала анимации (в моем случае через 1 секунду begin=1s ) в каком состоянии должен находится объект после окончания анимации ( fill=»freeze» « заморозить» состояние) Конструкцию animate добавляем для двух анимируемых атрибутов- отдельно для cx и отдельно для cy. Все, готово, осталось посмотреть результат . p, blockquote 43,0,0,0,0 —> p, blockquote 44,0,0,0,1 —> Анимация SVG-элемента path Думаю многие видели обзоры игровых консолей нового поколения от Polygon (Vox Media). Это те, где консоли отрисовывались в стиле blueprint’ов: Stroke-dasharray interpolation, теория Вообще техника подобной анимации линий не нова, просто до недавнего времени SVG и всё, что с ним связано, на мой взгляд, было несправедливо предано забвению, но к счастью ситуация меняется. Итак, трюк с анимацией элемента path возможен благодаря свойству stroke-dasharray элемента path . Это свойство позволяет задавать параметры пунктирной линии, а именно длину штриха и промежутка между штрихами. Если задать длину штриха равной всей длине линии, то получим обыкновенную сплошную линию. Если же задать длину штриха равной нулю, а длину промежутка опять-таки равной всей длине линии, то получим невидимую линию. А постепенно увеличивая длину штриха при длине промежутка, равной длине всей линии, мы можем имитировать её отрисовку. При таком подходе отрисовка будет происходить от начала линии. Если же вдруг необходимо отрисовывать с конца, то нужно использовать ещё одно свойство: stroke-dashoffset. Это свойство определяет смещение для первого штриха. Таким образом, уменьшая смещение и увеличивая длину штриха, получим отрисовку с конца линии. Ребята из Vox Media использовали гибридный вариант (который, на мой взгляд, избыточен), кстати почитать о том, как они это делали, можно (и нужно) в их блоге: Polygon feature design: SVG animations for fun and profit. Реализация SVG анимации В Vox Media предлагают использовать requestAnimationFrame для плавности анимации, но у нас немного другие цели, так что мы пойдём более простым путём, воспользуемся библиотекой D3.js и реализованной в ней анимацией на основе длительности. Вот собственно рабочий код, использовавшийся для анимации консоли из начала статьи. В функции transition(path) мы используем transition.attrTween(name, tween), который вызывает интерполятор, определённый в функции tweenDash() . Для вычисления длины используется метод getTotalLength(), определённый для элементов SVG path . Затем с помощью d3.interpolateString(a, b) задаётся интерполятор свойства stroke-dasharray , который выполнит интерполяцию значений от stroke-dasharray: 0,l; до stroke-dasharray: l,l; (здесь первое значение задаёт длину штриха, а второе длину промежутка). Посмотреть на то как это работает можно на bl.ocks.org: PlayStation 4: SVG animation. Думаю вы заметили, что часть элементов отображается постоянно, это происходит потому, что они нарисованы не с помощью path . Вообще подготовка и оптимизация векторных изображений для web это довольно обширная тема с массой нюансов, тянущая на отдельную статью. Движение вдоль элемента path У path есть ещё один весьма полезный метод — getPointAtLength(distance in float). Он позволяет получить координаты точки, находящейся на заданной дистанции от начала линии. С помощью него можно реализовать движение какого-либо маркера вдоль линии, и, что немаловажно, плавное вращение за счёт вычисления касательной к имеющейся линии. Начнём просто с движения вдоль линии, пока без вращения. Здесь pathStartPoint(path) вытаскивает координаты начала линии из атрибута d элемента path . В translateAlong(path) с помощью интерполятора задаются координаты нашего маркера. Пример можно посмотреть здесь: Marker animation along SVG path element with D3.js. А ещё можно объединить анимацию отрисовки линии и движение маркера, выглядеть это может следующим образом: Marker animation along SVG path element with D3.js II. Усложним задачу, добавим вращение (ну и поменяем маркер с круга на что-нибудь поинтереснее). В качестве маркера у нас будет ракета с шириной 48 и длиной 24 . Поскольку по умолчанию точкой привязки маркера является левый верхний угол, нам необходимо смещать его, чтобы привязка была к центру маркера. Также необходимо учитывать это при вращении, ведь оно тоже по умолчанию происходит вокруг левого верхнего угла. Со смещением вроде разобрались. Теперь перейдём непосредственно к вращению, здесь нам поможет определение касательной, угол будем определять с помощью арктангенса. Функция translateAlong(path) , определяющая интерполятор будет выглядеть следующим образом: Где и для чего это можно использовать Во-первых, для достижения интересного эффекта с точки зрения дизайна. Можно отображать объекты по мере скроллинга, можно делать анимацию текста, правда надо учитывать что по умолчанию каждая буква — это отдельный элемент path , да много чего можно придумать. А можно использовать с практической точки зрения, например для анимации движения по маршрутам на схемах и планах (анимация стрелочек и прочее). А ещё для инфографики, тут масса вариантов, если грамотно использовать можно весьма эффективно управлять вниманием читателя. На этом всё. Пробуйте, экспериментируйте, созидайте — всё в ваших руках. И пусть в наступившем году вам сопутствует удача. UPD: Ещё статьи на эту тему: SVG drawing animation Animated line drawing in SVG Animating Vectors with SVG
- Задание ориентации элемента относительно траектории движения rotate
- Управление расстоянием, пройденным анимацией по траектории, с помощью keyPoints
- Движение текста по произвольной траектории
- Анимация трансформаций: элемент Атрибут type служит для указания типа трансформации, которую анимируют. У него может быть одно из пяти значений: translate , scale , rotate , skewX и skewY . Атрибуты from , by и to принимают значения в том же синтаксисе, который подходит для данного типа трансформации: Для type=»translate» каждое отдельное значение выражается как [,] (сдвиг по каждой оси). Для type=»scale» каждое отдельное значение выражается как [,] (масштаб по каждой оси). Для type=»rotate» каждое отдельное значение выражается как [ ] (угол поворота и координаты центра вращения). Для type=»skewX» and type=»skewY» каждое отдельное значение выражается как (угол наклона). Если вы не очень знакомы с функциями SVG-атрибута transform , то ради краткости этой статьи, а также потому, что подробности его синтаксиса и работы выходят далеко за рамки этой статьи, я советую вам прочитать статью о них, которую я написала чуть раньше: «Разбираемся с системами координат и трансформациями в SVG (часть 2): атрибут transform» — прежде чем продолжать изучение этого руководства. Вернемся к предыдущему примеру, где мы вращали розовый прямоугольник с помощью элемента . Код для вращения выглядит так: Атрибуты from и to указывают угол поворота (начальный и конечный) и центр вращения. Конечно, в них обоих центр вращения остается тем же самым. Если вы не укажете центр, им станет верхний левый угол SVG-холста. Вот живой пример для вышеприведенного кода: Вот еще один забавный пример с одним animateTransform за авторством Габриэля: See the Pen Orbit by Gabriel (@guerreiro) on CodePen. Анимация одной отдельной трансформации очень проста, однако, всё может стать куда сложнее и запутаннее, когда дело дойдет до множественных трансформаций, особенно с учетом того, что один animateTransform может перекрывать другой, так что вместо наложения или последовательного применения эффектов вы можете получить полную противоположность. Так уж устроены системы координат и трансформации в SVG (снова рекомендую обратиться к ранее упомянутой статье). Примеров масса, но они выходят за рамки статьи. Для трансформирования SVG-графики я советую использовать CSS-трансформации. Браузеры вовсю стараются, чтобы те идеально работали с SVG, так что, возможно, вам вообще не понадобится никакой SMIL для анимации трансформаций в SVG. Элемент Элемент set предоставляет простое средство для задания значения атрибуту на определенный отрезок времени. Он поддерживает все типы атрибутов, включая те, которые по своей логике не могут быть интерполированы, напр. строки и булевы значения. Элемент set не поддерживает относительных/накопительных анимации: относительные и накопительные атрибуты недопустимы и игнорируются, даже если указаны. Поскольку используется для выставления элемента в определенное значение в определенный момент и отрезок времени, для него доступны не все атрибуты, упомянутые для предыдущих анимационных элементов. Например, у него нет атрибутов from или by , потому что изменяемое значение не меняется со временем постепенно. Для set вы можете указать целевой элемент, имя и тип атрибута, значение to и время анимации, которым можно управлять с помощью следующих атрибутов: begin , dur , end , min , max , restart , repeatCount , repeatDur и fill . Вот пример, который меняет цвет вращающегося прямоугольника на синий, когда по нему кликают. Цвет остается синим в течение 3 секунд, а затем возвращается к исходному цвету. Каждый раз при клике по прямоугольнику запускается анимация set , и цвет меняется на три секунды. Элементы, атрибуты и свойства, которые можно анимировать Не все SVG-атрибуты можно анимировать, и не все из тех, которые можно анимировать, можно анимировать всеми анимационными элементами. За полным списком анимируемых атрибутов и таблицей, показывающей, какой из этих атрибутов можно анимировать каким элементом, пожалуйста, обратитесь к этому разделу спецификации SVG-анимаций. В заключение У SMIL огромный потенциал, и я едва затронула поверхность и лишь коснулась основ и технических моментов того, как он работает в SVG. Можно создать множество очень впечатляющих эффектов, особенно с морфингом и преобразованием форм. Предела фантазии нет. Не бойтесь экспериментировать! И не забывайте делиться тем, что делаете, с сообществом; мы будем счастливы видеть, чего вы смогли достичь. Спасибо за чтение! Эта статья была обновлена по результатам дискуссии в комментариях. Спасибо за важные дополнения, Амелия. =) P.S. Это тоже может быть интересно: Если вам понравилась статья, поделитесь ей! Анимация движения В этом уроке мы заглянем внутрь svg файла и познакомимся с анимацией движения объектов. Использовать будем SMIL анимацию. p, blockquote 1,0,0,0,0 —> p, blockquote 2,0,0,0,0 —> Подробно познакомиться с SMIL 3.0 можно на сайте . p, blockquote 3,0,0,0,0 —> Пример простейшей SVG анимации (SMIL) В этом уроке мы будем использовать только конструкцию , а вот рассмотрим позже. p, blockquote 5,0,0,0,0 —> Двигать объекты на пустом экране скучно, поэтому давайте создадим простую иллюстрацию и на ней потренируемся. Рисунок совы на фоне луны ночью как раз подойдет. Результат получится такой . p, blockquote 6,0,0,0,0 —> SMIL анимация не работает в MS EDGE (увы). Работа проверялась в Firefox и Chrome. Шаг 1. Рисуем иллюстрацию для svg анимации Итак, запускайте редактор и задайте в свойствах документа альбомную ориентацию (shift+ctrl+D). Начнем рисовать с неба. Нарисуйте прямоугольник и задайте любой градиент, подойдет как радиальный так и линейный . В качестве цвета можно выбрать любой темно-синий цвет, все-таки у нас ночь. p, blockquote 8,0,0,0,0 —> p, blockquote 9,0,0,0,0 —> В нижней части рисунка добавьте прямоугольник. Он должен занимать менее половины рисунка. Верхнюю сторону прямоугольника сделайте в виде дуги. Для этого оконтуриваем объект Контур-оконтурить объект . После этого достаточно потянуть мышку вверх и мы получим дугу. Таким образом мы получили холм. p, blockquote 10,0,0,0,0 —> p, blockquote 11,0,1,0,0 —> Звезды получить проще всего. Рисуем несколько кругов белого цвета и дублируем необходимое количество раз. p, blockquote 12,0,0,0,0 —> p, blockquote 13,0,0,0,0 —> Для создания изображения тумана рисуем несколько кругов, накладываем их друг на друга, выделяем и применяем операцию Сумма Ctrl+. Для тумана лучше задать радиальный градиент. p, blockquote 14,0,0,0,0 —> p, blockquote 15,0,0,0,0 —> Полученное облако дублируем пару раз, изменяем размер и отражаем по горизонтали. Затем размещаем за холмом. p, blockquote 16,0,0,0,0 —> p, blockquote 17,0,0,0,0 —> С помощью инструмента кривые Безье рисуем контур произвольного дерева и задаем заливку черным цветом (дерево можно создать и с помощью векторизации растрового изображения реального дерева). p, blockquote 18,0,0,0,0 —> p, blockquote 19,0,0,0,0 —> Далее сова. Нарисуйте контур совы и задайте заливку цветом чуть более светлым чем небо. p, blockquote 20,0,0,0,0 —> p, blockquote 21,0,0,0,0 —> Сова должна быть едва видна. Контур совы можно нарисовать из пары эллипсов. После оконтуривания эллипсов придаем им нужную форму. p, blockquote 22,1,0,0,0 —> p, blockquote 23,0,0,0,0 —> Вот что у меня получилось. p, blockquote 24,0,0,0,0 —> p, blockquote 25,0,0,0,0 —> Последний объект это Луна. Здесь все просто. Рисуем круг белого цвета. p, blockquote 26,0,0,0,0 —> p, blockquote 27,0,0,0,0 —> И с помощью Page Down опускаем его за туман. p, blockquote 28,0,0,0,0 —> p, blockquote 29,0,0,0,0 —> Все, иллюстрация готова. Можно заняться анимацией. p, blockquote 30,0,0,0,0 —> Шаг 2. Анимация луны p, blockquote 31,0,0,0,0 —> Для создания анимации предварительно необходимо выяснить id окружности. Наша луна будет подниматься вверх пока не окажется за совой, освещая ее сзади. Для это открываем окно объектов Объект- объекты. Далее выделяем наш белый круг и в панели объектов находим его id. В моем случае это circle1327. p, blockquote 32,0,0,0,0 —> p, blockquote 33,0,0,1,0 —> Затем выясняем координаты центра окружности. Для этого открываем окно xml редактора, находим по id нашу окружность (левое окно) и в правом окне находим cx и cy. Скорее всего числа будут нецелыми. Лучше изменить значения на целые- так удобнее. p, blockquote 34,0,0,0,0 —> p, blockquote 35,0,0,0,0 —> Теперь сохраняем свою работу как простой svg документ- Файл- сохранить файл. Тип файла- простой svg. p, blockquote 36,0,0,0,0 —> Далее открываем наш файл в блокноте и добавляем в начало svg документа указание на использование пространства имен (возможно в safari не сработает) p, blockquote 37,0,0,0,0 —> Нужная строка (8) выделена. p, blockquote 38,0,0,0,0 —> Теперь ищем по id нашу окружность. Для этого воспользуйтесь поиском в блокноте p, blockquote 39,0,0,0,0 —> Отлично , осталось добавить после тега окружности следующую конструкцию. p, blockquote 40,0,0,0,0 —> Это описание анимации svg графики. Небольшой комментарий p, blockquote 41,0,0,0,0 —> Первая строка ( xlink …) связывает анимацию с объектом по его id. В последующих строках задается: p, blockquote 42,0,0,0,0 —> имя изменяемой величины ( attributeName ), продолжительность анимации ( dur ), начальное и конечное значение величины ( from — to ), условие начала анимации (в моем случае через 1 секунду begin=1s ) в каком состоянии должен находится объект после окончания анимации ( fill=»freeze» « заморозить» состояние) Конструкцию animate добавляем для двух анимируемых атрибутов- отдельно для cx и отдельно для cy. Все, готово, осталось посмотреть результат . p, blockquote 43,0,0,0,0 —> p, blockquote 44,0,0,0,1 —> Анимация SVG-элемента path Думаю многие видели обзоры игровых консолей нового поколения от Polygon (Vox Media). Это те, где консоли отрисовывались в стиле blueprint’ов: Stroke-dasharray interpolation, теория Вообще техника подобной анимации линий не нова, просто до недавнего времени SVG и всё, что с ним связано, на мой взгляд, было несправедливо предано забвению, но к счастью ситуация меняется. Итак, трюк с анимацией элемента path возможен благодаря свойству stroke-dasharray элемента path . Это свойство позволяет задавать параметры пунктирной линии, а именно длину штриха и промежутка между штрихами. Если задать длину штриха равной всей длине линии, то получим обыкновенную сплошную линию. Если же задать длину штриха равной нулю, а длину промежутка опять-таки равной всей длине линии, то получим невидимую линию. А постепенно увеличивая длину штриха при длине промежутка, равной длине всей линии, мы можем имитировать её отрисовку. При таком подходе отрисовка будет происходить от начала линии. Если же вдруг необходимо отрисовывать с конца, то нужно использовать ещё одно свойство: stroke-dashoffset. Это свойство определяет смещение для первого штриха. Таким образом, уменьшая смещение и увеличивая длину штриха, получим отрисовку с конца линии. Ребята из Vox Media использовали гибридный вариант (который, на мой взгляд, избыточен), кстати почитать о том, как они это делали, можно (и нужно) в их блоге: Polygon feature design: SVG animations for fun and profit. Реализация SVG анимации В Vox Media предлагают использовать requestAnimationFrame для плавности анимации, но у нас немного другие цели, так что мы пойдём более простым путём, воспользуемся библиотекой D3.js и реализованной в ней анимацией на основе длительности. Вот собственно рабочий код, использовавшийся для анимации консоли из начала статьи. В функции transition(path) мы используем transition.attrTween(name, tween), который вызывает интерполятор, определённый в функции tweenDash() . Для вычисления длины используется метод getTotalLength(), определённый для элементов SVG path . Затем с помощью d3.interpolateString(a, b) задаётся интерполятор свойства stroke-dasharray , который выполнит интерполяцию значений от stroke-dasharray: 0,l; до stroke-dasharray: l,l; (здесь первое значение задаёт длину штриха, а второе длину промежутка). Посмотреть на то как это работает можно на bl.ocks.org: PlayStation 4: SVG animation. Думаю вы заметили, что часть элементов отображается постоянно, это происходит потому, что они нарисованы не с помощью path . Вообще подготовка и оптимизация векторных изображений для web это довольно обширная тема с массой нюансов, тянущая на отдельную статью. Движение вдоль элемента path У path есть ещё один весьма полезный метод — getPointAtLength(distance in float). Он позволяет получить координаты точки, находящейся на заданной дистанции от начала линии. С помощью него можно реализовать движение какого-либо маркера вдоль линии, и, что немаловажно, плавное вращение за счёт вычисления касательной к имеющейся линии. Начнём просто с движения вдоль линии, пока без вращения. Здесь pathStartPoint(path) вытаскивает координаты начала линии из атрибута d элемента path . В translateAlong(path) с помощью интерполятора задаются координаты нашего маркера. Пример можно посмотреть здесь: Marker animation along SVG path element with D3.js. А ещё можно объединить анимацию отрисовки линии и движение маркера, выглядеть это может следующим образом: Marker animation along SVG path element with D3.js II. Усложним задачу, добавим вращение (ну и поменяем маркер с круга на что-нибудь поинтереснее). В качестве маркера у нас будет ракета с шириной 48 и длиной 24 . Поскольку по умолчанию точкой привязки маркера является левый верхний угол, нам необходимо смещать его, чтобы привязка была к центру маркера. Также необходимо учитывать это при вращении, ведь оно тоже по умолчанию происходит вокруг левого верхнего угла. Со смещением вроде разобрались. Теперь перейдём непосредственно к вращению, здесь нам поможет определение касательной, угол будем определять с помощью арктангенса. Функция translateAlong(path) , определяющая интерполятор будет выглядеть следующим образом: Где и для чего это можно использовать Во-первых, для достижения интересного эффекта с точки зрения дизайна. Можно отображать объекты по мере скроллинга, можно делать анимацию текста, правда надо учитывать что по умолчанию каждая буква — это отдельный элемент path , да много чего можно придумать. А можно использовать с практической точки зрения, например для анимации движения по маршрутам на схемах и планах (анимация стрелочек и прочее). А ещё для инфографики, тут масса вариантов, если грамотно использовать можно весьма эффективно управлять вниманием читателя. На этом всё. Пробуйте, экспериментируйте, созидайте — всё в ваших руках. И пусть в наступившем году вам сопутствует удача. UPD: Ещё статьи на эту тему: SVG drawing animation Animated line drawing in SVG Animating Vectors with SVG
- Элемент
- Элементы, атрибуты и свойства, которые можно анимировать
- В заключение
- P.S. Это тоже может быть интересно:
- Анимация движения
- Пример простейшей SVG анимации (SMIL)
- Шаг 1. Рисуем иллюстрацию для svg анимации
- Шаг 2. Анимация луны
- Анимация SVG-элемента path
- Stroke-dasharray interpolation, теория
- Реализация SVG анимации
- Движение вдоль элемента path
- Где и для чего это можно использовать
Видео:Как сделать текст по кругу CSS/JS радиус окружностиСкачать
Введение
SVG-графику можно анимировать с помощью анимационных элементов. Эти анимационные элементы изначально были определены в спецификации анимаций SMIL. В их число входят:
В дополнение к анимационным элементам, определенным в спецификации SMIL, SVG включает расширения, совместимые со спецификацией SMIL animations; эти расширения включают атрибуты, расширяющие функциональность элемента , и дополнительные анимационные элементы. В расширения SVG входят:
По своей природе SVG-анимации напоминают CSS-анимации и переходы. Создаются ключевые кадры, объекты движутся, цвета меняются и т.п. Однако они могут делать и то, чего CSS-анимации не могут, что мы еще рассмотрим.
Видео:SVG, большой гайдСкачать
Зачем использовать SVG-анимации?
SVG-картинки могут быть стилизованы и анимированы с помощью CSS (см. слайды). По сути, все трансформации и анимированные переходы, которые можно применять к HTML-элементам, применимы и к SVG-элементам. Но есть SVG-свойства, которые не анимируются силами CSS, а только силами SVG. Например, SVG-путь изначально содержит набор данных (атрибут d=»» ), которые определяют его форму. Эти данные можно изменять и анимировать с помощью SMIL, но не с помощью CSS. Это связано с тем, что SVG-элементы описываются набором атрибутов, известных как атрибуты представления. Некоторые из этих атрибутов можно устанавливать, менять и анимировать с помощью CSS, а некоторые нельзя.
Итак, многие анимации и эффекты на данный момент силами CSS просто недостижимы. Недостающие возможности CSS-анимаций для SVG можно восполнить либо использованием JavaScript, либо декларативными SVG-анимациями, основанными на SMIL.
Если вы предпочитаете JavaScript, я рекомендую библиотеку snap.svg Дмитрия Барановского, которую описывают как «SVGшный jQuery». Вот собрание примеров для нее.
Если же вам больше по душе декларативный подход к анимациям, вы можете воспользоваться анимационными SVG-элементами, которые мы рассматриваем в этом руководстве!
Еще одно преимущество SMIL перед JS-анимациями — то, что JS-анимации не работают, если SVG встроен в страницу в виде img или использован как background-image в CSS. SMIL-анимации работают в обоих случаях (по крайней мере, должны, поддержка браузерами на подходе). Это большое преимущество, по-моему. Оно может оказаться решающим, чтобы вы предпочли SMIL прочим вариантам. И эта статья — руководство, чтобы помочь вам начать использовать SMIL уже сегодня.
Видео:Уроки Front end | Анимация SVGСкачать
Браузерная поддержка и варианты для подстраховки
Поддержка SMIL браузерами вполне прилична. Это работает во всех браузерах, кроме IE и Оперы Мини. За подробностями о поддержке можете обратиться к таблице совместимости на Can I Use.
Если вам нужен резервный вариант на случай неподдержки SMIL-анимаций, вы можете «на лету» проверить наличие поддержки в браузере с помощью Modernizr. Если SMIL не поддерживается, вы можете предусмотреть какую-то замену (JS-анимацию, альтернативный интерфейс и т.д.).
Видео:SVG анимации stroke-dasharray & stroke-dashoffsetСкачать
Указание целевого объекта анимации с помощью xlink:href
Какой из четырех анимационных элементов вы бы ни выбрали, вам нужно указать целевой объект, для которого этот элемент задает анимацию.
Чтобы указать этот объект, можно использовать атрибут xlink:href. Этот атрибут принимает URI-ссылку на элемент, который будет объектом нашей анимации и который, соответственно, и будет изменяться с течением времени. Целевой объект должен быть частью текущего фрагмента SVG-документа.
Если вы уже сталкивались с анимационными SVG-элементами, вы, вероятно, видели их вложенными прямо в тот элемент, который ими предполагалось анимировать. Это тоже возможно, согласно спецификации:
Если атрибут xlink:href не задан, то целевым элементом становится непосредственный родительский элемент текущего анимационного элемента.
Так что если вы хотите «инкапсулировать» анимацию в элементе, к которому она применяется, вы можете делать так. А если вы хотите вынести анимации в какое-то другое место документа, вы можете сделать и это, указав целевой объект каждой анимации с помощью xlink:href — оба способа работают отлично.
Видео:JavaScript. Движение точки по окружности с использованием формул.Скачать
Указание целевого свойства анимации с помощью attributeName и attributeType
У всех анимационных элементов может быть и еще один общий атрибут: attributeName . Атрибут attributeName используется для указания имени атрибута, который вы анимируете.
Например, если вы хотите анимировать положение центра на оси X, вы можете задать cx в качестве значения атрибута attributeName .
attributeName принимает лишь одно значение, а не список значений, так что вы можете анимировать только по одному атрибуту за раз. Если вы хотите анимировать более одного атрибута, вам нужно определить более одной анимации для одного элемента. Мне бы хотелось, чтобы это было иначе, и здесь я вижу преимущество CSS-анимаций перед SMIL. Но опять же, из-за значений, возможных для других анимационных атрибутов (следующими в очереди на рассмотрение), есть смысл определять только одно имя атрибута за раз, иначе значения других атрибутов могут стать слишком сложными для работы с ними.
Указывая имя атрибута, вы можете добавить XMLNS-префикс (сокращение от «пространство имен XML»), чтобы обозначить пространство имен для атрибута. Пространство имен также можно указать с помощью атрибута attributeType . Например, некоторые атрибуты входят в пространство имен CSS (что значит, что они могут быть также CSS-свойствами), а другие есть только в XML. Таблицу этих атрибутов можно посмотреть здесь. В этой таблице приведены не все атрибуты SVG. Это только те из них, что можно задавать с помощью CSS. Некоторые из них уже доступны как CSS-свойства.
Если значение attributeType не заданано явно или равно auto , браузер должен сначала поискать соответствующее имя свойства в списке CSS-свойств, и, если ничего не найдено, поискать в пространстве имен XML по умолчанию для данного элемента.
Например, следующий код анимирует opacity SVG-прямоугольника. Так как атрибут opacity доступен также как CSS-свойство, значение attributeType указывает на пространство имен CSS:
Мы пройдемся по другим анимационным атрибутам в нижеследующих примерах. Если не указано иное, все анимационные атрибуты — общие для всех анимационных элементов.
Видео:Circular Animation CSS - CSS Animation Effects - Beginner CSS Animation TutorialСкачать
Анимация атрибута элемента от одного значения до другого в течение отрезка времени и указание конечного состояния: from , by , to , dur и fill
Давайте начнем с перемещения круга из одного положения в другое. Будем делать это, меняя значение его атрибута cx (который указывает X-координату его центра).
Чтобы изменить значение с одного на другое за период времени, используются атрибуты from , to , и dur . В дополнение к ним вы можете указать, когда анимация должна начаться, с помощью атрибута begin .
В примере выше, мы определили круг и затем вызвали анимацию для этого круга. Центр круга перемещается с начальной позиции в 50 единиц до 450 единиц вдоль оси X.
Атрибуту begin задано значение click . Это значит, что круг начинает двигаться, когда его кликнули. Можно также задать ему значение времени. Например, begin=»0s» запускает анимацию сразу же, как только страница загрузилась. Вы можете отсрочить анимацию, задавая положительные значения времени. Например, begin=»2s» запустит анимацию через две секунды после загрузки.
Еще более интересная особенность begin — то, что вы можете задавать значения типа click + 1s , чтобы запустить анимацию через секунду после клика! Более того, вы можете использовать другие значения, позволяющие синхронизировать анимации без необходимости рассчитывать длительности и задержки других анимаций. Подробнее об этом позже.
Атрибут dur похож на эквивалент animation-duration в CSS.
Атрибуты from и to похожи на ключевые кадры from и to в блоке @keyframe CSS-анимации:
Атрибут fill (который довольно неудачно получил одинаковое название с атрибутом fill , определяющим цвет заливки элемента) похож на свойство animation-fill-mode , определяющее, должен ли элемент вернуться в начальное состояние после завершения анимации, или нет. Значения похожи на аналогичные в CSS, за исключением других имен:
- freeze : результат анимации определен как «застывший» в конечном значении активного периода анимации. Результат анимации остается «застывшим», пока документ открыт (или до перезапуска анимации).
- remove : результат анимации убирается (больше не применяется), когда активный период анимации завершился. Как только достигнут конец анимации, анимация больше не влияет на целевой объект (если ее не перезапустить).
Попробуйте менять значения в живом демо-примере, чтобы посмотреть, как они влияют на анимацию:
Атрибут by служит для указания относительного сдвига анимации. Как можно предположить из названия, с его помощью вы можете указать величину, на которую анимация должна продвинуться. Эффект от by виден практически только тогда, когда вы продвигаетесь по анимации дискретными шагами, наподобие того, как это работает с CSS-функцией steps() . SVG-эквивалент самой CSS-функции steps() — это calcMode=»discrete» . Мы дойдем до атрибута calcMode далее в статье.
Другой случай, когда эффект от by более очевиден — когда вы задаете только атрибут to . Например, если вы будете использовать его с элементом set , который мы рассмотрим далее в статье.
И последнее, но немаловажное: by также оказывается полезным, когда вы работаете с относительными и накопительными анимациями. До них мы тоже дойдем чуть позже.
Перезапуск анимаций с помощью restart
Бывает полезно не дать анимации перезапуститься, пока она активна. Для этого SVG предлагает атрибут restart . Вы можете задать ему одно из трех возможных значений:
- always : анимация может быть перезапущена в любой момент. Значение по умолчанию.
- whenNotActive : анимация может быть перезапущена, только когда неактивна (т.е. после завершения активности). Попытки перезапустить анимацию во время активного промежутка игнорируются.
- never : элемент не может быть перезапущен весь остаток простой длительности его родительского контейнера времени (в случае SVG, поскольку родительским контейнером времени является фрагмент SVG-документа, анимация не может быть перезапущена, пока открыт документ).
Именование и синхронизация анимаций
Допустим, мы хотим анимировать положение и цвет круга, так, чтобы изменение цвета произошло после завершения движения. Мы можем сделать это, задав атрибуту begin анимации изменения цвета значение, равное dur ation анимации движения; так мы делали бы это и в CSS.
Однако у SMIL есть замечательная возможность обработки событий. Мы уже отметили, что атрибут begin принимает значения типа click + 5s . Это значение называется «значением события», и в данном случае состоит из ссылки на событие, за которым следует «часовое значение». Интересный момент заключен в названии второй части: «часовое значение». Почему не просто «значение времени»? Разгадка в том, что вы можете буквально задавать значение как на часах, напр. «10min» или «01:33», что эквивалентно «1 мин 33 с», или даже «02:30:03» (2 ч 30 мин 3 с). На момент написания статьи, часовые значения не реализованы полностью ни в одном браузере.
Так что, если мы вернемся к предыдущему демо и используем click + 01:30 , если браузер начнет его поддерживать, анимация запустится через 1 мин 30 с после клика на круг.
Другой тип значений, который он может принимать — ID другой анимации, за которым следует ссылка на событие. Если у вас есть две (и более) анимации (неважно, применяются ли они к одному и тому же элементу или нет!) и вы хотите синхронизировать их так, чтобы одна из них запускалась в зависимости от другой, вы можете сделать это, даже не зная длительности второй анимации.
Например, в следующем демо, синий прямоугольник начинает двигаться через 1 секунду после начала анимации круга. Это достигается заданием каждой анимации своего ID с последующим использованием этого ID с событием begin , как показано в следующем коде:
Именно begin=»circ-anim.begin + 1s» — та часть, что указывает браузеру начать анимацию прямоугольника через 1 секунду после начала анимации круга. Вы можете проверить на живом примере:
Можно также начать анимацию прямоугольника после завершения анимации круга, используя событие end :
Вы можете даже запустить ее в определенный момент до конца анимации круга:
Зацикливание анимаций с repeatCount
Если вы хотите проиграть анимацию больше одного раза, вам пригодится атрибут repeatCount . Можно указать желаемое количество повторений либо использовать ключевое слово indefinite , чтобы анимация повторялась бесконечно. Так что, чтобы повторить анимацию круга дважды, код должен выглядеть примерно так:
Вы можете проверить на живом примере. Я установила 2 повторения для круга и indefinite для квадрата.
Заметьте, как анимация начинается заново с начального значения from , а не со значения, достигаемого в конце анимации. К сожалению, в SMIL нет способа для перехода туда и обратно между начальным и конечным значением, как позволяют CSS-анимации. В CSS свойство animation-direction указывает, должна ли анимация проигрываться в обратном направлении при некоторых (или всех) повторениях. Значение animation-direction: alternate означает, что нечетные циклы анимации проигрываются в прямом направлении, а четные — в обратном. Это значит, что первый цикл проигрывается от начала до конца, второй цикл — назад от конца к началу, третий — снова от начала до конца, и т.д.
Чтобы добиться этого в SMIL, вам придется воспользоваться JavaScript, чтобы явно менять значения атрибутов from и to . Джон МакПартланд из студии Big Bite Creative не так давно написал пост с объяснением, как он делал это для анимации иконки меню, над которой он работал.
Еще один выход — указать желаемое конечное значение как значение для середины, а фактическое конечное значение оставить тем же, что начальное. Например, вы можете задать анимацию, начинающуюся со значения from и заканчивающаяся тем же самым значением в to , разве что вам придется указать то значение, которое по смыслу должно быть конечным, в качестве промежуточного значения между from и to .
В CSS мы могли сделать это примерно так:
Эквивалент этого в SMIL — использование атрибута values , который мы вкратце разберем чуть позже.
Таким образом, вышеописанное решение может подойти или не подойти в зависимости от типа анимации, который вам нужен, и от того, нужна ли вам последовательность анимаций, их повторение или накопление их результата.
Вот симпатичная несложная бесконечная анимация с использованием задержек времени начала, созданная Майлзом Иламом:
Ограничение времени повторения с помощью repeatDur
Бесконечное повторение анимации может раздражать или отталкивать пользователей, если анимация снова и снова возобновляется долгое время. Так что может иметь смысл ограничить возможность повторения анимации конечным периодом времени, и прекратить повторять ее через какое-то время после начала отображения документа. Оно известно как время представления.
Время представления указывает точку на временной оси относительно начала отображения документа для данного фрагмента. Она указывается с помощью атрибута repeatDur . Его синтаксис похож на часовое значение, но отсчитывается не относительно события другой анимации или действия пользователя, а от начала отображения документа.
Например, следующий код остановит повторение анимации через 1 мин 30 с после появления документа:
И вот живой демо-пример:
Синхронизация анимаций на основе количества повторений
Теперь давайте вернемся на шаг назад, к вопросу синхронизации между двумя анимациями. Действительно, в SMIL вы можете синхронизировать анимации так, что одна анимация запускается в зависимости от количества повторений другой. Например, можно запустить анимацию после энного по счету повторения другой анимации плюс (или минус) произвольное количество времени.
Следующий пример запускает анимацию прямоугольника на втором повторении анимации круга:
А вот живой пример, в котором анимация прямоугольника запускается через 2 секунды после второго повторения анимации круга.
Прим. перев.: пример в оригинальной статье у меня не работает ни в одном браузере, поэтому я добавил свой видоизмененный вариант. Похоже, чтобы repeat(n) работал в Chrome, число повторений анимации должно быть не менее n+1, т.е. указанное повторение не должно быть последним. Вот этот вариант:
Управление значениями ключевого кадра анимации: keyTimes и values
В CSS мы можем указывать, какие значения должно принимать анимируемое нами свойство в определенном кадре в течение анимации. Например, если вы анимируете левое смещение элемента, то вместо того, чтобы анимировать его, скажем, с 0 до 300 напрямую, вы можете анимировать его так, чтобы в некоторых кадрах оно принимало специальные значения, вроде таких:
Эти 0%, 20%, 80% и 100% — кадры анимации, а значения внутри блока для каждого кадра — значения для данного кадра. Выше описан эффект, когда элемент «отскакивает от стенки», а затем возвращается в окончательное положение.
В SMIL можно управлять значениями для отдельных кадров похожим образом, но синтаксис другой.
Чтобы указать ключевые кадры, используйте атрибут keyTimes . А чтобы задать значения анимируемого свойства, используйте атрибуты values . В SMIL достаточно удобная система именования.
Если мы вернемся к нашему движущемуся кругу и используем значения наподобие тех, что в примере CSS-анимации выше, код будет выглядеть примерно так:
Итак, что мы тут сделали?
Первое, что надо отметить — то, что значения времени ключевых кадров и промежуточных значений указываются в виде списков. Атрибут keyTimes представляет собой список значений времени, разделенных точкой с запятой, задающих темп анимации. Каждое время в списке соответствует значению в атрибуте values и определяет, когда это значение будет использовано в функции анимации. Каждое значение времени в списке keyTimes указывается как число с плавающей точкой от 0 до 1 (включительно), представляющее собой пропорциональное смещение относительно простой длительности анимационного элемента. Так что ключевые моменты времени очень похожи на аналогичные в CSS, только задаются не процентами, а дробью.
Вот живой пример для кода выше. Кликните по кругу, чтобы начать анимацию.
Заметьте, что, если используется список значений, анимация будет применять значения последовательно в течение своего периода. Если задан values , любые значения атрибутов from , to и by игнорируются.
Здесь же стоит также упомянуть, что вы можете использовать атрибут values без атрибута keyTimes — значения автоматически распределяется через равномерные промежутки времени (для любого calcMode , кроме paced , подробнее об этом буквально в следующем разделе).
Управление темпом анимации с помощью произвольной функции плавности: calcMode и keySplines
Я снова обращусь к сравнению CSS и SMIL, потому что понять синтаксис и некоторые понятия SMIL будет намного проще, если вы уже знакомы с CSS-анимациями.
В CSS вы можете изменить монотонный темп анимации по умолчанию и указать произвольную функцию плавности, управляющую анимацией, с помощью свойства animation-timing-function . Функция плавности может быть одним из зарезервированных ключевых слов, либо кубической функцией Безье. Последние можно генерировать с помощью инструментов наподобие такого, созданного Лией Веру.
В SMIL темп анимации задается с помощью атрибута calcMode . По умолчанию темп линейный ( linear ) у всех анимационных элементов, кроме animateMotion (мы рассмотрим его далее в статье). Помимо значения linear , можно задавать такие значения: discrete , paced или spline .
- discrete указывает, что функция анимации перескакивает с одного значения на следующее без какой-либо интерполяции. Это похоже на функцию steps() в CSS.
- paced похоже на linear , за исключением того, что оно игнорирует любые промежуточные значения и временные метки, заданные с помощью keyTimes . Оно рассчитывает расстояния между последовательными значениями и соответственно делит их на время. Если все ваши значения находятся в линейном порядке, вы не заметите разницы. Но если они смещаются взад-вперед, или если это цвета (которые обрабатываются как значения трехмерных векторов), вы наверняка увидите промежуточные значения. Вот живой пример, представленный Амелией Беллами-Ройдз, показывающий разницу между тремя упомянутыми значениями calcMode (прим. перев.: в данном переводе используется переведенная версия оригинального примера Амелии):
Вероятно, вы заметили в последнем предложении новый атрибут: keySplines . Итак, что этот атрибут keySplines делает?
Снова обратимся к CSS-эквивалентам.
В CSS, вы можете указывать темп анимации внутри каждого ключевого кадра, вместо того, чтобы задавать темп всей анимации. Это дает лучший контроль над тем, как должна проходить анимация на каждом ключевом кадре. Пример использования этой возможности — создание эффекта «прыгающего мяча». Ключевые кадры для этого могут выглядеть так:
Вместо ключевых слов для функций плавности мы могли задействовать соответствующие кубические функции Безье:
- ease-in = cubic-bezier(0.47, 0, 0.745, 0.715)
- ease-out = cubic-bezier(0.39, 0.575, 0.565, 1)
Давайте начнем с указания ключевых моментов времени и списка значений для нашего оранжевого круга, к которому будет применен такой же эффект «прыгания»:
Анимация начинается по клику и застывает, как только достигнет конечного значения. Следующим шагом, чтобы указать темп для каждого ключевого кадра, мы собираемся добавить атрибут keySplines .
Атрибут keySplines принимает набор управляющих точек Безье, которые ставятся в соответствие списку keyTimes , определяя тем самым кубическую кривую Безье для управления темпом анимации интервала. Каждое описание управляющих точек представляет собой набор из четырех значений x1 y1 x2 y2, описывающий управляющие точки Безье для одного временного отрезка. Все значения должны быть в диапазоне от 0 до 1, и если атрибуту calcMode не задано значение spline , то атрибут keySplines игнорируется.
Вместо того, чтобы принимать кубические функции Безье в качестве значений, keySplines принимает координаты двух управляющих точек, используемых для построения кривой. Управляющие точки показаны на следующем скриншоте генератора Лии. Скриншот показывает также координаты каждой точки, обозначенные тем же цветом, что сама точка. Для атрибута keySplines мы будем использовать именно эти значения, чтобы определить темп анимации ключевого кадра.
SMIL позволяет разделять эти значения либо запятыми с необязательным пробелом после, либо только пробелами. Значения keyTimes , определяющие соответствующий сегмент, являются «опорными точками» Безье, а значения keySplines — управляющие точки. Поэтому набор управляющих точек должен быть меньше, чем количество значений keyTimes (другими словами, keyTimes задает границы интервалов, а keySplines задаются для самих интервалов, поэтому в первом наборе оказыватся на один элемент больше — прим. перев.)
Если мы вернемся к примеру с «прыгающим мячиком», координаты управляющих точек для функций ease-in и ease-out показаны на следующих рисунках:
Таким образом, чтобы перевести это в анимационный SVG-элемент, мы получим следующий код:
Вот живой демо-пример:
Если вы хотите задать лишь единую функцию плавности для всей анимации без каких-либо промежуточных значений, вам всё равно придется задавать ключевые кадры с помощью атрибута keyTimes , но понадобятся только начальный и конечный кадры, т.е. 0; 1 , и никаких промежуточных values .
Относительные и накопительные анимации: additive и accumulate
Иногда бывает полезно определить анимацию, начинающуюся с того места, на котором предыдущая анимация закончилась, или такую, которая использует суммарный накопленный результат предыдущих анимаций как стартовое значение. Для этого в SVG есть два удобно названных атрибута: additive и accumulate .
Предположим, у вас есть элемент, который должен «расти» в ширину, или линия, длина которой должна увеличиваться, или элемент, который должен перемещаться с места на место поэтапно. Это особенно полезно для повторяющихся анимаций.
Как для любой другой анимации, вы зададите значения from и to . Однако, когда вы зададите для additive значение sum , каждое из этих значений будет считаться относительно исходного значения анимируемого атрибута.
Вернемся к нашему кругу. Для него исходная позиция cx равна 50. Если задать from=»0″ to=»100″ , то ноль на самом деле означает исходные 50, а 100 на самом деле означает 50 + 100; другими словами, практически это как бы задает from=»50″ to=»150″ .
Это дает нам следующий результат:
Это всё, что делает атрибут additive . Он просто указывает, должны ли значения from и to отсчитываться относительно текущего значения, или нет. Атрибут принимает лишь одно из двух значений: sum и replace . Последнее является значением по умолчанию, и по сути значит, что значения from and to заменяют текущее/исходное значение, что может привести к неприятному скачку перед началом анимации (попробуйте заменить sum на replace в примере выше, чтобы сравнить наглядно).
Однако, что если мы хотим добавлять значения так, чтобы второе повторение начиналось с конечного значения предыдущего? Здесь в игру вступает атрибут accumulate .
Атрибут accumulate отвечает за то, является ли анимация накопительной. По умолчанию его значение none , что означает, что при повторении, например, анимация стартует заново с начала. Но вы можете задать ему значение sum , что указывает, что каждая следующая итерация анимации основывается на конечном значении предыдущей итерации.
Так, если мы вернемся к предыдущей анимации и зададим accumulate=»sum» , мы получим следующий результат, которого мы и добивались:
Обратите внимание, что атрибут accumulate игнорируется, если целевой атрибут не поддерживает сложения значений, или если анимация не повторяется. Он также будет игнорироваться, если функция анимации задана только с атрибутом to .
Указание времени конца анимации с помощью end
Помимо указания, когда анимация начнется, вы можете также указать, когда она закончится, с помощью атрибута end . Например, вы можете установить анимацию на бесконечное повторение, а затем остановить ее, когда начнется анимация другого элемента. Атрибут end принимает значения, похожие на те, что принимает атрибут begin . Вы можете задавать абсолютные или относительные значения/смещения времени, количество повторений, значения событий и т.д.
Например, в следующем примере, оранжевый круг медленно движется с периодом в 30 секунд к противоположной стороне холста. Зеленый круг тоже анимируется, но только после клика. Анимация оранжевого круга прекращается, когда начинается анимация зеленого. Кликните по зеленому кругу, чтобы посмотреть, как оранжевый остановится:
Разумеется, такая же синхронизация анимаций возможна и для анимаций, применяемых к одному и тому же элементу. Например, предположим, мы установили анимацию цвета для круга, бесконечно меняющую его с одного значения на другое. Затем, когда по элементу кликнули, он движется к противоположной стороне. Теперь мы можем установить, чтобы анимация цвета остановилась, как только по элементу кликнули и анимация движения запустилась.
Задание интервалов анимации с помощью нескольких значений begin и end
Действительно, оба атрибута begin и end принимают список значений, разделенных точками с запятой. Каждое значение атрибута begin соответствует одному значению атрибута end , формируя таким образом активные и неактивные интервалы анимации.
Вы можете представить это как что-то вроде движущейся машины, где у колес машины бывают периоды «активности» и «неактивности», в зависимости от того, движется машина или нет. Вы даже можете сделать анимированный эффект движущейся машины, применив две анимации: одну, которая перемещает машину по координатной оси или некой траектории, причем эта анимация является относительной и накопительной, и вторую — которая вращает колеса машины в периоды, синхронизированные с движением машины.
Пример указания множественных начальных и конечных значений времени (т.е. интервалов) дан в следующем демо, где прямоугольник вращается на основе заданных интервалов, соответственно чередуя периоды активности и неактивности (перезапустите демо, если вы пропустили анимацию).
Заметьте также, что даже если вы зададите repeatCount значение indefinite , оно будет перекрыто значениями end анимация не будет повторяться бесконечно.
Ограничение активной длительности элемента с помощью min и max
Точно так же, как вы можете ограничить время повторения анимации, вы можете ограничить и время активной длительности анимации. Атрибуты min и max указывают, соответственно, минимальную и максимальную активную длительность анимационного элемента. Они дают возможность задавать активной длительности элемента верхний и нижний пределы. Значениями обоих атрибутов могут быть часовые значения.
Для min это указывает минимальную величину активной длительности, измеряемую во время активности элемента. Значение должно быть больше либо равно 0, который является значением по умолчанию и вообще не ограничивает активную длительность.
Для max часовое значение указывает максимальную величину активной длительности, измеряемую во время активности элемента. Значение также должно быть больше 0. По умолчанию max имеет значение indefinite . Оно вообще не ограничивает активную длительность.
Если заданы оба атрибута min и max , то значение max должно быть больше или равно значению min . Если это требование не выполняется, оба атрибута игнорируются.
Но что определяет активную длительность элемента? Мы уже упоминали длительность повторения, в дополнение к «простой длительности», которая является длительностью анимации без повторений (задаваемой с помощью dur ), так как это всё работает вместе? Что перекрывает что? И как быть с атрибутом end , который окажется «главным» и просто завершит анимацию?
Порядок такой: сначала браузер вычисляет активную длительность, исходя из значений dur , repeatCount , repeatDur и end . Затем он сравнивает результат вычисления с заданными значениями min и max . Если результат находится в этих пределах, вычисленное на первом шаге значение считается верным и не меняется. Иначе, возможны две ситуации:
- Если первоначально вычисленная длительность превышает значение max , активная длительность элемента становится равной значению max .
- Если первоначально вычисленная длительность меньше значения min , активная длительность элемента становится равной значению min , и элемент ведет себя следующим образом:
- Если длительность повторения (либо простая длительность, если анимация не повторяется) элемента больше чем min , то элемент проигрывается нормально в течение активной длительности, ограниченной min .
- Иначе, элемент проигрывается нормально в течение его длительности повторения (либо простой длительности, если элемент не повторяется), а затем «застывает» или не отображается в зависимости от значения атрибута fill .
Это помогает нам понять, как браузер фактически рассчитывает активную длительность. Ради краткости я не буду вдаваться здесь в подробности этого. Но в спецификации есть весьма исчерпывающая таблица с различными комбинациями атрибутов dur , repeatCount , repeatDur и end , которая показывает, чему будет равна активная длительность в случае каждой комбинации. Вы можете ознакомиться с таблицей и узнать больше подробностей в этом разделе спецификации.
Наконец, если анимационный элемент должен начинаться раньше его родительского элемента (напр., с отрицательным значением смещения), минимальная длительность отмеряется от вычисленного, а не наблюдаемого начала анимации. Это значит, что значение min может не давать видимого эффекта.
Пример : морфинг контуров
Одним из атрибутов, который можно анимировать в SMIL, но не в CSS, является атрибут d (сокращение от data, т.е. «данные») SVG-элемента
. Атрибут d содержит данные, определяющие контур формы, которую вы рисуете. Данные контура содержат набор команд и координат, которые сообщают браузеру, где и как рисовать точки, кривые и отрезки, образующие итоговый контур.
Анимация этого атрибута делает возможным морфинг SVG-контуров и создание эффектов плавного «перетекания» одной формы в другую. Но для того, чтобы изменять форму пути было возможно, начальная, конечная и любая из промежуточных форм должны иметь строго одинаковое количество вершин/ключевых точек, и порядок их должен оставаться тем же. Если число вершин не совпадает, анимация не заработает. Причина этого в том, что изменение формы на самом деле происходит путем перемещения вершин и интерполяции их положения, так что если одна вершина отсутствует или не совпадает, интерполировать оказывается нечего.
Чтобы анимировать SVG-контур, нужно задать для attributeName значение d , а затем указать для from и to значения, соответствующие начальной и конечной формам, также вы можете использовать атрибут values для задания любых промежуточных форм, через которые форма должна пройти в ходе изменения.
Ради краткости, я не буду вдаваться тут в подробности, как это делается. Вместо этого вы можете прочитать великолепную статью Ноа Блона, в которой он объясняет, как создавал меняющую форму анимацию как-бы-загрузки с помощью . Вот живой пример к статье Ноа:
А вот еще один пример морфинга, созданный Феликсом Хорнойю:
Вы можете даже менять форму контура, используемого как маска для обрезки! Пример этого, созданный Хизер Бачел:
Видео:Сделай самую аху#### анимацию на HTML/CSS и SVGСкачать
Анимация по произвольной траектории: элементВидео:JS-решения №13. Индикатор прокрутки на чистом JS + SVG-анимация окружностиСкачать
Задание траектории движения с помощью атрибута path
Видео:JS-решения №13. Индикатор прокрутки на чистом JS + SVG-анимация окружностиСкачать
Атрибут path задает траекторию движения. Он задается в том же формате и интерпретируется тем же образом, что атрибут d элемента path . Эффект анимации движения по траектории заключается в наложении дополнительной матрицы трансформации поверх текущей матрицы трансформации объекта, вызывающей сдвиг по осям X и Y в текущей системе координат пользователя на значения X и Y, рассчитываемые для каждого момента времени. Другими словами, заданная траектория отсчитывается относительно текущего положения элемента, используя данные траектории для перемещения объекта на позицию на этой траектории.
Для нашего круга мы зададим анимацию по траектории, которая будет выглядеть примерно так:
Вот код, требующийся для движения круга по этой траектории:
Я хочу особо обратить ваше внимание на координаты в данных пути. Путь начинается с перемещения (M) в точку с координатами (0, 0), прежде чем начать рисовать кривую (c) в другую точку. Важно отметить, что точка (0, 0) в данном случае — это позиция нашего круга, неважно, где он находится, а НЕ верхний левый угол системы координат. Как я отметила выше, координаты в атрибуте path отсчитываются относительно текущего положения элемента!
Результат вышеприведенного кода следующий:
Если вы укажете путь, начинающийся с другой точки, а не (0, 0), круг рывком перескочит на расстояние, заданное координатами начальной точки. Например, предположим, что вы рисуете путь в Illustrator с последующим экспортом его в виде траектории движения (так я делала это в первый раз). Экспортированный путь будет выглядеть как-то так:
Начальной точкой пути в этом случае будет (100.4, 102.2). Если бы мы использовали этот путь как траекторию движения, круг сначала «прыгнул» бы на примерно 100 единиц вправо и 102 единицы вниз, и лишь затем начал бы движение относительно нового положения. Так что не забывайте об этом при подготовке траекторий для ваших анимаций.
Если используются атрибуты from , by , to и values , то они указывают форму на текущем холсте, представляющую собой траекторию движения.
Указание траектории движения с помощью элемента
Есть и другой способ задания траектории движения. Вместо использования относительного атрибута path , можно ссылаться на внешний путь с помощью элемента . Элемент , дочерний по отношению к элементу , будет указывать на внешний путь с помощью атрибута xlink:href .
с траекторией движения может быть указан в любом месте документа; он даже может быть буквально лишь объявлен внутри элемента и вообще не отображаться на холсте. В следующем примере траектория отображается, потому что в большинстве случаев вы захотите показать путь, по которому элемент движется.
Заметьте, что, согласно спецификации:
Различные точки (x, y) формы предоставляют вспомогательные матрицы трансформации поверх текущей матрицы трансформации для указанного объекта, которые вызывают смещение по осям X и Y в текущей пользовательской системе координат на значение (x,y) формы, вычисляемое в зависимости от времени. Таким образом, указанный объект сдвигается с течением времени на смещение траектории движения относительно начала текущей пользовательской системы координат. Вспомогательные матрицы трансформации применяются поверх любых трансформаций, задаваемых свойством transform целевого элемента, и любых анимаций этого атрибута, заданных элементами animateTransform для целевого элемента.
Опять же, позиция круга «умножается» или «трансформируется» на координаты из данных пути.
В следующем примере, у нас есть путь посередине холста. Круг позиционируется в начало пути. Но всё же, когда движение по траектории используется, круг не начинает движение из текущего положения. Смотрите пример для лучшего объяснения. Кликните по кругу, чтобы анимировать его.
Видите, как круг движется по тому же самому контуру, но в другом месте? Это потому, что позиция круга трансформируется (сдвигается) на значения из данных траектории.
Один способ обойти это — начинать с положения круга в точке (0, 0), так что трансформация по данным пути передвинет его куда нужно, и всё заработает как ожидалось.
Другой способ — применить трансформацию, которая «обнулит» координаты круга перед тем, как задействовать траекторию.
Вот модифицированная версия примера выше, использующая замкнутую траекторию и бесконечно зацикленную анимацию.
Правила приоритета для
Поскольку один и тот же эффект можно реализовать с animateMotion более чем одним способом, нужны правила, по которым одни значения могут перекрывать другие.
Правила перекрытия для animateMotion таковы:
- При задании траектории движения, элемент mpath перекрывает атрибут path , который перекрывает values , а тот перекрывает from , by и to .
- При определении точек, соответствующих атрибуту keyTimes , атрибут keyPoints перекрывает path , который перекрывает values , а тот перекрывает from , by и to .
Видео:SVG анимация: способы анимировать SVG /SVG Animation: the ways of animating SVGСкачать
Задание ориентации элемента относительно траектории движения rotate
В нашем предыдущем примере, элемент, который мы анимировали вдоль траектории, был кругом. Но что, если бы мы анимировали элемент, для которого важна ориентация, например, иконку машинки? Иконка машинки в следующем примере создана Freepik.
В этом примере я заменила круг группой с ID, равным «car», содержащей элемент, образующий группу. Затем, чтобы избежать вышеописанных проблем с движением по траектории, я применила трансформацию, сдвигающую машинку в определенную точку, так что в итоге начальной позицией оказывается точка (0, 0). Значения внутри трансформации на самом деле являются координатами точки, где начинает рисоваться первый контур машинки (сразу после команды M).
Затем машинка начинает двигаться по траектории. Но… вот как выглядит это движение:
Ориентация машинки фиксирована, и не соответствует направлению движения. Чтобы изменить это, мы будем использовать атрибут rotate .
У атрибута rotate может быть одно из трех значений:
- auto : указывает, что объект будет поворачиваться с течением времени на угол направления (т.е. по касательному вектору направления) траектории движения.
- auto-reverse : указывает, что объект будет поворачиваться с течением времени на угол направления (т.е. по касательному вектору направления) траектории движения плюс 180 градусов.
- число: указывает, что к целевому элементу применена постоянная трансформация вращения, указанное число задает угол поворота в градусах.
Чтобы исправить ориентацию машинки в примере выше, мы начнем с задания вращению значения auto . Получим вот такой результат:
Если вы хотите, чтобы машинка «ездила» снаружи контура, значение auto-reverse решает задачу.
Это выглядит лучше, но у нас осталась проблема: машинка выглядит так, будто ездит по траектории задним ходом! Чтобы изменить это, нам придется перевернуть ее по ее оси Y. Это можно сделать путем масштабирования ее по этой оси с коэффициентом -1. Так что, если мы применим трансформацию к g с ID, равным car , машинка «поедет» вперед, как задумано. Трансформация масштабирования просто добавляется последовательно с ранее примененной трансформацией сдвига.
И окончательный демо-пример выглядит так:
Управление расстоянием, пройденным анимацией по траектории, с помощью keyPoints
Атрибут keyPoints дает возможность указывать продвижение по траектории для каждого значения, указанного в keyTimes . Если он задан, keyPoints заставляет keyTimes применяться к значениям из keyPoints , а не к точкам, перечисленным в атрибуте values или точкам в атрибуте path .
keyPoints принимает разделенный точками с запятой список значений с плавающей точкой от 0 до 1 и указывает, как далеко по траектории должен продвинуться объект в момент времени, заданный в соответствующем значении keyTimes . Расчет расстояния определяется алгоритмами браузера. Каждое значение продвижения в списке соответствует одному значению из списка в атрибуте keyTimes . Если задан список keyPoints , в нем должно быть ровно столько же значений, сколько в списке keyTimes .
Важный момент, который здесь надо отметить — задание значения linear для calcMode , чтобы keyPoints заработал. Кажется, что по логике он должен работать и со значением paced , если ваши ключевые точки смещены то взад, то вперед, но с ним он не работает.
Вот пример Амелии Беллами-Ройдз (чей профиль на Codepen вам стоило бы изучить полностью), использующий keyPoints для имитации поведения, при котором движение по траектории начинается с предустановленным отступом, поскольку по умолчанию в SMIL у нас сейчас нет такой возможности (прим. перев.: здесь тоже оригинальный пример заменен переведенным вариантом).
Видео:#10. SVG для НАЧИНАЮЩИХ (Анимируем SVG через CSS keyframes)Скачать
Движение текста по произвольной траектории
Движение текста по произвольной траектории отличается от движения других SVG-элементов по траекториям. Для анимации текста вам понадобится элемент , а не элемент .
Во-первых, начнем с позиционирования текста вдоль траектории. Это можно сделать, вложив элемент
. Текст, который будет размещен вдоль траектории, будет определен внутри элемента
, а не как непосредственный потомок элемента
Затем textPath должен сослаться на фактический путь, который мы хотим использовать, в точности как в предыдущих примерах. Путь, на который мы ссылаемся, тоже может либо отображаться на холсте, либо определяться внутри . Посмотрите код следующего демо-примера.
Чтобы анимировать текст вдоль траектории, мы используем элемент для анимации атрибута startOffset .
startOffset представляет собой отступ текста относительно пути. 0% — начало пути; 100% соответствуют его концу. Так что если, например, задать отступ в 50%, текст будет начинаться посередине траектории. Думаю, вы уже догадались, что это нам дает.
Анимируя startOffset , мы создадим эффект текста, движущегося по траектории. Взгляните на код следующего демо.
Видео:Сделай самую аху#### анимацию на CSS и SVGСкачать
Анимация трансформаций: элемент
Атрибут type служит для указания типа трансформации, которую анимируют. У него может быть одно из пяти значений: translate , scale , rotate , skewX и skewY .
Атрибуты from , by и to принимают значения в том же синтаксисе, который подходит для данного типа трансформации:
- Для type=»translate» каждое отдельное значение выражается как [,] (сдвиг по каждой оси).
- Для type=»scale» каждое отдельное значение выражается как [,] (масштаб по каждой оси).
- Для type=»rotate» каждое отдельное значение выражается как [ ] (угол поворота и координаты центра вращения).
- Для type=»skewX» and type=»skewY» каждое отдельное значение выражается как (угол наклона).
Если вы не очень знакомы с функциями SVG-атрибута transform , то ради краткости этой статьи, а также потому, что подробности его синтаксиса и работы выходят далеко за рамки этой статьи, я советую вам прочитать статью о них, которую я написала чуть раньше: «Разбираемся с системами координат и трансформациями в SVG (часть 2): атрибут transform» — прежде чем продолжать изучение этого руководства.
Вернемся к предыдущему примеру, где мы вращали розовый прямоугольник с помощью элемента . Код для вращения выглядит так:
Атрибуты from и to указывают угол поворота (начальный и конечный) и центр вращения. Конечно, в них обоих центр вращения остается тем же самым. Если вы не укажете центр, им станет верхний левый угол SVG-холста. Вот живой пример для вышеприведенного кода:
Вот еще один забавный пример с одним animateTransform за авторством Габриэля:
See the Pen Orbit by Gabriel (@guerreiro) on CodePen.
Анимация одной отдельной трансформации очень проста, однако, всё может стать куда сложнее и запутаннее, когда дело дойдет до множественных трансформаций, особенно с учетом того, что один animateTransform может перекрывать другой, так что вместо наложения или последовательного применения эффектов вы можете получить полную противоположность. Так уж устроены системы координат и трансформации в SVG (снова рекомендую обратиться к ранее упомянутой статье). Примеров масса, но они выходят за рамки статьи. Для трансформирования SVG-графики я советую использовать CSS-трансформации. Браузеры вовсю стараются, чтобы те идеально работали с SVG, так что, возможно, вам вообще не понадобится никакой SMIL для анимации трансформаций в SVG.
Видео:❌ CSS не нужен! Научишься анимировать любое статичное SVG изображение после этого видеоСкачать
Элемент
Элемент set предоставляет простое средство для задания значения атрибуту на определенный отрезок времени. Он поддерживает все типы атрибутов, включая те, которые по своей логике не могут быть интерполированы, напр. строки и булевы значения. Элемент set не поддерживает относительных/накопительных анимации: относительные и накопительные атрибуты недопустимы и игнорируются, даже если указаны.
Поскольку используется для выставления элемента в определенное значение в определенный момент и отрезок времени, для него доступны не все атрибуты, упомянутые для предыдущих анимационных элементов. Например, у него нет атрибутов from или by , потому что изменяемое значение не меняется со временем постепенно.
Для set вы можете указать целевой элемент, имя и тип атрибута, значение to и время анимации, которым можно управлять с помощью следующих атрибутов: begin , dur , end , min , max , restart , repeatCount , repeatDur и fill .
Вот пример, который меняет цвет вращающегося прямоугольника на синий, когда по нему кликают. Цвет остается синим в течение 3 секунд, а затем возвращается к исходному цвету. Каждый раз при клике по прямоугольнику запускается анимация set , и цвет меняется на три секунды.
Видео:Рисуем и анимируем svg-иконку в вебе | HTML, CSSСкачать
Элементы, атрибуты и свойства, которые можно анимировать
Не все SVG-атрибуты можно анимировать, и не все из тех, которые можно анимировать, можно анимировать всеми анимационными элементами. За полным списком анимируемых атрибутов и таблицей, показывающей, какой из этих атрибутов можно анимировать каким элементом, пожалуйста, обратитесь к этому разделу спецификации SVG-анимаций.
Видео:Как создать НЕ СКУЧНЫЙ BACKGORUND для сайта с помощью CSS и SVG анимации - скучные уроки #1Скачать
В заключение
У SMIL огромный потенциал, и я едва затронула поверхность и лишь коснулась основ и технических моментов того, как он работает в SVG. Можно создать множество очень впечатляющих эффектов, особенно с морфингом и преобразованием форм. Предела фантазии нет. Не бойтесь экспериментировать! И не забывайте делиться тем, что делаете, с сообществом; мы будем счастливы видеть, чего вы смогли достичь. Спасибо за чтение!
Эта статья была обновлена по результатам дискуссии в комментариях. Спасибо за важные дополнения, Амелия. =)
P.S. Это тоже может быть интересно:
Если вам понравилась статья, поделитесь ей!
Видео:Еще одна аху#### анимация на CSS и SVGСкачать
Анимация движения
В этом уроке мы заглянем внутрь svg файла и познакомимся с анимацией движения объектов. Использовать будем SMIL анимацию.
p, blockquote 1,0,0,0,0 —>
p, blockquote 2,0,0,0,0 —>
Подробно познакомиться с SMIL 3.0 можно на сайте .
p, blockquote 3,0,0,0,0 —>
Видео:Руководство по CSS анимации. Transition / Animation / KeyframesСкачать
Пример простейшей SVG анимации (SMIL)
В этом уроке мы будем использовать только конструкцию , а вот рассмотрим позже.
p, blockquote 5,0,0,0,0 —>
Двигать объекты на пустом экране скучно, поэтому давайте создадим простую иллюстрацию и на ней потренируемся. Рисунок совы на фоне луны ночью как раз подойдет. Результат получится такой .
p, blockquote 6,0,0,0,0 —>
SMIL анимация не работает в MS EDGE (увы). Работа проверялась в Firefox и Chrome.
Видео:Анимация спрайта на CSS на примере персонажа.Скачать
Шаг 1. Рисуем иллюстрацию для svg анимации
Итак, запускайте редактор и задайте в свойствах документа альбомную ориентацию (shift+ctrl+D). Начнем рисовать с неба. Нарисуйте прямоугольник и задайте любой градиент, подойдет как радиальный так и линейный .
В качестве цвета можно выбрать любой темно-синий цвет, все-таки у нас ночь.
p, blockquote 8,0,0,0,0 —>
p, blockquote 9,0,0,0,0 —>
В нижней части рисунка добавьте прямоугольник. Он должен занимать менее половины рисунка. Верхнюю сторону прямоугольника сделайте в виде дуги. Для этого оконтуриваем объект Контур-оконтурить объект . После этого достаточно потянуть мышку вверх и мы получим дугу. Таким образом мы получили холм.
p, blockquote 10,0,0,0,0 —>
p, blockquote 11,0,1,0,0 —>
Звезды получить проще всего. Рисуем несколько кругов белого цвета и дублируем необходимое количество раз.
p, blockquote 12,0,0,0,0 —>
p, blockquote 13,0,0,0,0 —>
Для создания изображения тумана рисуем несколько кругов, накладываем их друг на друга, выделяем и применяем операцию Сумма Ctrl+. Для тумана лучше задать радиальный градиент.
p, blockquote 14,0,0,0,0 —>
p, blockquote 15,0,0,0,0 —>
Полученное облако дублируем пару раз, изменяем размер и отражаем по горизонтали. Затем размещаем за холмом.
p, blockquote 16,0,0,0,0 —>
p, blockquote 17,0,0,0,0 —>
С помощью инструмента кривые Безье рисуем контур произвольного дерева и задаем заливку черным цветом (дерево можно создать и с помощью векторизации растрового изображения реального дерева).
p, blockquote 18,0,0,0,0 —>
p, blockquote 19,0,0,0,0 —>
Далее сова. Нарисуйте контур совы и задайте заливку цветом чуть более светлым чем небо.
p, blockquote 20,0,0,0,0 —>
p, blockquote 21,0,0,0,0 —>
Сова должна быть едва видна. Контур совы можно нарисовать из пары эллипсов. После оконтуривания эллипсов придаем им нужную форму.
p, blockquote 22,1,0,0,0 —>
p, blockquote 23,0,0,0,0 —>
Вот что у меня получилось.
p, blockquote 24,0,0,0,0 —>
p, blockquote 25,0,0,0,0 —>
Последний объект это Луна. Здесь все просто. Рисуем круг белого цвета.
p, blockquote 26,0,0,0,0 —>
p, blockquote 27,0,0,0,0 —>
И с помощью Page Down опускаем его за туман.
p, blockquote 28,0,0,0,0 —>
p, blockquote 29,0,0,0,0 —>
Все, иллюстрация готова. Можно заняться анимацией.
p, blockquote 30,0,0,0,0 —>
Видео:Создание красивого hover эффекта используя SVG анимациюСкачать
Шаг 2. Анимация луны
p, blockquote 31,0,0,0,0 —>
Для создания анимации предварительно необходимо выяснить id окружности. Наша луна будет подниматься вверх пока не окажется за совой, освещая ее сзади. Для это открываем окно объектов Объект- объекты. Далее выделяем наш белый круг и в панели объектов находим его id. В моем случае это circle1327.
p, blockquote 32,0,0,0,0 —>
p, blockquote 33,0,0,1,0 —>
Затем выясняем координаты центра окружности. Для этого открываем окно xml редактора, находим по id нашу окружность (левое окно) и в правом окне находим cx и cy. Скорее всего числа будут нецелыми. Лучше изменить значения на целые- так удобнее.
p, blockquote 34,0,0,0,0 —>
p, blockquote 35,0,0,0,0 —>
Теперь сохраняем свою работу как простой svg документ- Файл- сохранить файл. Тип файла- простой svg.
p, blockquote 36,0,0,0,0 —>
Далее открываем наш файл в блокноте и добавляем в начало svg документа указание на использование пространства имен (возможно в safari не сработает)
p, blockquote 37,0,0,0,0 —>
Нужная строка (8) выделена.
p, blockquote 38,0,0,0,0 —>
Теперь ищем по id нашу окружность. Для этого воспользуйтесь поиском в блокноте
p, blockquote 39,0,0,0,0 —>
Отлично , осталось добавить после тега окружности следующую конструкцию.
p, blockquote 40,0,0,0,0 —>
Это описание анимации svg графики. Небольшой комментарий
p, blockquote 41,0,0,0,0 —>
Первая строка ( xlink …) связывает анимацию с объектом по его id. В последующих строках задается:
p, blockquote 42,0,0,0,0 —>
- имя изменяемой величины ( attributeName ),
- продолжительность анимации ( dur ),
- начальное и конечное значение величины ( from — to ),
- условие начала анимации (в моем случае через 1 секунду begin=1s )
- в каком состоянии должен находится объект после окончания анимации ( fill=»freeze» « заморозить» состояние)
Конструкцию animate добавляем для двух анимируемых атрибутов- отдельно для cx и отдельно для cy. Все, готово, осталось посмотреть результат .
p, blockquote 43,0,0,0,0 —> p, blockquote 44,0,0,0,1 —>
Видео:Animate Any SVG icons with CSS Only | SVG Stroke Animation With Html CSSСкачать
Анимация SVG-элемента path
Думаю многие видели обзоры игровых консолей нового поколения от Polygon (Vox Media). Это те, где консоли отрисовывались в стиле blueprint’ов:
Stroke-dasharray interpolation, теория
Вообще техника подобной анимации линий не нова, просто до недавнего времени SVG и всё, что с ним связано, на мой взгляд, было несправедливо предано забвению, но к счастью ситуация меняется. Итак, трюк с анимацией элемента path возможен благодаря свойству stroke-dasharray элемента path . Это свойство позволяет задавать параметры пунктирной линии, а именно длину штриха и промежутка между штрихами. Если задать длину штриха равной всей длине линии, то получим обыкновенную сплошную линию. Если же задать длину штриха равной нулю, а длину промежутка опять-таки равной всей длине линии, то получим невидимую линию. А постепенно увеличивая длину штриха при длине промежутка, равной длине всей линии, мы можем имитировать её отрисовку. При таком подходе отрисовка будет происходить от начала линии. Если же вдруг необходимо отрисовывать с конца, то нужно использовать ещё одно свойство: stroke-dashoffset. Это свойство определяет смещение для первого штриха. Таким образом, уменьшая смещение и увеличивая длину штриха, получим отрисовку с конца линии.
Ребята из Vox Media использовали гибридный вариант (который, на мой взгляд, избыточен), кстати почитать о том, как они это делали, можно (и нужно) в их блоге: Polygon feature design: SVG animations for fun and profit.
Реализация SVG анимации
В Vox Media предлагают использовать requestAnimationFrame для плавности анимации, но у нас немного другие цели, так что мы пойдём более простым путём, воспользуемся библиотекой D3.js и реализованной в ней анимацией на основе длительности.
Вот собственно рабочий код, использовавшийся для анимации консоли из начала статьи.
В функции transition(path) мы используем transition.attrTween(name, tween), который вызывает интерполятор, определённый в функции tweenDash() . Для вычисления длины используется метод getTotalLength(), определённый для элементов SVG path . Затем с помощью d3.interpolateString(a, b) задаётся интерполятор свойства stroke-dasharray , который выполнит интерполяцию значений от stroke-dasharray: 0,l; до stroke-dasharray: l,l; (здесь первое значение задаёт длину штриха, а второе длину промежутка). Посмотреть на то как это работает можно на bl.ocks.org: PlayStation 4: SVG animation.
Думаю вы заметили, что часть элементов отображается постоянно, это происходит потому, что они нарисованы не с помощью path . Вообще подготовка и оптимизация векторных изображений для web это довольно обширная тема с массой нюансов, тянущая на отдельную статью.
Движение вдоль элемента path
У path есть ещё один весьма полезный метод — getPointAtLength(distance in float). Он позволяет получить координаты точки, находящейся на заданной дистанции от начала линии. С помощью него можно реализовать движение какого-либо маркера вдоль линии, и, что немаловажно, плавное вращение за счёт вычисления касательной к имеющейся линии.
Начнём просто с движения вдоль линии, пока без вращения.
Здесь pathStartPoint(path) вытаскивает координаты начала линии из атрибута d элемента path . В translateAlong(path) с помощью интерполятора задаются координаты нашего маркера. Пример можно посмотреть здесь: Marker animation along SVG path element with D3.js. А ещё можно объединить анимацию отрисовки линии и движение маркера, выглядеть это может следующим образом: Marker animation along SVG path element with D3.js II.
Усложним задачу, добавим вращение (ну и поменяем маркер с круга на что-нибудь поинтереснее). В качестве маркера у нас будет ракета с шириной 48 и длиной 24 . Поскольку по умолчанию точкой привязки маркера является левый верхний угол, нам необходимо смещать его, чтобы привязка была к центру маркера. Также необходимо учитывать это при вращении, ведь оно тоже по умолчанию происходит вокруг левого верхнего угла. Со смещением вроде разобрались. Теперь перейдём непосредственно к вращению, здесь нам поможет определение касательной, угол будем определять с помощью арктангенса.
Функция translateAlong(path) , определяющая интерполятор будет выглядеть следующим образом:
Где и для чего это можно использовать
Во-первых, для достижения интересного эффекта с точки зрения дизайна. Можно отображать объекты по мере скроллинга, можно делать анимацию текста, правда надо учитывать что по умолчанию каждая буква — это отдельный элемент path , да много чего можно придумать.
А можно использовать с практической точки зрения, например для анимации движения по маршрутам на схемах и планах (анимация стрелочек и прочее). А ещё для инфографики, тут масса вариантов, если грамотно использовать можно весьма эффективно управлять вниманием читателя.
На этом всё. Пробуйте, экспериментируйте, созидайте — всё в ваших руках. И пусть в наступившем году вам сопутствует удача.
UPD:
Ещё статьи на эту тему:
- SVG drawing animation
- Animated line drawing in SVG
- Animating Vectors with SVG