Complementary HSL
copy const a = document.body .appendChild ( document.createElement ( 'div' ) ) , b = document.body .appendChild ( document.createElement ( 'div' ) ) ; let degA = degB = 0 ; const size = { width: '100px' , height: '100px' } ; Object .assign ( a.style , size) ; Object .assign ( b.style , size) ; function loop( ) { degA += 1 ; degB = degA + 180 ; a.style .background = `hsl( ${ degA} deg, 100 %, 50 % ) `; b.style .background = `hsl( ${ degB} deg, 100 %, 50 % ) `; requestAnimationFrame( loop) ; } loop( ) ;
Try it out…
In HSL a hue difference of 180 degrees between two values will create a set of complimentary colors.
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.
ClassName Behaviors
copy const ui = document.body .appendChild ( document.createElement ( 'div' ) ) ; ui.innerHTML = ` < button class= "blue circle redBorder moveDown" > click</ button> < button class= "red circle sayHi" > click</ button> < button class= "green circle noBorder moveDown sayHi randomBgColor" > click</ button> < style> * { - webkit- user- select: none; user- select: none; } body, html { width: 100 %; height: 100 %; } button { position: relative; top: 0 ; margin: .5em; cursor: pointer; color: white; transition: all 200ms ease- out; text- shadow: 1px 2px 1px black; } .circle { width: 50px; height: 50px; border- radius: 500px; } .blue { background: #275ba1; } .red { background: red; } .green { background: green; } .redBorder { border: 2px solid red; } .noBorder { border: none; } </ style> `; const actions = { moveDown( e) { e.target .style .top = `${ parseFloat( e.target .style .top || 0 ) + 30 } px`; } , sayHi( e) { e.target .innerHTML = [ 'hi' , 'hello' , 'hey' , 'aloha' , 'what\' s up' ] [ Math .floor ( Math .random ( ) * 5 ) ] ; e.target .style .transform = ` rotate( ${ Math .random ( ) * 40 - 20 } deg) scale( ${ Math .random ( ) * .3 + 1 } ) ` } , randomBgColor( e) { const col = `hsl( ${ Math .random ( ) * 360 } deg, 50 %, 50 % ) ` e.target .style .background = col; } } ; document.body .addEventListener ( 'click' , e => { // combine as many actions as we want [ ...e .target .classList ] .forEach ( cls => { const action = actions[ cls] ; if ( action != null ) action( e) ; } ) ; } ) ;
Try it out…
This snippet takes the ideas from yesterdays post and goes one level further. This associates behavior with class names, so the class names can be combined to mix and match behavior.
In this case, combining classes like this green circle noBorder moveDown sayHi randomBgColor
will cause the element in question to “move down”, “say hi” and randomize its background color when it is clicked. Click the “Try it out” to get a better idea.
Creative Coding Auto-Painting
copy Object .getOwnPropertyNames ( Math ) .map ( i => ( this [ i] = Math [ i] ) ) ; ( ( width = innerWidth * 2 , height = innerHeight * 2 , cnv = document.body .appendChild ( Object .assign ( document.createElement ( 'canvas' ) , { width, height } ) ) , c = cnv.getContext ( '2d' ) , r = ( n = 1 ) => Math .random ( ) * n, NUM = 50 , f = ( ) => ( { ax: r( width) , ay: r( height) , x: 0 , y: 0 , T: r( 9 ) , R: r( innerWidth * 0.8 ) + 40 , t: r( 6 ) , C: round( r( 255 ) ) , m: r( 5 ) + 1 } ) , cs, sn, dx, dy, ns = [ ...Array ( NUM) ] .map ( f) ) => { Object .assign ( cnv.style , { transformOrigin: '0 0' , transform: 'scale(.5)' } ) Object .assign ( document.body .style , { margin: 0 , padding: 0 } ) const clear = ( ) => { c.fillStyle = '#666668' c.fillRect ( 0 , 0 , width, height) c.globalAlpha = 0.5 } onresize = ( ) => { width = cnv.width = innerWidth * 2 height = cnv.height = innerHeight * 2 clear( ) } clear( ) setInterval( ( ) => { for ( i = 0 ; i < 30 ; i++ ) { ns.map ( ( n, i) => { with ( n) { x = ax + R * cos( t) y = ay + R * sin( t) * pow( sin( t * 0.5 ) , m) c.fillStyle = `rgba( ${ C} , ${ C} , ${ C} , .02) ` ; ( cs = cos( T) ) , ( sn = sin( T) ) , ( dx = x - ax) , ( dy = y - ay) c.fillRect ( cs * dx - sn * dy + ax, sn * dx + cs * dy + ay, 50 , 50 ) t += 0.1 R -= 0.01 if ( R < 5 ) ns[ i] = f( ) } } ) } } , 16 ) } ) ( )
Try it out…
Speed coded semi-golfed canvas texture. Best if viewed in fullscreen.
Quick Touch Events 2 (easing)
copy // no scrolling on mobile document.addEventListener ( 'touchmove' , e => e.preventDefault ( ) , { passive: false } ) ; const hasTouch = navigator.maxTouchPoints != null && navigator.maxTouchPoints > 0 ; // looking forward to `navigator?.maxTouchPoints > 0` // being better supported function touchify( e) { const touch = [ ] ; touch.x = touch.y = 0 ; if ( e.touches != null && e.touches .length > 0 ) { touch.x = e.touches [ 0 ] .clientX ; touch.y = e.touches [ 0 ] .clientY ; for ( let i = 0 ; i < e.touches .length ; i++ ) { touch[ i] = e.touches [ i] ; } } else { touch.x = e.clientX ; touch.y = e.clientY ; touch[ 0 ] = { clientX: e.clientX , clientY: e.clientY } ; } return touch; } let moveOrTouchMove; if ( hasTouch) { moveOrTouchMove = 'touchmove' ; } else { moveOrTouchMove = 'mousemove' ; } function dot( x, y, radius, color) { const el = document.createElement ( 'div' ) ; const size = `${ radius * 2 } px`; Object .assign ( el.style , { position: 'absolute' , left: `${ x} px`, top: `${ y} px`, width: size, height: size, transform: `translate( ${ - radius} px, ${ - radius} px) `, borderRadius: '50%' , background: color } ) ; el.classList .add ( 'dot' ) ; document.body .appendChild ( el) ; return el; } let dotX = 100 , dotY = 100 , touchX = 200 , touchY = 150 , damp = 12 , dotEl = dot( dotX, dotY, 20 , 'red' ) ; document.addEventListener ( moveOrTouchMove, e => { const { x, y } = touchify( e) ; touchX = x; touchY = y; } ) ; function loop( ) { dotX += ( touchX - dotX) / damp; dotY += ( touchY - dotY) / damp; Object .assign ( dotEl.style , { left: `${ dotX} px`, top: `${ dotY} px` } ) ; window.requestAnimationFrame ( loop) ; } loop( ) ;
Try it out…
Move your mouse on desktop or your finger on mobile – watch the red dot follow…
This is a simpler version of some of the things used in yesterdays post – just a quick way to normalize touch events – just one of many ways to do this – for simple stuff this is my goto
.
If you want to try it out on its own page – take a look here (specifically good for trying it on mobile).
You’ll probably want a to use a meta tag like this – for the full effect.
copy < meta name= "viewport" content= "width=device-width, initial-scale=1.0" >