graphico 0.0.3 → 0.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/canvas.js +111 -59
- package/package.json +1 -1
- package/types/canvas.d.ts +25 -10
package/dist/canvas.js
CHANGED
|
@@ -12,6 +12,10 @@ var Canvas = /** @class */ (function () {
|
|
|
12
12
|
function Canvas(options) {
|
|
13
13
|
if (options === void 0) { options = {}; }
|
|
14
14
|
var _this = this;
|
|
15
|
+
/**
|
|
16
|
+
* Can be used to render 2D graphics onto the canvas
|
|
17
|
+
*/
|
|
18
|
+
this.graphics = [];
|
|
15
19
|
/**
|
|
16
20
|
* Contains a list of current keys pressed
|
|
17
21
|
*/
|
|
@@ -36,34 +40,48 @@ var Canvas = /** @class */ (function () {
|
|
|
36
40
|
* The last frame's high resolution timestamp
|
|
37
41
|
*/
|
|
38
42
|
this.lastFrame = 0;
|
|
43
|
+
/**
|
|
44
|
+
* Determine whether the client is focused or not
|
|
45
|
+
*/
|
|
46
|
+
this.focused = false;
|
|
39
47
|
this.config = Canvas.setDefaults(options, Canvas.defaults);
|
|
40
48
|
this.width = this.config.width;
|
|
41
49
|
this.height = this.config.height;
|
|
42
|
-
|
|
43
|
-
var
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
50
|
+
// Create the container <div> element and set properties
|
|
51
|
+
var container = document.createElement('div');
|
|
52
|
+
container.tabIndex = 1; // For element focus
|
|
53
|
+
container.style.outline = 'none';
|
|
54
|
+
container.style.width = "".concat(this.config.width * this.config.scale, "px");
|
|
55
|
+
container.style.height = "".concat(this.config.height * this.config.scale, "px");
|
|
56
|
+
container.style.border = "".concat(this.config.scale, "px solid ").concat(this.config.border);
|
|
57
|
+
container.style.background = this.config.background;
|
|
58
|
+
container.style.cursor = this.config.showMouse ? 'default' : 'none';
|
|
59
|
+
container.style.position = 'relative';
|
|
60
|
+
this.config.parent.appendChild(container);
|
|
61
|
+
// Create canvas layers
|
|
62
|
+
for (var i = 0; i < this.config.numLayers; i++) {
|
|
63
|
+
var canvas = document.createElement('canvas');
|
|
64
|
+
var graphics = canvas.getContext('2d', { 'willReadFrequently': this.config.acceleration === 'software' });
|
|
65
|
+
if (graphics) {
|
|
66
|
+
this.graphics.push(graphics);
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
throw new Error('Could not initialize canvas graphics.');
|
|
70
|
+
}
|
|
71
|
+
// Set properties for canvas
|
|
72
|
+
canvas.style.imageRendering = 'pixelated';
|
|
73
|
+
canvas.style.boxSizing = 'border-box';
|
|
74
|
+
canvas.width = this.config.width;
|
|
75
|
+
canvas.height = this.config.height;
|
|
76
|
+
canvas.style.width = '100%';
|
|
77
|
+
canvas.style.height = '100%';
|
|
78
|
+
canvas.style.position = 'absolute';
|
|
79
|
+
graphics.imageSmoothingEnabled = false;
|
|
80
|
+
container.appendChild(canvas);
|
|
49
81
|
}
|
|
50
|
-
// Set static properties
|
|
51
|
-
this.config.parent.appendChild(canvas);
|
|
52
|
-
canvas.tabIndex = 1; // For element focus
|
|
53
|
-
canvas.style.outline = 'none';
|
|
54
|
-
canvas.style.imageRendering = 'pixelated';
|
|
55
|
-
graphics.imageSmoothingEnabled = false;
|
|
56
|
-
// Set custom properties
|
|
57
|
-
canvas.width = this.config.width;
|
|
58
|
-
canvas.height = this.config.height;
|
|
59
|
-
canvas.style.width = "".concat(this.config.width * this.config.scale, "px");
|
|
60
|
-
canvas.style.height = "".concat(this.config.height * this.config.scale, "px");
|
|
61
|
-
canvas.style.background = this.config.background.toString();
|
|
62
|
-
canvas.style.border = "".concat(this.config.scale, "px solid ").concat(this.config.border);
|
|
63
|
-
canvas.style.cursor = this.config.showMouse ? 'default' : 'none';
|
|
64
82
|
// Event listeners
|
|
65
|
-
|
|
66
|
-
if (!_this.
|
|
83
|
+
container.addEventListener('mousemove', function (e) {
|
|
84
|
+
if (!_this.focused) {
|
|
67
85
|
return;
|
|
68
86
|
}
|
|
69
87
|
_this.mouseX = (e.offsetX / _this.config.scale) | 0;
|
|
@@ -71,8 +89,8 @@ var Canvas = /** @class */ (function () {
|
|
|
71
89
|
_this.log(e.type, _this.mouseX, _this.mouseY);
|
|
72
90
|
_this.config.mousemove(_this.mouseX, _this.mouseY);
|
|
73
91
|
});
|
|
74
|
-
|
|
75
|
-
if (!_this.
|
|
92
|
+
container.addEventListener('keydown', function (e) {
|
|
93
|
+
if (!_this.focused) {
|
|
76
94
|
return;
|
|
77
95
|
}
|
|
78
96
|
e.preventDefault();
|
|
@@ -83,8 +101,8 @@ var Canvas = /** @class */ (function () {
|
|
|
83
101
|
_this.config.keydown(key);
|
|
84
102
|
}
|
|
85
103
|
});
|
|
86
|
-
|
|
87
|
-
if (!_this.
|
|
104
|
+
container.addEventListener('keyup', function (e) {
|
|
105
|
+
if (!_this.focused) {
|
|
88
106
|
return;
|
|
89
107
|
}
|
|
90
108
|
var key = e.key.toLowerCase();
|
|
@@ -95,8 +113,8 @@ var Canvas = /** @class */ (function () {
|
|
|
95
113
|
_this.config.keyup(key);
|
|
96
114
|
}
|
|
97
115
|
});
|
|
98
|
-
|
|
99
|
-
if (!_this.
|
|
116
|
+
container.addEventListener('mousedown', function (e) {
|
|
117
|
+
if (!_this.focused) {
|
|
100
118
|
return;
|
|
101
119
|
}
|
|
102
120
|
var button = e.button;
|
|
@@ -106,8 +124,8 @@ var Canvas = /** @class */ (function () {
|
|
|
106
124
|
_this.config.mousedown(button);
|
|
107
125
|
}
|
|
108
126
|
});
|
|
109
|
-
|
|
110
|
-
if (!_this.
|
|
127
|
+
container.addEventListener('mouseup', function (e) {
|
|
128
|
+
if (!_this.focused) {
|
|
111
129
|
return;
|
|
112
130
|
}
|
|
113
131
|
var button = e.button;
|
|
@@ -118,30 +136,26 @@ var Canvas = /** @class */ (function () {
|
|
|
118
136
|
_this.config.mouseup(button);
|
|
119
137
|
}
|
|
120
138
|
});
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
_this.
|
|
139
|
+
container.addEventListener('focusin', function (e) {
|
|
140
|
+
_this.focused = true;
|
|
141
|
+
container.style.borderColor = _this.config.border;
|
|
142
|
+
_this.log(e.type, _this.focused);
|
|
124
143
|
_this.animation = requestAnimationFrame(function (time) { return _this.startAnimate(time); });
|
|
125
144
|
});
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
_this.
|
|
145
|
+
container.addEventListener('focusout', function (e) {
|
|
146
|
+
_this.focused = false;
|
|
147
|
+
container.style.borderColor = _this.config.borderBlur;
|
|
148
|
+
_this.log(e.type, _this.focused);
|
|
129
149
|
cancelAnimationFrame(_this.animation);
|
|
130
150
|
});
|
|
131
151
|
window.addEventListener('blur', function (e) {
|
|
132
152
|
_this.log(e.type);
|
|
133
153
|
cancelAnimationFrame(_this.animation);
|
|
134
154
|
});
|
|
135
|
-
|
|
155
|
+
container.addEventListener('contextmenu', function (e) { return e.preventDefault(); });
|
|
136
156
|
// Focus on the canvas
|
|
137
|
-
|
|
157
|
+
container.focus();
|
|
138
158
|
}
|
|
139
|
-
/**
|
|
140
|
-
* Determine if the canvas is currently focused.
|
|
141
|
-
*/
|
|
142
|
-
Canvas.prototype.isFocused = function () {
|
|
143
|
-
return this.graphics.canvas === document.activeElement;
|
|
144
|
-
};
|
|
145
159
|
/**
|
|
146
160
|
* Start the animation.
|
|
147
161
|
*/
|
|
@@ -195,11 +209,13 @@ var Canvas = /** @class */ (function () {
|
|
|
195
209
|
* Get the color of the selected pixel.
|
|
196
210
|
* @param x The pixel's x-coordinate
|
|
197
211
|
* @param y The pixel's y-coordinate
|
|
212
|
+
* @param layer The zero-indexed layer to get data from
|
|
198
213
|
* @returns `[red, green, blue, alpha]`
|
|
199
214
|
*/
|
|
200
|
-
Canvas.prototype.getPixel = function (x, y) {
|
|
201
|
-
|
|
202
|
-
|
|
215
|
+
Canvas.prototype.getPixel = function (x, y, layer) {
|
|
216
|
+
if (layer === void 0) { layer = 0; }
|
|
217
|
+
var data = this.graphics[layer].getImageData(x, y, 1, 1).data;
|
|
218
|
+
this.log(this.graphics[layer].getImageData(x, y, 2, 2));
|
|
203
219
|
;
|
|
204
220
|
return [data[0], data[1], data[2], data[3]];
|
|
205
221
|
};
|
|
@@ -208,38 +224,72 @@ var Canvas = /** @class */ (function () {
|
|
|
208
224
|
* @param x The pixel's x-coordinate
|
|
209
225
|
* @param y The pixel's y-coordinate
|
|
210
226
|
* @param color `[red, green, blue, alpha]`
|
|
227
|
+
* @param layer The zero-indexed layer to set data to
|
|
211
228
|
*/
|
|
212
|
-
Canvas.prototype.setPixel = function (x, y, color) {
|
|
213
|
-
|
|
229
|
+
Canvas.prototype.setPixel = function (x, y, color, layer) {
|
|
230
|
+
if (layer === void 0) { layer = 0; }
|
|
231
|
+
var data = this.graphics[layer].getImageData(x, y, 1, 1);
|
|
214
232
|
data.data[0] = color[0];
|
|
215
233
|
data.data[1] = color[1];
|
|
216
234
|
data.data[2] = color[2];
|
|
217
235
|
data.data[3] = color[3];
|
|
218
|
-
|
|
219
|
-
this.graphics.putImageData(data, x, y);
|
|
236
|
+
this.log(data);
|
|
237
|
+
this.graphics[layer].putImageData(data, x, y);
|
|
220
238
|
};
|
|
221
239
|
/**
|
|
222
240
|
* Take a screenshot of the canvas contents and save to a .png file.
|
|
241
|
+
* @param name The file name of the screenshot
|
|
223
242
|
*/
|
|
224
|
-
Canvas.prototype.screenshot = function () {
|
|
225
|
-
|
|
243
|
+
Canvas.prototype.screenshot = function (name) {
|
|
244
|
+
if (name === void 0) { name = 'screenshot'; }
|
|
245
|
+
// Create an offscreen canvas
|
|
246
|
+
var screen = new Canvas({
|
|
247
|
+
parent: document.createElement('div'),
|
|
248
|
+
height: this.config.height,
|
|
249
|
+
width: this.config.width,
|
|
250
|
+
scale: this.config.scale,
|
|
251
|
+
});
|
|
252
|
+
// Draw the background and each layer
|
|
253
|
+
screen.graphics[0].fillStyle = this.config.background;
|
|
254
|
+
screen.graphics[0].fillRect(0, 0, screen.width, screen.height);
|
|
255
|
+
for (var _i = 0, _a = this.graphics; _i < _a.length; _i++) {
|
|
256
|
+
var graphic = _a[_i];
|
|
257
|
+
screen.graphics[0].drawImage(graphic.canvas, 0, 0);
|
|
258
|
+
}
|
|
259
|
+
// Generate a data URL and set it as the download parameter for <a>
|
|
260
|
+
var dataURL = screen.graphics[0].canvas.toDataURL();
|
|
226
261
|
var downloadLink = document.createElement('a');
|
|
227
262
|
downloadLink.setAttribute('href', dataURL);
|
|
228
|
-
downloadLink.setAttribute('download',
|
|
263
|
+
downloadLink.setAttribute('download', name);
|
|
229
264
|
downloadLink.click();
|
|
265
|
+
// Remove all keys and mouse buttons down because we lose focus
|
|
266
|
+
this.keys.splice(0);
|
|
267
|
+
this.mouseButtons.splice(0);
|
|
230
268
|
};
|
|
231
269
|
/**
|
|
232
270
|
* Draw an object onto the canvas.
|
|
233
271
|
* @param drawable Any drawable object
|
|
272
|
+
* @param layer The zero-indexed layer to draw to
|
|
234
273
|
*/
|
|
235
|
-
Canvas.prototype.draw = function (drawable) {
|
|
236
|
-
|
|
274
|
+
Canvas.prototype.draw = function (drawable, layer) {
|
|
275
|
+
if (layer === void 0) { layer = 0; }
|
|
276
|
+
drawable.draw(this.graphics[layer]);
|
|
237
277
|
};
|
|
238
278
|
/**
|
|
239
279
|
* Completely clears the canvas.
|
|
280
|
+
* @param layer The zero-indexed layer to clear, if unset, will clear all layers
|
|
240
281
|
*/
|
|
241
|
-
Canvas.prototype.clear = function () {
|
|
242
|
-
|
|
282
|
+
Canvas.prototype.clear = function (layer) {
|
|
283
|
+
if (layer === void 0) { layer = -1; }
|
|
284
|
+
if (layer < 0) {
|
|
285
|
+
for (var _i = 0, _a = this.graphics; _i < _a.length; _i++) {
|
|
286
|
+
var graphic = _a[_i];
|
|
287
|
+
graphic.clearRect(0, 0, this.config.width, this.config.height);
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
else {
|
|
291
|
+
this.graphics[layer].clearRect(0, 0, this.config.width, this.config.height);
|
|
292
|
+
}
|
|
243
293
|
};
|
|
244
294
|
/**
|
|
245
295
|
* Log a message to the debug console.
|
|
@@ -278,6 +328,8 @@ var Canvas = /** @class */ (function () {
|
|
|
278
328
|
border: 'transparent',
|
|
279
329
|
borderBlur: 'transparent',
|
|
280
330
|
showMouse: true,
|
|
331
|
+
numLayers: 1,
|
|
332
|
+
acceleration: 'hardware',
|
|
281
333
|
keydown: function () { return; },
|
|
282
334
|
keyup: function () { return; },
|
|
283
335
|
mousemove: function () { return; },
|
package/package.json
CHANGED
package/types/canvas.d.ts
CHANGED
|
@@ -46,15 +46,15 @@ export declare class Canvas {
|
|
|
46
46
|
* The last frame's high resolution timestamp
|
|
47
47
|
*/
|
|
48
48
|
private lastFrame;
|
|
49
|
+
/**
|
|
50
|
+
* Determine whether the client is focused or not
|
|
51
|
+
*/
|
|
52
|
+
private focused;
|
|
49
53
|
/**
|
|
50
54
|
* Create a new canvas with the provided options
|
|
51
55
|
* @param options Configuration options
|
|
52
56
|
*/
|
|
53
57
|
constructor(options?: Partial<Options>);
|
|
54
|
-
/**
|
|
55
|
-
* Determine if the canvas is currently focused.
|
|
56
|
-
*/
|
|
57
|
-
private isFocused;
|
|
58
58
|
/**
|
|
59
59
|
* Start the animation.
|
|
60
60
|
*/
|
|
@@ -84,29 +84,34 @@ export declare class Canvas {
|
|
|
84
84
|
* Get the color of the selected pixel.
|
|
85
85
|
* @param x The pixel's x-coordinate
|
|
86
86
|
* @param y The pixel's y-coordinate
|
|
87
|
+
* @param layer The zero-indexed layer to get data from
|
|
87
88
|
* @returns `[red, green, blue, alpha]`
|
|
88
89
|
*/
|
|
89
|
-
getPixel(x: number, y: number): [number, number, number, number];
|
|
90
|
+
getPixel(x: number, y: number, layer?: number): [number, number, number, number];
|
|
90
91
|
/**
|
|
91
92
|
* Set the color of the selected pixel.
|
|
92
93
|
* @param x The pixel's x-coordinate
|
|
93
94
|
* @param y The pixel's y-coordinate
|
|
94
95
|
* @param color `[red, green, blue, alpha]`
|
|
96
|
+
* @param layer The zero-indexed layer to set data to
|
|
95
97
|
*/
|
|
96
|
-
setPixel(x: number, y: number, color: [number, number, number, number]): void;
|
|
98
|
+
setPixel(x: number, y: number, color: [number, number, number, number], layer?: number): void;
|
|
97
99
|
/**
|
|
98
100
|
* Take a screenshot of the canvas contents and save to a .png file.
|
|
101
|
+
* @param name The file name of the screenshot
|
|
99
102
|
*/
|
|
100
|
-
screenshot(): void;
|
|
103
|
+
screenshot(name?: string): void;
|
|
101
104
|
/**
|
|
102
105
|
* Draw an object onto the canvas.
|
|
103
106
|
* @param drawable Any drawable object
|
|
107
|
+
* @param layer The zero-indexed layer to draw to
|
|
104
108
|
*/
|
|
105
|
-
draw(drawable: Drawable): void;
|
|
109
|
+
draw(drawable: Drawable, layer?: number): void;
|
|
106
110
|
/**
|
|
107
111
|
* Completely clears the canvas.
|
|
112
|
+
* @param layer The zero-indexed layer to clear, if unset, will clear all layers
|
|
108
113
|
*/
|
|
109
|
-
clear(): void;
|
|
114
|
+
clear(layer?: number): void;
|
|
110
115
|
/**
|
|
111
116
|
* Log a message to the debug console.
|
|
112
117
|
*/
|
|
@@ -156,6 +161,16 @@ export interface Options {
|
|
|
156
161
|
* Optionally show or hide the mouse when hovering over the canvas
|
|
157
162
|
*/
|
|
158
163
|
readonly showMouse: boolean;
|
|
164
|
+
/**
|
|
165
|
+
* The number of layers in this canvas
|
|
166
|
+
*/
|
|
167
|
+
readonly numLayers: number;
|
|
168
|
+
/**
|
|
169
|
+
* Uses hardware (GPU) or software (CPU) acceleration
|
|
170
|
+
* - For pixel manipulation, software acceleration is recommended
|
|
171
|
+
* - Otherwise, hardware acceleration is recommended (default)
|
|
172
|
+
*/
|
|
173
|
+
readonly acceleration: 'hardware' | 'software';
|
|
159
174
|
/**
|
|
160
175
|
* Event listener for when a key is pressed
|
|
161
176
|
* @param key The key that was pressed
|
|
@@ -185,7 +200,7 @@ export interface Options {
|
|
|
185
200
|
/**
|
|
186
201
|
* Event listener for a the main animation loop
|
|
187
202
|
* @param dt The number of milliseconds in between frames
|
|
188
|
-
* @returns An array of `Drawable` to render, or void
|
|
203
|
+
* @returns An array of `Drawable` to render on layer 0, or void
|
|
189
204
|
*/
|
|
190
205
|
readonly loop: (dt: number) => Drawable[] | (void | never);
|
|
191
206
|
}
|