paint-by-numbers

Relaxing paint-by-numbers game  https://p.ce9e.org/paint-by-numbers/
git clone https://git.ce9e.org/paint-by-numbers.git

commit
59f88bffdb05e19ee651d79f28808143a5ba5992
parent
60e5d8242e5370dbc714eb52b3add073d5f586de
Author
Tobias Bengfort <tobias.bengfort@posteo.de>
Date
2023-02-13 04:59
refactor: frame module

Diffstat

A frame.js 50 ++++++++++++++++++++++++++++++++++++++++++++++++++
M paint.js 68 ++++++++++++++++++-------------------------------------------

2 files changed, 70 insertions, 48 deletions


diff --git a/frame.js b/frame.js

@@ -0,0 +1,50 @@
   -1     1 export var PXSIZE = 12;
   -1     2 
   -1     3 export class Frame {
   -1     4     constructor() {
   -1     5         this.image = null;
   -1     6         this.canvas = document.createElement('canvas');
   -1     7         this.ctx = this.canvas.getContext('2d');
   -1     8     }
   -1     9 
   -1    10     setImage(image) {
   -1    11         this.image = image;
   -1    12         if (this.image) {
   -1    13             this.canvas.width = image.width * PXSIZE;
   -1    14             this.canvas.height = image.height * PXSIZE;
   -1    15             this.ctx.textAlign = 'center';
   -1    16             this.ctx.textBaseline = 'middle';
   -1    17             this.fill(0);
   -1    18         }
   -1    19     }
   -1    20 
   -1    21     _setPixel(x, y, color) {
   -1    22         var i = y * this.image.width + x;
   -1    23         this.ctx.fillStyle = this.image.colors[color];
   -1    24         this.ctx.fillRect(x * PXSIZE, y * PXSIZE, PXSIZE, PXSIZE);
   -1    25         if (color !== this.image.data[i]) {
   -1    26             this.ctx.fillStyle = this.image.contrasts[color];
   -1    27             this.ctx.fillText(
   -1    28                 this.image.data[i], (x + 0.5) * PXSIZE, (y + 0.5) * PXSIZE
   -1    29             );
   -1    30         }
   -1    31     }
   -1    32 
   -1    33     setPixel(x, y, color) {
   -1    34         if (
   -1    35             this.image
   -1    36             && x >= 0 && x < this.image.width
   -1    37             && y >= 0 && y < this.image.height
   -1    38         ) {
   -1    39             this._setPixel(Math.floor(x), Math.floor(y), color);
   -1    40         }
   -1    41     }
   -1    42 
   -1    43     fill(color) {
   -1    44         for (var y = 0; y < this.image.height; y++) {
   -1    45             for (var x = 0; x < this.image.width; x++) {
   -1    46                 this._setPixel(x, y, color);
   -1    47             }
   -1    48         }
   -1    49     }
   -1    50 }

diff --git a/paint.js b/paint.js

@@ -1,17 +1,17 @@
   -1     1 import { Frame, PXSIZE } from './frame.js';
   -1     2 
    1     3 var input = document.querySelector('input');
    2     4 var palette = document.querySelector('.palette');
    3     5 
    4     6 var canvas = document.querySelector('canvas');
    5     7 var ctx = canvas.getContext('2d');
    6     8 
    7    -1 var offcanvas = document.createElement('canvas');
    8    -1 var octx = offcanvas.getContext('2d');
   -1     9 var frame = new Frame();
    9    10 
   10    11 var data;
   11    12 var pencil = 0;
   12    13 
   13    14 var zoom = 1;
   14    -1 var pxsize = 12;
   15    15 var dx = 0;
   16    16 var dy = 0;
   17    17 var speed_x = 0;
