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
ece7fb8f35c7a821aba30ac1d76c4786d6e72ddf
parent
d66c204a8a78b8791a93d156e7fd9ed46550dbd9
Author
Tobias Bengfort <tobias.bengfort@posteo.de>
Date
2023-02-12 17:34
interpolate draing on fast movements

Diffstat

M paint.js 116 +++++++++++++++++++++++++++++++++++++++++--------------------

1 files changed, 78 insertions, 38 deletions


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

@@ -10,9 +10,35 @@ var data;
   10    10 var pencil = 0;
   11    11 
   12    12 var zoom = 1;
   -1    13 var pxsize = 15;
   13    14 var dx = 0;
   14    15 var dy = 0;
   15    16 
   -1    17 var round = function(c) {
   -1    18     return Math.floor(c / 51) * 3;
   -1    19 };
   -1    20 
   -1    21 var makecolor = function(a) {
   -1    22     return '#'
   -1    23         + round(a[0]).toString(16)
   -1    24         + round(a[1]).toString(16)
   -1    25         + round(a[2]).toString(16);
   -1    26 };
   -1    27 
   -1    28 var sRGB = function(c) {
   -1    29     var x = round(c) / 15;
   -1    30     if (x < 0.04045) {
   -1    31         return x / 12.92;
   -1    32     } else {
   -1    33         return Math.pow((x + 0.055) / 1.055, 2.4);
   -1    34     }
   -1    35 };
   -1    36 
   -1    37 var makeContrast = function(a) {
   -1    38     var l = 0.2126 * sRGB(a[0]) + 0.7152 * sRGB(a[1]) + 0.0722 * sRGB(a[2]);
   -1    39     return l > 0.18 ? '#000' : '#fff';
   -1    40 }
   -1    41 
   16    42 var onAnimation = function(fn) {
   17    43     var called = false;
   18    44     return () => {
@@ -53,31 +79,6 @@ var img2data = function(img, scale) {
   53    79     return _ctx.getImageData(0, 0, _canvas.width, _canvas.height);
   54    80 };
   55    81 
   56    -1 var round = function(c) {
   57    -1     return Math.floor(c / 51) * 3;
   58    -1 };
   59    -1 
   60    -1 var makecolor = function(a) {
   61    -1     return '#'
   62    -1         + round(a[0]).toString(16)
   63    -1         + round(a[1]).toString(16)
   64    -1         + round(a[2]).toString(16);
   65    -1 };
   66    -1 
   67    -1 var sRGB = function(c) {
   68    -1     var x = round(c) / 15;
   69    -1     if (x < 0.04045) {
   70    -1         return x / 12.92;
   71    -1     } else {
   72    -1         return Math.pow((x + 0.055) / 1.055, 2.4);
   73    -1     }
   74    -1 };
   75    -1 
   76    -1 var makeContrast = function(a) {
   77    -1     var l = 0.2126 * sRGB(a[0]) + 0.7152 * sRGB(a[1]) + 0.0722 * sRGB(a[2]);
   78    -1     return l > 0.18 ? '#000' : '#fff';
   79    -1 }
   80    -1 
   81    82 var analyze = function(img) {
   82    83     var c, i, j;
   83    84     var colors = ['white'];
@@ -102,22 +103,28 @@ var analyze = function(img) {
  102   103     };
  103   104 };
  104   105 
  105    -1 var setPixel = function(x, y, color) {
   -1   106 var _setPixel = function(x, y, color) {
  106   107     var i = y * data.width + x;
  107   108     octx.fillStyle = data.colors[color];
  108    -1     octx.fillRect(x * 10, y * 10, 10, 10);
   -1   109     octx.fillRect(x * pxsize, y * pxsize, pxsize, pxsize);
  109   110     if (color !== data.data[i]) {
  110   111         octx.fillStyle = data.contrasts[color];
  111    -1         octx.fillText(data.data[i], x * 10 + 5, y * 10 + 5);
   -1   112         octx.fillText(data.data[i], (x + 0.5) * pxsize, (y + 0.5) * pxsize);
  112   113     }
  113   114 };
  114   115 
   -1   116 var setPixel = function(x, y, color) {
   -1   117     if (x >= 0 && x < data.width && y >= 0 && y < data.height) {
   -1   118         _setPixel(Math.floor(x), Math.floor(y), color);
   -1   119     }
   -1   120 }
   -1   121 
  115   122 input.addEventListener('change', () => {
  116   123     file2img(input.files[0]).then(img => {
  117   124         // FIXME: configurable size
  118   125         data = analyze(img2data(img, 100 / img.width));
  119    -1         offcanvas.width = data.width * 10;
  120    -1         offcanvas.height = data.height * 10;
   -1   126         offcanvas.width = data.width * pxsize;
   -1   127         offcanvas.height = data.height * pxsize;
  121   128         octx.textAlign = 'center';
  122   129         octx.textBaseline = 'middle';
  123   130 
@@ -193,22 +200,55 @@ window.addEventListener('keydown', event => {
  193   200     render();
  194   201 });
  195   202 
   -1   203 var prev_x = null;
   -1   204 var prev_y = null;
   -1   205 
   -1   206 var drawLine = function(x1, y1, x2, y2, color) {
   -1   207     var a, x, y;
   -1   208     var dx = Math.abs(x1 - x2);
   -1   209     var dy = Math.abs(y1 - y2);
   -1   210 
   -1   211     if (dx == 0 && dy == 0) {
   -1   212         setPixel(Math.floor(x1), Math.floor(y1), color);
   -1   213     }
   -1   214     if (dx > dy) {
   -1   215         a = (y1 - y2) / (x1 - x2);
   -1   216         for (x = Math.floor(Math.min(x1, x2)) + 1; x <= Math.max(x1, x2); x++) {
   -1   217             y = a * (x - x2) + y2;
   -1   218             setPixel(x, y, color);
   -1   219             setPixel(x - 1, y, color);
   -1   220         }
   -1   221     } else {
   -1   222         a = (x1 - x2) / (y1 - y2);
   -1   223         for (y = Math.floor(Math.min(y1, y2)) + 1; y <= Math.max(y1, y2); y++) {
   -1   224             x = a * (y - y2) + x2;
   -1   225             setPixel(x, y, color);
   -1   226             setPixel(x, y - 1, color);
   -1   227         }
   -1   228     }
   -1   229 };
   -1   230 
   -1   231 var last_click = null;
   -1   232 
  196   233 var onClick = function(event) {
  197   234     if (event.buttons & 1) {
  198   235         var rect = canvas.getBoundingClientRect();
  199   236         var cx = event.clientX - rect.x;
  200   237         var cy = event.clientY - rect.y;
  201   238 
  202    -1         var ocx = (cx - dx) / zoom;
  203    -1         var ocy = (cy - dy) / zoom;
   -1   239         var ocx = (cx - dx) / zoom / pxsize;
   -1   240         var ocy = (cy - dy) / zoom / pxsize;
  204   241 
  205    -1         var x = Math.floor(ocx / 10);
  206    -1         var y = Math.floor(ocy / 10);
  207    -1 
  208    -1         if (x >= 0 && x < data.width && y >= 0 && y < data.height) {
  209    -1             setPixel(x, y, pencil);
  210    -1             render();
   -1   242         if (last_click) {
   -1   243             drawLine(last_click.x, last_click.y, ocx, ocy, pencil);
   -1   244         } else {
   -1   245             setPixel(ocx, ocy, pencil);
  211   246         }
   -1   247         last_click = {x: ocx, y: ocy};
   -1   248 
   -1   249         render();
   -1   250     } else {
   -1   251         last_click = null;
  212   252     }
  213   253 };
  214   254