)
}
}
)
(
}
{
)
)
(
)
(
(
{
}
)
(
)
}
)
)
{
(
(
)
)
}
)
(
}

Cistercian Numerals (semi-golfed)

  1. N = -1
  2. S = 30
  3. H = 90
  4. h = 45
  5. d = document
  6. b = d.body
  7. m = _ => d.createElement(_)
  8. a = _ => b.appendChild(_)
  9.  
  10. with(a(
  11.     Object.assign(
  12.       m`canvas`,
  13.       { width: 80, height: 120 }
  14.     )
  15.   ).getContext`2d`
  16. ) { 
  17.   a(m`br`)
  18.  
  19.   L = (a, b, C, d) => {
  20.     moveTo(a, b)
  21.     lineTo(C, d)
  22.   }
  23.  
  24.   M = _ => L(0, 0, 0, H)
  25.   O = _ => L(0, 0, S, 0)
  26.   W = _ => L(0, S, S, S)
  27.   T = _ => L(0, 0, S, S)
  28.   F = _ => L(0, S, S, 0)
  29.   X = _ => L(S, 0, S, S)
  30.  
  31.   D = [
  32.     _ => {},
  33.     O, W, T, F, 
  34.     [O,F],
  35.     X,
  36.     [O,X],
  37.     [W,X],
  38.     [O,W,X]
  39.   ]
  40.  
  41.   n = s => {
  42.     [...s].reverse().map((l, i) => {
  43.       save()
  44.       translate(S+9, h+9)
  45.       scale(N**i, N**~~(i/2))
  46.       translate(0, -h)
  47.       M() ;[D[l]].flat().map(x => x && x())
  48.       restore()
  49.     })
  50.   }
  51.  
  52.   a(m`input`).oninput = e => {
  53.     clearRect(0, 0, 80, 120)
  54.     beginPath()
  55.     n(~~e.target.value+'')
  56.     stroke()
  57.   }
  58. }

Type any number from 0-9999 into the input field and see the corresponding Cistercian Numeral. This snippet is partially golfed, I left the canvas commands intact to make things a bit easier to understand.

Simpler SVG Version

This one hardcodes all numbers 0-9 as paths, unlike the canvas version which only defines 1,2,3,4 and 6 as paths and then combines them to create 5,7,8 and 9.

  1. h='innerHTML'
  2. C='children'
  3.  
  4. document.body[h]=`
  5. <svg id=G width=99 viewBox="0 0 80 120" 
  6.   style="stroke:black;fill:none;overflow:visible">
  7.   <g transform="translate(30,2)">
  8.     <path d="M0 0L 30 0"/>
  9.     <path d="M0 30L 30 30"/>
  10.     <path d="M0 0L 30 30"/>
  11.     <path d="M0 30L30 0"/>
  12.     <path d="M0 30L30 0 0 0"/>
  13.     <path d="M30 0L30 30"/>
  14.     <path d="M30 30L30 0 0 0"/>
  15.     <path d="M0 30L30 30 30 0"/>
  16.     <path d="M0 30L30 30 30 0 0 0"/>
  17.   </g>
  18.   <g transform=translate(30,2)scale(-1,1)></g>
  19.   <g transform=translate(30,92)scale(1,-1)></g>
  20.   <g transform=translate(30,92)scale(-1,-1)></g>
  21.   <path id=m d="M 30 2 L 30 92"/>
  22. </svg>
  23. <style>path:not(#m){opacity:0}</style><br>
  24. <input id=I>`
  25.  
  26. c=G[C]
  27. p=c[0][h] 
  28.  
  29. n = s => 
  30.   [...s].reverse().map((l, i) => 
  31.    l-1>-1 && (c[i][C][l-1].style.opacity=1))
  32.  
  33. I.oninput = e => {
  34.   for(i=0;i<4;i++)c[i][h]=p
  35.   n(~~e.target.value+'')
  36. }

