Как анимировать SVG иконки с помощью библиотеки segment?

Как анимировать SVG иконки с помощью библиотеки segment?

От автора: в этом уроке мы рассмотрим, как анимировать иконку svg иконку меню при помощи Dribbble шота от Tamas Kojo, в котором используются SVG и Segment – JavaScript библиотека для рисования и анимирования элемента SVG path.

скачать исходникидемо

Сегодня мы рады представить вам очень интересный эффект с иконкой меню. Идея возникла из Dribbble шота hamburger menu от Tamas Kojo. На первый взгляд это обычная иконка-гамбургер для меню мобильных устройств. Но при клике на нее, иконка превращается в крест, при этом процесс сопровождается довольно забавной анимацией. При клике на крестик, анимация прокручивается в обратном порядке, и иконка снова превращается в гамбургер. Давайте посмотрим:


Практика HTML5 и CSS3 с нуля до результата!

Получите бесплатный пошаговый видеокурс по основам адаптивной верстки с полного нуля на HTML5 и CSS3

При помощи SVG и библиотеки Segment мы воссоздадим этот эффект. Сперва, мы распланируем нашу анимацию, познакомимся с библиотекой, а затем нарисуем анимацию для иконки.

Планирование

Для воссоздания данного эффекта я не вижу ничего лучше, чем SVG. А JS библиотека Segment (альтернатива DrawSVGPlugin от GSAP) в этом нам поможет.

Необходимо создать три элемента path, которые будут описывать анимацию каждой прямой иконки гамбургера. С помощью Segment можно как угодно анимировать svg path элементы. Для прорисовки пути анимации каждой прямой можно воспользоваться любым редактором векторной графики (Adobe Illustrator или Inkscape); для достижения большей точности мы будем рисовать данные пути самостоятельно (связующие линии, кривые и дуги). Помните, что наша анимация «эластична», т.е. нужно учесть длину пути каждой прямой. Но прежде, давайте познакомимся с бибилиотекой Segment.

Знакомство с Segment

Данная библиотека – основной инструмент, который мы будем использовать, а точнее, небольшой JS класс (без зависимостей) для рисования и анимирования SVG путей. Пользоваться библиотекой достаточно просто:

<!-- добавьте segment скрипт(меньше 2kb) -->
<script src="/dist/segment.min.js"></script>

<!—задаем path -->
<svg>
 <path id="my-path" ...>
</svg>

<script>
 // инициализируем новый класс segment с path
 var myPath = document.getElementById("my-path"),
 segment = new Segment(myPath);

 // рисуем путь в любое время
 // Syntax: .draw(begin, end[, duration, options])
 segment.draw("25%", "75% - 10", 1);

 /* пример со всеми возможными вариантами */
 
 // задаем функцию смягчения (t параметр в промежутке [0, 1])
 function cubicIn(t) { 
 return t * t * t;
 }

 // задаем колбек функцию
 function done() {
 alert("Done!");
 }

 // рисуем путь
 segment.draw(0, "100%", 1, {delay: 1, easing: cubicIn, callback: done});
</script>

Чтобы более подробно разобраться в принципе работы, поиграйтесь с demo и ознакомьтесь с документацией на GitHub. Также можно прочесть данную статью. Важно отметить, что в библиотеке Segment нет своих функций смягчения (кроме линейной по умолчанию). Дабы восполнить недостачу, мы задействуем библиотеку d3-ease.

Прорисовка путей

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

Код ниже рисует картинку выше шаг за шагом:

<svg width="100px" height="100px">
 <path d="M 30 40 L 70 40 C 90 40 90 75 60 85 A 40 40 0 0 1 20 20 L 80 80"></path>
 <path d="M 30 50 L 70 50"></path>
 <path d="M 70 60 L 30 60 C 10 60 10 20 40 15 A 40 38 0 1 1 20 80 L 80 20"></path>
</svg>

Для достижения желаемого эффекта, необходимо добавить CSS стили и идентификаторы к элементам path. ID нам пригодится для получения доступа к path через скрипт. Далее будем использовать следующую HTML разметку:

Практика HTML5 и CSS3 с нуля до результата!

Получите бесплатный пошаговый видеокурс по основам адаптивной верстки с полного нуля на HTML5 и CSS3

Узнать подробнее
<!-- Wrapper -->
<div id="menu-icon-wrapper" class="menu-icon-wrapper">
 <!-- SVG с элементами path -->
 <svg width="100px" height="100px">
 <path id="pathA" d="M 30 40 L 70 40 C 90 40 90 75 60 85 A 40 40 0 0 1 20 20 L 80 80"/>
 <path id="pathB" d="M 30 50 L 70 50"/>
 <path id="pathC" d="M 70 60 L 30 60 C 10 60 10 20 40 15 A 40 38 0 1 1 20 80 L 80 20"/>
 </svg>
 <!-- триггер анимации -->
 <button id="menu-icon-trigger" class="menu-icon-trigger"></button>
</div>

И CSS стили:

// обертка задана с фиксированными шириной и высотой
// Заметьте, что свойство pointer-events установлено в 'none'. 
// нам не нужно, чтобы курсор изменялся на элементе анимации.
.menu-icon-wrapper{ 
 position: relative;
 display: inline-block;
 width: 34px;
 height: 34px;
 pointer-events: none;
 transition: 0.1s;
}

// выполняем трансформацию второго демо
.menu-icon-wrapper.scaled{
 transform: scale(0.5);
}

// задаем позицию SVG элемента
.menu-icon-wrapper svg{
 position: absolute;
 top: -33px;
 left: -33px;
}

