Cistercian Numerals (semi-golfed)
copy N = - 1 S = 30 H = 90 h = 45 d = document b = d.body m = _ => d.createElement ( _) a = _ => b.appendChild ( _) with( a( Object .assign ( m`canvas`, { width: 80 , height: 120 } ) ) .getContext `2d` ) { a( m`br`) L = ( a, b, C, d) => { moveTo( a, b) lineTo( C, d) } M = _ => L( 0 , 0 , 0 , H) O = _ => L( 0 , 0 , S, 0 ) W = _ => L( 0 , S, S, S) T = _ => L( 0 , 0 , S, S) F = _ => L( 0 , S, S, 0 ) X = _ => L( S, 0 , S, S) D = [ _ => { } , O, W, T, F, [ O, F] , X, [ O, X] , [ W, X] , [ O, W, X] ] n = s => { [ ...s ] .reverse ( ) .map ( ( l, i) => { save( ) translate( S+ 9 , h+ 9 ) scale( N** i, N** ~~( i/ 2 ) ) translate( 0 , - h) M( ) ; [ D[ l] ] .flat ( ) .map ( x => x && x( ) ) restore( ) } ) } a( m`input`) .oninput = e => { clearRect( 0 , 0 , 80 , 120 ) beginPath( ) n( ~~e.target .value + '' ) stroke( ) } }
Try it out…
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.
copy h= 'innerHTML' C= 'children' document.body [ h] = ` < svg id= G width= 99 viewBox= "0 0 80 120" style= "stroke:black;fill:none;overflow:visible" > < g transform= "translate(30,2)" > < path d= "M0 0L 30 0" /> < path d= "M0 30L 30 30" /> < path d= "M0 0L 30 30" /> < path d= "M0 30L30 0" /> < path d= "M0 30L30 0 0 0" /> < path d= "M30 0L30 30" /> < path d= "M30 30L30 0 0 0" /> < path d= "M0 30L30 30 30 0" /> < path d= "M0 30L30 30 30 0 0 0" /> </ g> < g transform= translate( 30 , 2 ) scale( - 1 , 1 ) ></ g> < g transform= translate( 30 , 92 ) scale( 1 ,- 1 ) ></ g> < g transform= translate( 30 , 92 ) scale( - 1 ,- 1 ) ></ g> < path id= m d= "M 30 2 L 30 92" /> </ svg> < style> path: not( #m) { opacity: 0 } </ style>< br> < input id= I> ` c= G[ C] p= c[ 0 ] [ h] n = s => [ ...s ] .reverse ( ) .map ( ( l, i) => l- 1 >- 1 && ( c[ i] [ C] [ l- 1 ] .style .opacity = 1 ) ) I.oninput = e => { for ( i= 0 ; i< 4 ; i++ ) c[ i] [ h] = p n( ~~e.target .value + '' ) }
Try it out…
Array Based Collision Cells
copy ( ( d = document, b = d.body , canvas = b.appendChild ( d.createElement ( 'canvas' ) ) , c = canvas.getContext ( '2d' ) , r = _ => Math .random ( ) , map = [ [ 0 , 0 , 0 , 0 , 0 , 2 ] , [ 1 , 1 , 0 , 0 , 0 , 1 ] , [ 1 , 1 , 2 , 0 , 0 , 0 ] , [ 2 , 2 , 0 , 0 , 0 , 1 ] , [ 0 , 1 , 0 , 0 , 2 , 0 ] , [ 2 , 0 , 0 , 0 , 2 , 1 ] , ] , mapW = map[ 0 ] .length , mapH = map.length , cols = [ , 'red' , 'black' ] , cell = ( x, y, idx, col = cols[ idx] , size = 30 , xp = x * size, yp = y * size, dir, mv = f => { map[ y] [ x] = 0 f( ) map[ y] [ x] = idx } ) => ( move) => { if ( move) { dir = ~~( r( ) * 4 ) if ( dir == 0 && x != 0 && map[ y] [ x - 1 ] == 0 ) { mv( _ => x-- ) } else if ( dir == 1 && x != mapW - 1 && map[ y] [ x + 1 ] == 0 ) { mv( _ => x++ ) } else if ( dir == 2 && y != 0 && map[ y - 1 ] [ x] == 0 ) { mv( _ => y-- ) } else if ( dir == 3 && y != mapH - 1 && map[ y + 1 ] [ x] == 0 ) { mv( _ => y++ ) } } xp += ( x * size - xp) / 4 yp += ( y * size - yp) / 4 c.fillStyle = col c.fillRect ( xp, yp, size, size) c.strokeStyle = 'gray' c.strokeRect ( xp, yp, size, size) } , cells = [ ] , w, h, idx, val, i, j, draw = ( ) => { c.fillStyle = 'gray' c.fillRect ( 0 , 0 , w, h) idx = ~~( r( ) * mapH * mapW) cells.forEach ( ( cell, i) => cell( idx == i && r( ) < .3) ) } ) => { b.style .margin = 0 onresize = ( ) => { w = canvas.width = innerWidth h = canvas.height = innerHeight draw( ) } onresize( ) for ( i = 0 ; i < mapH; i++ ) { for ( j = 0 ; j < mapW; j++ ) { val = map[ i] [ j] if ( val != 0 ) cells.push ( cell( j, i, val) ) } } setInterval( draw, 16 ) } ) ( )
Try it out…
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
copy const canvas = document.body .appendChild ( document.createElement ( 'canvas' ) ) ; const c = canvas.getContext ( '2d' ) ; document.body .style .margin = 0 ; function resize( ) { canvas.width = innerWidth; canvas.height = innerHeight; } addEventListener( 'resize' , resize) ; resize( ) ; const PAD = 50 ; const RAD = 2 ; const SPEED = 20 ; const TWO_PI = Math .PI * 2 ; let mode = 'draw' ; let t = Math .random ( ) * TWO_PI, x = innerWidth / 2 , y = innerHeight / 2 , vx = 0 , vy = 0 , ta = 0 ; function loop( ) { for ( var i = 0 ; i < SPEED; i++ ) { t = Math .sin ( ta) * TWO_PI; vx = RAD * Math .cos ( t) ; vy = RAD * Math .sin ( t) ; ta += Math .random ( ) * 0.1 - 0.05 ; x += vx; y += vy; if ( Math .random ( ) < 0.005 ) { mode = 'no draw' ; } else if ( Math .random ( ) < 0.005 ) { mode = 'draw' ; } if ( mode === 'draw' ) { c.fillStyle = 'red' ; c.fillRect ( x, y, 2 , 2 ) ; } if ( x < - PAD) { x = innerWidth + PAD; } else if ( x > innerWidth + PAD) { x = - PAD; } if ( y < - PAD) { y = innerHeight + PAD; } else if ( y > innerHeight + PAD) { y = - PAD; } } requestAnimationFrame( loop) ; } loop( ) ;
Try it out…
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
copy const canvas = document.body .appendChild ( document.createElement ( 'canvas' ) ) ; const width = 200 ; canvas.width = canvas.height = width; const c = canvas.getContext ( '2d' ) ; const pixels = c.createImageData ( canvas.width , canvas.height ) ; const size = canvas.width * canvas.height ; let index = 0 , x, y; for ( var i = 0 ; i < size; i++ ) { x = i % width; y = Math .floor ( i / width) ; pixels.data [ index++ ] = x; pixels.data [ index++ ] = y; pixels.data [ index++ ] = width - x; pixels.data [ index++ ] = 255 ; } c.putImageData ( pixels, 0 , 0 ) ;
Try it out…
This shows how to set pixel data on an html5 canvas.
isPointInPath Canvas
copy const canvas = document.createElement ( 'canvas' ) ; const c = canvas.getContext ( '2d' ) ; let mouseX = 0 , mouseY = 0 ; canvas.width = 400 ; canvas.height = 400 ; document.body .appendChild ( canvas) ; document.body .style .margin = 0 ; c.fillStyle = 'black' ; c.fillRect ( 0 , 0 , canvas.width , canvas.height ) ; document.addEventListener ( 'mousemove' , e => { mouseX = e.clientX ; mouseY = e.clientY ; } ) ; // no scroll on mobile: document.addEventListener ( 'touchmove' , e => e.preventDefault ( ) , { passive: false } ) ; document.addEventListener ( 'touchmove' , e => { mouseX = e.touches [ 0 ] .clientX ; mouseY = e.touches [ 0 ] .clientY ; } ) ; const loop = ( ) => { c.fillStyle = 'black' ; c.fillRect ( 0 , 0 , canvas.width , canvas.height ) ; c.lineWidth = 3 ; c.strokeStyle = 'blue' ; c.beginPath ( ) ; c.moveTo ( 20 , 20 ) ; c.lineTo ( 110 , 20 ) ; c.lineTo ( 110 , 110 ) ; c.lineTo ( 20 , 110 ) ; c.closePath ( ) ; if ( c.isPointInPath ( mouseX, mouseY) ) { c.strokeStyle = 'white' ; c.fillStyle = 'red' ; c.fill ( ) ; } c.stroke ( ) ; requestAnimationFrame( loop) ; } ; loop( ) ;
Try it out…
See if a point is with a path inside canvas. Take a look at MDN for more info.