Создание слоистой анимации на SVG. Анимация, старые подходы

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

Что такое Snap.svg?

Snap.svg — это библиотека JavaScript, которая призвана помогать веб-разработчикам поставлять расширенные возможности SVG в интернет. Данная библиотека в состоянии загружать, анимировать, и даже создавать SVG графику прямо в браузере. Snap был создан Дмитрием Барановским, который также создал Рафаэля, но в отличие от него, данная библиотека сделана для поддержки большинства современных браузеров.

Создание простой SVG графики

После того, как вы загрузили библиотеку и включили ее в вашу страницу, первое, что вам нужно сделать, это создать элемент SVG HTML:

Затем, подтвердите Snap библиотеку:

Var s = Snap();

Опуская параметры поверхности нашего рисунка, он автоматически будет размером 100% х 100%, но если вы хотите, задать конкретную ширину и высоту, вы можете это сделать следующим образом:

Var circle = s.circle(200, 200, 100);

Этот код создает простой круг 100px в радиусе, который расположен на 200px от верха и левой стороны нашей страницы.

Фон, по умолчанию, заполнения формы является черным, но мы можем изменить его, наряду с шириной штрихов, используя метод attr:

Circle.attr({ fill: "#6A8EAB", stroke: "#fff", strokeWidth: 3 });

Конечно же, мы можем создавать и другие формы с помощью Snap, например, прямоугольники:

Var r = s.rect(100, 100, 75, 75, 5);

Этот код создает прямоугольник 100px сверху и слева от рабочей области, с шириной и высотой в 75px и радиусом границы в 5px.

Еще мы можем добавить текст:

Var t = s.text(50, 50, "WebDesignMagazine");

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

Var circles = s.group(s.circle(100, 150, 70), s.circle(200, 150, 70));

Snap дает возможность анимировать наши элементы:

Circle.animate({r: 50}, 2000);

Одно из самых больших преимуществ Snap’а, является его возможность загружать уже существующие SVG:

Snap.load("image.svg", function (f) { // Code });

Этот код импортирует файлы SVG, но для того, чтобы разместить их на нашей чертежной доске, мы должны добавить его:

Snap.load("image.svg", function (f) { g = f.select("g"); s.append(g); });

Теперь он есть у нас на чертежной доске и мы можем сделать его перетаскиваемым:

G.drag();

И, как элементы, которые мы видели ранее, мы также можем изменить атрибуты наших изображений такие, как цвет заливки или штрихи (Stroke). Но это нужно сделать до того, как изображение добавляется на доску:

F.select("polygon").attr({fill: "#FF0000"});

Как вы видите, метод select позволяет нам делать поиск через элементы. В данном случае, мы ищем любые многоугольники (polygon) с черным фоном, а затем меняем их на красный.

А вы уже используете эту библиотеку в своих проектах? Если да, оставьте в комментариях - очень интересно посмотреть на готовый вариант.

Высоких конверсий!

Snap.svg - это JavaScript-библиотека, которая позволяет очень быстро создавать и управлять SVG графикой в современных браузерах, но вот все IE ниже IE9 обделены счастьем. Эта библиотека преемник другой библиотеки Raphaël , созданной Дмитрием Барановским - самой популярной JavaScript-библиотеки для работы с SVG на то время. Что такое Raphäel?Raphaël - великолепная библиотека выпущенная в 2008 году, самой большой победой которой стала поддержка браузера IE5.5 и выше. Однако поддержка большинства браузеров вносит ограничения и означает, что нельзя реализовать последние разработки, вместо этого приходится полагаться на общий набор функций SVG.

Через некоторое время сообщество разработчиков библиотеки Raphäel.js разделилось на две части: одна группа опиралась на кроссбраузерность, а другая опиралась для создания полноценных SVG элементов. Последней группе понадобились большие изменения для поддержки всех возможностей SVG, с которыми Raphäel.js не могла справиться из за ряда своих ограничений.

Поэтому была создана библиотека Snap.svg, которая была полностью написана с нуля Дмитрием Барановским (в команде Adobe Web Platform) для того чтобы работать с SVG было легче, а так же с использованием последних возможностей, которые SVG может предложить нам, такие как: маскирование, шаблоны, градиенты, группирование, анимация и многое другое.

Что вы можете делать со Snap.svg? Snap.svg поможет вам создать любую графику, но также можно работать уже с существующими SVG эелемнтами. Это значит, что ваше SVG не обязательно должно быть создано при помощи Snap.svg! Вы также можете свободно создавать и манипулировать графикой через такие инструменты как Adobe Illustrator, Inkscape или Sketch. Начало работы со Snap.svg Для начала вам нужно скачать Snap.svg . Ссылка ведет прямо на проект, расположенный на GitHub, поэтому у вас всегда будет свежая версия.

После этого вы обнаружите следующие файлы в архиве.


  • demos - здесь находятся некоторые примеры, которые вы также найдёте на офф. сайте .
  • dist - 2 вида библиотеки, сжатый и несжатый (для разработки) snap.svg.
  • doc - здесь вы найдете документацию по API, которая также доступна на офф. сайте .
  • src - компоненты, инструменты и плагины для работы Snap.svg вроде анимации, рисования, запуска задач для Grunt и др.
  • test - папка содержит модульные тесты для Snap.svg.
После скачивания Snap.svg вам нужно начать новый веб-проект, который должен включать следующую структуру:

  • index.html - главный HTML-документ;
  • js/snap.svg.js - подключение snap.svg;
  • js/main.js - наш основной рабочий файл.
Создайте шаблон HTML и подключите скрипты js/snap.svg.js и js/main.js где-нибудь на вашей странице, а так же вставьте контейнер внутрь и дайте ему идентификатор, через который мы будем обращаться к данному SVG. Структура должна быть следующей:

200?"200px":""+(this.scrollHeight+5)+"px");">



Моя первый SVG элемент



#svg {
width: 600px; height: 300px;
}






