Статьи

Представляем GraphicsJS, мощную облегченную графическую библиотеку

HTML5 является основой современной сети. И в настоящее время, когда речь идет о создании интерактивных изображений, SVG и Canvas часто являются технологиями выбора — Flash забыт, Silverlight — это редкий единорог, обитающий на окраинах Интернета, и мало кто помнит сторонние плагины.

Плюсы и минусы каждого хорошо документированы , но в двух словах, SVG лучше подходит для создания и обработки интерактивных элементов. Это связано с тем, что SVG является векторным форматом на основе XML, и когда изображение загружается на страницу с помощью <svg> , каждый элемент в нем становится доступным в SVG DOM.

В этой статье я хочу познакомить вас с GraphicsJS , новой и мощной библиотекой рисования JavaScript с открытым исходным кодом, которая основана на SVG (с резервным VML для старых версий IE). Я начну с краткого введения в его основы, а затем продемонстрирую функциональные возможности библиотеки с помощью двух коротких, но впечатляющих примеров: первый посвящен искусству, а второй иллюстрирует, как писать простой код. Убийца в игре менее чем за 50 линий.

Почему GraphicsJS

Существует множество библиотек, которые могут помочь разработчикам работать с SVG: Raphaël , Snap.svg и BonsaiJS, чтобы назвать некоторые из лучших. У каждого из них есть свои сильные и слабые стороны, но их тщательное сравнение будет предметом другой статьи. Эта статья посвящена GraphicsJS, поэтому позвольте мне объяснить, что делает ее хорошей и особенной.

GraphicsJS, легкая и мощная графическая библиотека JavaScript на основе SVG от AnyChart

Прежде всего, GraphicsJS является легковесным и имеет очень гибкий JavaScript API. Он реализует множество функций расширенного текста, а также виртуальный DOM — отсоединенный от реализации HTML DOM для браузера.

Во-вторых, это новая библиотека JavaScript с открытым исходным кодом, которая была опубликована еще прошлой осенью компанией AnyChart , одним из ведущих мировых разработчиков программного обеспечения в области интерактивной визуализации данных. AnyChart использует GraphicsJS для визуализации диаграмм в своих проприетарных продуктах в течение как минимум трех лет (с момента выпуска AnyChart 7.0), поэтому GraphicsJS полностью протестирована в бою. (Отказ от ответственности, я руководитель отдела исследований и разработок в AnyChart и ведущий разработчик GraphicsJS)

В-третьих, в отличие от JavaScript-библиотек AnyChart, GraphicsJS можно бесплатно использовать как в коммерческих, так и в некоммерческих проектах. Он доступен на GitHub под лицензией Apache.

В-четвертых, GraphicsJS совместима с различными браузерами, поддерживает Internet Explorer 6.0+, Safari 3.0+, Firefox 3.0+ и Opera 9.5+. Он отображает в VML в более старых версиях IE и SVG во всех других браузерах.

Наконец, GraphicsJS позволяет комбинировать графику и анимацию с отличным эффектом. Посетите его главную галерею с анимированным костром , вращающейся галактикой , падающим дождем , сгенерированными листьями , играбельными 15-головоломками и многим другим. GraphicsJS содержит много других примеров в своей обширной документации и полном справочнике по API .

Основы GraphicsJS

Чтобы начать с GraphicsJS, вам нужно обратиться к библиотеке и создать элемент HTML уровня блока для вашего чертежа:

 <html lang="en"> <head> <meta charset="utf-8" /> <title>GraphicsJS Basic Example</title> </head> <body> <div id="stage-container" style="width: 400px; height: 375px;"></div> <script src="https://cdn.anychart.com/js/latest/graphics.min.js"></script> <script> // GraphicsJS code here </script> </body> </html> 

Затем вы должны создать сцену и нарисовать в ней что-нибудь, например, прямоугольник , круг или другую форму :

 // create a stage var stage = acgraph.create('stage-container'); // draw a rectangle var stage.rect(25, 50, 350, 300); 

Вот пример на CodePen, в котором мы идем немного дальше и рисуем символ Дары смерти .

Наш первый шедевр

Fill, Stroke и Pattern Fill

