├── .gitignore
├── .gitmodules
├── Builder
├── build
├── builder.php
└── libcanvas-dynamic.php
├── Docs
└── Ru
│ ├── App
│ ├── App.md
│ ├── Element.md
│ ├── Layer.md
│ ├── Light
│ │ └── Light.md
│ └── MouseHandler.md
│ ├── Core
│ ├── Canvas.md
│ ├── Context2D.md
│ ├── LibCanvas.md
│ ├── Mouse.md
│ ├── Point.md
│ ├── Point3D.md
│ └── Size.md
│ ├── Engines
│ ├── Hex
│ │ ├── Projection.md
│ │ ├── hex-coords.png
│ │ └── hex-sizes.png
│ ├── Isometric
│ │ ├── Projection.md
│ │ ├── iso-result.png
│ │ └── iso.png
│ └── Tile
│ │ ├── Cell.md
│ │ ├── Element.md
│ │ ├── Mouse.md
│ │ └── Tile.md
│ ├── Plugins
│ ├── Animation
│ │ ├── Animation.md
│ │ ├── Frames.md
│ │ ├── Image.md
│ │ ├── Sheet.md
│ │ └── frames-demo.png
│ ├── Curve.md
│ ├── Curves.md
│ └── curves.png
│ └── Shapes
│ ├── Circle.md
│ ├── Ellipse.md
│ ├── Line.md
│ ├── Path.md
│ ├── Polygon.md
│ ├── Rectangle.md
│ └── RoundedRectangle.md
├── README.md
├── Source
├── .gitignore
├── App
│ ├── App.js
│ ├── Behavior.js
│ ├── Behaviors
│ │ ├── Behaviors.js
│ │ ├── Clickable.js
│ │ └── Draggable.js
│ ├── Clickable.js
│ ├── Container.js
│ ├── Dom.js
│ ├── Draggable.js
│ ├── Dragger.js
│ ├── Element.js
│ ├── Layer.js
│ ├── LayerShift.js
│ ├── Light
│ │ ├── Element.js
│ │ ├── Image.js
│ │ ├── Light.js
│ │ ├── Text.js
│ │ └── Vector.js
│ ├── MouseHandler.js
│ └── PointSearch.js
├── Context
│ ├── Context2D.js
│ ├── DrawImage.js
│ ├── Gradients.js
│ ├── Path.js
│ ├── Pixels.js
│ └── Text.js
├── Core
│ ├── Canvas.js
│ ├── Geometry.js
│ ├── Mouse.js
│ ├── Point.js
│ ├── Point3D.js
│ ├── Shape.js
│ └── Size.js
├── Engines
│ ├── Hex
│ │ ├── Engine.js
│ │ └── Projection.js
│ ├── Isometric
│ │ ├── Engine.js
│ │ └── Projection.js
│ └── Tile
│ │ ├── Cell.js
│ │ ├── Element.js
│ │ ├── Mouse.js
│ │ └── Tile.js
├── LibCanvas.js
├── Plugins
│ ├── Animation
│ │ ├── Animation.js
│ │ ├── Frames.js
│ │ ├── Image.js
│ │ └── Sheet.js
│ ├── Canvas2DContext.js
│ ├── Curve
│ │ ├── Curve.js
│ │ ├── Quadratic.js
│ │ └── Qubic.js
│ ├── Curves.js
│ ├── Image.js
│ ├── ImageBuilder.js
│ ├── ImagePrototype.js
│ ├── ProjectiveTexture.js
│ └── SpriteFont.js
├── Shapes
│ ├── Circle.js
│ ├── Ellipse.js
│ ├── Line.js
│ ├── Path.js
│ ├── Polygon.js
│ ├── Rectangle.js
│ └── RoundedRectangle.js
├── overall.js
└── package.yml
└── libcanvas-full-compiled.js
/.gitignore:
--------------------------------------------------------------------------------
1 | .directory
2 | .idea
3 | *.iml
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "AtomJS"]
2 | path = AtomJS
3 | url = git://github.com/theshock/atomjs.git
4 | [submodule "Packager"]
5 | path = Packager
6 | url = git@github.com:theshock/packager.git
7 |
--------------------------------------------------------------------------------
/Builder/build:
--------------------------------------------------------------------------------
1 | #!/usr/bin/php
2 |
3 | getProcessedFiles() as $file){
16 | fwrite($stderr, " * $file\n");
17 | }
18 | fwrite($stderr, " */\n\n");
19 |
20 | echo $builder->getResult();
21 |
22 | fclose($stderr);
23 |
--------------------------------------------------------------------------------
/Builder/builder.php:
--------------------------------------------------------------------------------
1 | _packager = new Packager($pkgDir);
17 | if (empty($components)) {
18 | $files = $this->_packager->get_all_files();
19 | } else {
20 | $files = $this->_packager->components_to_files($components);
21 | }
22 | $this->_files = $this->_packager->complete_files($files);
23 | $this->_result = $this->_packager->build($this->_files);
24 | }
25 |
26 | public function getResult()
27 | {
28 | return $this->_result;
29 | }
30 |
31 | public function getProcessedFiles()
32 | {
33 | return $this->_files;
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/Builder/libcanvas-dynamic.php:
--------------------------------------------------------------------------------
1 | getResult();
8 |
9 |
10 |
--------------------------------------------------------------------------------
/Docs/Ru/App/App.md:
--------------------------------------------------------------------------------
1 | LibCanvas.App
2 | =============
3 |
4 | `LibCanvas.App` - это основа фреймворка для построения интерактивных приложений на LibCanvas.
5 |
6 | #### Global
7 |
8 | После вызова LibCanvas.extract() можно использовать короткий алиас "App"
9 |
10 | ### Инициализация
11 |
12 | ```js
13 | var app = new LibCanvas.App( object settings )
14 | ```
15 |
16 | Settings может содержать следующие параметры:
17 |
18 | * `appendTo` - элемент, в который необходимо добавить приложение. По-умолчанию `body`
19 | * `size` - размеры окна приложения, объект LibCanvas.Size
20 | * `simple` - если `true`, то сгенерирует упрощённую вёрстку - из одного холста, но без возможности создавать и сдвигать слои
21 |
22 | #### Пример
23 |
24 | ```js
25 | var app = new App({
26 | appendTo: '#container',
27 | size: new Size(800, 500)
28 | })
29 | ```
30 |
31 | #### Обычная разметка для трёх слоёв:
32 |
33 | ```html
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 | ```
42 |
43 | #### Упрощённая разметка (максимум один слой):
44 |
45 | ```html
46 |
47 | ```
48 |
49 | #### Изменение размера приложения:
50 |
51 | Изменится только размер приложения, размер каждого из слоёв останется прежним.
52 |
53 | ```js
54 | app.container.size = new Size( 1500, 1200 );
55 | ```
56 |
57 |
58 | ### Методы
59 |
60 | #### createLayer
61 |
62 | ```js
63 | LibCanvas.App.Layer createLayer( object settings )
64 | ```
65 |
66 | Создаёт и возвращает слой LibCanvas.App
67 |
68 | ```js
69 | var layer = app.createLayer({ name: 'units' });
70 | ```
71 |
72 | #### destroy
73 |
74 | ```js
75 | LibCanvas.App destroy( )
76 | ```
77 |
78 | Уничтожает приложение
79 |
80 | ```js
81 | app.destroy();
82 | ```
83 |
84 | #### zIndexCompare
85 |
86 | ```js
87 | int zIndexCompare( LibCanvas.App.Element left, LibCanvas.App.Element right )
88 | ```
89 |
90 | Сравнивает позицию каждого из элементов и возвращает -1, если левый выше, +1 если выше правый и 0, если они на одном уровне
91 |
--------------------------------------------------------------------------------
/Docs/Ru/App/Element.md:
--------------------------------------------------------------------------------
1 | LibCanvas.App.Element
2 | =====================
3 |
4 | `LibCanvas.App.Element` - абстрактный класс-каркас для создания элементов, которые будут отрисовываться
5 |
6 | В отличии от остальных классов LibCanvas этот используется исключительно через наследование.
7 | Наш инструмент - его переопределение и создание собственных методов в классе наследнике:
8 |
9 | ```js
10 |
11 | atom.declare( 'Unit', App.Element, {
12 | renderTo: function (ctx, resources) {
13 | ctx.fill( this.shape, 'red' );
14 | }
15 | });
16 |
17 | new Unit( layer, {
18 | shape: new Circle(100, 100, 50)
19 | });
20 |
21 | ```
22 |
23 | ### Встроенные методы и свойства
24 |
25 | `atom.Events events` - объект, который слушает события
26 | `atom.Settings settings` - объект с настройками. Основные свойства:
27 | * `zIndex` - порядок отрисовки элемента
28 | * `shape` - фигура, которая обозначает элемент
29 | * `hidden` (*boolean*) - прячет или отображает элемент. Скрытие через `hidden` предпочтительнее, чем просто пустая отрисовка, т.к. тогда элемент не учавствует в просчёте коллизий и не стирается его предыдущее месторасположение.
30 |
31 | #### `redraw`
32 |
33 | `LibCanvas.App.Element redraw()`
34 |
35 | Метод, который сообщает приложению, что элемент изменился.
36 | Внимание! Сам метод ничего не перерисовывает, он только ставит элемент в очередь на отрисовку.
37 | Вызов элемент очень быстр и может безболезненно повторятся много раз за кадр
38 | Контекст метода привязан к элементу, так что может быть передан в качестве колбека без потери контекста
39 |
40 | ```js
41 | animate( element, {
42 | color: 'red',
43 | onChange: element.redraw
44 | })
45 | ```
46 |
47 | #### `destroy`
48 |
49 | `LibCanvas.App.Element destroy()`
50 |
51 | Удаляет элемент с контекста (но не отвязывает от событий мыши, если вы были подписаны через mouseHandler!)
52 | Контекст метода привязан к элементу, так что может быть передан в качестве колбека без потери контекста
53 |
54 | ```js
55 | destroyButton.onclick = element.destroy;
56 | ```
57 |
58 | ### Методы для переопределения
59 |
60 | #### renderTo
61 |
62 | ```js
63 | void renderTo( LibCanvas.Context2D ctx, atom.Registry resources )
64 | ```
65 |
66 | Рендерит елемент в контекст. Описывайте в этом методе только рендер, но не изменения объекта!
67 | По-умочанию вызывает метод `renderTo` у свойства `renderer` если есть или ничего не делает
68 |
69 | ```js
70 |
71 | atom.declare( 'Unit', App.Element, {
72 | renderTo: function (ctx, resources) {
73 | ctx.fill( this.shape, 'red' );
74 | ctx.stroke( this.shape, 'blue' );
75 | }
76 | });
77 |
78 | ```
79 |
80 | #### configure
81 |
82 | ```js
83 | void configure()
84 | ```
85 |
86 | Вызывается сразу после конструирования. Используется в наследниках `App.Element` вместо конструктора
87 |
88 | #### get currentBoundingShape
89 |
90 | Геттер, который возвращает фигуру, описывающую влияние элемента на контекст. По-умолчанию - прямоугольник, в который вложен `shape` элемента
91 |
92 | #### isTriggerPoint
93 |
94 | ```js
95 | boolean isTriggerPoint( Point point )
96 | ```
97 |
98 | Определяет, является ли точка точкой срабатывания для мыши или другого устройства ввода. По-умочанию - проверяет на принадлежность `shape`
99 |
100 | #### onUpdate
101 |
102 | ```js
103 | void onUpdate( int time )
104 | ```
105 |
106 | Если у слоя включён invoke, то вызывается каждый кадр и служит для изменения свойств объекта согласно времени.
107 | В аргументе `time` передаётся время в милисекундах прошедшее с момента последнего кадра для корректировки и отвязки скорости приложения от FPS
108 |
109 | ```js
110 |
111 | atom.declare( 'Unit', App.Element, {
112 | onUpdate: function (time) {
113 | // вращаемся со скоростью 90 градусов в секунду
114 | this.rotate( (90).degree() * time / 1000 );
115 |
116 | // т.к. изменения происходят каждый кадр - всегда вызываем отрисовку
117 | this.redraw();
118 | }
119 | });
120 | ```
121 |
122 | #### clearPrevious
123 |
124 | ```js
125 | void clearPrevious( LibCanvas.Context2D ctx )
126 | ```
127 |
128 | Очищает предыдущее расположение элемента в ctx. По-умолчанию - стирает `this.previousBoundingShape`
129 |
130 | #### distanceMove
131 |
132 | ```js
133 | void distanceMove( LibCanvas.Point point )
134 | ```
135 |
136 | Смещает элемент на расстояние `point`. Используется, например, в `App.Draggable`.
--------------------------------------------------------------------------------
/Docs/Ru/App/Layer.md:
--------------------------------------------------------------------------------
1 | LibCanvas.App.Layer
2 | ===================
3 |
4 | `LibCanvas.App.Layer` - класс для создания слоёв LibCanvas приложения
5 |
6 | ### Инициализация
7 |
8 | Создаётся только при помощи метода `LibCanvas.App#createLayer`:
9 |
10 | ```js
11 | LibCanvas.App.Layer app.createLayer( object settings );
12 | ```
13 |
14 | Settings может содержать следующие параметры:
15 |
16 | * `name` (*string*) - имя слоя (необходимо только для отладки)
17 | * `zIndex` (*number*) - z-index слоя
18 | * `invoke` (*boolean*) - необходимо ли вызывать у всех объектов метод `onUpdate` каждый кадр (по-умолчанию `false`)
19 | * `intersection` - при перерисовке одного из элементов, необходимо ли перерисовывать остальные. Значения:
20 | * `auto` (по-умолчанию) - только те, которые необходимо для корректной отрисовки
21 | * `manual` - нет, ни одного (например, когда вы хотите лично управлять перерисовкой)
22 | * `all` - да, все (например, если это дешевле, чем просчитывать все пересечения)
23 | * `full` - стирать весь холст и рисовать всё с нуля
24 |
25 | #### Пример
26 |
27 | ```js
28 | var layer = app.createLayer({
29 | name : 'units',
30 | zIndex: 3,
31 | invoke: true,
32 | intersection: 'all'
33 | })
34 | ```
35 |
36 | #### Изменение размера слоя
37 |
38 | Изменится только размер определённого слоя. Размер приложения и остальных слоёв останется прежним.
39 | Необходимо помнить, что изменение размера слоя уничтожит все отрисованные данные, потому необходимо вызвать `layer.redrawAll()`
40 |
41 | ```js
42 | layer.dom.size = new Size(1500, 1200);
43 | layer.redrawAll()
44 | ```
45 |
46 | ### Свойства
47 |
48 | #### ctx
49 |
50 | `2d-libcanvas` контекст элемента canvas слоя
51 |
52 | ```js
53 | layer.ctx.fillAll( 'red' )
54 | ```
55 |
56 | ### Методы
57 |
58 | #### stop
59 |
60 | ```js
61 | LibCanvas.App.Layer stop()
62 | ```
63 |
64 | Остановить отрисовку слоя
65 |
66 | ```js
67 | layer.stop()
68 | ```
69 |
70 | #### start
71 |
72 | ```js
73 | LibCanvas.App.Layer start()
74 | ```
75 |
76 | Возобновить отрисовку слоя
77 |
78 | ```js
79 | layer.start()
80 | ```
81 |
82 | #### hide
83 |
84 | ```js
85 | LibCanvas.App.Layer hide()
86 | ```
87 |
88 | Временно скрыть слой
89 |
90 | ```js
91 | layer.hide()
92 | ```
93 |
94 | #### show
95 |
96 | ```js
97 | LibCanvas.App.Layer show()
98 | ```
99 |
100 | Снова показать слой
101 |
102 | ```js
103 | layer.show()
104 | ```
105 |
106 | #### redrawAll
107 |
108 | ```js
109 | LibCanvas.App.Layer redrawAll()
110 | ```
111 |
112 | Перерисовывает все элементы слоя
113 |
114 | ```js
115 | layer.redrawAll()
116 | ```
117 |
--------------------------------------------------------------------------------
/Docs/Ru/App/Light/Light.md:
--------------------------------------------------------------------------------
1 | LibCanvas.App.Light
2 | ===================
3 |
4 | `LibCanvas.App.Light` - надстройка над `LibCanvas.App` для более лёгкого и доступного интерфейса
5 |
6 | ### Инициализация
7 |
8 | ```js
9 | var helper = new LibCanvas.App.Light( LibCanvas.Size size, object settings )
10 | ```
11 |
12 | `size` - размер приложения
13 |
14 | Settings может содержать следующие параметры:
15 |
16 | * `mouse` - будет ли использоваться мышь (по-умолчанию `true`)
17 | * `appendTo` - в какой элемент необходимо прикрепить приложение (по-умолчанию `body`)
18 |
19 | #### Пример
20 |
21 | ```js
22 | var helper = new LibCanvas.App.Light( new Size(800, 500) )
23 | ```
24 |
25 | ### Методы
26 |
27 | #### createVector
28 |
29 | ```js
30 | App.Light.Vector createVector( LibCanvas.Shape shape, object settings )
31 | ```
32 |
33 | Создаёт, добавляет в приложение и возвращает элемент App.Light.Vector, который служит для отрисовки геометрических фигур в приложении
34 |
35 | ```js
36 | var vector = helper.createVector( new Circle(100, 100, 20) );
37 | ```
38 |
39 | #### createText
40 |
41 | ```js
42 | App.Light.Text createText( LibCanvas.Shape shape, object style, object settings )
43 | ```
44 |
45 | Создаёт, добавляет в приложение и возвращает элемент App.Light.Text, который служит для отрисовки текста в приложении
46 | Содержимое `style` согласно интерфейса метода [Context2D.text](https://github.com/theshock/libcanvas/blob/master/Docs/Ru/Core/Context2D.md#%D0%9C%D0%B5%D1%82%D0%BE%D0%B4-text)
47 |
48 | ```js
49 | var text = helper.createText(
50 | new Rectangle(0, 0, 100, 40),
51 | {
52 | text: 'Hello, World!',
53 | bold: true
54 | }
55 | );
56 | ```
57 |
58 | #### createImage
59 |
60 | ```js
61 | App.Light.Image createImage( LibCanvas.Shape shape, Image image, object settings )
62 | ```
63 |
64 | Создаёт, добавляет в приложение и возвращает элемент App.Light.Image, который служит для отрисовки картинок в приложении
65 |
66 | ```js
67 |
68 | atom.ImagePreloader.run({ logo: 'html5-logo.png' },
69 | function (images) {
70 | var element = helper.createImage(
71 | new Rectangle(64, 64, 256, 256),
72 | images.get('logo')
73 | );
74 | });
75 | ```
--------------------------------------------------------------------------------
/Docs/Ru/App/MouseHandler.md:
--------------------------------------------------------------------------------
1 | LibCanvas.App.MouseHandler
2 | ==========================
3 |
4 | `LibCanvas.App.MouseHandler` - класс, который отвечает за взаимосвязь событий LibCanvas.Mouse и объектов LibCanvas.App.Element.
5 |
6 | ### Инициализация
7 |
8 | ```js
9 | LibCanvas.App.MouseHandler( object settings );
10 | ```
11 |
12 | Settings может содержать следующие параметры:
13 |
14 | * `app` (*LibCanvas.App*) - приложение, которое необходимо слушать
15 | * `mouse` (*LibCanvas.Mouse*) - объект LibCanvas.Mouse, который будет оповещать об изменениях мыши
16 | * `search` (*LibCanvas.App.ElementsMouseSearch*) - можно указать альтернативный объект, отвечающий за поиск тригернутого элемента, может использоваться для оптимизации
17 |
18 | #### Пример
19 |
20 | ```js
21 | var app, mouse, mouseHandler;
22 |
23 | app = new LibCanvas.App({ size: new Size(300,200) });
24 | mouse = new LibCanvas.Mouse(app.container.bounds);
25 | mouseHandler = new LibCanvas.App.MouseHandler({ app: app, mouse: mouse });
26 | ```
27 |
28 | Поисковик по-умолчанию (LibCanvas.App.ElementsMouseSearch) проверяет элементы на срабатывание вызывая `isTriggerPoint( Point )`
29 |
30 | ### События
31 |
32 | После подписки все элементы получают следующие события:
33 |
34 | * click
35 | * dblclick
36 | * contextmenu
37 | * wheel
38 | * mousedown
39 | * mouseup
40 | * mouseout
41 | * mouseover
42 | * mousemove
43 |
44 | ### Методы
45 |
46 | #### stop
47 |
48 | ```js
49 | LibCanvas.App.MouseHandler stop()
50 | ```
51 |
52 | Остановить обработку событий мыши
53 |
54 | ```js
55 | mouseHandler.stop()
56 | ```
57 |
58 | #### start
59 |
60 | ```js
61 | LibCanvas.App.MouseHandler start()
62 | ```
63 |
64 | Возобновить обработку событий мыши
65 |
66 | ```js
67 | mouseHandler.start()
68 | ```
69 |
70 | #### subscribe
71 |
72 | ```js
73 | LibCanvas.App.MouseHandler subscribe(LibCanvas.App.Element element)
74 | ```
75 |
76 | Подписать элемент на события мыши.
77 |
78 | ```js
79 | mouseHandler.subscribe( element );
80 |
81 | element.events.add( 'click', function (e) {
82 | console.log( 'element поймал клик мыши', e );
83 | })
84 | ```
85 |
86 | #### unsubscribe
87 |
88 | ```js
89 | LibCanvas.App.MouseHandler unsubscribe(LibCanvas.App.Element element)
90 | ```
91 |
92 | Отписать элемент от событий мыши. Если элемент был удалён с приложения при помощи метода "destroy", то отписка от событий мыши будет активированна автоматически при первом срабатывании события (но не сразу после уничтожения). Скрытые через `hidden: true` элементы всё так же получают события мыши.
93 |
94 | ```js
95 | mouseHandler.unsubscribe( element );
96 | // Элемент больше не ловит события мыши
97 | ```
98 |
99 | #### getOverElements
100 |
101 | ```js
102 | LibCanvas.App.Element[] getOverElements()
103 | ```
104 |
105 | Получить список элементов, над которыми находится мышь в данный момент (в порядке уменьшения z-index)
106 |
107 | ```js
108 | var overElements = mouseHandler.getOverElements();
109 | overElements.invoke('destroy');
110 | ```
111 |
112 | #### fall
113 |
114 | ```js
115 | LibCanvas.App.MouseHandler fall()
116 | ```
117 |
118 | Сообщает о необходимости провалиться событию мыши. Важно помнить, что если элемент подписан на события мыши, то он "блокирует" все элементы ниже. То есть при клике на нём события не сработают на элементах под ним даже если они тоже попадают в радиус действия мыши. Если по какой-то причине такое поведение не устраивает (элемент должен ловить события сам, но и не блокировать их для элементов, которые покрывает) можно использовать "проваливание":
119 |
120 | ```js
121 | mouseHandler.subscribe( element );
122 |
123 | element.events.add( 'mousedown', function (e) {
124 | console.log('Мышь нажата над нашим элементом', e);
125 | // Но элемент под ним тоже получит это событие
126 | mouseHandler.fall();
127 | });
128 | ```
129 |
130 |
--------------------------------------------------------------------------------
/Docs/Ru/Core/Canvas.md:
--------------------------------------------------------------------------------
1 | Создание своих контекстов
2 | =========================
3 |
4 | Улучшение прототипа HTMLCanvasElement позволяет легко создавать свои контексты при помощи LibCanvas.
5 | Достаточно вызвать `HTMLCanvasElement.addContext(name, ContextClass)`, где `ContextClass` - это класс с конструктором, принимающим первым аргументом ссылку на элемент canvas.
6 |
7 | #### Пример
8 |
9 | ```js
10 | new function () {
11 |
12 | var ContextClass = atom.declare({
13 | initialize: function (canvas) {
14 | this.canvas = canvas;
15 | this.ctx2d = canvas.getContext('2d');
16 | },
17 | welcome: function () {
18 | this.ctx2d.fillText('Hello World', 0, 0);
19 | }
20 | });
21 |
22 | HTMLCanvasElement.addContext('2d-hello', ContextClass);
23 | }
24 | ```
25 |
26 | #### Использование:
27 |
28 | ```js
29 | var myContext = canvas.getContext('2d-hello');
30 | myContext.welcome();
31 | myContext.fillRect(0, 0, 10, 10); // Error
32 | ```
33 |
34 | Методы стандартного контекста не реализованы, потому `fillRect` вернет ошибку.
35 | Самый простой способ избежать этого - унаследоваться от контекста LibCanvas.
36 | Обратите внимание - конструктор мы унаследовали от родительского `LibCanvas.Context2D`, потому достаточно реализовать методы.
37 |
38 | #### Пример
39 |
40 | ```js
41 | new function () {
42 | var HelloContextClass = atom.declare( LibCanvas.Context2D, {
43 | welcome: function () {
44 | return this.ctx2d.fillText('Hello World', 0, 0);
45 | }
46 | });
47 |
48 | HTMLCanvasElement.addContext('2d-libcanvas-hello', HelloContextClass);
49 | }
50 | ```
51 |
52 | #### Использование:
53 |
54 | ```js
55 | var myContext = canvas.getContext('2d-libcanvas-hello');
56 | myContext.welcome();
57 | myContext.fillRect(0, 0, 10, 10); // Success
58 | ```
59 |
60 | Желательно в названии указывать иерархию контекстовв порядке убывания, через тире.
61 |
62 | #### Canvas2DContext
63 | Вы можете использовать плагин `Canvas2DContext` для создания своего контекста на базе нативного (с максимально похожим интерфейсом)
64 |
65 | ```js
66 | new function () {
67 |
68 | var HelloContextClass = atom.declare( LibCanvas.Canvas2DContext, {
69 | welcome: function () {
70 | return this.ctx2d.fillText('Hello World', 0, 0);
71 | }
72 | });
73 |
74 | HTMLCanvasElement.addContext('2d-hello', HelloContextClass);
75 |
76 | }
77 | ```
78 |
79 | #### Использование:
80 |
81 | ```js
82 | var myContext = canvas.getContext('2d-hello');
83 | myContext.welcome();
84 | myContext.fillRect(0, 0, 10, 10); // Success
85 | ```
86 |
87 | ### Внимание!
88 | Крайне не рекомендуется переопределять встроенные в браузер контексты (которые всё-равно можно получить через метод `getOriginalContext`), т.к. это принесет в приложение очень неожиданное поведение.
89 | Так же не рекомендуется переопределять контекст `2d-libcanvas`
90 |
91 |
92 |
93 |
--------------------------------------------------------------------------------
/Docs/Ru/Core/LibCanvas.md:
--------------------------------------------------------------------------------
1 | LibCanvas
2 | =========
3 |
4 | `LibCanvas` - это глобальный объект, который является корнем пространства имён библиотеки. Он содержит несколько статических методов
5 |
6 |
7 | ## Статический метод extract
8 |
9 | ```js
10 | object LibCanvas.extract(object to = window)
11 | ```
12 |
13 | Позволяет извлечь некоторые классы LibCanvas в глобальное пространство имен (или в локальный объект) для более короткой записи
14 |
15 | #### Пример
16 |
17 | ```js
18 | // Стандартный подход:
19 | var circle = new LibCanvas.Shapes.Circle(100, 100, 20);
20 |
21 | // Извлекаем в локальную переменную
22 | var LC = LibCanvas.extract({});
23 | var circle = new LC.Circle(100, 100, 20);
24 |
25 | // Извлекаем в глобальное пространство имен:
26 | LibCanvas.extract();
27 | var circle = new Circle(100, 100, 20);
28 | ```
29 |
30 | ## Статический метод buffer
31 |
32 | ```js
33 | canvasElement LibCanvas.buffer(int width, int height, bool withCtx)
34 | canvasElement LibCanvas.buffer(LibCanvas.Size size, bool withCtx)
35 | ```
36 |
37 | Создает и возвращает элемент Canvas размером width*height.
38 | Если withCtx правдив, то свойство `ctx` элемента будет равно контексту '2d-libcanvas'
39 |
40 |
41 | #### Пример
42 |
43 | ```js
44 | var buffer = LibCanvas.buffer(100, 100, true);
45 | buffer.ctx.fillAll('black');
46 |
47 | libcanvas.ctx.drawImage(buffer, 10, 10);
48 | ```
--------------------------------------------------------------------------------
/Docs/Ru/Core/Mouse.md:
--------------------------------------------------------------------------------
1 | LibCanvas.Mouse
2 | ===============
3 |
4 | `LibCanvas.Mouse` предоставляет интерфейс для прозрачного управления мышью
5 |
6 | #### Global
7 |
8 | После вызова LibCanvas.extract() можно использовать короткий алиас "Mouse"
9 |
10 | ## Статические свойства
11 |
12 | #### метод prevent
13 |
14 | Может использовать, чтобы заглушить событие мыши по-умолчанию:
15 |
16 | ```js
17 | window.onclick = Mouse.prevent;
18 | ```
19 |
20 | #### метод getOffset
21 |
22 | ```js
23 | LibCanvas.Point getOffset( MouseEvent e, DOMElement element )
24 | ```
25 |
26 | Определяет положение мыши относительно элемента
27 |
28 | ```js
29 | var offset = Mouse.getOffset( event, canvas );
30 | ```
31 |
32 | #### метод addWheelDelta
33 |
34 | ```js
35 | MouseEvent addWheelDelta( MouseEvent e )
36 | ```
37 |
38 | Добавляет кроссбраузерное свойство `delta` в объект события, которое обозначает направление движения колёсика мыши
39 |
40 | ## Создание экземпляра LibCanvas.Mouse
41 |
42 | Первым аргументом принимает элемент, события которого надо слушать.
43 |
44 | ```js
45 | var mouse = new LibCanvas.Mouse( myCanvas );
46 | ```
47 |
48 | ## Свойства
49 |
50 | `point` - `LibCanvas.Point`, с текущими координатами мыши относительно начала элемента
51 |
52 | `previous` - `LibCanvas.Point`, предыдущие координаты мыши относительно начала элемента
53 |
54 | `delta` - `LibCanvas.Point`, последнее смещение координат мыши
55 |
56 | `events` - объект `atom.Events`
57 |
58 | ## События
59 |
60 | * click
61 | * dblclick
62 | * contextmenu
63 | * wheel
64 | * over
65 | * out
66 | * down
67 | * up
68 | * move
69 |
70 | #### Пример
71 |
72 | ```js
73 | mouse.events.add( 'click', function (event, mouse) {
74 | // нарисует круг радиусом 10 пикселей в точке клика:
75 | canvas.ctx.fill(
76 | new Circle( mouse.point, 10 )
77 | );
78 | });
79 | ```
80 |
81 | #### Особенности
82 |
83 | Событие `wheel` имеет дополнительное свойство `delta`, которого обозначает направление движения колёсика - "-1" или "1".
84 |
85 |
--------------------------------------------------------------------------------
/Docs/Ru/Core/Point3D.md:
--------------------------------------------------------------------------------
1 | LibCanvas.Point3D
2 | =================
3 |
4 | `LibCanvas.Point3D` - класс, который описывает точку в трёхмерном пространстве.
5 |
6 | #### Global
7 |
8 | После вызова LibCanvas.extract() можно использовать короткий алиас "Point3D"
9 |
10 | ## Создание экземпляра LibCanvas.Point3D
11 |
12 |
13 | Создать экземпляр класса `LibCanvas.Point` можно одним из следующих способов:
14 |
15 | ```js
16 | var xCoord = 15, yCoord = 20, zCoord = 25;
17 |
18 | // передав в конструктор координаты
19 | var point = new LibCanvas.Point3D( xCoord, yCoord, zCoord );
20 |
21 | // массив координат
22 | var point = new LibCanvas.Point3D([xCoord, yCoord, zCoord]);
23 |
24 | // объект координат
25 | var point = new LibCanvas.Point3D({ x : xCoord, y : yCoord, z: zCoord });
26 |
27 | // Другой объект LibCanvas.Point3D
28 | var point = new LibCanvas.Point3D(anotherPoint);
29 |
30 | // что равнозначно с
31 | var point = anotherPoint.clone();
32 |
33 | // после использования LibCanvas.extract():
34 | var point = new Point3D( xCoord, yCoord, zCoord );
35 | ```
36 |
37 | ## Метод equals
38 |
39 | ```js
40 | boolean equals(LibCanvas.Point3D to, int accuracy)
41 | ```
42 |
43 | Метод сравнивает две точки не по ссылкам
44 |
45 | #### аргумент `accuracy`
46 |
47 | Если указан, то означает количество знаков, с точностью которых будут сравниватся точки (для неточного сравнения)
48 |
49 | #### Пример
50 |
51 | ```js
52 | var bar = new LibCanvas.Point3D(15, 15, 10);
53 | var foo = new LibCanvas.Point3D(15, 15, 10);
54 |
55 | trace(bar == foo); // false
56 | trace(bar.equals(foo)); // true
57 | ```
58 |
59 | #### Пример с accuracy
60 |
61 | ```js
62 | var bar = new LibCanvas.Point3D(7, 12.88888324, 15.1111127);
63 | var foo = new LibCanvas.Point3D(7, 12.88888115, 15.1111093);
64 |
65 | console.log(bar == foo); // false
66 | console.log(bar.equals(foo)); // false
67 | console.log(bar.equals(foo, 8)); // false
68 | console.log(bar.equals(foo, 4)); // true
69 | ```
70 |
71 | ## Метод clone
72 |
73 | ```js
74 | LibCanvas.Point3D clone()
75 | ```
76 |
77 | Возвращает точку с такими же координатами
78 |
79 | #### Пример
80 |
81 | ```js
82 | var point = new LibCanvas.Point3D(15, 15, 10);
83 | var clone = point.clone();
84 | console.log(point == clone); // false
85 | console.log(point.equals(clone)); // true
86 | ```
87 |
88 | ## Метод move
89 |
90 | ```js
91 | LibCanvas.Point move(LibCanvas.Point point3d)
92 | ```
93 |
94 | #### Пример
95 |
96 | ```js
97 | var point = new LibCanvas.Point3D(10, 10, 10);
98 | var distance = new LibCanvas.Point3D( 5, -3, 1);
99 |
100 | point.move(distance); // Point3D(15, 7, 11)
101 | ```
102 |
103 | ## Метод diff
104 |
105 | ```js
106 | LibCanvas.Point3D diff(LibCanvas.Point3D point)
107 | ```
108 |
109 | Этот метод означает примерно следующее :
110 | на сколько надо сдвинуться точке, чтобы она оказалась на месте той, которая передана первым аргументом
111 |
112 | #### Пример
113 |
114 | ```js
115 | var pO = new LibCanvas.Point3D(10, 10, 7);
116 | var pA = new LibCanvas.Point3D(15, 18, 7);
117 |
118 | pA.diff(pO); // Point3D(-5, -8, 0)
119 | ``
120 |
121 | ## Метод map
122 |
123 | ```js
124 | LibCanvas.Point3D map(callback, context)
125 | ```
126 |
127 | Изменяет значения точки согласно результату вызова callback
128 |
129 | #### Пример
130 |
131 | ```js
132 | var point = new LibCanvas.Point3D(1, 2, 3);
133 |
134 | point.map(function (value, coord, point) {
135 | return value * value;
136 | });
137 |
138 | atom.trace( point ); // Point3D(1, 4, 9)
139 | ```
140 |
141 | ## Метод add
142 |
143 | ```js
144 | LibCanvas.Point3D add(value)
145 | ```
146 |
147 | Увеличить значение всех координат точки на `value`
148 |
149 | #### Пример
150 |
151 | ```js
152 | var point = new LibCanvas.Point3D(1, 2, 3);
153 |
154 | point.add(5);
155 |
156 | atom.trace( point ); // Point3D(6, 7, 8)
157 | ```
158 |
159 | ## Метод mul
160 |
161 | ```js
162 | LibCanvas.Point3D mul(value)
163 | ```
164 |
165 | Умножить значение всех координат точки на `value`
166 |
167 | #### Пример
168 |
169 | ```js
170 | var point = new LibCanvas.Point3D(1, 2, 3);
171 |
172 | point.mul(5);
173 |
174 | atom.trace( point ); // Point3D(5, 10, 15)
175 | ```
--------------------------------------------------------------------------------
/Docs/Ru/Core/Size.md:
--------------------------------------------------------------------------------
1 | LibCanvas.Size
2 | ==============
3 |
4 | `LibCanvas.Size` - расширение `LibCanvas.Point`, обладатает теми же свойствами, но `width` является алиасом для `x`, а `height` - алиасом для `y`.
5 |
6 | ```js
7 | var size = new LibCanvas.Size({ width: 15, height: 35 });
8 | ```
9 |
10 | #### Global
11 |
12 | После вызова LibCanvas.extract() можно использовать короткий алиас "Size"
13 |
--------------------------------------------------------------------------------
/Docs/Ru/Engines/Hex/hex-coords.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theshock/libcanvas/26010cb04c6777fde6c5174e25115597de072fc7/Docs/Ru/Engines/Hex/hex-coords.png
--------------------------------------------------------------------------------
/Docs/Ru/Engines/Hex/hex-sizes.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theshock/libcanvas/26010cb04c6777fde6c5174e25115597de072fc7/Docs/Ru/Engines/Hex/hex-sizes.png
--------------------------------------------------------------------------------
/Docs/Ru/Engines/Isometric/Projection.md:
--------------------------------------------------------------------------------
1 | Engines.Hex.Isometric
2 | =====================
3 |
4 | Библиотека для работы с изометрической проекцией 3d-координат.
5 |
6 | #### Global
7 |
8 | После вызова LibCanvas.extract() можно использовать короткий алиас "IsometricEngine"
9 |
10 | IsometricEngine.Projection
11 | ==========================
12 |
13 | Предпоставляет лёгкую возможность транслировать координаты из 3d-координат в пространстве в изометрические 2d-координаты и обратно.
14 |
15 | #### Координаты
16 |
17 | Координаты транслируются очень просто. Положительный сдвиг по оси Х смещает точку вверх-вправо, а положительный сдвиг по оси У - вниз-вправо. Положительный сдвиг по оси Z перемещает точку точно вверх.
18 |
19 | 
20 |
21 | #### Размер пикселя
22 |
23 | Существуют разные подходы к трансформации пикселей. Правильная изометрическая проекция требует угла в 30 градусов, но часто в компьютерных играх используется более острый угол, чтобы пропорции ячейки были 2:1. За эту величину отвечает настройка "factor":
24 |
25 | ```js
26 | factor: new Point3D(0.866, 0.5, 0.866) // правильная проекция
27 | factor: new Point3D( 1, 0.5, 1) // пропорциональная проекция
28 | ```
29 |
30 | Первое значение отвечает за ширину пикселя по Х координате, второе - за ширину пикселя по У координате, третье - за высоту по Z координате.
31 |
32 | Вы также можете пропорционально изменять пиксель при помощи настройки `size`
33 |
34 | Настройка `start` необходима для указания стартовых координат (где находится пиксель [0;0;0]).
35 |
36 | Пример:
37 |
38 | ```js
39 | var projection = new IsometricEngine.Projection({
40 | factor: new Point3D(1, 0.5, 1), // карта будет пропорциональной
41 | size : 2, // увеличиваем пиксели в два раза
42 | start : new Point(100, 100) - сетка начинается с лёгким отступом
43 | });
44 | ```
45 |
46 | ### Методы
47 |
48 | #### toIsometric
49 |
50 | ```js
51 | Point toIsometric( Point3D point3d )
52 | ```
53 |
54 | Транслирует координаты точки из трёхмерных в пространстве в двумерные на экране. Используется, например, при отрисовке.
55 |
56 | ```js
57 | var playersCoord = [
58 | new Point3D(100, 50, 10),
59 | new Point3D( 80, 20, 0),
60 | new Point3D( 20, 130, 4)
61 | ];
62 |
63 | playersCoord.forEach(function (coord3d) {
64 | ctx.fill(new Circle(
65 | projection.toIsometric(coord3d), 10
66 | ));
67 | });
68 | ```
69 |
70 | #### to3D
71 |
72 | ```js
73 | Point3D to3D( Point point3d[, int z = 0] )
74 | ```
75 |
76 | Транслирует координаты точки из двумерных на экране в трёхмерные в пространстве. Может использоваться для определения координаты поля при клике мышью. Т.к. точно нельзя определить на какой высоте находится текущая точка - можно использовать опциональный аргумент.
77 |
78 | ```js
79 | mouse.events.add('click', function (e) {
80 | var mapCoord = projection.to3d( mouse.point );
81 |
82 | atom.trace( mapCoord );
83 | });
84 | ```
85 |
86 | #### Пример
87 |
88 | ```js
89 | atom.dom(function () {
90 | function point (x, y, z) {
91 | return projection.toIsometric(new Point3D( x, y, z ));
92 | }
93 | function createColor (x, y) {
94 | // Цвет будет рассчитываться динамически
95 | // atom.Color проследит, чтобы мы не вылезли за границы
96 | // При смещении по оси Х клетка будет краснее
97 | // При смещении по оси Y клетка будет менее зелёной
98 | // При увеличении разницы между X и Y клетка будет терять синеву
99 | // Итог: левая клетка - зелёная, правая - розовая, нижняя - синяя, верхняя - жёлтая
100 | return new atom.Color( 128 + 24*x, 255 - 24*y, 128-24*(x-y)).toString();
101 | }
102 | function drawPoly(x, y) {
103 | // создаём полигон из 4 соседних точек. Высота в примере всегда равна нулю
104 | var poly = new Polygon(
105 | point(x+0,y+0,0),
106 | point(x+0,y+1,0),
107 | point(x+1,y+1,0),
108 | point(x+1,y+0,0)
109 | );
110 |
111 | buffer.ctx
112 | .fill(poly, createColor(x, y))
113 | .stroke(poly);
114 |
115 | buffer.ctx.fillText( x + '/' + y, poly.center );
116 | }
117 | function drawMap (width, height) {
118 | var x, y;
119 | for (x = 0; x < width; x++) for (y = 0; y < height; y++) {
120 | drawPoly(x,y);
121 | }
122 | }
123 |
124 | var buffer, x, y, projection;
125 |
126 | LibCanvas.extract();
127 |
128 | // Создаём холст, на котором будем рисовать карту
129 | buffer = LibCanvas.buffer(800, 480, true);
130 | // Добавляем его на наш экран
131 | atom.dom(buffer).appendTo('body');
132 | // Базовая настройка холста - заливаем фоном и указываем стили
133 | buffer.ctx
134 | .fillAll('#eee')
135 | .set({
136 | fillStyle : 'black',
137 | strokeStyle : '#777',
138 | textAlign : 'center',
139 | textBaseline: 'middle',
140 | font: '14px monospace'
141 | });
142 |
143 | // создаём проекцию, размер пикселя будет увеличен в 60 раз
144 | projection = new IsometricEngine.Projection({
145 | start: new Point(40, 240),
146 | size : 60
147 | });
148 | // отрисовываем карту размером 7*7 клеток
149 | drawMap(7, 7);
150 | });
151 | ```
152 |
153 | 
154 |
--------------------------------------------------------------------------------
/Docs/Ru/Engines/Isometric/iso-result.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theshock/libcanvas/26010cb04c6777fde6c5174e25115597de072fc7/Docs/Ru/Engines/Isometric/iso-result.png
--------------------------------------------------------------------------------
/Docs/Ru/Engines/Isometric/iso.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theshock/libcanvas/26010cb04c6777fde6c5174e25115597de072fc7/Docs/Ru/Engines/Isometric/iso.png
--------------------------------------------------------------------------------
/Docs/Ru/Engines/Tile/Cell.md:
--------------------------------------------------------------------------------
1 | Engines.Tile.Engine.Cell
2 | ========================
3 |
4 | Каждая ячейка тайлового движка является объектом `TileEngine.Cell`
5 | Эти объекты не создаются вручную, только внутри `TileEngine` и используются для двух целей:
6 | * Изменение и получение значения ячейки
7 | * Контейнер данных для отрисовки ячейки
8 |
9 | ### Свойства
10 |
11 | * `engine` - ссылка на движок `TileEngine`
12 | * `point` - координаты ячейки на поле
13 | * `rectangle` - прямоугольник, описывающий ячейку в пикселях
14 | * `value` - текущее значение ячейки. Изменение этого свойства автоматически обновляет `requireUpdate` у `TileEngine`
15 |
--------------------------------------------------------------------------------
/Docs/Ru/Engines/Tile/Element.md:
--------------------------------------------------------------------------------
1 | Engines.Tile.Engine.Element
2 | ===========================
3 |
4 | `TileEngine.Element` - это мост для связи `TileEngine` и `LibCanvas.App`.
5 | Необходим для встраивания тайлового движка в `LibCanvas.App` и подписи на события мыши.
6 |
7 | ### Инициализация
8 |
9 | ```js
10 | new TileEngine.Element( App.Layer layer, object settings )
11 | ```
12 |
13 | Settings может содержать следующие параметры:
14 |
15 | * `engine` (*TileEngine*) - обязательный параметр, ссылка на тайловый движок
16 | * `from` (*LibCanvas.Point*) - необязательный параметр, смещение отрисовки
17 |
18 | ```js
19 | var engineElement = new TileEngine.Element(
20 | app.createLayer('tile-engine'),
21 | { engine: engine }
22 | )
23 | ```
24 |
25 | Не стоит добавлять на слой с тайловым движком ещё какие либо элементы - отрисовка может быть некорректной.
26 |
27 | ### TileEngine.Element.app
28 |
29 | ```js
30 | TileEngine.Element.app( App app, TileEngine engine, Point from = null )
31 | ```
32 |
33 | Используется для более простых приложений - создаёт корректный слой в `LibCanvas.App`, создаёт и добавляет в слой элемент, возвращает этот элемент.
34 | По сути это просто сокращённая запись для создания элемента и слоя для него.
35 |
36 | ```js
37 | var engineElement = TileEngine.Element.app( app, engine )
38 | ```
--------------------------------------------------------------------------------
/Docs/Ru/Engines/Tile/Mouse.md:
--------------------------------------------------------------------------------
1 | Engines.Tile.Engine.Mouse
2 | =========================
3 |
4 | `TileEngine.Mouse` - специальный обработчик для оптимизированной обработки мыши при помощи делегации вместо подписывания каждой ячейки на свои события.
5 |
6 | ### Инициализация
7 |
8 | ```js
9 | new TileEngine.Mouse( TileEngine.Element element, LibCanvas.Mouse mouse )
10 | ```
11 |
12 | Важно помнить, что `element` должен быть предварительно подписан на события мыши при помощи объекта `App.MouseHandler`
13 |
14 | ### События
15 |
16 | * `over` - мышь наведена на ячейку
17 | * `out` - мышь убрана с ячейки
18 | * `down` - мышь нажата на ячейку
19 | * `up` - мышь отжата на ячейке
20 | * `click` - `down` и `up` сработали на одной ячейке
21 | * `contextmenu` - контекстное меню вызвано над ячейкой
22 |
23 | Во всех событиях первым аргументом передаётся ячейка, которая вызвала событие.
24 |
25 |
26 | #### Полный пример
27 |
28 | ```js
29 | element = TileEngine.Element.app( app, engine );
30 |
31 | mouse = new Mouse(app.container.bounds);
32 |
33 | new App.MouseHandler({ mouse: mouse, app: app })
34 | .subscribe( element );
35 |
36 | new TileEngine.Mouse( element, mouse ).events.add({
37 | over: function (cell) {
38 | console.log( 'mouse over ', cell );
39 | },
40 | out: function (cell) {
41 | console.log( 'mouse out of ', cell );
42 | },
43 | click: function (cell) {
44 | console.log( 'mouse click at ', cell );
45 | }
46 | });
47 | ```
--------------------------------------------------------------------------------
/Docs/Ru/Engines/Tile/Tile.md:
--------------------------------------------------------------------------------
1 | Engines.Tile.Engine
2 | ===================
3 |
4 | Основа тайлового движка. Отвечает за построение матрицы, хранение методов отрисовки и является фабрикой ячеек.
5 |
6 | #### Global
7 |
8 | После вызова LibCanvas.extract() можно использовать короткий алиас "TileEngine"
9 |
10 | ### Инициализация
11 |
12 | ```js
13 | var engine = new TileEngine( object settings )
14 | ```
15 |
16 | Settings может содержать следующие параметры:
17 |
18 | * `size` (*LibCanvas.Size*) - размеры поля в ячейках
19 | * `cellSize` (*LibCanvas.Size*) - размер ячейки в пикселях
20 | * `cellMargin` (*LibCanvas.Size*) - отступы между ячейками
21 | * `defaultValue` (*mixed*) - значение по-умолчанию для ячейки
22 |
23 | ```js
24 | engine = new TileEngine({
25 | // Поле размером 40*25 ячеек
26 | size: new Size(40, 25),
27 | // каждая ячейка размером 10*10
28 | cellSize: new Size(10, 10),
29 | // отступ между ячейками 1 пиксель
30 | cellMargin: new Size(1, 1),
31 | // значение по-умолчанию
32 | defaultValue: 'unknown'
33 | })
34 | ```
35 |
36 | ### Свойства
37 |
38 | `get width` - ширина поля в ячейках
39 | `get height` - высота поля в ячейках
40 | `get requireUpdate` - есть обновившиеся после последнего рефреша ячейки
41 |
42 | ### Методы
43 |
44 | #### setMethod
45 |
46 | ```js
47 | TileEngine setMethod( string name, Image value )
48 | TileEngine setMethod( string name, function value )
49 | TileEngine setMethod( string name, mixed value )
50 | TileEngine setMethod( object methods )
51 | ```
52 |
53 | Указывает способ отрисовки для каждого значения ячейки.
54 |
55 | Если значение типа Image, то в ячейку с соответствующим значением будет отрисована картинка
56 |
57 | Если значение типа function, то будет вызвана функция отрисовки с параметрами `[ctx, cell]`
58 |
59 | Если любое другое значение, то будет вызван fill прямоугольника соответствующим значением (паттерн, градиент, строка цвета)
60 |
61 | ```js
62 | engine.setMethod({
63 | unknown: 'black',
64 | grass : images.get('grass'),
65 | magic : function (ctx, cell) {
66 | var color = (cell.point.x > cell.point.y) ? 'red' : 'blue';
67 |
68 | ctx.fill( cell.rectangle, color );
69 | }
70 | });
71 | ```
72 |
73 | #### countSize
74 |
75 | ```js
76 | Size countSize()
77 | ```
78 |
79 | Посчитать размеры тайлового поля в пикселях согласно размерам поля, размерам ячейки и отступам
80 |
81 | ```js
82 | var canvas = LibCanvas.buffer(engine.countSize(), true)
83 | ```
84 |
85 | #### refresh
86 |
87 | ```js
88 | TileEngine refresh(Context2D ctx, Point translate = null)
89 | ```
90 |
91 | Перерисовать изменившиеся с последнего рефреша ячейки.
92 | До первой отрисовки всеячейки считаются изменившимися
93 | При необходимости можно задать смещение отрисоки
94 |
95 | ```js
96 | engine.refresh(canvas.ctx, new Point(100, 100))
97 | ```
98 |
99 | #### getCellByIndex
100 |
101 | ```js
102 | TileEngine.Cell getCellByIndex(Point point)
103 | ```
104 |
105 | Вернуть ячейку по соответсвующим координатам поля
106 |
107 | ```js
108 | engine.getCellByIndex(new Point(3, 1))
109 | ```
110 |
111 | #### getCellByPoint
112 |
113 | ```js
114 | TileEngine.Cell getCellByPoint(Point point)
115 | ```
116 |
117 | Вернуть ячейку по соответсвующим координатам в пикселях
118 |
119 | ```js
120 | engine.getCellByPoint(new Point(743, 351))
121 | ```
122 |
123 |
--------------------------------------------------------------------------------
/Docs/Ru/Plugins/Animation/Animation.md:
--------------------------------------------------------------------------------
1 | Plugins.Animation
2 | =================
3 |
4 | Класс для создания одного случая проигрывания анимации на базе прототипа `Plugins.Animation.Sheet`
5 |
6 | ### Инициализация
7 |
8 | ```js
9 | new Animation( object settings )
10 | ```
11 |
12 | Settings может содержать следующие параметры:
13 |
14 | * `sheet` (*Animation.Sheet*) - прототип анимации
15 |
16 | ```js
17 | animation = new Animation({
18 | sheet : this.animationSheet,
19 | onUpdate: this.redraw,
20 | onStop : this.destroy,
21 | });
22 | ```
23 |
24 | ### События
25 |
26 | `update` - вызывается когда переключается кадр анимации или при запуске анимации
27 |
28 | `stop` - вызывается когда анимация завершается последним кадром или при принудительном завершении методом `stop`
29 |
30 | ### Методы
31 |
32 | #### stop
33 |
34 | ```js
35 | Animation stop();
36 | ```
37 |
38 | Остановить анимацию
39 |
40 | ```js
41 | animation.stop();
42 | ```
43 |
44 | #### run
45 |
46 | ```js
47 | Animation run();
48 | ```
49 |
50 | Запустить анимацию сначала.
51 |
52 | ```js
53 | animation.run();
54 | ```
55 |
56 | #### synchronize
57 |
58 | ```js
59 | Animation synchronize();
60 | ```
61 |
62 | Синхронизировать старт анимации с другой анимацией.
63 |
64 | ```js
65 | fooAnimation.synchronize( coreAnimation );
66 | barAnimation.synchronize( coreAnimation );
67 |
68 | coreAnimation.run();
69 |
70 | // fooAnimation.startTime == barAnimation.startTime == coreAnimation.startTime
71 | ```
72 |
73 | #### get
74 |
75 | ```js
76 | Animation get();
77 | ```
78 |
79 | Получить текущий кадр анимации или `null` если анимация остановлена, закончилась или не запущена.
80 |
81 | ```js
82 | var frame = animation.get();
83 | ```
84 |
85 | ### Комплексный пример на базе LibCanvas.App
86 |
87 | ```js
88 |
89 | /** @class ExplosionLauncher */
90 | atom.declare( 'ExplosionLauncher', {
91 | initialize: function (layer, images) {
92 | this.layer = layer;
93 |
94 | this.animationSheet = new Animation.Sheet({
95 | frames: new Animation.Frames( images.get('explosion'), 50, 50 ),
96 | delay : 40
97 | })
98 | },
99 |
100 | explode: function (coordinates) {
101 | new Explosion( this.layer, {
102 | sheet: this.animationSheet,
103 | shape: new Circle(coordinates, 50)
104 | });
105 | }
106 | });
107 |
108 | /** @class Explosion */
109 | atom.declare( 'Explosion', App.Element, {
110 |
111 | configure: function () {
112 | this.animation = new Animation({
113 | sheet : this.settings.get('sheet'),
114 | onUpdate: this.redraw,
115 | onStop : this.destroy,
116 | });
117 | },
118 |
119 | renderTo: function (ctx) {
120 | ctx.drawImage({
121 | image : this.animation.get(),
122 | center: this.shape.center
123 | });
124 | }
125 |
126 | });
127 | ```
--------------------------------------------------------------------------------
/Docs/Ru/Plugins/Animation/Frames.md:
--------------------------------------------------------------------------------
1 | Plugins.Animation.Frames
2 | ========================
3 |
4 | Класс, который используется для "нарезки" картинок из одной тайловой картинки.
5 | Обычно кадры анимации похожи между собой и имеет смысл множество их собрать в одно изображение подобно технологии css-sprites.
6 | Допустим, у вас ширина кадра анимации 50 пикселей, высота - 40, 15 кадров. Вы можете нарисовать их в три ряда в картинке размером 250*120.
7 |
8 | 
9 |
10 | ### Инициализация
11 |
12 | ```js
13 | new Animation.Frames( Image image, int width = null, int height = null )
14 | ```
15 |
16 | * `image` (*Image*) - картинка-источник для нарезки
17 | * `width` (*int*) - ширина кадра. Равен ширине картинки, если `null`
18 | * `height` (*int*) - высота кадра. Равен высоте картинки, если `null`
19 |
20 |
21 | ```js
22 | var frames = new Animation.Frames( images.get('ship'), 100 );
23 | ```
24 |
25 | ### Методы
26 |
27 | `get length` - количество кадров в массиве
28 |
29 | ```js
30 | console.log( frames.length );
31 | ```
32 |
33 |
34 | #### get
35 |
36 | ```js
37 | canvasElement get( int index );
38 | ```
39 |
40 | Возвращает картинку-кадр, часть исходной картинки.
41 |
42 | ```js
43 | var frame = frames.get( 5 );
44 | ```
45 |
46 |
--------------------------------------------------------------------------------
/Docs/Ru/Plugins/Animation/Image.md:
--------------------------------------------------------------------------------
1 | Plugins.Animation.Element
2 | =========================
3 |
4 | Класс, который используется для создания картинки-анимации для вставки в dom-дерево
5 |
6 | ```js
7 | atom.dom Animation.Image.element( Animation animation );
8 | atom.dom Animation.Image.element( Animation.Sheet sheet );
9 | ```
10 |
11 | ### Пример
12 |
13 | ```js
14 | function appendAnimatedLogoTo( targetElement ) {
15 | var logoSheet = new Animation.Sheet({
16 | frames: new Animation.Frames( images.get('logo'), 50, 50 ),
17 | delay : 40,
18 | looped: true
19 | });
20 |
21 | Animation.Image.element( logoSheet ).appendTo( targetElement );
22 | }
23 | ```
--------------------------------------------------------------------------------
/Docs/Ru/Plugins/Animation/Sheet.md:
--------------------------------------------------------------------------------
1 | Plugins.Animation.Sheet
2 | =======================
3 |
4 | Класс для описания анимации, её прототипа от которого будут отталкиваться все объекты.
5 | Описывает задержку между фреймами, их зацикленность и порядок воспроизведения. Является технических классом, сущности которого используются только для передачи настроек в класс анимации.
6 |
7 | ### Инициализация
8 |
9 | ```js
10 | new Animation.Sheet( object settings )
11 | ```
12 |
13 | Settings может содержать следующие параметры:
14 |
15 | * `frames` (*Animation.Frames*) - список исходных кадров, которые необходимо объеденить в анимацию
16 | * `delay` (*int*) - задержка между кадрами в миллисекундах
17 | * `looped` (*bool*) - зациклена ли анимация или заканчивается с посленим кадром
18 | * `sequence` (*int[]*) - порядок кадров (по-умолчанию - с первого до последнего кадра анимации)
19 |
20 | ```js
21 | new Animation.Sheet({
22 | frames: new Animation.Frames( sourceImage ),
23 | delay : 40,
24 | looped: true,
25 | sequence: [ 0,1,1,2,1,2,2,3,4,5,4,5 ]
26 | })
27 | ```
--------------------------------------------------------------------------------
/Docs/Ru/Plugins/Animation/frames-demo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theshock/libcanvas/26010cb04c6777fde6c5174e25115597de072fc7/Docs/Ru/Plugins/Animation/frames-demo.png
--------------------------------------------------------------------------------
/Docs/Ru/Plugins/Curve.md:
--------------------------------------------------------------------------------
1 | Plugins.Curve
2 | =============
3 |
4 | Математическая база для Кривых Безье. Может использоваться для создания анимаций движения по пути и для других целей.
5 |
6 | ### Инициализация
7 |
8 | ```js
9 | // Quadratic curve, one control point
10 | var curve = new LibCanvas.Plugins.Curve({
11 | from: new Point(100, 100),
12 | to : new Point(200, 300),
13 | points: [
14 | new Point(200, 100)
15 | ]
16 | });
17 |
18 | // Qubic curve, two control points
19 | var curve = new LibCanvas.Plugins.Curve({
20 | from: new Point(100, 100),
21 | to : new Point(200, 300),
22 | points: [
23 | new Point(200, 100),
24 | new Point(100, 200),
25 | ]
26 | });
27 | ```
28 |
29 | * `from` (*LibCanvas.Point*) - точка начала кривой
30 | * `to` (*LibCanvas.Point*) - точка окончания кривой
31 | * `points` (*LibCanvas.Point[]*) - массив контрольных точек кривой
32 |
33 | ### Методы
34 |
35 | #### getPoint
36 |
37 | ```js
38 | LibCanvas.Point getPoint(float t)
39 | ```
40 |
41 | `t` - число между 0 и 1. Возвращает координаты точки прямой.
42 |
43 |
44 | ```js
45 | var point = curve.getPoint( 0.45 )
46 | ```
47 |
48 |
49 | #### getAngle
50 |
51 | ```js
52 | float getAngle(float t)
53 | ```
54 |
55 | `t` - число между 0 и 1. Возвращает угол кривой в соответствующем месте
56 |
57 |
58 | ```js
59 | var angle = curve.getAngle( 0.45 )
60 | ```
61 |
--------------------------------------------------------------------------------
/Docs/Ru/Plugins/Curves.md:
--------------------------------------------------------------------------------
1 | Plugins.Curves
2 | ==============
3 |
4 | Отрисовка кривых безье с динамической шириной и цветом. Расширяет встроенный объект Context2D ('2d-libcanvas'), предоставляя удобный метод `drawCurve`
5 |
6 | 
7 |
8 | ### Инициализация
9 |
10 | ```js
11 | Context2D drawCurve(object params)
12 | ```
13 |
14 | * `from` (*Point*) - точка начала кривой
15 | * `to` (*Point*) - точка окончания кривой
16 | * `points` (*Point[]*) - массив контрольный точек. Может содержать 0, 1 или 2 точки
17 | * `inverted` (*Boolean*) - добавляет "ленточность" (см. скриншот выше)
18 | * `gradient` (*object*) - описывает плавное изменение цвета кривой
19 | * `from` (*string*) - начальный цвет
20 | * `to` (*string*) - окончательный цвет
21 | * `fn` (*string*) - функция изменения цвета (см. [atom.Transition](https://github.com/theshock/atomjs/blob/master/Docs/En/Declare/Transition.md))
22 | * `width` (*object*) - описывает плавное изменение цвета кривой
23 | * `from` (*number*) - начальная ширина
24 | * `to` (*number*) - начальная ширина
25 | * `fn` (*string*) - функция изменения ширины (см. [atom.Transition](https://github.com/theshock/atomjs/blob/master/Docs/En/Declare/Transition.md))
26 |
27 | ```js
28 |
29 | ctx.drawCurve({
30 | from : new Point(100, 250),
31 | to : new Point(200, 100),
32 | points: [ new Point(100, 100), new Point(250, 250) ],
33 | inverted: true,
34 | gradient:{
35 | from: '#ff0',
36 | to : '#f00',
37 | fn : 'linear'
38 | },
39 | width:{
40 | from: 30,
41 | to : 1,
42 | fn : 'sine-in'
43 | }
44 | });
45 | ```
--------------------------------------------------------------------------------
/Docs/Ru/Plugins/curves.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theshock/libcanvas/26010cb04c6777fde6c5174e25115597de072fc7/Docs/Ru/Plugins/curves.png
--------------------------------------------------------------------------------
/Docs/Ru/Shapes/Circle.md:
--------------------------------------------------------------------------------
1 | Circle
2 | ======
3 | `LibCanvas.Shapes.Circle` - класс, который описывает простую геометрическую фигуру "круг"
4 |
5 | #### Global
6 |
7 | После вызова LibCanvas.extract() можно использовать короткий алиас "Circle"
8 |
9 | ## Создание экземпляра LibCanvas.Shapes.Circle
10 |
11 | ```js
12 | var circle = new LibCanvas.Shapes.Circle( centerX, centerY, radius );
13 |
14 | var circle = new LibCanvas.Shapes.Circle( centerPoint, radius );
15 |
16 | var circle = new LibCanvas.Shapes.circle({
17 | center : centerPoint,
18 | radius : toPoint
19 | });
20 | ```
21 |
22 | Не забывайте про передачу объектов по ссылке:
23 |
24 | ```js
25 | var circle = new LibCanvas.Shapes.Circle( point, 10 );
26 | circle.center.x = 100;
27 | alert(point.x); // 100
28 | ```
29 |
30 | Если необходимо, такого поведения можно избежать, передавая клон точки
31 |
32 | ```js
33 | var circle = new LibCanvas.Shapes.Circle( center.clone(), radius );
34 | ```
35 |
36 | ## Метод hasPoint
37 |
38 | ```js
39 | bool hasPoint(LibCanvas.Point point);
40 | ```
41 |
42 | Возвращает true если точка находится внутри круга
43 |
44 | #### Пример
45 |
46 | ```js
47 | var circle = new LibCanvas.Shapes.Circle({
48 | center : [25, 25],
49 | radius : 15
50 | });
51 | circle.hasPoint( new Point(22, 24) ); // true
52 | circle.hasPoint( new Point(88, 88) ); // false
53 | ```
54 |
55 | ## Метод move
56 |
57 | ```js
58 | LibCanvas.Shapes.Center move(LibCanvas.Point distance, bool reverse);
59 | ```
60 |
61 | Вызывает метод move у центра
62 |
63 | #### Пример
64 |
65 | ```js
66 | var circle = new LibCanvas.Shapes.Circle({
67 | center : [25, 25],
68 | radius : 15
69 | });
70 | circle.move({ x : 2, y : 3 });
71 | // circle.center == Point(27, 28)
72 | ```
73 |
74 | #### Возвращает `this`
75 |
76 | ## Метод intersect
77 |
78 | ```js
79 | bool intersect(LibCanvas.Shape shape);
80 | ```
81 |
82 | Проверяет пересечение двух фигур. Точное если `shape` является кругом и через boundingRectangle если `shape` - другая фигура.
83 |
84 | #### Пример
85 |
86 | ```js
87 | var circleA = new Circle(25, 25, 15);
88 | var circleB = new Circle(30, 30, 10);
89 | circleA.intersect( circleB ); // true
90 | ```
91 |
92 | ## Метод scale
93 |
94 | ```js
95 | Circle scale(number power, LibCanvas.Point pivot);
96 | ```
97 |
98 | Увеличивает круг в `power` раз относительно точки `pivot` или относительно центра круга
99 |
100 | #### Пример
101 |
102 | ```js
103 | var circle = new Circle(30, 30, 10);
104 |
105 | circle.scale( 2 );
106 |
107 | // Увеличили круг в два раза:
108 | //
109 | // var circle = new Circle(30, 30, 20);
110 | ```
111 |
112 | #### Возвращает `this`
113 |
114 |
115 | ## Метод draw
116 |
117 | ```js
118 | Circle draw(LibCanvas.Context2D ctx, String type);
119 | ```
120 |
121 | Отрисовывает круг в контекст, используя текущие настройки
122 |
123 | #### аргумент `type`
124 | Способ отрисовки. Может принимать значения `fill`, `stroke`, `clear`
125 |
126 | #### Пример
127 |
128 | ```js
129 | var circle = new Circle(100, 100, 20);
130 |
131 | var ctx = canvasElem
132 | .getContext('2d-libcanvas')
133 | .set({
134 | 'fillStyle': 'red',
135 | 'strokeStyle': 'black'
136 | });
137 | // Зальем красным круг в контексте
138 | circle.draw(ctx, 'fill');
139 | // Обведем черным круг в контексте
140 | circle.draw(ctx, 'stroke');
141 | ```
142 |
143 | Но такой способ рекомендуется использовать только если по какой либо причине не доступен следующий:
144 |
145 | ```js
146 | var ctx = canvasElem
147 | .getContext('2d-libcanvas')
148 | .fill (circle, 'red')
149 | .stroke(circle, 'black');
150 | ```
151 |
152 | #### Возвращает `this`
153 |
154 | ## Метод processPath
155 |
156 | ```js
157 | Circle processPath(LibCanvas.Context2D ctx, bool noWrap = false)
158 | ```
159 |
160 | Проходит путь с помощью `ctx.arc`
161 |
162 | #### аргумент `noWrap`
163 | если указан в false(по умолчанию), то обрамляет с помощью `beginPath`, `endPath`
164 |
165 | #### Пример
166 |
167 | ```js
168 | new Circle(100, 150, 30).processPath(ctx);
169 |
170 | // равносильно:
171 |
172 | ctx
173 | .beginPath()
174 | .arc(100, 150, 30, 0, Math.PI*2, false)
175 | .closePath();
176 | ```
177 |
178 | ## Метод clone
179 |
180 | ```js
181 | Circle clone()
182 | ```
183 |
184 | Возвращает новый круг с таким же радиусом и клонированным центром
185 |
186 | #### Пример
187 |
188 | ```js
189 | var circle = new Circle(100, 150, 30);
190 |
191 | var circleClone = circle.clone();
192 | ```
193 |
194 | ## Метод equals
195 |
196 | ```js
197 | Circle equals( Circle circle )
198 | ```
199 |
200 | Проверяет, равны ли два круга
201 |
202 | #### Пример
203 |
204 | ```js
205 | var circleA = new Circle(100, 150, 30);
206 | var circleB = new Circle(100, 150, 30);
207 |
208 | console.log( circleA == circleB ); // false
209 | console.log( circleA.equals(circleB) ); // true
210 | ```
--------------------------------------------------------------------------------
/Docs/Ru/Shapes/Ellipse.md:
--------------------------------------------------------------------------------
1 | LibCanvas.Shapes.Ellipse
2 | ========================
3 |
4 | `Ellipse` - наследник фигуры `Rectangle`. Врисовывает эллипс в ректанг, описанный точками `from` и `to`
5 |
6 | ```js
7 | var ellipse = new Ellipse({ from: [10, 10], to: [100, 50] });
8 | ```
9 |
10 | [Пример использования »](http://libcanvas.github.com/shapes/ellipse.html)
11 |
12 | #### Global
13 |
14 | После вызова LibCanvas.extract() можно использовать короткий алиас "Ellipse"
15 |
16 | ## Свойства
17 |
18 | ### angle
19 | Угол поворота эллипса. Суть - эллипс вписан в прямоугольник, а потом развёрнут вокруг центра на свойство `angle`
20 |
21 | ## Метод rotate
22 |
23 | ```js
24 | LibCanvas.Shapes.Ellipse rotate(int degree)
25 | ```
26 |
27 | Поворачивает эллипс на `degree` градусов вокруг центра.
28 |
29 | #### Возвращает `this`
30 |
--------------------------------------------------------------------------------
/Docs/Ru/Shapes/Line.md:
--------------------------------------------------------------------------------
1 | LibCanvas.Shapes.Line
2 | =====================
3 |
4 | #### Global
5 |
6 | После вызова LibCanvas.extract() можно использовать короткий алиас "Line"
7 |
8 | ## Создание экземпляра LibCanvas.Shapes.Line
9 |
10 | ```js
11 | // две точки LibCanvas.Point - откуда и куда
12 | var line = new LibCanvas.Shapes.Line( fromPoint, toPoint );
13 |
14 | // объект параметров
15 | var line = new LibCanvas.Shapes.Line({
16 | from : fromPoint,
17 | to : toPoint
18 | });
19 | ```
20 |
21 | Не забывайте, что точки передаются по ссылке, потому если вы объявили line через две точки то при изменении точки внутри линии будут менятся и оригинальные точки.
22 |
23 | ```js
24 | var line = new Line( fromPoint, toPoint );
25 | line.from.x = 100;
26 | alert(fromPoint.x); // 100
27 | ```
28 |
29 | Если необходимо, такого поведения можно избежать, передавая клоны точек
30 |
31 | ```js
32 | var line = new LibCanvas.Shapes.Line( fromPoint.clone(), toPoint.clone() );
33 | ```
34 |
35 | Или клонируя линию:
36 |
37 | ```js
38 | var line = new LibCanvas.Shapes.Line( fromPoint, toPoint ).clone();
39 | ```
40 |
41 | ## Свойства
42 |
43 | ### length (get)
44 | Получить длину линии
45 |
46 | ### center (get)
47 | Создает новую точку с координатами, которые соотвутствуют центру линии
48 |
49 | ```js
50 | var line = new Line({
51 | from : [10, 10],
52 | to : [20, 20]
53 | });
54 | line.center; // Point(15, 15)
55 | ```
56 |
57 | ## Метод hasPoint
58 |
59 | ```js
60 | bool hasPoint(LibCanvas.Point point);
61 | ```
62 |
63 | Возвращает true если точка находится на линии
64 |
65 | #### Пример
66 |
67 | ```js
68 | var line = new LibCanvas.Shapes.Line({
69 | from : [4, 4],
70 | to : [8, 8]
71 | });
72 | line.hasPoint( [6, 6] ); // true
73 | line.hasPoint( [2, 5] ); // false
74 | ```
75 |
76 | ## Метод move
77 |
78 | ```js
79 | LibCanvas.Shapes.Line move(LibCanvas.Point distance, bool reverse);
80 | ```
81 |
82 | Вызывает метод move у обоих точек
83 |
84 | #### Пример
85 |
86 | ```js
87 | var line = new LibCanvas.Shapes.Line({
88 | from : [4, 4],
89 | to : [8, 8]
90 | });
91 | line.move({ x : 2, y : 3 });
92 | // line.from == Point( 6, 7)
93 | // line.to == Point(10, 11)
94 | ```
95 |
96 | #### Возвращает `this`
97 |
98 | ## Метод processPath
99 |
100 | ```js
101 | LibCanvas.Context2D processPath(LibCanvas.Context2D ctx, bool noWrap = false)
102 | ```
103 |
104 | Прокладывает путь с помощью с точки `from` с помощью `ctx.moveTo` в точку `to` с помощью `ctx.lineTo`
105 |
106 | #### аргумент `noWrap`
107 | если указан в false(по умолчанию), то обрамляет с помощью beginPath, endPath
108 |
109 | #### Пример
110 |
111 | ```js
112 | LibCanvas.Shapes.Line({
113 | from : [4, 4],
114 | to : [8, 8]
115 | }).processPath(ctx);
116 |
117 | // равносильно c:
118 | ctx.beginPath()
119 | .moveTo(4, 4) // line.from
120 | .lineTo(8, 8) // line.to
121 | .closePath();
122 | ```
123 |
124 | #### Возвращает `this`
125 |
126 | ## Метод perpendicular
127 |
128 | ```js
129 | LibCanvas.Point perpendicular(LibCanvas.Point point)
130 | ```
131 |
132 | Возвращает перпендикуляр точки `point` на текущую прямую
133 |
134 | #### Пример
135 |
136 | ```js
137 | var line = new LibCanvas.Shapes.Line( [0,3], [4,0] );
138 | var point = new LibCanvas.Point( 0, 0 );
139 |
140 | line.perpendicular( point ); // Point(1.44, 1.92)
141 | ```
142 |
143 | ## Метод intersect
144 |
145 | ```js
146 | bool intersect(LibCanvas.Shapes.Line line)
147 | LibCanvas.Point intersect(LibCanvas.Shapes.Line line, true)
148 | ```
149 |
150 | Определяет пересечение линии с другой линией. Если параметр `point` равен `true`, то вернётся точка пересечения или `null`, если отсутствует - вернётся `true` или `false`.
151 |
152 | ```js
153 | var first = new Line([10, 10], [20, 20]);
154 | var second = new Line([10, 20], [20, 10]);
155 |
156 | trace( first.intersect(second ) ); // true
157 | trace( first.intersect(second, true) ); // Point(15, 15)
158 | ```
159 |
160 | ## Метод distanceTo
161 |
162 | ```js
163 | Number distanceTo(LibCanvas.Point point, boolean asInfinitiveLine)
164 | ```
165 |
166 | Определяет расстояние между линией и точкой `point`. Если `asInfinitiveLine=true`, то линия будет считатьтся бесконечной прямой, иначе - отрезком.
167 |
168 | ```js
169 | var line = new Line (10, 10, 20, 20),
170 | point = new Point(41, 40);
171 |
172 | line.distanceTo(point ); // 29
173 | line.distanceTo(point, true); // 0.7071
174 | ```
175 |
176 | ## Метод equals
177 |
178 | ```js
179 | bool equals(LibCanvas.Shapes.Line line, int accuracy)
180 | ```
181 |
182 | Сравнивает точки линий методом LibCanvas.Point.equals
183 |
184 |
185 | ```js
186 | var foo = new LibCanvas.Shapes.Line(15, 20, 10, 5);
187 | var bar = new LibCanvas.Shapes.Line(15, 20, 10, 5);
188 |
189 | trace(bar == foo); // false
190 | trace(bar.equals(foo)); // true
191 | ```
192 |
193 | ## Метод clone
194 |
195 | ```js
196 | LibCanvas.Shapes.Line clone()
197 | ```
198 |
199 | Возвращает линию с такими же координатами
200 |
201 | ```js
202 | var line = new LibCanvas.Shapes.Line(15, 20, 10, 5);
203 | var clone = line.clone();
204 |
205 | trace(line == clone); // false
206 | trace(line.equals(clone)); // true
207 | ```
--------------------------------------------------------------------------------
/Docs/Ru/Shapes/Path.md:
--------------------------------------------------------------------------------
1 | Path
2 | ====
3 |
4 | `LibCanvas.Shapes.Path` - используется для создания фигур на базе кривых Безье.
5 |
6 | #### Global
7 |
8 | После вызова LibCanvas.extract() можно использовать короткий алиас "Path"
9 |
10 | ## Создание экземпляра LibCanvas.Shapes.Path
11 |
12 | ```js
13 | var polygon = new LibCanvas.Shapes.Path();
14 | ```
15 |
16 | #### Пример
17 |
18 | ```js
19 | var path = new Path();
20 | ```
21 |
22 | ## get length
23 |
24 | Возвращает количество шагов в пути:
25 |
26 | #### Пример
27 |
28 | ```js
29 | pathFrom = new Point(150, 200);
30 |
31 | path = new Path()
32 | .moveTo ( pathFrom )
33 | .curveTo([300, 200], [250, 150])
34 | .curveTo([200, 280], [290, 250])
35 | .curveTo( pathFrom , [220, 220]);
36 |
37 | console.log( path.length ); // 4
38 | ```
39 |
40 | ## Описание шагов пути
41 |
42 | ### moveTo
43 |
44 | ```js
45 | Path moveTo(LibCanvas.Point point);
46 | ```
47 |
48 | Добавить шаг перемещения к точке `point`
49 |
50 | #### Пример
51 |
52 | ```js
53 | path.moveTo( new Point(100, 150) );
54 | ```
55 |
56 | ### lineTo
57 |
58 | ```js
59 | Path lineTo(LibCanvas.Point point);
60 | ```
61 |
62 | Провести линию к точке `point`
63 |
64 | #### Пример
65 |
66 | ```js
67 | path.lineTo( new Point(100, 150) );
68 | ```
69 |
70 | ### curveTo
71 |
72 | ```js
73 | Path curveTo(LibCanvas.Point point, LibCanvas.Point cp1, LibCanvas.Point cp2 = null);
74 | ```
75 |
76 | Провести кривую линию к точке `point`
77 |
78 | #### Пример
79 |
80 | ```js
81 | // Квадратическая кривая
82 | path.curveTo( new Point(100, 150), new Point(50, 50) );
83 | // Кубическая кривая
84 | path.curveTo( new Point(100, 150), new Point(50, 50), new Point(80, 40) );
85 | ```
86 |
87 | ## Метод hasPoint
88 |
89 | ```js
90 | bool hasPoint(LibCanvas.Point point);
91 | ```
92 |
93 | Возвращает true если точка находится внутри пути
94 |
95 | #### Пример
96 |
97 | ```js
98 | pathFrom = new Point(150, 200);
99 |
100 | path = new Path()
101 | .moveTo ( pathFrom )
102 | .curveTo([300, 200], [250, 150])
103 | .curveTo([200, 280], [290, 250])
104 | .curveTo( pathFrom , [220, 220]);
105 |
106 | path.hasPoint( new Point(160, 200) ); // true
107 | path.hasPoint( new Point(666, 200) ); // false
108 | ```
109 |
110 | ## Метод move
111 |
112 | ```js
113 | Path move(LibCanvas.Point distance, bool reverse);
114 | ```
115 |
116 | Вызывает метод move у всех точек пути. Если точка повторяется несколько раз - сдвигается лишь однажды
117 |
118 | #### Пример
119 |
120 | ```js
121 | pathFrom = new Point(150, 200);
122 |
123 | path = new Path()
124 | .moveTo ( pathFrom )
125 | .curveTo([300, 200], [250, 150])
126 | .curveTo([200, 280], [290, 250])
127 | .curveTo( pathFrom , [220, 220]);
128 |
129 | path.move( new Point(42, 13) );
130 | ```
131 |
132 | #### Возвращает `this`
133 |
134 | ## Метод rotate
135 |
136 | ```js
137 | Path rotate(number angle, LibCanvas.Point pivot);
138 | ```
139 | Вращает путь вокруг точки `pivot` на `angle` радиан.
140 |
141 | #### Пример
142 |
143 | ```js
144 | pathFrom = new Point(150, 200);
145 |
146 | path = new Path()
147 | .moveTo ( pathFrom )
148 | .curveTo([300, 200], [250, 150])
149 | .curveTo([200, 280], [290, 250])
150 | .curveTo( pathFrom , [220, 220]);
151 |
152 | // вращаем путь вокруг центра
153 | path.rotate( (6).degree(), path.center );
154 | ```
155 |
156 | #### Возвращает `this`
157 |
158 | ## Метод scale
159 |
160 | ```js
161 | Path scale(number power, LibCanvas.Point pivot);
162 | ```
163 |
164 | Увеличивает путь в `power` раз относительно точки `pivot`
165 |
166 | #### Пример
167 |
168 | pathFrom = new Point(150, 200);
169 |
170 | path = new Path()
171 | .moveTo ( pathFrom )
172 | .curveTo([300, 200], [250, 150])
173 | .curveTo([200, 280], [290, 250])
174 | .curveTo( pathFrom , [220, 220]);
175 |
176 | // Скукожили путь в два раза:
177 | path.scale( 0.5, path.center );
178 | ```
179 |
180 | #### Возвращает `this`
181 |
182 |
183 | ## Метод draw
184 |
185 | ```js
186 | Path draw(LibCanvas.Context2D ctx, String type);
187 | ```
188 |
189 | Отрисовывает путь в контекст, используя текущие настройки
190 |
191 | #### аргумент `type`
192 | Способ отрисовки. Может принимать значения `fill`, `stroke`, `clear`
193 |
194 | #### Пример
195 |
196 | ```js
197 | pathFrom = new Point(150, 200);
198 |
199 | path = new Path()
200 | .moveTo ( pathFrom )
201 | .curveTo([300, 200], [250, 150])
202 | .curveTo([200, 280], [290, 250])
203 | .curveTo( pathFrom , [220, 220]);
204 |
205 | var ctx = canvasElem
206 | .getContext('2d-libcanvas')
207 | .set({
208 | 'fillStyle': 'red',
209 | 'strokeStyle': 'black'
210 | });
211 | // Зальем красным многоугольник в контексте
212 | path.draw(ctx, 'fill');
213 | // Обведем черным многоугольник в контексте
214 | path.draw(ctx, 'stroke');
215 | ```
216 |
217 | Но такой способ рекомендуется использовать только если по какой либо причине не доступен следующий:
218 |
219 | ```js
220 | var ctx = canvasElem
221 | .getContext('2d-libcanvas')
222 | .fill (path, 'red')
223 | .stroke(path, 'black');
224 | ```
225 |
226 | #### Возвращает `this`
227 |
228 | ## Метод processPath
229 |
230 | ```js
231 | Path processPath(LibCanvas.Context2D ctx, bool noWrap = false)
232 | ```
233 |
234 | Проходит путь с помощью `ctx.moveTo`, `ctx.lineTo`, `ctx.curveTo`
235 |
236 | #### аргумент `noWrap`
237 | если указан в false(по умолчанию), то обрамляет с помощью `beginPath`, `endPath`
238 |
239 | #### Пример
240 |
241 | ```js
242 | path = new Path()
243 | .moveTo ([150, 200])
244 | .curveTo([300, 200], [250, 150])
245 | .curveTo([200, 280], [290, 250])
246 | .curveTo([150, 200], [220, 220])
247 | .processPath(ctx);
248 |
249 | // равносильно:
250 |
251 | ctx
252 | .beginPath()
253 | .moveTo ([150, 200])
254 | .curveTo([300, 200], [250, 150])
255 | .curveTo([200, 280], [290, 250])
256 | .curveTo([150, 200], [220, 220])
257 | .closePath();
258 | ```
259 |
260 | ## Метод clone
261 |
262 | ```js
263 | Path clone()
264 | ```
265 |
266 | Возвращает новый путь с склонированными точками
267 |
268 | #### Пример
269 |
270 | ```js
271 | path = new Path()
272 | .moveTo ([150, 200])
273 | .curveTo([300, 200], [250, 150])
274 | .curveTo([200, 280], [290, 250])
275 | .curveTo([150, 200], [220, 220]);
276 |
277 | var pathClone = path.clone();
278 | ```
279 |
280 | Внимание! Если в оригинальном пути несколько точек ссылались на один объект, то в новом пути, клоне, это будут разные, не связанные объекты точек.
--------------------------------------------------------------------------------
/Docs/Ru/Shapes/RoundedRectangle.md:
--------------------------------------------------------------------------------
1 | LibCanvas.Shapes.RoundedRectangle
2 | =================================
3 |
4 | `RoundedRectangle` - наследник фигуры `Rectangle`, отличается закруглёнными уголками. Полностью повторяет интерфейс родителя.
5 |
6 | #### Global
7 |
8 | После вызова LibCanvas.extract() можно использовать короткий алиас "RoundedRectangle"
9 |
10 | ## Свойства
11 |
12 | ### radius (set/get)
13 | радиус закругления уголков
14 |
15 | ## Метод setRadius
16 |
17 | ```js
18 | LibCanvas.Shapes.RoundedRectangle setRadius(int radius);
19 | ```
20 |
21 | Устанавливает радиус фигуры. Всего-лишь удобный алиас для `shape.radius = radius`.
22 |
23 | ```js
24 | var roundedRectangle = new RoundedRectangle( 20, 20, 50, 60 ).setRadius( 5 );
25 | ```
26 |
27 | #### Возвращает `this`
28 |
29 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## LibCanvas Javascript Framework
2 |
3 | *LibCanvas* is a free javascript library, based on [AtomJS framework](https://github.com/theshock/atomjs) and available under [LGPL](http://www.gnu.org/copyleft/lgpl.html)/[MIT](http://opensource.org/licenses/mit-license.php) License.
4 |
5 | #### [Examples](http://libcanvas.github.com/)
6 |
7 | Current objectives of the project:
8 |
9 | * Full documentation
10 | * Translation to English
11 |
12 | For consultation, write to shocksilien@gmail.com
13 |
14 | ## Возможности LibCanvas
15 |
16 | LibCanvas - библиотека для создания интерактивных приложений и игр на html5. Основные возможности:
17 |
18 | * [Расширенный 2D Context](https://github.com/theshock/libcanvas/blob/master/Docs/Ru/Core/Context2D.md):
19 | * Method chaining
20 | * Фигуры в качестве аргументов
21 | * Дополнительные методы
22 | * Именованные аргументы
23 |
24 | * [Геометрия](https://github.com/theshock/libcanvas/tree/master/Docs/Ru/Shapes)
25 | * [Действия с точками](https://github.com/theshock/libcanvas/blob/master/Docs/Ru/Core/Point.md)
26 | * Изменения фигуры
27 | * Пересечения
28 | * Базовые математические операции
29 |
30 |
31 | * [Фреймворк LibCanvas.App](https://github.com/theshock/libcanvas/tree/master/Docs/Ru/App)
32 | * Отрисовка только изменившихся частей холста
33 | * События мыши
34 | * Draggable/Droppable
35 | * Слои, внутренний zIndex
36 | * Быстрое смещение слоёв
37 |
38 |
39 | * Игровые движки
40 | * [Тайловый](https://github.com/theshock/libcanvas/blob/master/Docs/Ru/Engines/Tile/)
41 | * [Изометрический](https://github.com/theshock/libcanvas/blob/master/Docs/Ru/Engines/Isometric/Projection.md)
42 | * [Гексагональный](https://github.com/theshock/libcanvas/blob/master/Docs/Ru/Engines/Hex/Projection.md)
43 |
44 |
45 | * Дополнительные возможности (плагины)
46 | * [Спрайтовые анимации](https://github.com/theshock/libcanvas/tree/master/Docs/Ru/Plugins/Animation)
47 | * [Математическая модель кривых Безье](https://github.com/theshock/libcanvas/blob/master/Docs/Ru/Plugins/Curve.md) (для построения путей)
48 | * [Кривые с динамической шириной и цветом](https://github.com/theshock/libcanvas/blob/master/Docs/Ru/Plugins/Curves.md)
49 | * Спрайтовые шрифты
50 | * Рендеринг текстуры в проекции
51 |
52 | ## Интеграция
53 |
54 | * [Gem для Ruby on Rails](https://github.com/tanraya/libcanvas-rails)
55 |
56 | ## Переход на новую версию
57 |
58 | 21 декабря 2012-ого года была публично переведена в "master" главной ветка "declare".
59 |
60 | Предыдущая версия всё ещё доступна [в ветке previous](https://github.com/theshock/libcanvas/tree/previous), но больше не разрабатывается.
61 |
62 | Основные изменения в новой версии:
63 |
64 | * Основательно переписан код, убраны основные баги архитектуры и неочевидные вещи
65 | * Повышена производительность основных компонентов библиотеки
66 | * Более не требуется расширение прототипов. Оно всё ещё поддерживается, но теперь полностью на совести пользователя - библиотека не требует расширенных при помощи atom прототипов
67 | * Используется atom.declare вместо atom.Class в целях повышения производительности и облечения дебага
68 |
69 |
--------------------------------------------------------------------------------
/Source/.gitignore:
--------------------------------------------------------------------------------
1 | .idea
2 |
--------------------------------------------------------------------------------
/Source/App/App.js:
--------------------------------------------------------------------------------
1 | /*
2 | ---
3 |
4 | name: "App"
5 |
6 | description: "LibCanvas.App"
7 |
8 | license:
9 | - "[GNU Lesser General Public License](http://opensource.org/licenses/lgpl-license.php)"
10 | - "[MIT License](http://opensource.org/licenses/mit-license.php)"
11 |
12 | authors:
13 | - "Shock "
14 |
15 | requires:
16 | - LibCanvas
17 |
18 | provides: App
19 |
20 | ...
21 | */
22 |
23 | /** @class App */
24 | LibCanvas.declare( 'LibCanvas.App', 'App', {
25 | initialize: function (settings) {
26 | this.bindMethods( 'tick' );
27 |
28 | this.layers = [];
29 | this.settings = new Settings({ appendTo: 'body' }).set(settings);
30 | this.container = new App.Container(
31 | this.settings.subset(['simple', 'size', 'appendTo'])
32 | );
33 | this.resources = new Registry();
34 |
35 | atom.frame.add( this.tick );
36 | },
37 |
38 | destroy: function () {
39 | atom.array.invoke( this.layers, 'destroy' );
40 | atom.frame.remove( this.tick );
41 | this.container.destroy();
42 | },
43 |
44 | get rectangle () {
45 | return this.container.rectangle;
46 | },
47 |
48 | /**
49 | * return "-1" if left is higher, "+1" if right is higher & 0 is they are equals
50 | * @param {App.Element} left
51 | * @param {App.Element} right
52 | * @returns {number}
53 | */
54 | zIndexCompare: function (left, right, inverted) {
55 | var leftZ, rightZ, factor = inverted ? -1 : +1;
56 |
57 | if (!left || !left .layer) throw new TypeError( 'Wrong left element' );
58 | if (!right || !right.layer) throw new TypeError( 'Wrong right element' );
59 |
60 |
61 | leftZ = left.layer.dom.zIndex;
62 | rightZ = right.layer.dom.zIndex;
63 |
64 | if (leftZ > rightZ) return -1 * factor;
65 | if (leftZ < rightZ) return +1 * factor;
66 |
67 | leftZ = left.zIndex;
68 | rightZ = right.zIndex;
69 |
70 | if (leftZ > rightZ) return -1 * factor;
71 | if (leftZ < rightZ) return +1 * factor;
72 |
73 | return 0;
74 | },
75 |
76 | createLayer: function (settings) {
77 | if (this.settings.get('simple') && this.layers.length) {
78 | throw new Error('You can create only one layer in "Simple" mode');
79 | }
80 |
81 | var layer = new App.Layer(this, settings);
82 | this.layers.push(layer);
83 | return layer;
84 | },
85 |
86 | tick: function (time) {
87 | atom.array.invoke(this.layers, 'tick', time);
88 | }
89 | });
90 |
91 | var App = LibCanvas.App;
--------------------------------------------------------------------------------
/Source/App/Behavior.js:
--------------------------------------------------------------------------------
1 | /*
2 | ---
3 |
4 | name: "App.Behavior"
5 |
6 | description: ""
7 |
8 | license:
9 | - "[GNU Lesser General Public License](http://opensource.org/licenses/lgpl-license.php)"
10 | - "[MIT License](http://opensource.org/licenses/mit-license.php)"
11 |
12 | authors:
13 | - "Shock "
14 |
15 | requires:
16 | - LibCanvas
17 |
18 | provides: App.Behavior
19 |
20 | ...
21 | */
22 |
23 | /** @class App.Behavior */
24 | var Behavior = declare( 'LibCanvas.App.Behavior', {
25 |
26 | eventName: null,
27 |
28 | initialize: function (element, callback) {
29 | this.element = element;
30 | this.events = element.events;
31 | this.eventArgs(callback);
32 | },
33 |
34 | started: false,
35 |
36 | /** @private */
37 | changeStatus: function (status){
38 | if (this.started == status) {
39 | return false;
40 | } else {
41 | this.started = status;
42 | return true;
43 | }
44 | },
45 |
46 | /** @private */
47 | eventArgs: function (callback) {
48 | if (this.eventName && atom.core.isFunction(callback)) {
49 | this.events.add( this.eventName, callback );
50 | }
51 | return this;
52 | },
53 |
54 | /** @private */
55 | getMouse: function (handler, strict) {
56 | var mouse = this.element.layer.app.resources.get(
57 | handler ? 'mouseHandler' : 'mouse'
58 | );
59 |
60 | if (strict && !mouse) {
61 | throw new Error('No mouse in element');
62 | }
63 |
64 | return mouse;
65 | }
66 |
67 | });
--------------------------------------------------------------------------------
/Source/App/Behaviors/Behaviors.js:
--------------------------------------------------------------------------------
1 | /*
2 | ---
3 |
4 | name: "App.Behaviors"
5 |
6 | description: "DEPRECATED"
7 |
8 | license:
9 | - "[GNU Lesser General Public License](http://opensource.org/licenses/lgpl-license.php)"
10 | - "[MIT License](http://opensource.org/licenses/mit-license.php)"
11 |
12 | authors:
13 | - "Shock "
14 |
15 | requires:
16 | - LibCanvas
17 |
18 | provides: App.Behaviors
19 |
20 | ...
21 | */
22 |
23 | /** @class App.Behaviors */
24 | var Behaviors = declare( 'LibCanvas.App.Behaviors', {
25 | behaviors: {},
26 |
27 | initialize: function (element) {
28 | this.element = element;
29 | this.behaviors = {};
30 | },
31 |
32 | /** @param [handler=false] */
33 | getMouse: function (handler) {
34 | return this.element.layer.app.resources.get(
35 | handler ? 'mouseHandler' : 'mouse'
36 | );
37 | },
38 |
39 | add: function (Behaviour, args) {
40 | if (typeof Behaviour == 'string') {
41 | Behaviour = this.constructor[Behaviour];
42 | }
43 |
44 | return this.behaviors[Behaviour.index] = new Behaviour(this, slice.call( arguments, 1 ));
45 | },
46 |
47 | get: function (name) {
48 | return this.behaviors[name] || null;
49 | },
50 |
51 | startAll: function (arg) {
52 | this.invoke('start', arguments);
53 | return this;
54 | },
55 |
56 | stopAll: function () {
57 | this.invoke('stop', arguments);
58 | return this;
59 | },
60 |
61 | /** @private */
62 | invoke: function (method, args) {
63 | var i, b = this.behaviors;
64 | for (i in b) if (b.hasOwnProperty(i)) {
65 | b[i][method].apply(b[i], args);
66 | }
67 | return this;
68 | }
69 |
70 | }).own({
71 | attach: function (target, types, arg) {
72 | target.behaviors = new Behaviors(target);
73 |
74 | types.forEach(function (type) {
75 | target.behaviors.add(type, arg);
76 | });
77 |
78 | return target.behaviors;
79 | }
80 | });
81 |
82 |
83 | declare( 'LibCanvas.App.Behaviors.Behavior', {
84 | started: false,
85 |
86 | /** @private */
87 | eventArgs: function (args, eventName) {
88 | if (atom.core.isFunction(args[0])) {
89 | this.events.add( eventName, args[0] );
90 | }
91 | },
92 |
93 | /** @private */
94 | changeStatus: function (status){
95 | if (this.started == status) {
96 | return false;
97 | } else {
98 | this.started = status;
99 | return true;
100 | }
101 | }
102 | });
--------------------------------------------------------------------------------
/Source/App/Behaviors/Clickable.js:
--------------------------------------------------------------------------------
1 | /*
2 | ---
3 |
4 | name: "App.Behaviors.Clickable"
5 |
6 | description: "DEPRECATED"
7 |
8 | license:
9 | - "[GNU Lesser General Public License](http://opensource.org/licenses/lgpl-license.php)"
10 | - "[MIT License](http://opensource.org/licenses/mit-license.php)"
11 |
12 | authors:
13 | - "Shock "
14 |
15 | requires:
16 | - LibCanvas
17 | - App.Behaviors
18 |
19 | provides: App.Behaviors.Clickable
20 |
21 | ...
22 | */
23 |
24 | new function () {
25 |
26 | function setValueFn (name, val) {
27 | var result = [name, val];
28 | return function () {
29 | if (this[name] != val) {
30 | this[name] = val;
31 | this.events.fire('statusChange', result);
32 | }
33 | };
34 | }
35 |
36 | return declare( 'LibCanvas.App.Behaviors.Clickable', App.Behaviors.Behavior, {
37 |
38 | callbacks: {
39 | 'mouseover' : setValueFn('hover' , true ),
40 | 'mouseout' : (function () {
41 | var dehover = setValueFn('hover' , false),
42 | deactive = setValueFn('active', false);
43 |
44 | return function (e) {
45 | dehover .call(this, e);
46 | deactive.call(this, e);
47 | };
48 | })(),
49 | 'mousedown' : setValueFn('active', true ),
50 | 'mouseup' : setValueFn('active', false)
51 | },
52 |
53 | initialize: function (behaviors, args) {
54 | this.events = behaviors.element.events;
55 | this.eventArgs(args, 'statusChange');
56 | },
57 |
58 | start: function () {
59 | if (!this.changeStatus(true)) return this;
60 |
61 | this.eventArgs(arguments, 'statusChange');
62 | this.events.add(this.callbacks);
63 | },
64 |
65 | stop: function () {
66 | if (!this.changeStatus(false)) return this;
67 |
68 | this.events.remove(this.callbacks);
69 | }
70 |
71 | }).own({ index: 'clickable' });
72 |
73 | };
--------------------------------------------------------------------------------
/Source/App/Behaviors/Draggable.js:
--------------------------------------------------------------------------------
1 | /*
2 | ---
3 |
4 | name: "App.Behaviors.Draggable"
5 |
6 | description: "DEPRECATED"
7 |
8 | license:
9 | - "[GNU Lesser General Public License](http://opensource.org/licenses/lgpl-license.php)"
10 | - "[MIT License](http://opensource.org/licenses/mit-license.php)"
11 |
12 | authors:
13 | - "Shock "
14 |
15 | requires:
16 | - LibCanvas
17 | - App.Behaviors
18 |
19 | provides: App.Behaviors.Draggable
20 |
21 | ...
22 | */
23 |
24 | declare( 'LibCanvas.App.Behaviors.Draggable', App.Behaviors.Behavior, {
25 | stopDrag: [ 'up', 'out' ],
26 |
27 | initialize: function (behaviors, args) {
28 | this.bindMethods([ 'onStop', 'onDrag', 'onStart' ]);
29 |
30 | this.behaviors = behaviors;
31 | this.element = behaviors.element;
32 | if (!atom.core.isFunction(this.element.move)) {
33 | throw new TypeError( 'Element ' + this.element + ' must has «move» method' );
34 | }
35 | this.events = behaviors.element.events;
36 | this.eventArgs(args, 'moveDrag');
37 | },
38 |
39 | bindMouse: function (method) {
40 | var mouse = this.mouse, stop = this.stopDrag;
41 |
42 | mouse.events
43 | [method]( 'move', this.onDrag )
44 | [method]( stop , this.onStop );
45 |
46 | return mouse;
47 | },
48 |
49 | start: function () {
50 | if (!this.changeStatus(true)) return this;
51 |
52 | this.mouse = this.behaviors.getMouse();
53 | if (!this.mouse) throw new Error('No mouse in element');
54 | this.eventArgs(arguments, 'moveDrag');
55 | this.events.add( 'mousedown', this.onStart );
56 | },
57 |
58 | stop: function () {
59 | if (!this.changeStatus(false)) return this;
60 |
61 | this.events.remove( 'mousedown', this.onStart );
62 | },
63 |
64 | /** @private */
65 | onStart: function (e) {
66 | if (e.button !== 0) return;
67 |
68 | this.bindMouse('add');
69 | this.events.fire('startDrag', [ e ]);
70 | },
71 |
72 | /** @private */
73 | onDrag: function (e) {
74 | if (!this.element.layer) {
75 | return this.onStop(e, true);
76 | }
77 |
78 | var delta = this.behaviors.getMouse().delta;
79 | this.element.move( delta );
80 | this.events.fire('moveDrag', [delta, e]);
81 | },
82 |
83 | /** @private */
84 | onStop: function (e, forced) {
85 | if (e.button === 0 || forced === true) {
86 | this.bindMouse('remove');
87 | this.events.fire('stopDrag', [ e ]);
88 | }
89 | }
90 | }).own({ index: 'draggable' });
--------------------------------------------------------------------------------
/Source/App/Clickable.js:
--------------------------------------------------------------------------------
1 | /*
2 | ---
3 |
4 | name: "App.Clickable"
5 |
6 | description: "Provides interface for clickable canvas objects"
7 |
8 | license:
9 | - "[GNU Lesser General Public License](http://opensource.org/licenses/lgpl-license.php)"
10 | - "[MIT License](http://opensource.org/licenses/mit-license.php)"
11 |
12 | authors:
13 | - "Shock "
14 |
15 | requires:
16 | - LibCanvas
17 | - App.Behavior
18 |
19 | provides: App.Clickable
20 |
21 | ...
22 | */
23 |
24 | /** @class App.Clickable */
25 | var Clickable = declare( 'LibCanvas.App.Clickable', App.Behavior, {
26 |
27 | eventName: 'statusChange',
28 |
29 | callbacks: {
30 | mousedown: function (e) {
31 | Clickable.setValue(this, 'active', true , e);
32 | },
33 | mouseup : function (e) {
34 | Clickable.setValue(this, 'active', false, e);
35 | },
36 | mouseover: function (e) {
37 | Clickable.setValue(this, 'hover' , true , e);
38 | },
39 | mouseout : function (e) {
40 | Clickable.setValue(this, 'hover' , false, e);
41 | Clickable.setValue(this, 'active', false, e);
42 | }
43 | },
44 |
45 | start: function (callback) {
46 | if (this.changeStatus(true)) {
47 | this.eventArgs(callback);
48 | this.events.add(this.callbacks);
49 | }
50 | return this;
51 | },
52 |
53 | stop: function () {
54 | if (this.changeStatus(false)) {
55 | this.events.remove(this.callbacks);
56 | }
57 | return this;
58 | }
59 |
60 | });
61 |
62 | Clickable.setValue = function (element, name, val, event) {
63 | if (element[name] != val) {
64 | element[name] = val;
65 | element.events.fire(
66 | Clickable.prototype.eventName,
67 | [name, val, event]
68 | );
69 | }
70 | };
--------------------------------------------------------------------------------
/Source/App/Container.js:
--------------------------------------------------------------------------------
1 | /*
2 | ---
3 |
4 | name: "App.Container"
5 |
6 | description: ""
7 |
8 | license:
9 | - "[GNU Lesser General Public License](http://opensource.org/licenses/lgpl-license.php)"
10 | - "[MIT License](http://opensource.org/licenses/mit-license.php)"
11 |
12 | authors:
13 | - "Shock "
14 |
15 | requires:
16 | - LibCanvas
17 | - App
18 |
19 | provides: App.Container
20 |
21 | ...
22 | */
23 |
24 | /**
25 | * @class App.Container
26 | * @private */
27 | declare( 'LibCanvas.App.Container', {
28 | /** @private
29 | * @property {Size} */
30 | currentSize: null,
31 |
32 | /** @property {App.Dom[]} */
33 | doms: [],
34 |
35 | wrapper: null,
36 | bounds : null,
37 |
38 | initialize: function (settings) {
39 | this.doms = [];
40 | this.settings = new Settings(settings);
41 | this.currentSize = new Size(this.settings.get('size') || [0,0]);
42 |
43 | this.isSimple = this.settings.get('simple');
44 |
45 | if (this.isSimple) {
46 | this.createWrappersSimple();
47 | } else {
48 | this.createWrappers();
49 | }
50 | },
51 |
52 | get rectangle () {
53 | var size = this.size;
54 | return new Rectangle(0, 0, size.width, size.height);
55 | },
56 |
57 | set size(size) {
58 | if (this.isSimple) {
59 | this.doms[0].size = size;
60 | } else {
61 | size = this.currentSize.set(size).toObject();
62 | this.wrapper.css(size);
63 | this.bounds .css(size);
64 | }
65 | },
66 |
67 | get size() {
68 | return this.currentSize;
69 | },
70 |
71 | destroy: function () {
72 | if (!this.isSimple) {
73 | this.wrapper.destroy();
74 | }
75 | return this;
76 | },
77 |
78 | createDom: function (settings) {
79 | var dom = new App.Dom( this, settings );
80 | this.doms.push(dom);
81 | return dom;
82 | },
83 |
84 | appendTo: function (element) {
85 | if (element) this.wrapper.appendTo( element );
86 | return this;
87 | },
88 |
89 | /** @private */
90 | createWrappersSimple: function () {
91 | var size = this.currentSize.toObject();
92 |
93 | this.wrapper = atom.dom(LibCanvas.buffer(size,true));
94 | this.bounds = this.wrapper;
95 |
96 | this.wrapper
97 | .addClass('libcanvas-app-simple')
98 | .appendTo( this.settings.get('appendTo') )
99 | },
100 |
101 | /** @private */
102 | createWrappers: function () {
103 | var size = this.currentSize.toObject();
104 |
105 | this.wrapper = atom.dom.create('div')
106 | .css(size)
107 | .addClass('libcanvas-app')
108 | .appendTo(this.settings.get( 'appendTo' ));
109 |
110 | this.bounds = atom.dom.create('div')
111 | .css({
112 | overflow: 'hidden',
113 | position: 'absolute'
114 | })
115 | .css(size)
116 | .appendTo(this.wrapper);
117 | }
118 | });
--------------------------------------------------------------------------------
/Source/App/Dom.js:
--------------------------------------------------------------------------------
1 | /*
2 | ---
3 |
4 | name: "App.Dom"
5 |
6 | description: ""
7 |
8 | license:
9 | - "[GNU Lesser General Public License](http://opensource.org/licenses/lgpl-license.php)"
10 | - "[MIT License](http://opensource.org/licenses/mit-license.php)"
11 |
12 | authors:
13 | - "Shock "
14 |
15 | requires:
16 | - LibCanvas
17 | - App
18 |
19 | provides: App.Dom
20 |
21 | ...
22 | */
23 |
24 |
25 | /** @class App.Dom */
26 | declare( 'LibCanvas.App.Dom', {
27 | /** @private
28 | * @property {Size} */
29 | currentSize: null,
30 |
31 | /** @private
32 | * @property {App.Container} */
33 | container: null,
34 |
35 | /** @private
36 | * @property {Point} */
37 | shift: null,
38 |
39 | /** @private */
40 | z: 0,
41 |
42 | initialize: function (container, settings) {
43 | this.container = container;
44 | this.settings = new Settings(settings);
45 | this.shift = new Point(0,0);
46 | this.name = this.settings.get('name') || '';
47 | this.createSize();
48 | this.createElement();
49 | },
50 |
51 | set zIndex (z) {
52 | this.z = z;
53 | if (!this.container.isSimple) {
54 | this.element.css('zIndex', z);
55 | }
56 | },
57 |
58 | get zIndex () {
59 | return this.z;
60 | },
61 |
62 | set size(size) {
63 | size = this.currentSize.set(size);
64 |
65 | this.canvas.width = size.width ;
66 | this.canvas.height = size.height;
67 | },
68 |
69 | get size() {
70 | return this.currentSize;
71 | },
72 |
73 | destroy: function () {
74 | this.element.destroy();
75 | this.size = new Size(0,0);
76 | },
77 |
78 | /**
79 | * @param {Point} shift
80 | * @returns {App.Dom}
81 | */
82 | addShift: function ( shift ) {
83 | var newShift = this.getShift().move( shift );
84 | this.element.css({
85 | marginLeft: newShift.x,
86 | marginTop : newShift.y
87 | });
88 | return this;
89 | },
90 |
91 | /**
92 | * @param {Point} shift
93 | * @returns {App.Dom}
94 | */
95 | setShift: function (shift) {
96 | return this.addShift( this.shift.diff(shift) );
97 | },
98 |
99 | /** @returns {Point} */
100 | getShift: function () {
101 | if (this.container.isSimple) {
102 | throw new Error('Shift not available in Simple mode');
103 | }
104 |
105 | return this.shift;
106 | },
107 |
108 | /** @private */
109 | createSize: function () {
110 | var size = this.settings.get('size');
111 |
112 | if (this.container.isSimple) {
113 | this.currentSize = this.container.size;
114 | if (size) {
115 | this.currentSize.set(size);
116 | }
117 | } else {
118 | this.currentSize = size || this.container.size.clone();
119 | }
120 |
121 |
122 | },
123 |
124 | /** @private */
125 | createElement: function () {
126 | if (this.container.isSimple) {
127 | this.createElementSimple();
128 | } else {
129 | this.createElementNormal();
130 | }
131 | },
132 |
133 | /** @private */
134 | createElementNormal: function () {
135 | this.canvas = new LibCanvas.Buffer(this.size, true);
136 |
137 | this.element = atom.dom(this.canvas);
138 |
139 | this.element
140 | .attr({ 'data-name': this.name })
141 | .css ({ 'position' : 'absolute' })
142 | .appendTo( this.container.bounds );
143 |
144 | this.zIndex = this.settings.get('zIndex') || 0;
145 | },
146 |
147 | /** @private */
148 | createElementSimple: function () {
149 | this.element = this.container.wrapper;
150 |
151 | this.canvas = this.element.first;
152 | this.canvas.width = this.size.width;
153 | this.canvas.height = this.size.height;
154 | }
155 | });
--------------------------------------------------------------------------------
/Source/App/Draggable.js:
--------------------------------------------------------------------------------
1 | /*
2 | ---
3 |
4 | name: "App.Draggable"
5 |
6 | description: "When object implements LibCanvas.Draggable interface dragging made possible"
7 |
8 | license:
9 | - "[GNU Lesser General Public License](http://opensource.org/licenses/lgpl-license.php)"
10 | - "[MIT License](http://opensource.org/licenses/mit-license.php)"
11 |
12 | authors:
13 | - "Shock "
14 |
15 | requires:
16 | - LibCanvas
17 | - App.Behavior
18 |
19 | provides: App.Draggable
20 |
21 | ...
22 | */
23 |
24 | /** @class App.Draggable */
25 | declare( 'LibCanvas.App.Draggable', App.Behavior, {
26 |
27 | eventName: 'moveDrag',
28 |
29 | stopDrag: [ 'up', 'out' ],
30 |
31 | initialize: function method (element, callback) {
32 | this.bindMethods([ 'onStop', 'onDrag', 'onStart' ]);
33 |
34 | method.previous.call( this, element, callback );
35 | },
36 |
37 | start: function (callback) {
38 | if (this.changeStatus(true)) {
39 | this.mouse = this.getMouse(false, true);
40 | this.eventArgs(callback);
41 | this.events.add( 'mousedown', this.onStart )
42 | }
43 | return this;
44 | },
45 |
46 | stop: function () {
47 | if (this.changeStatus(false)) {
48 | this.events.remove( 'mousedown', this.onStart );
49 | }
50 | return this;
51 | },
52 |
53 | /** @private */
54 | bindMouse: function (method) {
55 | var mouse = this.mouse, stop = this.stopDrag;
56 |
57 | mouse.events
58 | [method]( 'move', this.onDrag )
59 | [method]( stop , this.onStop );
60 |
61 | return mouse;
62 | },
63 |
64 | /** @private */
65 | onStart: function (e) {
66 | if (e.button !== 0) return;
67 |
68 | this.bindMouse('add');
69 | this.events.fire('startDrag', [ e ]);
70 | },
71 |
72 | /** @private */
73 | onDrag: function (e) {
74 | if (!this.element.layer) {
75 | return this.onStop(e, true);
76 | }
77 |
78 | var delta = this.mouse.delta;
79 | this.element.distanceMove( delta );
80 | this.events.fire('moveDrag', [delta, e]);
81 | },
82 |
83 | /** @private */
84 | onStop: function (e, forced) {
85 | if (e.button === 0 || forced === true) {
86 | this.bindMouse('remove');
87 | this.events.fire('stopDrag', [ e ]);
88 | }
89 | }
90 | });
--------------------------------------------------------------------------------
/Source/App/Dragger.js:
--------------------------------------------------------------------------------
1 | /*
2 | ---
3 |
4 | name: "App.Dragger"
5 |
6 | description: ""
7 |
8 | license:
9 | - "[GNU Lesser General Public License](http://opensource.org/licenses/lgpl-license.php)"
10 | - "[MIT License](http://opensource.org/licenses/mit-license.php)"
11 |
12 | authors:
13 | - "Shock "
14 |
15 | requires:
16 | - LibCanvas
17 | - App
18 | - App.LayerShift
19 |
20 | provides: App.Dragger
21 |
22 | ...
23 | */
24 | /** @class App.Dragger */
25 | declare( 'LibCanvas.App.Dragger', {
26 | initialize: function (mouse) {
27 | this.bindMethods([ 'dragStart', 'dragStop', 'dragMove' ]);
28 | this.events = new Events(this);
29 |
30 | this.mouse = mouse;
31 | this.shifts = [];
32 |
33 | this._events = {
34 | down: this.dragStart,
35 | up : this.dragStop,
36 | out : this.dragStop,
37 | move: this.dragMove
38 | };
39 | },
40 |
41 | addLayerShift: function (shift) {
42 | this.shifts.push( shift );
43 | return this;
44 | },
45 |
46 | started: false,
47 |
48 | start: function (callback) {
49 | if (callback !== undefined) {
50 | this.callback = callback;
51 | }
52 | this.started = true;
53 | this.mouse.events.add( this._events );
54 | return this;
55 | },
56 |
57 | stop: function () {
58 | this.started = false;
59 | this.mouse.events.remove( this._events );
60 | return this;
61 | },
62 |
63 | /** @private */
64 | dragStart: function (e) {
65 | if (!this.shouldStartDrag(e)) return;
66 |
67 | for (var i = this.shifts.length; i--;) {
68 | this.shifts[i].layer.stop();
69 | }
70 | this.drag = true;
71 | this.events.fire( 'start', [ e ]);
72 | },
73 | /** @private */
74 | dragStop: function (e) {
75 | if (!this.drag) return;
76 |
77 | for (var i = this.shifts.length; i--;) {
78 | var shift = this.shifts[i];
79 | shift.addElementsShift();
80 | shift.layer.start();
81 | }
82 |
83 | this.drag = false;
84 | this.events.fire( 'stop', [ e ]);
85 | },
86 | /** @private */
87 | dragMove: function (e) {
88 | if (!this.drag) return;
89 | for (var i = this.shifts.length; i--;) {
90 | this.shifts[i].addShift(this.mouse.delta);
91 | }
92 | },
93 | /** @private */
94 | shouldStartDrag: function (e) {
95 | if (!this.started) return false;
96 |
97 | return this.callback ? this.callback(e) : true;
98 | }
99 | });
--------------------------------------------------------------------------------
/Source/App/Element.js:
--------------------------------------------------------------------------------
1 | /*
2 | ---
3 |
4 | name: "App.Element"
5 |
6 | description: "LibCanvas.Layer"
7 |
8 | license:
9 | - "[GNU Lesser General Public License](http://opensource.org/licenses/lgpl-license.php)"
10 | - "[MIT License](http://opensource.org/licenses/mit-license.php)"
11 |
12 | authors:
13 | - "Shock "
14 |
15 | requires:
16 | - LibCanvas
17 | - App
18 |
19 | provides: App.Element
20 |
21 | ...
22 | */
23 |
24 | /** @class App.Element */
25 | declare( 'LibCanvas.App.Element', {
26 |
27 | layer : null,
28 | zIndex : 0,
29 | renderer: null,
30 | settings: {},
31 | opacity : 1,
32 | opacityThreshold: 0.01,
33 |
34 | /** @constructs */
35 | initialize: function (layer, settings) {
36 | this.bindMethods([ 'redraw', 'destroy' ]);
37 |
38 | this.events = new Events(this);
39 | this.settings = new Settings({ hidden: false })
40 | .set(this.settings)
41 | .set(settings)
42 | .addEvents(this.events);
43 | layer.addElement( this );
44 |
45 | var ownShape = this.shape && this.shape != this.constructor.prototype.shape;
46 |
47 | if (ownShape || this.settings.get('shape')) {
48 | if (!ownShape) this.shape = this.settings.get('shape');
49 | this.saveCurrentBoundingShape();
50 | }
51 | if (this.settings.get('zIndex') != null) {
52 | this.zIndex = Number( this.settings.get('zIndex') );
53 | }
54 |
55 | this.configure();
56 | },
57 |
58 | configure: function () {
59 | return this;
60 | },
61 |
62 | previousBoundingShape: null,
63 |
64 | get currentBoundingShape () {
65 | return this.shape.getBoundingRectangle().fillToPixel();
66 | },
67 |
68 | redraw: function () {
69 | if (this.layer) {
70 | this.layer.redrawElement( this );
71 | }
72 | return this;
73 | },
74 |
75 | destroy: function () {
76 | if (this.layer) {
77 | this.layer.rmElement( this );
78 | }
79 | return this;
80 | },
81 |
82 | distanceMove: function (point) {
83 | this.shape.move(point);
84 | return this;
85 | },
86 |
87 | hasPoint: function (point) {
88 | return this.shape.hasPoint( point );
89 | },
90 |
91 | isTriggerPoint: function (point) {
92 | if (this.hasMousePoint) {
93 | return this.hasMousePoint(point);
94 | } else {
95 | return this.hasPoint(point);
96 | }
97 | },
98 |
99 | addShift: function (shift) {
100 | this.shape.move( shift );
101 | if (this.previousBoundingShape)
102 | this.previousBoundingShape.move( shift );
103 | return this;
104 | },
105 |
106 | isVisible: function () {
107 | return !this.settings.get('hidden') && this.opacity > this.opacityThreshold;
108 | },
109 |
110 | onUpdate: function (time) {
111 | return this;
112 | },
113 |
114 | clearPrevious: function ( ctx ) {
115 | if (this.previousBoundingShape) ctx.clear( this.previousBoundingShape );
116 | return this;
117 | },
118 |
119 | saveCurrentBoundingShape: function () {
120 | var shape = this.currentBoundingShape;
121 | this.previousBoundingShape = shape.fillToPixel ?
122 | shape.clone().fillToPixel() : shape.clone().grow( 2 );
123 | return this;
124 | },
125 |
126 | renderToWrapper: function (ctx, resources) {
127 | if (this.opacity < this.opacityThreshold) {
128 | return;
129 | }
130 | ctx.save();
131 | if (this.opacity + this.opacityThreshold < 1) {
132 | ctx.set({ globalAlpha: this.opacity });
133 | }
134 | this.renderTo(ctx, resources);
135 | ctx.restore();
136 | return this;
137 | },
138 |
139 | renderTo: function (ctx, resources) {
140 | if (this.renderer) {
141 | this.renderer.renderTo(ctx, resources);
142 | }
143 | return this;
144 | }
145 | });
--------------------------------------------------------------------------------
/Source/App/Layer.js:
--------------------------------------------------------------------------------
1 | /*
2 | ---
3 |
4 | name: "App.Layer"
5 |
6 | description: ""
7 |
8 | license:
9 | - "[GNU Lesser General Public License](http://opensource.org/licenses/lgpl-license.php)"
10 | - "[MIT License](http://opensource.org/licenses/mit-license.php)"
11 |
12 | authors:
13 | - "Shock "
14 |
15 | requires:
16 | - LibCanvas
17 | - App
18 | - App.Dom
19 |
20 | provides: App.Layer
21 |
22 | ...
23 | */
24 |
25 |
26 | /** @class App.Layer */
27 | declare( 'LibCanvas.App.Layer', {
28 |
29 | initialize: function (app, settings) {
30 | this.settings = new Settings({
31 | invoke : app.settings.get('invoke'),
32 | intersection: 'auto' // auto|manual|all
33 | }).set(settings);
34 |
35 | this.intersection = this.settings.get('intersection');
36 | this.redrawAllMode = this.intersection === 'all' || this.intersection === 'full';
37 |
38 | this.app = app;
39 | this.elements = [];
40 | this.redraw = this.redrawAllMode ? this.elements : [];
41 | this.clear = [];
42 | this.createDom();
43 | },
44 |
45 | get ctx () {
46 | return this.dom.canvas.ctx;
47 | },
48 |
49 | /** @private */
50 | stopped: false,
51 |
52 | destroy: function () {
53 | atom.array.invoke( this.elements, 'destroy' );
54 | this.dom.destroy();
55 | },
56 |
57 | hide: function () {
58 | this.dom.element.css({ display: 'none' });
59 | return this.stop();
60 | },
61 |
62 | show: function () {
63 | this.dom.element.css({ display: '' });
64 | return this.stop();
65 | },
66 |
67 | start: function () {
68 | this.stopped = false;
69 | return this;
70 | },
71 |
72 | stop: function () {
73 | this.stopped = true;
74 | return this;
75 | },
76 |
77 | redrawAll: function () {
78 | atom.array.invoke( this.elements, 'redraw' );
79 | return this;
80 | },
81 |
82 | /** @private */
83 | tick: function (time) {
84 | if (this.stopped) return this;
85 |
86 | if (this.settings.get( 'invoke' )) {
87 | this.sortElements();
88 | this.updateAll(time);
89 | }
90 |
91 | if (this.needUpdate) {
92 | this.draw();
93 | this.needUpdate = false;
94 | }
95 |
96 | return this;
97 | },
98 |
99 |
100 | /** @private */
101 | draw: function () {
102 | var
103 | intersection = this.intersection,
104 | ctx = this.dom.canvas.ctx,
105 | resources = this.app.resources;
106 |
107 | if (intersection === 'full') {
108 | ctx.clearAll();
109 | } else {
110 | if (intersection === 'auto') {
111 | this.addIntersections();
112 | } else if (intersection === 'all') {
113 | atom.array.invoke(this.clear, 'clearPrevious', ctx, resources);
114 | }
115 |
116 | atom.array.invoke(this.redraw, 'clearPrevious', ctx, resources);
117 | }
118 |
119 | this.drawElements(this.redraw, ctx, resources);
120 |
121 | if (intersection === 'all') {
122 | this.clear.length = 0;
123 | } else if (intersection !== 'full') {
124 | this.redraw.length = 0;
125 | }
126 | },
127 |
128 | /** @private */
129 | drawElements: function (elements, ctx, resources) {
130 | // draw elements with the lower zIndex first
131 | atom.array.sortBy( elements, 'zIndex' );
132 |
133 | for (var i = elements.length; i--;) {
134 | this.drawElement(elements[i], ctx, resources);
135 | }
136 | },
137 |
138 | /** @private */
139 | drawElement: function (elem, ctx, resources) {
140 | if (elem.layer == this) {
141 | elem.redrawRequested = false;
142 | if (elem.isVisible()) {
143 | elem.renderToWrapper( ctx, resources );
144 | if (this.intersection !== 'full') {
145 | elem.saveCurrentBoundingShape();
146 | }
147 | }
148 | }
149 | },
150 |
151 | /** @private */
152 | sortElements: function () {
153 | atom.array.sortBy( this.elements, 'zIndex' );
154 | },
155 |
156 | /** @private */
157 | updateAll: function (time) {
158 | atom.array.invoke( this.elements, 'onUpdate', time, this.app.resources );
159 | },
160 |
161 | /** @private */
162 | needUpdate: false,
163 |
164 | /** @private */
165 | createDom: function () {
166 | this.dom = this.app.container.createDom(
167 | this.settings.subset([ 'name', 'zIndex', 'size' ])
168 | );
169 | },
170 |
171 | /** @private */
172 | addElement: function (element) {
173 | if (element.layer != this) {
174 | if (element.layer) {
175 | element.layer.rmElement( element );
176 | }
177 |
178 | element.layer = this;
179 | this.elements.push( element );
180 | this.redrawElement( element );
181 | }
182 | return this;
183 | },
184 |
185 | /** @private */
186 | rmElement: function (element) {
187 | if (element.layer == this) {
188 | if (this.intersection === 'all') {
189 | this.needUpdate = true;
190 | this.clear.push(element);
191 | } else {
192 | this.redrawElement( element );
193 | }
194 | atom.core.eraseOne( this.elements, element );
195 | element.layer = null;
196 | }
197 | return this;
198 | },
199 |
200 | /** @private */
201 | redrawElement: function (element) {
202 | if (element.layer == this && !element.redrawRequested) {
203 | this.needUpdate = true;
204 | element.redrawRequested = true;
205 | if (!this.redrawAllMode) {
206 | this.redraw.push( element );
207 | }
208 | }
209 | return this;
210 | },
211 |
212 | /** @private */
213 | addIntersections: function () {
214 | var i, elem, layer = this;
215 |
216 | for (i = 0; i < this.redraw.length; i++) {
217 | elem = this.redraw[i];
218 |
219 | this.findIntersections(elem.previousBoundingShape, elem, this.redrawElement);
220 | this.findIntersections(elem. currentBoundingShape, elem, function (e) {
221 | // we need to redraw it, only if it will be over our element
222 | if (e.zIndex > elem.zIndex) {
223 | layer.redrawElement( e );
224 | }
225 | });
226 | }
227 | },
228 |
229 | /** @private */
230 | findIntersections: function (shape, elem, fn) {
231 | if (!shape) return;
232 |
233 | var i = this.elements.length, e;
234 | while (i--) {
235 | e = this.elements[i];
236 | // check if we need also `e.currentBoundingShape.intersect( shape )`
237 | if (e != elem && e.isVisible() &&
238 | e.previousBoundingShape &&
239 | e.previousBoundingShape.intersect( shape )
240 | ) fn.call( this, e );
241 | }
242 | }
243 |
244 | });
245 |
--------------------------------------------------------------------------------
/Source/App/LayerShift.js:
--------------------------------------------------------------------------------
1 | /*
2 | ---
3 |
4 | name: "App.LayerShift"
5 |
6 | description: ""
7 |
8 | license:
9 | - "[GNU Lesser General Public License](http://opensource.org/licenses/lgpl-license.php)"
10 | - "[MIT License](http://opensource.org/licenses/mit-license.php)"
11 |
12 | authors:
13 | - "Shock "
14 |
15 | requires:
16 | - LibCanvas
17 | - App
18 |
19 | provides: App.LayerShift
20 |
21 | ...
22 | */
23 |
24 | /** @class App.LayerShift */
25 | declare( 'LibCanvas.App.LayerShift', {
26 |
27 | initialize: function (layer) {
28 | this.layer = layer;
29 | this.shift = new Point(0, 0);
30 | this.elementsShift = new Point(0, 0);
31 | },
32 |
33 | /**
34 | * @private
35 | * @property {Point}
36 | */
37 | shift: null,
38 |
39 | /**
40 | * @private
41 | * @property {Point}
42 | */
43 | elementsShift: null,
44 |
45 | /**
46 | * @param {Point} shift
47 | */
48 | addElementsShift: function (shift) {
49 | if (!shift) {
50 | shift = this.elementsShift.diff(this.shift);
51 | } else {
52 | shift = Point(shift);
53 | }
54 | var e = this.layer.elements, i = e.length;
55 | while (i--) e[i].addShift(shift);
56 | this.elementsShift.move(shift);
57 | return this;
58 | },
59 |
60 | /**
61 | * @private
62 | * @property {LibCanvas.Shapes.Rectangle}
63 | */
64 | limitShift: null,
65 |
66 | /**
67 | * @param {Rectangle} limitShift
68 | */
69 | setLimitShift: function (limitShift) {
70 | this.limitShift = limitShift ? Rectangle(limitShift) : null;
71 | return this;
72 | },
73 |
74 | /**
75 | * @param {Point} shift
76 | */
77 | addShift: function ( shift, withElements ) {
78 | shift = new Point( shift );
79 |
80 | var limit = this.limitShift, current = this.shift;
81 | if (limit) {
82 | shift.x = atom.number.limit(shift.x, limit.from.x - current.x, limit.to.x - current.x);
83 | shift.y = atom.number.limit(shift.y, limit.from.y - current.y, limit.to.y - current.y);
84 | }
85 |
86 | current.move( shift );
87 | this.layer.dom.addShift( shift );
88 | this.layer.dom.canvas.ctx.translate( shift, true );
89 | if (withElements) this.addElementsShift( shift );
90 | return this;
91 | },
92 |
93 | /**
94 | * @param {Point} shift
95 | */
96 | setShift: function (shift, withElements) {
97 | return this.addShift( this.shift.diff(shift), withElements );
98 | },
99 |
100 | /**
101 | * @returns {Point}
102 | */
103 | getShift: function () {
104 | return this.shift;
105 | }
106 | });
--------------------------------------------------------------------------------
/Source/App/Light/Element.js:
--------------------------------------------------------------------------------
1 | /*
2 | ---
3 |
4 | name: "App.Light.Element"
5 |
6 | description: ""
7 |
8 | license:
9 | - "[GNU Lesser General Public License](http://opensource.org/licenses/lgpl-license.php)"
10 | - "[MIT License](http://opensource.org/licenses/mit-license.php)"
11 |
12 | authors:
13 | - "Shock "
14 |
15 | requires:
16 | - LibCanvas
17 | - App
18 | - App.Light
19 |
20 | provides: App.Light.Element
21 |
22 | ...
23 | */
24 |
25 | /** @class App.Light.Vector */
26 | App.Light.Element = atom.declare( 'LibCanvas.App.Light.Element', App.Element, {
27 |
28 | get behaviors () {
29 | throw new Error( 'Please, use `element.clickable` & `element.draggable` instead' );
30 | },
31 |
32 | clickable : null,
33 | draggable : null,
34 | animatable: null,
35 |
36 | configure: function () {
37 | this.clickable = new App.Clickable(this, this.redraw);
38 | this.draggable = new App.Draggable(this, this.redraw);
39 | this.animatable = new atom.Animatable(this);
40 | this.animate = this.animatable.animate;
41 |
42 | if (this.settings.get('mouse') !== false) {
43 | this.listenMouse();
44 | }
45 | },
46 |
47 | /**
48 | * Override by Animatable method
49 | */
50 | animate: function(){},
51 |
52 | listenMouse: function (unsubscribe) {
53 | var method = unsubscribe ? 'unsubscribe' : 'subscribe';
54 | return this.layer.app.resources.get('mouseHandler')[method](this);
55 | },
56 |
57 | destroy: function method () {
58 | this.listenMouse(true);
59 | return method.previous.call(this);
60 | }
61 | });
--------------------------------------------------------------------------------
/Source/App/Light/Image.js:
--------------------------------------------------------------------------------
1 | /*
2 | ---
3 |
4 | name: "App.Light.Image"
5 |
6 | description: ""
7 |
8 | license:
9 | - "[GNU Lesser General Public License](http://opensource.org/licenses/lgpl-license.php)"
10 | - "[MIT License](http://opensource.org/licenses/mit-license.php)"
11 |
12 | authors:
13 | - "Shock "
14 |
15 | requires:
16 | - LibCanvas
17 | - App.Light.Element
18 |
19 | provides: App.Light.Image
20 |
21 | ...
22 | */
23 |
24 | /** @class App.Light.Image */
25 | App.Light.Image = atom.declare( 'LibCanvas.App.Light.Image', App.Light.Element, {
26 | get currentBoundingShape () {
27 | return this.shape.clone().fillToPixel();
28 | },
29 |
30 | renderTo: function (ctx) {
31 | ctx.drawImage({
32 | image: this.settings.get('image'),
33 | draw : this.shape
34 | })
35 | }
36 | });
--------------------------------------------------------------------------------
/Source/App/Light/Light.js:
--------------------------------------------------------------------------------
1 | /*
2 | ---
3 |
4 | name: "App.Light"
5 |
6 | description: "LibCanvas.App.Light"
7 |
8 | license:
9 | - "[GNU Lesser General Public License](http://opensource.org/licenses/lgpl-license.php)"
10 | - "[MIT License](http://opensource.org/licenses/mit-license.php)"
11 |
12 | authors:
13 | - "Shock "
14 |
15 | requires:
16 | - LibCanvas
17 | - App
18 |
19 | provides: App.Light
20 |
21 | ...
22 | */
23 |
24 | /** @class App.Light */
25 | declare( 'LibCanvas.App.Light', {
26 |
27 | initialize: function (size, settings) {
28 | var mouse, mouseHandler;
29 |
30 | this.settings = new Settings({
31 | size : Size.from(size),
32 | name : 'main',
33 | mouse : true,
34 | invoke : false,
35 | simple : true,
36 | appendTo: 'body',
37 | intersection: 'auto'
38 | }).set(settings || {});
39 |
40 | this.app = new App( this.settings.subset(['size', 'appendTo', 'simple']) );
41 | this.layer = this.app.createLayer(this.settings.subset(['name','invoke','intersection']));
42 | if (this.settings.get('mouse') === true) {
43 | mouse = new Mouse(this.app.container.bounds);
44 | mouseHandler = new App.MouseHandler({ mouse: mouse, app: this.app });
45 |
46 | this.app.resources.set({ mouse: mouse, mouseHandler: mouseHandler });
47 | }
48 | },
49 |
50 | createVector: function (shape, settings) {
51 | settings = atom.core.append({ shape:shape }, settings || {});
52 | return new App.Light.Vector(this.layer, settings);
53 | },
54 |
55 | createText: function (shape, style, settings) {
56 | settings = atom.core.append({ shape: shape, style: style }, settings);
57 | return new App.Light.Text(this.layer, settings);
58 | },
59 |
60 | createImage: function (shape, image, settings) {
61 | return new App.Light.Image(this.layer, atom.core.append({
62 | shape: shape, image: image
63 | }, settings));
64 | },
65 |
66 | get mouse () {
67 | return this.app.resources.get( 'mouse' );
68 | },
69 |
70 | get mouseHandler () {
71 | return this.app.resources.get( 'mouseHandler' );
72 | }
73 |
74 | });
--------------------------------------------------------------------------------
/Source/App/Light/Text.js:
--------------------------------------------------------------------------------
1 | /*
2 | ---
3 |
4 | name: "App.Light.Text"
5 |
6 | description: ""
7 |
8 | license:
9 | - "[GNU Lesser General Public License](http://opensource.org/licenses/lgpl-license.php)"
10 | - "[MIT License](http://opensource.org/licenses/mit-license.php)"
11 |
12 | authors:
13 | - "Shock "
14 |
15 | requires:
16 | - LibCanvas
17 | - App
18 | - App.Light
19 |
20 | provides: App.Light.Text
21 |
22 | ...
23 | */
24 |
25 | /** @class App.Light.Text */
26 | atom.declare( 'LibCanvas.App.Light.Text', App.Element, {
27 | get style () {
28 | return this.settings.get('style') || {};
29 | },
30 |
31 | get content () {
32 | return this.style.text || '';
33 | },
34 |
35 | set content (c) {
36 | if (Array.isArray(c)) c = c.join('\n');
37 |
38 | if (c != this.content) {
39 | this.redraw();
40 | this.style.text = String(c) || '';
41 | }
42 | },
43 |
44 | renderTo: function (ctx) {
45 | var bg = this.settings.get('background');
46 |
47 | if (bg) ctx.fill( this.shape, bg );
48 | ctx.text(atom.core.append({
49 | to : this.shape
50 | }, this.style));
51 | }
52 | });
--------------------------------------------------------------------------------
/Source/App/Light/Vector.js:
--------------------------------------------------------------------------------
1 | /*
2 | ---
3 |
4 | name: "App.Light.Vector"
5 |
6 | description: ""
7 |
8 | license:
9 | - "[GNU Lesser General Public License](http://opensource.org/licenses/lgpl-license.php)"
10 | - "[MIT License](http://opensource.org/licenses/mit-license.php)"
11 |
12 | authors:
13 | - "Shock "
14 |
15 | requires:
16 | - App.Light.Element
17 |
18 | provides: App.Light.Vector
19 |
20 | ...
21 | */
22 |
23 | /** @class App.Light.Vector */
24 | App.Light.Vector = atom.declare( 'LibCanvas.App.Light.Vector', App.Light.Element, {
25 | active: false,
26 | hover : false,
27 |
28 | configure: function method () {
29 | method.previous.call(this);
30 |
31 | this.style = {};
32 | this.styleActive = {};
33 | this.styleHover = {};
34 | },
35 |
36 | setStyle: function (key, values) {
37 | if (typeof key == 'object') {
38 | values = key;
39 | key = '';
40 | }
41 | key = 'style' + atom.string.ucfirst(key);
42 |
43 | atom.core.append( this[key], values );
44 | return this.redraw();
45 | },
46 |
47 | getStyle: function (type) {
48 | if (!this.style) return null;
49 |
50 | var
51 | active = (this.active || null) && this.styleActive[type],
52 | hover = (this.hover || null) && this.styleHover [type],
53 | plain = this.style[type];
54 |
55 | return active != null ? active :
56 | hover != null ? hover :
57 | plain != null ? plain : null;
58 | },
59 |
60 | get currentBoundingShape () {
61 | var
62 | br = this.shape.getBoundingRectangle(),
63 | lw = this.getStyle('stroke') && (this.getStyle('lineWidth') || 1);
64 |
65 | return lw ? br.fillToPixel().grow(2 * Math.ceil(lw)) : br;
66 | },
67 |
68 | renderTo: function (ctx) {
69 | var fill = this.getStyle('fill'),
70 | stroke = this.getStyle('stroke'),
71 | lineW = this.getStyle('lineWidth'),
72 | opacity = this.getStyle('opacity');
73 |
74 | if (opacity === 0) return this;
75 |
76 | ctx.save();
77 | if (opacity) ctx.globalAlpha = atom.number.round(opacity, 3);
78 | if (fill) ctx.fill(this.shape, fill);
79 | if (stroke) {
80 | ctx.lineWidth = lineW || 1;
81 | ctx.stroke(this.shape, stroke);
82 | }
83 | ctx.restore();
84 | return this;
85 | }
86 | });
--------------------------------------------------------------------------------
/Source/App/MouseHandler.js:
--------------------------------------------------------------------------------
1 | /*
2 | ---
3 |
4 | name: "App.MouseHandler"
5 |
6 | description: "LibCanvas.App.MouseHandler"
7 |
8 | license:
9 | - "[GNU Lesser General Public License](http://opensource.org/licenses/lgpl-license.php)"
10 | - "[MIT License](http://opensource.org/licenses/mit-license.php)"
11 |
12 | authors:
13 | - "Shock "
14 |
15 | requires:
16 | - LibCanvas
17 | - Mouse
18 | - App
19 | - App.PointSearch
20 |
21 | provides: App.MouseHandler
22 |
23 | ...
24 | */
25 |
26 | /** @class App.MouseHandler */
27 | declare( 'LibCanvas.App.MouseHandler', {
28 |
29 | events: 'down up move out dblclick contextmenu wheel'.split(' '),
30 |
31 | /** @private */
32 | mouse: null,
33 |
34 | /** @constructs */
35 | initialize: function (settings) {
36 | var handler = this;
37 |
38 | handler.settings = new Settings(settings);
39 | handler.lastMouseMove = [];
40 | handler.lastMouseDown = [];
41 | handler.subscribers = [];
42 |
43 | handler.app = handler.settings.get('app');
44 | handler.mouse = handler.settings.get('mouse');
45 | handler.compareFunction = function (left, right) {
46 | return handler.app.zIndexCompare(left, right, true);
47 | };
48 | handler.search =
49 | handler.settings.get('search') ||
50 | new App.PointSearch();
51 |
52 | this.events.forEach(function (type) {
53 | handler.mouse.events.add( type, function (e) {
54 | handler.event(type, e);
55 | });
56 | });
57 | },
58 |
59 | stop: function () {
60 | this.stopped = true;
61 | return this;
62 | },
63 |
64 | start: function () {
65 | this.stopped = false;
66 | return this;
67 | },
68 |
69 | subscribe : function (elem) {
70 | if (this.subscribers.indexOf(elem) == -1) {
71 | this.subscribers.push(elem);
72 | this.search.add(elem);
73 | }
74 | return this;
75 | },
76 |
77 | unsubscribe : function (elem) {
78 | var index = this.subscribers.indexOf(elem);
79 | if (index != -1) {
80 | this.subscribers.splice(index, 1);
81 | atom.core.eraseOne(this.lastMouseDown, elem);
82 | atom.core.eraseOne(this.lastMouseMove, elem);
83 | this.search.remove(elem);
84 | }
85 | return this;
86 | },
87 |
88 | unsubscribeAll: function () {
89 | this.subscribers.length = 0;
90 | this.search.removeAll();
91 | return this;
92 | },
93 |
94 | fall: function () {
95 | this.falling = true;
96 | return this;
97 | },
98 |
99 | getOverElements: function () {
100 | if (!this.mouse.inside) return [];
101 |
102 | var
103 | elements = this.search.findByPoint( this.mouse.point ),
104 | i = elements.length;
105 |
106 | while (i--) if (!elements[i].layer) {
107 | this.unsubscribe(elements[i]);
108 | elements.splice(i, 1);
109 | }
110 |
111 | return elements.sort( this.compareFunction );
112 | },
113 |
114 | /** @private */
115 | stopped: false,
116 |
117 | /** @private */
118 | falling: false,
119 |
120 | /** @private */
121 | checkFalling: function () {
122 | var value = this.falling;
123 | this.falling = false;
124 | return value;
125 | },
126 |
127 | /** @private */
128 | event: function (type, e) {
129 | if (this.stopped) return;
130 |
131 | var method = ['dblclick', 'contextmenu', 'wheel'].indexOf( type ) >= 0
132 | ? 'forceEvent' : 'parseEvent';
133 |
134 | return this[method]( type, e );
135 | },
136 |
137 | /** @private */
138 | parseEvent: function (type, event) {
139 | if (type == 'down') this.lastMouseDown.length = 0;
140 |
141 | var i, elem,
142 | elements = this.getOverElements(),
143 | stopped = false,
144 | eventArgs = [event],
145 | isChangeCoordEvent = (type == 'move' || type == 'out');
146 |
147 | // В первую очередь - обрабатываем реальный mouseout с элементов
148 | if (isChangeCoordEvent) {
149 | this.informOut(eventArgs, elements);
150 | }
151 |
152 | for (i = elements.length; i--;) {
153 | elem = elements[i];
154 | // мышь над элементом, сообщаем о mousemove
155 | // о mouseover, mousedown, click, если необходимо
156 | if (!stopped) {
157 | if (this.fireElem( type, elem, eventArgs )) {
158 | stopped = true;
159 | if (!isChangeCoordEvent) break;
160 | }
161 | // предыдущий элемент принял событие на себя
162 | // необходимо сообщить остальным элементам под ним о mouseout
163 | // Но только если это событие передвижения или выхода за границы холста
164 | // а не активационные, как маусдаун или маусап
165 | } else {
166 | this.stoppedElem(elem, eventArgs);
167 | }
168 | }
169 |
170 | return stopped;
171 | },
172 |
173 | /** @private */
174 | informOut: function (eventArgs, elements) {
175 | var
176 | elem,
177 | lastMove = this.lastMouseMove,
178 | i = lastMove.length;
179 | while (i--) {
180 | elem = lastMove[i];
181 | if (elements.indexOf(elem) < 0) {
182 | elem.events.fire( 'mouseout', eventArgs );
183 | lastMove.splice(i, 1);
184 | }
185 | }
186 | },
187 |
188 | /** @private */
189 | stoppedElem: function (elem, eventArgs) {
190 | var
191 | lastMove = this.lastMouseMove,
192 | index = lastMove.indexOf(elem);
193 | if (index > -1) {
194 | elem.events.fire( 'mouseout', eventArgs );
195 | lastMove.splice(index, 1);
196 | }
197 | },
198 |
199 | /** @private */
200 | fireElem: function (type, elem, eventArgs) {
201 | var
202 | lastDown = this.lastMouseDown,
203 | lastMove = this.lastMouseMove;
204 |
205 | if (type == 'move') {
206 | if (lastMove.indexOf(elem) < 0) {
207 | elem.events.fire( 'mouseover', eventArgs );
208 | lastMove.push( elem );
209 | }
210 | } else if (type == 'down') {
211 | lastDown.push(elem);
212 | // If mouseup on this elem and last mousedown was on this elem - click
213 | } else if (type == 'up' && lastDown.indexOf(elem) > -1) {
214 | elem.events.fire( 'click', eventArgs );
215 | }
216 | elem.events.fire( 'mouse' + type, eventArgs );
217 |
218 | return !this.checkFalling();
219 | },
220 |
221 | /** @private */
222 | forceEvent: function (type, event) {
223 | var
224 | elements = this.getOverElements(),
225 | i = elements.length;
226 | while (i--) {
227 | elements[i].events.fire( type, [ event ]);
228 | if (!this.checkFalling()) {
229 | break;
230 | }
231 | }
232 | }
233 |
234 | });
--------------------------------------------------------------------------------
/Source/App/PointSearch.js:
--------------------------------------------------------------------------------
1 | /*
2 | ---
3 |
4 | name: "App.PointSearch"
5 |
6 | description: "LibCanvas.App.ElementsMouseSearch"
7 |
8 | license:
9 | - "[GNU Lesser General Public License](http://opensource.org/licenses/lgpl-license.php)"
10 | - "[MIT License](http://opensource.org/licenses/mit-license.php)"
11 |
12 | authors:
13 | - "Shock "
14 |
15 | requires:
16 | - LibCanvas
17 | - App
18 |
19 | provides: App.PointSearch
20 |
21 | ...
22 | */
23 |
24 | /** @class App.PointSearch */
25 | declare( 'LibCanvas.App.PointSearch', {
26 |
27 | initialize: function () {
28 | this.elements = [];
29 | },
30 |
31 | add: function (elem) {
32 | this.elements.push( elem );
33 | return this;
34 | },
35 |
36 | remove: function (elem) {
37 | atom.core.eraseOne( this.elements, elem );
38 | return this;
39 | },
40 |
41 | removeAll: function () {
42 | this.elements.length = 0;
43 | return this;
44 | },
45 |
46 | findByPoint: function (point) {
47 | var e = this.elements, i = e.length, result = [];
48 | while (i--) if (e[i].isTriggerPoint( point )) {
49 | result.push(e[i]);
50 | }
51 | return result;
52 | }
53 |
54 | });
55 |
56 | /** @deprecated */
57 | App.ElementsMouseSearch = App.PointSearch;
--------------------------------------------------------------------------------
/Source/Context/DrawImage.js:
--------------------------------------------------------------------------------
1 | /*
2 | ---
3 |
4 | name: "Context.DrawImage"
5 |
6 | description: "LibCanvas.Context2D adds new canvas context '2d-libcanvas'"
7 |
8 | license:
9 | - "[GNU Lesser General Public License](http://opensource.org/licenses/lgpl-license.php)"
10 | - "[MIT License](http://opensource.org/licenses/mit-license.php)"
11 |
12 | authors:
13 | - "Shock "
14 |
15 | requires:
16 | - LibCanvas
17 | - Point
18 | - Size
19 | - Shapes.Rectangle
20 | - Shapes.Circle
21 |
22 | provides: Context.DrawImage
23 |
24 | ...
25 | */
26 |
27 | new function () {
28 |
29 | var toPoint = Point.from, toRectangle = Rectangle.from;
30 |
31 | /** @class LibCanvas.Context.DrawImage */
32 | LibCanvas.declare( 'LibCanvas.Context.DrawImage', {
33 | initialize: function (context) {
34 | this.context = context;
35 | this.ctx2d = context.ctx2d;
36 | },
37 |
38 | drawImage: function (args) {
39 | var a, center, from, draw, crop, scale, image, pivot, angle;
40 |
41 | if (this.checkNonObject(args)) return;
42 |
43 | a = args[0];
44 |
45 | image = a.image;
46 | angle = a.angle;
47 | scale = a.scale && toPoint(a.scale);
48 | center = a.center && toPoint(a.center);
49 | from = a.from && toPoint(a.from);
50 | draw = a.draw && toRectangle(a.draw);
51 | crop = a.crop && toRectangle(a.crop);
52 |
53 | if (! atom.dom.isElement(image) ) throw new TypeError('Wrong image in Context.DrawImage');
54 | if (! (center || from || draw) ) throw new TypeError('Wrong arguments in Context.DrawImage');
55 |
56 | pivot = this.getTransformPivot(
57 | angle, scale, image,
58 | center, from, draw
59 | );
60 |
61 | if (pivot) this.transform(pivot, angle, scale);
62 | draw ?
63 | this.drawRect (image, draw, crop , a.optimize) :
64 | this.drawPoint(image, from, center, a.optimize);
65 | if (pivot) this.ctx2d.restore();
66 |
67 | return this.context;
68 | },
69 |
70 | /** @private */
71 | run: function (array) {
72 | this.ctx2d.drawImage.apply( this.ctx2d, array );
73 | },
74 | /** @private */
75 | transform: function (center, angle, scale) {
76 | this.ctx2d.save();
77 | if (angle) this.context.rotate(angle, center);
78 | if (scale) this.context.scale (scale, center);
79 | },
80 | /** @private */
81 | checkNonObject: function (args) {
82 | var image = args[0], length = args.length, target;
83 | if (length > 2) {
84 | this.run(args);
85 | return true;
86 | }
87 | if (length == 2) {
88 | target = args[1];
89 |
90 | if (target instanceof Point) {
91 | this.drawPoint(image, target);
92 | return true;
93 | }
94 | if (target instanceof Rectangle) {
95 | this.drawRect(image, target);
96 | return true;
97 | }
98 |
99 | throw new Error('Unknown second argument in Context.DrawImage');
100 | }
101 |
102 | if (length == 0) {
103 | throw new Error('Empty arguments in Context.DrawImage');
104 | }
105 |
106 | if (atom.dom.isElement(image)) {
107 | this.ctx2d.drawImage(image, 0, 0);
108 | return true;
109 | }
110 |
111 | return false;
112 | },
113 | /** @private */
114 | drawPoint: function (image, from, center, optimize) {
115 | var
116 | point = center || from,
117 | fromX = point.x,
118 | fromY = point.y;
119 |
120 | if (center) {
121 | fromX -= image.width / 2;
122 | fromY -= image.height / 2;
123 | }
124 |
125 | if (optimize) {
126 | fromX = Math.round(fromX);
127 | fromY = Math.round(fromY);
128 | }
129 |
130 | this.ctx2d.drawImage(image, fromX, fromY);
131 | },
132 | /** @private */
133 | drawRect: function (image, rect, crop, optimize) {
134 | var deltaX, deltaY, fromX, fromY;
135 |
136 | if (crop) {
137 | this.ctx2d.drawImage( image,
138 | crop.from.x, crop.from.y, crop.width, crop.height,
139 | rect.from.x, rect.from.y, rect.width, rect.height
140 | );
141 | return;
142 | }
143 |
144 | if (optimize) {
145 | fromX = Math.round(rect.from.x);
146 | fromY = Math.round(rect.from.y);
147 | deltaX = Math.abs(rect.width - image.width );
148 | deltaY = Math.abs(rect.height - image.width );
149 |
150 | if (deltaX < 1.1 && deltaY < 1.1) {
151 | this.ctx2d.drawImage(image, fromX, fromY);
152 | } else {
153 | this.ctx2d.drawImage(image, fromX, fromY,
154 | Math.round(rect.width),
155 | Math.round(rect.height)
156 | );
157 | }
158 | return;
159 | }
160 |
161 | this.ctx2d.drawImage( image,
162 | rect.from.x, rect.from.y,
163 | rect.width , rect.height
164 | );
165 | },
166 | /** @private */
167 | getTransformPivot: function (angle, scale, image, center, from, draw) {
168 | if ( !angle && (!scale || (scale.x == 1 && scale.y == 1)) ) return null;
169 |
170 | if (center) return center;
171 | if ( draw ) return draw.center;
172 |
173 | return new Point(from.x + image.width/2, from.y + image.height/2);
174 | }
175 | });
176 |
177 | };
178 |
--------------------------------------------------------------------------------
/Source/Context/Gradients.js:
--------------------------------------------------------------------------------
1 | /*
2 | ---
3 |
4 | name: "Context.Gradients"
5 |
6 | description: "LibCanvas.Context2D adds new canvas context '2d-libcanvas'"
7 |
8 | license:
9 | - "[GNU Lesser General Public License](http://opensource.org/licenses/lgpl-license.php)"
10 | - "[MIT License](http://opensource.org/licenses/mit-license.php)"
11 |
12 | authors:
13 | - "Shock "
14 |
15 | requires:
16 | - LibCanvas
17 | - Point
18 | - Size
19 | - Shapes.Rectangle
20 | - Shapes.Circle
21 |
22 | provides: Context.Gradients
23 |
24 | ...
25 | */
26 |
27 | new function () {
28 |
29 | var toPoint = Point.from, toRectangle = Rectangle.from, toCircle = Circle.from;
30 |
31 |
32 | var addColorStopSource = document
33 | .createElement('canvas')
34 | .getContext('2d')
35 | .createLinearGradient(0,0,1,1)
36 | .addColorStop;
37 |
38 | var addColorStop = function (colors) {
39 | if (typeof colors == 'object') {
40 | for (var position in colors) if (colors.hasOwnProperty(position)) {
41 | addColorStopSource.call( this, parseFloat(position), colors[position] );
42 | }
43 | } else {
44 | addColorStopSource.apply( this, arguments );
45 | }
46 | return this;
47 | };
48 |
49 |
50 | var fixGradient = function (grad) {
51 | grad.addColorStop = addColorStop;
52 | return grad;
53 | };
54 |
55 | /** @class LibCanvas.Context.Gradients */
56 | LibCanvas.declare( 'LibCanvas.Context.Gradients', {
57 | initialize: function (context) {
58 | this.context = context;
59 | this.ctx2d = context.ctx2d;
60 | },
61 |
62 | /** @returns {CanvasGradient} */
63 | createGradient: function (from, to, colors) {
64 | var gradient;
65 | if ( from instanceof Rectangle ) {
66 | colors = to;
67 | gradient = this.createLinearGradient([ from ]);
68 | } else if (from instanceof Circle) {
69 | gradient = this.createRadialGradient([ from, to ]);
70 | } else if (from instanceof Point) {
71 | gradient = this.createLinearGradient([ from, to ]);
72 | } else {
73 | throw new Error('Unknown arguments in Context.Gradients.createGradient');
74 | }
75 | if (typeof colors == 'object') gradient.addColorStop( colors );
76 | return gradient;
77 | },
78 | /** @returns {CanvasGradient} */
79 | createRectangleGradient: function (rectangle, colors) {
80 | rectangle = toRectangle( rectangle );
81 |
82 | var from = rectangle.from, line = new Line( rectangle.bottomLeft, rectangle.topRight );
83 |
84 | return this.createGradient( from, line.perpendicular(from).scale(2, from), colors );
85 | },
86 | /** @returns {CanvasGradient} */
87 | createLinearGradient : function (a) {
88 | var from, to;
89 | if (a.length != 4) {
90 | if (a.length == 2) {
91 | to = toPoint(a[0]);
92 | from = toPoint(a[1]);
93 | } else if (a.length == 1) {
94 | to = toPoint(a[0].to);
95 | from = toPoint(a[0].from);
96 | } else {
97 | throw new TypeError('Wrong arguments.length in the Context.createLinearGradient');
98 | }
99 | a = [from.x, from.y, to.x, to.y];
100 | }
101 | return fixGradient( this.ctx2d.createLinearGradient.apply(this.ctx2d, a) );
102 | },
103 | /** @returns {CanvasGradient} */
104 | createRadialGradient: function (a) {
105 | var points, c1, c2, length = a.length;
106 | if (length == 1 || length == 2) {
107 | if (length == 2) {
108 | c1 = toCircle( a[0] );
109 | c2 = toCircle( a[1] );
110 | } else {
111 | c1 = toCircle( a.start );
112 | c2 = toCircle( a.end );
113 | }
114 | points = [c1.center.x, c1.center.y, c1.radius, c2.center.x, c2.center.y, c2.radius];
115 | } else if (length == 6) {
116 | points = a;
117 | } else {
118 | throw new TypeError('Wrong arguments.length in the Context.createRadialGradient');
119 | }
120 |
121 | return fixGradient( this.ctx2d.createRadialGradient.apply(this.ctx2d, points) );
122 | }
123 | });
124 |
125 | };
126 |
--------------------------------------------------------------------------------
/Source/Context/Path.js:
--------------------------------------------------------------------------------
1 | /*
2 | ---
3 |
4 | name: "Context.Path"
5 |
6 | description: "LibCanvas.Context2D adds new canvas context '2d-libcanvas'"
7 |
8 | license:
9 | - "[GNU Lesser General Public License](http://opensource.org/licenses/lgpl-license.php)"
10 | - "[MIT License](http://opensource.org/licenses/mit-license.php)"
11 |
12 | authors:
13 | - "Shock "
14 |
15 | requires:
16 | - LibCanvas
17 | - Point
18 | - Size
19 | - Shapes.Circle
20 |
21 | provides: Context.Path
22 |
23 | ...
24 | */
25 |
26 | new function () {
27 |
28 | var toPoint = Point.from, toCircle = Circle.from;
29 |
30 |
31 | /** @class LibCanvas.Context.Path */
32 | LibCanvas.declare( 'LibCanvas.Context.Path', {
33 | initialize: function (context) {
34 | this.context = context;
35 | this.ctx2d = context.ctx2d;
36 | },
37 |
38 |
39 | /** @returns {Context2D} */
40 | arc : function (a) {
41 |
42 | if (a.length > 1) {
43 | return this.ctx2d.arc.apply(this.ctx2d, a);
44 | } else if (!a[0].circle) {
45 | throw new TypeError('Wrong arguments in CanvasContext.arc');
46 | }
47 |
48 | var f = a[0], circle, angle, angleStart, angleEnd, angleSize;
49 | circle = toCircle(f.circle);
50 | angle = f.angle;
51 |
52 | if (Array.isArray(angle)) {
53 | angleStart = angle[0];
54 | angleEnd = angle[1];
55 | } else {
56 | angleStart = angle.start;
57 | angleEnd = angle.end;
58 | angleSize = angle.size;
59 |
60 | if (angleSize == null) {
61 | // do nothing
62 | } else if (angleEnd == null) {
63 | angleEnd = angleSize + angleStart;
64 | } else if (angleStart == null) {
65 | angleStart = angleEnd - angleSize;
66 | }
67 | }
68 | this.ctx2d.arc(
69 | circle.center.x, circle.center.y, circle.radius,
70 | angleStart, angleEnd, !!(f.anticlockwise || f.acw)
71 | );
72 | return this.context;
73 | },
74 |
75 | /** @returns {Context2D} */
76 | arcTo : function () {
77 | // @todo Beauty arguments
78 | this.ctx2d.arcTo.apply(this.ctx2d, arguments);
79 | return this.context;
80 | },
81 | /** @returns {Context2D} */
82 | curveTo: function (a) {
83 | var p, l, to, curve = a[0];
84 |
85 | if (typeof curve == 'number') {
86 | if (a.length === 4) {
87 | return this.quadraticCurveTo(a);
88 | } else if (a.length === 6) {
89 | return this.bezierCurveTo(a);
90 | }
91 | } else if (a.length > 1) {
92 | p = atom.array.from( a ).map(toPoint);
93 | to = p.shift()
94 | } else {
95 | p = atom.array.from( curve.points ).map(toPoint);
96 | to = toPoint(curve.to);
97 | }
98 |
99 | l = p.length;
100 |
101 | if (l == 2) {
102 | this.ctx2d.bezierCurveTo(
103 | p[0].x, p[0].y, p[1].x, p[1].y, to.x, to.y
104 | );
105 | } else if (l == 1) {
106 | this.ctx2d.quadraticCurveTo(
107 | p[0].x, p[0].y, to.x, to.y
108 | );
109 | } else {
110 | this.ctx2d.lineTo(to.x, to.y);
111 | }
112 | return this.context;
113 | },
114 | /** @returns {Context2D} */
115 | quadraticCurveTo : function (a) {
116 | if (a.length == 4) {
117 | this.ctx2d.quadraticCurveTo.apply(this.ctx2d, a);
118 | return this.context;
119 | } else {
120 | a = a.length == 2 ? {p:a[0], to:a[1]} : a[0];
121 | return this.curveTo([{
122 | to: a.to,
123 | points: [a.p]
124 | }]);
125 | }
126 | },
127 | /** @returns {Context2D} */
128 | bezierCurveTo : function (a) {
129 | if (a.length == 6) {
130 | this.ctx2d.bezierCurveTo.apply(this.ctx2d, a);
131 | return this.context;
132 | } else {
133 | a = a.length == 3 ? {p1:a[0], p2:a[1], to:a[2]} : a[0];
134 | return this.curveTo([{
135 | to: a.to,
136 | points: [a.p1, a.p2]
137 | }]);
138 | }
139 | },
140 | isPointInPath: function (x, y) {
141 | if (y == null) {
142 | x = toPoint(x);
143 | y = x.y;
144 | x = x.x;
145 | }
146 | return this.ctx2d.isPointInPath(x, y);
147 | }
148 |
149 | });
150 |
151 | };
152 |
--------------------------------------------------------------------------------
/Source/Context/Pixels.js:
--------------------------------------------------------------------------------
1 | /*
2 | ---
3 |
4 | name: "Context.Pixels"
5 |
6 | description: "LibCanvas.Context2D adds new canvas context '2d-libcanvas'"
7 |
8 | license:
9 | - "[GNU Lesser General Public License](http://opensource.org/licenses/lgpl-license.php)"
10 | - "[MIT License](http://opensource.org/licenses/mit-license.php)"
11 |
12 | authors:
13 | - "Shock "
14 |
15 | requires:
16 | - LibCanvas
17 | - Point
18 | - Size
19 | - Shapes.Rectangle
20 | - Shapes.Circle
21 |
22 | provides: Context.Pixels
23 |
24 | ...
25 | */
26 |
27 | new function () {
28 |
29 | var toPoint = Point.from, toRectangle = Rectangle.from, size1x1 = new Size(1,1);
30 |
31 |
32 | /** @class LibCanvas.Context.Pixels */
33 | LibCanvas.declare( 'LibCanvas.Context.Pixels', {
34 | initialize: function (context) {
35 | this.context = context;
36 | this.ctx2d = context.ctx2d;
37 | },
38 |
39 | // image data
40 | /** @returns {CanvasPixelArray} */
41 | createImageData : function (w, h) {
42 | if (w == null) {
43 | w = this.context.width;
44 | h = this.context.height;
45 | } else if (h == null) {
46 | if (w.width == null && w.height == null) {
47 | throw new TypeError('Wrong argument in the Context.createImageData');
48 | } else {
49 | h = w.height;
50 | w = w.width;
51 | }
52 | }
53 |
54 | return this.ctx2d.createImageData(w, h);
55 | },
56 |
57 | /** @returns {Context2D} */
58 | putImageData : function (a) {
59 | var put = {}, args, rect;
60 |
61 | switch (a.length) {
62 | case 1: {
63 | if (typeof a != 'object') {
64 | throw new TypeError('Wrong argument in the Context.putImageData');
65 | }
66 |
67 | a = a[0];
68 | put.image = a.image;
69 | put.from = toPoint(a.from);
70 |
71 | if (a.crop) put.crop = toRectangle(a.crop);
72 | } break;
73 |
74 | case 3: {
75 | put.image = a[0];
76 | put.from = new Point(a[1], a[2]);
77 | } break;
78 |
79 | case 7: {
80 | put.image = a[0];
81 | put.from = new Point(a[1], a[2]);
82 | put.crop = new Rectangle(a[3], a[4], a[5], a[6]);
83 | } break;
84 |
85 | default : throw new TypeError('Wrong args number in the Context.putImageData');
86 | }
87 |
88 | args = [put.image, put.from.x, put.from.y];
89 |
90 | if (put.crop) {
91 | rect = put.crop;
92 | atom.array.append(args, [rect.from.x, rect.from.y, rect.width, rect.height])
93 | }
94 |
95 | this.ctx2d.putImageData.apply(this.ctx2d, args);
96 | return this.context;
97 | },
98 | /** @returns {CanvasPixelArray} */
99 | getImageData : function (args) {
100 | var rect = toRectangle(args.length > 1 ? args : args[0]);
101 |
102 | return this.ctx2d.getImageData(rect.from.x, rect.from.y, rect.width, rect.height);
103 | },
104 | getPixels : function (args) {
105 | var
106 | rect = toRectangle(args.length > 1 ? args : args[0]),
107 | data = this.getImageData(rect).data,
108 | result = [],
109 | line = [];
110 | for (var i = 0, L = data.length; i < L; i+=4) {
111 | line.push({
112 | r : data[i],
113 | g : data[i+1],
114 | b : data[i+2],
115 | a : data[i+3] / 255
116 | });
117 | if (line.length == rect.width) {
118 | result.push(line);
119 | line = [];
120 | }
121 | }
122 | return result;
123 | },
124 |
125 | getPixel: function (point) {
126 | var
127 | rect = new Rectangle(toPoint( point ), size1x1),
128 | data = slice.call(this.getImageData([rect]).data);
129 |
130 | data[3] /= 255;
131 |
132 | return new atom.Color(data);
133 | }
134 |
135 | });
136 |
137 | };
138 |
--------------------------------------------------------------------------------
/Source/Context/Text.js:
--------------------------------------------------------------------------------
1 | /*
2 | ---
3 |
4 | name: "Context.Text"
5 |
6 | description: "LibCanvas.Context2D adds new canvas context '2d-libcanvas'"
7 |
8 | license:
9 | - "[GNU Lesser General Public License](http://opensource.org/licenses/lgpl-license.php)"
10 | - "[MIT License](http://opensource.org/licenses/mit-license.php)"
11 |
12 | authors:
13 | - "Shock "
14 |
15 | requires:
16 | - LibCanvas
17 | - Point
18 | - Size
19 | - Shapes.Rectangle
20 | - Shapes.Circle
21 |
22 | provides: Context.Text
23 |
24 | ...
25 | */
26 |
27 | new function () {
28 |
29 | var toPoint = Point.from, toRectangle = Rectangle.from, size1x1 = new Size(1,1);
30 |
31 |
32 | /** @class LibCanvas.Context.Text */
33 | LibCanvas.declare( 'LibCanvas.Context.Text', {
34 | initialize: function (context) {
35 | this.context = context;
36 | this.ctx2d = context.ctx2d;
37 | },
38 | // text
39 | /** @returns {Context2D} */
40 | method: function (method, text, x, y, maxWidth) {
41 | var type = typeof x;
42 | if (type != 'number' && type != 'string') {
43 | maxWidth = y;
44 | x = toPoint( x );
45 | y = x.y;
46 | x = x.x;
47 | }
48 | var args = [text, x, y];
49 | if (maxWidth) args.push( maxWidth );
50 | this.ctx2d[method].apply( this.ctx2d, args );
51 | return this.context;
52 | },
53 | fillText : function (text, x, y, maxWidth) {
54 | return this.method( 'fillText', text, x, y, maxWidth);
55 | },
56 | strokeText : function (text, x, y, maxWidth) {
57 | return this.method('strokeText', text, x, y, maxWidth);
58 | },
59 | /** @returns {object} */
60 | measureText : function (args) {
61 | return this.ctx2d.measureText.apply(this.ctx2d, args)
62 | },
63 | /** @returns {Context2D} */
64 | text : function (cfg) {
65 | if (!this.ctx2d.fillText) return this;
66 |
67 | var ctx = this.ctx2d;
68 |
69 | cfg = atom.core.append({
70 | text : '',
71 | color : null, /* @color */
72 | wrap : 'normal', /* no|normal */
73 | to : null,
74 | align : 'left', /* center|left|right */
75 | size : 16,
76 | weight : 'normal', /* bold|normal */
77 | style : 'normal', /* italic|normal */
78 | family : 'arial,sans-serif', /* @fontFamily */
79 | lineHeight : null,
80 | overflow : 'visible', /* hidden|visible */
81 | padding : [0,0],
82 | shadow : null,
83 | stroke : null,
84 | lineWidth : null
85 | }, cfg);
86 |
87 | ctx.save();
88 | if (typeof cfg.padding == 'number') {
89 | cfg.padding = [cfg.padding, cfg.padding];
90 | }
91 | var method = cfg.stroke ? 'strokeText' : 'fillText';
92 | var to = cfg.to ? toRectangle(cfg.to) : this.context.rectangle;
93 | var lh = Math.round(cfg.lineHeight || (cfg.size * 1.15));
94 | this.context.set('font', atom.string.substitute(
95 | '{style}{weight}{size}px {family}', {
96 | style : cfg.style == 'italic' ? 'italic ' : '',
97 | weight : cfg.weight == 'bold' ? 'bold ' : '',
98 | size : cfg.size,
99 | family : cfg.family
100 | })
101 | );
102 |
103 | if (cfg.color) {
104 | this.context.set(cfg.stroke ? 'strokeStyle' : 'fillStyle', cfg.color);
105 | }
106 |
107 | if (cfg.shadow) this.context.shadow = cfg.shadow;
108 | if (cfg.overflow == 'hidden') this.context.clip(to);
109 | if (cfg.lineWidth) this.context.set({ lineWidth: cfg.lineWidth });
110 |
111 | function xGet (lineWidth) {
112 | var al = cfg.align, pad = cfg.padding[1];
113 | return Math.round(
114 | al == 'left' ? to.from.x + pad :
115 | al == 'right' ? to.to.x - lineWidth - pad :
116 | to.from.x + (to.width - lineWidth)/2
117 | );
118 | }
119 | function measure (text) {
120 | return Number(ctx.measureText(text).width);
121 | }
122 | var lines = String(cfg.text).split('\n');
123 |
124 | if (cfg.wrap == 'no') {
125 | lines.forEach(function (line, i) {
126 | if (!line) return;
127 |
128 | ctx[method](line, xGet(cfg.align == 'left' ? 0 : measure(line)), to.from.y + (i+1)*lh);
129 | });
130 | } else {
131 | var lNum = 0;
132 | lines.forEach(function (line) {
133 | if (!line) {
134 | lNum++;
135 | return;
136 | }
137 |
138 | var words = (line || ' ').match(/.+?(\s|$)/g);
139 | if (!words) {
140 | lNum++;
141 | return;
142 | }
143 | var L = '';
144 | var Lw = 0;
145 | for (var i = 0; i <= words.length; i++) {
146 | var last = i == words.length;
147 | if (!last) {
148 | var text = words[i];
149 | // @todo too slow. 2-4ms for 50words
150 | var wordWidth = measure(text);
151 | if (!Lw || Lw + wordWidth < to.width) {
152 | Lw += wordWidth;
153 | L += text;
154 | continue;
155 | }
156 | }
157 | if (Lw) {
158 | ctx[method](L, xGet(Lw), to.from.y + (++lNum)*lh + cfg.padding[0]);
159 | if (last) {
160 | L = '';
161 | Lw = 0;
162 | } else {
163 | L = text;
164 | Lw = wordWidth;
165 | }
166 | }
167 | }
168 | if (Lw) {
169 | ctx[method](L, xGet(Lw), to.from.y + (++lNum)*lh + cfg.padding[0]);
170 | }
171 | });
172 |
173 | }
174 | ctx.restore();
175 | return this.context;
176 | }
177 |
178 | });
179 |
180 | };
181 |
--------------------------------------------------------------------------------
/Source/Core/Canvas.js:
--------------------------------------------------------------------------------
1 | /*
2 | ---
3 |
4 | name: "Core.Canvas"
5 |
6 | description: "Provides some Canvas extensions"
7 |
8 | license:
9 | - "[GNU Lesser General Public License](http://opensource.org/licenses/lgpl-license.php)"
10 | - "[MIT License](http://opensource.org/licenses/mit-license.php)"
11 |
12 | authors:
13 | - "Shock "
14 |
15 | requires:
16 | - LibCanvas
17 |
18 | provides: Core.Canvas
19 |
20 | ...
21 | */
22 |
23 | atom.core.append(HTMLCanvasElement,
24 | /** @lends HTMLCanvasElement */
25 | {
26 | /** @private */
27 | _newContexts: {},
28 | /** @returns {HTMLCanvasElement} */
29 | addContext: function (name, ctx) {
30 | this._newContexts[name] = ctx;
31 | return this;
32 | },
33 | /** @returns {Context2D} */
34 | getContext: function (name) {
35 | return this._newContexts[name] || null;
36 | }
37 | });
38 |
39 | atom.core.append(HTMLCanvasElement.prototype,
40 | /** @lends HTMLCanvasElement.prototype */
41 | {
42 | getOriginalContext: HTMLCanvasElement.prototype.getContext,
43 | /** @returns {Context2D} */
44 | getContext: function (type) {
45 | if (!this.contextsList) {
46 | this.contextsList = {};
47 | }
48 |
49 | if (!this.contextsList[type]) {
50 | var ctx = HTMLCanvasElement.getContext(type);
51 | if (ctx) {
52 | ctx = new ctx(this);
53 | } else try {
54 | ctx = this.getOriginalContext.apply(this, arguments);
55 | } catch (e) {
56 | throw (!e.toString().match(/NS_ERROR_ILLEGAL_VALUE/)) ? e :
57 | new TypeError('Wrong Context Type: «' + type + '»');
58 | }
59 | this.contextsList[type] = ctx;
60 | }
61 | return this.contextsList[type];
62 | }
63 | });
--------------------------------------------------------------------------------
/Source/Core/Geometry.js:
--------------------------------------------------------------------------------
1 | /*
2 | ---
3 |
4 | name: "Geometry"
5 |
6 | description: "Base for such things as Point and Shape"
7 |
8 | license:
9 | - "[GNU Lesser General Public License](http://opensource.org/licenses/lgpl-license.php)"
10 | - "[MIT License](http://opensource.org/licenses/mit-license.php)"
11 |
12 | authors:
13 | - "Shock "
14 |
15 | requires:
16 | - LibCanvas
17 |
18 | provides: Geometry
19 |
20 | ...
21 | */
22 |
23 | /** @class Geometry */
24 | var Geometry = declare( 'LibCanvas.Geometry', {
25 | initialize : function () {
26 | if (arguments.length) this.set.apply(this, arguments);
27 | },
28 | cast: function (args) {
29 | return this.constructor.castArguments(args);
30 | }
31 | }).own({
32 | invoke: declare.castArguments,
33 | from : function (obj) {
34 | return this(obj);
35 | }
36 | });
--------------------------------------------------------------------------------
/Source/Core/Mouse.js:
--------------------------------------------------------------------------------
1 | /*
2 | ---
3 |
4 | name: "Mouse"
5 |
6 | description: "A mouse control abstraction class"
7 |
8 | license:
9 | - "[GNU Lesser General Public License](http://opensource.org/licenses/lgpl-license.php)"
10 | - "[MIT License](http://opensource.org/licenses/mit-license.php)"
11 |
12 | authors:
13 | - "Shock "
14 |
15 | requires:
16 | - LibCanvas
17 | - Point
18 |
19 | provides: Mouse
20 |
21 | ...
22 | */
23 |
24 | /** @class Mouse */
25 | var Mouse = LibCanvas.declare( 'LibCanvas.Mouse', 'Mouse', {
26 | /** @private */
27 | elem: null,
28 |
29 | /** @property {boolean} */
30 | inside: false,
31 | /** @property {Point} */
32 | point: null,
33 | /** @property {Point} */
34 | previous: null,
35 | /** @property {Point} */
36 | delta: null,
37 | /** @property {Events} */
38 | events: null,
39 |
40 | /** @private */
41 | mapping: {
42 | click : 'click',
43 | dblclick : 'dblclick',
44 | contextmenu: 'contextmenu',
45 |
46 | mouseover : 'over',
47 | mouseout : 'out',
48 | mousedown : 'down',
49 | mouseup : 'up',
50 | mousemove : 'move',
51 |
52 | DOMMouseScroll: 'wheel',
53 | mousewheel : 'wheel'
54 | },
55 |
56 | initialize : function (elem, offsetElem) {
57 | this.bindMethods( 'onEvent' );
58 |
59 | if (elem == null) {
60 | throw new TypeError('`elem` is undefined');
61 | }
62 |
63 | this.elem = atom.dom(elem);
64 | this.offsetElem = offsetElem ? atom.dom(offsetElem) : this.elem;
65 |
66 | this.point = new Point(0, 0);
67 | this.previous = new Point(0, 0);
68 | this.delta = new Point(0, 0);
69 | this.events = new Events(this);
70 |
71 | this.listen(this.onEvent);
72 | },
73 | /** @private */
74 | fire: function (name, e) {
75 | this.events.fire(name, [e, this]);
76 | return this;
77 | },
78 | /** @private */
79 | onEvent: function (e) {
80 | var
81 | name = this.mapping[e.type],
82 | fn = this.eventActions[name];
83 |
84 | if (fn) fn.call(this, e);
85 |
86 | this.fire(name, e);
87 | },
88 | /** @private */
89 | getOffset: function (e) {
90 | return this.constructor.getOffset(e, this.offsetElem);
91 | },
92 | /** @private */
93 | set: function (e, inside) {
94 | var point = this.getOffset(e);
95 |
96 | this.previous.set( this.point );
97 | this.delta .set( this.previous.diff( point ) );
98 | this.point .set( point );
99 | this.inside = inside;
100 | },
101 | /** @private */
102 | eventActions: {
103 | wheel: function (e) {
104 | this.constructor.addWheelDelta(e);
105 | },
106 |
107 | move: function (e) {
108 | this.set(e, true);
109 | },
110 |
111 | down: function (e) {
112 | this.set(e, true);
113 | },
114 |
115 | over: function (e) {
116 | if (this.checkEvent(e)) {
117 | this.fire('enter', e);
118 | }
119 | },
120 |
121 | out: function (e) {
122 | if (this.checkEvent(e)) {
123 | this.set(e, false);
124 | this.fire('leave', e);
125 | }
126 | }
127 | },
128 | /** @private */
129 | checkEvent: function (e) {
130 | var related = e.relatedTarget, elem = this.elem;
131 |
132 | return related == null || (
133 | related && related != elem.first && !elem.contains(related)
134 | );
135 | },
136 | /** @private */
137 | listen : function (callback) {
138 | this.elem
139 | .bind({ selectstart: false })
140 | .bind(atom.object.map(
141 | this.mapping, atom.fn.lambda(callback)
142 | ));
143 | }
144 | }).own({
145 | prevent: function (e) {e.preventDefault()},
146 | addWheelDelta: function (e) {
147 | e.delta =
148 | // IE, Opera, Chrome
149 | e.wheelDelta ? e.wheelDelta > 0 ? 1 : -1 :
150 | // Fx
151 | e.detail ? e.detail < 0 ? 1 : -1 : null;
152 |
153 | return e;
154 | },
155 | eventSource: function (e) {
156 | return e.changedTouches ? e.changedTouches[0] : e;
157 | },
158 | expandEvent: function (e) {
159 | var source = this.eventSource(e);
160 |
161 | if (e.pageX == null) {
162 | e.pageX = source.pageX != null ? source.pageX : source.clientX + document.scrollLeft;
163 | e.pageY = source.pageY != null ? source.pageY : source.clientY + document.scrollTop ;
164 | }
165 |
166 | return e;
167 | },
168 | getOffset : function (e, element) {
169 | var elementOffset = atom.dom(element || this.eventSource(e).target).offset();
170 |
171 | this.expandEvent(e);
172 |
173 | return new Point(
174 | e.pageX - elementOffset.x,
175 | e.pageY - elementOffset.y
176 | );
177 | }
178 | });
--------------------------------------------------------------------------------
/Source/Core/Point3D.js:
--------------------------------------------------------------------------------
1 | /*
2 | ---
3 |
4 | name: "Point3D"
5 |
6 | description: "A X/Y/Z point coordinates encapsulating class"
7 |
8 | license:
9 | - "[GNU Lesser General Public License](http://opensource.org/licenses/lgpl-license.php)"
10 | - "[MIT License](http://opensource.org/licenses/mit-license.php)"
11 |
12 | authors:
13 | - "Shock "
14 |
15 | requires:
16 | - LibCanvas
17 | - Geometry
18 |
19 | provides: Point3D
20 |
21 | ...
22 | */
23 |
24 | /** @class Point3D */
25 | var Point3D = LibCanvas.declare( 'LibCanvas.Point3D', 'Point3D', Geometry, {
26 | x: 0,
27 | y: 0,
28 | z: 0,
29 |
30 | /** @private */
31 | coordinatesArray: ['x', 'y', 'z'],
32 |
33 | /**
34 | * @constructs
35 | * @param {Number} x
36 | * @param {Number} y
37 | * @param {Number} z
38 | * @returns {Point3D}
39 | */
40 | set: function (x, y, z) {
41 | if ( arguments.length > 1 ) {
42 | this.x = Number(x) || 0;
43 | this.y = Number(y) || 0;
44 | this.z = Number(z) || 0;
45 | } else if ( x && typeof x.x === 'number' ) {
46 | this.set( x.x, x.y, x.z );
47 | } else if ( x && typeof x[0] === 'number' ) {
48 | this.set( x[0], x[1], x[2] );
49 | } else {
50 | throw new Error( 'Wrong arguments in Isometric.Point3D' );
51 | }
52 | return this;
53 | },
54 |
55 | /**
56 | * You can pass callback (function( value, axis, point ){})
57 | * @param {function} fn
58 | * @param {object} [context=null]
59 | * @returns {Point3D}
60 | */
61 | map: function (fn, context) {
62 | var point = this;
63 | point.coordinatesArray.forEach(function (axis) {
64 | point[axis] = fn.call( context || point, point[axis], axis, point );
65 | });
66 | return this;
67 | },
68 |
69 | /**
70 | * @param {Number} factor
71 | * @returns {Point3D}
72 | */
73 | add: function (factor) {
74 | return this.map(function (c) { return c+factor });
75 | },
76 |
77 | /**
78 | * @param {Number} factor
79 | * @returns {Point3D}
80 | */
81 | mul: function (factor) {
82 | return this.map(function (c) { return c*factor });
83 | },
84 |
85 | /**
86 | * @param {Point3D} point3d
87 | * @returns {Point3D}
88 | */
89 | diff: function (point3d) {
90 | point3d = this.cast( point3d );
91 | return new this.constructor(
92 | point3d.x - this.x,
93 | point3d.y - this.y,
94 | point3d.z - this.z
95 | );
96 | },
97 |
98 | /**
99 | * @param {Point3D} point3d
100 | * @returns {Point3D}
101 | */
102 | move: function (point3d) {
103 | point3d = this.cast( arguments );
104 | this.x += point3d.x;
105 | this.y += point3d.y;
106 | this.z += point3d.z;
107 | return this;
108 | },
109 |
110 | /**
111 | * @param {Point3D} point3d
112 | * @param {Number} accuracy
113 | * @returns {boolean}
114 | */
115 | equals: function (point3d, accuracy) {
116 | return point3d.x.equals( this.x, accuracy ) &&
117 | point3d.y.equals( this.y, accuracy ) &&
118 | point3d.z.equals( this.z, accuracy );
119 | },
120 |
121 | /** @returns {Point3D} */
122 | clone: function () {
123 | return new this.constructor( this );
124 | },
125 |
126 | /** @returns Array */
127 | toArray: function () {
128 | return [this.x, this.y, this.z];
129 | },
130 |
131 | /** @returns String */
132 | dump: function () {
133 | return '[LibCanvas.Point3D(' + this.toArray() + ')]';
134 | }
135 | });
--------------------------------------------------------------------------------
/Source/Core/Shape.js:
--------------------------------------------------------------------------------
1 | /*
2 | ---
3 |
4 | name: "Shape"
5 |
6 | description: "Abstract class LibCanvas.Shape defines interface for drawable canvas objects"
7 |
8 | license:
9 | - "[GNU Lesser General Public License](http://opensource.org/licenses/lgpl-license.php)"
10 | - "[MIT License](http://opensource.org/licenses/mit-license.php)"
11 |
12 | authors:
13 | - "Shock "
14 |
15 | requires:
16 | - LibCanvas
17 | - Geometry
18 | - Point
19 |
20 | provides: Shape
21 |
22 | ...
23 | */
24 |
25 | var shapeTestBuffer = function () {
26 | if (!shapeTestBuffer.buffer) {
27 | return shapeTestBuffer.buffer = LibCanvas.buffer(1, 1, true);
28 | }
29 | return shapeTestBuffer.buffer;
30 | };
31 |
32 | /** @class Shape */
33 | var Shape = declare( 'LibCanvas.Shape', Geometry, {
34 | set : 'abstract',
35 | hasPoint : 'abstract',
36 | processPath: 'abstract',
37 | draw : function (ctx, type) {
38 | this.processPath(ctx)[type]();
39 | return this;
40 | },
41 | // Методы ниже рассчитывают на то, что в фигуре есть точки from и to
42 | getCoords : function () {
43 | return this.from;
44 | },
45 | /** @returns {LibCanvas.Shape} */
46 | grow: function (size) {
47 | if (typeof size == 'number') {
48 | size = new Point(size/2, size/2);
49 | } else {
50 | size = new Point(size.x/2, size.y/2);
51 | }
52 |
53 | this.from.move(size, true);
54 | this. to .move(size);
55 | return this;
56 | },
57 | get x () { return this.from.x },
58 | get y () { return this.from.y },
59 | set x (x) {
60 | return this.move(new Point(x - this.x, 0));
61 | },
62 | set y (y) {
63 | return this.move(new Point(0, y - this.y));
64 | },
65 | get bottomLeft () {
66 | return new Point(this.from.x, this.to.y);
67 | },
68 | get topRight() {
69 | return new Point(this.to.x, this.from.y);
70 | },
71 | get center() {
72 | var from = this.from, to = this.to;
73 | return new Point( (from.x + to.x) / 2, (from.y + to.y) / 2 );
74 | },
75 | getBoundingRectangle: function () {
76 | return new Rectangle( this.from, this.to );
77 | },
78 | getCenter : function () {
79 | return this.center;
80 | },
81 | move : function (distance, reverse) {
82 | this.from.move(distance, reverse);
83 | this. to .move(distance, reverse);
84 | return this;
85 | },
86 | equals : function (shape, accuracy) {
87 | return shape instanceof this.constructor &&
88 | shape.from.equals(this.from, accuracy) &&
89 | shape.to .equals(this.to , accuracy);
90 | },
91 | clone : function () {
92 | return new this.constructor(this.from.clone(), this.to.clone());
93 | },
94 | dumpPoint: function (point) {
95 | return '[' + point.x + ', ' + point.y + ']';
96 | },
97 | dump: function (shape) {
98 | if (!shape) return this.toString();
99 | return '[shape '+shape+'(from'+this.dumpPoint(this.from)+', to'+this.dumpPoint(this.to)+')]';
100 | }
101 | });
--------------------------------------------------------------------------------
/Source/Core/Size.js:
--------------------------------------------------------------------------------
1 | /*
2 | ---
3 |
4 | name: "Size"
5 |
6 | description: ""
7 |
8 | license:
9 | - "[GNU Lesser General Public License](http://opensource.org/licenses/lgpl-license.php)"
10 | - "[MIT License](http://opensource.org/licenses/mit-license.php)"
11 |
12 | authors:
13 | - "Shock "
14 |
15 | requires:
16 | - LibCanvas
17 | - Point
18 |
19 | provides: Size
20 |
21 | ...
22 | */
23 |
24 | /** @class Size */
25 | var Size = LibCanvas.declare( 'LibCanvas.Size', 'Size', Point, {
26 | set: function method (size) {
27 | if (typeof size == 'object' && size.width != null) {
28 | this.x = Number(size.width);
29 | this.y = Number(size.height);
30 |
31 | return this;
32 | }
33 | return method.previous.apply( this, arguments );
34 | },
35 |
36 | get width ( ) { return this.x },
37 | get height ( ) { return this.y },
38 | set width (w) { this.x = w },
39 | set height (h) { this.y = h },
40 |
41 | /** @returns {object} */
42 | toObject: function () {
43 | return { width: this.x, height: this.y };
44 | }
45 | });
46 |
47 | /** @private */
48 | Size.from = function (object) {
49 | if (object == null) return null;
50 |
51 | return object instanceof Size ? object : new Size(object);
52 | };
--------------------------------------------------------------------------------
/Source/Engines/Hex/Engine.js:
--------------------------------------------------------------------------------
1 | /*
2 | ---
3 |
4 | name: "Engines.Hex"
5 |
6 | license:
7 | - "[GNU Lesser General Public License](http://opensource.org/licenses/lgpl-license.php)"
8 | - "[MIT License](http://opensource.org/licenses/mit-license.php)"
9 |
10 | authors:
11 | - "Shock "
12 |
13 | requires:
14 | - LibCanvas
15 |
16 | provides: Engines.Hex
17 |
18 | ...
19 | */
20 |
21 | /** @class HexEngine */
22 | LibCanvas.declare( 'LibCanvas.Engines.Hex', 'HexEngine', { });
--------------------------------------------------------------------------------
/Source/Engines/Isometric/Engine.js:
--------------------------------------------------------------------------------
1 | /*
2 | ---
3 |
4 | name: "Engines.Isometric"
5 |
6 | license:
7 | - "[GNU Lesser General Public License](http://opensource.org/licenses/lgpl-license.php)"
8 | - "[MIT License](http://opensource.org/licenses/mit-license.php)"
9 |
10 | authors:
11 | - "Shock "
12 |
13 | requires:
14 | - LibCanvas
15 |
16 | provides: Engines.Isometric
17 |
18 | ...
19 | */
20 |
21 | /** @class HexEngine */
22 | LibCanvas.declare( 'LibCanvas.Engines.Isometric', 'IsometricEngine', { });
--------------------------------------------------------------------------------
/Source/Engines/Isometric/Projection.js:
--------------------------------------------------------------------------------
1 | /*
2 | ---
3 |
4 | name: "Engines.Isometric.Projection"
5 |
6 | license:
7 | - "[GNU Lesser General Public License](http://opensource.org/licenses/lgpl-license.php)"
8 | - "[MIT License](http://opensource.org/licenses/mit-license.php)"
9 |
10 | authors:
11 | - "Shock "
12 |
13 | requires:
14 | - LibCanvas
15 | - Point3D
16 | - Engines.Isometric
17 |
18 | provides: Engines.Isometric.Projection
19 |
20 | ...
21 | */
22 |
23 | /** @class IsometricProjection */
24 | atom.declare( 'LibCanvas.Engines.Isometric.Projection', {
25 |
26 | /**
27 | * factor (and default factor in proto)
28 | * @property {Point3D}
29 | */
30 | factor: [0.866, 0.5, 0.866],
31 |
32 | /**
33 | * size (and default size in proto)
34 | * @property int
35 | */
36 | size: 1,
37 |
38 | /**
39 | * start (and default start in proto)
40 | * @property {Point}
41 | */
42 | start: [0, 0],
43 |
44 | /**
45 | * @constructs
46 | * @param {object} settings
47 | * @param {Point3D} settings.factor
48 | * @param {Point3D} settings.size
49 | * @param {Point} settings.start - position of [0,0] coordinate
50 | */
51 | initialize: function (settings) {
52 | this.bindMethods([ 'toIsometric', 'to3D' ]);
53 | this.settings = new Settings(settings);
54 |
55 | this.factor = Point3D( this.settings.get('factor') || this.factor );
56 | this.size = Number ( this.settings.get('size') || this.size );
57 | this.start = Point ( this.settings.get('start') || this.start );
58 | },
59 |
60 | /**
61 | * @param {Point3D} point3d
62 | * @returns {Point}
63 | */
64 | toIsometric: function (point3d) {
65 | point3d = Point3D( point3d );
66 | return new Point(
67 | (point3d.y + point3d.x) * this.factor.x,
68 | (point3d.y - point3d.x) * this.factor.y - point3d.z * this.factor.z
69 | )
70 | .mul(this.size)
71 | .move(this.start);
72 | },
73 |
74 | /**
75 | * @param {Point} point
76 | * @param {int} [z=0]
77 | * @returns {Point3D}
78 | */
79 | to3D: function (point, z) {
80 | point = Point(point);
81 | z = Number(z) || 0;
82 |
83 | var
84 | size = this.size,
85 | start = this.start,
86 | dXY = ((point.y - start.y) / size + z * this.factor.z) / this.factor.y,
87 | pX = ((point.x - start.x) / size / this.factor.x - dXY) / 2;
88 |
89 | return new Point3D( pX, pX + dXY, z );
90 | }
91 | });
--------------------------------------------------------------------------------
/Source/Engines/Tile/Cell.js:
--------------------------------------------------------------------------------
1 | /*
2 | ---
3 |
4 | name: "TileEngine.Cell"
5 |
6 | license:
7 | - "[GNU Lesser General Public License](http://opensource.org/licenses/lgpl-license.php)"
8 | - "[MIT License](http://opensource.org/licenses/mit-license.php)"
9 |
10 | authors:
11 | - "Shock "
12 |
13 | requires:
14 | - Engines.Tile
15 |
16 | provides: Engines.Tile.Cell
17 |
18 | ...
19 | */
20 | /** @class TileEngine.Cell */
21 | declare( 'LibCanvas.Engines.Tile.Cell', {
22 |
23 | initialize: function (engine, point, rectangle, value) {
24 | this.engine = engine;
25 | this.point = point;
26 | this.value = value;
27 | this.rectangle = rectangle;
28 | },
29 |
30 | /** @private */
31 | _value: null,
32 |
33 | get value () {
34 | return this._value;
35 | },
36 |
37 | set value (value) {
38 | this._value = value;
39 | this.engine.updateCell(this);
40 | },
41 |
42 | renderTo: function (ctx) {
43 | var method, value = this.value, rectangle = this.rectangle;
44 |
45 | ctx.clear( rectangle );
46 |
47 | if (value == null) return this;
48 |
49 | method = this.engine.methods[ value ];
50 |
51 | if (method == null) {
52 | throw new Error( 'No method in tile engine: «' + this.value + '»')
53 | }
54 |
55 | if (atom.dom.isElement(method)) {
56 | ctx.drawImage( method, rectangle );
57 | } else if (typeof method == 'function') {
58 | method.call( this, ctx, this );
59 | } else {
60 | ctx.fill( rectangle, method );
61 | }
62 | return this;
63 | }
64 |
65 | });
--------------------------------------------------------------------------------
/Source/Engines/Tile/Element.js:
--------------------------------------------------------------------------------
1 | /*
2 | ---
3 |
4 | name: "TileEngine.Element"
5 |
6 | license:
7 | - "[GNU Lesser General Public License](http://opensource.org/licenses/lgpl-license.php)"
8 | - "[MIT License](http://opensource.org/licenses/mit-license.php)"
9 |
10 | authors:
11 | - "Shock "
12 |
13 | requires:
14 | - Engines.Tile
15 | - App.Element
16 |
17 | provides: Engines.Tile.Element
18 |
19 | ...
20 | */
21 | /** @class TileEngine.Element */
22 | declare( 'LibCanvas.Engines.Tile.Element', App.Element, {
23 | configure: function () {
24 | this.shape = new Rectangle(
25 | this.settings.get('from') || new Point(0, 0),
26 | this.engine.countSize()
27 | );
28 | this.engine.events.add( 'update', this.redraw );
29 | },
30 |
31 | get engine () {
32 | return this.settings.get('engine');
33 | },
34 |
35 | clearPrevious: function () {},
36 |
37 | renderTo: function (ctx) {
38 | this.engine.refresh(ctx, this.shape.from);
39 | }
40 | }).own({
41 | app: function (app, engine, from) {
42 | return new this( app.createLayer({
43 | name: 'tile-engine',
44 | intersection: 'manual',
45 | invoke: false
46 | }), {
47 | engine: engine,
48 | from: from
49 | });
50 | }
51 | });
52 |
53 |
--------------------------------------------------------------------------------
/Source/Engines/Tile/Mouse.js:
--------------------------------------------------------------------------------
1 | /*
2 | ---
3 |
4 | name: "TileEngine.Mouse"
5 |
6 | license:
7 | - "[GNU Lesser General Public License](http://opensource.org/licenses/lgpl-license.php)"
8 | - "[MIT License](http://opensource.org/licenses/mit-license.php)"
9 |
10 | authors:
11 | - "Shock "
12 |
13 | requires:
14 | - Engines.Tile.Element
15 |
16 | provides: Engines.Tile.Mouse
17 |
18 | ...
19 | */
20 | /** @class TileEngine.Mouse */
21 | declare( 'LibCanvas.Engines.Tile.Mouse', {
22 | eventsList: 'mousemove mouseout mousedown mouseup contextmenu'
23 | .split(' '),
24 |
25 | initialize: function (element, mouse) {
26 | this.bindMethods(this.eventsList);
27 |
28 | this.events = new Events(this);
29 |
30 | /** @private */
31 | this.mouse = mouse;
32 | /** @private */
33 | this.element = element;
34 | /** @private */
35 | this.previous = null;
36 | /** @private */
37 | this.lastDown = null;
38 | this.subscribe(false);
39 | },
40 |
41 | /** @private */
42 | subscribe: function (un) {
43 | var events = atom.object.collect(this, this.eventsList, null);
44 |
45 | this.element.events
46 | [ un ? 'remove' : 'add' ]
47 | (events);
48 | },
49 | /** @private */
50 | mousemove: function (e) {
51 | var cell = this.get();
52 | if (this.previous != cell) {
53 | this.outCell(e);
54 | this.fire( 'over', cell, e );
55 | this.previous = cell;
56 | }
57 | },
58 | /** @private */
59 | mouseout: function (e) {
60 | this.outCell(e);
61 | },
62 | /** @private */
63 | mousedown: function (e) {
64 | var cell = this.get();
65 | this.fire( 'down', cell, e );
66 | this.lastDown = cell;
67 | },
68 | /** @private */
69 | mouseup: function (e) {
70 | var cell = this.get();
71 | this.fire( 'up', cell, e );
72 | if (cell != null && cell == this.lastDown) {
73 | this.fire( 'click', cell, e );
74 | }
75 | this.lastDown = null;
76 | },
77 | /** @private */
78 | contextmenu: function (e) {
79 | var cell = this.get();
80 | if (cell != null) {
81 | this.fire( 'contextmenu', cell, e );
82 | }
83 | },
84 | /** @private */
85 | get: function () {
86 | return this.element.engine.getCellByPoint(
87 | this.mouse.point.clone().move(this.element.shape.from, true)
88 | );
89 | },
90 |
91 | /** @private */
92 | fire: function (event, cell, e) {
93 | return this.events.fire( event, [ cell, e ]);
94 | },
95 |
96 | /** @private */
97 | outCell: function (e) {
98 | if (this.previous) {
99 | this.fire( 'out', this.previous, e );
100 | this.previous = null;
101 | }
102 | }
103 | });
--------------------------------------------------------------------------------
/Source/Engines/Tile/Tile.js:
--------------------------------------------------------------------------------
1 | /*
2 | ---
3 |
4 | name: "TileEngine"
5 |
6 | license:
7 | - "[GNU Lesser General Public License](http://opensource.org/licenses/lgpl-license.php)"
8 | - "[MIT License](http://opensource.org/licenses/mit-license.php)"
9 |
10 | authors:
11 | - "Shock "
12 |
13 | requires:
14 | - LibCanvas
15 | - Point
16 | - Size
17 | - Rectangle
18 |
19 | provides: Engines.Tile
20 |
21 | ...
22 | */
23 |
24 | /** @class TileEngine */
25 | var TileEngine = LibCanvas.declare( 'LibCanvas.Engines.Tile', 'TileEngine', {
26 |
27 | /**
28 | * @param {Object} settings
29 | * @param {*} settings.defaultValue
30 | * @param {Size} settings.size
31 | * @param {Size} settings.cellSize
32 | * @param {Size} settings.cellMargin
33 | */
34 | initialize: function (settings) {
35 | this.cells = [];
36 | this.methods = {};
37 | this.cellsUpdate = [];
38 |
39 | this.events = new Events(this);
40 | this.settings = new Settings(settings).addEvents(this.events);
41 | this.createMatrix();
42 | },
43 |
44 | setMethod: atom.core.overloadSetter(function (name, method) {
45 | if (this.isValidMethod(method)) {
46 | this.methods[ name ] = method;
47 | } else {
48 | throw new TypeError( 'Unknown method: «' + name + '»' );
49 | }
50 | }),
51 |
52 | countSize: function () {
53 | var
54 | settings = this.settings,
55 | cellSize = settings.get('cellSize'),
56 | cellMargin = settings.get('cellMargin');
57 |
58 | return new Size(
59 | (cellSize.x + cellMargin.x) * this.width - cellMargin.x,
60 | (cellSize.y + cellMargin.y) * this.height - cellMargin.y
61 | );
62 | },
63 |
64 | getCellByIndex: function (point) {
65 | point = Point.from(point);
66 | return this.isIndexOutOfBounds(point) ? null:
67 | this.cells[ this.width * point.y + point.x ];
68 | },
69 |
70 | getCellByPoint: function (point) {
71 | var
72 | settings = this.settings,
73 | cellSize = settings.get('cellSize'),
74 | cellMargin = settings.get('cellMargin');
75 |
76 | point = Point.from(point);
77 |
78 | return this.getCellByIndex(new Point(
79 | parseInt(point.x / (cellSize.width + cellMargin.x)),
80 | parseInt(point.y / (cellSize.height + cellMargin.y))
81 | ));
82 | },
83 |
84 | refresh: function (ctx, translate) {
85 | if (this.requireUpdate) {
86 | ctx.save();
87 | if (translate) ctx.translate(translate);
88 | atom.array.invoke( this.cellsUpdate, 'renderTo', ctx );
89 | ctx.restore();
90 | this.cellsUpdate.length = 0;
91 | }
92 | return this;
93 | },
94 |
95 | get width () {
96 | return this.settings.get('size').width;
97 | },
98 |
99 | get height () {
100 | return this.settings.get('size').height;
101 | },
102 |
103 | get requireUpdate () {
104 | return !!this.cellsUpdate.length;
105 | },
106 |
107 | /** @private */
108 | isValidMethod: function (method) {
109 | var type = typeof method;
110 |
111 | return type == 'function'
112 | || type == 'string'
113 | || atom.dom.isElement(method);
114 | },
115 |
116 | /** @private */
117 | createMatrix : function () {
118 | var x, y,
119 | settings = this.settings,
120 | size = settings.get('size'),
121 | value = settings.get('defaultValue'),
122 | cellSize = settings.get('cellSize'),
123 | cellMargin = settings.get('cellMargin');
124 |
125 | for (y = 0; y < size.height; y++) for (x = 0; x < size.width; x++) {
126 | this.createMatrixCell(new Point(x, y), cellSize, cellMargin, value);
127 | }
128 | return this;
129 | },
130 |
131 | /** @private */
132 | createMatrixCell: function (point, size, margin, value) {
133 | var shape = this.createCellRectangle(point, size, margin);
134 |
135 | this.cells.push(this.createCell(point, shape, value));
136 | },
137 |
138 | /** @private */
139 | createCell: function (point, shape, value) {
140 | return new TileEngine.Cell( this, point, shape, value );
141 | },
142 |
143 | /** @private */
144 | createCellRectangle: function (point, cellSize, cellMargin) {
145 | return new Rectangle({
146 | from: new Point(
147 | (cellSize.x + cellMargin.x) * point.x,
148 | (cellSize.y + cellMargin.y) * point.y
149 | ),
150 | size: cellSize
151 | });
152 | },
153 |
154 | /** @private */
155 | isIndexOutOfBounds: function (point) {
156 | return point.x < 0 || point.y < 0 || point.x >= this.width || point.y >= this.height;
157 | },
158 |
159 | /** @private */
160 | updateCell: function (cell) {
161 | if (!this.requireUpdate) {
162 | this.events.fire('update', [ this ]);
163 | }
164 | atom.array.include( this.cellsUpdate, cell );
165 | return this;
166 | }
167 |
168 | });
--------------------------------------------------------------------------------
/Source/LibCanvas.js:
--------------------------------------------------------------------------------
1 | /*
2 | ---
3 |
4 | name: "LibCanvas"
5 |
6 | description: "LibCanvas initialization"
7 |
8 | license:
9 | - "[GNU Lesser General Public License](http://opensource.org/licenses/lgpl-license.php)"
10 | - "[MIT License](http://opensource.org/licenses/mit-license.php)"
11 |
12 | authors:
13 | - Pavel Ponomarenko aka Shock
14 |
15 | provides: LibCanvas
16 |
17 | ...
18 | */
19 |
20 | var LibCanvas = this.LibCanvas = declare({ name: 'LibCanvas', prototype: {} })
21 | .own({
22 | Buffer: function () {
23 | return LibCanvas.buffer.apply( LibCanvas, arguments );
24 | },
25 | buffer: function (width, height, withCtx) {
26 | var canvas, size, a = slice.call(arguments), last = a[a.length-1];
27 |
28 | withCtx = (typeof last === 'boolean' ? a.pop() : false);
29 |
30 | size = Size(a.length == 1 ? a[0] : a);
31 |
32 | canvas = atom.dom.create("canvas", {
33 | width : size.width,
34 | height : size.height
35 | }).first;
36 |
37 | if (withCtx) canvas.ctx = new Context2D(canvas);
38 | return canvas;
39 | },
40 | 'declare.classes': {},
41 | declare: function (declareName, shortName, Parent, object) {
42 | if (typeof shortName == 'object') {
43 | object = Parent;
44 | Parent = shortName;
45 | shortName = null;
46 | }
47 | if (object == null) {
48 | object = Parent;
49 | Parent = null;
50 | }
51 | var Class = declare( declareName, Parent, object );
52 | if (shortName) {
53 | if (shortName in this['declare.classes']) {
54 | throw new Error( 'Duplicate declaration: ' + shortName );
55 | }
56 | this['declare.classes'][shortName] = Class;
57 | }
58 | return Class;
59 | },
60 | extract: function (to) {
61 | to = to || global;
62 | for (var k in this['declare.classes']) {
63 | to[k] = this['declare.classes'][k];
64 | }
65 | return to;
66 | }
67 | });
--------------------------------------------------------------------------------
/Source/Plugins/Animation/Animation.js:
--------------------------------------------------------------------------------
1 | /*
2 | ---
3 |
4 | name: "Plugins.Animation.Core"
5 |
6 | description: ""
7 |
8 | license:
9 | - "[GNU Lesser General Public License](http://opensource.org/licenses/lgpl-license.php)"
10 | - "[MIT License](http://opensource.org/licenses/mit-license.php)"
11 |
12 | authors:
13 | - Pavel Ponomarenko aka Shock
14 |
15 | provides:
16 | - Plugins.Animation
17 | - Plugins.Animation.Core
18 |
19 | requires:
20 | - LibCanvas
21 |
22 | ...
23 | */
24 |
25 | /** @class Animation */
26 | var Animation = LibCanvas.declare( 'LibCanvas.Plugins.Animation', 'Animation', {
27 | /** @private */
28 | ownStartTime: null,
29 | /** @private */
30 | timeoutId : 0,
31 | /** @private */
32 | synchronizedWith: null,
33 |
34 | initialize: function (settings) {
35 | this.bindMethods('update');
36 |
37 | this.events = new atom.Events(this);
38 | this.settings = new atom.Settings(settings).addEvents(this.events);
39 | this.run();
40 | },
41 |
42 | stop: function () {
43 | this.startTime = null;
44 | return this.update();
45 | },
46 |
47 | run: function () {
48 | this.startTime = Date.now();
49 | return this.update();
50 | },
51 |
52 | synchronize: function (anim) {
53 | this.synchronizedWith = anim;
54 | return this;
55 | },
56 |
57 | get: function () {
58 | return this.sheet.get(this.startTime);
59 | },
60 |
61 | /** @private */
62 | get sheet () {
63 | return this.settings.get('sheet');
64 | },
65 |
66 | /** @private */
67 | set sheet (sheet) {
68 | return this.settings.set('sheet', sheet);
69 | },
70 |
71 | /** @private */
72 | set startTime (time) {
73 | this.ownStartTime = time;
74 | },
75 |
76 | /** @private */
77 | get startTime () {
78 | if (this.synchronizedWith) {
79 | return this.synchronizedWith.startTime;
80 | } else {
81 | return this.ownStartTime;
82 | }
83 | },
84 |
85 | /** @private */
86 | update: function () {
87 | var delay = this.getDelay();
88 |
89 | clearTimeout(this.timeoutId);
90 |
91 | if (delay == null || this.startTime == null) {
92 | this.events.fire('stop');
93 | } else {
94 | this.timeoutId = setTimeout( this.update, delay );
95 | this.events.fire('update', [ this.get() ]);
96 | }
97 | return this;
98 | },
99 |
100 | /** @private */
101 | getDelay: function () {
102 | return this.startTime == null ? null :
103 | this.sheet.getCurrentDelay(this.startTime);
104 | }
105 | });
--------------------------------------------------------------------------------
/Source/Plugins/Animation/Frames.js:
--------------------------------------------------------------------------------
1 | /*
2 | ---
3 |
4 | name: "Plugins.Animation.Frames"
5 |
6 | description: ""
7 |
8 | license:
9 | - "[GNU Lesser General Public License](http://opensource.org/licenses/lgpl-license.php)"
10 | - "[MIT License](http://opensource.org/licenses/mit-license.php)"
11 |
12 | authors:
13 | - Pavel Ponomarenko aka Shock
14 |
15 | provides:
16 | - Plugins.Animation
17 | - Plugins.Animation.Frames
18 |
19 | requires:
20 | - LibCanvas
21 | - Plugins.Animation.Core
22 |
23 | ...
24 | */
25 |
26 | /** @class Animation.Frames */
27 | atom.declare( 'LibCanvas.Plugins.Animation.Frames', {
28 | /** @private */
29 | sprites: [],
30 |
31 | initialize: function (image, width, height) {
32 | if (image == null) throw new TypeError('`image` cant be null');
33 |
34 | this.sprites = [];
35 | this.image = image;
36 | this.size = new Size(
37 | Math.round( width == null ? image.width : width ),
38 | Math.round( height == null ? image.height : height )
39 | );
40 |
41 | this.prepare();
42 | },
43 |
44 | get: function (id) {
45 | var sprite = this.sprites[id];
46 |
47 | if (!sprite) {
48 | throw new Error('No sprite with such id: ' + id);
49 | }
50 |
51 | return sprite;
52 | },
53 |
54 | get length () {
55 | return this.sprites.length;
56 | },
57 |
58 | /** @private */
59 | prepare: function () {
60 | var x, y,
61 | im = this.image,
62 | w = this.size.width,
63 | h = this.size.height;
64 |
65 | for (y = 0; y <= im.height - h; y += h) {
66 | for (x = 0; x <= im.width - w; x += w) {
67 | this.sprites.push( this.makeSprite(new Point(x, y)) );
68 | }
69 | }
70 |
71 | if (!this.length) {
72 | throw new TypeError('Animation is empty');
73 | }
74 | },
75 |
76 | /** @private */
77 | makeSprite: function (from) {
78 | var
79 | size = this.size,
80 | buffer = LibCanvas.buffer(size, true);
81 |
82 | buffer.ctx.drawImage({
83 | image: this.image,
84 | draw : buffer.ctx.rectangle,
85 | crop : new Rectangle(from, size)
86 | });
87 |
88 | return buffer;
89 | }
90 | });
--------------------------------------------------------------------------------
/Source/Plugins/Animation/Image.js:
--------------------------------------------------------------------------------
1 | /*
2 | ---
3 |
4 | name: "Plugins.Animation.Image"
5 |
6 | description: ""
7 |
8 | license:
9 | - "[GNU Lesser General Public License](http://opensource.org/licenses/lgpl-license.php)"
10 | - "[MIT License](http://opensource.org/licenses/mit-license.php)"
11 |
12 | authors:
13 | - Pavel Ponomarenko aka Shock
14 |
15 | provides:
16 | - Plugins.Animation
17 | - Plugins.Animation.Image
18 |
19 | requires:
20 | - LibCanvas
21 | - Plugins.Animation.Core
22 |
23 | ...
24 | */
25 |
26 | /** @name Animation.Image */
27 | atom.declare( 'LibCanvas.Plugins.Animation.Image', {
28 | /** @private */
29 | initialize: function (animation) {
30 | this.bindMethods('update');
31 |
32 | if (animation instanceof Animation.Sheet) {
33 | animation = { sheet: animation };
34 | }
35 | if (!(animation instanceof Animation)) {
36 | animation = new Animation(animation);
37 | }
38 |
39 | this.buffer = LibCanvas.buffer(animation.sheet.size, true);
40 | this.element = atom.dom(this.buffer);
41 | this.animation = animation;
42 | this.element.controller = this;
43 |
44 | animation.events.add( 'update', this.update );
45 | },
46 |
47 | /** @private */
48 | update: function (image) {
49 | var ctx = this.buffer.ctx;
50 |
51 | ctx.clearAll();
52 | if (image) ctx.drawImage(image);
53 | }
54 | }).own({
55 | element: function (animation) {
56 | return new this(animation).element;
57 | }
58 | });
--------------------------------------------------------------------------------
/Source/Plugins/Animation/Sheet.js:
--------------------------------------------------------------------------------
1 | /*
2 | ---
3 |
4 | name: "Plugins.Animation.Sheet"
5 |
6 | description: ""
7 |
8 | license:
9 | - "[GNU Lesser General Public License](http://opensource.org/licenses/lgpl-license.php)"
10 | - "[MIT License](http://opensource.org/licenses/mit-license.php)"
11 |
12 | authors:
13 | - Pavel Ponomarenko aka Shock
14 |
15 | provides:
16 | - Plugins.Animation
17 | - Plugins.Animation.Sheet
18 |
19 | requires:
20 | - LibCanvas
21 | - Plugins.Animation.Core
22 |
23 | ...
24 | */
25 |
26 | /** @class Animation.Sheet */
27 | atom.declare( 'LibCanvas.Plugins.Animation.Sheet', {
28 |
29 | initialize: function (options) {
30 | this.frames = options.frames;
31 | this.delay = options.delay;
32 | this.looped = options.looped;
33 | if (options.sequence == null) {
34 | this.sequence = atom.array.range(0, this.frames.length - 1);
35 | } else {
36 | this.sequence = options.sequence;
37 | }
38 | },
39 |
40 | /** @private */
41 | get size () {
42 | return this.frames.size;
43 | },
44 |
45 | /** @private */
46 | get: function (startTime) {
47 | if (startTime == null) return null;
48 |
49 | var id = this.getFrameId(this.countFrames(startTime));
50 | return id == null ? id : this.frames.get( id );
51 | },
52 |
53 | /** @private */
54 | getCurrentDelay: function (startTime) {
55 | var frames, switchTime;
56 |
57 | frames = this.countFrames(startTime);
58 |
59 | if (this.getFrameId(frames) == null) {
60 | return null;
61 | }
62 |
63 | // когда был включён текущий кадр
64 | switchTime = frames * this.delay + startTime;
65 |
66 | // до следующего кадра - задержка минус время, которое уже показывается текущий
67 | return this.delay - ( Date.now() - switchTime );
68 | },
69 |
70 | /** @private */
71 | getFrameId: function (framesCount) {
72 | if (this.looped) {
73 | return this.sequence[ framesCount % this.sequence.length ];
74 | } else if (framesCount >= this.sequence.length) {
75 | return null;
76 | } else {
77 | return this.sequence[framesCount];
78 | }
79 | },
80 |
81 | /** @private */
82 | countFrames: function (startTime) {
83 | return Math.floor( (Date.now() - startTime) / this.delay );
84 | }
85 |
86 | });
--------------------------------------------------------------------------------
/Source/Plugins/Canvas2DContext.js:
--------------------------------------------------------------------------------
1 | /*
2 | ---
3 |
4 | name: "Canvas2DContext"
5 |
6 | description: "LibCanvas.Canvas2DContext is similar to original 2d context (and chainable). Can be used for creating your own contexts"
7 |
8 | license: "[GNU Lesser General Public License](http://opensource.org/licenses/lgpl-license.php)"
9 |
10 | authors:
11 | - "Shock "
12 |
13 | requires:
14 | - LibCanvas
15 |
16 | provides: Canvas2DContext
17 |
18 | ...
19 | */
20 |
21 | new function () {
22 |
23 | var object = {
24 | initialize: function (canvas) {
25 | if (canvas instanceof CanvasRenderingContext2D) {
26 | this.ctx2d = canvas;
27 | this.canvas = this.ctx2d.canvas;
28 | } else {
29 | this.canvas = canvas;
30 | this.ctx2d = canvas.getOriginalContext('2d');
31 | }
32 | },
33 | get width () { return this.canvas.width },
34 | get height() { return this.canvas.height },
35 | set width (width) { this.canvas.width = width },
36 | set height(height) { this.canvas.height = height }
37 | },
38 |
39 | methods = (
40 | 'arc arcTo beginPath bezierCurveTo clearRect clip ' +
41 | 'closePath drawImage fill fillRect fillText lineTo moveTo ' +
42 | 'quadraticCurveTo rect restore rotate save scale setTransform ' +
43 | 'stroke strokeRect strokeText transform translate'
44 | ).split(' '),
45 |
46 | getterMethods = (
47 | 'createPattern drawFocusRing isPointInPath measureText ' +
48 | 'createImageData createLinearGradient ' +
49 | 'createRadialGradient getImageData putImageData'
50 | ).split(' '),
51 |
52 | properties = (
53 | 'fillStyle font globalAlpha globalCompositeOperation lineCap ' +
54 | 'lineJoin lineWidth miterLimit shadowOffsetX shadowOffsetY ' +
55 | 'shadowBlur shadowColor strokeStyle textAlign textBaseline'
56 | ).split(' ');
57 |
58 | properties.forEach(function (property) {
59 | atom.accessors.define(object, property, {
60 | set: function (value) {
61 | try {
62 | this.ctx2d[property] = value;
63 | } catch (e) {
64 | throw TypeError('Exception while setting «' + property + '» to «' + value + '»: ' + e.message);
65 | }
66 | },
67 | get: function () {
68 | return this.ctx2d[property];
69 | }
70 | })
71 | });
72 |
73 | methods.forEach(function (method) {
74 | object[method] = function () {
75 | this.ctx2d[method].apply(this.ctx, arguments);
76 | return this;
77 | };
78 | });
79 |
80 | getterMethods.forEach(function (method) {
81 | object[method] = function () {
82 | return this.ctx2d[method].apply(this.ctx, arguments);
83 | };
84 | });
85 |
86 | atom.declare( 'LibCanvas.Canvas2DContext', object );
87 |
88 | };
--------------------------------------------------------------------------------
/Source/Plugins/Curve/Curve.js:
--------------------------------------------------------------------------------
1 | /*
2 | ---
3 |
4 | name: "Plugins.Curve"
5 |
6 | description: "Provides math base for bezier curves"
7 |
8 | license:
9 | - "[GNU Lesser General Public License](http://opensource.org/licenses/lgpl-license.php)"
10 | - "[MIT License](http://opensource.org/licenses/mit-license.php)"
11 |
12 | authors:
13 | - Pavel Ponomarenko aka Shock
14 |
15 | provides: Plugins.Curve.Core
16 |
17 | requires:
18 | - LibCanvas
19 | - Point
20 |
21 | ...
22 | */
23 |
24 | /** @name LibCanvas.Plugins.Curve */
25 | atom.declare( 'LibCanvas.Plugins.Curve', {
26 |
27 | step: 0.0001,
28 |
29 | initialize: function (data) {
30 | var Class = this.constructor.classes[data.points.length];
31 |
32 | if (Class) return new Class(data);
33 |
34 | this.setData(data);
35 | },
36 |
37 | setData: function (data) {
38 | this.from = data.from;
39 | this.to = data.to;
40 | this.cp = data.points;
41 | },
42 |
43 | getAngle: function (t) {
44 | var f;
45 |
46 | if (t < this.step) {
47 | f = t - this.step;
48 | } else {
49 | f = t;
50 | t += this.step;
51 | }
52 |
53 | return this.getPoint(t).angleTo(this.getPoint(f));
54 | }
55 |
56 | }).own({
57 | classes: {},
58 |
59 | addClass: function (points, Class) {
60 | this.classes[points] = Class;
61 | }
62 | });
--------------------------------------------------------------------------------
/Source/Plugins/Curve/Quadratic.js:
--------------------------------------------------------------------------------
1 | /*
2 | ---
3 |
4 | name: "Plugins.Curve.Quadratic"
5 |
6 | description: "Provides math base for bezier curves"
7 |
8 | license:
9 | - "[GNU Lesser General Public License](http://opensource.org/licenses/lgpl-license.php)"
10 | - "[MIT License](http://opensource.org/licenses/mit-license.php)"
11 |
12 | authors:
13 | - Pavel Ponomarenko aka Shock
14 |
15 | provides:
16 | - Plugins.Curve
17 | - Plugins.Curve.Quadratic
18 |
19 | requires:
20 | - Plugins.Curve.Core
21 |
22 | ...
23 | */
24 |
25 | /** @name LibCanvas.Plugins.Curve.Quadratic */
26 | atom.declare( 'LibCanvas.Plugins.Curve.Quadratic', LibCanvas.Plugins.Curve, {
27 |
28 | initialize: function (data) {
29 | this.setData(data);
30 | },
31 |
32 | getPoint: function (t) {
33 | var
34 | from = this.from,
35 | to = this.to,
36 | point= this.cp[0],
37 | i = 1 - t;
38 |
39 | return new Point(
40 | i*i*from.x + 2*t*i*point.x + t*t*to.x,
41 | i*i*from.y + 2*t*i*point.y + t*t*to.y
42 | );
43 | }
44 |
45 | });
46 |
47 | LibCanvas.Plugins.Curve.addClass(1, LibCanvas.Plugins.Curve.Quadratic);
--------------------------------------------------------------------------------
/Source/Plugins/Curve/Qubic.js:
--------------------------------------------------------------------------------
1 | /*
2 | ---
3 |
4 | name: "Plugins.Curve.Qubic"
5 |
6 | description: "Provides math base for bezier curves"
7 |
8 | license:
9 | - "[GNU Lesser General Public License](http://opensource.org/licenses/lgpl-license.php)"
10 | - "[MIT License](http://opensource.org/licenses/mit-license.php)"
11 |
12 | authors:
13 | - Pavel Ponomarenko aka Shock
14 |
15 | provides:
16 | - Plugins.Curve
17 | - Plugins.Curve.Qubic
18 |
19 | requires:
20 | - Plugins.Curve.Core
21 |
22 | ...
23 | */
24 |
25 | /** @name LibCanvas.Plugins.Curve.Qubic */
26 | atom.declare( 'LibCanvas.Plugins.Curve.Qubic', LibCanvas.Plugins.Curve, {
27 |
28 | initialize: function (data) {
29 | this.setData(data);
30 | },
31 |
32 | getPoint: function (t) {
33 | var
34 | from = this.from,
35 | to = this.to,
36 | cp = this.cp,
37 | i = 1 - t;
38 |
39 | return new Point(
40 | i*i*i*from.x + 3*t*i*i*cp[0].x + 3*t*t*i*cp[1].x + t*t*t*to.x,
41 | i*i*i*from.y + 3*t*i*i*cp[0].y + 3*t*t*i*cp[1].y + t*t*t*to.y
42 | );
43 | }
44 |
45 | });
46 |
47 | LibCanvas.Plugins.Curve.addClass(2, LibCanvas.Plugins.Curve.Qubic);
--------------------------------------------------------------------------------
/Source/Plugins/Curves.js:
--------------------------------------------------------------------------------
1 | /*
2 | ---
3 |
4 | name: "Plugins.ExtendedCurves"
5 |
6 | description: "Curves with dynamic width and color"
7 |
8 | license: "[GNU Lesser General Public License](http://opensource.org/licenses/lgpl-license.php)"
9 |
10 | authors:
11 | - "Artem Smirnov "
12 | - "Shock "
13 |
14 | requires:
15 | - LibCanvas
16 | - Context2D
17 |
18 | provides: Plugins.ExtendedCurves
19 |
20 | ...
21 | */
22 |
23 | new function () {
24 |
25 | // The following text contains bad code and due to it's code it should not be readed by ANYONE!
26 |
27 | var
28 | Transition = atom.Transition,
29 | Color = atom.Color,
30 | EC = {};
31 |
32 | /** @returns {atom.Color} */
33 | EC.getColor = function (color) {
34 | return new Color(color || [0,0,0,1]);
35 | };
36 |
37 | EC.getPoints = function (prevPos, pos, width, inverted) {
38 | var
39 | w = pos.x-prevPos.x,
40 | h = pos.y-prevPos.y,
41 | dist = atom.math.hypotenuse(w, h),
42 |
43 | sin = h / dist,
44 | cos = w / dist,
45 |
46 | dx = sin * width,
47 | dy = cos * width;
48 |
49 | return [
50 | new Point(pos.x + dx, pos.y + dy*inverted),
51 | new Point(pos.x - dx, pos.y - dy*inverted)
52 | ];
53 | };
54 |
55 | EC.getGradientFunction = function (attr) {
56 | switch (typeof attr.gradient) {
57 | case 'undefined' :
58 | return atom.fn.lambda( EC.getColor(attr.color) );
59 |
60 | case 'function' :
61 | return attr.gradient;
62 |
63 | default :
64 | var gradient = { fn: attr.gradient.fn || 'linear' };
65 |
66 | if (typeof gradient.fn != 'string') {
67 | throw new Error('LibCanvas.Context2D.drawCurve -- unexpected type of gradient function');
68 | }
69 |
70 | gradient.from = EC.getColor(attr.gradient.from);
71 | gradient.to = EC.getColor(attr.gradient.to );
72 |
73 | var diff = gradient.from.diff( gradient.to );
74 |
75 | return function (t) {
76 | var factor = Transition.get(gradient.fn)(t);
77 | return gradient.from.shift( diff.clone().mul(factor) ).toString();
78 | };
79 | }
80 | };
81 |
82 | EC.getWidthFunction = function (attr) {
83 | attr.width = attr.width || 1;
84 | switch (typeof attr.width) {
85 | case 'number' : return atom.fn.lambda(attr.width);
86 | case 'function': return attr.width;
87 | case 'object' : return EC.getWidthFunction.range( attr.width );
88 | default: throw new TypeError('LibCanvas.Context2D.drawCurve -- unexpected type of width');
89 | }
90 | };
91 |
92 | EC.getWidthFunction.range = function (width) {
93 | if(!width.from || !width.to){
94 | throw new Error('LibCanvas.Context2D.drawCurve -- width.from or width.to undefined');
95 | }
96 | var diff = width.to - width.from;
97 | return function(t){
98 | return width.from + diff * Transition.get(width.fn || 'linear')(t);
99 | }
100 | };
101 |
102 | EC.curvesFunctions = [
103 | function (p, t) { // linear
104 | return {
105 | x:p[0].x + (p[1].x - p[0].x) * t,
106 | y:p[0].y + (p[1].y - p[0].y) * t
107 | };
108 | },
109 | function (p,t) { // quadratic
110 | var i = 1-t;
111 | return {
112 | x:i*i*p[0].x + 2*t*i*p[1].x + t*t*p[2].x,
113 | y:i*i*p[0].y + 2*t*i*p[1].y + t*t*p[2].y
114 | };
115 | },
116 | function (p, t) { // qubic
117 | var i = 1-t;
118 | return {
119 | x:i*i*i*p[0].x + 3*t*i*i*p[1].x + 3*t*t*i*p[2].x + t*t*t*p[3].x,
120 | y:i*i*i*p[0].y + 3*t*i*i*p[1].y + 3*t*t*i*p[2].y + t*t*t*p[3].y
121 | };
122 | }
123 | ];
124 |
125 | Context2D.prototype.drawCurve = function (obj) {
126 | var points = atom.array.append( [Point(obj.from)], obj.points.map(Point), [Point(obj.to)] );
127 |
128 | var gradientFunction = EC.getGradientFunction(obj), //Getting gradient function
129 | widthFunction = EC.getWidthFunction(obj), //Getting width function
130 | curveFunction = EC.curvesFunctions[ obj.points.length ]; //Getting curve function
131 |
132 | if (!curveFunction) throw new Error('LibCanvas.Context2D.drawCurve -- unexpected number of points');
133 |
134 | var step = obj.step || 0.02;
135 |
136 | var invertedMultipler = obj.inverted ? 1 : -1;
137 |
138 | var controlPoint, prevContorolPoint,
139 | drawPoints , prevDrawPoints ,
140 | width , color, prevColor, style;
141 |
142 | prevContorolPoint = curveFunction(points, -step);
143 |
144 | for (var t=-step ; t<1.02 ; t += step) {
145 | controlPoint = curveFunction(points, t);
146 | color = gradientFunction(t);
147 | width = widthFunction(t) / 2;
148 |
149 | drawPoints = EC.getPoints(prevContorolPoint, controlPoint, width, invertedMultipler);
150 |
151 | if (t >= step) {
152 | // #todo: reduce is part of array, not color
153 | var diff = EC.getColor(prevColor).diff(color);
154 |
155 | if ( (diff.red + diff.green + diff.blue) > 150 ) {
156 | style = this.createLinearGradient(prevContorolPoint, controlPoint);
157 | style.addColorStop(0, prevColor);
158 | style.addColorStop(1, color);
159 | } else {
160 | style = color;
161 | }
162 |
163 | this
164 | .set("lineWidth",1)
165 | .beginPath(prevDrawPoints[0])
166 | .lineTo (prevDrawPoints[1])
167 | .lineTo (drawPoints[1])
168 | .lineTo (drawPoints[0])
169 | .fill (style)
170 | .stroke(style);
171 | }
172 | prevDrawPoints = drawPoints;
173 | prevContorolPoint = controlPoint;
174 | prevColor = color;
175 | }
176 | return this;
177 | };
178 |
179 | };
--------------------------------------------------------------------------------
/Source/Plugins/Image.js:
--------------------------------------------------------------------------------
1 | /*
2 | ---
3 |
4 | name: "Plugins.Image"
5 |
6 | description: "Provides some Image extensions"
7 |
8 | license:
9 | - "[GNU Lesser General Public License](http://opensource.org/licenses/lgpl-license.php)"
10 | - "[MIT License](http://opensource.org/licenses/mit-license.php)"
11 |
12 | authors:
13 | - "Shock "
14 |
15 | requires:
16 | - LibCanvas
17 | - Shapes.Rectangle
18 |
19 | provides: Plugins.Image
20 |
21 | ...
22 | */
23 |
24 | var UtilsImage = atom.declare( 'LibCanvas.Utils.Image', {
25 | canvasCache: null,
26 |
27 | initialize: function (image) {
28 | this.image = image;
29 | this.cache = {};
30 | },
31 |
32 | /**
33 | * @param {Rectangle} rect
34 | * #todo: use createPattern
35 | */
36 | createSprite: function (rect) {
37 | var image, buf, xShift, yShift, x, y, xMax, yMax, crop, size, current, from, to;
38 |
39 | if (rect.width <= 0 || rect.height <= 0) {
40 | throw new TypeError('Wrong rectangle size');
41 | }
42 |
43 | image = this.image;
44 | buf = LibCanvas.buffer(rect.width, rect.height, true);
45 |
46 | // если координаты выходят за левый/верхний край картинки
47 | if (rect.from.x < 0) xShift = Math.ceil(Math.abs(rect.from.x) / rect.width );
48 | if (rect.from.y < 0) yShift = Math.ceil(Math.abs(rect.from.y) / rect.height);
49 | if (xShift || yShift) {
50 | rect = rect.clone().move(new Point(
51 | xShift * image.width,
52 | yShift * image.height
53 | ));
54 | }
55 |
56 | // для того, чтобы была возможность указывать ректангл, выходящий
57 | // за пределы картинки. текущая картинка повторяется как паттерн
58 | xMax = Math.ceil(rect.to.x / image.width );
59 | yMax = Math.ceil(rect.to.y / image.height);
60 | for (y = yMax; y-- > 0;) for (x = xMax; x-- > 0;) {
61 | current = new Point(x * image.width, y * image.height);
62 | from = current.clone();
63 | to = from.clone().move([image.width, image.height]);
64 |
65 | if (from.x < rect.from.x) from.x = rect.from.x;
66 | if (from.y < rect.from.y) from.y = rect.from.y;
67 | if ( to.x > rect. to .x) to.x = rect. to .x;
68 | if ( to.y > rect. to .y) to.y = rect. to .y;
69 |
70 | crop = new Rectangle(from, to);
71 | size = crop.size;
72 | crop.from.x %= image.width;
73 | crop.from.y %= image.height;
74 | crop.size = size;
75 |
76 | if (x) current.x -= rect.from.x;
77 | if (y) current.y -= rect.from.y;
78 |
79 | if (size.width && size.height) buf.ctx.drawImage({
80 | image : image,
81 | crop : crop,
82 | draw : new Rectangle( current, size )
83 | });
84 | }
85 |
86 | return buf;
87 | },
88 |
89 | toCanvas: function () {
90 | var cache = this.canvasCache;
91 |
92 | if (!cache) {
93 | cache = this.canvasCache = LibCanvas.buffer(this, true);
94 | cache.ctx.drawImage(this);
95 | }
96 | return cache;
97 | },
98 |
99 | isLoaded: function () {
100 | return this.constructor.isLoaded( this.image );
101 | },
102 |
103 | sprite: function () {
104 | if (!this.isLoaded()) throw new Error('Not loaded in Image.sprite, logged');
105 |
106 | if (arguments.length) {
107 | var
108 | rect = Rectangle(arguments),
109 | index = rect.dump(),
110 | cache = this.cache[index];
111 |
112 | if (!cache) {
113 | cache = this.cache[index] = this.createSprite(rect);
114 | }
115 | return cache;
116 | } else {
117 | return this.toCanvas();
118 | }
119 | }
120 | });
121 |
122 | UtilsImage.own({
123 | isLoaded : function (image) {
124 | return image.complete && ( (image.naturalWidth == null) || !!image.naturalWidth );
125 | },
126 |
127 | sprite: function (image, rectangle) {
128 | return this.mix(image).sprite(rectangle);
129 | },
130 |
131 | toCanvas: function (image) {
132 | return this.mix(image).toCanvas();
133 | },
134 |
135 | mix: function (image) {
136 | var key = 'libcanvas.image';
137 |
138 | if (!image[key]) {
139 | image[key] = new this(image);
140 | }
141 |
142 | return image[key];
143 | }
144 | });
--------------------------------------------------------------------------------
/Source/Plugins/ImagePrototype.js:
--------------------------------------------------------------------------------
1 | /*
2 | ---
3 |
4 | name: "Plugins.ImagePrototype"
5 |
6 | description: "Provides some Image extensions"
7 |
8 | license:
9 | - "[GNU Lesser General Public License](http://opensource.org/licenses/lgpl-license.php)"
10 | - "[MIT License](http://opensource.org/licenses/mit-license.php)"
11 |
12 | authors:
13 | - "Shock "
14 |
15 | requires:
16 | - LibCanvas
17 | - Utils.Image
18 |
19 | provides: Plugins.ImagePrototype
20 |
21 | ...
22 | */
23 |
24 | // tag
25 | atom.core.append(HTMLImageElement.prototype, {
26 | createSprite: function (rect) {
27 | return UtilsImage.mix(this).createSprite(rect);
28 | },
29 | toCanvas: function () {
30 | return UtilsImage.mix(this).toCanvas();
31 | },
32 | sprite : function () {
33 | var utils = UtilsImage.mix(this);
34 |
35 | return utils.sprite.apply( utils, arguments );
36 | },
37 | isLoaded : function () {
38 | return UtilsImage.isLoaded(this);
39 | }
40 | });
41 |
42 | // mixin from image
43 | atom.core.append(HTMLCanvasElement.prototype, {
44 | createSprite : HTMLImageElement.prototype.createSprite,
45 | sprite : HTMLImageElement.prototype.sprite,
46 | isLoaded : atom.fn.lambda(true),
47 | toCanvas : atom.fn.lambda()
48 | });
--------------------------------------------------------------------------------
/Source/Shapes/Circle.js:
--------------------------------------------------------------------------------
1 | /*
2 | ---
3 |
4 | name: "Shapes.Circle"
5 |
6 | description: "Provides circle as canvas object"
7 |
8 | license:
9 | - "[GNU Lesser General Public License](http://opensource.org/licenses/lgpl-license.php)"
10 | - "[MIT License](http://opensource.org/licenses/mit-license.php)"
11 |
12 | authors:
13 | - "Shock "
14 |
15 | requires:
16 | - LibCanvas
17 | - Point
18 | - Shape
19 |
20 | provides: Shapes.Circle
21 |
22 | ...
23 | */
24 |
25 | /** @class Circle */
26 | var Circle = LibCanvas.declare( 'LibCanvas.Shapes.Circle', 'Circle', Shape, {
27 | set : function () {
28 | var
29 | center, radius,
30 | a = atom.array.pickFrom(arguments);
31 |
32 | if (a.length >= 3) {
33 | center = new Point(a[0], a[1]);
34 | radius = a[2];
35 | } else if (a.length == 2) {
36 | center = Point.from(a[0]);
37 | radius = a[1];
38 | } else {
39 | a = a[0];
40 | radius = a.r == null ? a.radius : a.r;
41 | if ('x' in a && 'y' in a) {
42 | center = new Point(a.x, a.y);
43 | } else if ('center' in a) {
44 | center = Point.from(a.center);
45 | } else if ('from' in a) {
46 | center = new Point(a.from).move({
47 | x: this.radius,
48 | y: this.radius
49 | });
50 | }
51 | }
52 |
53 | this.center = center;
54 | this.radius = radius;
55 |
56 | if (center == null) throw new TypeError('center is null');
57 | if (radius == null) throw new TypeError('radius is null');
58 | },
59 | // we need accessors to redefine parent "get center"
60 | get center ( ) { return this._center; },
61 | set center (c) { this._center = c; },
62 | grow: function (size) {
63 | this.radius += size/2;
64 | return this;
65 | },
66 | getCoords : function () {
67 | return this.center;
68 | },
69 | hasPoint : function (point) {
70 | return this.center.checkDistanceTo(point, this.radius, true);
71 | },
72 | scale : function (factor, pivot) {
73 | if (pivot) this.center.scale(factor, pivot);
74 | this.radius *= factor;
75 | return this;
76 | },
77 | getCenter: function () {
78 | return this.center;
79 | },
80 | intersect : function (obj) {
81 | if (obj instanceof this.constructor) {
82 | return this.center.checkDistanceTo(obj.center, this.radius + obj.radius, true);
83 | } else {
84 | return this.getBoundingRectangle().intersect( obj );
85 | }
86 | },
87 | move : function (distance, reverse) {
88 | this.center.move(distance, reverse);
89 | return this;
90 | },
91 | processPath : function (ctx, noWrap) {
92 | if (!noWrap) ctx.beginPath();
93 | if (this.radius) {
94 | ctx.arc({
95 | circle : this,
96 | angle : [0, Math.PI * 2]
97 | });
98 | }
99 | if (!noWrap) ctx.closePath();
100 | return ctx;
101 | },
102 | getBoundingRectangle: function () {
103 | var r = this.radius, center = this.center;
104 | return new Rectangle(
105 | new Point(center.x - r, center.y - r),
106 | new Point(center.x + r, center.y + r)
107 | );
108 | },
109 | clone : function () {
110 | return new this.constructor(this.center.clone(), this.radius);
111 | },
112 | getPoints : function () {
113 | return { center : this.center };
114 | },
115 | equals : function (shape, accuracy) {
116 | return shape instanceof this.shape &&
117 | shape.radius == this.radius &&
118 | shape.center.equals(this.center, accuracy);
119 | },
120 | dump: function () {
121 | return '[shape Circle(center['+this.center.x+', '+this.center.y+'], '+this.radius+')]';
122 | }
123 | });
124 |
125 | /** @private */
126 | Circle.from = function (object) {
127 | if (object == null) return null;
128 |
129 | return object instanceof Circle ? object : new Circle(object);
130 | };
131 |
--------------------------------------------------------------------------------
/Source/Shapes/Ellipse.js:
--------------------------------------------------------------------------------
1 | /*
2 | ---
3 |
4 | name: "Shapes.Ellipse"
5 |
6 | description: "Provides ellipse as canvas object"
7 |
8 | license:
9 | - "[GNU Lesser General Public License](http://opensource.org/licenses/lgpl-license.php)"
10 | - "[MIT License](http://opensource.org/licenses/mit-license.php)"
11 |
12 | authors:
13 | - "Shock "
14 |
15 | requires:
16 | - LibCanvas
17 | - Point
18 | - Shapes.Rectangle
19 |
20 | provides: Shapes.Ellipse
21 |
22 | ...
23 | */
24 |
25 | /** @class Ellipse */
26 | var Ellipse = LibCanvas.declare( 'LibCanvas.Shapes.Ellipse', 'Ellipse', Rectangle, {
27 | set: function () {
28 | this.bindMethods( 'update' );
29 | Rectangle.prototype.set.apply(this, arguments);
30 | },
31 | _angle : 0,
32 | get angle () {
33 | return this._angle;
34 | },
35 | set angle (a) {
36 | if (this._angle == a) return;
37 | this._angle = atom.math.normalizeAngle(a);
38 | this.updateCache = true;
39 | },
40 | update: function () {
41 | this.updateCache = true;
42 | },
43 | rotate : function (degree) {
44 | this.angle += degree;
45 | return this;
46 | },
47 | hasPoint : function () {
48 | var ctx = this.processPath( shapeTestBuffer().ctx );
49 | return ctx.isPointInPath(Point(arguments));
50 | },
51 | cache : null,
52 | updateCache : true,
53 | countCache : function () {
54 | if (this.cache && !this.updateCache) {
55 | return this.cache;
56 | }
57 |
58 | if (this.cache === null) {
59 | this.cache = [];
60 | for (var i = 12; i--;) this.cache.push(new Point());
61 | }
62 | var c = this.cache,
63 | angle = this._angle,
64 | kappa = .5522848,
65 | x = this.from.x,
66 | y = this.from.y,
67 | xe = this.to.x,
68 | ye = this.to.y,
69 | xm = (xe + x) / 2,
70 | ym = (ye + y) / 2,
71 | ox = (xe - x) / 2 * kappa,
72 | oy = (ye - y) / 2 * kappa;
73 | c[0].set(x, ym - oy); c[ 1].set(xm - ox, y); c[ 2].set(xm, y);
74 | c[3].set(xm + ox, y); c[ 4].set(xe, ym -oy); c[ 5].set(xe, ym);
75 | c[6].set(xe, ym +oy); c[ 7].set(xm +ox, ye); c[ 8].set(xm, ye);
76 | c[9].set(xm -ox, ye); c[10].set(x, ym + oy); c[11].set(x, ym);
77 |
78 | if (angle) {
79 | var center = new Point(xm, ym);
80 | for (i = c.length; i--;) c[i].rotate(angle, center);
81 | }
82 |
83 | return c;
84 | },
85 | processPath : function (ctx, noWrap) {
86 | if (!noWrap) ctx.beginPath();
87 | var c = this.countCache();
88 | ctx.beginPath(c[11])
89 | .bezierCurveTo(c[0], c[1], c[2])
90 | .bezierCurveTo(c[3], c[4], c[5])
91 | .bezierCurveTo(c[6], c[7], c[8])
92 | .bezierCurveTo(c[9], c[10],c[11]);
93 | if (!noWrap) ctx.closePath();
94 | return ctx;
95 | },
96 | equals : function (shape, accuracy) {
97 | return Rectangle.prototype.equals.call( this, shape, accuracy ) && shape.angle == this.angle;
98 | },
99 | draw : function (ctx, type) {
100 | this.processPath(ctx)[type]();
101 | return this;
102 | },
103 | dump: function (name) {
104 | return Rectangle.prototype.dump.call(this, name || 'Ellipse');
105 | }
106 | });
--------------------------------------------------------------------------------
/Source/Shapes/Line.js:
--------------------------------------------------------------------------------
1 | /*
2 | ---
3 |
4 | name: "Shapes.Line"
5 |
6 | description: "Provides line as canvas object"
7 |
8 | license:
9 | - "[GNU Lesser General Public License](http://opensource.org/licenses/lgpl-license.php)"
10 | - "[MIT License](http://opensource.org/licenses/mit-license.php)"
11 |
12 | authors:
13 | - "Shock "
14 |
15 | requires:
16 | - LibCanvas
17 | - Point
18 | - Shape
19 |
20 | provides: Shapes.Line
21 |
22 | ...
23 | */
24 |
25 | var Line = function () {
26 |
27 | var between = function (x, a, b, accuracy) {
28 | return atom.number.equals(x, a, accuracy)
29 | || atom.number.equals(x, b, accuracy)
30 | || (a < x && x < b)
31 | || (b < x && x < a);
32 | };
33 |
34 | var halfPi = Math.PI/2;
35 |
36 | /** @class Line */
37 | return LibCanvas.declare( 'LibCanvas.Shapes.Line', 'Line', Shape, {
38 | set : function (from, to) {
39 | var a = atom.array.pickFrom(arguments);
40 |
41 | if (a.length === 4) {
42 | this.from = new Point( a[0], a[1] );
43 | this.to = new Point( a[2], a[3] );
44 | } else {
45 | this.from = Point.from(a[0] || a.from);
46 | this.to = Point.from(a[1] || a.to);
47 | }
48 |
49 | return this;
50 | },
51 | hasPoint : function (point) {
52 | var fx = this.from.x,
53 | fy = this.from.y,
54 | tx = this.to.x,
55 | ty = this.to.y,
56 | px = point.x,
57 | py = point.y;
58 |
59 | if (!( atom.number.between(point.x, Math.min(fx, tx), Math.max(fx, tx))
60 | && atom.number.between(point.y, Math.min(fy, ty), Math.max(fy, ty))
61 | )) return false;
62 |
63 | // if triangle square is zero - points are on one line
64 | return atom.number.round(((fx-px)*(ty-py)-(tx-px)*(fy-py)), 6) == 0;
65 | },
66 | getBoundingRectangle: function () {
67 | return new Rectangle(this.from, this.to).fillToPixel().grow(2);
68 | },
69 | intersect: function (line, point, accuracy) {
70 | if (line.constructor != this.constructor) {
71 | return this.getBoundingRectangle().intersect( line );
72 | }
73 | var a = this.from, b = this.to, c = line.from, d = line.to, x, y, FALSE = point ? null : false;
74 | if (atom.number.equals(d.x, c.x, accuracy)) { // DC == vertical line
75 | if (atom.number.equals(b.x, a.x, accuracy)) {
76 | if (atom.number.equals(a.x, d.x, accuracy)) {
77 | if (atom.number.between(a.y, c.y, d.y)) {
78 | return a.clone();
79 | } else if (atom.number.between(b.y, c.y, d.y)) {
80 | return b.clone();
81 | } else {
82 | return FALSE;
83 | }
84 | } else {
85 | return FALSE;
86 | }
87 | }
88 | x = d.x;
89 | y = b.y + (x-b.x)*(a.y-b.y)/(a.x-b.x);
90 | } else {
91 | x = ((a.x*b.y - b.x*a.y)*(d.x-c.x)-(c.x*d.y - d.x*c.y)*(b.x-a.x))/((a.y-b.y)*(d.x-c.x)-(c.y-d.y)*(b.x-a.x));
92 | y = ((c.y-d.y)*x-(c.x*d.y-d.x*c.y))/(d.x-c.x);
93 | x *= -1;
94 | }
95 |
96 | if (!between(x, a.x, b.x, accuracy)) return FALSE;
97 | if (!between(y, a.y, b.y, accuracy)) return FALSE;
98 | if (!between(x, c.x, d.x, accuracy)) return FALSE;
99 | if (!between(y, c.y, d.y, accuracy)) return FALSE;
100 |
101 | return point ? new Point(x, y) : true;
102 | },
103 | perpendicular: function (point) {
104 | point = Point( point );
105 | var
106 | fX = this.from.x,
107 | fY = this.from.y,
108 | tX = this.to.x,
109 | tY = this.to.y,
110 | pX = point.x,
111 | pY = point.y,
112 | dX = (tX-fX) * (tX-fX),
113 | dY = (tY-fY) * (tY-fY),
114 | rX = ((tX-fX)*(tY-fY)*(pY-fY)+fX*dY+pX*dX) / (dX+dY),
115 | rY = (tY-fY)*(rX-fX)/(tX-fX)+fY;
116 |
117 | return new Point( rX, rY );
118 | },
119 | distanceTo: function (p, asInfiniteLine) {
120 | p = Point(p);
121 | var f = this.from, t = this.to, angle, s, x, y;
122 |
123 | if (!asInfiniteLine) {
124 | angle = Math.atan2(p.x - t.x, p.y - t.y);
125 | if ( atom.number.between(angle, -halfPi, halfPi) ) {
126 | return t.distanceTo( p );
127 | }
128 |
129 | angle = Math.atan2(f.x - p.x, f.y - p.y);
130 | if ( atom.number.between(angle, -halfPi, halfPi) ) {
131 | return f.distanceTo( p );
132 | }
133 | }
134 |
135 | s = Math.abs(
136 | f.x * (t.y - p.y) +
137 | t.x * (p.y - f.y) +
138 | p.x * (f.y - t.y)
139 | ) / 2;
140 |
141 | x = f.x - t.x;
142 | y = f.y - t.y;
143 | return 2 * s / Math.sqrt(x*x+y*y);
144 | },
145 | get length () {
146 | return this.to.distanceTo(this.from);
147 | },
148 | getLength : function () {
149 | return this.length;
150 | },
151 | draw : function (ctx, type) {
152 | ctx.beginPath();
153 | this.processPath(ctx, true)[type]();
154 | ctx.closePath();
155 | return this;
156 | },
157 | processPath : function (ctx, noWrap) {
158 | if (!noWrap) ctx.beginPath();
159 | ctx.moveTo(this.from).lineTo(this.to);
160 | if (!noWrap) ctx.closePath();
161 | return ctx;
162 | },
163 | dump: function () {
164 | return Shape.prototype.dump.call(this, 'Line');
165 | }
166 | });
167 |
168 | }();
169 |
--------------------------------------------------------------------------------
/Source/Shapes/Path.js:
--------------------------------------------------------------------------------
1 | /*
2 | ---
3 |
4 | name: "Shapes.Path"
5 |
6 | description: "Provides Path as canvas object"
7 |
8 | license:
9 | - "[GNU Lesser General Public License](http://opensource.org/licenses/lgpl-license.php)"
10 | - "[MIT License](http://opensource.org/licenses/mit-license.php)"
11 |
12 | authors:
13 | - "Shock "
14 |
15 | requires:
16 | - LibCanvas
17 | - Point
18 | - Shape
19 | - Shapes.Polygon
20 |
21 | provides: Shapes.Path
22 |
23 | ...
24 | */
25 |
26 | /**
27 | * @class Path
28 | * @extends Polygon:
29 | * get center
30 | * draw()
31 | * move(distance, reverse)
32 | * scale(power, pivot)
33 | * rotate(angle, pivot)
34 | * getBoundingRectangle()
35 | * [empty] grow()
36 | */
37 | var Path = LibCanvas.declare( 'LibCanvas.Shapes.Path', 'Path', Polygon, {
38 | parts: [],
39 |
40 | initialize : function (parts) {
41 | this.parts = [];
42 |
43 | if (parts) this.set(parts);
44 | },
45 |
46 | set : function (parts) {
47 | this.parts.length = 0;
48 |
49 | if (Array.isArray(parts)) {
50 | for (var i = 0, l = parts.length; i < l; i++) {
51 | this.push(parts[i]);
52 | }
53 | }
54 | },
55 |
56 | get length () {
57 | return this.parts.length;
58 | },
59 |
60 | // methods
61 | moveTo: function (point) {
62 | return this.push('moveTo', [ Point.from(point) ]);
63 | },
64 | lineTo: function (point) {
65 | return this.push('lineTo', [ Point.from(point) ]);
66 | },
67 | curveTo: function (to, cp1, cp2) {
68 | var points = atom.array.pickFrom(arguments).map(Point);
69 | return this.push('curveTo', points);
70 | },
71 |
72 | // queue/stack
73 | push : function (method, points) {
74 | this.parts.push(Path.Part.from(method, points));
75 | return this;
76 | },
77 | unshift: function (method, points) {
78 | this.parts.unshift(Path.Part.from(method, points));
79 | return this;
80 | },
81 | pop : function () {
82 | return this.parts.pop();
83 | },
84 | shift: function () {
85 | return this.parts.shift();
86 | },
87 |
88 | processPath : function (ctx, noWrap) {
89 | if (!noWrap) ctx.beginPath();
90 | this.forEach(function (part) {
91 | ctx[part.method].apply(ctx, part.points);
92 | });
93 | if (!noWrap) ctx.closePath();
94 | return ctx;
95 | },
96 |
97 | intersect: function (obj) {
98 | return this.getBoundingRectangle()
99 | .intersect( obj.getBoundingRectangle() );
100 | },
101 |
102 | forEach: function (fn) {
103 | var parts = this.parts, i = 0, l = parts.length;
104 | while (i < l) {
105 | fn.call( this, parts[i++], i, this );
106 | }
107 | return this;
108 | },
109 |
110 | get points () {
111 | var points = [];
112 | this.forEach(function (part) {
113 | for (var i = 0, l = part.points.length; i < l; i++) {
114 | atom.array.include(points, part.points[i]);
115 | }
116 | });
117 | return points;
118 | },
119 |
120 | hasPoint : function (point) {
121 | var ctx = shapeTestBuffer().ctx;
122 | this.processPath(ctx);
123 | return ctx.isPointInPath(Point.from(point));
124 | },
125 | clone: function () {
126 | return new this.constructor(
127 | this.parts.invoke('clone')
128 | );
129 | }
130 | });
131 | /** @class Path.Part */
132 | atom.declare('LibCanvas.Shapes.Path.Part', {
133 | initialize: function (method, points) {
134 | this.method = method;
135 | this.points = points.map(Point);
136 | },
137 |
138 | clone: function () {
139 | return new this.constructor(
140 | this.method,
141 | this.points.invoke('clone')
142 | );
143 | }
144 | }).own({
145 | from: function (method, args) {
146 | if (method == null) {
147 | throw new Error('Empty path method');
148 | }
149 |
150 | if (typeof method == 'string') {
151 | return new this(method, args) ;
152 | } else if (atom.core.isArrayLike(method)) {
153 | return new this(method[0], args[1]);
154 | } else {
155 | return this;
156 | }
157 | }
158 | });
--------------------------------------------------------------------------------
/Source/Shapes/Polygon.js:
--------------------------------------------------------------------------------
1 | /*
2 | ---
3 |
4 | name: "Shapes.Polygon"
5 |
6 | description: "Provides user-defined concave polygon as canvas object"
7 |
8 | license:
9 | - "[GNU Lesser General Public License](http://opensource.org/licenses/lgpl-license.php)"
10 | - "[MIT License](http://opensource.org/licenses/mit-license.php)"
11 |
12 | authors:
13 | - "Shock "
14 |
15 | requires:
16 | - LibCanvas
17 | - Point
18 | - Shape
19 | - Shapes.Line
20 |
21 | provides: Shapes.Polygon
22 |
23 | ...
24 | */
25 |
26 | /** @class Polygon */
27 | var Polygon = LibCanvas.declare( 'LibCanvas.Shapes.Polygon', 'Polygon', Shape, {
28 | initialize: function method () {
29 | this.points = [];
30 | this._lines = [];
31 | method.previous.apply(this, arguments);
32 | },
33 | set : function (poly) {
34 | this.points.length = 0;
35 |
36 | var source = Array.isArray(poly) ? poly : atom.core.toArray(arguments);
37 |
38 | atom.array.append( this.points,
39 | source
40 | .filter(Boolean)
41 | .map(Point)
42 | );
43 |
44 | this._lines.length = 0;
45 |
46 | return this;
47 | },
48 | get length () {
49 | return this.points.length;
50 | },
51 | get lines () {
52 | var
53 | lines = this._lines,
54 | p = this.points,
55 | l = p.length,
56 | i = 0;
57 |
58 | if (lines.length != l) for (;i < l; i++) {
59 | lines.push( new Line( p[i], i+1 == l ? p[0] : p[i+1] ) );
60 | }
61 |
62 | return this._lines;
63 | },
64 | get center () {
65 | return new Point().mean(this.points);
66 | },
67 | get: function (index) {
68 | return this.points[index];
69 | },
70 | getCoords : function () {
71 | return this.points[0];
72 | },
73 | processPath : function (ctx, noWrap) {
74 | var p = this.points, i = 0, l = p.length;
75 |
76 | if (!noWrap) ctx.beginPath();
77 | for (; i <= l; i++) {
78 | if (i == 0) {
79 | ctx.moveTo(p[i]);
80 | } else {
81 | ctx.lineTo(p[i == l ? 0 : i]);
82 | }
83 | }
84 | if (!noWrap) ctx.closePath();
85 |
86 | return ctx;
87 | },
88 |
89 | grow: function () { return this; },
90 |
91 | getBoundingRectangle: function () {
92 | var p = this.points, l = p.length, from, to;
93 |
94 | if (l == 0) {
95 | throw new Error('Shape is empty');
96 | }
97 |
98 | while (l--) {
99 |
100 | if (from) {
101 | from.x = Math.min( from.x, p[l].x );
102 | from.y = Math.min( from.y, p[l].y );
103 | to.x = Math.max( to.x, p[l].x );
104 | to.y = Math.max( to.y, p[l].y );
105 | } else {
106 | from = p[l].clone();
107 | to = p[l].clone();
108 | }
109 |
110 | }
111 |
112 | return new Rectangle( from, to );
113 | },
114 |
115 | // points invoking
116 | move : function (distance, reverse) {
117 | return this.invoke('move', distance, reverse)
118 | },
119 | rotate : function (angle, pivot) {
120 | return this.invoke('rotate', angle, pivot)
121 | },
122 | scale : function (power, pivot) {
123 | return this.invoke('scale', power, pivot)
124 | },
125 | invoke: function (method, args) {
126 | args = Array.prototype.slice.call(arguments, 1);
127 |
128 | this.points.map(function (point) {
129 | point[method].apply(point, args);
130 | });
131 | return this;
132 | },
133 | forEach : function (fn) {
134 | this.points.forEach(fn);
135 | return this;
136 | },
137 | each: function (fn, context) {
138 | return this.forEach(context ? fn.bind(context) : fn);
139 | },
140 |
141 | hasPoint : function (point) {
142 | point = Point.from(point);
143 |
144 | var result = false, points = this.points;
145 | for (var i = 0, l = this.length; i < l; i++) {
146 | var k = (i || l) - 1, I = points[i], K = points[k];
147 | if (
148 | (atom.number.between(point.y, I.y , K.y, "L")
149 | || atom.number.between(point.y, K.y , I.y, "L")
150 | ) && point.x < (K.x - I.x) * (point.y -I.y) / (K.y - I.y) + I.x
151 | ) {
152 | result = !result;
153 | }
154 | }
155 | return result;
156 | },
157 | intersect : function (poly) {
158 | if (poly.constructor != this.constructor) {
159 | return this.getBoundingRectangle().intersect( poly );
160 | }
161 |
162 | var tL = this.lines, pL = poly.lines, i = tL.length, k = pL.length;
163 | while (i-- > 0) for (k = pL.length; k-- > 0;) {
164 | if (tL[i].intersect(pL[k])) return true;
165 | }
166 | return false;
167 | },
168 | getPoints : function () {
169 | return atom.array.toHash(this.points);
170 | },
171 | clone: function () {
172 | return new this.constructor( atom.array.invoke(this.points, 'clone') );
173 | }
174 | });
--------------------------------------------------------------------------------
/Source/Shapes/RoundedRectangle.js:
--------------------------------------------------------------------------------
1 | /*
2 | ---
3 |
4 | name: "Shapes.RoundedRectangle"
5 |
6 | description: "Provides rounded rectangle as canvas object"
7 |
8 | license:
9 | - "[GNU Lesser General Public License](http://opensource.org/licenses/lgpl-license.php)"
10 | - "[MIT License](http://opensource.org/licenses/mit-license.php)"
11 |
12 | authors:
13 | - "Shock "
14 |
15 | requires:
16 | - LibCanvas
17 | - Shapes.Rectangle
18 |
19 | provides: Shapes.RoundedRectangle
20 |
21 | ...
22 | */
23 |
24 | /** @class RoundedRectangle */
25 | var RoundedRectangle = LibCanvas.declare(
26 | 'LibCanvas.Shapes.RoundedRectangle', 'RoundedRectangle', Rectangle, {
27 | radius: 0,
28 |
29 | setRadius: function (value) {
30 | this.radius = value;
31 | return this;
32 | },
33 | draw : Shape.prototype.draw,
34 | processPath : function (ctx, noWrap) {
35 | var from = this.from, to = this.to, radius = this.radius;
36 | if (!noWrap) ctx.beginPath();
37 | ctx
38 | .moveTo (from.x, from.y+radius)
39 | .lineTo (from.x, to.y-radius)
40 | .curveTo(from.x, to.y, from.x + radius, to.y)
41 | .lineTo (to.x-radius, to.y)
42 | .curveTo(to.x,to.y, to.x,to.y-radius)
43 | .lineTo (to.x, from.y+radius)
44 | .curveTo(to.x, from.y, to.x-radius, from.y)
45 | .lineTo (from.x+radius, from.y)
46 | .curveTo(from.x,from.y,from.x,from.y+radius);
47 | if (!noWrap) ctx.closePath();
48 | return ctx;
49 | },
50 |
51 |
52 | clone: function method () {
53 | return method.previous
54 | .apply(this, arguments)
55 | .setRadius(this.radius);
56 | },
57 |
58 | equals: function (shape, accuracy) {
59 | return Rectangle.prototype.equals.call( this, shape, accuracy ) && shape.radius == this.radius;
60 | },
61 |
62 | dump: function () {
63 | var p = function (p) { return '[' + p.x + ', ' + p.y + ']'; };
64 | return '[shape RoundedRectangle(from'+p(this.from)+', to'+p(this.to)+', radius='+this.radius+')]';
65 | }
66 | });
--------------------------------------------------------------------------------
/Source/overall.js:
--------------------------------------------------------------------------------
1 | /*
2 | ---
3 |
4 | name: "LibCanvas"
5 |
6 | description: "LibCanvas - free javascript library, based on AtomJS framework."
7 |
8 | license:
9 | - "[GNU Lesser General Public License](http://opensource.org/licenses/lgpl-license.php)"
10 | - "[MIT License](http://opensource.org/licenses/mit-license.php)"
11 |
12 | authors:
13 | - Pavel Ponomarenko aka Shock
14 |
15 | ...
16 | */
17 |
18 | (function (atom, Math) { // LibCanvas
19 |
20 | // bug in Safari 5.1 ( 'use strict' + 'set prop' )
21 | // 'use strict';
22 |
23 | var undefined,
24 | /** @global {Object} global */
25 | global = this,
26 | /** @global {Function} slice */
27 | slice = [].slice,
28 | /** @global {Function} declare */
29 | declare = atom.declare,
30 | /** @global {Function} Registry */
31 | Registry = atom.Registry,
32 | /** @global {Function} Events */
33 | Events = atom.Events,
34 | /** @global {Function} Settings */
35 | Settings = atom.Settings;
36 | /*** [Code] ***/
37 |
38 | }).call(typeof window == 'undefined' ? exports : window, atom, Math);
--------------------------------------------------------------------------------
/Source/package.yml:
--------------------------------------------------------------------------------
1 | name: "LibCanvas"
2 |
3 | exports: "libcanvas.js"
4 |
5 | web: "[libcanvas.com](http://libcanvas.com/)"
6 |
7 | description: "LibCanvas - html5 canvas framework"
8 |
9 | license:
10 | - "[GNU Lesser General Public License](http://opensource.org/licenses/lgpl-license.php)"
11 | - "[MIT License](http://opensource.org/licenses/mit-license.php)"
12 |
13 | copyright: "© [LibCanvas](http://libcanvas.com)"
14 |
15 | authors: "[LibCanvas Development Team](http://libcanvas.com)"
16 |
17 | sources: "*.js"
18 |
19 | overall: "overall.js"
--------------------------------------------------------------------------------