├── .documentup.json
├── .gitignore
├── LICENSE
├── README.md
├── demos
├── 00-helloworld.js
├── 01-painter.js
├── 02-writer.js
├── 03-game-goblins
│ ├── README.md
│ ├── game.js
│ └── resources
│ │ ├── background.png
│ │ ├── entry.wav
│ │ ├── hero.png
│ │ ├── monster.png
│ │ └── tada.wav
├── 04-audiocontext
│ ├── audio.js
│ └── conga1.wav
├── 05-game-fruits
│ ├── README.md
│ ├── fruits.js
│ ├── music.wav
│ ├── sounds
│ │ ├── bomb.wav
│ │ ├── fall.wav
│ │ ├── floor.wav
│ │ ├── fruit.wav
│ │ ├── heart.wav
│ │ └── timebullet.wav
│ └── sprites
│ │ ├── 1.png
│ │ ├── 2.png
│ │ ├── 3.png
│ │ ├── 4.png
│ │ ├── 5.png
│ │ ├── 6.png
│ │ ├── 7.png
│ │ ├── 8.png
│ │ ├── 9.png
│ │ ├── b1.png
│ │ ├── b2.png
│ │ ├── b3.png
│ │ ├── bg.jpg
│ │ ├── fox1.png
│ │ ├── fox2.png
│ │ ├── fox3.png
│ │ ├── fox4.png
│ │ ├── fox5.png
│ │ ├── fox6.png
│ │ ├── fox7.png
│ │ ├── fox8.png
│ │ └── heart.png
└── 06-irc-client
│ ├── README.md
│ ├── input.js
│ ├── irc.js
│ ├── nicklist.js
│ └── output.js
├── lib
├── audiobuffersource.js
├── audiocontext.js
├── canvas.js
├── canvascontext2d.js
├── common.js
├── core.js
├── five.js
├── image.js
└── window.js
├── make.js
├── package.json
├── screenshot.png
└── test
├── .gitignore
├── audio.js
├── canvas.js
├── canvascontext2d.js
├── image.js
├── img-ref
├── canvas-blank.png
├── context2d-drawImage-save-restore-matrix.png
├── context2d-drawImage-scale-mirror.png
├── context2d-drawImage-translate-imageontop.png
├── context2d-drawImage.png
├── context2d-fillRect-black-sq.png
├── context2d-fillRect-black-sq2.png
├── context2d-fillRect-blue-sq.png
├── context2d-fillRect-many-rgb-colored.png
├── context2d-fillRect-red-sq.png
├── context2d-fillRect-scale-redonblue.png
├── context2d-fillRect-translate-redonblue.png
├── context2d-fillText-hello-big-arial.png
├── context2d-fillText-hello-big-courier.png
├── context2d-fillText-hello-black.png
├── context2d-fillText-hello-green.png
├── context2d-fillText-scale-redonblue.png
├── context2d-fillText-translate-redonblue.png
├── context2d-strokePath-lineTo-translate-blueonright.png
└── context2d-strokePath-lineTo.png
├── resources
└── image.png
├── test.js
└── window.js
/.documentup.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Node-Five",
3 | "twitter": [
4 | "arturadib"
5 | ]
6 | }
7 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2011, Mozilla Corporation
2 | All rights reserved.
3 |
4 | You may use this project under the terms of the New BSD license as follows:
5 |
6 | Redistribution and use in source and binary forms, with or without
7 | modification, are permitted provided that the following conditions are met:
8 | * Redistributions of source code must retain the above copyright
9 | notice, this list of conditions and the following disclaimer.
10 | * Redistributions in binary form must reproduce the above copyright
11 | notice, this list of conditions and the following disclaimer in the
12 | documentation and/or other materials provided with the distribution.
13 | * Neither the name of Mozilla Corporation nor the
14 | names of its contributors may be used to endorse or promote products
15 | derived from this software without specific prior written permission.
16 |
17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 | ARE DISCLAIMED. IN NO EVENT SHALL MOZILLA CORPORATION BE LIABLE FOR ANY
21 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Node-Five
2 |
3 | _This is a highly experimental, rapidly-changing project. The APIs might change overnight._
4 |
5 | **Node-Five** brings a subset of HTML5 APIs to Node.js. Presently the main focus is on low-level graphics and audio (for example, `Canvas` and `AudioContext`), but other higher-level APIs are welcome. (HTML/CSS layout engine, anyone?)
6 |
7 | Node-Five is written in JavaScript on top of [Node-Qt](http://github.com/arturadib/node-qt).
8 |
9 |
10 |
11 |
12 | #### Hello world
13 |
14 | This example illustrates a minimal use of the HTML5 Canvas API:
15 |
16 | 
17 |
18 | ```javascript
19 | var five = require('path-to-node-five-dir'),
20 | window = new five.Window(300, 150),
21 | canvas = new five.Canvas(window),
22 | ctx = canvas.getContext('2d');
23 |
24 | ctx.fillStyle = 'black';
25 | ctx.fillText('hello node, hello qt', 20, 20);
26 | ```
27 |
28 | For other examples see the [demos/](five/tree/master/demos) directory.
29 |
30 |
31 |
32 |
33 |
34 | # Getting started
35 |
36 | Since the project is under heavy development, no npm packages are available at the moment. To start, clone the latest development version and install the necessary dependencies:
37 |
38 | ```
39 | $ git clone git://github.com/arturadib/node-five.git
40 | $ cd node-five
41 | $ npm install
42 | ```
43 |
44 | If everything went well you should be able to run the demos, for example:
45 |
46 | ```
47 | $ node demos/03-game-goblins/game.js
48 | ```
49 |
50 | To run the unit tests:
51 |
52 | ```
53 | $ node make test
54 | ```
55 |
56 | (Since different platforms generate different images based on several factors, it's likely the image-based regression tests will fail on your setup. Ignore those errors).
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
69 |
70 |
71 |
72 |
73 | # API reference
74 |
75 |
76 | ## five
77 |
78 | Main object. Typical usage is:
79 |
80 | ```
81 | var five = require('path-to-node-five-dir');
82 | ```
83 |
84 | #### useInterval()
85 | Add event handler to Node's event loop via setTimeout(). This is the default event loop integration.
86 |
87 | #### useTick()
88 | Add event handler to Node's event loop via `process.nextTick()`.
89 | This should used in applications that require more instant responsiveness (CPU-intensive!).
90 |
91 | #### stop()
92 | Stop Node-Five's event loop. Applications never exit without a call to this method.
93 |
94 | ## five.Window(width, height)
95 |
96 | Native window constructor with the given `height` and `width`.
97 |
98 | #### width = 640
99 | Gets/sets window width in pixels
100 |
101 | #### height = 480
102 | Gets/sets window height in pixels
103 |
104 | #### close()
105 | Closes window. It can't be reopened.
106 |
107 | #### addEventListener(event, callback)
108 | Binds `event` to `callback`. Supported events are listed below.
109 |
110 | #### removeEventListener(event, callback)
111 | Removes callback from `event` handler.
112 |
113 | #### Supported events for `addEventListener()`
114 |
115 | + `mousedown`:
116 | Callback will be passed `{ clientX, clientY, button }`. `button` values correspond
117 | to the convenience constants `five.LeftButton`, `five.RightButton`, etc.
118 | See http://developer.qt.nokia.com/doc/qt-4.8/qt.html#MouseButton-enum
119 | for a list of supported button codes
120 |
121 | + `mouseup`:
122 | Callback will be passed `{ clientX, clientY, button }` as in `mousedown`.
123 |
124 | + `mousemove`:
125 | Callback will be passed `{ clientX, clientY }`.
126 |
127 | + `keydown`:
128 | Callback will be passed `{ key, char }`.
129 | Key values correspond to the convenience constants `five.Key_Esc`, `five.Key_Left`, etc.
130 | See http://developer.qt.nokia.com/doc/qt-4.8/qt.html#Key-enum for the list of supported keys.
131 | `char` is the corresponding Unicode character, if available.
132 |
133 | + `keyup`:
134 | Callback will be passed `{ key, char }`. Details as in `keydown`.
135 |
136 | ## five.Canvas(window)
137 |
138 | Class/constructor for Canvas objects, either off-screen (no `window` argument) or inside an existing `window`.
139 |
140 | #### width = 300
141 |
142 | #### height = 150
143 |
144 | #### viewWidth = width
145 | (Non-standard) Width of the canvas view. Will crop canvas and create
146 | scroll bars if smaller than the canvas `width`.
147 |
148 | #### viewHeight = height
149 | (Non-standard) Height of the canvas view. Will crop canvas and create scroll bars if smaller
150 | than the canvas `height`.
151 |
152 | #### scrollTop = 0
153 | Vertical scroll position. To be used when `height > viewHeight`.
154 | Maximum value is `height - viewHeight`.
155 |
156 | #### scrollLeft = 0
157 | Horizontal scroll position. To be used when `width > viewWidth`.
158 | Maximum value is `width - viewWidth`.
159 |
160 | #### top = 0
161 | (Non-standard) Top position of the canvas with respect to parent window (if any), in pixels.
162 | Only absolute positioning is available.
163 |
164 | #### left = 0
165 | (Non-standard) Left position of the canvas with respect to parent window (if any), in pixels.
166 | Only absolute positioning is available.
167 |
168 | #### getContext(type)
169 | Presently only supports `type == '2d'`.
170 |
171 | #### toDataURL()
172 |
173 | ## five.Canvas.getContext('2d')
174 |
175 | The documentation below is for exposed methods after a `ctx = canvas.getContext('2d')`
176 | call, which returns a `CanvasRenderingContext2D` object.
177 |
178 | #### ctx.fillStyle = 'color'
179 | Currently only supports color types (e.g. `'rgb()'`, `'rgba()'`, `'blue'`, `'#aabbcc'`, etc)
180 |
181 | #### ctx.strokeStyle = 'color'
182 | Currently only supports color types (e.g. `'rgb()'`, `'rgba()'`, `'blue'`, `'#aabbcc'`, etc)
183 |
184 | #### ctx.font = '10px family'
185 | Currently only supports the format above
186 |
187 | #### ctx.fillRect(x, y, w, h)
188 |
189 | #### ctx.fillText(text, x, y)
190 |
191 | #### ctx.translate(x, y)
192 |
193 | #### ctx.scale(x, y)
194 |
195 | #### ctx.beginPath()
196 |
197 | #### ctx.closePath()
198 |
199 | #### ctx.moveTo(x, y)
200 |
201 | #### ctx.lineTo(x, y)
202 |
203 | #### ctx.stroke()
204 |
205 | #### ctx.drawImage(image, x, y)
206 | Presently only supports images created via `five.Image()`
207 |
208 | ## five.Image()
209 |
210 | Constructor for image objects. Intended to mirror `Image()` constructor from browsers.
211 |
212 | #### src = 'file_name'
213 | Presently only supports local paths, e.g. `./images/file.png`
214 |
215 | #### complete
216 |
217 | #### onload = callback
218 |
219 | ## five.AudioContext
220 |
221 | Class/constructor for AudioContext objects.
222 |
223 | #### destination
224 | Currently returns null
225 |
226 | #### createBufferSource()
227 | Returns a new AudioBufferSourceNode object
228 |
229 | ## five.AudioContext.createBufferSource()
230 |
231 | The documentation below is for exposed methods after a `source = context.createBufferSource()`
232 | call, which returns an `AudioBufferSourceNode` object.
233 |
234 | #### source.buffer = 'filename'
235 | Non-compliant. Presently must specify local filename.
236 |
237 | #### source.connect(dest)
238 | `dest` is currently a dummy variable. The destination will always
239 | be the default audio device
240 |
241 | #### source.loop = `true/false`
242 |
243 | #### source.noteOn(when)
244 | Currently `when = 0`, i.e. immediately
245 |
--------------------------------------------------------------------------------
/demos/00-helloworld.js:
--------------------------------------------------------------------------------
1 | var five = require('..'),
2 | window = new five.Window(640, 480),
3 | canvas = new five.Canvas(window),
4 | ctx = canvas.getContext('2d');
5 |
6 | canvas.width = window.width;
7 | canvas.height = window.height;
8 |
9 | ctx.font = '16px arial';
10 | ctx.fillText('Hello world, from Node-Five', 20, 20);
11 |
--------------------------------------------------------------------------------
/demos/01-painter.js:
--------------------------------------------------------------------------------
1 | var five = require('..');
2 |
3 | var window = new five.Window(640, 480),
4 | canvas = new five.Canvas(window),
5 | ctx = canvas.getContext('2d');
6 |
7 | canvas.width = window.width;
8 | canvas.height = window.height;
9 |
10 | ctx.strokeStyle = 'blue';
11 |
12 | var holdingButton = false;
13 |
14 | window.addEventListener('mousedown', function(e) {
15 | ctx.fillRect(e.clientX, e.clientY, 1, 1);
16 | ctx.beginPath();
17 | ctx.moveTo(e.clientX, e.clientY);
18 |
19 | holdingButton = true;
20 | });
21 |
22 | window.addEventListener('mouseup', function(e) {
23 | ctx.fillRect(e.clientX, e.clientY, 1, 1);
24 | ctx.beginPath();
25 | ctx.moveTo(e.clientX, e.clientY);
26 |
27 | holdingButton = false;
28 | });
29 |
30 | window.addEventListener('mousemove', function(e) {
31 | if (!holdingButton)
32 | return;
33 |
34 | ctx.lineTo(e.clientX, e.clientY);
35 | ctx.stroke();
36 | });
37 |
--------------------------------------------------------------------------------
/demos/02-writer.js:
--------------------------------------------------------------------------------
1 | var five = require('..');
2 |
3 | var window = new five.Window(640, 480),
4 | canvas = new five.Canvas(window),
5 | ctx = canvas.getContext('2d');
6 |
7 | canvas.width = window.width;
8 | canvas.height = window.height;
9 |
10 | // All units in pixels
11 | const kFontSize = 14,
12 | kInitialX = 10,
13 | kLinePadding = 4,
14 | kCharWidth = kFontSize - 4;
15 |
16 | var x = kInitialX, y = kFontSize + kLinePadding;
17 |
18 | // Reset writing area
19 | ctx.fillStyle = 'white';
20 | ctx.fillRect(0, 0, 640, 480);
21 |
22 | // Defaults
23 | ctx.fillStyle = 'blue';
24 | ctx.font = kFontSize + 'px courier';
25 |
26 | //
27 | // Key handler
28 | //
29 |
30 | window.addEventListener('keydown', function(e) {
31 | if (e.key === five.Key_Enter || e.key === five.Key_Return) {
32 | clearCursor(x, y);
33 | x = kInitialX;
34 | y += kFontSize + kLinePadding;
35 | showCursor(x, y);
36 | return;
37 | }
38 |
39 | if (e.key === five.Key_Backspace) {
40 | if (x === kInitialX)
41 | return;
42 |
43 | clearCursor(x, y);
44 | x -= kCharWidth;
45 |
46 | // Erase character
47 | ctx.save();
48 | ctx.fillStyle = 'white';
49 | ctx.fillRect(x, y - kFontSize, kCharWidth, kFontSize + 4);
50 | ctx.restore();
51 |
52 | showCursor(x, y);
53 | return;
54 | }
55 |
56 | // All others
57 |
58 | if (e.char.length === 0)
59 | return;
60 |
61 | clearCursor(x, y);
62 | ctx.fillText(e.char, x, y);
63 | x += kCharWidth;
64 | showCursor(x, y);
65 | });
66 |
67 | //
68 | // Cursor blinking
69 | //
70 |
71 | var cursorOn = false;
72 |
73 | function clearCursor(x, y) {
74 | ctx.save();
75 | ctx.fillStyle = 'white';
76 | ctx.fillRect(x, y-13, 3, 16);
77 | ctx.restore();
78 | cursorOn = false;
79 | }
80 |
81 | function showCursor(x, y) {
82 | ctx.save();
83 | ctx.fillStyle = 'black';
84 | ctx.fillRect(x, y-13, 3, 16);
85 | ctx.restore();
86 | cursorOn = true;
87 | }
88 |
89 | setInterval(function() {
90 | if (cursorOn)
91 | clearCursor(x, y);
92 | else
93 | showCursor(x, y);
94 | }, 500);
95 |
--------------------------------------------------------------------------------
/demos/03-game-goblins/README.md:
--------------------------------------------------------------------------------
1 | This example is adapted from the tutorial:
2 |
3 | + http://www.lostdecadegames.com/how-to-make-a-simple-html5-canvas-game/
4 | + https://github.com/lostdecade/simple_canvas_game
5 |
--------------------------------------------------------------------------------
/demos/03-game-goblins/game.js:
--------------------------------------------------------------------------------
1 | // Simple canvas game: Get the goblins!
2 | //
3 | // Adapted from the tutorial:
4 | // http://www.lostdecadegames.com/how-to-make-a-simple-html5-canvas-game/
5 | // https://github.com/lostdecade/simple_canvas_game
6 |
7 |
8 | var five = require('../..');
9 |
10 | // Create the canvas
11 | var window = new five.Window(512, 480);
12 | var canvas = new five.Canvas(window);
13 | var ctx = canvas.getContext("2d");
14 |
15 | canvas.width = window.width;
16 | canvas.height = window.height;
17 |
18 | // Background image
19 | var bgReady = false;
20 | var bgImage = new five.Image();
21 | bgImage.onload = function () {
22 | bgReady = true;
23 | };
24 | bgImage.src = __dirname + "/resources/background.png";
25 |
26 | // Hero image
27 | var heroReady = false;
28 | var heroImage = new five.Image();
29 | heroImage.onload = function () {
30 | heroReady = true;
31 | };
32 | heroImage.src = __dirname + "/resources/hero.png";
33 |
34 | // Monster image
35 | var monsterReady = false;
36 | var monsterImage = new five.Image();
37 | monsterImage.onload = function () {
38 | monsterReady = true;
39 | };
40 | monsterImage.src = __dirname + "/resources/monster.png";
41 |
42 | // Game objects
43 | var hero = {
44 | speed: 256 // movement in pixels per second
45 | };
46 | var monster = {};
47 | var monstersCaught = 0;
48 |
49 | // Handle keyboard controls
50 | var keysDown = {};
51 |
52 | window.addEventListener("keydown", function (e) {
53 | keysDown[e.key] = true;
54 | });
55 |
56 | window.addEventListener("keyup", function (e) {
57 | delete keysDown[e.key];
58 | }, false);
59 |
60 | // Reset the game when the player catches a monster
61 | var reset = function () {
62 | hero.x = canvas.width / 2;
63 | hero.y = canvas.height / 2;
64 |
65 | // Throw the monster somewhere on the screen randomly
66 | monster.x = 32 + (Math.random() * (canvas.width - 64));
67 | monster.y = 32 + (Math.random() * (canvas.height - 64));
68 | };
69 |
70 | // Update game objects
71 | var update = function (modifier) {
72 | if (five.Key_Up in keysDown) { // up
73 | hero.y -= hero.speed * modifier;
74 | }
75 | if (five.Key_Down in keysDown) { // down
76 | hero.y += hero.speed * modifier;
77 | }
78 | if (five.Key_Left in keysDown) { // left
79 | hero.x -= hero.speed * modifier;
80 | }
81 | if (five.Key_Right in keysDown) { // right
82 | hero.x += hero.speed * modifier;
83 | }
84 |
85 | // Are they touching?
86 | if (
87 | hero.x <= (monster.x + 32)
88 | && monster.x <= (hero.x + 32)
89 | && hero.y <= (monster.y + 32)
90 | && monster.y <= (hero.y + 32)
91 | ) {
92 | ++monstersCaught;
93 | playSound(__dirname + '/resources/tada.wav');
94 | reset();
95 | }
96 | };
97 |
98 | // Draw everything
99 | var render = function () {
100 | if (bgReady) {
101 | ctx.drawImage(bgImage, 0, 0);
102 | }
103 |
104 | if (heroReady) {
105 | ctx.drawImage(heroImage, hero.x, hero.y);
106 | }
107 |
108 | if (monsterReady) {
109 | ctx.drawImage(monsterImage, monster.x, monster.y);
110 | }
111 |
112 | // Score
113 | ctx.fillStyle = "rgb(250, 250, 250)";
114 | ctx.font = "24px Helvetica";
115 | // ctx.textAlign = "left";
116 | // ctx.textBaseline = "top";
117 | ctx.fillText("Goblins caught: " + monstersCaught, 50, 70);
118 | };
119 |
120 | // The main game loop
121 | var main = function () {
122 | var now = Date.now();
123 | var delta = now - then;
124 |
125 | update(delta / 1000);
126 | render();
127 |
128 | then = now;
129 | };
130 |
131 |
132 | function playSound(path) {
133 | var context = new five.AudioContext(),
134 | source = context.createBufferSource();
135 | source.buffer = path; // currently non-compliant
136 | source.connect(context.destination);
137 | source.noteOn(0); // play sound
138 | }
139 |
140 | // Audio intro
141 | playSound(__dirname + '/resources/entry.wav');
142 |
143 | // Let's play this game!
144 | reset();
145 | var then = Date.now();
146 | setInterval(main, 1); // Execute as fast as possible
147 |
--------------------------------------------------------------------------------
/demos/03-game-goblins/resources/background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arturadib/node-five/ea642fcef0d95d3df69fe0b974b80ccb95e25b47/demos/03-game-goblins/resources/background.png
--------------------------------------------------------------------------------
/demos/03-game-goblins/resources/entry.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arturadib/node-five/ea642fcef0d95d3df69fe0b974b80ccb95e25b47/demos/03-game-goblins/resources/entry.wav
--------------------------------------------------------------------------------
/demos/03-game-goblins/resources/hero.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arturadib/node-five/ea642fcef0d95d3df69fe0b974b80ccb95e25b47/demos/03-game-goblins/resources/hero.png
--------------------------------------------------------------------------------
/demos/03-game-goblins/resources/monster.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arturadib/node-five/ea642fcef0d95d3df69fe0b974b80ccb95e25b47/demos/03-game-goblins/resources/monster.png
--------------------------------------------------------------------------------
/demos/03-game-goblins/resources/tada.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arturadib/node-five/ea642fcef0d95d3df69fe0b974b80ccb95e25b47/demos/03-game-goblins/resources/tada.wav
--------------------------------------------------------------------------------
/demos/04-audiocontext/audio.js:
--------------------------------------------------------------------------------
1 | var five = require('../..');
2 |
3 | var context = new five.AudioContext();
4 |
5 | var source = context.createBufferSource();
6 | source.buffer = __dirname + '/conga1.wav'; // currently non-compliant
7 | source.connect(context.destination);
8 | source.noteOn(0); // play sound
9 |
--------------------------------------------------------------------------------
/demos/04-audiocontext/conga1.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arturadib/node-five/ea642fcef0d95d3df69fe0b974b80ccb95e25b47/demos/04-audiocontext/conga1.wav
--------------------------------------------------------------------------------
/demos/05-game-fruits/README.md:
--------------------------------------------------------------------------------
1 | Demo adapted from:
2 |
3 | https://developer.mozilla.org/en-US/demos/detail/fruits
4 |
5 | Copyright (c) 2012 E. Azuar # -LaNsHoR- lanshor@gmail.com
6 |
7 | This program is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program. If not, see .
19 |
--------------------------------------------------------------------------------
/demos/05-game-fruits/fruits.js:
--------------------------------------------------------------------------------
1 | /* Adapted to Node-Five by Artur B Adib */
2 | /* Original source: https://developer.mozilla.org/en-US/demos/detail/fruits */
3 |
4 | /*** Fruits! v0.3 ***/
5 |
6 | /* Copyright (c) 2012 E. Azuar # -LaNsHoR- lanshor@gmail.com
7 |
8 | This program is free software: you can redistribute it and/or modify
9 | it under the terms of the GNU General Public License as published by
10 | the Free Software Foundation, either version 3 of the License, or
11 | (at your option) any later version.
12 |
13 | This program is distributed in the hope that it will be useful,
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 | GNU General Public License for more details.
17 |
18 | You should have received a copy of the GNU General Public License
19 | along with this program. If not, see .
20 | */
21 |
22 | var five = require('../..');
23 |
24 | var window = new five.Window(800,600);
25 |
26 | //Aliases & Global Vars
27 | var game;
28 | var keyleft=0;
29 | var keyup=0;
30 | var keyright=0;
31 |
32 | //Global Functions
33 | function newGame()
34 | {
35 | if(game)
36 | {
37 | game.gameOver();
38 | setTimeout(function(){game=0;newGame();},50);
39 | return;
40 | }
41 | game=new Game();
42 | game.init();
43 | }
44 |
45 | function gameLoop()
46 | {
47 | if(!game.gameover)
48 | {
49 | game.loop();
50 | setTimeout(gameLoop,20) //about 50fps
51 | }
52 | }
53 |
54 | function keyControlDown(event)
55 | {
56 | var control=true;
57 | switch(event.key)
58 | {
59 | case five.Key_Left: keyleft=1; control=false;break;
60 | case five.Key_Up: keyup=1; control=false;break;
61 | case five.Key_Right: keyright=1;control=false;break;
62 | case five.Key_Down: control=false;
63 | }
64 | return control;
65 | }
66 |
67 | function keyControlUp(event)
68 | {
69 | var control=true;
70 | switch(event.key)
71 | {
72 | case five.Key_Left: keyleft=0; control=false;break;
73 | case five.Key_Up: keyup=0; control=false;break;
74 | case five.Key_Right: keyright=0;control=false;break;
75 | case five.Key_Down: control=false;
76 | }
77 | return control;
78 | }
79 |
80 | //Sound Control
81 | function Sound(id)
82 | {
83 | var context = new five.AudioContext(),
84 | source = context.createBufferSource();
85 |
86 | source.buffer = __dirname+"/sounds/"+id+".wav";
87 | source.connect(context.destination);
88 |
89 | this.play=function()
90 | {
91 | source.noteOn(0); // play sound
92 | }
93 | }
94 |
95 | var sounds=new Object();
96 | sounds.bomb=new Sound("bomb");
97 | sounds.fruit=new Sound("fruit");
98 | sounds.heart=new Sound("heart");
99 | sounds.fall=new Sound("fall");
100 | sounds.timebullet=new Sound("timebullet");
101 | sounds.floor=new Sound("floor");
102 |
103 | //Game Class
104 | function Game()
105 | {
106 | //--graphics
107 | this.context=0;
108 | //--sprites
109 | this.bg=0;
110 | this.fruits_sprites=0;
111 | this.player_sprites=0;
112 | this.heart=0;
113 | this.clock=0;
114 | this.floor=0;
115 | //--entities
116 | this.fruits=0;
117 | this.player=0;
118 | this.bonus_floor=0;
119 | this.bonus_heart=0;
120 | this.bonus_clock=0;
121 | //--game control
122 | this.loaded=0;
123 | this.points=0;
124 | this.health=0;
125 | this.frames=0;
126 | this.with_floor=0;
127 | this.with_clock=0;
128 | this.floor_end=0;
129 | this.clock_end=0;
130 | this.gameover=false;
131 | //--time
132 | this.start=0;
133 | this.seconds=0;
134 | //--others
135 | this.n_fruits=0;
136 | this.n_resources=21;
137 | this.idata=0; //image data of tunned background
138 | //------------------------------------------------------
139 | this.init=function()
140 | {
141 | //-- graphics
142 | var canvas=new five.Canvas(window);
143 | canvas.width = window.width;
144 | canvas.height = window.height;
145 |
146 | this.context=canvas.getContext('2d');
147 | this.context.fillStyle="black";
148 | this.context.fillText("loading... please, wait",50,50);
149 |
150 | //-- reset vars
151 | this.points=0;
152 | this.health=150;
153 | this.frames=0;
154 | this.with_floor=0;
155 | this.with_clock=0;
156 | this.bonus_heart=0;
157 | this.bonus_clock=0;
158 | this.bonus_floor=0;
159 | this.floor_end=0;
160 | this.clock_end=0;
161 | this.n_fruits=2;
162 | this.gameover=false;
163 | this.start=new Date();
164 | this.player=new Player();
165 | this.fruits=new Array();
166 | for(var i=0;i900){this.n_fruits=11;return;}
236 | if(this.seconds>600){this.n_fruits=10;return;}
237 | if(this.seconds>300){this.n_fruits=9;return;}
238 | if(this.seconds>45) {this.n_fruits=8;return;}
239 | if(this.seconds>30) {this.n_fruits=7;return;}
240 | if(this.seconds>25) {this.n_fruits=6;return;}
241 | if(this.seconds>15) {this.n_fruits=5;return;}
242 | if(this.seconds>10) {this.n_fruits=4;return;}
243 | if(this.seconds>5) {this.n_fruits=3;return;}
244 | }
245 | this.loop=function()
246 | {
247 | //control
248 | var now=new Date();
249 | this.increment();
250 | this.seconds=(now-this.start)/1000;
251 | this.frames++;
252 | //clean and draw background
253 | if(!this.with_clock)
254 | this.context.drawImage(this.bg,0,0);
255 | // else
256 | // this.context.putImageData(this.idata,0,0);
257 | //draw floor
258 | if(this.with_floor)
259 | {
260 | this.context.fillStyle="rgba(100,175,255,0.5)";
261 | this.context.fillRect(0,595,800,5);
262 | }
263 | //draw health hearts
264 | for(var i=0;ithis.health-30)
267 | break;
268 | this.context.drawImage(this.heart,i+5,5);
269 | }
270 | var mod=this.health%30;
271 | if(mod)
272 | this.context.drawImage(this.heart, 0, 0, mod, 30, i+5, 5, mod, 30);
273 | //draw and move bonus
274 | if(this.bonus_heart)
275 | {
276 | this.bonus_heart.render(this.context);
277 | if(this.bonus_heart.y>600)
278 | this.bonus_heart=0;
279 | }
280 | if(this.bonus_clock)
281 | {
282 | this.bonus_clock.render(this.context);
283 | if(this.bonus_clock.y>600)
284 | this.bonus_clock=0;
285 | }
286 | if(this.bonus_floor)
287 | {
288 | this.bonus_floor.render(this.context);
289 | if(this.bonus_floor.y>600)
290 | this.bonus_floor=0;
291 | }
292 | //draw and move fruits
293 | for(var i=0;i600)
299 | {
300 | sounds.fall.play();
301 | if(this.fruits[i].type!=9)
302 | this.health-=5;
303 | this.fruits[i]=new Fruit();
304 | }
305 | if(this.fruits[i].y>this.player.y && this.fruits[i].ythis.player.x && this.fruits[i].xthis.player.y && this.bonus_heart.ythis.player.x && this.bonus_heart.xthis.player.y && this.bonus_clock.ythis.player.x && this.bonus_clock.xthis.player.y && this.bonus_floor.ythis.player.x && this.bonus_floor.xthis.clock_end)
343 | this.with_clock=0;
344 | if(this.seconds>this.floor_end)
345 | this.with_floor=0;
346 | //bonus respawn
347 | if(this.seconds>30 && !this.bonus_heart && this.frames%1500==0)
348 | this.bonus_heart=new Bonus(1);
349 | if(this.seconds>45 && !this.bonus_clock && this.frames%750==0 && Math.random()>0.7)
350 | this.bonus_clock=new Bonus(2);
351 | if(this.seconds>20 && !this.bonus_floor && this.frames%500==0 && Math.random()>0.9)
352 | this.bonus_floor=new Bonus(3);
353 | //draw Player
354 | this.player.render(this.context);
355 | if(this.health<0)
356 | this.gameOver();
357 | } // this.loop
358 | } // Game()
359 |
360 | //Fruit Class
361 | function Fruit()
362 | {
363 | this.type=Math.round(Math.random()*7)+1;
364 | if(Math.random()>0.95)
365 | this.type=9; //fruit bomb
366 | this.v=Math.random()*5+1; //v in pixels/frame
367 | this.y=-30; //coord y
368 | this.x=Math.random()*750+25; //coord x
369 | this.img=new five.Image(); //sprite
370 | this.img.src=__dirname+"/sprites/"+this.type+".png";
371 | this.points=0;
372 | switch(this.type)
373 | {
374 | case 2:this.points=10;break;
375 | case 3:this.points=15;break;
376 | case 8:this.points=25;break;
377 | case 7:this.points=50;break;
378 | case 5:this.points=75;break;
379 | case 6:this.points=100;break;
380 | case 4:this.points=150;break;
381 | case 1:this.points=250;break;
382 | }
383 | this.render=function(context)
384 | {
385 | context.drawImage(this.img,this.x,this.y);
386 | if(game.with_floor && this.y>=565)
387 | {
388 | this.y=565;
389 | return;
390 | }
391 | if(game.with_clock)
392 | this.y+=(this.v*0.25); //time-bullet!
393 | else
394 | this.y+=this.v; //fall
395 | }
396 | } // Fruit()
397 |
398 | //Bonus Class
399 | function Bonus(type)
400 | {
401 | this.type=type; //1=heart; 2=clock; 3=floor
402 | this.v=Math.random()*5+1; //v in pixels/frame
403 | this.y=-30; //coord y
404 | this.x=Math.random()*750+25; //coord x
405 | this.img=new five.Image(); //sprite
406 | this.img.src=__dirname+"/sprites/b"+this.type+".png";
407 | this.render=function(context)
408 | {
409 | context.drawImage(this.img,this.x,this.y);
410 | if(game.with_floor && this.y>=565)
411 | {
412 | this.y=565;
413 | return;
414 | }
415 | if(game.with_clock)
416 | this.y+=(this.v*0.25); //time-bullet!
417 | else
418 | this.y+=this.v; //fall
419 | }
420 | } // Bonus()
421 |
422 | //Player Class
423 | function Player()
424 | {
425 | this.x=100;
426 | this.y=550;
427 | this.vx=0;
428 | this.vy=0;
429 | this.frames=0;
430 | this.right=0;
431 | //- Sprites
432 | this.sprites=new Array();
433 | for(var i=1;i<=8;i++)
434 | {
435 | this.sprites[i]=new five.Image();
436 | this.sprites[i].src=__dirname+"/sprites/fox"+i+".png";
437 | }
438 | this.render=function(context)
439 | {
440 | this.frames++;
441 | //- Movement
442 | if(keyleft)
443 | {
444 | if(this.right)
445 | this.vx=-1; //Fast stop
446 | else
447 | this.vx--;
448 | this.right=0;
449 | }
450 | else if(keyright)
451 | {
452 | if(!this.right)
453 | this.vx=1; //Fast stop
454 | else
455 | this.vx++;
456 | this.right=1;
457 | }
458 | else
459 | this.vx*=0.9;
460 | //- Limits
461 | if(this.x<0 || this.x>750)
462 | this.vx=0;
463 | this.vx=Math.max(this.vx,-15); //vx limits
464 | this.vx=Math.min(this.vx,+15); //vx limits
465 | //- Jump
466 | if(this.vy!=0) //Gravity
467 | this.vy+=1.5;
468 | if(keyup && this.y==550)
469 | this.vy=-20;
470 | if(((keyright && this.x==0) || (keyleft && this.x==750)) && this.y<550) //Super-Jump
471 | {
472 | if(this.x==0)
473 | keyleft=0;
474 | else
475 | keyright=0;
476 | this.vy=-20;
477 | }
478 | if(this.y>550)
479 | {
480 | this.vy=0;
481 | this.y=550;
482 | }
483 | this.y+=this.vy;
484 | this.x+=this.vx;
485 | this.x=Math.max(this.x,0); //scroll limits
486 | this.x=Math.min(this.x,750); //scroll limits
487 | //Render
488 | var i=5;
489 | if(this.vy==0 && Math.abs(this.vx)>0.2) //Run
490 | i=(Math.round(this.frames/2)%8)+1;
491 | else if(this.vy>0) //Jumping
492 | i=8;
493 | else if(this.vy<0) //Falling
494 | i=4;
495 | if(this.right)
496 | {
497 | context.save();
498 | context.translate(800, 0);
499 | context.scale(-1, 1);
500 | context.drawImage(this.sprites[i], 800-this.x-50, this.y);
501 | context.restore();
502 | }
503 | else
504 | context.drawImage(this.sprites[i],this.x,this.y);
505 | }
506 | } // Player()
507 |
508 | //Window control and event listeners
509 | window.addEventListener('keydown', keyControlDown);
510 | window.addEventListener('keyup', keyControlUp);
511 |
512 | // Play music
513 | {
514 | var context = new five.AudioContext(),
515 | source = context.createBufferSource();
516 |
517 | source.buffer = __dirname+"/music.wav";
518 | source.loop = true;
519 | source.connect(context.destination);
520 | source.noteOn(0);
521 | }
522 |
523 | newGame();
524 |
--------------------------------------------------------------------------------
/demos/05-game-fruits/music.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arturadib/node-five/ea642fcef0d95d3df69fe0b974b80ccb95e25b47/demos/05-game-fruits/music.wav
--------------------------------------------------------------------------------
/demos/05-game-fruits/sounds/bomb.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arturadib/node-five/ea642fcef0d95d3df69fe0b974b80ccb95e25b47/demos/05-game-fruits/sounds/bomb.wav
--------------------------------------------------------------------------------
/demos/05-game-fruits/sounds/fall.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arturadib/node-five/ea642fcef0d95d3df69fe0b974b80ccb95e25b47/demos/05-game-fruits/sounds/fall.wav
--------------------------------------------------------------------------------
/demos/05-game-fruits/sounds/floor.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arturadib/node-five/ea642fcef0d95d3df69fe0b974b80ccb95e25b47/demos/05-game-fruits/sounds/floor.wav
--------------------------------------------------------------------------------
/demos/05-game-fruits/sounds/fruit.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arturadib/node-five/ea642fcef0d95d3df69fe0b974b80ccb95e25b47/demos/05-game-fruits/sounds/fruit.wav
--------------------------------------------------------------------------------
/demos/05-game-fruits/sounds/heart.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arturadib/node-five/ea642fcef0d95d3df69fe0b974b80ccb95e25b47/demos/05-game-fruits/sounds/heart.wav
--------------------------------------------------------------------------------
/demos/05-game-fruits/sounds/timebullet.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arturadib/node-five/ea642fcef0d95d3df69fe0b974b80ccb95e25b47/demos/05-game-fruits/sounds/timebullet.wav
--------------------------------------------------------------------------------
/demos/05-game-fruits/sprites/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arturadib/node-five/ea642fcef0d95d3df69fe0b974b80ccb95e25b47/demos/05-game-fruits/sprites/1.png
--------------------------------------------------------------------------------
/demos/05-game-fruits/sprites/2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arturadib/node-five/ea642fcef0d95d3df69fe0b974b80ccb95e25b47/demos/05-game-fruits/sprites/2.png
--------------------------------------------------------------------------------
/demos/05-game-fruits/sprites/3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arturadib/node-five/ea642fcef0d95d3df69fe0b974b80ccb95e25b47/demos/05-game-fruits/sprites/3.png
--------------------------------------------------------------------------------
/demos/05-game-fruits/sprites/4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arturadib/node-five/ea642fcef0d95d3df69fe0b974b80ccb95e25b47/demos/05-game-fruits/sprites/4.png
--------------------------------------------------------------------------------
/demos/05-game-fruits/sprites/5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arturadib/node-five/ea642fcef0d95d3df69fe0b974b80ccb95e25b47/demos/05-game-fruits/sprites/5.png
--------------------------------------------------------------------------------
/demos/05-game-fruits/sprites/6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arturadib/node-five/ea642fcef0d95d3df69fe0b974b80ccb95e25b47/demos/05-game-fruits/sprites/6.png
--------------------------------------------------------------------------------
/demos/05-game-fruits/sprites/7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arturadib/node-five/ea642fcef0d95d3df69fe0b974b80ccb95e25b47/demos/05-game-fruits/sprites/7.png
--------------------------------------------------------------------------------
/demos/05-game-fruits/sprites/8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arturadib/node-five/ea642fcef0d95d3df69fe0b974b80ccb95e25b47/demos/05-game-fruits/sprites/8.png
--------------------------------------------------------------------------------
/demos/05-game-fruits/sprites/9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arturadib/node-five/ea642fcef0d95d3df69fe0b974b80ccb95e25b47/demos/05-game-fruits/sprites/9.png
--------------------------------------------------------------------------------
/demos/05-game-fruits/sprites/b1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arturadib/node-five/ea642fcef0d95d3df69fe0b974b80ccb95e25b47/demos/05-game-fruits/sprites/b1.png
--------------------------------------------------------------------------------
/demos/05-game-fruits/sprites/b2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arturadib/node-five/ea642fcef0d95d3df69fe0b974b80ccb95e25b47/demos/05-game-fruits/sprites/b2.png
--------------------------------------------------------------------------------
/demos/05-game-fruits/sprites/b3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arturadib/node-five/ea642fcef0d95d3df69fe0b974b80ccb95e25b47/demos/05-game-fruits/sprites/b3.png
--------------------------------------------------------------------------------
/demos/05-game-fruits/sprites/bg.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arturadib/node-five/ea642fcef0d95d3df69fe0b974b80ccb95e25b47/demos/05-game-fruits/sprites/bg.jpg
--------------------------------------------------------------------------------
/demos/05-game-fruits/sprites/fox1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arturadib/node-five/ea642fcef0d95d3df69fe0b974b80ccb95e25b47/demos/05-game-fruits/sprites/fox1.png
--------------------------------------------------------------------------------
/demos/05-game-fruits/sprites/fox2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arturadib/node-five/ea642fcef0d95d3df69fe0b974b80ccb95e25b47/demos/05-game-fruits/sprites/fox2.png
--------------------------------------------------------------------------------
/demos/05-game-fruits/sprites/fox3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arturadib/node-five/ea642fcef0d95d3df69fe0b974b80ccb95e25b47/demos/05-game-fruits/sprites/fox3.png
--------------------------------------------------------------------------------
/demos/05-game-fruits/sprites/fox4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arturadib/node-five/ea642fcef0d95d3df69fe0b974b80ccb95e25b47/demos/05-game-fruits/sprites/fox4.png
--------------------------------------------------------------------------------
/demos/05-game-fruits/sprites/fox5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arturadib/node-five/ea642fcef0d95d3df69fe0b974b80ccb95e25b47/demos/05-game-fruits/sprites/fox5.png
--------------------------------------------------------------------------------
/demos/05-game-fruits/sprites/fox6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arturadib/node-five/ea642fcef0d95d3df69fe0b974b80ccb95e25b47/demos/05-game-fruits/sprites/fox6.png
--------------------------------------------------------------------------------
/demos/05-game-fruits/sprites/fox7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arturadib/node-five/ea642fcef0d95d3df69fe0b974b80ccb95e25b47/demos/05-game-fruits/sprites/fox7.png
--------------------------------------------------------------------------------
/demos/05-game-fruits/sprites/fox8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arturadib/node-five/ea642fcef0d95d3df69fe0b974b80ccb95e25b47/demos/05-game-fruits/sprites/fox8.png
--------------------------------------------------------------------------------
/demos/05-game-fruits/sprites/heart.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arturadib/node-five/ea642fcef0d95d3df69fe0b974b80ccb95e25b47/demos/05-game-fruits/sprites/heart.png
--------------------------------------------------------------------------------
/demos/06-irc-client/README.md:
--------------------------------------------------------------------------------
1 | Extraordinarly simple IRC client, inspired by LimeChat.
2 |
3 | To use it you'll have to pull the npm package `irc`:
4 |
5 | ```
6 | $ npm install irc
7 | ```
8 |
9 | Then node-run `irc.js` as usual with the necessary Node-Five flags.
10 |
--------------------------------------------------------------------------------
/demos/06-irc-client/input.js:
--------------------------------------------------------------------------------
1 | var five = global.five,
2 | window = global.window;
3 |
4 | var inputCallback = null,
5 | text = '';
6 |
7 | // All units in pixels
8 | const kFontSize = 12,
9 | kInitialX = 10,
10 | kCharWidth = kFontSize - 4,
11 | kBgColor = 'black',
12 | kCursorColor = 'white',
13 | kColor = 'white',
14 | kLineColor = 'white';
15 |
16 |
17 | //
18 | // Initialize input area
19 | //
20 |
21 | var canvas = new five.Canvas(window),
22 | ctx = canvas.getContext('2d');
23 |
24 | canvas.width = window.width;
25 | canvas.height = 40;
26 | canvas.top = window.height - canvas.height;
27 | canvas.left = 0;
28 |
29 | ctx.fillStyle = kColor;
30 | ctx.font = kFontSize + 'px courier';
31 |
32 | function clearInput() {
33 | ctx.save();
34 | ctx.fillStyle = kBgColor;
35 | ctx.fillRect(0, 0, canvas.width, canvas.height);
36 | // Separation line
37 | ctx.fillStyle = kLineColor;
38 | ctx.fillRect(0, 0, canvas.width, 1);
39 | ctx.restore();
40 | }
41 |
42 | clearInput();
43 | var x = kInitialX, y = canvas.height/2 + kFontSize/2;
44 |
45 | //
46 | // Key handler
47 | //
48 |
49 | window.addEventListener('keydown', function(e) {
50 | if (e.key === five.Key_Enter || e.key === five.Key_Return) {
51 | clearCursor(x, y);
52 | x = kInitialX;
53 | clearInput();
54 | showCursor(x, y);
55 |
56 | if (inputCallback)
57 | inputCallback(text);
58 | text = '';
59 |
60 | return;
61 | }
62 |
63 | if (e.key === five.Key_Backspace) {
64 | if (x === kInitialX)
65 | return;
66 |
67 | clearCursor(x, y);
68 | x -= kCharWidth;
69 |
70 | // Erase character
71 | ctx.save();
72 | ctx.fillStyle = kBgColor;
73 | ctx.fillRect(x, y - kFontSize, kCharWidth, kFontSize + 4);
74 | ctx.restore();
75 |
76 | showCursor(x, y);
77 | return;
78 | }
79 |
80 | // All others
81 |
82 | if (e.char.length === 0)
83 | return;
84 |
85 | clearCursor(x, y);
86 | ctx.fillText(e.char, x, y);
87 | text += e.char;
88 | x += kCharWidth;
89 | showCursor(x, y);
90 | });
91 |
92 | //
93 | // Cursor blinking
94 | //
95 |
96 | var cursorOn = false;
97 |
98 | function clearCursor(x, y) {
99 | ctx.save();
100 | ctx.fillStyle = kBgColor;
101 | ctx.fillRect(x, y-13, 2, 16);
102 | ctx.restore();
103 | cursorOn = false;
104 | }
105 |
106 | function showCursor(x, y) {
107 | ctx.save();
108 | ctx.fillStyle = kCursorColor;
109 | ctx.fillRect(x, y-13, 2, 16);
110 | ctx.restore();
111 | cursorOn = true;
112 | }
113 |
114 | setInterval(function() {
115 | if (cursorOn)
116 | clearCursor(x, y);
117 | else
118 | showCursor(x, y);
119 | }, 500);
120 |
121 | //
122 | // Exports
123 | //
124 |
125 | exports.onInput = function(callback) {
126 | inputCallback = callback;
127 | }
128 |
--------------------------------------------------------------------------------
/demos/06-irc-client/irc.js:
--------------------------------------------------------------------------------
1 | //
2 | // Globals
3 | //
4 | global.five = require('../..');
5 | global.window = new five.Window(1000, 800);
6 |
7 | var irc = require('irc'),
8 | inputArea = require('./input'),
9 | outputArea = require('./output'),
10 | nicklistArea = require('./nicklist');
11 |
12 | const kServer = 'irc.mozilla.org',
13 | kNick = 'McTest',
14 | kChannel = '#labs';
15 |
16 | outputArea.push('~Connecting to '+kServer+' '+kChannel+' as "'+kNick+'"...');
17 |
18 | var client = new irc.Client(kServer, kNick, {
19 | channels: [kChannel]
20 | });
21 |
22 | inputArea.onInput(function(text) {
23 | outputArea.push('$'+kNick+': ' + text);
24 | client.say(kChannel, text);
25 | });
26 |
27 | client.addListener('names', function (channel, nicks) {
28 | var nickArr = [];
29 | for (nick in nicks) {
30 | nickArr.push(nick);
31 | }
32 | nickArr.sort();
33 | nicklistArea.update(nickArr);
34 | });
35 |
36 | client.addListener('message', function (from, to, message) {
37 | outputArea.push('@'+from+': ' + message);
38 | });
39 |
40 | client.addListener('quit', function (nick, reason, channels, message) {
41 | outputArea.push('~'+nick+' has left IRC: ' + (reason || 'no reason'));
42 | });
43 |
44 | client.addListener('join', function (channel, nick, message) {
45 | outputArea.push('~'+nick+' has joined');
46 | });
47 |
--------------------------------------------------------------------------------
/demos/06-irc-client/nicklist.js:
--------------------------------------------------------------------------------
1 | var five = global.five,
2 | window = global.window;
3 |
4 | // All units in pixels
5 | const kFontSize = 12,
6 | kBgColor = '#002',
7 | kColor = 'rgb(200,170,120)',
8 | kLineColor = 'white',
9 | kPaddingX = 8,
10 | kPaddingY = 4,
11 | kLineIncrement = kFontSize + 4,
12 | kWidth = 150;
13 |
14 | //
15 | // Initialize nick list area
16 | //
17 |
18 | var canvas = new five.Canvas(window),
19 | ctx = canvas.getContext('2d');
20 |
21 | canvas.width = kWidth;
22 | canvas.height = window.height - 40;
23 | canvas.viewHeight = canvas.height;
24 | canvas.top = 0;
25 | canvas.left = window.width - kWidth;
26 | ctx.font = kFontSize + 'px courier';
27 |
28 | function clearCanvas() {
29 | ctx.save();
30 | ctx.fillStyle = kBgColor;
31 | ctx.fillRect(0, 0, canvas.width, canvas.height);
32 | ctx.fillStyle = kLineColor;
33 | ctx.fillRect(0, 0, 1, canvas.height);
34 | ctx.restore();
35 | }
36 | clearCanvas();
37 |
38 | //
39 | // Exports
40 | //
41 |
42 | exports.update = function(nickArr) {
43 | // Reset y to very top
44 | var y = kFontSize + kPaddingY;
45 |
46 | var height = y + nickArr.length*kLineIncrement;
47 | if (height > canvas.height)
48 | canvas.height = height;
49 |
50 | clearCanvas();
51 |
52 | nickArr.forEach(function(nick) {
53 | // Simple output
54 | ctx.save();
55 | ctx.fillStyle = kColor;
56 | ctx.fillText(nick, kPaddingX, y);
57 | ctx.restore();
58 |
59 | y += kLineIncrement;
60 | });
61 | }
62 |
--------------------------------------------------------------------------------
/demos/06-irc-client/output.js:
--------------------------------------------------------------------------------
1 | var five = global.five,
2 | window = global.window;
3 |
4 | // All units in pixels
5 | const kFontSize = 12,
6 | kBgColor = 'black',
7 | kColor = 'white',
8 | kNickColor = 'rgb(200, 170, 120)',
9 | kInfoColor = '#666',
10 | kSelfColor = 'rgb(100, 120, 140)',
11 | kPaddingX = 8,
12 | kPaddingY = 8,
13 | kLineIncrement = kFontSize + 4;
14 |
15 | //
16 | // Initialize output area
17 | //
18 |
19 | var canvas = new five.Canvas(window),
20 | ctx = canvas.getContext('2d');
21 |
22 | canvas.width = window.width - 150;
23 | canvas.height = window.height - 40;
24 | canvas.viewHeight = canvas.height;
25 | canvas.top = 0;
26 | canvas.left = 0;
27 | ctx.font = kFontSize + 'px courier';
28 |
29 | var y, textArr = [];
30 |
31 | function printLine(line) {
32 | //
33 | // Info line: "~Line contents"
34 | //
35 | var infoMatch = line.match(/^\~/);
36 | if (infoMatch) {
37 | // Remove '~'
38 | line = line.replace(/^\~/, '');
39 | ctx.save();
40 | ctx.fillStyle = kInfoColor;
41 | ctx.fillText(line, kPaddingX, y);
42 | ctx.restore();
43 | y += kLineIncrement;
44 | return;
45 | }
46 |
47 | //
48 | // Simple output
49 | //
50 | ctx.save();
51 | ctx.fillStyle = kColor;
52 | ctx.fillText(line.substr(1), kPaddingX, y);
53 | ctx.restore();
54 |
55 | //
56 | // Message line: "@nick Message contents"
57 | // Prints colored nick on top of simple output
58 | //
59 | var nickMatch = line.match(/^\@([\w|\d|\-]+)/);
60 | if (nickMatch) {
61 | ctx.save();
62 | ctx.fillStyle = kNickColor;
63 | ctx.fillText(nickMatch[1], kPaddingX, y);
64 | ctx.restore();
65 | }
66 |
67 | //
68 | // Self message line: "$nick Message contents"
69 | // Prints colored nick on top of simple output
70 | //
71 | var selfMatch = line.match(/^\$([\w|\d|\-]+)/);
72 | if (selfMatch) {
73 | ctx.save();
74 | ctx.fillStyle = kSelfColor;
75 | ctx.fillText(selfMatch[1], kPaddingX, y);
76 | ctx.restore();
77 | }
78 |
79 | y += kLineIncrement;
80 | }
81 |
82 | // Re-paints the entire canvas
83 | function refresh() {
84 | // Reset y to very top
85 | y = kFontSize + kPaddingY;
86 |
87 | ctx.save();
88 | ctx.fillStyle = kBgColor;
89 | ctx.fillRect(0, 0, canvas.width, canvas.height);
90 | ctx.restore();
91 |
92 | textArr.forEach(function(text) {
93 | printLine(text);
94 | });
95 |
96 | canvas.scrollTop = canvas.height;
97 | }
98 |
99 | refresh();
100 |
101 | //
102 | // Exports
103 | //
104 |
105 | exports.push = function(text) {
106 | text = text.toString();
107 | textArr.push(text);
108 |
109 | if (y > canvas.height) {
110 | canvas.height += kLineIncrement;
111 | refresh();
112 | } else {
113 | printLine(text);
114 | }
115 | }
116 |
--------------------------------------------------------------------------------
/lib/audiobuffersource.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2011, Mozilla Corporation
2 | // All rights reserved.
3 | //
4 | // Author(s): Artur Adib
5 | //
6 | // You may use this file under the terms of the New BSD license as follows:
7 | //
8 | // Redistribution and use in source and binary forms, with or without
9 | // modification, are permitted provided that the following conditions are met:
10 | // * Redistributions of source code must retain the above copyright
11 | // notice, this list of conditions and the following disclaimer.
12 | // * Redistributions in binary form must reproduce the above copyright
13 | // notice, this list of conditions and the following disclaimer in the
14 | // documentation and/or other materials provided with the distribution.
15 | // * Neither the name of Mozilla Corporation nor the
16 | // names of its contributors may be used to endorse or promote products
17 | // derived from this software without specific prior written permission.
18 | //
19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 | // ARE DISCLAIMED. IN NO EVENT SHALL MOZILLA CORPORATION BE LIABLE FOR ANY
23 | // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26 | // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 | // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 |
30 | //@
31 | //@ ## five.AudioContext.createBufferSource()
32 | //@
33 | //@ The documentation below is for exposed methods after a `source = context.createBufferSource()`
34 | //@ call, which returns an `AudioBufferSourceNode` object.
35 |
36 | var qt = require('node-qt');
37 |
38 | //
39 | // Class AudioBufferSourceNode()
40 | //
41 | module.exports = function() {
42 |
43 | ///////////////////////////////////////////////////////////////////////////
44 | // Private
45 | //
46 |
47 | var sound_; // QSound
48 |
49 | ///////////////////////////////////////////////////////////////////////////
50 | // Public
51 | //
52 |
53 | var obj = Object.create({
54 | //@
55 | //@ #### source.buffer = 'filename'
56 | //@ Non-compliant. Presently must specify local filename.
57 | set buffer(val) {
58 | sound_ = new qt.QSound(val);
59 | },
60 |
61 | //@
62 | //@ #### source.connect(dest)
63 | //@ `dest` is currently a dummy variable. The destination will always
64 | //@ be the default audio device
65 | connect: function() {
66 | },
67 |
68 | //@
69 | //@ #### source.loop = `true/false`
70 | set loop(val) {
71 | if (!sound_)
72 | return;
73 |
74 | if (val)
75 | sound_.setLoops(-1);
76 | else
77 | sound_.setLoops(0);
78 | },
79 |
80 | //@
81 | //@ #### source.noteOn(when)
82 | //@ Currently `when = 0`, i.e. immediately
83 | noteOn: function() {
84 | if (!sound_)
85 | return;
86 |
87 | sound_.play();
88 | },
89 | }); // prototype
90 |
91 | ///////////////////////////////////////////////////////////////////////////
92 | // Constructor
93 | //
94 |
95 | return obj;
96 | }
97 |
--------------------------------------------------------------------------------
/lib/audiocontext.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2011, Mozilla Corporation
2 | // All rights reserved.
3 | //
4 | // Author(s): Artur Adib
5 | //
6 | // You may use this file under the terms of the New BSD license as follows:
7 | //
8 | // Redistribution and use in source and binary forms, with or without
9 | // modification, are permitted provided that the following conditions are met:
10 | // * Redistributions of source code must retain the above copyright
11 | // notice, this list of conditions and the following disclaimer.
12 | // * Redistributions in binary form must reproduce the above copyright
13 | // notice, this list of conditions and the following disclaimer in the
14 | // documentation and/or other materials provided with the distribution.
15 | // * Neither the name of Mozilla Corporation nor the
16 | // names of its contributors may be used to endorse or promote products
17 | // derived from this software without specific prior written permission.
18 | //
19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 | // ARE DISCLAIMED. IN NO EVENT SHALL MOZILLA CORPORATION BE LIABLE FOR ANY
23 | // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26 | // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 | // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 |
30 |
31 | //////////////////////////////////////////////////////////////////////////////
32 | //
33 | // Only a very simplified version of the API is currently implemented, and we
34 | // do so with a temporary hack based on QSound, which can only operate with
35 | // local files. We should really be using QAudioOutput, which is part of Qt's
36 | // low level multimedia facilities (QtMultimedia).
37 | //
38 | // Do not use the Phonon module. It's too high-level, and introduces terrible
39 | // platform dependencies (GStream lib on Linux, DirectX SDK on Windows, etc).
40 | //
41 |
42 |
43 | //@
44 | //@ ## five.AudioContext
45 | //@
46 | //@ Class/constructor for AudioContext objects.
47 |
48 | var qt = require('node-qt'),
49 | AudioBufferSourceNode = require('./audiobuffersource.js');
50 |
51 | //
52 | // Class AudioContext()
53 | //
54 | module.exports = function() {
55 |
56 | ///////////////////////////////////////////////////////////////////////////
57 | // Private
58 | //
59 |
60 | ///////////////////////////////////////////////////////////////////////////
61 | // Public
62 | //
63 |
64 | var obj = Object.create({
65 | //@
66 | //@ #### destination
67 | //@ Currently returns null
68 | get destination() {
69 | return null;
70 | },
71 |
72 | //@
73 | //@ #### createBufferSource()
74 | //@ Returns a new AudioBufferSourceNode object
75 | createBufferSource: function() {
76 | return new AudioBufferSourceNode;
77 | }
78 | }); // prototype
79 |
80 | ///////////////////////////////////////////////////////////////////////////
81 | // Constructor
82 | //
83 |
84 | return obj;
85 | }
86 |
--------------------------------------------------------------------------------
/lib/canvas.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2011, Mozilla Corporation
2 | // All rights reserved.
3 | //
4 | // Author(s): Artur Adib
5 | //
6 | // You may use this file under the terms of the New BSD license as follows:
7 | //
8 | // Redistribution and use in source and binary forms, with or without
9 | // modification, are permitted provided that the following conditions are met:
10 | // * Redistributions of source code must retain the above copyright
11 | // notice, this list of conditions and the following disclaimer.
12 | // * Redistributions in binary form must reproduce the above copyright
13 | // notice, this list of conditions and the following disclaimer in the
14 | // documentation and/or other materials provided with the distribution.
15 | // * Neither the name of Mozilla Corporation nor the
16 | // names of its contributors may be used to endorse or promote products
17 | // derived from this software without specific prior written permission.
18 | //
19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 | // ARE DISCLAIMED. IN NO EVENT SHALL MOZILLA CORPORATION BE LIABLE FOR ANY
23 | // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26 | // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 | // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 |
30 | //@
31 | //@ ## five.Canvas(window)
32 | //@
33 | //@ Class/constructor for Canvas objects, either off-screen (no `window` argument) or inside an existing `window`.
34 |
35 | var qt = require('node-qt'),
36 | CanvasRenderingContext2D = require('./canvascontext2d');
37 |
38 | // Holds references to objects that shouldn't get garbage collected during a Node-Five session
39 | // e.g. Windows, painting devices (Pixmaps), etc
40 | var refStore = [];
41 |
42 | //
43 | // Class Canvas()
44 | //
45 | module.exports = function(parent) {
46 |
47 | ///////////////////////////////////////////////////////////////////////////
48 | // Private
49 | //
50 |
51 | var pixmap_, painter_,
52 | parentWidget_ = parent ? parent.__widget : null,
53 | scrollArea_ = null,
54 | widget_ = null,
55 | geom_ = {
56 | width: 300, // Spec default
57 | height: 150, // Spec default
58 | viewWidth: undefined,
59 | viewHeight: undefined,
60 | top: 0,
61 | left: 0
62 | };
63 |
64 | function resetPixmap() {
65 | pixmap_ = new qt.QPixmap(geom_.width, geom_.height);
66 | // Spec default is transparent black
67 | pixmap_.fill(new qt.QColor(0, 0, 0, 0));
68 |
69 | if (painter_.isActive())
70 | painter_.end();
71 | painter_.begin(pixmap_);
72 | }
73 |
74 | function updateGeometry() {
75 | if (!scrollArea_ || !widget_)
76 | return;
77 |
78 | scrollArea_.move(geom_.left, geom_.top);
79 | scrollArea_.resize(geom_.viewWidth || geom_.width, geom_.viewHeight || geom_.height);
80 | widget_.resize(geom_.width, geom_.height);
81 |
82 | // Avoid having one scrollbar come up due to another scrollbar appearing
83 | // This will crop the content though, corresponding to the scrollbar's width/height
84 | if (geom_.viewWidth && geom_viewWidth < geom_.width)
85 | scrollArea_.setHorizontalScrollBarPolicy(0); // auto
86 | else
87 | scrollArea_.setHorizontalScrollBarPolicy(1); // off
88 |
89 | if (geom_.viewHeight && geom_.viewHeight < geom_.height)
90 | scrollArea_.setVerticalScrollBarPolicy(0); // auto
91 | else
92 | scrollArea_.setVerticalScrollBarPolicy(1); // off
93 | }
94 |
95 | ///////////////////////////////////////////////////////////////////////////
96 | // Public
97 | //
98 |
99 | var obj = Object.create({
100 | //@
101 | //@ #### width = 300
102 | set width(val) {
103 | geom_.width = val;
104 | resetPixmap(); // as per spec
105 | updateGeometry();
106 | },
107 |
108 | get width() {
109 | return geom_.width;
110 | },
111 |
112 | //@
113 | //@ #### height = 150
114 | set height(val) {
115 | geom_.height = val;
116 | resetPixmap(); // as per spec
117 | updateGeometry();
118 | },
119 |
120 | get height() {
121 | return geom_.height;
122 | },
123 |
124 | //@
125 | //@ #### viewWidth = width
126 | //@ (Non-standard) Width of the canvas view. Will crop canvas and create
127 | //@ scroll bars if smaller than the canvas `width`.
128 | set viewWidth(val) {
129 | geom_.viewWidth = val;
130 | updateGeometry();
131 | },
132 |
133 | get viewWidth() {
134 | return geom_.viewWidth;
135 | },
136 |
137 | //@
138 | //@ #### viewHeight = height
139 | //@ (Non-standard) Height of the canvas view. Will crop canvas and create scroll bars if smaller
140 | //@ than the canvas `height`.
141 | set viewHeight(val) {
142 | geom_.viewHeight = val;
143 | updateGeometry();
144 | },
145 |
146 | get viewHeight() {
147 | return geom_.viewHeight;
148 | },
149 |
150 | //@
151 | //@ #### scrollTop = 0
152 | //@ Vertical scroll position. To be used when `height > viewHeight`.
153 | //@ Maximum value is `height - viewHeight`.
154 | set scrollTop(val) {
155 | if (typeof val === 'number')
156 | scrollArea_.verticalScrollBar().setValue(val);
157 | },
158 |
159 | get scrollTop() {
160 | return scrollArea_.verticalScrollBar().value();
161 | },
162 |
163 | //@
164 | //@ #### scrollLeft = 0
165 | //@ Horizontal scroll position. To be used when `width > viewWidth`.
166 | //@ Maximum value is `width - viewWidth`.
167 | set scrollLeft(val) {
168 | if (typeof val === 'number')
169 | scrollArea_.horizontalScrollBar().setValue(val);
170 | },
171 |
172 | get scrollLeft() {
173 | return scrollArea_.horizontalScrollBar().value();
174 | },
175 |
176 | //@
177 | //@ #### top = 0
178 | //@ (Non-standard) Top position of the canvas with respect to parent window (if any), in pixels.
179 | //@ Only absolute positioning is available.
180 | set top(val) {
181 | geom_.top = val;
182 | updateGeometry();
183 | },
184 |
185 | get top() {
186 | return geom_.top;
187 | },
188 |
189 | //@
190 | //@ #### left = 0
191 | //@ (Non-standard) Left position of the canvas with respect to parent window (if any), in pixels.
192 | //@ Only absolute positioning is available.
193 | set left(val) {
194 | geom_.left = val;
195 | updateGeometry();
196 | },
197 |
198 | get left() {
199 | return geom_.left;
200 | },
201 |
202 | //@
203 | //@ #### getContext(type)
204 | //@ Presently only supports `type == '2d'`.
205 | getContext: function(type) {
206 | if (type === '2d')
207 | return new CanvasRenderingContext2D(painter_, parentWidget_);
208 | },
209 |
210 | //@
211 | //@ #### toDataURL()
212 | toDataURL: function() {
213 | // HACK
214 | // Ideally we'd save the pixmap to a QBuffer-QByteArray in memory, then run QByteArray.toBase64()
215 | // This would require bindings to QBuffer and QByteArray though, so some other time...
216 | var fs = require('fs');
217 | pixmap_.save('__tmp_canvas.png');
218 | var buf = fs.readFileSync('__tmp_canvas.png');
219 | fs.unlink('__tmp_canvas.png');
220 | return 'data:image/png;base64,' + buf.toString('base64');
221 | }
222 | }); // prototype
223 |
224 | ///////////////////////////////////////////////////////////////////////////
225 | // Constructor
226 | //
227 |
228 | painter_ = new qt.QPainter;
229 | resetPixmap();
230 |
231 | // Painting on a window?
232 | if (parentWidget_) {
233 | // Create widget wrapper (for scroll support) and the widget itself
234 | scrollArea_ = new qt.QScrollArea(parentWidget_);
235 | widget_ = new qt.QWidget(scrollArea_);
236 | scrollArea_.setWidget(widget_);
237 |
238 | scrollArea_.setFrameShape(0); // no borders
239 | scrollArea_.setFocusPolicy(0); // no focus (prevents Qt from intercepting Tab + arrow keys)
240 | widget_.setFocusPolicy(0); // no focus
241 |
242 | scrollArea_.resize(geom_.width, geom_.height);
243 | widget_.resize(geom_.width, geom_.height);
244 | scrollArea_.show();
245 | widget_.show();
246 |
247 | // Bind pixmap to widget
248 | widget_.paintEvent(function() {
249 | var painter_ = new qt.QPainter;
250 | painter_.begin(widget_);
251 | painter_.drawPixmap(0, 0, pixmap_);
252 | painter_.end();
253 | });
254 | }
255 |
256 | refStore.push(obj);
257 | return obj;
258 | }
259 |
--------------------------------------------------------------------------------
/lib/canvascontext2d.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2011, Mozilla Corporation
2 | // All rights reserved.
3 | //
4 | // Author(s): Artur Adib
5 | //
6 | // You may use this file under the terms of the New BSD license as follows:
7 | //
8 | // Redistribution and use in source and binary forms, with or without
9 | // modification, are permitted provided that the following conditions are met:
10 | // * Redistributions of source code must retain the above copyright
11 | // notice, this list of conditions and the following disclaimer.
12 | // * Redistributions in binary form must reproduce the above copyright
13 | // notice, this list of conditions and the following disclaimer in the
14 | // documentation and/or other materials provided with the distribution.
15 | // * Neither the name of Mozilla Corporation nor the
16 | // names of its contributors may be used to endorse or promote products
17 | // derived from this software without specific prior written permission.
18 | //
19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 | // ARE DISCLAIMED. IN NO EVENT SHALL MOZILLA CORPORATION BE LIABLE FOR ANY
23 | // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26 | // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 | // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 |
30 | //////////////////////////////////////////////////////////////////////////////
31 | //
32 | // The implementation below is based on QPainter, whose API is fortuitously
33 | // very similar to that of 2d canvas context
34 | //
35 |
36 | //@
37 | //@ ## five.Canvas.getContext('2d')
38 | //@
39 | //@ The documentation below is for exposed methods after a `ctx = canvas.getContext('2d')`
40 | //@ call, which returns a `CanvasRenderingContext2D` object.
41 |
42 | var qt = require('node-qt');
43 |
44 | // getStyle()
45 | // Helper function for fillStyle and strokeStyle getters
46 | // Returns appropriate value from given style state
47 | function getStyle(state) {
48 | if (!(state instanceof qt.QColor))
49 | return null; // not yet supported
50 |
51 | // It's a QColor
52 | var color = state;
53 |
54 | if (color.alpha() === 255)
55 | // '#aabbcc'
56 | return color.name();
57 | else
58 | // 'rgba(1, 2, 3, 0.5)'
59 | return 'rgba('+color.red()+', '+color.green()+', '+color.blue()+', '+(color.alpha()/255).toFixed(2)+')';
60 | }
61 |
62 | // setStyle()
63 | // Helper function for fillStyle and strokeStyle setters
64 | // Returns internal state from user-given value
65 | function setStyle(val) {
66 | if (!(typeof val === 'string'))
67 | return null; // not yet supported
68 |
69 | val = val.replace(/\s/g, '');
70 |
71 | // 'rgb(1, 2, 3)
72 | var rgbMatch = val.match(/rgb\((\d+)\,(\d+)\,(\d+).*\)/);
73 | if (rgbMatch)
74 | return new qt.QColor(rgbMatch[1], rgbMatch[2], rgbMatch[3]);
75 |
76 | // 'rgba(1, 2, 3, 0.5)'
77 | var rgbaMatch = val.match(/rgba\((\d+)\,(\d+)\,(\d+)\,([\d|\.]+).*\)/);
78 | if (rgbaMatch)
79 | return new qt.QColor(rgbaMatch[1], rgbaMatch[2], rgbaMatch[3], 255*rgbaMatch[4]);
80 |
81 | // '#abc', '#aabbcc', etc, 'blue', 'black', etc
82 | // These are handled by QColor itself
83 | return new qt.QColor(val);
84 | }
85 |
86 | //
87 | // Class CanvasRenderingContext2D()
88 | //
89 | module.exports = function(painter, widget) {
90 |
91 | ///////////////////////////////////////////////////////////////////////////
92 | // Private
93 | //
94 |
95 | var painter_ = painter,
96 | widget_ = widget,
97 | path_ = null,
98 | stack_ = [];
99 |
100 | var state_ = {
101 | fillStyle: new qt.QColor('black'),
102 | strokeStyle: new qt.QColor('black'),
103 | font: new qt.QFont('sans-serif', 10),
104 | matrix: new qt.QMatrix(1, 0, 0, 1, 0, 0)
105 | }
106 |
107 | function cloneState(state) {
108 | return {
109 | fillStyle: new qt.QColor(state.fillStyle),
110 | strokeStyle: new qt.QColor(state.strokeStyle),
111 | font: new qt.QFont(state.font),
112 | matrix: new qt.QMatrix(state.matrix)
113 | }
114 | }
115 |
116 | function updateWidget() {
117 | if (widget_)
118 | widget_.update();
119 | }
120 |
121 | ///////////////////////////////////////////////////////////////////////////
122 | // Public
123 | //
124 |
125 | var obj = Object.create({
126 | save: function() {
127 | // Can't push state_ directly as that would keep the state by reference
128 | // We need to push by value so that the saved state is not modified by ensuing state-changing operations
129 | stack_.push( cloneState(state_) );
130 | },
131 |
132 | restore: function() {
133 | if (stack_.length > 0)
134 | state_ = stack_.pop();
135 | },
136 |
137 | get fillStyle() {
138 | return getStyle(state_.fillStyle);
139 | },
140 |
141 | //@
142 | //@ #### ctx.fillStyle = 'color'
143 | //@ Currently only supports color types (e.g. `'rgb()'`, `'rgba()'`, `'blue'`, `'#aabbcc'`, etc)
144 | set fillStyle(val) {
145 | state_.fillStyle = setStyle(val) || state_.fillStyle;
146 | },
147 |
148 | get strokeStyle() {
149 | return getStyle(state_.strokeStyle);
150 | },
151 |
152 | //@
153 | //@ #### ctx.strokeStyle = 'color'
154 | //@ Currently only supports color types (e.g. `'rgb()'`, `'rgba()'`, `'blue'`, `'#aabbcc'`, etc)
155 | set strokeStyle(val) {
156 | state_.strokeStyle = setStyle(val) || state_.strokeStyle;
157 | },
158 |
159 | get font() {
160 | var font = state_.font;
161 | return font.pointSizeF() + 'px ' + font.family();
162 | },
163 |
164 | //@
165 | //@ #### ctx.font = '10px family'
166 | //@ Currently only supports the format above
167 | set font(val) {
168 | var match = val.match(/([\d|\.]+)px\s+([\w|\-]+)/);
169 | if (!match)
170 | return;
171 |
172 | var size = match[1],
173 | family = match[2];
174 |
175 | var font = new qt.QFont;
176 | font.setFamily(family);
177 | font.setPointSizeF(size);
178 | state_.font = font;
179 | },
180 |
181 | //@
182 | //@ #### ctx.fillRect(x, y, w, h)
183 | fillRect: function(x, y, w, h) {
184 | painter_.save();
185 | // setMatrix() is undocumented in Qt. The syntax is the same as setTransform()
186 | painter_.setMatrix(state_.matrix, false);
187 | painter_.fillRect(x, y, w, h, state_.fillStyle);
188 | painter_.restore();
189 |
190 | updateWidget();
191 | },
192 |
193 | //@
194 | //@ #### ctx.fillText(text, x, y)
195 | fillText: function(text, x, y) {
196 | // TODO: check if spec supports other fillStyles
197 | var fillStyle = state_.fillStyle instanceof qt.QColor ?
198 | state_.fillStyle : new qt.QColor(0, 0, 0);
199 |
200 | painter_.save();
201 | var pen = new qt.QPen(state_.fillStyle);
202 | painter_.setPen(pen);
203 | painter_.setFont(state_.font);
204 | // setMatrix() is undocumented in Qt. The syntax is the same as setTransform()
205 | painter_.setMatrix(state_.matrix, false);
206 | painter_.drawText(x, y, text);
207 | painter_.restore();
208 |
209 | updateWidget();
210 | },
211 |
212 | //@
213 | //@ #### ctx.translate(x, y)
214 | translate: function(x, y) {
215 | state_.matrix.translate(x, y);
216 | },
217 |
218 | //@
219 | //@ #### ctx.scale(x, y)
220 | scale: function(x, y) {
221 | state_.matrix.scale(x, y);
222 | },
223 |
224 | //@
225 | //@ #### ctx.beginPath()
226 | beginPath: function() {
227 | path_ = new qt.QPainterPath;
228 | },
229 |
230 | //@
231 | //@ #### ctx.closePath()
232 | closePath: function() {
233 | path_.closeSubpath();
234 | },
235 |
236 | //@
237 | //@ #### ctx.moveTo(x, y)
238 | moveTo: function(x, y) {
239 | if (!path_)
240 | return;
241 |
242 | path_.moveTo(new qt.QPointF(x, y));
243 | },
244 |
245 | //@
246 | //@ #### ctx.lineTo(x, y)
247 | lineTo: function(x, y) {
248 | if (!path_)
249 | return;
250 |
251 | path_.lineTo(new qt.QPointF(x, y));
252 | },
253 |
254 | //@
255 | //@ #### ctx.stroke()
256 | stroke: function() {
257 | if (!path_)
258 | return;
259 |
260 | if (!(state_.strokeStyle instanceof qt.QColor))
261 | return;
262 |
263 | var pen = new qt.QPen(state_.strokeStyle);
264 |
265 | painter_.save();
266 | painter_.setMatrix(state_.matrix, false);
267 | painter_.strokePath(path_, pen);
268 | painter_.restore();
269 |
270 | updateWidget();
271 | },
272 |
273 | //@
274 | //@ #### ctx.drawImage(image, x, y)
275 | //@ Presently only supports images created via `five.Image()`
276 | drawImage: function(image, x, y) {
277 | var img = image.__image;
278 | if (!(img instanceof qt.QImage))
279 | return; // not supported
280 |
281 | painter_.save();
282 | painter_.setMatrix(state_.matrix, false);
283 | painter_.drawImage(x, y, img);
284 | painter_.restore();
285 |
286 | updateWidget();
287 | }
288 | }); // prototype
289 |
290 | ///////////////////////////////////////////////////////////////////////////
291 | // Constructor
292 | //
293 |
294 | return obj;
295 | }
296 |
--------------------------------------------------------------------------------
/lib/common.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2011, Mozilla Corporation
2 | // All rights reserved.
3 | //
4 | // Author(s): Artur Adib
5 | //
6 | // You may use this file under the terms of the New BSD license as follows:
7 | //
8 | // Redistribution and use in source and binary forms, with or without
9 | // modification, are permitted provided that the following conditions are met:
10 | // * Redistributions of source code must retain the above copyright
11 | // notice, this list of conditions and the following disclaimer.
12 | // * Redistributions in binary form must reproduce the above copyright
13 | // notice, this list of conditions and the following disclaimer in the
14 | // documentation and/or other materials provided with the distribution.
15 | // * Neither the name of Mozilla Corporation nor the
16 | // names of its contributors may be used to endorse or promote products
17 | // derived from this software without specific prior written permission.
18 | //
19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 | // ARE DISCLAIMED. IN NO EVENT SHALL MOZILLA CORPORATION BE LIABLE FOR ANY
23 | // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26 | // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 | // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 |
30 | // extend(target_obj, source_obj1 [, source_obj2 ...])
31 | // shallow extend, e.g.:
32 | // common.extend({a:1}, {b:2}, {c:3})
33 | // returns {a:1, b:2, c:3}
34 | exports.extend = function(target) {
35 | var sources = [].slice.call(arguments, 1);
36 | sources.forEach(function(source) {
37 | for (key in source)
38 | target[key] = source[key];
39 | });
40 |
41 | return target;
42 | }
43 |
--------------------------------------------------------------------------------
/lib/core.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2011, Mozilla Corporation
2 | // All rights reserved.
3 | //
4 | // Author(s): Artur Adib
5 | //
6 | // You may use this file under the terms of the New BSD license as follows:
7 | //
8 | // Redistribution and use in source and binary forms, with or without
9 | // modification, are permitted provided that the following conditions are met:
10 | // * Redistributions of source code must retain the above copyright
11 | // notice, this list of conditions and the following disclaimer.
12 | // * Redistributions in binary form must reproduce the above copyright
13 | // notice, this list of conditions and the following disclaimer in the
14 | // documentation and/or other materials provided with the distribution.
15 | // * Neither the name of Mozilla Corporation nor the
16 | // names of its contributors may be used to endorse or promote products
17 | // derived from this software without specific prior written permission.
18 | //
19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 | // ARE DISCLAIMED. IN NO EVENT SHALL MOZILLA CORPORATION BE LIABLE FOR ANY
23 | // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26 | // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 | // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 |
30 | //@
31 | //@ ## five
32 | //@
33 | //@ Main object. Typical usage is:
34 | //@
35 | //@ ```
36 | //@ var five = require('path-to-node-five-dir');
37 | //@ ```
38 |
39 | var qt = require('node-qt');
40 |
41 | var app = new qt.QApplication();
42 | var timerHandler, tickStop = false;
43 |
44 | //@
45 | //@ #### useInterval()
46 | //@ Add event handler to Node's event loop via setTimeout(). This is the default event loop integration.
47 | exports.useInterval = function() {
48 | if (timerHandler)
49 | clearInterval(timerHandler);
50 | tickStop = true;
51 |
52 | timerHandler = setInterval(function(){
53 | app.processEvents();
54 | }, 0);
55 | }
56 |
57 | //@
58 | //@ #### useTick()
59 | //@ Add event handler to Node's event loop via `process.nextTick()`.
60 | //@ This should used in applications that require more instant responsiveness (CPU-intensive!).
61 | exports.useTick = function() {
62 | var registerNextTick = function() {
63 | process.nextTick(function(){
64 | app.processEvents();
65 | if (!tickStop) registerNextTick();
66 | });
67 | };
68 |
69 | if (timerHandler)
70 | clearInterval(timerHandler);
71 | tickStop = false;
72 |
73 | registerNextTick();
74 | }
75 |
76 | //@
77 | //@ #### stop()
78 | //@ Stop Node-Five's event loop. Applications never exit without a call to this method.
79 | exports.stop = function() {
80 | clearInterval(timerHandler);
81 | }
82 |
--------------------------------------------------------------------------------
/lib/five.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2011, Mozilla Corporation
2 | // All rights reserved.
3 | //
4 | // Author(s): Artur Adib
5 | //
6 | // You may use this file under the terms of the New BSD license as follows:
7 | //
8 | // Redistribution and use in source and binary forms, with or without
9 | // modification, are permitted provided that the following conditions are met:
10 | // * Redistributions of source code must retain the above copyright
11 | // notice, this list of conditions and the following disclaimer.
12 | // * Redistributions in binary form must reproduce the above copyright
13 | // notice, this list of conditions and the following disclaimer in the
14 | // documentation and/or other materials provided with the distribution.
15 | // * Neither the name of Mozilla Corporation nor the
16 | // names of its contributors may be used to endorse or promote products
17 | // derived from this software without specific prior written permission.
18 | //
19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 | // ARE DISCLAIMED. IN NO EVENT SHALL MOZILLA CORPORATION BE LIABLE FOR ANY
23 | // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26 | // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 | // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 |
30 | var qt = require('node-qt'),
31 | common = require('./common'),
32 | five = require('./core');
33 |
34 | // Expose key and button codes, e.g. five.Key_Left, five.LeftButton, etc
35 | common.extend(five, qt.Key);
36 | common.extend(five, qt.MouseButton);
37 |
38 | //
39 | // Expose classes
40 | //
41 | five.Window = require('./window');
42 | five.Canvas = require('./canvas');
43 | five.Image = require('./image');
44 | five.AudioContext = require('./audiocontext');
45 |
46 | // Integrate Qt events with Node's event loop
47 | five.useInterval();
48 |
49 | module.exports = five;
50 |
--------------------------------------------------------------------------------
/lib/image.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2011, Mozilla Corporation
2 | // All rights reserved.
3 | //
4 | // Author(s): Artur Adib
5 | //
6 | // You may use this file under the terms of the New BSD license as follows:
7 | //
8 | // Redistribution and use in source and binary forms, with or without
9 | // modification, are permitted provided that the following conditions are met:
10 | // * Redistributions of source code must retain the above copyright
11 | // notice, this list of conditions and the following disclaimer.
12 | // * Redistributions in binary form must reproduce the above copyright
13 | // notice, this list of conditions and the following disclaimer in the
14 | // documentation and/or other materials provided with the distribution.
15 | // * Neither the name of Mozilla Corporation nor the
16 | // names of its contributors may be used to endorse or promote products
17 | // derived from this software without specific prior written permission.
18 | //
19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 | // ARE DISCLAIMED. IN NO EVENT SHALL MOZILLA CORPORATION BE LIABLE FOR ANY
23 | // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26 | // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 | // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 |
30 | //@
31 | //@ ## five.Image()
32 | //@
33 | //@ Constructor for image objects. Intended to mirror `Image()` constructor from browsers.
34 |
35 | var qt = require('node-qt');
36 |
37 | //
38 | // Class Image()
39 | //
40 | module.exports = function() {
41 |
42 | ///////////////////////////////////////////////////////////////////////////
43 | // Private
44 | //
45 |
46 | var image_,
47 | onload_,
48 | complete_ = false;
49 |
50 | ///////////////////////////////////////////////////////////////////////////
51 | // Public
52 | //
53 |
54 | var obj = Object.create({
55 | //@
56 | //@ #### src = 'file_name'
57 | //@ Presently only supports local paths, e.g. `./images/file.png`
58 | set src(val) {
59 | image_ = new qt.QImage(val);
60 | if (!image_.isNull()) {
61 | complete_ = true;
62 | if (onload_)
63 | onload_();
64 | } else {
65 | complete_ = false;
66 | }
67 | },
68 |
69 | //@
70 | //@ #### complete
71 | get complete() {
72 | return complete_;
73 | },
74 |
75 | //@
76 | //@ #### onload = callback
77 | set onload(val) {
78 | onload_ = val;
79 | if (complete_)
80 | onload_();
81 | },
82 |
83 | // TODO: find a better pattern to avoid leaking internals like image_
84 | get __image() {
85 | return image_;
86 | }
87 | }); // prototype
88 |
89 | ///////////////////////////////////////////////////////////////////////////
90 | // Constructor
91 | //
92 |
93 | return obj;
94 | }
95 |
--------------------------------------------------------------------------------
/lib/window.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2011, Mozilla Corporation
2 | // All rights reserved.
3 | //
4 | // Author(s): Artur Adib
5 | //
6 | // You may use this file under the terms of the New BSD license as follows:
7 | //
8 | // Redistribution and use in source and binary forms, with or without
9 | // modification, are permitted provided that the following conditions are met:
10 | // * Redistributions of source code must retain the above copyright
11 | // notice, this list of conditions and the following disclaimer.
12 | // * Redistributions in binary form must reproduce the above copyright
13 | // notice, this list of conditions and the following disclaimer in the
14 | // documentation and/or other materials provided with the distribution.
15 | // * Neither the name of Mozilla Corporation nor the
16 | // names of its contributors may be used to endorse or promote products
17 | // derived from this software without specific prior written permission.
18 | //
19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 | // ARE DISCLAIMED. IN NO EVENT SHALL MOZILLA CORPORATION BE LIABLE FOR ANY
23 | // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26 | // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 | // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 |
30 | //@
31 | //@ ## five.Window(width, height)
32 | //@
33 | //@ Native window constructor with the given `height` and `width`.
34 |
35 | var qt = require('node-qt');
36 |
37 | // Holds global references to objects that shouldn't get garbage collected during a Node-Five session
38 | // e.g. Windows, painting devices (Pixmaps), etc
39 | var refStore = [];
40 |
41 | //
42 | // Class Window()
43 | //
44 | module.exports = function(width, height) {
45 |
46 | ///////////////////////////////////////////////////////////////////////////
47 | // Private
48 | //
49 |
50 | var widget_,
51 | width_ = width || 640,
52 | height_ = height || 480,
53 | eventHandlers_ = {
54 | mousedown: [],
55 | mouseup: [],
56 | mousemove: [],
57 | keyup: [],
58 | keydown: []
59 | };
60 |
61 | ///////////////////////////////////////////////////////////////////////////
62 | // Public
63 | //
64 |
65 | var obj = Object.create({
66 | //@
67 | //@ #### width = 640
68 | //@ Gets/sets window width in pixels
69 | set width(val) {
70 | width_ = val;
71 |
72 | if (!widget_)
73 | return;
74 | widget_.resize(width_, height_);
75 | },
76 |
77 | get width() {
78 | return width_;
79 | },
80 |
81 | //@
82 | //@ #### height = 480
83 | //@ Gets/sets window height in pixels
84 | set height(val) {
85 | height_ = val;
86 |
87 | if (!widget_)
88 | return;
89 | widget_.resize(width_, height_);
90 | },
91 |
92 | get height() {
93 | return height_;
94 | },
95 |
96 | //@
97 | //@ #### close()
98 | //@ Closes window. It can't be reopened.
99 | close: function() {
100 | widget_.close();
101 | },
102 |
103 | //@
104 | //@ #### addEventListener(event, callback)
105 | //@ Binds `event` to `callback`. Supported events are listed below.
106 | addEventListener: function(event, callback) {
107 | if (!event || !callback)
108 | return;
109 |
110 | eventHandlers_[event].push(callback);
111 |
112 | if (event === 'mousemove')
113 | widget_.setMouseTracking(true);
114 | },
115 |
116 | //@
117 | //@ #### removeEventListener(event, callback)
118 | //@ Removes callback from `event` handler.
119 | removeEventListener: function(event, callback) {
120 | if (!event || !callback)
121 | return;
122 |
123 | var arr = eventHandlers_[event],
124 | pos = arr.indexOf(callback);
125 |
126 | if (pos > -1)
127 | arr.splice(pos, 1);
128 |
129 | // No need for mouse tracking if no more handlers left
130 | if (event === 'mousemove' && arr.length === 0)
131 | widget_.setMouseTracking(false);
132 | },
133 |
134 | // TODO: find a better window-canvas instantiation pattern to avoid leaking internals like widget
135 | get __widget() {
136 | return widget_;
137 | }
138 | });
139 |
140 | ///////////////////////////////////////////////////////////////////////////
141 | // Constructor
142 | //
143 |
144 | // Prepare main widget
145 | widget_ = new qt.QWidget();
146 | widget_.resize(width_, height_);
147 | widget_.show();
148 |
149 | //@
150 | //@ #### Supported events for `addEventListener()`
151 | //@
152 | //@ + `mousedown`:
153 | //@ Callback will be passed `{ clientX, clientY, button }`. `button` values correspond
154 | //@ to the convenience constants `five.LeftButton`, `five.RightButton`, etc.
155 | //@ See http://developer.qt.nokia.com/doc/qt-4.8/qt.html#MouseButton-enum
156 | //@ for a list of supported button codes
157 | widget_.mousePressEvent(function(qtEvent) {
158 | eventHandlers_['mousedown'].forEach(function(handler) {
159 | handler({
160 | clientX: qtEvent.x(),
161 | clientY: qtEvent.y(),
162 | button: qtEvent.button()
163 | });
164 | });
165 | });
166 |
167 | //@
168 | //@ + `mouseup`:
169 | //@ Callback will be passed `{ clientX, clientY, button }` as in `mousedown`.
170 | widget_.mouseReleaseEvent(function(qtEvent) {
171 | eventHandlers_['mouseup'].forEach(function(handler) {
172 | handler({
173 | clientX: qtEvent.x(),
174 | clientY: qtEvent.y(),
175 | button: qtEvent.button()
176 | });
177 | });
178 | });
179 |
180 | //@
181 | //@ + `mousemove`:
182 | //@ Callback will be passed `{ clientX, clientY }`.
183 | widget_.mouseMoveEvent(function(qtEvent) {
184 | eventHandlers_['mousemove'].forEach(function(handler) {
185 | handler({
186 | clientX: qtEvent.x(),
187 | clientY: qtEvent.y()
188 | });
189 | });
190 | });
191 |
192 | //@
193 | //@ + `keydown`:
194 | //@ Callback will be passed `{ key, char }`.
195 | //@ Key values correspond to the convenience constants `five.Key_Esc`, `five.Key_Left`, etc.
196 | //@ See http://developer.qt.nokia.com/doc/qt-4.8/qt.html#Key-enum for the list of supported keys.
197 | //@ `char` is the corresponding Unicode character, if available.
198 | widget_.keyPressEvent(function(qtEvent) {
199 | eventHandlers_['keydown'].forEach(function(handler) {
200 | handler({
201 | key: qtEvent.key(),
202 | char: qtEvent.text()
203 | });
204 | });
205 | });
206 |
207 | //@
208 | //@ + `keyup`:
209 | //@ Callback will be passed `{ key, char }`. Details as in `keydown`.
210 | widget_.keyReleaseEvent(function(qtEvent) {
211 | eventHandlers_['keyup'].forEach(function(handler) {
212 | handler({
213 | key: qtEvent.key(),
214 | char: qtEvent.text()
215 | });
216 | });
217 | });
218 |
219 | refStore.push(obj);
220 | return obj;
221 | }
222 |
--------------------------------------------------------------------------------
/make.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 | require('shelljs/make');
3 |
4 | var root = __dirname;
5 |
6 | //
7 | // Docs
8 | //
9 | target.docs = function() {
10 | cd(root);
11 |
12 | echo('_________________________________________________________________');
13 | echo('Building docs');
14 |
15 | var apiDocs = grep('//@',
16 | 'lib/core.js',
17 | 'lib/window.js',
18 | 'lib/canvas.js',
19 | 'lib/canvascontext2d.js',
20 | 'lib/image.js',
21 | 'lib/audiocontext.js',
22 | 'lib/audiobuffersource.js'
23 | ).replace(/ *\/\/\@ */g, '');
24 |
25 | sed(/# API reference(.|\n)*/, '# API reference\n\n' + apiDocs, 'README.md').to('README.md');
26 | }
27 |
28 |
29 | //
30 | // Test
31 | //
32 | target.test = function() {
33 | cd(root);
34 |
35 | echo('_________________________________________________________________');
36 | echo('Running Node-Five tests');
37 | echo();
38 |
39 | cd('test');
40 | rm('-f', 'img-test/*');
41 | ls('*.js').forEach(function(f) {
42 | echo('Running test file '+f);
43 | exec('node '+f);
44 | });
45 | }
46 |
47 |
48 | //
49 | // Ref
50 | //
51 | target.ref = function() {
52 | cd(root);
53 |
54 | echo('_________________________________________________________________');
55 | echo('Node-Five tests: Overwriting reference images');
56 | rm('-f', 'img-ref/*');
57 | mv('img-test/*', 'img-ref');
58 | }
59 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | { "name": "node-five"
2 | , "version": "0.0.1"
3 | , "author": "Artur Adib"
4 | , "description": "HTML5 APIs for Node.js"
5 | , "homepage": "http://github.com/arturadib/node-five"
6 | , "main": "./lib/five.js"
7 | , "dependencies": {
8 | "shelljs": "0.0.5pre4",
9 | "node-qt": "0.0.2"
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arturadib/node-five/ea642fcef0d95d3df69fe0b974b80ccb95e25b47/screenshot.png
--------------------------------------------------------------------------------
/test/.gitignore:
--------------------------------------------------------------------------------
1 | img-test/
2 |
3 |
--------------------------------------------------------------------------------
/test/audio.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2011, Mozilla Corporation
2 | // All rights reserved.
3 | //
4 | // Author(s): Artur Adib
5 | //
6 | // You may use this file under the terms of the New BSD license as follows:
7 | //
8 | // Redistribution and use in source and binary forms, with or without
9 | // modification, are permitted provided that the following conditions are met:
10 | // * Redistributions of source code must retain the above copyright
11 | // notice, this list of conditions and the following disclaimer.
12 | // * Redistributions in binary form must reproduce the above copyright
13 | // notice, this list of conditions and the following disclaimer in the
14 | // documentation and/or other materials provided with the distribution.
15 | // * Neither the name of Mozilla Corporation nor the
16 | // names of its contributors may be used to endorse or promote products
17 | // derived from this software without specific prior written permission.
18 | //
19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 | // ARE DISCLAIMED. IN NO EVENT SHALL MOZILLA CORPORATION BE LIABLE FOR ANY
23 | // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26 | // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 | // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 |
30 | var assert = require('assert'),
31 | five = require('..');
32 |
33 | // Constructor
34 | {
35 | var context = new five.AudioContext();
36 | assert.ok(context);
37 |
38 | var source = context.createBufferSource();
39 | assert.ok(source);
40 |
41 | // crash test only
42 | source.connect(context.destination);
43 | }
44 |
45 | five.stop();
46 |
--------------------------------------------------------------------------------
/test/canvas.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2011, Mozilla Corporation
2 | // All rights reserved.
3 | //
4 | // Author(s): Artur Adib
5 | //
6 | // You may use this file under the terms of the New BSD license as follows:
7 | //
8 | // Redistribution and use in source and binary forms, with or without
9 | // modification, are permitted provided that the following conditions are met:
10 | // * Redistributions of source code must retain the above copyright
11 | // notice, this list of conditions and the following disclaimer.
12 | // * Redistributions in binary form must reproduce the above copyright
13 | // notice, this list of conditions and the following disclaimer in the
14 | // documentation and/or other materials provided with the distribution.
15 | // * Neither the name of Mozilla Corporation nor the
16 | // names of its contributors may be used to endorse or promote products
17 | // derived from this software without specific prior written permission.
18 | //
19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 | // ARE DISCLAIMED. IN NO EVENT SHALL MOZILLA CORPORATION BE LIABLE FOR ANY
23 | // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26 | // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 | // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 |
30 | var assert = require('assert'),
31 | five = require('..'),
32 | test = require('./test');
33 |
34 | // Constructor: window
35 | {
36 | var window = new five.Window(111, 222),
37 | canvas = new five.Canvas(window);
38 |
39 | assert.equal(canvas.width, 300); // spec default
40 | assert.equal(canvas.height, 150); // spec default
41 | assert.equal(canvas.top, 0);
42 | assert.equal(canvas.left, 0);
43 | assert.equal(typeof canvas.viewWidth, 'undefined');
44 | assert.equal(typeof canvas.viewHeight, 'undefined');
45 | }
46 |
47 | // Constructor- headless
48 | {
49 | var canvas = new five.Canvas;
50 |
51 | assert.equal(canvas.width, 300); // spec default
52 | assert.equal(canvas.height, 150); // spec default
53 | }
54 |
55 | // getContext()
56 | {
57 | var canvas = new five.Canvas;
58 | assert.ok(canvas.getContext('2d'));
59 | }
60 |
61 | // Regression tests
62 | {
63 | var canvas = new five.Canvas;
64 |
65 | test.regression('canvas-blank', canvas, function() {});
66 | }
67 |
68 | five.stop();
69 |
--------------------------------------------------------------------------------
/test/canvascontext2d.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2011, Mozilla Corporation
2 | // All rights reserved.
3 | //
4 | // Author(s): Artur Adib
5 | //
6 | // You may use this file under the terms of the New BSD license as follows:
7 | //
8 | // Redistribution and use in source and binary forms, with or without
9 | // modification, are permitted provided that the following conditions are met:
10 | // * Redistributions of source code must retain the above copyright
11 | // notice, this list of conditions and the following disclaimer.
12 | // * Redistributions in binary form must reproduce the above copyright
13 | // notice, this list of conditions and the following disclaimer in the
14 | // documentation and/or other materials provided with the distribution.
15 | // * Neither the name of Mozilla Corporation nor the
16 | // names of its contributors may be used to endorse or promote products
17 | // derived from this software without specific prior written permission.
18 | //
19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 | // ARE DISCLAIMED. IN NO EVENT SHALL MOZILLA CORPORATION BE LIABLE FOR ANY
23 | // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26 | // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 | // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 |
30 | var assert = require('assert'),
31 | five = require('..'),
32 | test = require('./test');
33 |
34 | function checkDefaults(ctx) {
35 | assert.equal(ctx.fillStyle, '#000000');
36 | assert.equal(ctx.strokeStyle, '#000000');
37 | assert.equal(ctx.font, '10px sans-serif');
38 | }
39 |
40 | // Getters, setters
41 | {
42 | var canvas = new five.Canvas,
43 | ctx = canvas.getContext('2d');
44 |
45 | checkDefaults(ctx);
46 |
47 | ctx.save();
48 |
49 | //
50 | // fillStyle, strokeStyle
51 | //
52 |
53 | ctx.fillStyle = ' #030201 ';
54 | assert.equal(ctx.fillStyle, '#030201');
55 | ctx.strokeStyle = ' #030201 ';
56 | assert.equal(ctx.strokeStyle, '#030201');
57 |
58 | ctx.fillStyle = ' blue ';
59 | assert.equal(ctx.fillStyle, '#0000ff');
60 | ctx.strokeStyle = ' blue ';
61 | assert.equal(ctx.strokeStyle, '#0000ff');
62 |
63 | ctx.fillStyle = ' rgb ( 1,2, 3) ';
64 | assert.equal(ctx.fillStyle, '#010203');
65 | ctx.strokeStyle = ' rgb ( 1,2, 3) ';
66 | assert.equal(ctx.strokeStyle, '#010203');
67 |
68 | ctx.fillStyle = ' rgba ( 3,1, 2, 1.0) ';
69 | assert.equal(ctx.fillStyle, '#030102');
70 | ctx.strokeStyle = ' rgba ( 3,1, 2, 1.0) ';
71 | assert.equal(ctx.strokeStyle, '#030102');
72 |
73 | ctx.fillStyle = ' rgba ( 2,3, 1, 0.2311111) ';
74 | // FF seems to use 2 decimal points precision
75 | assert.equal(ctx.fillStyle, 'rgba(2, 3, 1, 0.23)');
76 | ctx.strokeStyle = ' rgba ( 2,3, 1, 0.2311111) ';
77 | // FF seems to use 2 decimal points precision
78 | assert.equal(ctx.strokeStyle, 'rgba(2, 3, 1, 0.23)');
79 |
80 | //
81 | // Font
82 | //
83 |
84 | ctx.font = '15px helvetica';
85 | assert.equal(ctx.font, '15px helvetica');
86 |
87 | ctx.font = ' 15px helvetica ';
88 | assert.equal(ctx.font, '15px helvetica');
89 |
90 | ctx.font = ' 1px sans-serif ';
91 | assert.equal(ctx.font, '1px sans-serif');
92 |
93 | ctx.font = '5px arial';
94 | ctx.font = ' 1pxx sans-serif-- '; // induce parse error
95 | assert.equal(ctx.font, '5px arial');
96 |
97 | // Defaults
98 | ctx.restore();
99 |
100 | checkDefaults(ctx);
101 | }
102 |
103 | // Regression tests
104 | {
105 | var canvas = new five.Canvas,
106 | ctx = canvas.getContext('2d');
107 |
108 | test.regression('context2d-fillRect-black-sq', canvas, function() {
109 | ctx.fillRect(0, 0, 10, 10);
110 | });
111 | }
112 |
113 | {
114 | var canvas = new five.Canvas,
115 | ctx = canvas.getContext('2d');
116 |
117 | test.regression('context2d-fillRect-black-sq2', canvas, function() {
118 | ctx.fillStyle = 'red';
119 | ctx.fillRect(10, 10, 20, 20);
120 |
121 | canvas.width = canvas.width; // reset canvas pixmap, as per spec
122 |
123 | ctx.fillStyle = 'black';
124 | ctx.fillRect(0, 0, 10, 10); // should be only square
125 | });
126 | }
127 |
128 | {
129 | var canvas = new five.Canvas,
130 | ctx = canvas.getContext('2d');
131 |
132 | test.regression('context2d-fillRect-red-sq', canvas, function() {
133 | ctx.fillStyle = 'red';
134 | ctx.fillRect(0, 0, 10, 10);
135 | });
136 | }
137 |
138 | {
139 | var canvas = new five.Canvas,
140 | ctx = canvas.getContext('2d');
141 |
142 | test.regression('context2d-fillRect-blue-sq', canvas, function() {
143 | ctx.fillStyle = '#0000ff';
144 | ctx.fillRect(0, 0, 10, 10);
145 | });
146 | }
147 |
148 | {
149 | var canvas = new five.Canvas,
150 | ctx = canvas.getContext('2d');
151 |
152 | test.regression('context2d-fillText-hello-black', canvas, function() {
153 | ctx.fillText('hello', 20, 20);
154 | });
155 | }
156 |
157 | {
158 | var canvas = new five.Canvas,
159 | ctx = canvas.getContext('2d');
160 |
161 | test.regression('context2d-fillText-hello-green', canvas, function() {
162 | ctx.fillStyle = 'green';
163 | ctx.fillText('hello', 20, 20);
164 | });
165 | }
166 |
167 | {
168 | var canvas = new five.Canvas,
169 | ctx = canvas.getContext('2d');
170 |
171 | test.regression('context2d-fillText-hello-big-arial', canvas, function() {
172 | ctx.font = '40px arial';
173 | ctx.fillText('hello', 20, 50);
174 | });
175 | }
176 |
177 | {
178 | var canvas = new five.Canvas,
179 | ctx = canvas.getContext('2d');
180 |
181 | test.regression('context2d-fillText-hello-big-courier', canvas, function() {
182 | ctx.font = '40px courier';
183 | ctx.fillText('hello', 20, 50);
184 | });
185 | }
186 |
187 | {
188 | var canvas = new five.Canvas,
189 | ctx = canvas.getContext('2d');
190 |
191 | test.regression('context2d-fillRect-many-rgb-colored', canvas, function() {
192 | var i, j;
193 | for (i=0;i<6;i++) {
194 | for (j=0;j<6;j++) {
195 | ctx.fillStyle = 'rgb(' + Math.floor(255-42.5*i) + ',' +
196 | Math.floor(255-42.5*j) + ',0)';
197 | ctx.fillRect(j*25,i*25,25,25);
198 | }
199 | }
200 | });
201 | }
202 |
203 | {
204 | var canvas = new five.Canvas,
205 | ctx = canvas.getContext('2d');
206 |
207 | test.regression('context2d-fillRect-translate-redonblue', canvas, function() {
208 | ctx.save();
209 | ctx.fillStyle = 'blue';
210 | ctx.fillRect(0, 0, 20, 20);
211 | ctx.restore();
212 |
213 | ctx.save();
214 | ctx.fillStyle = 'red';
215 | ctx.translate(10, 10);
216 | ctx.fillRect(0, 0, 20, 20);
217 | ctx.restore();
218 | });
219 | }
220 |
221 | {
222 | var canvas = new five.Canvas,
223 | ctx = canvas.getContext('2d');
224 |
225 | test.regression('context2d-fillRect-scale-redonblue', canvas, function() {
226 | ctx.save();
227 | ctx.fillStyle = 'blue';
228 | ctx.fillRect(0, 0, 20, 20);
229 | ctx.restore();
230 |
231 | ctx.save();
232 | ctx.fillStyle = 'red';
233 | ctx.translate(10, 10);
234 | ctx.scale(2, 2);
235 | ctx.fillRect(0, 0, 20, 20);
236 | ctx.restore();
237 | });
238 | }
239 |
240 | {
241 | var canvas = new five.Canvas,
242 | ctx = canvas.getContext('2d');
243 |
244 | test.regression('context2d-fillText-translate-redonblue', canvas, function() {
245 | ctx.save();
246 | ctx.fillStyle = 'blue';
247 | ctx.fillText('hello world', 0, 20);
248 | ctx.restore();
249 |
250 | ctx.save();
251 | ctx.fillStyle = 'red';
252 | ctx.translate(10, 10);
253 | ctx.fillText('hello world', 0, 20);
254 | ctx.restore();
255 | });
256 | }
257 |
258 | {
259 | var canvas = new five.Canvas,
260 | ctx = canvas.getContext('2d');
261 |
262 | test.regression('context2d-fillText-scale-redonblue', canvas, function() {
263 | ctx.save();
264 | ctx.fillStyle = 'blue';
265 | ctx.fillText('hello world', 0, 20);
266 | ctx.restore();
267 |
268 | ctx.save();
269 | ctx.fillStyle = 'red';
270 | ctx.scale(2, 2);
271 | ctx.fillText('hello world', 0, 20);
272 | ctx.restore();
273 | });
274 | }
275 |
276 | {
277 | var canvas = new five.Canvas,
278 | ctx = canvas.getContext('2d');
279 |
280 | test.regression('context2d-strokePath-lineTo', canvas, function() {
281 | ctx.beginPath();
282 | ctx.strokeStyle = 'red';
283 | ctx.moveTo(10, 10);
284 | ctx.lineTo(30, 30);
285 | ctx.stroke();
286 | });
287 | }
288 |
289 | {
290 | var canvas = new five.Canvas,
291 | ctx = canvas.getContext('2d');
292 |
293 | test.regression('context2d-strokePath-lineTo-translate-blueonright', canvas, function() {
294 | ctx.beginPath();
295 | ctx.strokeStyle = 'red';
296 | ctx.moveTo(10, 10);
297 | ctx.lineTo(30, 30);
298 | ctx.stroke();
299 | ctx.closePath();
300 |
301 | ctx.beginPath();
302 | ctx.strokeStyle = 'blue';
303 | ctx.translate(10, 0);
304 | ctx.moveTo(10, 10);
305 | ctx.lineTo(30, 30);
306 | ctx.stroke();
307 | });
308 | }
309 |
310 | {
311 | var canvas = new five.Canvas,
312 | ctx = canvas.getContext('2d');
313 |
314 | test.regression('context2d-drawImage', canvas, function() {
315 | var image = new five.Image();
316 | image.src = 'resources/image.png';
317 | assert.equal(image.complete, true);
318 | ctx.drawImage(image, 0, 0);
319 | });
320 | }
321 |
322 | {
323 | var canvas = new five.Canvas,
324 | ctx = canvas.getContext('2d');
325 |
326 | test.regression('context2d-drawImage-translate-imageontop', canvas, function() {
327 | ctx.fillStyle = 'blue';
328 | ctx.fillRect(0, 0, 20, 20);
329 |
330 | var image = new five.Image();
331 | image.src = 'resources/image.png';
332 | assert.equal(image.complete, true);
333 |
334 | ctx.translate(10, 10);
335 | ctx.drawImage(image, 0, 0);
336 | });
337 | }
338 |
339 | {
340 | var canvas = new five.Canvas,
341 | ctx = canvas.getContext('2d');
342 |
343 | test.regression('context2d-drawImage-scale-mirror', canvas, function() {
344 | var image = new five.Image();
345 | image.src = 'resources/image.png';
346 | assert.equal(image.complete, true);
347 |
348 | ctx.drawImage(image, 0, 0);
349 |
350 | ctx.translate(200, 0);
351 | ctx.scale(-1, 1);
352 | ctx.drawImage(image, 0, 0);
353 | });
354 | }
355 |
356 | {
357 | var canvas = new five.Canvas,
358 | ctx = canvas.getContext('2d');
359 |
360 | test.regression('context2d-drawImage-save-restore-matrix', canvas, function() {
361 | var image = new five.Image();
362 | image.src = 'resources/image.png';
363 | assert.equal(image.complete, true);
364 |
365 | ctx.save();
366 | ctx.translate(200, 0);
367 | ctx.scale(-1, 1);
368 | ctx.restore();
369 |
370 | // should draw original picture at 0, 0
371 | ctx.drawImage(image, 0, 0);
372 | });
373 | }
374 |
375 | five.stop();
376 |
--------------------------------------------------------------------------------
/test/image.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2011, Mozilla Corporation
2 | // All rights reserved.
3 | //
4 | // Author(s): Artur Adib
5 | //
6 | // You may use this file under the terms of the New BSD license as follows:
7 | //
8 | // Redistribution and use in source and binary forms, with or without
9 | // modification, are permitted provided that the following conditions are met:
10 | // * Redistributions of source code must retain the above copyright
11 | // notice, this list of conditions and the following disclaimer.
12 | // * Redistributions in binary form must reproduce the above copyright
13 | // notice, this list of conditions and the following disclaimer in the
14 | // documentation and/or other materials provided with the distribution.
15 | // * Neither the name of Mozilla Corporation nor the
16 | // names of its contributors may be used to endorse or promote products
17 | // derived from this software without specific prior written permission.
18 | //
19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 | // ARE DISCLAIMED. IN NO EVENT SHALL MOZILLA CORPORATION BE LIABLE FOR ANY
23 | // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26 | // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 | // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 |
30 | var assert = require('assert'),
31 | five = require('..'),
32 | test = require('./test');
33 |
34 | // Constructor
35 | {
36 | var image = new five.Image();
37 | image.src = 'resources/image.png';
38 | assert.equal(image.complete, true);
39 | }
40 |
41 | // Constructor- bad file
42 | {
43 | var image = new five.Image();
44 | image.src = 'BAD-FILE';
45 | assert.equal(image.complete, false);
46 | }
47 |
48 | // .onload() : before .src
49 | {
50 | var called = false;
51 | var image = new five.Image();
52 | image.onload = function() { called = true; }
53 | image.src = 'resources/image.png';
54 | assert.equal(called, true);
55 | }
56 |
57 | // .onload() : after .src
58 | {
59 | var called = false;
60 | var image = new five.Image();
61 | image.src = 'resources/image.png';
62 | image.onload = function() { called = true; }
63 | assert.equal(called, true);
64 | }
65 |
66 | // .onload() : bad image before .src
67 | {
68 | var called = false;
69 | var image = new five.Image();
70 | image.onload = function() { called = true; }
71 | image.src = 'BAD-IMAGE';
72 | assert.equal(called, false);
73 | }
74 |
75 | // .onload() : bad image after .src
76 | {
77 | var called = false;
78 | var image = new five.Image();
79 | image.src = 'BAD-IMAGE';
80 | image.onload = function() { called = true; }
81 | assert.equal(called, false);
82 | }
83 |
84 | five.stop();
85 |
--------------------------------------------------------------------------------
/test/img-ref/canvas-blank.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arturadib/node-five/ea642fcef0d95d3df69fe0b974b80ccb95e25b47/test/img-ref/canvas-blank.png
--------------------------------------------------------------------------------
/test/img-ref/context2d-drawImage-save-restore-matrix.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arturadib/node-five/ea642fcef0d95d3df69fe0b974b80ccb95e25b47/test/img-ref/context2d-drawImage-save-restore-matrix.png
--------------------------------------------------------------------------------
/test/img-ref/context2d-drawImage-scale-mirror.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arturadib/node-five/ea642fcef0d95d3df69fe0b974b80ccb95e25b47/test/img-ref/context2d-drawImage-scale-mirror.png
--------------------------------------------------------------------------------
/test/img-ref/context2d-drawImage-translate-imageontop.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arturadib/node-five/ea642fcef0d95d3df69fe0b974b80ccb95e25b47/test/img-ref/context2d-drawImage-translate-imageontop.png
--------------------------------------------------------------------------------
/test/img-ref/context2d-drawImage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arturadib/node-five/ea642fcef0d95d3df69fe0b974b80ccb95e25b47/test/img-ref/context2d-drawImage.png
--------------------------------------------------------------------------------
/test/img-ref/context2d-fillRect-black-sq.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arturadib/node-five/ea642fcef0d95d3df69fe0b974b80ccb95e25b47/test/img-ref/context2d-fillRect-black-sq.png
--------------------------------------------------------------------------------
/test/img-ref/context2d-fillRect-black-sq2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arturadib/node-five/ea642fcef0d95d3df69fe0b974b80ccb95e25b47/test/img-ref/context2d-fillRect-black-sq2.png
--------------------------------------------------------------------------------
/test/img-ref/context2d-fillRect-blue-sq.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arturadib/node-five/ea642fcef0d95d3df69fe0b974b80ccb95e25b47/test/img-ref/context2d-fillRect-blue-sq.png
--------------------------------------------------------------------------------
/test/img-ref/context2d-fillRect-many-rgb-colored.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arturadib/node-five/ea642fcef0d95d3df69fe0b974b80ccb95e25b47/test/img-ref/context2d-fillRect-many-rgb-colored.png
--------------------------------------------------------------------------------
/test/img-ref/context2d-fillRect-red-sq.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arturadib/node-five/ea642fcef0d95d3df69fe0b974b80ccb95e25b47/test/img-ref/context2d-fillRect-red-sq.png
--------------------------------------------------------------------------------
/test/img-ref/context2d-fillRect-scale-redonblue.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arturadib/node-five/ea642fcef0d95d3df69fe0b974b80ccb95e25b47/test/img-ref/context2d-fillRect-scale-redonblue.png
--------------------------------------------------------------------------------
/test/img-ref/context2d-fillRect-translate-redonblue.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arturadib/node-five/ea642fcef0d95d3df69fe0b974b80ccb95e25b47/test/img-ref/context2d-fillRect-translate-redonblue.png
--------------------------------------------------------------------------------
/test/img-ref/context2d-fillText-hello-big-arial.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arturadib/node-five/ea642fcef0d95d3df69fe0b974b80ccb95e25b47/test/img-ref/context2d-fillText-hello-big-arial.png
--------------------------------------------------------------------------------
/test/img-ref/context2d-fillText-hello-big-courier.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arturadib/node-five/ea642fcef0d95d3df69fe0b974b80ccb95e25b47/test/img-ref/context2d-fillText-hello-big-courier.png
--------------------------------------------------------------------------------
/test/img-ref/context2d-fillText-hello-black.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arturadib/node-five/ea642fcef0d95d3df69fe0b974b80ccb95e25b47/test/img-ref/context2d-fillText-hello-black.png
--------------------------------------------------------------------------------
/test/img-ref/context2d-fillText-hello-green.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arturadib/node-five/ea642fcef0d95d3df69fe0b974b80ccb95e25b47/test/img-ref/context2d-fillText-hello-green.png
--------------------------------------------------------------------------------
/test/img-ref/context2d-fillText-scale-redonblue.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arturadib/node-five/ea642fcef0d95d3df69fe0b974b80ccb95e25b47/test/img-ref/context2d-fillText-scale-redonblue.png
--------------------------------------------------------------------------------
/test/img-ref/context2d-fillText-translate-redonblue.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arturadib/node-five/ea642fcef0d95d3df69fe0b974b80ccb95e25b47/test/img-ref/context2d-fillText-translate-redonblue.png
--------------------------------------------------------------------------------
/test/img-ref/context2d-strokePath-lineTo-translate-blueonright.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arturadib/node-five/ea642fcef0d95d3df69fe0b974b80ccb95e25b47/test/img-ref/context2d-strokePath-lineTo-translate-blueonright.png
--------------------------------------------------------------------------------
/test/img-ref/context2d-strokePath-lineTo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arturadib/node-five/ea642fcef0d95d3df69fe0b974b80ccb95e25b47/test/img-ref/context2d-strokePath-lineTo.png
--------------------------------------------------------------------------------
/test/resources/image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arturadib/node-five/ea642fcef0d95d3df69fe0b974b80ccb95e25b47/test/resources/image.png
--------------------------------------------------------------------------------
/test/test.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2011, Mozilla Corporation
2 | // All rights reserved.
3 | //
4 | // Author(s): Artur Adib
5 | //
6 | // You may use this file under the terms of the New BSD license as follows:
7 | //
8 | // Redistribution and use in source and binary forms, with or without
9 | // modification, are permitted provided that the following conditions are met:
10 | // * Redistributions of source code must retain the above copyright
11 | // notice, this list of conditions and the following disclaimer.
12 | // * Redistributions in binary form must reproduce the above copyright
13 | // notice, this list of conditions and the following disclaimer in the
14 | // documentation and/or other materials provided with the distribution.
15 | // * Neither the name of Mozilla Corporation nor the
16 | // names of its contributors may be used to endorse or promote products
17 | // derived from this software without specific prior written permission.
18 | //
19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 | // ARE DISCLAIMED. IN NO EVENT SHALL MOZILLA CORPORATION BE LIABLE FOR ANY
23 | // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26 | // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 | // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 |
30 | var fs = require('fs'),
31 | path = require('path');
32 |
33 | var testDir = __dirname+'/img-test/',
34 | refDir = __dirname+'/img-ref/';
35 |
36 | if (!path.existsSync(testDir)) {
37 | console.log('! regression warning: img-test/ dir does not exist. creating it...')
38 | fs.mkdirSync(testDir);
39 | }
40 |
41 | function saveImageFromUrl(url, file) {
42 | var buf = new Buffer(url.substr(url.search(',') + 1), 'base64');
43 | fs.writeFileSync(file, buf);
44 | }
45 |
46 | function readUrlFromImage(file) {
47 | var buf = fs.readFileSync(file);
48 | return 'data:image/png;base64,' + buf.toString('base64');
49 | }
50 |
51 | exports.regression = function(name, canvas, callback) {
52 | callback();
53 |
54 | saveImageFromUrl(canvas.toDataURL(), testDir+name+'.png');
55 |
56 | // Can't compare if refs don't exist
57 | if (!path.existsSync(refDir+name+'.png')) {
58 | console.log('! regression warning: could not find reference file for test:', name)
59 | return;
60 | }
61 |
62 | var testUrl = readUrlFromImage(testDir+name+'.png');
63 | var refUrl = readUrlFromImage(refDir+name+'.png');
64 | if (testUrl !== refUrl) {
65 | console.log('!!! regression error in test:', name);
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/test/window.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2011, Mozilla Corporation
2 | // All rights reserved.
3 | //
4 | // Author(s): Artur Adib
5 | //
6 | // You may use this file under the terms of the New BSD license as follows:
7 | //
8 | // Redistribution and use in source and binary forms, with or without
9 | // modification, are permitted provided that the following conditions are met:
10 | // * Redistributions of source code must retain the above copyright
11 | // notice, this list of conditions and the following disclaimer.
12 | // * Redistributions in binary form must reproduce the above copyright
13 | // notice, this list of conditions and the following disclaimer in the
14 | // documentation and/or other materials provided with the distribution.
15 | // * Neither the name of Mozilla Corporation nor the
16 | // names of its contributors may be used to endorse or promote products
17 | // derived from this software without specific prior written permission.
18 | //
19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 | // ARE DISCLAIMED. IN NO EVENT SHALL MOZILLA CORPORATION BE LIABLE FOR ANY
23 | // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26 | // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 | // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 |
30 | var assert = require('assert'),
31 | five = require('..');
32 |
33 | // Constructor
34 | {
35 | // Defaults
36 | var window = new five.Window;
37 | assert.equal(window.width, 640);
38 | assert.equal(window.height, 480);
39 |
40 | var window2 = new five.Window(100, 200);
41 | assert.equal(window2.width, 100);
42 | assert.equal(window2.height, 200);
43 |
44 | // Sanity check (prototype/private var leaks, etc)
45 | assert.equal(window.width, 640);
46 | assert.equal(window.height, 480);
47 | }
48 |
49 | five.stop();
50 |
--------------------------------------------------------------------------------