Array Based Collision Cells

  1. ((
  2.   d = document,
  3.   b = d.body,
  4.   canvas = b.appendChild(
  5.     d.createElement('canvas')
  6.   ),
  7.   c = canvas.getContext('2d'),
  8.   r = _ => Math.random(),
  9.   map = [
  10.     [0, 0, 0, 0, 0, 2],
  11.     [1, 1, 0, 0, 0, 1],
  12.     [1, 1, 2, 0, 0, 0],
  13.     [2, 2, 0, 0, 0, 1],
  14.     [0, 1, 0, 0, 2, 0],
  15.     [2, 0, 0, 0, 2, 1],
  16.   ],
  17.   mapW = map[0].length,
  18.   mapH = map.length,
  19.   cols = [, 'red', 'black'],
  20.   cell = (
  21.     x, y, idx,
  22.     col = cols[idx],
  23.     size = 30,
  24.     xp = x * size,
  25.     yp = y * size,
  26.     dir, 
  27.     mv = f => {
  28.       map[y][x] = 0
  29.       f()
  30.       map[y][x] = idx
  31.     }
  32.   ) => (move) => {
  33.     if (move) {
  34.       dir = ~~(r() * 4)
  35.       if (dir == 0 &&
  36.         x != 0 &&
  37.         map[y][x - 1] == 0) {
  38.         mv(_ => x--)
  39.       } else if (dir == 1 &&
  40.         x != mapW - 1 &&
  41.         map[y][x + 1] == 0) {
  42.         mv(_ => x++)
  43.       } else if (dir == 2 &&
  44.         y != 0 &&
  45.         map[y - 1][x] == 0) {
  46.         mv(_ => y--)
  47.       } else if (dir == 3 &&
  48.         y != mapH - 1 &&
  49.         map[y + 1][x] == 0
  50.       ) {
  51.         mv(_ => y++)
  52.       }
  53.     }
  54.  
  55.     xp += (x * size - xp) / 4
  56.     yp += (y * size - yp) / 4
  57.     c.fillStyle = col
  58.     c.fillRect(xp, yp, size, size)
  59.     c.strokeStyle = 'gray'
  60.     c.strokeRect(xp, yp, size, size)
  61.   },
  62.   cells = [],
  63.   w, h, idx, val, i, j,
  64.   draw = () => {
  65.     c.fillStyle = 'gray'
  66.     c.fillRect(0, 0, w, h)
  67.  
  68.     idx = ~~(r() * mapH * mapW)
  69.  
  70.     cells.forEach((cell, i) =>
  71.       cell(idx == i && r() < .3))
  72.   }
  73. ) => {
  74.   b.style.margin = 0
  75.  
  76.   onresize = () => {
  77.     w = canvas.width = innerWidth
  78.     h = canvas.height = innerHeight
  79.     draw()
  80.   }
  81.   onresize()
  82.  
  83.   for (i = 0; i < mapH; i++) {
  84.     for (j = 0; j < mapW; j++) {
  85.       val = map[i][j]
  86.       if (val != 0) cells.push(cell(j, i, val)) 
  87.     }
  88.   }
  89.  
  90.   setInterval(draw, 16)
  91. })()

Array based avoid. I was about to port an old thing that was similar to this and then thought it would be more fun to speedcode it instead. The result is a slightly golfed version of this old thing.

