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.
Wiggly Line on Canvas 2
copy const canvas = document.body .appendChild ( document.createElement ( 'canvas' ) ) ; const c = canvas.getContext ( '2d' ) ; document.body .style .margin = 0 ; function resize( ) { canvas.width = innerWidth * 2 ; canvas.height = innerHeight * 2 ; canvas.style .width = innerWidth + 'px' ; canvas.style .height = innerHeight + 'px' ; } addEventListener( 'resize' , resize) ; resize( ) ; const PAD = 50 ; const RAD = 2 ; const SPEED = 200 ; const TWO_PI = Math .PI * 2 ; let mode = 'draw' ; let t = Math .random ( ) * TWO_PI, x = canvas.width / 2 , y = canvas.height / 2 , vx = 0 , vy = 0 , ta = 0 ; let solid = false ; let dotMod = 3 ; function loop( ) { if ( Math .random ( ) < .01) solid = ! solid; if ( Math .random ( ) < .01) dotMod = [ 2 , 3 , 6 ] [ Math .floor ( Math .random ( ) * 3 ) ] 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' && ( solid || i % dotMod === 0 ) ) { c.fillStyle = 'black' ; c.fillRect ( x, y, 2 , 2 ) ; } if ( x < - PAD) { x = canvas.width + PAD; } else if ( x > canvas.width + PAD) { x = - PAD; } if ( y < - PAD) { y = canvas.height + PAD; } else if ( y > canvas.height + PAD) { y = - PAD; } } requestAnimationFrame( loop) ; } loop( ) ;
Try it out…
This is a variation on a post from awhile back. I was posting it over on dev.to and realized I wanted it to look a bit different.
Canvas Particle
copy const canvas = document.createElement ( 'canvas' ) , c = canvas.getContext ( '2d' ) ; canvas.width = 500 ; canvas.height = 500 ; document.body .appendChild ( canvas) ; c.fillStyle = 'black' ; c.fillRect ( 0 , 0 , canvas.width , canvas.height ) ; let a = 0.29 , b = 0.22 ; function f( x, y) { if ( Math .random ( ) < 0.001 ) b = Math .random ( ) ; return Math .cos ( ( x + Math .sin ( x) * 0.01 + Math .cos ( x * a) ) * b) ; } let x = 1 , y = 0 ; setInterval( ( ) => { if ( Math .random ( ) < 0.03 ) { x = 1 ; y = 0 ; } if ( Math .random ( ) < 0.001 ) a = Math .random ( ) ; for ( let i = 0 ; i < 1e3; i++ ) { x = x + f( y) ; y = y + f( x) ; c.save ( ) ; c.translate ( 150 , 250 ) ; c.scale ( 0.5 , 0.5 ) ; c.fillStyle = 'rgba(255, 255, 255, 0.01)' ; c.fillRect ( x, y, 5 , 5 ) ; c.restore ( ) ; } } , 20 ) ;
Try it out…
A single particle moves around and leaves a trail
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