tongong.net

personal website
git clone https://tongong.net/git/tongong.net.git
Log | Files | Refs

main.js (7606B)


      1 const m = require("lib/mithril");
      2 const stream = require("lib/mithril-stream");
      3 const zimg = require("./zoomimg.js");
      4 const custom_file_upload = require("./custom_file.js");
      5 
      6 const example_graydata = require("data/data.js").example_grayscale;
      7 const example_colordata = require("data/data.js").example_color;
      8 
      9 async function base64_to_img(txt) {
     10     return new Promise((res, rej) => {
     11         const img = new Image();
     12         img.src = "data:;base64," + txt;
     13         img.addEventListener("load", () => res(img));
     14     });
     15 }
     16 
     17 const img_color = await base64_to_img(example_colordata);
     18 const img_gray = await base64_to_img(example_graydata);
     19 
     20 // store all update streams in a container to avoid having a pile of local
     21 // variables
     22 const stream_container = {};
     23 // select a stream from the container
     24 const zoom_stream = (st) => {
     25     if (stream_container[st] == undefined)
     26         stream_container[st] = stream();
     27     return stream_container[st];
     28 };
     29 const zoom_stream_list = () => Object.keys(stream_container);
     30 
     31 // list of mithril components to be mounted in their containers
     32 const components = [
     33     {view: (vnode) => m(zimg, {
     34         size: 601,
     35         image: (x, y) => 0,
     36         noise: (x, y, val) => {
     37             let color = 255 * ((x + y) % 2);
     38             return [color, color, color];
     39         },
     40         update: zoom_stream("demo1-checker"),
     41     })},
     42     {view: (vnode) => m(zimg, {
     43         size: 601,
     44         image: (x, y) => {
     45             const square = 0.2 <= x && x < 0.6 && 0.4 <= y && y < 0.8;
     46             const circle = ((x - 0.6) ** 2 + (y - 0.4) ** 2) < 0.2**2;
     47             return (square + circle) % 2; // xor
     48         },
     49         noise: (x, y, val) => {
     50             let color = 255 * ((x + y + val) % 2);
     51             return [color, color, color];
     52         },
     53         update: zoom_stream("demo2-checkerinvert"),
     54     })},
     55     {view: (vnode) => m(zimg, {
     56         size: 600,
     57         image: (x, y) => x >= 0.5,
     58         noise: (x, y, val) => {
     59             let color = val? 128 : Math.random() * 255;
     60             return [color, color, color];
     61         },
     62         update: zoom_stream("demo3-grayrandom"),
     63     })},
     64     {view: (vnode) => m(zimg, {
     65         size: 601,
     66         image: (x, y) => {
     67             return 0.3 <= x && x < 0.7 && 0.3 <= y && y < 0.7;
     68         },
     69         noise: (x, y, val) => {
     70             let color = 128;
     71             if (val) color = (x + y) % 2 * 256;
     72             return [color, color, color];
     73         },
     74         update: zoom_stream("demo4-checkergray"),
     75     })},
     76     {view: (vnode) => m(zimg, {
     77         size: 601,
     78         image: (x, y) => {
     79             return 0.3 <= x && x < 0.7 && 0.3 <= y && y < 0.7;
     80         },
     81         noise: (x, y, val) => {
     82             const RAND = 16;
     83             let color = 128;
     84             if (val) color = RAND + (x + y) % 2 * (256 - RAND * 2);
     85             color = color - RAND + Math.random() * RAND * 2;
     86             return [color, color, color];
     87         },
     88         update: zoom_stream("demo5-checkergrayrandom"),
     89     })},
     90     {view: (vnode) => m(zimg, {
     91         size: 400,
     92         image: (x, y) => {
     93             return 0.3 <= x && x < 0.7 && 0.3 <= y && y < 0.7;
     94         },
     95         noise: (x, y, val) => {
     96             const RAND = 16;
     97             let color = 128;
     98             if (val) color = RAND + (x + y) % 2 * (256 - RAND * 2);
     99             color = color - RAND + Math.random() * RAND * 2;
    100             return [color, color, color];
    101         },
    102         update: zoom_stream("demo5-checkergrayrandom"),
    103     })},
    104     {view: (vnode) => m(zimg, {
    105         size: 601,
    106         image: (x, y) => {
    107             return 0.3 <= x && x < 0.7 && 0.3 <= y && y < 0.7;
    108         },
    109         noise: (x, y, val) => {
    110             const RAND = 64;
    111             let color = 150;
    112             // let color = 181; // = 256 / sqrt(2)
    113             if (val) color = RAND + (x + y + 1) % 2 * (256 - RAND * 2);
    114             color = color - RAND + Math.random() * RAND * 2;
    115             return [color, color, color];
    116         },
    117     })},
    118     {view: (vnode) => m(zimg, {
    119         size: 601,
    120         image: (x, y) => {
    121             return 0.3 <= x && x < 0.7 && 0.3 <= y && y < 0.7;
    122         },
    123         noise: (x, y, val) => {
    124             let color = 128;
    125             const RAND = 80;
    126             let colordiff = Math.random();
    127             if (val) {
    128                 if ((x + y + 1) % 2 == 0)
    129                     colordiff = Math.max(colordiff, Math.random());
    130                 else
    131                     colordiff = Math.min(colordiff, Math.random());
    132             }
    133             color = color - RAND + colordiff * 2 * RAND;
    134             return [color, color, color];
    135         },
    136         update: zoom_stream("demo6-reordering"),
    137     })},
    138     {view: (vnode) => m(zimg, {
    139         size: 601,
    140         // image: (x, y) => {
    141         //     if (x < 0.5) return 0.3 <= x && 0.3 <= y && y < 0.7;
    142         //     return 1 - y;
    143         // },
    144         image: img_gray,
    145         noise: (x, y, val) => {
    146             val = val[0] / 256;
    147             // val: input color; 0 <= val < 1
    148             let color = 128;
    149             const RAND = 100;
    150             // imagine a square. in x direction are the gray levels. in
    151             // y direction are the infinitesimal probabilities. the
    152             // square is cut by a point-symmetric line. the area above
    153             // is for dark pixels on the checkerboard - below is for
    154             // light pixels. if we hit randomly in one of those areas
    155             // we get a color with the correct probabilities
    156             let xp = Math.random();
    157             let yp = Math.random();
    158             // the dividing line is linear (this was chosen to ease
    159             // computation but it may be a bad choice)
    160             // it can be described by the function:
    161             // -> f(x) = (1-2*val) * x + val
    162             // for val = 0.5: f(x) = 0.5
    163             // for val = 0:   f(x) = x
    164             // for val = 1:   f(x) = 1 - x
    165             // if we hit in the wrong area mirror at the central point
    166             // != for xor
    167             if ((x + y + 1) % 2 == 0 != yp < (1-2*val)*xp+val) {
    168                 xp = 1 - xp;
    169                 // yp = 1 - yp;
    170             }
    171             color = color - RAND + xp * 2 * RAND;
    172             return [color, color, color];
    173         },
    174         update: zoom_stream("demo7-reordering-grayscale"),
    175     })},
    176     {view: (vnode) => m(custom_file_upload, {color: false})},
    177     {view: (vnode) => m(zimg, {
    178         size: 601,
    179         image: img_color,
    180         noise: (x, y, val) => {
    181             return val.map(valc => {
    182                 valc = valc / 256;
    183                 let color = 128;
    184                 const RAND = 100;
    185                 let xp = Math.random();
    186                 let yp = Math.random();
    187                 if ((x + y + 1) % 2 == 0 != yp < (1-2*valc)*xp+valc) {
    188                     xp = 1 - xp;
    189                 }
    190                 return color - RAND + xp * 2 * RAND;
    191             });
    192         },
    193         update: zoom_stream("demo8-color"),
    194     })},
    195     {view: (vnode) => m(custom_file_upload, {color: true})},
    196 ];
    197 
    198 Array.from(document.querySelectorAll("div.js-container")).forEach((c, i) => {
    199     m.mount(c, components[i]);
    200 });
    201 
    202 // link the links (connect <a> tags and interactive frames)
    203 zoom_stream_list().forEach(st => {
    204     Array.from(document.querySelectorAll("." + st)).forEach(a => {
    205         // if (!a.innerHTML.endsWith("x")) console.error("broken link text");
    206         const zoomlevel = parseFloat(a.innerHTML.slice(0, -1));
    207         a.onclick = () => {
    208             zoom_stream(st)(zoomlevel);
    209             // manual redraw is neccessary for handlers defined outside of
    210             // mithril
    211             m.redraw();
    212         };
    213     });
    214 });