Wiggly Line Canvas

  1. const canvas = document.body.appendChild(
  2.   document.createElement('canvas')
  3. );
  4. const c = canvas.getContext('2d');
  5. document.body.style.margin = 0;
  6.  
  7. function resize() {
  8.   canvas.width = innerWidth;
  9.   canvas.height = innerHeight;
  10. }
  11. addEventListener('resize', resize);
  12. resize();
  13.  
  14. const PAD = 50;
  15. const RAD = 2;
  16. const SPEED = 20;
  17. const TWO_PI = Math.PI * 2;
  18.  
  19. let mode = 'draw';
  20.  
  21. let t = Math.random() * TWO_PI, 
  22.     x = innerWidth / 2, 
  23.     y = innerHeight / 2,
  24.     vx = 0, vy = 0, ta = 0;
  25.  
  26. function loop() {
  27.   for (var i = 0; i < SPEED; i++) {
  28.     t = Math.sin(ta) * TWO_PI;
  29.     vx = RAD * Math.cos(t);
  30.     vy = RAD * Math.sin(t);
  31.     ta += Math.random() * 0.1 - 0.05;
  32.     x += vx;
  33.     y += vy;
  34.  
  35.     if (Math.random() < 0.005) {
  36.       mode = 'no draw';
  37.     } else if (Math.random() < 0.005) {
  38.       mode = 'draw';
  39.     }
  40.  
  41.     if (mode === 'draw') {
  42.       c.fillStyle = 'red';
  43.       c.fillRect(x, y, 2, 2);
  44.     }
  45.  
  46.     if (x < -PAD) {
  47.       x = innerWidth + PAD;
  48.     } else if (x > innerWidth + PAD) {
  49.       x = -PAD;
  50.     }
  51.     if (y < -PAD) {
  52.       y = innerHeight + PAD;
  53.     } else if (y > innerHeight + PAD) {
  54.       y = -PAD;
  55.     }
  56.   }
  57.  
  58.   requestAnimationFrame(loop);
  59. }
  60. loop();

Recently saw this in some very old code – cool trick for moving things in a wiggly way – or in this case, drawing a wiggly line.

Canvas ImageData

  1. const canvas = document.body.appendChild(
  2.   document.createElement('canvas')
  3. );
  4. const width = 200;
  5. canvas.width = canvas.height = width;
  6.  
  7. const c = canvas.getContext('2d');
  8. const pixels = c.createImageData(canvas.width, canvas.height);
  9. const size = canvas.width * canvas.height;
  10.  
  11. let index = 0, x, y;
  12.  
  13. for (var i = 0; i < size; i++){
  14.   x = i % width;
  15.   y = Math.floor(i / width);
  16.  
  17.   pixels.data[index++] = x;
  18.   pixels.data[index++] = y;
  19.   pixels.data[index++] = width - x;
  20.   pixels.data[index++] = 255;
  21. }
  22. c.putImageData(pixels, 0, 0);

This shows how to set pixel data on an html5 canvas.

// canvas // color // graphics // hex // javascript // math

isPointInPath Canvas

  1. const canvas = document.createElement('canvas');
  2. const c = canvas.getContext('2d');
  3. let mouseX = 0, mouseY = 0;
  4.  
  5. canvas.width = 400;
  6. canvas.height = 400;
  7. document.body.appendChild(canvas);
  8. document.body.style.margin = 0;
  9.  
  10. c.fillStyle = 'black';
  11. c.fillRect(0, 0, canvas.width, canvas.height);
  12.  
  13. document.addEventListener('mousemove', e => {
  14.   mouseX = e.clientX;
  15.   mouseY = e.clientY;
  16. });
  17.  
  18. // no scroll on mobile: 
  19. document.addEventListener('touchmove', 
  20.   e => e.preventDefault(), { passive: false });
  21.  
  22. document.addEventListener('touchmove', e => {
  23.   mouseX = e.touches[0].clientX;
  24.   mouseY = e.touches[0].clientY;
  25. });
  26.  
  27. const loop = () => {
  28.   c.fillStyle = 'black';
  29.   c.fillRect(0, 0, canvas.width, canvas.height); 	
  30.   c.lineWidth = 3;
  31.   c.strokeStyle = 'blue';
  32.   c.beginPath();
  33.   c.moveTo(20, 20);
  34.   c.lineTo(110, 20);
  35.   c.lineTo(110, 110);
  36.   c.lineTo(20, 110);
  37.   c.closePath();
  38.  
  39.   if (c.isPointInPath(mouseX, mouseY)) {
  40.     c.strokeStyle = 'white';
  41.     c.fillStyle = 'red';
  42.     c.fill();
  43.   }
  44.   c.stroke();
  45.  
  46.   requestAnimationFrame(loop);
  47. };
  48.  
  49. loop();

See if a point is with a path inside canvas. Take a look at MDN for more info.

snippet.zone ~ 2021-24 /// {s/z}