Bad/Simple UI Counter
copy < script> count = 0 </ script> < div> < p> You clicked < span id= "countEl" > 0 </ span> times</ p> < button onclick= "countEl.innerHTML = ++count" > Click me</ button> </ div>
Try it out….
This kind of thing is often showcased on UI Framework demo pages. I thought it would be interesting to create it in the simplest way possible while still being readable. This is the only code needed for the entire web page… the browser will figure out the rest… 😀
Fast Sine and Cosine Approximation
copy let t = 0 , cos, sin, x, y; const PI = Math .PI ; const TWO_PI = PI * 2 ; const HALF_PI = PI / 2 ; const tA = 4 / PI; const tB = 4 / PI ** 2 ; const canvas = document.body .appendChild ( document.createElement ( 'canvas' ) ) ; const c = canvas.getContext ( '2d' ) ; canvas.width = canvas.height = 300 ; function loop( ) { // low precision sine/cosine // always wrap input angle to -PI..PI t += 0.1 ; if ( t < - PI) { t += TWO_PI; } else if ( t > PI) { t -= TWO_PI; } // compute sine if ( t < 0 ) { sin = tA * t + tB * t * t; } else { sin = tA * t - tB * t * t; } // compute cosine: sin(t + PI/2) = cos(t) t += HALF_PI; if ( t > PI) { t -= TWO_PI; } if ( t < 0 ) { cos = tA * t + tB * t * t; } else { cos = tA * t - tB * t * t; } t -= HALF_PI; // move the shape x = 110 + 100 * cos; y = 110 + 100 * sin; c.fillStyle = 'rgba(100, 100, 20, .5)' ; c.fillRect ( x, y, 10 , 10 ) ; window.requestAnimationFrame ( loop) ; } loop( ) ;
Try it out…
This is an old trick for fast sine/cosine approximation. I learned about it from Michael Baczynski’s blog which now seems to be down. Here is a wayback link for the original article and another one to a more in-depth discussion about it:
original post
original thread
It’s unlikely that the speed gain (if there even is one here) makes sense in javascript. This is really more for fun… a quick search will turn up all kinds of cool info about fast sine/cosine stuff.
SVG getScreenCTM
copy const el = document.body .appendChild ( document.createElement `div` ) ; el.innerHTML = ` < svg width= "200" height= "200" viewBox= "0 0 200 200" > < rect class= "rect" transform= "translate(50, 50) scale(1.2) rotate(25)" fill= "purple" x= "0" y= "0" width= "50" height= "50" /> </ svg> `; const box = document.body .appendChild ( document.createElement `div` ) ; Object .assign ( box.style , { position: 'absolute' , left: 0 , top: 0 , width: '50px' , height: '50px' , transformOrigin: '0 0' , outline: '5px solid red' } ) ; const rect = document.querySelector ( '.rect' ) ; const { a, b, c, d, e, f} = rect.getScreenCTM ( ) box.style .transform = ` matrix( ${ [ a, b, c, d, e, f] } ) `;
Try it out…
The transformation matrix of an SVG element can be obtained using getScreenCTM
or getCTM
. The latter of which will be relative to the SVG coordinate space, vs the coordinate space of the page.
Here we take the matrix data from getScreenCTM
and use it on a div to place a border over an SVG rect
node. This is great for layering HTML on top of SVG.
Elasticity With Trails
copy let pointX = pointY = 0 ; document.addEventListener ( 'touchmove' , e => e.preventDefault ( ) , { passive: false } ) ; document.addEventListener ( 'mousemove' , e => { pointX = e.clientX ; pointY = e.clientY ; } ) ; document.addEventListener ( 'touchmove' , e => { pointX = e.touches [ 0 ] .clientX ; pointY = e.touches [ 0 ] .clientY ; } ) ; let el = document.body .appendChild ( document.createElement `div` ) ; const size = 20 ; const halfSize = size / 2 ; Object .assign ( el.style , { position: 'absolute' , width: `${ size} px`, height: `${ size} px`, background: 'red' , borderRadius: `${ size} px`, left: 0 , top: 0 } ) ; let x = vx = y = vy = 0 ; const FADE_TIME = 800 ; const plotDot = ( x, y) => { const dot = document.body .appendChild ( el.cloneNode ( ) ) ; const time = dot.style .transform += ' scale(.25)' ; dot.style .transition = `opacity ${ FADE_TIME} ms ease- out`; window.requestAnimationFrame ( ( ) => { dot.style .opacity = 0 ; setTimeout( ( ) => dot.parentNode .removeChild ( dot) , FADE_TIME) ; } ) } let ticks = 0 ; const loop = ( ) => { vx = ( ( pointX - x) * .08 + vx) * .95; vy = ( ( pointY - y) * .08 + vy) * .95; x += vx; y += vy; if ( ticks++ % 2 === 0 && Math .abs ( pointX - x) > 1 && Math .abs ( pointY - y) > 1 ) { plotDot( ) ; } el.style .transform = `translate( ${ x - halfSize} px, ${ y - halfSize} px) `; requestAnimationFrame( loop) ; } loop( ) ; const info = document.body .appendChild ( document.createElement `div` ) ; info.innerHTML = 'move mouse or finger left/right/up/down' ;
Try it out…
This is a variation on yesterdays post. This has elasticity on both axis and draws a trail of dots…
Elasticity
copy let pointX = pointY = 0 ; document.addEventListener ( 'mousemove' , e => { pointX = e.clientX ; pointY = e.clientY ; } ) ; document.addEventListener ( 'touchmove' , e => { pointX = e.touches [ 0 ] .clientX pointY = e.touches [ 0 ] .clientY } ) ; let el = document.body .appendChild ( document.createElement `div` ) ; const size = 20 ; const halfSize = size / 2 ; Object .assign ( el.style , { position: 'absolute' , width: `${ size} px`, height: `${ size} px`, background: 'red' , left: 0 , top: 0 } ) let x = vx = 0 ; const loop = ( ) => { vx = ( ( pointX - x) * .2 + vx) * .79; x += vx; el.style .transform = `translate( ${ x - halfSize} px, 50px) `; requestAnimationFrame( loop) ; } loop( ) ; let info = document.body .appendChild ( document.createElement `div` ) ; info.innerHTML = 'move mouse or finger left/right' ;
Try it out…
Basic interactive elasticity with mouse or touch