(function( $ ) { // Setup canvas var animate, refreshRate = 50, // How fast (smooth) it animates click = false, clickIncrement = 0.5, clickDelta = 0, hueDelta = 0, $win = $( window ), $canvas = $( 'canvas' ), canvas = $canvas[0], ctx = canvas.getContext( '2d' ), points = [], interval = 10, canvasWidth = $canvas.width(), canvasHeight = $canvas.height(), mouseX = 200, mouseY = 200, // Our workhorse draw function drawPoint = function( x, y, radius, color ) { ctx.fillStyle = color; ctx.beginPath(); ctx.arc( x, y, radius, 0, Math.PI * 2, false ); ctx.closePath(); ctx.fill(); }, render = function( points ) { var hue; // Each time this renders, we clear the previous content ctx.clearRect( 0, 0, canvasWidth, canvasHeight ); // If the mousebutton is currently clicked, keep growing the clickDelta // modifier (which makes the points bigger) by clickIncrement if ( click ) { // But only to a certain point if ( clickDelta < 5 ) { clickDelta += clickIncrement; } } else { // And don't let it fall below zero if ( clickDelta > 0 ) { clickDelta -= clickIncrement; } } // Strobe colors for maximum chillaxment if ( click === false ) { // If the mousebutton isn't clicked, strobe inward hueDelta += 10; } else { // If it is, strobe outward hueDelta -= 10; } // Reset the hue once it reaches the end of the color wheel if ( hueDelta > 360 ) { hueDelta = 0; } else if ( hueDelta < 0 ) { // Or the beginning hueDelta = 360; } // Iterate through all the points in our array for ( var i = 0, iLength = points.length; i < iLength; i += 1 ) { var x = points[i][0], y = points[i][1], x2, y2, radius = 1, radiusDelta = 0, // The distance formula: // http://www.mathwarehouse.com/algebra/distance_formula/index.php distance = Math.sqrt( Math.pow( mouseX - x, 2 ) + Math.pow( mouseY - y, 2 ) ), step = ( canvasWidth ) / 3; radiusDelta = ( distance / step ); // Set the hue of points by their distance to the mouse if ( mouseX && mouseY ) { // Add randomization to the edge to make it more ragged / textured distance += ( Math.random() * 50 ) - 25; hue = ( distance > 360 ) ? distance % 360 : distance; hue = ( hue + hueDelta ) % 360; } else { hue = 360; } // Set the size of the point radius = radius + radiusDelta + clickDelta + points[i][2]; radius = ( radius < 1 ) ? 1 : radius; // Randomize the opacity of each point to create attractive variance points[i][4] += ( Math.random() * 0.1 ) - 0.05; // Ensure opacity is between 1 and 0 if ( points[i][4] > 1 ) { points[i][4] = 1; } else if ( points[i][4] < 0 ) { points[i][4] = 0; } // We're done calculating -- draw the point! drawPoint( x, y, radius, 'hsla(' + hue + ', 50%, 50%, ' + points[i][4] + ')' ); } }; // Set up an array of points to iterate over with each rendering for ( var i = interval; i < canvasHeight; i += interval ) { for ( var j = interval; j < canvasWidth; j += interval ) { var rand = ( Math.random() * 2 ) - 1, randDelta = Math.floor( Math.random() * 2 ), opacity = Math.random(); // This is an atavism - disregard if ( randDelta !== 1 ) { randDelta = -1; } points.push( [ j, i, rand, randDelta, opacity ] ); } } // Set the mouseX and mouseY variables on mouse move so that // the visualization responds to mouse movement $win.bind( 'mousemove', function( event ) { mouseX = event.pageX - $canvas.offset().left; mouseY = event.pageY - $canvas.offset().top; }); $win.bind( 'mousedown', function( event ) { click = true; }); $win.bind( 'mouseup', function( event ) { click = false; }); // Animation happens by re-rendering everything every refreshRate milliseconds animate = setInterval( (function() { render( points ); }), refreshRate ); })( jQuery );
<!-- Canvas width and height need to be defined explicitly via attributes: http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html#attr-canvas-width --> <canvas width="300" height="300"></canvas> <p>move your mouse | click and hold</p>