Drag/swipe to rotate.
A Pen by Hakim El Hattab on CodePen.
| <canvas></canvas> | |
| <span>drag to rotate</span> |
| var canvas = document.querySelector( 'canvas' ); | |
| var context = canvas.getContext( '2d' ); | |
| var time = 0, | |
| velocity = 0.1, | |
| velocityTarget = 0.1, | |
| width, | |
| height, | |
| lastX, | |
| lastY; | |
| var MAX_OFFSET = 400; | |
| var SPACING = 4; | |
| var POINTS = MAX_OFFSET / SPACING; | |
| var PEAK = MAX_OFFSET * 0.25; | |
| var POINTS_PER_LAP = 6; | |
| var SHADOW_STRENGTH = 6; | |
| setup(); | |
| function setup() { | |
| resize(); | |
| step(); | |
| window.addEventListener( 'resize', resize ); | |
| window.addEventListener( 'mousedown', onMouseDown ); | |
| document.addEventListener( 'touchstart', onTouchStart ); | |
| } | |
| function resize() { | |
| width = canvas.width = window.innerWidth; | |
| height = canvas.height = window.innerHeight; | |
| } | |
| function step() { | |
| time += velocity; | |
| velocity += ( velocityTarget - velocity ) * 0.3; | |
| clear(); | |
| render(); | |
| requestAnimationFrame( step ); | |
| } | |
| function clear() { | |
| context.clearRect( 0, 0, width, height ); | |
| } | |
| function render() { | |
| var x, y, | |
| cx = width/2, | |
| cy = height/2; | |
| context.globalCompositeOperation = 'lighter'; | |
| context.strokeStyle = '#fff'; | |
| context.shadowColor = '#fff'; | |
| context.lineWidth = 2; | |
| context.beginPath(); | |
| for( var i = POINTS; i > 0; i -- ) { | |
| var value = i * SPACING + ( time % SPACING ); | |
| var ax = Math.sin( value/POINTS_PER_LAP ) * Math.PI, | |
| ay = Math.cos( value/POINTS_PER_LAP ) * Math.PI; | |
| x = ax * value, | |
| y = ay * value * 0.35; | |
| var o = 1 - ( Math.min( value, PEAK ) / PEAK ); | |
| y -= Math.pow( o, 2 ) * 200; | |
| y += 200 * value / MAX_OFFSET; | |
| y += x / cx * width * 0.1; | |
| context.globalAlpha = 1 - ( value / MAX_OFFSET ); | |
| context.shadowBlur = SHADOW_STRENGTH * o; | |
| context.lineTo( cx + x, cy + y ); | |
| context.stroke(); | |
| context.beginPath(); | |
| context.moveTo( cx + x, cy + y ); | |
| } | |
| context.lineTo( cx, cy - 200 ); | |
| context.lineTo( cx, 0 ); | |
| context.stroke(); | |
| } | |
| function onMouseDown( event ) { | |
| lastX = event.clientX; | |
| lastY = event.clientY; | |
| document.addEventListener( 'mousemove', onMouseMove ); | |
| document.addEventListener( 'mouseup', onMouseUp ); | |
| } | |
| function onMouseMove( event ) { | |
| var vx = ( event.clientX - lastX ) / 100; | |
| var vy = ( event.clientY - lastY ) / 100; | |
| if( event.clientY < height/2 ) vx *= -1; | |
| if( event.clientX > width/2 ) vy *= -1; | |
| velocityTarget = vx + vy; | |
| lastX = event.clientX; | |
| lastY = event.clientY; | |
| } | |
| function onMouseUp( event ) { | |
| document.removeEventListener( 'mousemove', onMouseMove ); | |
| document.removeEventListener( 'mouseup', onMouseUp ); | |
| } | |
| function onTouchStart( event ) { | |
| event.preventDefault(); | |
| lastX = event.touches[0].clientX; | |
| lastY = event.touches[0].clientY; | |
| document.addEventListener( 'touchmove', onTouchMove ); | |
| document.addEventListener( 'touchend', onTouchEnd ); | |
| } | |
| function onTouchMove( event ) { | |
| var vx = ( event.touches[0].clientX - lastX ) / 100; | |
| var vy = ( event.touches[0].clientY - lastY ) / 100; | |
| if( event.touches[0].clientY < height/2 ) vx *= -1; | |
| if( event.touches[0].clientX > width/2 ) vy *= -1; | |
| velocityTarget = vx + vy; | |
| lastX = event.touches[0].clientX; | |
| lastY = event.touches[0].clientY; | |
| } | |
| function onTouchEnd( event ) { | |
| document.removeEventListener( 'touchmove', onTouchMove ); | |
| document.removeEventListener( 'touchend', onTouchEnd ); | |
| } |
Drag/swipe to rotate.
A Pen by Hakim El Hattab on CodePen.
| body { | |
| display: flex; | |
| height: 100vh; | |
| background-color: #111; | |
| } | |
| canvas { | |
| margin: auto; | |
| } | |
| span { | |
| color: #777; | |
| position: absolute; | |
| top: 20px; | |
| left: 20px; | |
| user-select: none; | |
| } |