Любую форму или контур можно раскрасить, используя настройки заливки и настройки обводки . У всего есть обводка (граница), но только формы и замкнутые контуры имеют заливку. Настройки заливки и обводки очень разнообразны, вы можете пойти до линейного или кругового градиента как для заливки, так и для обводки. Кроме того, линии могут быть пунктирными, и поддерживается заполнение изображения несколькими режимами листов. Но все это довольно стандартный материал, который можно найти практически в любой библиотеке. Что делает GraphicsJS особенным, так это возможность заливки штриховкой и рисунком, которая позволяет вам не только использовать один из 32 (!) Доступных шаблонов заливки штриховки из коробки, но и легко создавать собственные рисунки, сделанные из фигур или текста.

Теперь посмотрим, что именно возможно! Я нарисую маленькую фотографию человека, стоящего возле дома, а затем дополню его различными рисунками и цветовой заливкой. Ради простоты, давайте сделаем его наивной художественной картиной (и постараемся не впадать в художественный брут ). Здесь это идет:

 // create a stage var stage = acgraph.create('stage-container'); // draw the frame var frame = stage.rect(25, 50, 350, 300); // draw the house var walls = stage.rect(50, 250, 200, 100); var roof = stage.path() .moveTo(50, 250) .lineTo(150, 180) .lineTo(250, 250) .close(); // draw a man var head = stage.circle(330, 280, 10); var neck = stage.path().moveTo(330, 290).lineTo(330, 300); var kilt = stage.triangleUp(330, 320, 20); var rightLeg = stage.path().moveTo(320, 330).lineTo(320, 340); var leftLeg = stage.path().moveTo(340, 330).lineTo(340, 340); 

Проверьте результат на CodePen .

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

Также обратите внимание, как цепочка, которая повсеместно присутствует в GraphicsJS, помогает сократить код. stage.path().moveTo(320, 330).lineTo(320, 340); (например, stage.path().moveTo(320, 330).lineTo(320, 340); ) должна использоваться осторожно, но она делает код компактным и его легче читать при правильном применении.

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

 // color the picture // fancy frame frame.stroke(["red", "green", "blue"], 2, "2 2 2"); // brick walls walls.fill(acgraph.hatchFill('horizontalbrick')); // straw roof roof.fill("#e4d96f"); // plaid kilt kilt.fill(acgraph.hatchFill('plaid')); 

Вот как выглядит наш пример сейчас .

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

 // 169 is a char code of the copyright symbol var text = acgraph.text().text(String.fromCharCode(169)).opacity(0.2); var pattern_font = stage.pattern(text.getBounds()); pattern_font.addChild(text); // fill the whole image with the pattern frame.fill(pattern_font); 

Как видите, это очень легко сделать: вы создаете экземпляр текстового объекта , затем формируете шаблон на этапе и помещаете текст в шаблон.

Создайте Художественную игру Time-Killer за менее чем 50 строк кода

В следующей части этой статьи я хочу показать вам, как создать игру типа Cookie Clicker с GraphicsJS, содержащую менее 50 строк кода.

Название игры «Уличный дворник на ветру» , и игрок берет на себя роль дворника, убирающего улицу в ветреный осенний день. В игре используется некоторый код из сгенерированной процедуры, оставляющий образец в галерее GraphicsJS.

Вы можете проверить готовую игру на CodePen (или в конце статьи ).

Layers, zIndex и виртуальный DOM

Мы начнем с создания этапа (как и прежде), а затем объявим некоторые начальные переменные:

 // create stage var stage = acgraph.create("stage-container"); // color palettes for leaves var palette_fill = ['#5f8c3f', '#cb9226', '#515523', '#f2ad33', '#8b0f01']; var palette_stroke = ['#43622c', '#8e661b', '#393b19', '#a97924', '#610b01']; // counter var leavesCounter = 0; 

В этой игре мы будем работать со слоем — объектом, предназначенным для группировки элементов в GraphicsJS. Элементы должны быть сгруппированы, если вы хотите применить к ним аналогичные изменения, такие как преобразования. Вы можете изменить слои в режиме ожидания (подробнее об этом позже), что повышает производительность и удобство работы.

