Graphics2D.js — объекты, интерактивность, анимация на canvas… И ничего лишнего
Доброго new Date ().getTimeOfDay (); HTML5 Canvas незаменим, когда нужно что-то динамически нарисовать. Но если мы захотим что-то динамически изменять — нам придётся хранить состояние элементов и перерисовывать при необходимости.Если мы захотим реагировать на события — нам придётся ловить координаты мыши и определять, находятся ли они внутри нужной фигуры.И т.д.
Частые повторяющиеся задачи. Так и появляются фреймворки и библиотеки.
Впрочем, случай с Graphics2D.js немного другой: мне просто захотелось порисовать. С объектной моделью, анимацией и событиями. И — ничего лишнего.Но максимально расширяемо: идей много, и всё можно вынести в плагины.
keyten.github.io/Graphics2D/ (русская версия сайта будет сегодня-завтра)Начинаем Контекст: var ctx = Graphics2D.id ('mycanvas');
// ну или так: var ctx = Graphics2D.query ('canvas', 1); // второй
// или var ctx = Graphics2D.query (document.getElementById ('mycanvas')); Нарисуем… ну, например, небольшой круг, который будет анимироваться при наведении мыши:
ctx.circle ({ cx: 300, cy: 300, radius: 50, fill: '#f0a' }).mouseover (function (){ this.animate ({ scale: 2, opacity: 0.5, }, 300); }).mouseout (function (){ this.animate ({ scale: 0.5, opacity: 1 }, 300); }); jsfiddle.net/wzemyho6/А теперь… пусть их будет 100:
for (var i = 0; i < 100; i++){ ctx.circle({ cx : Math.floor(Math.random() * 700), cy : Math.floor(Math.random() * 400), radius : 10, fill : 'rgb(' + [Math.floor(Math.random() * 255), Math.floor(Math.random() * 255), Math.floor(Math.random() * 255)].join(',') + ')' }).mouseover(function(){ this.animate({ scale : 2, opacity : 0.5, }, 300); }).mouseout(function(){ this.animate({ scale : 0.5, opacity : 1 }, 300); }); } jsfiddle.net/9v63govv/Что удивляет даже меня самого — неплохая производительность: анимация начинает ощутимо тормозить начинает при 2-3 тысячах.Объекты Встроенных рисуемых объектов 6: rect, circle, path, image, text и textblock.Все фигуры наследуются от внутреннего класса Shape, который содержит большинство методов, изменяющих объект (трансформации, анимация, события, заливка, обводка, прозрачность...).Разница между text и textblock: второй умеет переносить строки (автоматически и вручную через \n), в качестве координат указываются координаты блока, а не надписи.В объекте path — кривые — квадратичные и кубические Безье, эллиптические… всё, что позволяет canvas. И вдобавок, всё расширяемо: например, один из плагинов добавляет рисование Catmull-Rom.Любой объект мы можем создавать, указывая параметры по порядку, либо в объекте (последний позволяет дополнительные параметры:
ctx.circle (150, 150, 70, 'red', '2 px black'); // fill, stroke ctx.circle ({ cx: 150, cy: 150, radius: 70, fill: 'red', stroke: '5 px dot red 0.5 round',
opacity: 0.5 //, а вот дополнительный параметр }); В любом объекте мы можем указывать заливку и обводку одновременно, причём последняя позволяет сразу несколько параметров.А вот градиент:
var rect = ctx.rect (100, 100, 200, 200, { colors: ['red', 'green', 'blue'], from: 'top', to: 'bottom' }); Также можно создать градиент отдельным объектом ctx.gradient и залить им сразу несколько фигур. А потом любое изменение градиента будет отражаться на всех фигурах.Да и инлайновый градиент тоже экземпляр класса градиентов, например, изменим один из цветов: rect.fill ().color (0, 'yellow'); Пути рисуются одним из трёх вариантов:
ctx.path («M10,10 L200,200 Z», null,»2 px blue»); ctx.path ([ [10,10], [200,200], [400,100,450,150] ]); ctx.path ([ { name: 'moveTo', arguments:[10,10] }, { name: 'lineTo', arguments:[200,200] }, { name: 'closePath' } ]); Объекты без заливки и обводки не рисуются, но могут реагировать на события (это нужно включить функцией path.events (true)… так будет через пару дней).
Строковый формат — не SVG, хотя поддерживает полный его синтаксис (пропуск пробелов перед минусов, пропуск повторяющихся функций и т.п.). Поддерживает только функции M, L, C, Q и Z (только абсолютные координаты) — moveTo, lineTo, bezier, quadratic и closePath.
На днях будет плагин, добавляющий полную поддержку SVG-путей :)
Можно обрабатывать отдельные точки путей:
path.point (0).name; // → moveTo path.point (0).set ('x', 20);
path.before (1, 'L20,20 L30,50'); Нативный контекст Мы можем создать функцию, рисующую на нативном контексте (например, чтобы оптимизировать какую-то медленную функциональность) и добавить её в перерисовку: ctx.push ({ draw: function (ctx){ ctx.fillRect (200, 200, 10, 10); } }); При большом желании можно добавить также обработку событий (просто добавить функцию isPointIn)… Или даже унаследовать от Graphics2D.Shape (получив кучу функций для изменения стилей и трансформации)…Впрочем, это отдельная тема, о которой я, при желании хабрачитателей, расскажу.
Кроме того, большинство фигур и их методов умеют принимать CSS-значения, например: ctx.rect (»10pt»,»10pt»,»2em»,»2em», «blue»)
Это функциональность, в смысле которой я до сих пор не уверен (будет интересно увидеть ваши комментарии на эту тему).
Плагины Как я уже упоминал, Graphics2D достаточно расширяем, вот некоторые уже существующие плагины: — Sprite — просто-спрайты и спрайтовая анимация.— ImageAnim — анимация, когда разные кадры в разных файлах.— CatmullRom — рисование кривых Catmull-Rom (в рамках объекта Path).Планируются и другие (расширенная обработка событий, поддержка SVG-путей…) — как я говорил, идей много, и всё пойдёт в плагины.keyten.github.io/Graphics2D/ (русская версия сайта будет сегодня-завтра)Github: github.com/keyten/Graphics2D.Лицензия: MIT / LGPL.Некоторые демо: Bezier, Gradients, Transformations, Textblock.
На этом всё, интересно услышать ваши отзывы.
И ещё: большое спасибо TheShock-у за немалую помощь.