// задаем стили для path
.menu-icon-wrapper svg path{
 stroke: #fff;
 stroke-width: 6px;
 stroke-linecap: round;
 fill: transparent;
}

// устанавливаем pointer-events на 'auto', 
// позволяя запускать анимацию только по одному событию
.menu-icon-wrapper .menu-icon-trigger{
 position: relative;
 width: 100%;
 height: 100%;
 cursor: pointer;
 pointer-events: auto;
 background: none;
 border: none;
 margin: 0;
 padding: 0;
}

Анимация

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

var pathA = document.getElementById('pathA'),
 pathC = document.getElementById('pathC'),
 segmentA = new Segment(pathA, 8, 32),
 segmentC = new Segment(pathC, 8, 32);

После этого можно приступить к анимации, сохраняя длину планки (end — begin = 24) в процессе анимирования. Проанализировав последовательность анимации, можно понять, что первая функция смягчения линейная, заканчивающаяся гибким поворотом. Мы будем использовать функции, в качестве параметра в которые передается сегмент. Для верхней и нижней планки гамбургера функция будет одна и та же, так как анимация одинаковая, только направлена в другую сторону.

// линейная секция с колбеком к следующей секции
function inAC(s) { s.draw('80% - 24', '80%', 0.3, {delay: 0.1, callback: function(){ inAC2(s) }}); }

// Гибкая секция, применяется функция elastic-out 
function inAC2(s) { s.draw('100% - 54.5', '100% - 30.5', 0.6, {easing: ease.ease('elastic-out', 1, 0.3)}); }

// запуск анимации
inAC(segmentA); // верхняя планка
inAC(segmentC); // нижняя планка
То же самое необходимо повторить и для средней планки:
// инициализация
var pathB = document.getElementById('pathB'),
 segmentB = new Segment(pathB, 8, 32);

// немного расширяем планку
function inB(s) { s.draw(8 - 6, 32 + 6, 0.1, {callback: function(){ inB2(s) }}); }

// обратно уменьшаем с уаругим эффектом 
function inB2(s) { s.draw(8 + 12, 32 - 12, 0.3, {easing: ease.ease('bounce-out', 1, 0.3)}); }

// запуск анимации
inB(segmentB);

Для обратного эффекта, превращения крестика в гамбургер:

function outAC(s) { s.draw('90% - 24', '90%', 0.1, {easing: ease.ease('elastic-in', 1, 0.3), callback: function(){ outAC2(s) }}); }
function outAC2(s) { s.draw('20% - 24', '20%', 0.3, {callback: function(){ outAC3(s) }}); }
function outAC3(s) { s.draw(8, 32, 0.7, {easing: ease.ease('elastic-out', 1, 0.3)}); }

function outB(s) { s.draw(8, 32, 0.7, {delay: 0.1, easing: ease.ease('elastic-out', 2, 0.4)}); }

// запуск анимации
outAC(segmentA);
outB(segmentB);
outAC(segmentC);

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

var trigger = document.getElementById('menu-icon-trigger'),
 toCloseIcon = true;

trigger.onclick = function() {
 if (toCloseIcon) {
 inAC(segmentA);
 inB(segmentB);
 inAC(segmentC);
 } else {
 outAC(segmentA);
 outB(segmentB);
 outAC(segmentC);
 }
 toCloseIcon = !toCloseIcon;
};

Анимация закончена, но есть небольшая проблема. В разных браузерах, она выглядит немного по-разному. Длина элементов path вычисляется в браузерах по-разному, а значит, есть и небольшое различие (существенное). Особенно это заметно в Firefox и Chrome.

Решение данной проблемы достаточно простое. Мы увеличим наш SVG, тем самым увеличив размер элементов path, а потом уменьшим svg под необходимый размер. В нашем случае мы изменили размер SVG в 10 раз, в итоге получили следующий код:

<svg width="1000px" height="1000px">
 <path id="pathA" d="M 300 400 L 700 400 C 900 400 900 750 600 850 A 400 400 0 0 1 200 200 L 800 800"></path>
 <path id="pathB" d="M 300 500 L 700 500"></path>
 <path id="pathC" d="M 700 600 L 300 600 C 100 600 100 200 400 150 A 400 380 0 1 1 200 800 L 800 200"></path>
</svg>

А затем уменьшили размер с помощью CSS:

.menu-icon-wrapper svg {
 transform: scale(0.1);
 transform-origin: 0 0;
}

Обратите внимание на то, что необходимо также увеличить значения float в JS (умножить на 10), а также изменить значение stroke-width в CSS. Данный метод поможет снизить до минимума различия в браузерах, но если вас не смущают небольшие данные мелочи, то можно придерживаться первоначального варианта.

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

Надеемся, данный урок был полезен для вас!

Проект на GitHub

Автор: Luis Manuel

Источник: http://tympanus.net/

Редакция: Команда webformyself.


Практика HTML5 и CSS3 с нуля до результата!

Получите бесплатный пошаговый видеокурс по основам адаптивной верстки с полного нуля на HTML5 и CSS3

Самые свежие новости IT и веб-разработки на нашем Telegram-канале

Фреймворк Bootstrap - верстаем адаптивно, просто, быстро!

Получите видеокурс по основам Bootstrap

Получить

Метки: ,

Похожие статьи:

Комментарии Вконтакте:

Комментарии Facebook:

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Можно использовать следующие HTML-теги и атрибуты: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Я не робот.

Spam Protection by WP-SpamFree