Работа с SVG Давайте переместимся непосредственно к коду. Дальше вам понадобятся базовые знания JavaScript и понимание того, как он работает. Но это не особо важно, потому что мы не собираемся в этом уроке погружаться слишком глубоко, но если вы решили создавать большие проекты с использованием данной библиотеки, советуем подучить JS.

Для начала инициализируем Snap указывающий на наш элемент через создание переменной, указывающей ссылку на наш SVG елемент. В нашем это элемент с идентификатором #svg . Переменную назовем s .

200?"200px":""+(this.scrollHeight+5)+"px");">var s = Snap("#svg");


Отсюда, через переменную s, мы получим доступ ко всем методам библиотеки Snap.svg. Например мы захотим произвольную фигуру, такую как круг или прямоугольник. Но тут есть небольшие тонкости, о которых мы сейчас расскажем.

  • Круг может принимать три значения: x, y и радиус (офф. документация по Circle API);
  • Прямоугольник может принимать шесть значений: x, y, ширина, высота, радиус по горизонтали и радиус по вертикали (офф. документация по Rect API);
  • Эллипс может принимать четыре значения: x, y, радиус по горизонтали и радиус по вертикали (офф. документация по ellipse API).
К нашей переменной s мы добавляем методы, которые помогут нам создать наши фигуры.

200?"200px":""+(this.scrollHeight+5)+"px");">// Круг с радиусом 80px
var circle = s.circle(90,120,80);
// Квадрат с размером стороны 160px
var square = s.rect(210,40,160,160);
// Эллипс с радиусом по вертикали 80px и радиусом по горизонтали 50px
var ellipse = s.ellipse(460,120,50,80);

Код выше покажет следующий результат.

circle.attr({
fill: "coral",
stroke: "coral",
strokeOpacity: .3,
strokeWidth: 10
});

Square.attr({
fill: "lightblue",
stroke: "lightblue",
strokeOpacity: .3,
strokeWidth: 10
});

Ellipse.attr({
fill: "mediumturquoise",
stroke: "mediumturquoise",
strokeOpacity: .2,
strokeWidth: 10
});


Теперь наши фигуры на SVG стали гораздо симпатичнее и приятней! Дополнительная манипуляция с SVG Snap.svg использует мощное метод под именем group, который группирует векторы вместе, делая их одной фигурой. Вы можете группировать сколько угодно фигур, добавляя их в виде списка элементов. Давайте создадим два круга, сгруппируем их и сделаем немного прозрачной заливку каждого круга, чтобы было видно, как это работает.

