Создание слоистой анимации на SVG. SVG для мобильных

Мы давно обещали сделать ролик про анимацию SVG элементов на страницах, но все как-то не удавалось. Сегодня мы наконец-то рады вам представить первый ролик из серии, в котором расскажем про варианты анимации SVG: с помощью CSS, SMIL и JavaScript (на примере Snap.svg).

На самом деле у нас с этим роликом было как с Мистралями. Не сложились обстоятельства для записи. Ну вот теперь наконец-то сложились.

SVG анимации

Попробуем еще разок собрать все вместе со ссылками. Существуют три способа анимации SVG элементов на странице, два из которых применимы и для HTML элементов. Я, конечно же, говорю про CSS и JavaScript анимации. Но для SVG можно еще использовать SMIL (Synchronized Multimedia Integration Language) анимации.

SMIL анимации

Это очень крутая технология если нам нужно анимировать path-ы и при этом хранить это все в одном SVG файле. Да, CSS анимации тоже можно включать в файл, но с их помощью нельзя анимировать атрибут d у path-ов, поэтому SMIL оказывается намного более интересной технологией. Собственно JavaScript тоже можно включать прямо в SVG файлы, но поддержка браузеров немного разная, поэтому нужно обязательно думать что и как использовать.

SMIL поддерживается во всех браузерах с незапамятных времен (с ранних версий), кроме Internet Explorer, который не поддерживает эти анимации до сих пор.

CSS анимации

Здесь все предельно ясно, мы уже давно привыкли использовать CSS для небольших анимаций HTML элементов. Тоже самое можно делать и с SVG: большинство атрибутов можно анимировать и поддержка браузеров значительно лучше . Ну потому что хотя бы Internet Exporer 10 узнал про такое явление, как CSS анимации.

JavaScript анимации

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

В некоторые даже включены возможности анимации, например в Snap.svg. Я бы всем советовал именно эту библиотеку, хотя многие привыкли работать с Velocity.js, такой подход тоже имеет право на существование.

Одним из лучших способов презентации графики онлайн является масштабируемая векторная графика. Все благодаря тому, что 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) с черным фоном, а затем меняем их на красный.

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

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

Подготовка SVG для использования в вебе это очень простой процесс, не сложнее экспорта JPEG или PNG . Используйте любой привычный для вас графический редактор (Illustrator, Sketch, Inkscape [бесплатен], и тому подобное [или даже Photoshop, если вы используете слои с формами]) с тем размером изображения, который вы планируете использовать. Обычно я работаю в Иллюстраторе, поэтому я объясню некоторые способы подготовки файлов в этой программе, но вообще они применимы и для любой другой программы. Вам, возможно, стоит перевести текст в кривые, поскольку шрифт, скорее всего, будет неправильно отображаться, если, конечно, вы не планируете стилизовать их с помощью веб-шрифта, используемого на странице (что возможно!). Не стоит также превращать все объекты в единые формы, особенно если у вас есть обводка, которой необходимо будет управлять на странице, тем более преобразование объектов зачастую не уменьшает размер файла. Любые имена, присвоенные группам или слоям, будут добавлены к SVG как ID элемента. Это довольно удобно для стилизации, но немного увеличит общий размер файла.

Перед тем как сделать экспорт, необходимо проверить, все ли изображения находятся в целочисленной пиксельной сетке (то есть, например не 23.3px × 86.8px ). В противном случае скорее всего изображению не будет хватать чёткости и часть изображения обрежется. В Иллюстраторе это можно сделать следующим образом: Object > Artboards > Fit to Artwork Bounds . Затем жмём save as и выбираем SVG , и оставляем настройки по умолчанию. Здесь можно сделать небольшую оптимизацию, но на самом деле не стоит, так как далее мы будем применять разные улучшающие приёмы, поэтому сейчас мы не будем тратить впустую время на эти настройки.

Приёмы для уменьшения размеров файла.

(Смотрите по оптимизации)

Чтобы добиться наименьшего размера SVG , логично будет удалить из него всё лишнее. Наиболее известная и полезная программа (по крайней мере я так думаю) для обработки SVG это SVGO . Она удаляет весь не нужный код. Но! Будьте внимательны используя эту программу, если планируете управлять SVG при помощи CSS / JS , так как она может слишком сильно почистить код, что затруднит дальнейшие изменения. Удобство SVGO ещё и в том, что её можно включить в процесс автоматической сборки проекта, но можно также использовать GUI если хочется.

Разбираясь подробнее с правильным удалением всего ненужного, мы можем сделать ещё кое-что в графическом редакторе. Сперва нужно убедиться, что используется настолько мало контуров/форм, насколько это возможно, так же как и точек на этих контурах. Можно объединять и упрощать всё, что поддаётся упрощению, и удалить все ненужные точки. В Иллюстраторе есть плагин VectorScribe с инструментом Smart Remove Brush Tool , который поможет удалить точки и при этом оставить общую форму той же.

