- PVSM.RU - https://www.pvsm.ru -
На Хабре много статей. Но не каждая показывает, как размышлял автор, его грабли и действия.
Здесь я хочу вам рассказать, как я делал пасхалку для логотипа веб-студии в которой я работал.
Как то раз увидев завораживающую анимацию [1] от создателя библиотеки mo-js [2] для svg-эфектов, я загорелся и решенил сделать что-то подобное. Как раз мне на глаза попалась обновленная главная страничка нашей студии, недолго думая я собрался сделать анимацию для логотипа.
И раз эта статья рассказывает, как все это происходило, то к моему сожалению я не стану пересказывать весь мануал [3] по данной библиотеки. Его вам придется прочитать самим, если конечно захотите сделать что-то подобное.
Ну а чтобы сразу вникнуть в статью:
→ Ссылка на демо просмотр только от 1204x400, кликнуть на колокольчик [4]
→ Ссылка на GitHub [5]
Изначально я хотел разбивать логотип на мелкие кусочки, сжимать их в 1 точку, и только потом как пазл собирать в единое целое со всевозможными эффектами (думаю это было бы красиво). Но быстро понял, что делаю очень быструю анимацию и естественно она будет без звука. Когда логотип создателя библиотеки, как я написал, был «Завораживающим».
Свое второе вдохновение я нашел в одной навязчивой мелодии (Clannad песенка булочек [6]), думаю многие щас вздохнули в меланхоличном припадке. Да она просто умиляющая. И раз это колыбельная, то и тематика ей должна быть подстать!
Сюжет выдумывать особо и не пришлось. Колыбельная — «ночь, звезды, луна», замечательные ассоциации, большие варианты развития сюжета моей пасхалки.
Первым делом я нашел минус этой песенки и нарезал ее до 30 секунд, это максимум времени, сколько может выдержать любой гость, не закрыв страницы (думаю на большее меня бы и самого не хватило). Далее сделал метки эффектов, наиболее подходящим инструментом я выбрал Adobe Audition CC 2017 (честно говоря другого инструмента я и не искал, просто он мне попался на глаза первым).
Выглядело это так:
Библиотека предоставляет вложенные временные шкалы объекта TimeLine(), я бы мог разделить все на отдельные блоки, и начинать их анимацию по отдельности. Но т.к. у меня была привязка к мелодии, я счел необходимым сделать все на 1 единой временной шкале, дабы не запутать себя самого с таймингом. Просто сделал большие блоки массивов с временем начала в виде предоставляемого библиотекой параметра задержки (delay).
С точки зрения обычного пользователя, сюжет анимации всегда довольно простой. Падают радужные лучи, вырастают буквы, появляется рельеф, звезды и выходит луна, финиш, еще можно что-то там повозить. Но редко кто описывает, как он это делал, сколько вложил сил, терпения и слез своей музы.
Структуризация кода всегда помогает мыслить в рамках отдельных модулей и у меня получилось 5 объектов для манипуляций над элементами анимации.
Анимация падения радуги мне далась довольно легко, я банально скопировал ее с примера в тутореал. Сделал массив с координатами и описал это в 1 методе
rainbow(200, 500, 'A', 'str1')
где параметры — это продолжительность, время задержки (в моем случае начала) анимации и последние 2 описывают координату.
Эффект падения получился невзрачный:
Изменили на улучшенный:
Описывает анимацию букв. Он стал первым по сложности для меня объектом. Концепция анимации заключалась в росте, будто растения. С буквами пришлось изрядно повозиться, думаю не каждый умеет работать в Illustrator (я в том числе). И как человек получивший в этом опыт, советую:
Потратил 60% общего времени только на синхронизацию, сверку координат, отрисовку отдельных линий (которые нельзя сымитировать стандартными фигурами). Мне приходилось по 20 раз менять 1 параметр, ради достижения хорошего эффекта. Но мой внутренний перфекционист пошел на компромисс со временем и сдался.
Код же прост для обзора:
...that.plant_D(800, 10111),
...that.plant_A(800, 10200),
...that.plant_R(800, 10300),
...that.plant_N(800, 10400),
...that.plant_E(800, 10500),
...that.plant_O(800, 10600),
...that.plant_S(800, 12500),
...that.plant_T(800, 13100),
...that.plant_U(800, 13400),
...that.plant_D2(800, 13700),
...that.plant_I(800, 14000),
...that.plant_O2(800, 14300)
Вторым с чем я столкнулся — это с собственной невежественностью в чтении мануалов, мы все в той или иной степени этим страдаем. Банально упустил пункт о том, что собственные заготовки svg должны быть в разрешении 100x100 и первая буква «D» пошла наперекосяк. Ну и конечно, в таких случаях мы всегда делаем костыль, что и случилось. Просто поменял ей размер, после инициализации (а раз я использовал объект Burst, то и менять мне надо сразу всех потомков).
for (let el of equal.el.children) {
el.style['height'] = '180px';
}
В дальнейшем я задал вопрос на GitHub, на что меня ткнули в пунктик мануала)
Добавление собственной svg происход след. образом:
class elipceR2 extends mojs.CustomShape {
getShape () { return '<path d="M0,120.5h13.9c39.6,0,59.6-30.6,59.1-61C73,29.8,52.8-0.2,13.3,0L0.1,0"/>'; }
getLength () { return 200; } // optional
}
добавить и использовать (простота во всем):
mojs.addShape( 'elipceR2', elipceR2');
new mojs.Shape({ shape: 'elipceR2'});
Либо использовать дефолтные svg-фигуры.
Описывает горизонт, горы, выход луны. С луной возился долго, надо было соблюдать стилистику и луна с детальным рельефом тут не подходила:
Но, я удачно нагуглил более лучший вариант:
немного поправить напильником и получаем замечательную луну, хорошо подходящую к нашей стилистике.
Для приличия код:
that.moon(5000, 20000),
that.mountains(1500, 18500),
that.horizonLine(1600, 18500),
Второй по сложности объект. Стал основными источником синхронизации эффектов с музыкальной нарезкой «Семейства булочек».
Я сделал несколько массивов звезд и вывел их в заданный момент, попутно закинув их в контекст объекта для дальнейших манипуляций c цветом, размером и их координатами.
Где, параметры это время анимации, начало, и кол-во звезд.
that.curentStars = [
...that.star(200, 17050, 5),
...that.star(200, 17300, 15),
...that.star(200, 17600, 25),
...that.star(200, 17900, 30),
...that.star(200, 18200, 35),
];
Как-то размыть svg средствами библиотеки мне не удалось, пришлось их просто увеличивать. Как всегда, длительность анимации, ее начало, массив и кол-во звезд, которые мы берем рандомно,
that.shineStars(10, 21200, that.curentStars, 3);
that.shineStars(10, 21600, that.curentStars, 3);
that.shineStars(10, 21900, that.curentStars, 3);
that.shineStars(10, 22100, that.curentStars, 4);
that.shineStars(10, 22400, that.curentStars, 4);
that.shineStars(10, 22700, that.curentStars, 4);
that.shineStars(10, 23300, that.curentStars, 10);
that.shineStars(10, 23900, that.curentStars, 15);
that.shineStars(10, 24500, that.curentStars, 12);
that.shineStars(10, 25150, that.curentStars, 9);
that.shineStars(10, 25700, that.curentStars, 6);
that.shineStars(10, 26300, that.curentStars, 7);
that.shineStars(10, 26600, that.curentStars, 4);
that.shineStars(10, 27200, that.curentStars, 8);
that.shineStars(10, 28170, that.curentStars, 3);
попутно закидывая в свойство для падения this.curRimShineStar.
Оказалось, что если выбирать звезды рандомно, то бывают моменты, когда звезда имеет очень маленькое расстояние к координате к которой она должна была начать движение. И как следствие я просто видел падающую точку. Отфильтровав массив по координатам на правую зону, я добился более продолжительной анимации и показу хвоста за звездой.
that.shootingStar(500, 29600, {y: 52, x: PARAMS.COORDINATES_X.str1.D});
that.shootingStar(500, 29800, {y: 52, x: PARAMS.COORDINATES_X.str1.A});
that.shootingStar(500, 30100, {y: 52, x: PARAMS.COORDINATES_X.str1.R[0]});
that.shootingStar(500, 30400, {y: 52, x: PARAMS.COORDINATES_X.str1.N[0]});
that.shootingStar(500, 30700, {y: 52, x: PARAMS.COORDINATES_X.str1.N[1]});
that.shootingStar(500, 31070, {y: 52, x: PARAMS.COORDINATES_X.str1.E});
that.shootingStar(500, 31370, {y: 52, x: PARAMS.COORDINATES_X.str1.O});
Очень огорчило отсутствие некоторых подробностей по местоположению параметров в объектах, но все решилось банальным выводом его в консоль и чтением исходников (долго, но всегда гарантированный результат). Мне потребовалось узнать, когда объект завершит свою анимацию после всех манипуляций с ним и я не сразу понял что свойство Object.timeline._props.time его показывает, изначально я искал его в Object._o
Где то я конечно схалтурил в коде, за что трудно себя простить. Но в целом анимация удалась замечательной.
Чтобы гость мог покрутить ползунок и самому посмотреть, как это происходило, пришлось добавить и таймер, который завершал анимацию через пару секунд простоя. Тут моя фантазия уже закончилась и я просто добавил 3 уменьшающихся круга. По истечению которых, при помощи той же JQuery.animate() мы растворяем буквы в логотипе и удаляем все теги, что добавила библиотека.
К сожалению библиотека не может делать очень долгих анимаций, это можно заметить, есть дернуть ползунок очень быстро в сторону, вы увидите как все пойдет кусками, где то будут элементы, где то нет. Решить это можно думаю лишь принудительным манипулированием скорости ползунка.
Автор: Frimko
Источник [7]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/javascript/246605
Ссылки в тексте:
[1] завораживающую анимацию: http://codepen.io/sol0mka/pen/4f1780feb76ffca8357c8a70513d02bb
[2] mo-js: http://mojs.io/
[3] мануал: https://github.com/legomushroom/mojs/blob/master/api/readme.md
[4] Ссылка на демо просмотр только от 1204x400, кликнуть на колокольчик: https://frimko.github.io/logo_animate_darneo/index.html
[5] Ссылка на GitHub: https://github.com/Frimko/logo_animate_darneo
[6] Clannad песенка булочек: https://www.youtube.com/watch?v=b61SlFOQFss
[7] Источник: https://habrahabr.ru/post/322676/?utm_source=habrahabr&utm_medium=rss&utm_campaign=sandbox
Нажмите здесь для печати.