200?"200px":""+(this.scrollHeight+5)+"px");">var circle_1 = s.circle(200, 200, 140);
var circle_2 = s.circle(150, 200, 140);

Circles.attr({
fill: "coral",
fillOpacity: .6
});


Мы получим следующее:


Var circles = s.group(circle_1, circle_2);

Circles.attr({
fill: "coral",
fillOpacity: .6,
});

Ellipse.attr({
opacity: .4
});


Мы получим следующее:

circles.attr({
fill: "coral",
fillOpacity: .6,
mask: ellipse
});

Ellipse.attr({
fill: "#fff",
opacity: .8
});


Мы получим следующее:

var circle_1 = s.circle(300, 200, 140);
var circle_2 = s.circle(250, 200, 140);

// Группируем круги вместе

Var circles = s.group(circle_1, circle_2);
var ellipse = s.ellipse(275, 220, 170, 90);

// Затем добавляем заливку цвета и прозрачости
// к кругу и применяем маску
circles.attr({
fill: "coral",
fillOpacity: .6,
mask: ellipse
});

Ellipse.attr({
fill: "#fff",
opacity: .8
});

// Создание эффекта мигания путём изменения значения
// ry для эллипса с 90px до 1px и обратно

Function blink(){
ellipse.animate({ry:1}, 220, function(){
ellipse.animate({ry: 90}, 300);
});
};

// Вызываем метод blink каждые 3 секунды

SetInterval(blink, 3000);

Поддержка браузеров Как упоминалось ранее все эти функции поддерживаются в современных браузерах, начиная с: IE9+, Safari, Chrome, Firefox и Opera.
Более точную поддержку браузерами можно узнать с точностью до версий. Бесплатно и с открытым исходным кодом Snap.svg доступна под лицензией Apache 2, это значит, что библиотека совершенно бесплатна и с полностью открытым исходным кодом. Вывод Мы рассмотрели с вами очень мощный инструмент для работы c SVG который вы можете использовать уже сейчас в своих проектах. Надеемся что статья была для вас интересной! Всем спасибо за внимание.

  • FalleN

  • 3217

  • 92

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

В этой статье я смешаю старое с новым, взяв за основу что-то примитивное и вдохнув в это новую жизнь. Sass поможет оптимизировать рабочий процесс и, возможно, поможет продемонстрировать автоматизацию. Иногда автоматизация может стоять на службе творчества.

Анимация, старые подходы

Я далеко не эксперт в анимации, зато я знаю, что мне действительно нравится: когда все двигается. Все очень просто, я веб-дизайнер, а веб-анимация является частью моей работы. Поддержка анимации уже настолько повсеместна, что мы можем переключить свое внимание на более возвышенные вещи, как цели и значение анимации.

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

Долговечное очарование

«Делайте все собственными руками, даже когда используете компьютер.» — Хаяо Миядзаки

Студия Гибли Хайо Миядзаки, которая выпустила массу замечательных произведений, среди которых Унесенные призраками, Ходячий замок и Принцесса Мононоке, придерживается традиционных ручных методов анимации, слоистой анимации . В отличие от CGI или keyframe анимации с помощью CSS данный подход занимает гораздо больше времени.

Миядзаки также известен тем, что лично готовит лапшу рамен для своих работников-аниматоров поздними ночами, и все ради успеха.

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

Левая, гладкая анимация сделана при помощи keyframe трансформаций, в то время как в основе правой лежат три независимых кадра, один за другим. Пользователи Firefix могли заметить, что для анимации выше не применилось свойство transform-origin, все дело в баге .

Неудобный SMIL

Если сказать, что в интернете не существует технологии для создания веб слоистой анимации, это будет ложь. Громоздкое название Синхронизированный язык мультимедийных интеграций (SMIL), этот язык предназначен для создания анимации. У Jonathan Ingram есть замечательный урок по использованию SMIL для создания слоистой и зацикленной анимации на примере персонажей Mortal Kombat:

< animate

id = "frame2"

attributeName = "display"

values = "none;inline;none;none"

keyTimes = "0;0.33;0.66;1"

dur = "1s"

begin = "0s"

repeatCount = "indefinite" / >

Элемент animate используется для определения состояния анимации для родительского элемента.

