Русские документы
Ежедневные компьютерные новости RSS rusdoc.ru  Найти :
http://www.rusdoc.ru. Версия для печати.

«LibCanvas» — фреймворк для работы с Javascript Canvas

Раздел: Programming / JavaScript @ 08.04.2010 | Ключевые слова: libcanvas фреймворк javascript javascript framework

Автор: TheShock
Источник: habrahabr

Думаю, люди, которые следят за моим творчеством, заметили, что я очень увлекся рисованием на Canvas в Javascript. Возможно это немного излишне, но ничего не могу с собой поделать, уж очень нравится эта технология. Так нравится, что я аж буду выступать на конференции с докладом о ней (Пономаренко Павел).

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



Инструментарий


Я безумно люблю JQuery, Я считаю его идеальным фреймворком для работы с DOM и сейчас, когда я от него отказался в этом фреймворке — я еще раз убедился в этом. Но вне DOM, имхо, JQuery становится слишком громоздким и его философия только раздражает. Потому изначально я решил написать сообственный фреймворк. расширяя прототипы втроенных объектов и создавая базовые функции для работы с DOM. В определенный момент гугля в поисках интересных решений с наследованием в Javascript я осознал одну истину: я пишу MooTools. Потому мною было принято решение, этот фреймворк был за пару часов изучен в достаточной для работы степени и я переписал весь, практически готовый проект (заодно отрефакторив) на новом фреймворке, о чем не жалею(Тем не менее для работы с DOM мне все равно намного приятнее JQuery). Кое-чего в MooTools мне таки не хватило, потому пришлось дорасширить втроенные объекты, добавив в их прототипы парочку методов)

Сообственно сам фреймворк


Все классы фреймворка находятся в пространстве имен LibCanvas.*. Я старался сделать его максимально изящным, исправив те недостатки, которые я смог заметить. Описание может показаться несколько сумбурным (в силу целой ночи программинга и того, что щас 7 часов утра, но с живым примером в конце станет яснее)

Оболочка


Я предлагаю работать с канвасом через некую универсальную оболочку, в которую уже встроен ImagePreloader, ProgressBar, fps-метер и другие фенечки.
new LibCanvas.Canvas2D($(`canvas`))
    .