@@ -40,7 +40,7 @@ var sRGB = function(c) {
   40    40 var makeContrast = function(a) {
   41    41     var l = 0.2126 * sRGB(a[0]) + 0.7152 * sRGB(a[1]) + 0.0722 * sRGB(a[2]);
   42    42     return l > 0.18 ? '#000' : '#fff';
   43    -1 }
   -1    43 };
   44    44 
   45    45 var onAnimation = function(fn) {
   46    46     var called = false;
@@ -106,30 +106,12 @@ var analyze = function(img) {
  106   106     };
  107   107 };
  108   108 
  109    -1 var _setPixel = function(x, y, color) {
  110    -1     var i = y * data.width + x;
  111    -1     octx.fillStyle = data.colors[color];
  112    -1     octx.fillRect(x * pxsize, y * pxsize, pxsize, pxsize);
  113    -1     if (color !== data.data[i]) {
  114    -1         octx.fillStyle = data.contrasts[color];
  115    -1         octx.fillText(data.data[i], (x + 0.5) * pxsize, (y + 0.5) * pxsize);
  116    -1     }
  117    -1 };
  118    -1 
  119    -1 var setPixel = function(x, y, color) {
  120    -1     if (x >= 0 && x < data.width && y >= 0 && y < data.height) {
  121    -1         _setPixel(Math.floor(x), Math.floor(y), color);
  122    -1     }
  123    -1 }
  124    -1 
  125   109 input.addEventListener('change', () => {
  126   110     file2img(input.files[0]).then(img => {
  127   111         // FIXME: configurable size
  128   112         data = analyze(img2data(img, 80 / img.width));
  129    -1         offcanvas.width = data.width * pxsize;
  130    -1         offcanvas.height = data.height * pxsize;
  131    -1         octx.textAlign = 'center';
  132    -1         octx.textBaseline = 'middle';
   -1   113 
   -1   114         frame.setImage(data);
  133   115 
  134   116         palette.innerHTML = '';
  135   117         for (var i = 0; i < data.colors.length; i++) {
@@ -152,20 +134,13 @@ input.addEventListener('change', () => {
  152   134         setPencil(0);
  153   135         resizeCanvas();
  154   136 
  155    -1         zoom = canvas.height / offcanvas.height * 0.8;
  156    -1         dx = (canvas.width - offcanvas.width * zoom) / 2;
  157    -1         dy = (canvas.height - offcanvas.height * zoom) / 2;
   -1   137         zoom = canvas.height / frame.canvas.height * 0.8;
   -1   138         dx = (canvas.width - frame.canvas.width * zoom) / 2;
   -1   139         dy = (canvas.height - frame.canvas.height * zoom) / 2;
  158   140 
  159   141         speed_x = 0;
  160   142         speed_y = 0;
  161   143 
  162    -1         var x, y;
  163    -1         for (y = 0; y < data.height; y++) {
  164    -1             for (x = 0; x < data.width; x++) {
  165    -1                 setPixel(x, y, 0);
  166    -1             }
  167    -1         }
  168    -1 
  169   144         render();
  170   145     });
  171   146 });
@@ -184,7 +159,7 @@ var resizeCanvas = function() {
  184   159 
  185   160 var render = onAnimation(function() {
  186   161     ctx.clearRect(0, 0, canvas.width, canvas.height);
  187    -1     ctx.drawImage(offcanvas, dx, dy, offcanvas.width * zoom, offcanvas.height * zoom);
   -1   162     ctx.drawImage(frame.canvas, dx, dy, frame.canvas.width * zoom, frame.canvas.height * zoom);
  188   163 });
  189   164 
  190   165 var applySpeed = onAnimation(function() {
@@ -223,7 +198,7 @@ var setPencil = function(color) {
  223   198         palette.pencil.value = pencil;
  224   199         palette.querySelector(':checked').parentElement.scrollIntoView();
  225   200     }
  226    -1 }
   -1   201 };
  227   202 
  228   203 window.addEventListener('keydown', event => {
  229   204     // FIXME: kinetic movement;
@@ -248,30 +223,27 @@ window.addEventListener('keydown', event => {
  248   223     render();
  249   224 });
  250   225 
  251    -1 var prev_x = null;
  252    -1 var prev_y = null;
  253    -1 
  254   226 var drawLine = function(x1, y1, x2, y2, color) {
  255   227     var a, x, y;
  256   228     var dx = Math.abs(x1 - x2);
  257   229     var dy = Math.abs(y1 - y2);
  258   230 
  259    -1     if (dx == 0 && dy == 0) {
  260    -1         setPixel(Math.floor(x1), Math.floor(y1), color);
   -1   231     if (dx === 0 && dy === 0) {
   -1   232         frame.setPixel(Math.floor(x1), Math.floor(y1), color);
  261   233     }
  262   234     if (dx > dy) {
  263   235         a = (y1 - y2) / (x1 - x2);
  264   236         for (x = Math.floor(Math.min(x1, x2)) + 1; x <= Math.max(x1, x2); x++) {
  265   237             y = a * (x - x2) + y2;
  266    -1             setPixel(x, y, color);
  267    -1             setPixel(x - 1, y, color);
   -1   238             frame.setPixel(x, y, color);
   -1   239             frame.setPixel(x - 1, y, color);
  268   240         }
  269   241     } else {
  270   242         a = (x1 - x2) / (y1 - y2);
  271   243         for (y = Math.floor(Math.min(y1, y2)) + 1; y <= Math.max(y1, y2); y++) {
  272   244             x = a * (y - y2) + x2;
  273    -1             setPixel(x, y, color);
  274    -1             setPixel(x, y - 1, color);
   -1   245             frame.setPixel(x, y, color);
   -1   246             frame.setPixel(x, y - 1, color);
  275   247         }
  276   248     }
  277   249 };
@@ -284,13 +256,13 @@ var onClick = onAnimation(function(event) {
  284   256         var cx = event.clientX - rect.x;
  285   257         var cy = event.clientY - rect.y;
  286   258 
  287    -1         var ocx = (cx - dx) / zoom / pxsize;
  288    -1         var ocy = (cy - dy) / zoom / pxsize;
   -1   259         var ocx = (cx - dx) / zoom / PXSIZE;
   -1   260         var ocy = (cy - dy) / zoom / PXSIZE;
  289   261 
  290   262         if (last_click) {
  291   263             drawLine(last_click.x, last_click.y, ocx, ocy, pencil);
  292   264         } else {
  293    -1             setPixel(ocx, ocy, pencil);
   -1   265             frame.setPixel(ocx, ocy, pencil);
  294   266         }
  295   267         last_click = {x: ocx, y: ocy};
  296   268