Предварительная оптимизация

Smart Remove Brush Tool удалил точки

Дальше будем увеличивать изображение. В Иллюстраторе удобно включить просмотр с пиксельной сеткой View > Pixel Preview и проверить, как располагаются контуры. Чтобы разместить контуры по сетке, потребуется немного времени, но эти усилия окупятся и позволят добиться более чёткого рендеринга (лучше обратить на это внимание заранее).

Точки вне сетки

Выравнивание по сетке

Если есть два и более объекта для выравнивания, то стоит удалить все ненужные перекрытия. Иногда даже если контуры тщательно выровнены, может быть видна тонкая белая линия. Чтобы предотвратить такое, можно немного наложить объекты друг на друга в местах перекрытия. Важно: в SVG z-index имеет определённый порядок, который зависит от объекта, находящегося снизу, поэтому стоит поместить верхний объект в нижнюю часть файла в коде.

И, наконец, последнее, но немаловажное, то, о чём обычно забывают - это активировать gzip сжатие SVG на вашем сайте в.htaccess файле.

AddType image/svg+xml svg svgz AddOutputFilterByType DEFLATE "image/svg+xml" \ "text/css" \ "text/html" \ "text/javascript" ... etc

В качестве примера того, насколько эффективна эта техника, я воспользуюсь оригинальным логотипом Breaking Borders и оптимизирую его таким образом: увеличиваю размер до того, каким он должен быть; приведу в порядок контуры; удалю максимально возможное количество точек; передвину точки на целочисленные пиксели; сдвину все области перекрытий и отправлю это всё в SVGO .

Оригинал: 1,413b После оптимизации: 409b

В итоге размер файла стал меньше на ~71% (и на ~83% при сжатии)

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

  • 3216

  • 92
  • Tutorial

Думаю многие видели обзоры игровых консолей нового поколения от Polygon (Vox Media) . Это те, где консоли отрисовывались в стиле blueprint"ов:

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

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 и реализованной в ней анимацией на основе длительности.

Вот собственно рабочий код, использовавшийся для анимации консоли из начала статьи.

Queue() .defer(d3.xml, "PS4.svg", "image/svg+xml") .await(ready); function ready(error, xml) { //Adding our svg file to HTML document var importedNode = document.importNode(xml.documentElement, true); d3.select("#pathAnimation").node().appendChild(importedNode); var svg = d3.select("svg"), svgWidth = svg.attr("width"), svgHeight = svg.attr("height"); var paths = svg.selectAll("path") .call(transition); function transition(path) { path.transition() .duration(5000) .attrTween("stroke-dasharray", tweenDash) .each("end", function() { d3.select(this).call(transition); }); // infinite loop } function tweenDash() { var l = this.getTotalLength(), i = d3.interpolateString("0," + l, l + "," + l); // interpolation of stroke-dasharray attr return function(t) { return i(t); }; } }


Начнём просто с движения вдоль линии, пока без вращения.

Queue() .defer(d3.xml, "wiggle.svg", "image/svg+xml") .await(ready); function ready(error, xml) { //Adding our svg file to HTML document var importedNode = document.importNode(xml.documentElement, true); d3.select("#pathAnimation").node().appendChild(importedNode); var svg = d3.select("svg"); var path = svg.select("path#wiggle"), startPoint = pathStartPoint(path); var marker = svg.append("circle"); marker.attr("r", 7) .attr("transform", "translate(" + startPoint + ")"); transition(); //Get path start point for placing marker function pathStartPoint(path) { var d = path.attr("d"), dsplitted = d.split(" "); return dsplitted.split(","); } function transition() { marker.transition() .duration(7500) .attrTween("transform", translateAlong(path.node())) .each("end", transition);// infinite loop } function translateAlong(path) { var l = path.getTotalLength(); return function(i) { return function(t) { var p = path.getPointAtLength(t * l); return "translate(" + p.x + "," + p.y + ")";//Move marker } } } }
Здесь pathStartPoint(path) вытаскивает координаты начала линии из атрибута элемента 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) , определяющая интерполятор будет выглядеть следующим образом:

Function translateAlong(path) { var l = path.getTotalLength(); var t0 = 0; return function(i) { return function(t) { var p0 = path.getPointAtLength(t0 * l);//previous point var p = path.getPointAtLength(t * l);////current point var angle = Math.atan2(p.y - p0.y, p.x - p0.x) * 180 / Math.PI;//angle for tangent t0 = t; //Shifting center to center of rocket var centerX = p.x - 24, centerY = p.y - 12; return "translate(" + centerX + "," + centerY + ")rotate(" + angle + " 24" + " 12" +")"; } } }
Реализацию можно посмотреть здесь.