Однако не обходится и без серьезных проблем. Несмотря на довольно старую классификацию, SMIL все же не поддерживается в IE. Более того, поддержка также не планируется ни в IE12, 15 или даже в 38. В то же самое время язык устаревает, а поддержка в Chrome падает. Paul Kinlan из Google рассказал, что в бета-версии Chrome 45 фактически закрыли глаза на предупреждения об устаревании SMIL.

Поддержка SMIL продолжает уменьшаться, и я нахожу немного странным использование XML разметки для создания анимации. Я привык, что моя анимация находится в отдельном файле стилей, и думаю ей там самое место. В конце концов, анимируя элемент, мы меняем только его визуальное положение, но не затрагиваем разметку. Это можно только в JavaScript.
К сожалению, в CSS нет явного или быстрого способа создания слоистой анимации, однако я опишу способ на основе редко используемых keyframe свойств CSS.

Начнем

@keyframe анимация работает с помощью свойства animation-timing-function, вы должны знать о некоторых временных функциях . К примеру, свойство ease-in уменьшает скорость анимации, когда та подходит к завершению.

Редко используемая функция steps() также представляет интерес для нас, так как она имитирует эффект подергивания, анимация будто бы состоит из отдельных слоев, проигрываемых один за другим. К примеру, steps(5) выполнит довольно плавную анимацию из пяти отдельных слоев.

Все значения функции steps() имитируют keyframe анимацию; нету какого-то магического переключения кадров. Но, если воспользоваться steps(1), то можно просто переключаться между кадрами без какой-либо анимации. Изменяя свойство opacity от 1 до 0, мы можем показывать и прятать анимируемый элемент за один шаг: вот он есть, а вот и нет. Это очень важный этап построения слоистой анимации, которую я собираюсь создать.

Элементы, как отдельные слои

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

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

Разметка

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

< g class = "animation-name" >

< path d = "" > < / path >

< path d = > < / path >

< path d = "" > < / path >

< / g >

Создание слоев

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

Разместите все фигуры одна над другой и подгоните размер документа под размер фигур. Чтобы сделать это выберите File->Document Properties а затем Resize page to drawing or selection. Проследите, чтобы не была выбрана какая-то отдельная фигура, иначе размер документа будет подобран под эту конкретную фигуру.

Затем выберите все фигуры и кликните Object->Group, создастся элемент группы . Затем, не снимая выделения с группы, откройте Edit &-> XML Editor и задайте группе класс.shapes.

Отлично, теперь сохраните SVG файл. Из списка выберите Optimized SVG и поставьте галочку напротив Enable viewboxing. Теперь наш SVG полностью готов к анимированию.

Замечания по оптимизации

Используя такие простые формы, как у нас, SVG данные сводятся к минимуму. В данном случае размер анимированного SVG (вместе с CSS, который мы еще напишем) будет всего 2.3 Кб. Проще говоря, чем проще фигура на каждом слое, тем больше слоев можно себе позволить. Для анимирования более сложных изображений, как каракули, которые мы будем использовать в данной статье, я рекомендую использовать инструмент от Jake Archibald SVGOMG .

Наложение слоев

Как я писал выше при помощи steps(1) можно переключать видимость элемента с помощью непрозрачности. Нельзя добиться такого же эффекта со свойством display, так как оно принимает только конкретные значения (нечего анимировать). Для начала установим все слои в контейнере в opacity:0.

Shapes > * { opacity: 0; animation-duration: 0.75s; animation-iteration-count: infinite; animation-timing-function: steps(1); }

