├── .gitignore
├── README.md
├── Rakefile
├── pixel.js
└── pixel.min.js
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | docs
3 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Pixel
2 |
3 | A pixel drawing library.
4 |
5 | See a demo app using this library at [http://drawbang.com](http://drawbang.com) and its source code at [http://github.com/potomak/drawbang](http://github.com/potomak/drawbang)
6 |
7 | ## Documentation
8 |
9 | Generate documentation using Docco
10 |
11 | rake doc
12 |
13 | ## Compiling
14 |
15 | Compile library using Google Closure Compiler REST API
16 |
17 | rake compile
18 |
19 | More info about Google Closure Compiler REST API at http://code.google.com/closure/compiler/docs/gettingstarted_api.html
--------------------------------------------------------------------------------
/Rakefile:
--------------------------------------------------------------------------------
1 | require 'rubygems'
2 | require 'rake'
3 | require 'net/http'
4 |
5 | desc "Default task is :compile"
6 | task :default => :compile
7 |
8 | desc "Generate documentation"
9 | task :doc do
10 | library_path = 'pixel.js'
11 |
12 | puts "Generating documentation for #{library_path}"
13 | sh "docco #{library_path}"
14 | end
15 |
16 | desc "Compile library, it depends on :doc task"
17 | task :compile => :doc do
18 | library_path = 'pixel.js'
19 | output_path = "#{library_path.gsub(/\.js$/, '')}.min.js"
20 |
21 | puts "Compiling #{library_path}"
22 | uri = URI('http://closure-compiler.appspot.com/compile')
23 | options = {
24 | 'js_code' => File.open(library_path).read,
25 | 'compilation_level' => 'SIMPLE_OPTIMIZATIONS',
26 | 'output_format' => 'text',
27 | 'output_info' => 'compiled_code'
28 | }
29 | res = Net::HTTP.post_form(uri, options)
30 |
31 | puts "Writing compiled code to #{output_path}"
32 | File.open(output_path, 'w') {|f| f.write(res.body)}
33 | end
--------------------------------------------------------------------------------
/pixel.js:
--------------------------------------------------------------------------------
1 | // Pixel is a javascript pixel drawing library.
2 |
3 | var PIXEL = function() {
4 | // Global constants.
5 | var TRANSPARENT = "rgba(0, 0, 0, 0)";
6 |
7 | // Global variables.
8 | var version = '0.1',
9 | debug = false,
10 | matrix = [],
11 | frames = [],
12 | animation = null,
13 | currentFrame = 0,
14 | /* NOTE: deprecated
15 | onionFrame = null,
16 | */
17 | mainCanvas = null,
18 | previewCanvases = [],
19 | drawing = false,
20 | action = "pixel",
21 | settings = {
22 | previewCanvas: {
23 | pixelSize: 1,
24 | size: 16,
25 | gridColor: "#eeeeee",
26 | showGrid: false
27 | },
28 | mainCanvas: {
29 | pixelSize: 20,
30 | size: 320,
31 | gridColor: "#eeeeee",
32 | showGrid: false
33 | }
34 | },
35 | history = {
36 | action: [],
37 | undo: [],
38 | oldUndo: [],
39 | redo: []
40 | };
41 |
42 | // ## Canvas(canvas, settings)
43 | //
44 | // A canvas object.
45 | //
46 | // `canvas` a canvas element.
47 | // `settings` an object with settings to draw this canvas.
48 | function Canvas(canvas, settings) {
49 | // A canvas element.
50 | this.canvas = canvas;
51 |
52 | // Context element of `canvas`
53 | this.ctx = canvas.getContext("2d");
54 |
55 | // An object with canvas settings.
56 | //
57 | // Example settings:
58 | //
59 | // {
60 | // pixelSize: 1,
61 | // size: 16,
62 | // gridColor: "#eeeeee",
63 | // showGrid: false
64 | // }
65 | this.settings = settings;
66 |
67 | // ## clearCanvas()
68 | //
69 | // Clears canvas.
70 | this.clearCanvas = function() {
71 | this.canvas.width = this.canvas.width;
72 | }
73 |
74 | // ## drawGrid()
75 | //
76 | // Draws canvas grid.
77 | this.drawGrid = function() {
78 | var correction = 0.5;
79 |
80 | if(this.settings.showGrid) {
81 | for (var x = correction+this.settings.pixelSize; x < this.settings.size; x += this.settings.pixelSize) {
82 | this.ctx.moveTo(x, 0);
83 | this.ctx.lineTo(x, this.settings.size);
84 | this.ctx.moveTo(0, x);
85 | this.ctx.lineTo(this.settings.size, x);
86 | }
87 |
88 | this.ctx.strokeStyle = this.settings.gridColor;
89 | this.ctx.stroke();
90 | }
91 | }
92 |
93 | // ## getDataURL()
94 | //
95 | // Returns canvas data url string as `image/png`.
96 | this.getDataURL = function() {
97 | return this.canvas.toDataURL("image/png");
98 | }
99 |
100 | // ## draw(m)
101 | //
102 | // Draws canvas using `m` as bitmap data.
103 | this.draw = function(m) {
104 | this.clearCanvas();
105 |
106 | /* NOTE: deprecated
107 |
108 | if(onionFrame != null && typeof frames[onionFrame] != 'undefined' && frames[onionFrame] != null) {
109 | for(var i = 0; i < frames[onionFrame].length; i++) {
110 | for(var j = 0; j < frames[onionFrame][i].length; j++) {
111 | c = frames[onionFrame][i][j];
112 | if(c != TRANSPARENT) {
113 | components = c.match(/#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/);
114 | c = "rgba(" +
115 | new Number("0x" + components[1]) + ", " +
116 | new Number("0x" + components[2]) + ", " +
117 | new Number("0x" + components[3]) + ", 0.5)";
118 | }
119 | ctx.fillStyle = c;
120 | ctx.fillRect(i*pixelSize, j*pixelSize, pixelSize, pixelSize);
121 | }
122 | }
123 | }
124 | */
125 |
126 | for(var i = 0; i < m.length; i++) {
127 | for(var j = 0; j < m[i].length; j++) {
128 | this.ctx.fillStyle = m[i][j];
129 | this.ctx.fillRect(i*this.settings.pixelSize, j*this.settings.pixelSize, this.settings.pixelSize, this.settings.pixelSize);
130 | }
131 | }
132 |
133 | this.drawGrid();
134 | }
135 | }
136 |
137 |
138 | // ## init(mainCanvas, previewCanvases, debug)
139 | //
140 | // Initializes Pixel library.
141 | //
142 | // `mainCanvas` is a HTML5 canvas elements.
143 | // `previewCanvases` is an array of HTML5 canvas elements.
144 | // `debug` is a flag to override default debug settings.
145 | var init = function(aMainCanvas, aPreviewCanvases, aDebug) {
146 | mainCanvas = new Canvas(aMainCanvas, settings.mainCanvas);
147 | for(var i = 0; i < aPreviewCanvases.length; i++) {
148 | previewCanvases[i] = new Canvas(aPreviewCanvases[i], settings.previewCanvas);
149 | }
150 | typeof aDebug != 'undefined' ? debug = aDebug : null;
151 |
152 | initMatrix();
153 | initCanvas();
154 | }
155 |
156 | // ## initMatrix()
157 | //
158 | // Initializes matrix values to transparent.
159 | var initMatrix = function() {
160 | var length = settings.mainCanvas.size/settings.mainCanvas.pixelSize
161 | matrix = [];
162 |
163 | for(var i = 0; i < length; i++) {
164 | matrix.push(new Array(length));
165 | }
166 |
167 | for(var i = 0; i < matrix.length; i++) {
168 | for(var j = 0; j < matrix[i].length; j++) {
169 | matrix[i][j] = TRANSPARENT;
170 | }
171 | }
172 | }
173 |
174 | // ## initCanvas()
175 | //
176 | // Initializes canvas and history.
177 | var initCanvas = function() {
178 | history = {
179 | action: [],
180 | undo: [],
181 | oldUndo: [],
182 | redo: []
183 | };
184 |
185 | draw();
186 | }
187 |
188 | // ## log(obj)
189 | //
190 | // Logs `obj` to `console` if `debug` flag is `true`.
191 | var log = function(obj) {
192 | debug && console.log([(new Date()).toString(), obj]);
193 | }
194 |
195 | // ## printMatrix(m)
196 | //
197 | // Returns a formatted string representing `m`, where `m` is a matrix composed by
198 | // an *array of arrays*.
199 | var printMatrix = function(m) {
200 | mString = "";
201 |
202 | for(var i = 0; i < m.length; i++) {
203 | for(var j = 0; j < m[i].length; j++) {
204 | mString += (TRANSPARENT == m[i][j] ? "0" : "X") + ", ";
205 | }
206 |
207 | mString += "\n";
208 | }
209 |
210 | return mString;
211 | }
212 |
213 | // ## setDraw(flag)
214 | //
215 | // Sets `drawing` attribute.
216 | var setDraw = function(wantToDraw) {
217 | drawing = wantToDraw;
218 | }
219 |
220 | // ## setAction(action)
221 | //
222 | // Sets `action` attribute.
223 | var setAction = function(wantedAction) {
224 | action = wantedAction;
225 | }
226 |
227 | // ## clearCanvasAt(index)
228 | //
229 | // Clears canvas at `index`.
230 | var clearCanvasAt = function(index) {
231 | previewCanvases[index].clearCanvas();
232 |
233 | if(currentFrame == index) {
234 | mainCanvas.clearCanvas();
235 | frames[currentFrame] = null;
236 | initMatrix();
237 | initCanvas();
238 | }
239 | }
240 |
241 | // ## clearCanvas()
242 | //
243 | // Clears current frame canvas.
244 | var clearCanvas = function() {
245 | clearCanvasAt(currentFrame);
246 | }
247 |
248 | // ## removeFrame(index)
249 | //
250 | // Removes frame object from `frames` at `index`.
251 | var removeFrame = function(index) {
252 | frames.splice(index, 1);
253 | }
254 |
255 | // ## copyMatrix(m)
256 | //
257 | // Returns an object copied from `m` matrix.
258 | var copyMatrix = function(m) {
259 | if(typeof m != 'undefined') {
260 | var copy = m.slice();
261 |
262 | for(var i = 0; i < m.length; i++) {
263 | copy[i] = m[i].slice();
264 | }
265 |
266 | return copy;
267 | }
268 | }
269 |
270 | // ## doAction(x, y, color)
271 | //
272 | // Executes `action` at (`x`, `y`) with `color`.
273 | var doAction = function(x, y, color) {
274 | if(drawing) {
275 | var coords = {
276 | x: pixelify(x, settings.mainCanvas.pixelSize),
277 | y: pixelify(y, settings.mainCanvas.pixelSize)
278 | }
279 |
280 | switch(action) {
281 | case "pixel":
282 | var startColor = drawPixel(coords.x, coords.y, color);
283 |
284 | if(startColor != false) {
285 | history.undo.push(function() {
286 | drawPixel(coords.x, coords.y, startColor);
287 | });
288 |
289 | history.action.push(function() {
290 | drawPixel(coords.x, coords.y, color);
291 | });
292 | }
293 |
294 | break;
295 |
296 | case "clearPixel":
297 | var startColor = drawPixel(coords.x, coords.y, TRANSPARENT);
298 |
299 | if(startColor != false) {
300 | history.undo.push(function() {
301 | drawPixel(coords.x, coords.y, startColor);
302 | });
303 |
304 | history.action.push(function() {
305 | drawPixel(coords.x, coords.y, TRANSPARENT);
306 | });
307 | }
308 |
309 | break;
310 |
311 | case "fill":
312 | var startMatrix = fillPixels(coords.x, coords.y, color);
313 |
314 | if(startColor != false) {
315 | history.undo.push(function() {
316 | draw(startMatrix);
317 | });
318 |
319 | history.action.push(function() {
320 | fillPixels(coords.x, coords.y, color)
321 | });
322 | }
323 |
324 | break;
325 |
326 | default:
327 | log("unknown action:" + action);
328 | }
329 | }
330 | }
331 |
332 | // ## pixelify(val)
333 | //
334 | // Returns quantized value of `val` by `pixelSize`.
335 | //
336 | // `val` a number.
337 | // `pixelSize` a number representing *pixel size in pixels*
338 | var pixelify = function(val, pixelSize) {
339 | var i = Math.floor(val/pixelSize);
340 |
341 | i >= matrix.length && (i = matrix.length-1);
342 | i <= 0 && (i = 0);
343 |
344 | return i;
345 | }
346 |
347 | // ## drawPixel(x, y, color)
348 | //
349 | // Draws pixel at (`x`, `y`) of `color`.
350 | var drawPixel = function(x, y, color) {
351 | var startColor = matrix[x][y];
352 |
353 | if(startColor != color) {
354 | matrix[x][y] = color;
355 | draw();
356 |
357 | return startColor;
358 | }
359 |
360 | return false;
361 | }
362 |
363 | // ## getColorAt(x, y)
364 | //
365 | // Returns color string at (`x`, `y`).
366 | //
367 | // Color string format:
368 | //
369 | // /#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/
370 | var getColorAt = function(x, y) {
371 | return TRANSPARENT == matrix[x][y] ? "#ffffff" : matrix[x][y];
372 | }
373 |
374 | // ## fillPixels(x, y, color)
375 | //
376 | // Fills pixels.
377 | var fillPixels = function(x, y, color) {
378 | var startColor = getColorAt(x, y);
379 |
380 | if(startColor != color) {
381 | var startMatrix = copyMatrix(matrix),
382 | start = (new Date()).getTime();
383 |
384 | fillPixel(x, y, startColor, color);
385 | log("flood fill time: " + ((new Date()).getTime()-start));
386 |
387 | draw();
388 |
389 | return startMatrix;
390 | }
391 |
392 | return false;
393 | }
394 |
395 | // ## fillPixel(x, y, startColor, endColor)
396 | //
397 | // Recursive part of `fillPixels` function.
398 | //
399 | // `x`
400 | // `y`
401 | // `startColor` a hex representation of starting color.
402 | // `endColor` a hex representation of target color.
403 | var fillPixel = function(x, y, startColor, endColor) {
404 | if(x >= 0 && x < matrix[0].length && y >= 0 && y < matrix.length) {
405 | if(getColorAt(x, y) == startColor) {
406 | matrix[x][y] = endColor;
407 |
408 | fillPixel(x+1, y, startColor, endColor);
409 | fillPixel(x-1, y, startColor, endColor);
410 | fillPixel(x, y+1, startColor, endColor);
411 | fillPixel(x, y-1, startColor, endColor);
412 | }
413 | }
414 | }
415 |
416 | // ## draw(m)
417 | //
418 | // Draws main canvas and preview canvas at `currentFrame` using `m` as matrix or
419 | // global `matrix` if `m` is `undefined`.
420 | var draw = function(m) {
421 | typeof m == 'undefined' ? m = matrix : matrix = copyMatrix(m);
422 |
423 | mainCanvas.clearCanvas();
424 | previewCanvases[currentFrame].clearCanvas();
425 |
426 | /* NOTE: deprecated
427 |
428 | if(onionFrame != null && typeof frames[onionFrame] != 'undefined' && frames[onionFrame] != null) {
429 | for(var i = 0; i < frames[onionFrame].length; i++) {
430 | for(var j = 0; j < frames[onionFrame][i].length; j++) {
431 | c = frames[onionFrame][i][j];
432 | if(c != TRANSPARENT) {
433 | components = c.match(/#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/);
434 | c = "rgba(" +
435 | new Number("0x" + components[1]) + ", " +
436 | new Number("0x" + components[2]) + ", " +
437 | new Number("0x" + components[3]) + ", 0.5)";
438 | }
439 | ctx.fillStyle = c;
440 | ctx.fillRect(i*pixelSize, j*pixelSize, pixelSize, pixelSize);
441 | }
442 | }
443 | }
444 | */
445 |
446 | mainCanvas.draw(m);
447 | previewCanvases[currentFrame].draw(m);
448 | }
449 |
450 | // ## getHistory()
451 | //
452 | // Returns history object.
453 | var getHistory = function() {
454 | return history;
455 | }
456 |
457 | // ## undo()
458 | //
459 | // Undoes latest action.
460 | var undo = function() {
461 | if(history.undo.length > 0) {
462 | var todo = history.undo.pop();
463 | todo.call();
464 | history.redo.push(history.action.pop());
465 | history.oldUndo.push(todo);
466 | }
467 | }
468 |
469 | // ## redo()
470 | //
471 | // Viceversa of `undo()`.
472 | //
473 | // **Deprecation warning**
474 | var redo = function() {
475 | if(history.redo.length > 0) {
476 | var todo = history.redo.pop();
477 | todo.call();
478 | history.undo.push(history.oldUndo.pop());
479 | history.action.push(todo);
480 | }
481 | }
482 |
483 | // ## getFrame(frame)
484 | //
485 | // Returns data matrix for frame at index `frame`.
486 | var getFrame = function(frame) {
487 | return currentFrame == frame ? matrix : frames[frame];
488 | }
489 |
490 | // ## getCurrentFrame()
491 | //
492 | // Returns current frame data matrix.
493 | var getCurrentFrame = function() {
494 | return matrix;
495 | }
496 |
497 | // ## getCurrentFrameId()
498 | //
499 | // Returns current frame id.
500 | var getCurrentFrameId = function() {
501 | return currentFrame;
502 | }
503 |
504 | // ## setCurrentFrame(frame)
505 | //
506 | // Sets current frame and matrix to object at index `frame`.
507 | var setCurrentFrame = function(frame) {
508 | log("setCurrentFrame: " + frame);
509 |
510 | if(frame != currentFrame) {
511 | frames[currentFrame] = copyMatrix(matrix);
512 | matrix = copyMatrix(frames[frame]);
513 |
514 | // a new frame
515 | if(typeof matrix == 'undefined') {
516 | // set current frame placeholder
517 | frames[frame] = null;
518 | // initialize matrix
519 | initMatrix();
520 | }
521 |
522 | currentFrame = frame;
523 |
524 | initCanvas();
525 |
526 | log("setCurrentFrame - frames.length: " + frames.length);
527 | }
528 | }
529 |
530 | // ## setOnionFrame(frame)
531 | //
532 | // Sets `frame` as onion frame and draws canvas.
533 | //
534 | // **Deprecation warning**
535 | var setOnionFrame = function(frame) {
536 | onionFrame = frame;
537 | draw();
538 | }
539 |
540 | // ## getCurrentOnionFrameId()
541 | //
542 | // Returns current onion frame index.
543 | //
544 | // **Deprecation warning**
545 | var getCurrentOnionFrameId = function() {
546 | return onionFrame;
547 | }
548 |
549 | // ## play(fps, callback)
550 | //
551 | // Plays animation at `fps` frames per second.
552 | //
553 | // At every frame redraw `callback` is called.
554 | var play = function(fps, callback) {
555 | if(frames.length > 1) {
556 | animation = setInterval(function() {
557 | activeFrame = (currentFrame+1)%frames.length;
558 | log([
559 | "play animation",
560 | "activeFrame: " + activeFrame,
561 | "currentFrame: " + currentFrame,
562 | "frames.length: " + frames.length
563 | ]);
564 | setCurrentFrame(activeFrame);
565 | callback(activeFrame);
566 | }, (1/fps)*1000);
567 | }
568 | }
569 |
570 | // ## stop()
571 | //
572 | // Stops animation.
573 | var stop = function() {
574 | clearInterval(animation);
575 | animation = null;
576 | }
577 |
578 | // ## moveTop()
579 | //
580 | // Moves canvas top by one pixel.
581 | var moveTop = function() {
582 | var startMatrix = copyMatrix(matrix),
583 | start = (new Date()).getTime();
584 |
585 | // For each column of pixels
586 | for(var i = 0; i < matrix.length; i++) {
587 | // push at beginning of column latest array element.
588 | matrix[i].push(matrix[i].shift());
589 | }
590 |
591 | log("move top time: " + ((new Date()).getTime()-start));
592 |
593 | draw();
594 |
595 | history.undo.push(function() {
596 | draw(startMatrix);
597 | });
598 | }
599 |
600 | // ## moveRight()
601 | //
602 | // Moves canvas right by one pixel.
603 | var moveRight = function() {
604 | var startMatrix = copyMatrix(matrix),
605 | start = (new Date()).getTime();
606 |
607 | // For each row of pixels:
608 | for(j = 0; j < matrix[0].length; j++) {
609 | // save latest row pixel to `temp` buffer,
610 | var temp = matrix[matrix.length-1][j];
611 |
612 | // shift elements by row,
613 | for(i = matrix.length - 1; i > 0; i--) {
614 | matrix[i][j] = matrix[i-1][j];
615 | }
616 |
617 | // set first row element as `temp`.
618 | matrix[0][j] = temp;
619 | }
620 |
621 | log("move right time: " + ((new Date()).getTime()-start));
622 |
623 | draw();
624 |
625 | history.undo.push(function() {
626 | draw(startMatrix);
627 | });
628 | }
629 |
630 | // ## flipVertical()
631 | //
632 | // Flips canvas vertically.
633 | var flipVertical = function() {
634 | var startMatrix = copyMatrix(matrix),
635 | start = (new Date()).getTime();
636 |
637 | // For each column of pixels,
638 | for(var i = 0; i < matrix.length; i++) {
639 | // for half of each row of pixels,
640 | for(var j = 0; j < matrix[i].length/2; j++) {
641 | var temp = matrix[i][j],
642 | length = matrix[i].length;
643 |
644 | // swap first half column with second half.
645 | matrix[i][j] = matrix[i][length-1-j];
646 | matrix[i][length-1-j] = temp;
647 | }
648 | }
649 |
650 | log("flip vertical time: " + ((new Date()).getTime()-start));
651 |
652 | draw();
653 |
654 | history.undo.push(function() {
655 | draw(startMatrix);
656 | });
657 | }
658 |
659 | // ## flipHorizontal()
660 | //
661 | // Flips canvas horizontally.
662 | var flipHorizontal = function() {
663 | var startMatrix = copyMatrix(matrix),
664 | start = (new Date()).getTime();
665 |
666 | // For half of each column of pixels,
667 | for(var i = 0; i < matrix.length/2; i++) {
668 | // for each row of pixels,
669 | for(var j = 0; j < matrix[i].length; j++) {
670 | var temp = matrix[i][j],
671 | length = matrix.length;
672 |
673 | // swap first half row with second half.
674 | matrix[i][j] = matrix[length-1-i][j];
675 | matrix[length-1-i][j] = temp;
676 | }
677 | }
678 |
679 | log("flip vertical time: " + ((new Date()).getTime()-start));
680 |
681 | draw();
682 |
683 | history.undo.push(function() {
684 | draw(startMatrix);
685 | });
686 | }
687 |
688 | // ## rotate()
689 | //
690 | // Rotates canvas left by 90 degrees.
691 | var rotate = function() {
692 | var startMatrix = copyMatrix(matrix),
693 | start = (new Date()).getTime();
694 |
695 | // For each column of pixels,
696 | for(var i = 0; i < matrix.length; i++) {
697 | // for each row of pixels,
698 | for(var j = 0; j < matrix[i].length; j++) {
699 | // swap each element to swap row with column.
700 | matrix[i][j] = startMatrix[matrix[i].length-1 - j][i];
701 | }
702 | }
703 |
704 | log("rotate time: " + ((new Date()).getTime()-start));
705 |
706 | draw();
707 |
708 | history.undo.push(function() {
709 | draw(startMatrix);
710 | });
711 | }
712 |
713 | // ## copyFrameAt(index)
714 | //
715 | // Copies frame at `index` to current frame.
716 | //
717 | // `index` an integer representing an index of `frames` array.
718 | var copyFrameAt = function(index) {
719 | var startMatrix = copyMatrix(matrix),
720 | start = (new Date()).getTime();
721 |
722 | matrix = copyMatrix(getFrame(index));
723 |
724 | log("copyFrameAt " + index + ": " + ((new Date()).getTime()-start));
725 |
726 | draw();
727 |
728 | history.undo.push(function() {
729 | draw(startMatrix);
730 | });
731 | }
732 |
733 | return {
734 | init: init,
735 | clearCanvasAt: clearCanvasAt,
736 | clearCanvas: clearCanvas,
737 | removeFrame: removeFrame,
738 | setDraw: setDraw,
739 | setAction: setAction,
740 | doAction: doAction,
741 | getHistory: getHistory,
742 | undo: undo,
743 | /* NOTE: deprecated
744 | redo: redo,
745 | */
746 | getFrame: getFrame,
747 | setCurrentFrame: setCurrentFrame,
748 | /* NOTE: deprecated
749 | setOnionFrame: setOnionFrame,
750 | getCurrentOnionFrameId: getCurrentOnionFrameId,
751 | */
752 | getCurrentFrame: getCurrentFrame,
753 | getCurrentFrameId: getCurrentFrameId,
754 | play: play,
755 | stop: stop,
756 | moveRight: moveRight,
757 | moveTop: moveTop,
758 | flipHorizontal: flipHorizontal,
759 | flipVertical: flipVertical,
760 | rotate: rotate,
761 | copyFrameAt: copyFrameAt,
762 | log: log
763 | };
764 | }();
--------------------------------------------------------------------------------
/pixel.min.js:
--------------------------------------------------------------------------------
1 | var PIXEL=function(){function x(a,b){this.canvas=a;this.ctx=a.getContext("2d");this.settings=b;this.clearCanvas=function(){this.canvas.width=this.canvas.width};this.drawGrid=function(){if(this.settings.showGrid){for(var a=0.5+this.settings.pixelSize;a=b.length&&(c=b.length-1);0>=c&&(c=0);return c},
4 | o=function(a,d,c){var e=b[a][d];return e!=c?(b[a][d]=c,h(),e):!1},C=function(a,d){return"rgba(0, 0, 0, 0)"==b[a][d]?"#ffffff":b[a][d]},D=function(a,d,c){var e=C(a,d);if(e!=c){var g=l(b),k=(new Date).getTime();q(a,d,e,c);m("flood fill time: "+((new Date).getTime()-k));h();return g}return!1},q=function(a,d,c,e){0<=a&&a