setFps(50// количество фпс, которое браузер постарается рендерить
    
.fpsMeter(20// включаем измеритель фпс. он будет брать последних N каждов, получать среднее значение и выводить количество fps
    
.setConfig({
        
background  `#EFEBE7`// этим фоном заливаемся весь холст
        
images      App.imagesList// пока эти картинки не загрузятся - канвас работу не начнет 
        
progressBar App.progressBarStyle // но чтобы пользователь не впал в ступор - покажем прогрессбар
    
})
    .
addElement(new App.MyFirstElement()) // Добавляем пару элементов в канвас
    
.addElement(new App.SecondElement()) // кажыдй кадр будет вызывать их метод .draw()
    
.start(); // сюда можно также передать ф-цию, в которой сделать дополнительные действия


Изменение Контекста


Мне всегда не нравилось во встроенном контексте две вещи: то, что функции возвращают undefined вместо this из-за чего нельзя делать цепочки вызовов и иногда функции с огромным количеством одинаковых аргументов, например:
ctx.drawImage(image1516123456123245);

Я создал свой контекст с бле с возвращаемым this, именованными параметрами и еще некоторыми плюшками. Замечу, что он обратно-совместим с обычным контекстом, хотя его использовать и не рекомендуется. Получить его очень просто:
$(`canvas`).getContext(`2d-libcanvas`)

Замечу, что отныне очень просто создавать свои контексты (если они вам нужны), для примера смотрите ./js/Libs/LibCanvas/Core/Context2D.js:
LibCanvas.addCanvasContext(`2d-libcanvas`LibCanvas.Context2D);

На случай, если вы переопределили один из втроенных контекстов — всегда можно вызвать оригинальный:
$(`canvas`).getOriginalContext(`2d`);

Но контекст перетерпел кое-какие изменения и теперь стал удобнее. Например, теперь когда вы рисуете картинку — нет потребности догадываться, где какой параметр что значит (можно использовать любую пару from-to, from-size, to-size):
ctx.drawImage({
    
image images[`ufo`],
    
crop  : {
        
from : [4080], 
        
to   : [120160]
    },
    
draw  : {
        
from : [8080]
        
size : [160160]
    }
})


И еще несколько косметических изменений:
ctx.fillAll(`green`// Все полотно залили зеленым
    
.set(`strokeStyle``red`)
    .
stroke(new CanvasLib.Shapes.Polygon([
        [
231,  67],
        [
281,  67],
        [
317103],
        [
317153],
        [
281189],
        [
231189],
        [
195153],
        [
195103]
    ])) 
// обвели восьмиугольник
    
.arc({
        
circle : [1006040], // круг с центром в 100:60, радиусом 40 пикселей
        
angle  : [(5).degree(), (35).degree()] // c 5 по 35 градус
    
})

Замечу, что Number.degree() возвращает то вменяемое число градусов, которое было в Number, но в радианах, которые больше любит техника.

Фигуры


На базе CanvasLib.Shapes.* строится практически половина возможностей фреймворка. На данный момент там есть только три фигуры — Polygon, Circle, Rectangle, но со временем количество будет увеличиватся, например добавится RoundedRectangle, может еще что-то. Естественно можно создавать свои фигуры. Но важным при этом является реализация правильного алгоритма определения, находится ли определенная точка в пределах этой фигуры или нет. Поиск CanvasLib.Shapes.* в текущей версии находит 26 упоминаний.

Мышь и события


Самое интересное. В фреймворке реализованы события внутри элемента канвас а-ля тех, что мы используем в html. Изначально никак не задать обработку, например, mouseover на определенный объект внутри Канвас, это событие срабатывает только на сам html-элемент. Фреймворк позволяет работать с событиями очень легко и расширяемо. Достаточно подписаться на рассылку сообщений о событиях:
this.canvas.mouse.subscribe(this);

И при каждом событии будет вызывать метод event c именем события. На данный момент реализованы следующие: [click, mouseover, mousemove, mouseout, mouseup, mousedown], а также [away:mouseover, away:mousemove, away:mouseout, away:mouseup, away:mousedown] в случае, если событие произошло вне элемента. Для того, чтобы событие обработалось необходимо, чтобы элемент возвращал фигуру(getShape) у которой есть метод hasDot. То есть, например, если у нас есть круглая кнопка метод должен вернуть фигуру Circle "покарывающую" эту кнопку.
Иногда вместо того, чтобы обрабатывать евенты достаточно унаследоваться от LibCanvas.InterfaceElement, что позволит создавать объект, рендерящийся одним и з трех методов, зависимо от состояния:
elem.drawStandart(); // обычный метод
elem.drawHover();    // при наведенной мышке
elem.drawActive();   // когда объект нажат
, а также можно bind`ить и unbind`ить функции на события (как в том же ДжиКвери при работе с дом), что идеально для создания игр и GUI.

Пример


Заметьте, что само приложение - это только ./js/App/* и ./js/Start.js. Все остальное - фреймворк. Представте, насколько пришлось бы писать тяжелую логику, чтобы это обработать без фреймворка!
Желтая круглая фигня в правом нижнем углу - это EventsTester. Он подписан на события и выводит в правую панель состояние события. Если событие уже было хоть раз вызвано - меняются только координаты. Вы можете посмотреть, как для него выглядят все события, что происходят на хлсте.
Три фигни сверху - это LibCanvas.InterfaceElement, о котором я писал чуть выше. На них повешена через elem.bind(`click`fn);
функция, которая показывает соответствующую картинку. Таким образом можна сделать, например, табы, как в JQueryUI. Или интерфейс какой-то игрушки)

Основные недоработки


1. Несколько функций в контексте остались со старым интерфейсом (например , setTransform). Я их не очень заю и на знаю, как их сделать удобнее для пользователя
2. Возможно недостаточно тестировалось
3. Осел не поддерживается. Опера, Хром и Фокс - работает

Благодарности


Спасибо за помощь моему другу greedykid, а также прекрасной девушке nutochka, (которая, между прочим, участвует в Miss IT) и помогала мне делать эту либу. Без вас я бы не справился.
Пользуясь случаем передаю привет маме и папе

Ссылки и лицензия


Лицензия - LGPL, скачать можно, как всегда на гуглокоде: code.google.com/p/libcanvas/


Вернуться в раздел: Programming / JavaScript
© Copyright 1998-2012 Александр Томов. All rights reserved.