Создаем анимацию с помощью Paper.js

Веб только-только начинает использовать анимацию. Годами рулили анимированные GIF и Flash. Текст двигался и мерцал, но это было убого. Анимации были внутри блоков, как видео на YouTube. HTML5 canvas изменил всё в веб анимации.

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

Анимации становятся еще мощнее и требуют меньше кода, когда вы комбинируете тэг canvas с высокоуровневыми библиотеками, например с Paper.js. Эта статья познакомит вас с HTML5 анимацией и проведет через все шаги создания анимации семян одуванчика, разлетающихся по ветру.

Элементарные действия описать легко, а сложные — сложно

Компьютерам нравится чистота. Они создают электронные таблицы, показывают статистику и рисуют многомерные кривые; они всегда следуют правилам.

В реальности даже самые простые вещи усложнены. Листья падают с деревьев, вода разбрызгивается — все эти мелкие взаимодействия вокруг нас выглядят простыми, потому что мы к ним привыкли; но даже порывы ветра на самом деле сложны и непредсказуемы.

В этой статье мы будем анимировать семена одуванчика, летящие на ветру.

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

Создаем анимацию с помощью Paper.js

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

Создаем анимацию с помощью Paper.js

Paper.js

Рисовать простые формы с тэгом canvas, без специальных библиотек для рисования, легко. Создайте ваш canvas:

 <canvas id="canvas" width="300" height="300"></canvas>

Затем добавьте маленький JavaScript.

// Get our canvas
var canvas = $('#canvas')[0].getContext("2d");

// Draw a circle
canvas.beginPath();
canvas.arc(100, 100, 15, 0, Math.PI*2, true); 

// Close the path
canvas.closePath();

// Fill it in
canvas.fill();

Создаем анимацию с помощью Paper.js

Cheat sheets for canvas помогут вам с основами, но когда вы начнете рисовать что-то серьезное, то понадобится высокоуровневая библиотека, такая как Paper.js.

Paper.js — это библиотека JavaScript для рисования и анимации. В основном она базируется на Scriptographer, скриптовом языке для Adobe Illustrator. Вы можете программировать на JavaScript с помощью Paper.js, но большую часть времени вы будете работать с разновидностью JavaScript, называемой PaperScript.

Paper.js называет себя «The Swiss Army Knife of Vector Graphics Scripting», где самое важное слово - «vector».

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

Векторная графика похожа на детские картинки «соедини точки»: набор линий и форм, из которых получаются инструкции, как нарисовать изображение любого размера. С помощью векторной графики вы можете  сделать изображение буквы Z ооочень большим и оно все равно будет выглядеть четким. Если вы переведете ее в растровую графику и увеличите, буква будет размытой.

Создаем анимацию с помощью Paper.js

Библиотеки векторной графики идеально подходят для анимации, потому что они очень просто реализуют изменение размеров, поворот и движение объектов. Кроме того, они гораздо быстрее, потому что у программы есть инструкции для рисования каждого объекта и нет необходимости разбираться в этом.

Страница Paper.js examples page демонстрирует суперские вещи, которые вы можете сделать с помощью векторной графики.

Одуванчик — это подностью работающий пример, вы можете посмотреть его здесь. Также вы можете изменить код, нажав кнопку «Edit», сразу увидеть свои поправки и скопировать код на свой сайт. В этой статье мы по очереди объясним каждый кусок кода, но учтите, что чтобы запустить его самостоятельно, понадобится вернуться на страницу с примером и скопировать оттуда код в свою среду.

Рисуем наш одуванчик

Для начала импортируем наши JavaScript и PaperScript файлы.

<script src="paper.js" type="text/javascript" charset="utf-8">
</script>
<script type="text/paperscript" canvas="canvas" src="dandelion.pjs"
id="script"></script>

Код PaperScript для проигрывания анимации определен как text/paperscript. Теперь мы готовы рисовать.

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

Пути — это основные «строительные блоки» для анимации. Они отрисовывают линии, кривые и многоугольники. Также вы можете определить для них заливку, чтобы сделать сложные формы. Наш path будет выглядеть так:

var path = new Path();
path.strokeColor = '#567e37';
path.strokeWidth = 5;