Shapes > * {

opacity : 0 ;

animation - duration : 0.75s ;

animation - iteration - count : infinite ;

animation - timing - function : steps (1 ) ;

Как и при настройке пошаговых временных функций, я выбрал бесконечное число итераций, длительность анимации 0.75s. Так как каждый кадр появляется на одинаковое количество времени, а кадров у нас три, то каждый кадр должен появляться на 0.25s, или 4 кадра в секунду.

Итак, как и говорилось, каждый кадр появляется за другим? Каждому элементу необходимо задать длительность анимации 0.75s, а затем запустить все кадры одновременно, плавно показывая один поверх другого. При трех слоях каждый должен быть виден треть времени. Я использовал проценты (в @keyframe синтаксисе) и применил для каждого nth-child свою анимацию.

@keyframes shape-1 { 0% { opacity: 1; } 33.33333% { opacity: 0; } } .shapes > :nth-child(1) { animation-name: shapes-1; } @keyframes shapes-2 { 33.33333% { opacity: 1; } 66.66667% { opacity: 0; } } .shapes > :nth-child(2) { animation-name: shapes-2; } @keyframes shapes-3 { 66.66667% { opacity: 1; } 100% { opacity: 0; } } .shapes > :nth-child(3) { animation-name: shapes-3; }

@ keyframes shape - 1 {

0 % {

opacity : 1 ;

33.33333 % {

opacity : 0 ;

Shapes > : nth - child (1 ) {

animation - name : shapes - 1 ;

@ keyframes shapes - 2 {

33.33333 % {

opacity : 1 ;

66.66667 % {

opacity : 0 ;

Shapes > : nth - child (2 ) {

animation - name : shapes - 2 ;

@ keyframes shapes - 3 {

66.66667 % {

opacity : 1 ;

100 % {

opacity : 0 ;

Shapes > : nth - child (3 ) {

animation - name : shapes - 3 ;

Встраивание и подключение

Теперь, чтобы создать мою масштабируемую GIF анимацию, я, наконец, могу добавить в SVG файл стили. Так как у меня не стоит на компьютере таск раннер, я использовал онлайн версию autoprefixer для автоматического добавления вендорных префиксов.

< svg viewBox = "0 0 100 100" >

< g class = "animation-name" >

< path d = "" > < / path >

< path d = "" > < / path >

< path d = "" > < / path >

< / g >

< / svg >

Некоторые, но не все браузеры будут проигрывать анимацию, даже если подключить SVG через тег img. Более надежно использовать object.

< object type = "image/svg+xml" data = "path_to/shapes.svg" role = "img" aria - label = "shapes animation" >

< div role = "img" class = "shapes-fallback" aria - label = "shapes animation" > < / div >

< / object >

Заметьте, что WAI-ARIA роль со значением img и атрибут aria-label как для объекта (object), так и для элемента DIV используются для семантической точности. Я не стал делать фоллбэк для старых браузеров с помощью img, так как некоторые браузеры загружают этот тег в дополнении к SVG. Но вам, конечно, необходимо добавить статичное фоновое изображение через CSS с помощью свойства background-image для элемента.shapes-fallback.

Одно изображение, много анимаций

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

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

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

Переменная анимация

В моем примере shark.svg и виляющий хвост, и мигающие глаза используют чередующуюся, симметричную анимацию, где все слои проигрываются сначала вперед, потом назад, и так бесконечно. Каждый элемент слоистой анимации начинает двигаться одновременно, создавая эффект бесконечной анимации с помощью свойства animation-direction: alternate для каждого слоя:

Tail > * { animation-direction: alternate; }

Tail > * {

animation - direction : alternate ;

Данный подход экономит вес. Чтобы добиться такого же эффекта в GIF, необходимо добавить изображения дважды: сначала в обычном порядке, потом в обратном.

По-настоящему слоистая анимация

Я начал свою статью с заключения, что традиционная слоистая анимация трудно сравнима с современной keyframe анимацией. До появления слоистой анимации каждый кадр рисовался полностью – не только анимируемая часть изображения. Если на слоях рисовать только анимируемые части, статичные фоны можно использовать повторно. Кроме экономии времени такой подход также повышает плавность.

SVG это формат изображений на основе текста, данный формат делится на множество «поддеревьев» разметки. Это делает данный формат идеальным для объединения статичных и анимированных изображений.

Автоматизация с помощью Sass

Моя анимация становится все более изощренной, а создание отдельных классов анимаций для каждого слоя слегка утомительно. Для выполнения тяжелой работы я подключил Sass. С помощью директивы @for и некоторых вычислений мне удалось сгенерировать анимацию автоматически:

$cels: 6; $fraction: 100 / $cels; @for $i from 1 through $cels { $name: shapes; $start: ($fraction * $i) - $fraction; @keyframes #{$name}-#{$i} { #{$start * 1%} { opacity: 1; } #{($start + $fraction) * 1%} { opacity: 0; } } > :nth-child(#{$i}) { animation-name: #{$name}-#{$i}; } }