- PVSM.RU - https://www.pvsm.ru -
Набрёл на статью со сравнением трёх JS библиотек для рисования в WEB Paper.js, Processing.js и Raphael.js. Думаю она будет интересна не только мне.
Прежде чем начать рисовать что-либо в браузере, спросите себя о следующих трёх вещах:
Paper.js, Processing.js и Raphaël на данный момент являются лидирующими библиотеками для рисования в Web. Также есть пара новичков, чья популярность растёт, и конечно Вы всегда можете использовать Flash, но эта троица хорошо работает с HTML5 и имеет широчайшую поддержку среди производителей браузеров.
Выбор наиболее подходящего фреймворка может определить успех Вашего проекта. Эта статья опишет преимущества и недостатки каждой библиотеки и даст достаточно информации чтобы сделать верный выбор.
Весь код приведённый в статье является Open Source и доступен на демонстрационной странице [1] созданной специально для поддержки этой статьи.
Paper.js | Processing.js | Raphaël | |
---|---|---|---|
Технология | Тэг canvas | Тэг canvas | SVG |
Язык | PaperScript | Processing script | JavaScript |
Браузеры с | IE 9 | IE 9 | IE 7 |
Мобильные браузеры | Да | Да | Только iOS |
Модель | Векторная и растровая | Растровая | Векторная |
Размер файла ядра | 56 KB | 64 KB | 20 KB |
Все используют исключительно JavaScript, но каждый из фреймворков реализуют свой подход. Raphaël написан непосредственно на JavaScript, зато Paper.js использует PaperScript, а Processing.js использует свой собственный язык. Все они поддерживаются в Firefox, Chrome и Safari, проблема только с Internet Explorer — Paper.js и Processing.js используют тэг canvas и поэтому требуют минимум IE 9.
PaperScript это расширение языка JavaScript позволяющие писать код не загрязняющий глобальное пространство имён. Это уменьшает вероятность конфликтов в JavaScript. PaperScript также напрямую поддерживает математические примитивы, такие как Point [2] и Size [3]: Вы можете складывать две точки вместе, так, как-будто это простые числа.
Processing.js основан на фреймворке под названием Processing [4], который использует для работы Виртуальную Java машину. Вы определяете int и float вместо var, а также можете использовать наследование в Java-стиле. Не смотря на то, что скрипт на Processing.js более походит на Java, это всё же JavaScript и не требует более специфических для Java вещей.
Использование любой из трёх библиотек не составит проблем, если Вы знакомы с JavaScript.
Для начала импортируем каждую библиотеку. В каждом случае этот процесс несколько различается
Paper.js определяет тип скрипта как text/paperscript и ID целевого элемента canvas на котором мы будем рисовать.
<head>
<script src="paper.js" type="text/javascript" charset="utf-8"></script>
<script type="text/paperscript" canvas="paperCircle" src="paper_circle.pjs" id="script"></script>
</head>
<body>
<canvas id="paperCircle" class="canvas" width="200" height="200" style="background-color: white;"></canvas>
</body>
Processing.js использует data-processing-sources атрибут тега canvas для инициализации. Автор использовал .java расширение для скрипта с файлом Processing, чтобы его редактор кода правильно отобразил подсветку синтаксиса. Другие авторы могут использовать расширения .pde или .pjs. Как Вам удобнее.
<head>
<script src="processing.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<canvas width="200" height="200" class="canvas" data-processing-sources="processing_circle.java"></canvas>
</body>
Raphaël подключается как и любой другой JavaScript файл. Он отлично работает совместно с jQuery’s ready [5] функцией и со всеми остальными JS фреймворками.
<head>
<script src="raphael-min.js" type="text/javascript" charset="utf-8"></script>
<script src="raphael_circle.js" type="text/javascript" charset="utf-8"></script>
</head>
Теперь мы готовы рисовать
Оба Paper.js и Raphaël используют объектно-ориентированный подход к процессу рисования: Вы рисуете круг и получаете объект Круг. Processing.js просто рисует круг и ничего не возвращает. Следующий код иллюстрирует как это происходит. Давайте начнём с кружка размерами 100 на 100 по центру экрана.
var circle = new Path.Circle(new Point(100, 100), 10);
circle.fillColor = '#ee2a33';
var paper = Raphael('raphaelCircle', 200, 200);
var c = paper.ellipse(100, 100, 10, 10);
c.attr({'fill': '#00aeef', 'stroke': '#00aeef'});
void setup() {
size(200, 200);
}
void draw() {
background(#ffffff);
translate(100, 100);
fill(#52b755);
noStroke();
ellipse(0, 0, 20, 20);
}
Каждый кусок кода рисует один и тот же круг. Разница в том, что Вы можете потом с ним сделать.
Paper.js создаёт круг как path [6] объект. Мы можем сохранить его и изменить в дальнейшем. В Paper.js, circle.fillColor = 'red'; рисует красным цветом круг, а circle.scale(2) делает его в два раза больше.
Raphaël как и Paper.js’ реализует объектно-ориентированную модель. В Raphaël, мы можем изменить цвет нашего круга используя circle.attr('fill', 'red'); и изменить его размеры написав circle.scale(2, 2);. Главная идея состоит в том, что круг, это объект к свойствам которого мы можем получить доступ позднее.
Processing.js не использует объектов; функция ellipse() не возвращает значения. Как только мы нарисовали круг используя Processing.js, он становится частью создаваемого изображения, как при обычном рисовании чернилами по бумаге; это ни какой-то отдельный объект, которому можно изменить свойства. Для изменения цвета мы должны нарисовать такой же круг, но другого цвета поверх первого.
Когда мы вызываем функцию fill() [7], изменяется цвет для всех примитивов отображаемых далее. После вызова функции translate() [8] и fill() [7], все фигуры будут закрашены зелёным.
Так как функции изменяют сразу всё, мы легко можем получить совсем неожиданные эффекты. Вызываешь безвредную функцию и вдруг всё становится зелёным! Processing.js предоставляет функции pushMatrix() [9] и popMatrix() [10] для изоляции изменений, но их ещё надо не забыть вызвать.
Отсутствие объектов у Processing.js означает то, что сложные рисунки обрабатываются значительно быстрее. Paper.js и Raphaël хранят ссылки на все нарисованные объекты, что увеличивает количествотребуемой памяти и на сложной графике заметно замедляют приложение. Processing.js не содержит ссылок на создаваемые объекты, в итоге каждая часть рисунка занимает очень мало памяти. Объектный подход оправдан в случае, если Вы хотите получить доступ к объекту позже, в противном случае это напрасная трата ресурсов. Paper.js даёт возможность избежать ненужного расхода памяти там, где это не нужно, для этого используется Symbol [11] который растеризует объект, но конечно нужно всё спланировать заранее чтобы приложение работало достаточно быстро.
Различные подходы определяют весь стиль работы с библиотеками. Конечно это влияет и на то, как в них работать с анимацией.
Вращение кругов не слишком зрелищно, поэтому давайте пусть вокруг круга вертится квадрат.
Processing.js поддерживает анимацию используя функции setup() [12] и draw() [13] функции, примерно так:
float angle = 0.0;
void setup() {
size(200, 200);
frameRate(30);
}
void draw() {
background(#ffffff);
translate(100, 100);
fill(#52b755);
noStroke();
ellipse(0, 0, 20, 20);
rotate(angle);
angle += 0.1;
noFill();
stroke(#52b755);
strokeWeight(2);
rect(-40, -40, 80, 80);
}
Setup функция вызывается в момент старта приложения. Мы говорим Processing.js с частотой 30 кадров в секунду, в итоге наша функция draw() будет вызываться 30 раз в секунду. Это число может показаться высоким, но это нормально если мы хотим получить плавную анимацию.
Функция draw() вначале заливает весь холст одним цветом; это закрасит всё, что осталось от предыдущего кадра. Это главная особенность Processing.js: мы не манипулируем объектами, поэтому мы должны очистить всё, что осталось с предыдущего кадра.
Далее, мы переводим фокус в точку 100,100. Это позиционирует отрисовку на 100 пикселей слева и 100 пикселей от верха холста для всех операций рисования, пока мы не изменим координаты. Далее мы изменяем предыдущее значение угла наклона. Это значение увеличивается с каждым кадром заставляя квадрат вращаться. И последний шаг, это отображение квадрата с использованием функций fill [7] и rect [14].
Обычно функция rotate() Processing.js оперирует радианами [15] вместо градусов [16]. Поэтому мы каждый раз увеличиваем значение угла на 0.2, а не большее значение, к примеру 3. Это один из многих случаев при программном рисовании когда нам нужна тригонометрия.
В Paper.js простую анимация реализовать проще, чем в Processing.js, используя постоянный объект rectangle:
var r;
function init() {
var c = new Path.Circle(new Point(100, 100), 10);
c.fillColor = '#ee2a33';
var point = new Point(60, 60);
var size = new Size(80, 80);
var rectangle = new Rectangle(point, size);
r = new Path.Rectangle(rectangle);
r.strokeColor = '#ee2a33';
r.strokeWidth = 2;
}
function onFrame(event) {
r.rotate(3);
}
init();
Мы используем состояние нашего квадрата в виде объекта, и Paper.js управляет рисованием на экране. С каждым кадром мы вращаем его понемногу. Paper.js управляет всеми трансформациями, поэтому мы не должны перерисовывать всё в ручную в начале каждого кадра или следить за текущим значением угла поворота или беспокоится о том, чтобы не задеть другие объекты.
Анимация на Raphaël написана на стандартном JavaScript, т.е. Raphaël не определяет каких-то специальных функций для управления кадрами. Вместо этого мы используем обычную функцию setInterval().
var paper = Raphael('raphaelAnimation', 200, 200);
var c = paper.ellipse(100, 100, 10, 10);
c.attr({
'fill': '#00aeef',
'stroke': '#00aeef'
});
var r = paper.rect(60, 60, 80, 80);
r.attr({
'stroke-width': 2,
'stroke': '#00aeef'
});
setInterval(function() {
r.rotate(6);
}, 33);
Raphaël похож на Paper.js в своём объектно-ориентированном подходе. У нас есть квадрат, и мы вызываем его метод rotate() [17]. Таким образом мы можем вращать квадрат используя всего несколько строк кода.
Raphaël раскрывает свои преимущества когда появляется нужда в добавлении интерактивности в рисунок. Он предоставляет событийную модель, сходную с обычной для JavaScript, позволяя легко обнаруживать клики мышкой, начало перетаскивания или прикосновения пользователя. Давайте добавим квадрату реакцию на клик мышкой.
var paper = Raphael('raphaelInteraction', 200, 200);
var r = paper.rect(60, 60, 80, 80);
r.attr({'fill': '#00aeef', 'stroke': '#00aeef'});
var clicked = false;
r.click(function() {
if (clicked) {
r.attr({'fill': '#00aeef', 'stroke': '#00aeef'});
} else {
r.attr({'fill': '#f00ff0', 'stroke': '#f00ff0'});
}
clicked = !clicked;
});
Функция click() в Raphaël работает как в jQuery, и её можно навесить на любой объект. Получив событие клика, изменить цвет квадрата не составляет проблемы. Raphaël имеет дополнительные функции для поддержки перетаскивания, прохождения курсора над объектом и все другие события которые доступны в JavaScript.
Paper.js идёт другим путём для обслуживания задач взаимодействия, но и он довольно прост:
var hitOptions = {
fill: true,
tolerance: 5
};
function init() {
var point = new Point(60, 60);
var size = new Size(80, 80);
var rectangle = new Rectangle(point, size);
r = new Path.Rectangle(rectangle);
r.fillColor = '#ee2a33';
}
function onMouseUp(event) {
var hitResult = project.hitTest(event.point, hitOptions);
if (hitResult && hitResult.item) {
if (hitResult.item.clicked) {
hitResult.item.fillColor = '#ee2a33';
} else {
hitResult.item.fillColor = '#f00ff0';
}
hitResult.item.clicked = !hitResult.item.clicked;
}
}
init();
Paper.js работает с курсором используя концепцию названную “hit testing [18]” Точка нажатия высчитывается по текущим координатам курсора и библиотека получает расположенный там объект. Настройки позволяют конфигурировать поведение программы: можно указать такие вещи как: на сколько близко курсор должен быть, чтобы засчитать объекту клик, является-ли объектом всё его внутренне пространство или только край. Мы можем применить это обнаружение кликов к любому объекту (или группе объектов) в Paper.js.
Команда Paper.js также добавила объектный подход, сходный с Raphaël всего несколько недель назад (на февраль 2012). События должны появиться в следующей версии.
У Processing.js обнаружение клика мышки достаточно запутано. Объектный стиль не поддерживается, так-что мы должны рассчитывать в основном на свои собственные силы.
float bx;
float by;
int bs = 20;
boolean bover = false;
boolean clicked = false;
void setup() {
size(200, 200);
bx = width/2.0;
by = height/2.0;
noStroke();
fill(#52b755);
frameRate(10);
}
void draw() {
background(#ffffff);
// Test if the cursor is over the box
if (mouseX > bx-bs && mouseX < bx+bs && mouseY > by-bs && mouseY < by+bs) {
bover = true;
} else {
bover = false;
}
translate(100, 100);
rect(-40, -40, 80, 80);
}
void mousePressed() {
if (bover) {
if (clicked) {
fill(#52b755);
} else {
fill(#f00ff0);
}
clicked = !clicked;
}
}
Как только Processing.js отрисовывает квадрат, он забывает о нём. Мы хотим, чтобы при клике на квадрат он менял свой цвет, но скрипт этого не знает, поэтому мы должны делать все вычисления сами. Функция draw() определяет позицию курсора и высчитывает лежит-ли он в пределах нашего квадрата.
Для одного квадрата код не такой уж и страшный, но к примеру для круга нужно будет считать каждый раз Пr2. А более сложные фигуры, такие как овалы, кривые и сложные формы потребует еще больше математики.
Каждый фреймворк имеет свои преимущества. Каждая библиотека предоставляет возможности для создания классных демок и ещё более классных приложений.
Paper.js отлично подходит для манипулирования сложными фигурами. Он может вращать, скручивать и трансформировать любой объект сотней различных методов. Это даёт возможность модифицировать объекты используя жесты мышкой (gestures). Новый Google Music Tour [19], заставляет цветные линии двигаться под музыку, показывая как эта библиотека справляется со сложными изменениями простых фигур.
Ещё один вау-фактор в Paper.js это поддержка растровой графики [20]. Paper.js может полностью изменить способы, которыми отображаются изображения — к примеру превращая их в спирали [21] или кубиковые полотна (Q*bert boards) [22].
Основное преимущество Processing.js’ это его скорость, которая позволяет создавать сложную анимацию даже на слабых машинах. Тут [23] есть много примеров, также отличный пример плавности анимации на Processing.js используется на сайте Ricardo Sánchez [24].
Рассекающие воду хвосты и плавающие тела рыб выглядят очень натурально. Processing.js позволяет добиться этого просто, используя кривые и настраиваемые анимации.
Processing.js также поддерживает сложные эффекты на элементах, такие как затенение, освещение и 3-D трансформации. Если Вы хотите быстро создать сложные анимации на канве, то Processing.js является лучшим выбором.
Одной из лучших возможностей Raphaël является поддержка Internet Explorer 7 и 8. Если Ваше приложение должно поддерживать старые браузеры, то Raphaël является единственным выбором.
Ещё одним важным преимуществом Raphaël является его общество. Raphaël старше чем Paper.js и Processing.js и поэтому у него было больше времени на создание галереи примеров, туториала и описания типичных проблем и способов их решения. У него есть встроенная поддержка easing [25], анимации трансформаций [26] и обработчиков событий, которую мы видели в интерактивном примере; также у него есть собственная библиотека для создания графиков [27].
Также у Raphaël отличный набор разнообразных инструментов.
Если Вы работали с Flash, отсутствие инструментов для этих библиотек Вас расстроит. Многие фреймворки позволяют редактировать SVG изображения, но ни один из них не предоставляет drag-and-drop способа для создания приложений.
Тут приведены некоторые простые инструменты, но они скорее могут быть рассмотрены в качестве доказательства самой возможности создавать такие программы, нежели самостоятельные приложения. Adobe работает над программой названной Edge [28], но ей ещё много предстоит пройти чтобы стать нормальным инструментом.
Если Вы хотите, drag and drop, то Web анимация ещё не для Вас. На данный момент создание анимации в этой области более похоже на программирование видео игр. Написание кода для отображения круга сложнее, чем просто кликнуть и перетащить фигуру из палитры, на это даёт много преимуществ при создании более сложных приложений.
Итак, мы рассмотрели несколько простых примеров, познакомились в преимуществами и недостатками каждой платформы и поняли, в каком случае какая из них подходит лучше. Каждая библиотека имеет свои плюсы и минусы, но всё-таки основываясь только на примитивных примерах о них довольно сложно судить.
Для сравнения каждой библиотеки были нарисованы несколько шестерёнок. Каждая из которых состоит из двух кругов, с набором зубцов вокруг внешнего круга.
Когда все поверхности залиты одним цветом, фигура похожа на шестерёнку.
Шестерёнка будет немного поворачиваться на каждом кадре анимации. Основная шестерёнка будет задавать скорость, а все остальные будут вращаться зависимо от неё. Шестерёнки будут располагаться, сцепляться и вращаться друг о друга основываясь на сумасшедшем количестве тригонометрии. Расположите их на одном холсте и Вы получите сложную систему шестерёнок.
Ну, это был не совсем Raphaël. Функция вращения работает в Raphaël не так как в Paper.js и Processing.js. Raphaël не поддерживает вращение вокруг фиксированной точки. Вместо этого зубцы шестерёнки каждый раз перерисовываются независимо и летят вокруг по воздуху вместо того, чтобы вращаться вокруг центра. Единственное как автор может представить себе это можно сделать, это отрисовать шестерёнку целиком и вращать её, но там слишком много математики чем он хотел-бы приводить. Если кто-то хочет попробовать реализовать это сам, добро пожаловать, это Open Source.
Мы играемся с каждой новой освоенной технологией: мы надеемся, что она решит многие наши проблемы и это окупит инвестиции в её изучение. Технологии набирают и теряют популярность, но в этом участвуют многие факторы, к примеру поддержка производителей или требования бизнеса. Будущее нашей индустрии это частенько игра в догадки.
Сегодня Flash выглядит не лучшей технологией для изучения. У Flash есть классные инструменты разработки, годы накопленного опыта разработки и большое общество, но даже Adobe уходит от него.
С SVG похожая ситуация. Браузеры его поддерживают, но не уделяют слишком много внимания.
Каждый производитель браузеров постоянно работает над увеличением скорости отрисовки canvas, для получения возможности использования аппаратной акселерации и лучшей поддержки таких библиотек как Paper.js и Processing.js. Все мобильные браузеры А-класса поддерживают canvas, и их разработчики постоянно работают над улучшением качества этой поддержки.
Автор: Pavel_Osipov
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/javascript/5399
Ссылки в тексте:
[1] демонстрационной странице: http://zgrossbart.github.com/3gears/
[2] Point: http://paperjs.org/reference/point
[3] Size: http://paperjs.org/reference/size
[4] Processing: http://processing.org/
[5] jQuery’s ready: http://api.jquery.com/ready/
[6] path: http://paperjs.org/reference/path
[7] fill(): http://processingjs.org/reference/fill_
[8] translate(): http://processingjs.org/reference/translate_
[9] pushMatrix(): http://processingjs.org/reference/pushMatrix_
[10] popMatrix(): http://processingjs.org/reference/popMatrix_
[11] Symbol: http://paperjs.org/reference/symbol
[12] setup(): http://processingjs.org/reference/setup_
[13] draw(): http://processingjs.org/reference/draw_
[14] rect: http://processingjs.org/reference/rect_
[15] радианами: http://ru.wikipedia.org/wiki/Радиан
[16] градусов: http://ru.wikipedia.org/wiki/Градус_(геометрия)
[17] rotate(): http://raphaeljs.com/reference.html#Element.rotate
[18] hit testing: http://paperjs.org/examples/hit-testing/
[19] Google Music Tour: http://music.google.com/about/tour/
[20] растровой графики : http://ru.wikipedia.org/wiki/Растровая_графика
[21] спирали: http://paperjs.org/examples/spiral-raster/
[22] кубиковые полотна (Q*bert boards): http://paperjs.org/examples/q-bertify/
[23] Тут: http://processingjs.org/exhibition
[24] Ricardo Sánchez: http://nardove.com
[25] easing: http://raphaeljs.com/easing.html
[26] анимации трансформаций: http://raphaeljs.com/animation.html
[27] создания графиков: http://g.raphaeljs.com/
[28] Edge: http://success.adobe.com/en/na/sem/products/edge.html?sdid=JAPEL&skwcid=TC|23230|HTML5%20animation%20tools||S|b|8325947226
[29] Paper.js:: http://zgrossbart.github.com/3gears/paper_gears.html
[30] Processing.js:: http://zgrossbart.github.com/3gears/processing_gears.html
[31] Raphaël:: http://zgrossbart.github.com/3gears/raphael_gears.html
Нажмите здесь для печати.