var firstPoint = new Point(0, 550);
path.add(firstPoint);

var throughPoint = new Point(75, 400);
var toPoint = new Point(100, 250);
path.arcTo(throughPoint, toPoint);

Наш путь — это дуга, поэтому ему нужны три точки: начальная, конечная и промежуточная. Трех точек достаточно, чтобы определить любую дугу. Функция arcTo рисует линию между ними. Путь также поддерживает информацию о стилях, такую как цвет и ширина штриха; значения #567e37 и 5 сделают нашу дугу зеленой и толстой. Paper.js поддерживает такие же коды цветов, как в CSS.

Мы можем добавить еще несколько элементов, чтобы все это улучшить:

path.fullySelected = true;

var circle = new Path.Circle(throughPoint, 5);
circle.fillColor = '#CC0000';

Описанный путь отобразит линии, чтобы показать нам дугу; красный круг — это промежуточная точка.

Создаем анимацию с помощью Paper.js

Стебель заканчивается кругом, чтобы обозначить цветок, к нему мы будем прикреплять все семена. Круги намного легче делать в Paper.js, чем в простом canvas.

var bulb = new Path.Circle(toPoint, 10);
bulb.fillColor = '#567e37';

Одна строка рисует круг, еще одна делает его зеленым, и теперь мы готовы добавить наши семена.

Рисуем семена

Каждое семечко состоит из луковицы, стебля и маленьких тонких частей на вершине.

Создаем анимацию с помощью Paper.js

Оно начинается с маленького овала для луковицы и дуги для стебля. Овал — это прямоугольник со скругленными углами.

var size = new Size(4, 10);
var rectangle = new Rectangle(p, size);
var bottom = new Path.Oval(rectangle);
bottom.fillColor = '#d0aa7b';

Стебель — это еще одна дуга, но значительно тоньше, чем стебель цветка:

var stem = new Path();
stem.strokeColor = '#567e37';
stem.strokeWidth = 1;
stem.add(new Point(p.x + 2, p.y));

var throughPoint = new Point(p.x + 4, p.y - height / 2);
var toPoint = new Point(p.x + 3, p.y - height);
stem.arcTo(throughPoint, toPoint);

Пучки — это много дуг с кругами на конце каждой линии. Каждое семя имеет случайное число пучков, которые начинаются наверху дуги стебля и изгибаются в разных направлениях. Случайность заставляет их выглядеть немного сложнее и, следовательно, более естественными. У каждого семени будет случайное число пучков, от 4 до 10.

for (var i = 0; i < random(4, 10); i++) {
    path = new Path();
    path.strokeColor = '#fff3c9';
    path.strokeWidth = 1;

    var p1 = new Point(p.x, p.y);
    path.add(new Point(p1.x + 2, p1.y + 2));

    // Each flutter extends a random amount up in the air
    var y = random(1, 5);

    // We draw every other stem on the right or the left so they're
    // spaced out in the seed.
    if (i % 2 == 0) {
        throughPoint = new Point(p1.x + random(1, 3), p1.y - y);
        toPoint = new Point(p1.x + random(5, 35), p1.y - 20 - y);
    } else {
        throughPoint = new Point(p1.x - random(1, 3), p1.y - y);
        toPoint = new Point(p1.x - random(5, 35), p1.y - 20 - y);
    }

    path.arcTo(throughPoint, toPoint);

    // Now we put the circle at the tip of the flutter.
    circle = new Path.Circle(toPoint, 2);
    circle.fillColor = '#fff3c9';
}

Теперь, когда мы нарисовали семя, нам нужно как-то управлять им; позднее нам понадобится передвигать его и поворачивать. Семя состоит из многих частей, и мы не хотим управлять каждой их них по отдельности. В Paper.js есть специальный объект group. Группы объединяют набор объектов так, что мы можем манипулировать ими всеми сразу.

var group = new Group();
group.addChild(bottom);
group.addChild(stem);

this.group = group;

На последнем шаге мы объединим семя в многоразовый объект Seed. Мы добавим весь написанный код в новую функцию с именем Seed и добавим возможность задавать исходные переменные. В этом примере вызывается функция create, но вы можете назвать ее по-другому.

