Slider Range Input Wave
copy N = 8 // try changing this b = document.body b.innerHTML += 'Drag any slider<br>' for ( i = N; i--; ) b.innerHTML += `< input id= ${ i} value= 0 type= range style= width: 200px; display: block> ` onchange = oninput = e => { t = e.target for ( i = N; i--; ) t.id != i && ( self[ i] .value = 100 * Math .sin ( t.value / 60 * i) ) }
Try it out…
Sine wave with range sliders…
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
What is the current element? (document.activeElement)
copy console.log ( document.activeElement ) ;
I use document.activeElement
constantly when I do accessibility work (getting things to work with screenreaders like NVDA, JAWS or VoiceOver). document.activeElement
contains the current element that is in focus on a page.
You can easily debug it with a live expression in the chrome console:
Here is a small demo to play with – try clicking or tabbing around the buttons and inputs:
copy const el = document.createElement ( 'el' ) ; el.innerHTML = ` < button class= "one" > one</ button> < button class= "two" > two</ button> < button class= "three" > three</ button> < button class= "four" > four</ button> < hr> < input type= "text" placeholder= "type..." > < hr> < input type= "range" > `; document.body .appendChild ( el) ; let lastActive; setInterval( ( ) => { if ( document.activeElement != lastActive) { lastActive = document.activeElement ; console.log ( lastActive.outerHTML ) ; } // no need to update 60fps } , 100 ) ;
Try it out…