В этой демонстрации мы используем функциональность слоя, чтобы помочь нам сгруппировать листья и избежать их, покрывающих ярлык (который говорит нам, сколько было проведено). Для этого мы создаем метку, а затем вызываем метод stage.layer , который создает слой, связанный с этапом. Мы назначаем этому слою более низкое zIndex чем у метки.

 // create a label to count leaves var counterLabel = stage.text(10,10, "Swiped: 0", {fontSize: 20}); // a layer for the leaves var gameLayer = stage.layer().zIndex(counterLabel.zIndex()-1); 

После этого, независимо от того, сколько листов мы создаем в слое, мы можем быть уверены, что они не покроют текст.

Трансформации

Далее, давайте добавим функцию рисования наших листьев. Это позволит использовать удобный API-интерфейс преобразования GraphicsJS, который позволяет перемещать, масштабировать, вращать и сдвигать как элементы, так и группы элементов. При использовании в сочетании со слоями и виртуальным DOM, это очень мощный инструмент.

 function drawLeaf(x, y) { // choose a random color from a palette var index = Math.floor(Math.random() * 5); var fill = palette_fill[index]; var stroke = palette_stroke[index]; // generate random scaling factor and rotation angle var scale = Math.round(Math.random() * 30) / 10 + 1; var angle = Math.round(Math.random() * 360 * 100) / 100; // create a new path (leaf) var path = acgraph.path(); // color and draw a leaf path.fill(fill).stroke(stroke, 1, 'none', 'round', 'round'); var size = 18; path.moveTo(x, y) .curveTo(x + size / 2, y - size / 2, x + 3 * size / 4, y + size / 4, x + size, y) .curveTo(x + 3 * size / 4, y + size / 3, x + size / 3, y + size / 3, x, y); // apply random transformations path.scale(scale, scale, x, y).rotate(angle, x, y); return path; }; 

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

Обработка событий

Любой объект, сцена и слой в GraphicsJS могут обрабатывать события . Полный список поддерживаемых событий доступен в API EventType . Этапы имеют четыре специальных события для управления рендерингом.

В этом примере игры мы используем прослушиватели событий, прикрепленные к конечным объектам, поэтому они исчезают один за другим, когда пользователь наводит на них курсор мыши. Для этого добавьте следующий код в drawLeaves функции drawLeaves перед оператором return :

 path.listen("mouseover", function(){ path.remove(); counterLabel.text("Swiped: " + leavesCounter++); if (gameLayer.numChildren() < 200) shakeTree(300); }); 

Здесь мы также видим, что мы используем слой для подсчета листьев.

 if (gameLayer.numChildren() < 200) shakeTree(300); 

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

GraphicsJS предоставляет виртуальный DOM , абстракцию HTML DOM, легкий и не связанный с реализацией SVG / VML для браузера. Это полезно для выполнения многих полезных задач, таких как отслеживание всех объектов и слоев, применение преобразований к группам и оптимизация рендеринга с помощью методов, которые позволяют нам отслеживать и контролировать процесс рендеринга.

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

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

При создании листьев в нашей игре нам нужно приостановить рендеринг при добавлении новых листьев и возобновить его только после внесения всех изменений:

 function shakeTree(n){ stage.suspend(); // suspend rendering for (var i = 0; i < n; i++) { var x = Math.random() * stage.width()/2 + 50; var y = Math.random() * stage.height()/2 + 50; gameLayer.addChild(drawLeaf(x, y)); // add a leaf } stage.resume(); // resume rendering } 

Этот способ обработки новых элементов заставляет новые листья появляться почти мгновенно.

Наконец, shakeTree() все с вызова shakeTree() .

 // shake a tree for the first time shakeTree(500); 

Конечный результат

Сonclusion

Переход на HTML5 изменил Интернет. Когда речь идет о современных веб-приложениях или даже простом сайте, мы часто сталкиваемся с задачами, требующими манипулирования изображениями. Хотя невозможно найти решение, которое хорошо работает в любой ситуации, вы должны рассмотреть библиотеку GraphicsJS. Это открытый исходный код, надежный, имеет отличную поддержку браузера и множество функций, которые делают его интересным, удобным и, конечно, полезным.

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

Ссылки для дальнейшего чтения