function Seed() {

    this.create = function (/*Point*/ p, /*boolean*/ shortStem) {
    …

Функция create рисует семя в указанной точке, а параметр shortSterm указывает, короткий ли стебель. Мы рассмотрим семена с короткими стеблями позже.

Такие типы функций не работают как конструкторы в JavaScript, но поддерживаются в PaperScript.

var seed = new Seed()
seed.create(new Point(100, 100), false);

Наши семена будут выглядеть так, когда мы нарисуем их:

Создаем анимацию с помощью Paper.js

Объект Seed отрисовывает наши случайные семена одуванчика. Теперь мы можем добавить их к цветку.

Добавим немного хаоса

Семена будут выглядеть лучше, когда мы распределим их вокруг цветка в виде ореола. Цветок — это круг, а круг — это путь, значит, мы можем получить каждую точку этого пути.

var bulb = new Path.Circle(toPoint, 10); bulb.fillColor = '#567e37';

var angle = 360 / bulb.length;
var seeds = [];

for (var i = 0; i < bulb.length; i++) {
    var seed = new Seed()
    seed.create(bulb.getPointAt(i));

    // Rotate each seed so that it points out from the bulb
    seed.rotate(i * angle);
    seeds.push(seed);
}

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

for (var i = 0; i < 18; i++) {
    var seed = new Seed()
    var point = new Point(toPoint.x + random(-3, 3),
                          toPoint.y + random(-3, 3));
    seed.create(new Point(toPoint), true);
    seed.rotate(random(0, 360));
    seeds.push(seed);
}

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

Анимируем семена

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

Воспроизвести поведение реального ветра очень сложно, поэтому мы будем «раздувать» семена по случайно выглядящим путям. Каждому семени назначим произвольную точку на правом краю экрана в качестве конечного пункта:

this.dest = new  Point(1800, random(-300, 1100));

Функция rotateMove двигает каждое семя к его точке назначения и вращает его. Мы можем работать с нашим объектом Seed как с группой и перемещать его одной функцией.

this.rotateMove = function(/*int*/ angle) {
    if (this.group.position.x < 850 && this.group.position.y < 650) {
        var vector = this.dest - this.group.position;
        this.group.position += vector / 150;

        this.angle += angle;
        this.group.rotate(angle);
    } else {
        this.isOffScreen = true
    }
}

Эта функция будет перемещать семя, пока оно не покинет экран. Вызов rotateMove в каждом кадре анимации приведет к тому, что семя будет лететь через весь экран.

Paper.js реализует для нас простой способ делать анимацию с помощью функции onFrame; когда мы определим onFrame, Paper.js будет вызывать ее для каждого кадра в анимации. Мы будем перебирать все семена покадрово и перемещать их через экран.

function onFrame(event) {
    for (var i = 0; i < seedCount; i++) {
        if (!seeds[i].isOffscreen()) {
            seeds[i].rotateMove(random(2, 4));
        }
    }
}

Семена скользят и вращаются чуть ближе к точке назначения в каждом кадре анимации. Стартуют все в одной точке, а цель у всех разная, поэтому они будут мило разлетаться в пространстве.

Создаем анимацию с помощью Paper.js

Мы не хотим, чтобы все семена разлетелись одновременно, поэтому используем таймер.

function start() {
    var id = setInterval(function() {
        seedCount++;
        if (seedCount === seeds.length) {
            clearInterval(id);
        }
    }, 1000);
}

Таймер ждет одну секунду, прежде чем «отпустить» следующее семя, создавая чувство легкости нашего одуванчика.

Зеленая трава и голубое небо — это фоновое изображение, которое просто добавлено в canvas. И вот у нас получился одуванчик с разлетающимися на ветру семенами.

Создаем анимацию с помощью Paper.js

Смотрите рабочий пример здесь. Вы можете редактировать и запускать исходный код как часть анимации или скачать его со страницы на GitHub.

Paper.js в реальном мире

На Paper.js есть впечатляющие примеры и у него приятный стиль программирования, но вы должны знать о некоторых подводных камнях прежде, чем начнете использовать его на своем сайте.

Не работает в старых браузерах

Все рисование на Paper.js делается с помощью тэга canvas, и необходима поддержка HTML5. Это значит, что вам необходимы браузеры Internet Explorer 9+, Firefox 4+, Safari 5+ или Chrome. Если ваш сайт должен поддерживать устаревшие браузеры, то вы не сможете использовать canvas.

Нет способа обойти это требование, и если вам необходимы старые браузеры, то вам не повезло. Как говорит сайт Paper.js, “Let’s go forward!.”

Производительность может быть низкой

Paper.js может очень замедлить браузер, даже если есть поддержка HTML5. Pixar рендерит «Buzz and Woody» на гигантских серверных фермах, а у вас есть только компьютер вашего пользователя.

Не только ноутбуки медленнее серверных кластеров, но еще и браузеры усложняют дело, отрисовывая canvas с помощью CPU вместо GPU. Игры типа Halo и Rage используют графический процессор вашей видеокарты, чтобы рендерить ракетные установки и мутантов. CPU менее эффективен для графики, так что один компьютер может поддерживать плавную отрисовку сложных видеоигр, но семена одуванчика может отображать медленно и прерывисто.

Убедитесь, что протестировали анимацию на самом медленном железе, и следите за использованием CPU. Используйте группы, чтобы минимизировать вычисления, и будьте очень осторожны с действиями в каждом вызове onFrame.

Мобильные устройства медленнее

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

События на объектном уровне не поддерживаются

Другие графические библиотеки, такие как SVG (обсудим ниже), поддерживают события мыши и клавиатуры на объектном уровне. Эти события позволяют легко реагировать на щелчок по многоугольнику или пути, наведение или прикосновение.

Тэг canvas не поддерживает события на объектном уровне. В Paper.js есть базовая функциональность для проверки нажатия, но на очень низком уровне. Вы можете прослушивать события мыши и клавиатуры на всем холсте, но вам нужно обрабатывать эти события для отдельных элементов управления.

Что насчет SVG?

Спецификация SVG (Scalable Vector Graphics) была опубликована более 10 лет назад, но эта технология выступила на первый план только с помощью библиотек типа Raphaël.js, которые упрощают генерацию изображений SVG в JavaScript. Язык SVG мощный, хорошо работает с меньшими изображениями и поддерживается, начиная с Internet Explorer 7, с конвертацией в VML (Vector Markup Language). SVG — лучший выбор, если вы хотите поддерживать старые браузеры.

Реальная проблема SVG в скорости, поддержке в будущем и мобильных устройствах. Каждый разработчик браузеров активно работает над ускорение работы canvas. Safari 5 уже предоставляет аппаратное ускорение для canvas, а остальные работают над этим. Также SVG не поддерживается в устройствах на Android.

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

Другие библиотеки для работы с  canvas

Paper.js не единственный вариант для canvasProcessing.js от создателей jQuery портирует язык программирования Processing но JavaScript. Эта библиотека поддерживает анимацию, и у нее много примеров.

Движок three.js поддерживает canvas и библиотеку WebGL, он сосредоточен больше на 3-D рисовании. Google Dart также будет поддерживать canvas со встроенными объектами для рендеринга.

Paper.js — зрелая библиотека с очень отзывчивым сообществом в Paper.js Google Group и многими впечатляющими и хорошо документированными примерами. Посмотрите, какие удивительные вещи делают с помощью него.

Больше примеров на Paper.js

Наш одуванчик — это только начало. Вот еще несколько впечатляющих анимаций, написанных на Paper.js.

  • Примеры, у Paper.js есть страница, полная невероятных примеров. Voronoi - самый лучший. Обязательно нажмите пробел и посмотрите на пути. Еще больше примеров на GitHub.
  • Nardove, рыбки Рикардо Санчеза (Ricardo Sánchez) сделаны с помощью Paper.js и Processing.js. Подождите минуту, рыбки застенчивы.
  • Node Garden in Paper.js,” Andrew Berg
  • The HBO Recycling Program” Инфографика, созданная с помощью Paper.js, показывает, как часто HBO использует в разных сериалах одних и тех же актеров.
  • 20 Multi-Touch Gestures You Should Learn Today,” Zack Grossbart создал интерактивный урок с помощью Paper.js.

А где ваши креативы на Paper.js?

Автор оригинала на английском — Зак Гроссбарт

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

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

*

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