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 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
- var canvas = document.createElement('canvas');
43
- var graphics = canvas.getContext('2d');
44
- if (graphics) {
45
- this.graphics = graphics;
46
- }
47
- else {
48
- throw new Error('Could not initialize canvas graphics.');
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
- canvas.addEventListener('mousemove', function (e) {
66
- if (!_this.isFocused()) {
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
- canvas.addEventListener('keydown', function (e) {
75
- if (!_this.isFocused()) {
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
- canvas.addEventListener('keyup', function (e) {
87
- if (!_this.isFocused()) {
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
- canvas.addEventListener('mousedown', function (e) {
99
- if (!_this.isFocused()) {
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
- canvas.addEventListener('mouseup', function (e) {
110
- if (!_this.isFocused()) {
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
- canvas.addEventListener('focusin', function (e) {
122
- canvas.style.borderColor = _this.config.border;
123
- _this.log(e.type);
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
- canvas.addEventListener('focusout', function (e) {
127
- canvas.style.borderColor = _this.config.borderBlur;
128
- _this.log(e.type);
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
- canvas.addEventListener('contextmenu', function (e) { return e.preventDefault(); });
155
+ container.addEventListener('contextmenu', function (e) { return e.preventDefault(); });
136
156
  // Focus on the canvas
137
- canvas.focus();
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
- var data = this.graphics.getImageData(x, y, 1, 1).data;
202
- console.log(this.graphics.getImageData(x, y, 2, 2));
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
- var data = this.graphics.getImageData(x, y, 1, 1);
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
- console.log(data);
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
- var dataURL = this.graphics.canvas.toDataURL();
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', 'screenshot');
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
- drawable.draw(this.graphics);
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
- this.graphics.clearRect(0, 0, this.config.width, this.config.height);
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "graphico",
3
- "version": "0.0.3",
3
+ "version": "0.0.4",
4
4
  "description": "Canvas 2D rendering toolkit for games and visual projects",
5
5
  "homepage": "https://npm.nicfv.com/",
6
6
  "bin": "",
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
  }