{"id":268,"date":"2016-02-16T23:42:30","date_gmt":"2016-02-17T05:42:30","guid":{"rendered":"http:\/\/timothypoon.com\/blog\/?p=268"},"modified":"2016-02-19T09:01:12","modified_gmt":"2016-02-19T15:01:12","slug":"html5-canvas-particles-revisisted-with-physics","status":"publish","type":"post","link":"https:\/\/timothypoon.com\/blog\/2016\/02\/16\/html5-canvas-particles-revisisted-with-physics\/","title":{"rendered":"HTML5 Canvas Particles Revisisted \u2014 With Physics!"},"content":{"rendered":"<p>While I wrote a few years ago about <a href=\"http:\/\/timothypoon.com\/blog\/2011\/01\/19\/html5-canvas-particle-animation\/\">HTML5 canvas particle effects<\/a>, I&#8217;ve gotten a lot of questions about the effect I have on my <a href=\"http:\/\/timothypoon.com\/\">new personal site<\/a>. No, not the crazy swirling thing on the left\u2014we&#8217;ll go over that another time\u2014but the fun little bouncy ball thing. Go ahead and check it out. I&#8217;ll wait.<\/p>\n<p>Pretty cool, right? It&#8217;s written entirely without any framework or library like jQuery or D3.js or Three.js. While they&#8217;re pretty handy for compatibility, data visualization, and comprehensive 3D graphics rendering (respectively), I didn&#8217;t have much of a need for something so straightforward. Plus, it makes it easier to understand the mechanics of it all when I write about it.<\/p>\n<p>Which is right now. (Duh doy.)<\/p>\n<h2>The Setup<\/h2>\n<p>HTML-wise, this isn&#8217;t terribly complex. In fact, all we need is a canvas to draw on. Like, literally.<\/p>\n<div class=\"codecolorer-container html4strict railscasts\" style=\"overflow:auto;white-space:nowrap;width:100%;\"><table cellspacing=\"0\" cellpadding=\"0\"><tbody><tr><td class=\"line-numbers\"><div>1<br \/>2<br \/>3<br \/>4<br \/>5<br \/>6<br \/>7<br \/>8<br \/>9<br \/>10<br \/><\/div><\/td><td><div class=\"html4strict codecolorer\"><span class=\"sc0\">&lt;!DOCTYPE html&gt;<\/span><br \/>\n<span class=\"sc2\">&lt;<a href=\"http:\/\/december.com\/html\/4\/element\/html.html\"><span class=\"kw2\">html<\/span><\/a> <span class=\"kw3\">lang<\/span><span class=\"sy0\">=<\/span><span class=\"st0\">&quot;en-us&quot;<\/span>&gt;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"sc2\">&lt;<a href=\"http:\/\/december.com\/html\/4\/element\/head.html\"><span class=\"kw2\">head<\/span><\/a>&gt;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"sc2\">&lt;<a href=\"http:\/\/december.com\/html\/4\/element\/meta.html\"><span class=\"kw2\">meta<\/span><\/a> <span class=\"kw3\">http-equiv<\/span><span class=\"sy0\">=<\/span><span class=\"st0\">&quot;X-UA-Compatible&quot;<\/span> <span class=\"kw3\">content<\/span><span class=\"sy0\">=<\/span><span class=\"st0\">&quot;IE=edge&quot;<\/span>&gt;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"sc2\">&lt;<a href=\"http:\/\/december.com\/html\/4\/element\/title.html\"><span class=\"kw2\">title<\/span><\/a>&gt;<\/span>Weeeee!<span class=\"sc2\">&lt;<span class=\"sy0\">\/<\/span><a href=\"http:\/\/december.com\/html\/4\/element\/title.html\"><span class=\"kw2\">title<\/span><\/a>&gt;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"sc2\">&lt;<span class=\"sy0\">\/<\/span><a href=\"http:\/\/december.com\/html\/4\/element\/head.html\"><span class=\"kw2\">head<\/span><\/a>&gt;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"sc2\">&lt;<a href=\"http:\/\/december.com\/html\/4\/element\/body.html\"><span class=\"kw2\">body<\/span><\/a>&gt;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"sc2\">&lt;canvas <span class=\"kw3\">id<\/span><span class=\"sy0\">=<\/span><span class=\"st0\">&quot;bubbles&quot;<\/span>&gt;&lt;<span class=\"sy0\">\/<\/span>canvas&gt;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"sc2\">&lt;<span class=\"sy0\">\/<\/span><a href=\"http:\/\/december.com\/html\/4\/element\/body.html\"><span class=\"kw2\">body<\/span><\/a>&gt;<\/span><br \/>\n<span class=\"sc2\">&lt;<span class=\"sy0\">\/<\/span><a href=\"http:\/\/december.com\/html\/4\/element\/html.html\"><span class=\"kw2\">html<\/span><\/a>&gt;<\/span><\/div><\/td><\/tr><\/tbody><\/table><\/div>\n<p>For styles, we can keep it simple, too. All we want is to make sure the <code class=\"codecolorer text geshi\"><span class=\"text\">canvas<\/span><\/code> is where we want it.<\/p>\n<div class=\"codecolorer-container css railscasts\" style=\"overflow:auto;white-space:nowrap;width:100%;\"><table cellspacing=\"0\" cellpadding=\"0\"><tbody><tr><td class=\"line-numbers\"><div>1<br \/>2<br \/>3<br \/>4<br \/>5<br \/>6<br \/>7<br \/>8<br \/>9<br \/>10<br \/>11<br \/>12<br \/>13<br \/>14<br \/>15<br \/>16<br \/>17<br \/>18<br \/>19<br \/>20<br \/><\/div><\/td><td><div class=\"css codecolorer\">html<span class=\"sy0\">,<\/span> body<span class=\"sy0\">,<\/span> <span class=\"re0\">#bubbles<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">border<\/span><span class=\"sy0\">:<\/span> <span class=\"nu0\">0<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">margin<\/span><span class=\"sy0\">:<\/span> <span class=\"nu0\">0<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">padding<\/span><span class=\"sy0\">:<\/span> <span class=\"nu0\">0<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">width<\/span><span class=\"sy0\">:<\/span> <span class=\"re3\">100%<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">height<\/span><span class=\"sy0\">:<\/span> <span class=\"re3\">100%<\/span><span class=\"sy0\">;<\/span><br \/>\n<span class=\"br0\">&#125;<\/span><br \/>\n<br \/>\nbody <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">background<\/span><span class=\"sy0\">:<\/span> linear-gradient<span class=\"br0\">&#40;<\/span>to <span class=\"kw2\">bottom<\/span><span class=\"sy0\">,<\/span> <span class=\"kw3\">rgba<\/span><span class=\"br0\">&#40;<\/span><span class=\"nu0\">91<\/span><span class=\"sy0\">,<\/span><span class=\"nu0\">91<\/span><span class=\"sy0\">,<\/span><span class=\"nu0\">91<\/span><span class=\"sy0\">,<\/span><span class=\"nu0\">1<\/span><span class=\"br0\">&#41;<\/span> <span class=\"re3\">0%<\/span><span class=\"sy0\">,<\/span> <span class=\"kw3\">rgba<\/span><span class=\"br0\">&#40;<\/span><span class=\"nu0\">58<\/span><span class=\"sy0\">,<\/span><span class=\"nu0\">58<\/span><span class=\"sy0\">,<\/span><span class=\"nu0\">58<\/span><span class=\"sy0\">,<\/span><span class=\"nu0\">1<\/span><span class=\"br0\">&#41;<\/span> <span class=\"re3\">100%<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n<span class=\"br0\">&#125;<\/span><br \/>\n<br \/>\n<span class=\"coMULTI\">\/* Only if you want the hover effect *\/<\/span><br \/>\n<span class=\"re0\">#bubbles<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">opacity<\/span><span class=\"sy0\">:<\/span> <span class=\"nu0\">0<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">transition<\/span><span class=\"sy0\">:<\/span> opacity <span class=\"re3\">0.8s<\/span> ease-in-out<span class=\"sy0\">;<\/span><br \/>\n<span class=\"br0\">&#125;<\/span><br \/>\n<span class=\"re0\">#bubbles<\/span><span class=\"sy0\">:<\/span><span class=\"kw5\">hover<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">opacity<\/span><span class=\"sy0\">:<\/span> <span class=\"nu0\">1<\/span><span class=\"sy0\">;<\/span><br \/>\n<span class=\"br0\">&#125;<\/span><\/div><\/td><\/tr><\/tbody><\/table><\/div>\n<h2>The JavaScript<\/h2>\n<p>While not terribly complex, let&#8217;s break it down into bite-sized chunks.<\/p>\n<div class=\"codecolorer-container javascript railscasts\" style=\"overflow:auto;white-space:nowrap;width:100%;\"><table cellspacing=\"0\" cellpadding=\"0\"><tbody><tr><td class=\"line-numbers\"><div>1<br \/>2<br \/>3<br \/>4<br \/>5<br \/>6<br \/>7<br \/>8<br \/><\/div><\/td><td><div class=\"javascript codecolorer\"><span class=\"kw1\">var<\/span> canvas <span class=\"sy0\">=<\/span> document.<span class=\"me1\">querySelector<\/span><span class=\"br0\">&#40;<\/span><span class=\"st0\">'#bubbles'<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; &nbsp; context <span class=\"sy0\">=<\/span> canvas.<span class=\"me1\">getContext<\/span><span class=\"br0\">&#40;<\/span><span class=\"st0\">'2d'<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; &nbsp; particles <span class=\"sy0\">=<\/span> <span class=\"br0\">&#91;<\/span><span class=\"br0\">&#93;<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; &nbsp; last_draw <span class=\"sy0\">=<\/span> <span class=\"kw2\">undefined<\/span><span class=\"sy0\">,<\/span><br \/>\n<br \/>\n&nbsp; &nbsp; MAX_PARTICLES <span class=\"sy0\">=<\/span> <span class=\"nu0\">100<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; &nbsp; CANVAS_WIDTH <span class=\"sy0\">=<\/span> <span class=\"nu0\">0<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; &nbsp; CANVAS_HEIGHT <span class=\"sy0\">=<\/span> <span class=\"nu0\">0<\/span><span class=\"sy0\">;<\/span><\/div><\/td><\/tr><\/tbody><\/table><\/div>\n<p>All this does is instantiate and set the necessary variables. <code class=\"codecolorer text geshi\"><span class=\"text\">canvas<\/span><\/code> is the DOM node, <code class=\"codecolorer text geshi\"><span class=\"text\">context<\/span><\/code> is the drawing context, <code class=\"codecolorer text geshi\"><span class=\"text\">particles<\/span><\/code> is where we&#8217;ll track all the particles we create, and <code class=\"codecolorer text geshi\"><span class=\"text\">last_draw<\/span><\/code> will be used for <code class=\"codecolorer text geshi\"><span class=\"text\">requestAnimationFrame()<\/span><\/code> calculations.<\/p>\n<p>The rest of the variables are constants for drawing. They should mostly speak for themselves.<\/p>\n<div class=\"codecolorer-container javascript railscasts\" style=\"overflow:auto;white-space:nowrap;width:100%;\"><table cellspacing=\"0\" cellpadding=\"0\"><tbody><tr><td class=\"line-numbers\"><div>1<br \/>2<br \/>3<br \/>4<br \/>5<br \/>6<br \/>7<br \/>8<br \/><\/div><\/td><td><div class=\"javascript codecolorer\"><span class=\"kw1\">function<\/span> setDimensions<span class=\"br0\">&#40;<\/span>e<span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; CANVAS_WIDTH <span class=\"sy0\">=<\/span> canvas.<span class=\"me1\">clientWidth<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; CANVAS_HEIGHT <span class=\"sy0\">=<\/span> canvas.<span class=\"me1\">clientHeight<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; canvas.<span class=\"me1\">width<\/span> <span class=\"sy0\">=<\/span> CANVAS_WIDTH<span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; canvas.<span class=\"me1\">height<\/span> <span class=\"sy0\">=<\/span> CANVAS_HEIGHT<span class=\"sy0\">;<\/span><br \/>\n<span class=\"br0\">&#125;<\/span><br \/>\nsetDimensions<span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\nwindow.<span class=\"me1\">addEventListener<\/span><span class=\"br0\">&#40;<\/span><span class=\"st0\">'resize'<\/span><span class=\"sy0\">,<\/span> setDimensions<span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><\/div><\/td><\/tr><\/tbody><\/table><\/div>\n<p>This is how we make sure the canvas stays the right size. The CSS styles will make sure the canvas stays full, but you need to set the HTML attributes to make sure the drawing functions properly. It&#8217;ll run every <code class=\"codecolorer text geshi\"><span class=\"text\">resize<\/span><\/code> event.<\/p>\n<div class=\"codecolorer-container javascript railscasts\" style=\"overflow:auto;white-space:nowrap;width:100%;height:300px;\"><table cellspacing=\"0\" cellpadding=\"0\"><tbody><tr><td class=\"line-numbers\"><div>1<br \/>2<br \/>3<br \/>4<br \/>5<br \/>6<br \/>7<br \/>8<br \/>9<br \/>10<br \/>11<br \/>12<br \/>13<br \/>14<br \/>15<br \/>16<br \/>17<br \/>18<br \/>19<br \/>20<br \/>21<br \/>22<br \/>23<br \/>24<br \/>25<br \/>26<br \/>27<br \/>28<br \/>29<br \/>30<br \/>31<br \/>32<br \/>33<br \/>34<br \/>35<br \/>36<br \/>37<br \/>38<br \/>39<br \/>40<br \/>41<br \/>42<br \/>43<br \/>44<br \/>45<br \/>46<br \/>47<br \/>48<br \/>49<br \/>50<br \/>51<br \/>52<br \/>53<br \/>54<br \/>55<br \/>56<br \/>57<br \/>58<br \/>59<br \/>60<br \/>61<br \/>62<br \/>63<br \/>64<br \/>65<br \/>66<br \/>67<br \/>68<br \/>69<br \/>70<br \/>71<br \/>72<br \/>73<br \/>74<br \/>75<br \/>76<br \/>77<br \/>78<br \/>79<br \/>80<br \/>81<br \/>82<br \/>83<br \/>84<br \/>85<br \/>86<br \/>87<br \/>88<br \/>89<br \/>90<br \/>91<br \/>92<br \/>93<br \/>94<br \/>95<br \/>96<br \/>97<br \/>98<br \/>99<br \/>100<br \/>101<br \/>102<br \/>103<br \/>104<br \/>105<br \/>106<br \/>107<br \/>108<br \/>109<br \/>110<br \/>111<br \/>112<br \/>113<br \/>114<br \/>115<br \/>116<br \/>117<br \/>118<br \/>119<br \/><\/div><\/td><td><div class=\"javascript codecolorer\"><span class=\"kw1\">function<\/span> Particle<span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">var<\/span> self <span class=\"sy0\">=<\/span> <span class=\"kw1\">this<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; pos_x <span class=\"sy0\">=<\/span> <span class=\"nu0\">0<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; pos_y <span class=\"sy0\">=<\/span> <span class=\"nu0\">0<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; vel_x <span class=\"sy0\">=<\/span> <span class=\"nu0\">0<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; vel_y <span class=\"sy0\">=<\/span> <span class=\"nu0\">0<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; acc_x <span class=\"sy0\">=<\/span> <span class=\"nu0\">0<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; acc_y <span class=\"sy0\">=<\/span> <span class=\"nu0\">1.5<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; color <span class=\"sy0\">=<\/span> <span class=\"nu0\">0<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; radius <span class=\"sy0\">=<\/span> <span class=\"nu0\">0<\/span><span class=\"sy0\">;<\/span><br \/>\n<br \/>\n&nbsp; &nbsp; <span class=\"kw1\">this<\/span>.<span class=\"me1\">reset<\/span> <span class=\"sy0\">=<\/span> <span class=\"kw1\">function<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span><span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"co1\">\/\/ Centralize position<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; self.<span class=\"me1\">setPosX<\/span><span class=\"br0\">&#40;<\/span>CANVAS_WIDTH <span class=\"sy0\">\/<\/span> <span class=\"nu0\">2<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; self.<span class=\"me1\">setPosY<\/span><span class=\"br0\">&#40;<\/span>CANVAS_HEIGHT <span class=\"sy0\">\/<\/span> <span class=\"nu0\">2<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"co1\">\/\/ Randomize velocities<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; self.<span class=\"me1\">setVelX<\/span><span class=\"br0\">&#40;<\/span><span class=\"kw4\">Math<\/span>.<span class=\"me1\">random<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span> <span class=\"sy0\">*<\/span> <span class=\"nu0\">40<\/span> <span class=\"sy0\">-<\/span> <span class=\"nu0\">20<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; self.<span class=\"me1\">setVelY<\/span><span class=\"br0\">&#40;<\/span><span class=\"kw4\">Math<\/span>.<span class=\"me1\">random<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span> <span class=\"sy0\">*<\/span> <span class=\"sy0\">-<\/span><span class=\"nu0\">30<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"co1\">\/\/ Also randomize the radius<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; self.<span class=\"me1\">setRadius<\/span><span class=\"br0\">&#40;<\/span><span class=\"kw4\">Math<\/span>.<span class=\"me1\">random<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span> <span class=\"sy0\">*<\/span> <span class=\"nu0\">15<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"co1\">\/\/ And finally the color<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; self.<span class=\"me1\">setColor<\/span><span class=\"br0\">&#40;<\/span><span class=\"kw4\">Math<\/span>.<span class=\"me1\">random<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span> <span class=\"sy0\">*<\/span> <span class=\"nu0\">360<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><span class=\"sy0\">;<\/span><br \/>\n<br \/>\n&nbsp; &nbsp; <span class=\"kw1\">this<\/span>.<span class=\"me1\">setColor<\/span> <span class=\"sy0\">=<\/span> <span class=\"kw1\">function<\/span><span class=\"br0\">&#40;<\/span>c<span class=\"br0\">&#41;<\/span><span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"kw1\">if<\/span> <span class=\"br0\">&#40;<\/span><span class=\"kw1\">typeof<\/span><span class=\"br0\">&#40;<\/span>c<span class=\"br0\">&#41;<\/span> <span class=\"sy0\">===<\/span> <span class=\"st0\">'number'<\/span><span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; color <span class=\"sy0\">=<\/span> c<span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">this<\/span>.<span class=\"me1\">getColor<\/span> <span class=\"sy0\">=<\/span> <span class=\"kw1\">function<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span><span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"kw1\">return<\/span> color<span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><span class=\"sy0\">;<\/span><br \/>\n<br \/>\n&nbsp; &nbsp; <span class=\"kw1\">this<\/span>.<span class=\"me1\">setRadius<\/span> <span class=\"sy0\">=<\/span> <span class=\"kw1\">function<\/span><span class=\"br0\">&#40;<\/span>r<span class=\"br0\">&#41;<\/span><span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"kw1\">if<\/span> <span class=\"br0\">&#40;<\/span><span class=\"kw1\">typeof<\/span><span class=\"br0\">&#40;<\/span>r<span class=\"br0\">&#41;<\/span> <span class=\"sy0\">===<\/span> <span class=\"st0\">'number'<\/span><span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; radius <span class=\"sy0\">=<\/span> r<span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">this<\/span>.<span class=\"me1\">getRadius<\/span> <span class=\"sy0\">=<\/span> <span class=\"kw1\">function<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span><span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"kw1\">return<\/span> radius<span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><span class=\"sy0\">;<\/span><br \/>\n<br \/>\n&nbsp; &nbsp; <span class=\"kw1\">this<\/span>.<span class=\"me1\">setPosX<\/span> <span class=\"sy0\">=<\/span> <span class=\"kw1\">function<\/span><span class=\"br0\">&#40;<\/span>x<span class=\"br0\">&#41;<\/span><span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"kw1\">if<\/span> <span class=\"br0\">&#40;<\/span><span class=\"kw1\">typeof<\/span><span class=\"br0\">&#40;<\/span>x<span class=\"br0\">&#41;<\/span> <span class=\"sy0\">===<\/span> <span class=\"st0\">'number'<\/span><span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; pos_x <span class=\"sy0\">=<\/span> x<span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">this<\/span>.<span class=\"me1\">setPosY<\/span> <span class=\"sy0\">=<\/span> <span class=\"kw1\">function<\/span><span class=\"br0\">&#40;<\/span>y<span class=\"br0\">&#41;<\/span><span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"kw1\">if<\/span> <span class=\"br0\">&#40;<\/span><span class=\"kw1\">typeof<\/span><span class=\"br0\">&#40;<\/span>y<span class=\"br0\">&#41;<\/span> <span class=\"sy0\">===<\/span> <span class=\"st0\">'number'<\/span><span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; pos_y <span class=\"sy0\">=<\/span> y<span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><span class=\"sy0\">;<\/span><br \/>\n<br \/>\n&nbsp; &nbsp; <span class=\"kw1\">this<\/span>.<span class=\"me1\">getPosX<\/span> <span class=\"sy0\">=<\/span> <span class=\"kw1\">function<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span><span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"kw1\">return<\/span> pos_x<span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">this<\/span>.<span class=\"me1\">getPosY<\/span> <span class=\"sy0\">=<\/span> <span class=\"kw1\">function<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span><span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"kw1\">return<\/span> pos_y<span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><span class=\"sy0\">;<\/span><br \/>\n<br \/>\n&nbsp; &nbsp; <span class=\"kw1\">this<\/span>.<span class=\"me1\">setVelX<\/span> <span class=\"sy0\">=<\/span> <span class=\"kw1\">function<\/span><span class=\"br0\">&#40;<\/span>x<span class=\"br0\">&#41;<\/span><span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"kw1\">if<\/span> <span class=\"br0\">&#40;<\/span><span class=\"kw1\">typeof<\/span><span class=\"br0\">&#40;<\/span>x<span class=\"br0\">&#41;<\/span> <span class=\"sy0\">===<\/span> <span class=\"st0\">'number'<\/span><span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; vel_x <span class=\"sy0\">=<\/span> x<span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">this<\/span>.<span class=\"me1\">setVelY<\/span> <span class=\"sy0\">=<\/span> <span class=\"kw1\">function<\/span><span class=\"br0\">&#40;<\/span>y<span class=\"br0\">&#41;<\/span><span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"kw1\">if<\/span> <span class=\"br0\">&#40;<\/span><span class=\"kw1\">typeof<\/span><span class=\"br0\">&#40;<\/span>y<span class=\"br0\">&#41;<\/span> <span class=\"sy0\">===<\/span> <span class=\"st0\">'number'<\/span><span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; vel_y <span class=\"sy0\">=<\/span> y<span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><span class=\"sy0\">;<\/span><br \/>\n<br \/>\n&nbsp; &nbsp; <span class=\"kw1\">this<\/span>.<span class=\"me1\">getVelX<\/span> <span class=\"sy0\">=<\/span> <span class=\"kw1\">function<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span><span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"kw1\">return<\/span> vel_x<span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">this<\/span>.<span class=\"me1\">getVelY<\/span> <span class=\"sy0\">=<\/span> <span class=\"kw1\">function<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span><span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"kw1\">return<\/span> vel_y<span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><span class=\"sy0\">;<\/span><br \/>\n<br \/>\n&nbsp; &nbsp; <span class=\"kw1\">this<\/span>.<span class=\"me1\">setAccX<\/span> <span class=\"sy0\">=<\/span> <span class=\"kw1\">function<\/span><span class=\"br0\">&#40;<\/span>x<span class=\"br0\">&#41;<\/span><span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"kw1\">if<\/span> <span class=\"br0\">&#40;<\/span><span class=\"kw1\">typeof<\/span><span class=\"br0\">&#40;<\/span>x<span class=\"br0\">&#41;<\/span> <span class=\"sy0\">===<\/span> <span class=\"st0\">'number'<\/span><span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; acc_x <span class=\"sy0\">=<\/span> x<span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">this<\/span>.<span class=\"me1\">setAccY<\/span> <span class=\"sy0\">=<\/span> <span class=\"kw1\">function<\/span><span class=\"br0\">&#40;<\/span>y<span class=\"br0\">&#41;<\/span><span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"kw1\">if<\/span> <span class=\"br0\">&#40;<\/span><span class=\"kw1\">typeof<\/span><span class=\"br0\">&#40;<\/span>y<span class=\"br0\">&#41;<\/span> <span class=\"sy0\">===<\/span> <span class=\"st0\">'number'<\/span><span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; acc_y <span class=\"sy0\">=<\/span> y<span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><span class=\"sy0\">;<\/span><br \/>\n<br \/>\n&nbsp; &nbsp; <span class=\"kw1\">this<\/span>.<span class=\"me1\">getAccX<\/span> <span class=\"sy0\">=<\/span> <span class=\"kw1\">function<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span><span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"kw1\">return<\/span> acc_x<span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">this<\/span>.<span class=\"me1\">getAccY<\/span> <span class=\"sy0\">=<\/span> <span class=\"kw1\">function<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span><span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"kw1\">return<\/span> acc_y<span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><span class=\"sy0\">;<\/span><br \/>\n<br \/>\n&nbsp; &nbsp; <span class=\"kw1\">this<\/span>.<span class=\"me1\">step<\/span> <span class=\"sy0\">=<\/span> <span class=\"kw1\">function<\/span><span class=\"br0\">&#40;<\/span>tdiff<span class=\"br0\">&#41;<\/span><span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"co1\">\/\/ Move position<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; self.<span class=\"me1\">setPosX<\/span><span class=\"br0\">&#40;<\/span>self.<span class=\"me1\">getPosX<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span> <span class=\"sy0\">+<\/span> <span class=\"br0\">&#40;<\/span>self.<span class=\"me1\">getVelX<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span> <span class=\"sy0\">*<\/span> tdiff<span class=\"br0\">&#41;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; self.<span class=\"me1\">setPosY<\/span><span class=\"br0\">&#40;<\/span>self.<span class=\"me1\">getPosY<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span> <span class=\"sy0\">+<\/span> <span class=\"br0\">&#40;<\/span>self.<span class=\"me1\">getVelY<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span> <span class=\"sy0\">*<\/span> tdiff<span class=\"br0\">&#41;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"co1\">\/\/ Alter velocities<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; self.<span class=\"me1\">setVelX<\/span><span class=\"br0\">&#40;<\/span>self.<span class=\"me1\">getVelX<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span> <span class=\"sy0\">+<\/span> <span class=\"br0\">&#40;<\/span>self.<span class=\"me1\">getAccX<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span> <span class=\"sy0\">*<\/span> tdiff<span class=\"br0\">&#41;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; self.<span class=\"me1\">setVelY<\/span><span class=\"br0\">&#40;<\/span>self.<span class=\"me1\">getVelY<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span> <span class=\"sy0\">+<\/span> <span class=\"br0\">&#40;<\/span>self.<span class=\"me1\">getAccY<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span> <span class=\"sy0\">*<\/span> tdiff<span class=\"br0\">&#41;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"co1\">\/\/ Detect boundaries<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"kw1\">if<\/span> <span class=\"br0\">&#40;<\/span>self.<span class=\"me1\">getPosX<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span> <span class=\"sy0\">-<\/span> self.<span class=\"me1\">getRadius<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span> <span class=\"sy0\">&lt;=<\/span> <span class=\"nu0\">0<\/span> <span class=\"sy0\">||<\/span> self.<span class=\"me1\">getPosX<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span> <span class=\"sy0\">+<\/span> self.<span class=\"me1\">getRadius<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span> <span class=\"sy0\">&gt;=<\/span> CANVAS_WIDTH<span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; self.<span class=\"me1\">setVelX<\/span><span class=\"br0\">&#40;<\/span>self.<span class=\"me1\">getVelX<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span> <span class=\"sy0\">*<\/span> <span class=\"sy0\">-<\/span><span class=\"nu0\">1.0<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"kw1\">if<\/span> <span class=\"br0\">&#40;<\/span>self.<span class=\"me1\">getPosY<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span> <span class=\"sy0\">-<\/span> self.<span class=\"me1\">getRadius<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span> <span class=\"sy0\">&gt;=<\/span> CANVAS_HEIGHT<span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; self.<span class=\"me1\">reset<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><span class=\"sy0\">;<\/span><br \/>\n<br \/>\n&nbsp; &nbsp; <span class=\"kw1\">this<\/span>.<span class=\"me1\">reset<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n<span class=\"br0\">&#125;<\/span><\/div><\/td><\/tr><\/tbody><\/table><\/div>\n<p>Here is the workhorse object. It&#8217;s the <code class=\"codecolorer text geshi\"><span class=\"text\">Particle<\/span><\/code> object that contains all of the movement functions.<\/p>\n<p>It all kicks off from the <code class=\"codecolorer text geshi\"><span class=\"text\">reset()<\/span><\/code> function. It centers the particle within the canvas and then randomizes the initial velocity, radius, and color. Color is pretty cool because you are just randomizing against an <code class=\"codecolorer text geshi\"><span class=\"text\">hsl()<\/span><\/code> value and picking a hue somewhere on the spectrum with some bubble gum-style saturation and lightness.<\/p>\n<p>The physics of it all is super simple. If you remember your high school <a href=\"http:\/\/www.physicsclassroom.com\/class\/1DKin\/Lesson-6\/Kinematic-Equations\">kinematics<\/a>, then you&#8217;ll get this. <\/p>\n<p>It&#8217;s all handled in the <code class=\"codecolorer text geshi\"><span class=\"text\">step()<\/span><\/code> function. Acceleration, velocity, and position are broken into their component X and Y vectors. The acceleration will always stay the same, though you can tweak it to make the particles fall faster or slower. Velocity is impacted by the acceleration, resulting in the position coordinates.<\/p>\n<div class=\"codecolorer-container javascript railscasts\" style=\"overflow:auto;white-space:nowrap;width:100%;\"><div class=\"javascript codecolorer\">newPosition <span class=\"sy0\">=<\/span> oldPosition <span class=\"sy0\">+<\/span> <span class=\"br0\">&#40;<\/span>oldVelocity <span class=\"sy0\">*<\/span> timeDelta<span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\nnewVelocity <span class=\"sy0\">=<\/span> oldVelocity <span class=\"sy0\">+<\/span> <span class=\"br0\">&#40;<\/span>acceleration <span class=\"sy0\">*<\/span> timeDelta<span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><\/div><\/div>\n<p>You&#8217;ll also notice inside <code class=\"codecolorer text geshi\"><span class=\"text\">step()<\/span><\/code> that if a particle&#8217;s edge also hits the edge of the canvas, it&#8217;ll bounce back. You can add a dampening effect by changing <code class=\"codecolorer javascript geshi\"><span class=\"javascript\">self.<span class=\"me1\">setVelX<\/span><span class=\"br0\">&#40;<\/span>self.<span class=\"me1\">getVelX<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span> <span class=\"sy0\">*<\/span> <span class=\"sy0\">-<\/span><span class=\"nu0\">1.0<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><\/span><\/code> to some other value less than <code class=\"codecolorer text geshi\"><span class=\"text\">1.0<\/span><\/code>, which is more realistic but less fun.<\/p>\n<p>And then if the particle clears the bottom of the canvas, it&#8217;ll reset to the center with a new radius, color, and velocity.<\/p>\n<p>Now for particle instantiation, which is also pretty simple.<\/p>\n<div class=\"codecolorer-container javascript railscasts\" style=\"overflow:auto;white-space:nowrap;width:100%;\"><table cellspacing=\"0\" cellpadding=\"0\"><tbody><tr><td class=\"line-numbers\"><div>1<br \/>2<br \/>3<br \/><\/div><\/td><td><div class=\"javascript codecolorer\"><span class=\"kw1\">for<\/span> <span class=\"br0\">&#40;<\/span><span class=\"kw1\">var<\/span> i <span class=\"sy0\">=<\/span> <span class=\"nu0\">0<\/span><span class=\"sy0\">;<\/span> i <span class=\"sy0\">&lt;<\/span> MAX_PARTICLES<span class=\"sy0\">;<\/span> i<span class=\"sy0\">++<\/span><span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; particles.<span class=\"me1\">push<\/span><span class=\"br0\">&#40;<\/span><span class=\"kw1\">new<\/span> Particle<span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n<span class=\"br0\">&#125;<\/span><\/div><\/td><\/tr><\/tbody><\/table><\/div>\n<p>And finally, we just write another step function that is called by <code class=\"codecolorer text geshi\"><span class=\"text\">requestAnimationFrame()<\/span><\/code>. If you haven&#8217;t used it before, it&#8217;s a nice way to tell the browser to throw to an animation callback when it&#8217;s appropriate to do so. Paul Irish still has <a href=\"http:\/\/www.paulirish.com\/2011\/requestanimationframe-for-smart-animating\/\">the gold standard<\/a> on explaining why you should be using it.<\/p>\n<div class=\"codecolorer-container javascript railscasts\" style=\"overflow:auto;white-space:nowrap;width:100%;\"><table cellspacing=\"0\" cellpadding=\"0\"><tbody><tr><td class=\"line-numbers\"><div>1<br \/>2<br \/>3<br \/>4<br \/>5<br \/>6<br \/>7<br \/>8<br \/>9<br \/>10<br \/>11<br \/>12<br \/>13<br \/>14<br \/>15<br \/>16<br \/>17<br \/>18<br \/>19<br \/>20<br \/>21<br \/>22<br \/>23<br \/><\/div><\/td><td><div class=\"javascript codecolorer\"><span class=\"kw1\">function<\/span> step<span class=\"br0\">&#40;<\/span>timestamp<span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">if<\/span> <span class=\"br0\">&#40;<\/span>last_draw <span class=\"sy0\">===<\/span> <span class=\"kw2\">undefined<\/span><span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; last_draw <span class=\"sy0\">=<\/span> timestamp<span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><br \/>\n<br \/>\n&nbsp; &nbsp; <span class=\"co1\">\/\/ Clear the canvas<\/span><br \/>\n&nbsp; &nbsp; context.<span class=\"me1\">clearRect<\/span><span class=\"br0\">&#40;<\/span><span class=\"nu0\">0<\/span><span class=\"sy0\">,<\/span> <span class=\"nu0\">0<\/span><span class=\"sy0\">,<\/span> CANVAS_WIDTH<span class=\"sy0\">,<\/span> CANVAS_HEIGHT<span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n<br \/>\n&nbsp; &nbsp; <span class=\"co1\">\/\/ Draw the particles<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">for<\/span> <span class=\"br0\">&#40;<\/span><span class=\"kw1\">var<\/span> i <span class=\"sy0\">=<\/span> <span class=\"nu0\">0<\/span><span class=\"sy0\">;<\/span> i <span class=\"sy0\">&lt;<\/span> MAX_PARTICLES<span class=\"sy0\">;<\/span> i<span class=\"sy0\">++<\/span><span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; context.<span class=\"me1\">beginPath<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; context.<span class=\"me1\">fillStyle<\/span> <span class=\"sy0\">=<\/span> <span class=\"st0\">'hsl('<\/span> <span class=\"sy0\">+<\/span> particles<span class=\"br0\">&#91;<\/span>i<span class=\"br0\">&#93;<\/span>.<span class=\"me1\">getColor<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span> <span class=\"sy0\">+<\/span> <span class=\"st0\">', 80%, 70%)'<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; context.<span class=\"me1\">arc<\/span><span class=\"br0\">&#40;<\/span>particles<span class=\"br0\">&#91;<\/span>i<span class=\"br0\">&#93;<\/span>.<span class=\"me1\">getPosX<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">,<\/span> particles<span class=\"br0\">&#91;<\/span>i<span class=\"br0\">&#93;<\/span>.<span class=\"me1\">getPosY<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">,<\/span> particles<span class=\"br0\">&#91;<\/span>i<span class=\"br0\">&#93;<\/span>.<span class=\"me1\">getRadius<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">,<\/span> <span class=\"kw4\">Math<\/span>.<span class=\"me1\">PI<\/span><span class=\"sy0\">*<\/span><span class=\"nu0\">2<\/span><span class=\"sy0\">,<\/span> <span class=\"kw2\">false<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; context.<span class=\"me1\">fill<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"co1\">\/\/ Force particle movement calculations<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; particles<span class=\"br0\">&#91;<\/span>i<span class=\"br0\">&#93;<\/span>.<span class=\"me1\">step<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#40;<\/span>timestamp <span class=\"sy0\">-<\/span> last_draw<span class=\"br0\">&#41;<\/span> <span class=\"sy0\">\/<\/span> <span class=\"nu0\">50<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><br \/>\n<br \/>\n&nbsp; &nbsp; last_draw <span class=\"sy0\">=<\/span> timestamp<span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; window.<span class=\"me1\">requestAnimationFrame<\/span><span class=\"br0\">&#40;<\/span>step<span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n<span class=\"br0\">&#125;<\/span><br \/>\nwindow.<span class=\"me1\">requestAnimationFrame<\/span><span class=\"br0\">&#40;<\/span>step<span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><\/div><\/td><\/tr><\/tbody><\/table><\/div>\n<p>The gist of it is you clear the canvas and then iterate through the list of particle objects to draw them and <code class=\"codecolorer text geshi\"><span class=\"text\">step()<\/span><\/code> them. In this case, I&#8217;ve taken the time delta and scaled it down so it animates at a reasonable rate.<\/p>\n<p>If you&#8217;re not familiar with canvas drawing, these steps are rather uncomplicated. You start be defining a new path, its fill style (our random HSL color), drawing a circle via the <code class=\"codecolorer text geshi\"><span class=\"text\">arc()<\/span><\/code> <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/API\/CanvasRenderingContext2D\/arc\">context method<\/a>, ad then filling it. Easy!<\/p>\n<h2>Party Time!<\/h2>\n<p>And that&#8217;s it! You can check out a <a href=\"http:\/\/timothypoon.com\/blog\/demos\/canvas-particle-physics\/\">live demo<\/a> if you don&#8217;t believe me.<\/p>\n<p>If you have any questions, shout at me in the comments. I&#8217;ll gladly answer anything you&#8217;ve got. It&#8217;s pretty simple stuff, but even simple things are hard the first time you do it. Having someone light the way makes it a lot more digestible.<\/p>\n<p>Bye, Internet friends!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>While I wrote a few years ago about HTML5 canvas particle effects, I&#8217;ve gotten a lot of questions about the effect I have on my new personal site. No, not the crazy swirling thing on the left\u2014we&#8217;ll go over that another time\u2014but the fun little bouncy ball thing. Go ahead and check it out. I&#8217;ll wait. Pretty cool, right? It&#8217;s written entirely without any framework or library like jQuery or D3.js or Three.js. While they&#8217;re pretty handy for compatibility, data visualization, and comprehensive 3D graphics rendering (respectively), I didn&#8217;t have&#8230;<a class=\"read-more\" href=\"https:\/\/timothypoon.com\/blog\/2016\/02\/16\/html5-canvas-particles-revisisted-with-physics\/\">read more<\/a><\/p>\n","protected":false},"author":1,"featured_media":270,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[1],"tags":[15,16,22,18,19],"class_list":["post-268","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-code","tag-html","tag-html5","tag-html5-canvas","tag-javascript","tag-particle-animation","et-bg-layout-dark","et-white-bg"],"jetpack_featured_media_url":"https:\/\/timothypoon.com\/blog\/wp-content\/uploads\/2016\/02\/html5-canvas-particles-revisisted.png","jetpack_shortlink":"https:\/\/wp.me\/p462yg-4k","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/timothypoon.com\/blog\/wp-json\/wp\/v2\/posts\/268","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/timothypoon.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/timothypoon.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/timothypoon.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/timothypoon.com\/blog\/wp-json\/wp\/v2\/comments?post=268"}],"version-history":[{"count":2,"href":"https:\/\/timothypoon.com\/blog\/wp-json\/wp\/v2\/posts\/268\/revisions"}],"predecessor-version":[{"id":271,"href":"https:\/\/timothypoon.com\/blog\/wp-json\/wp\/v2\/posts\/268\/revisions\/271"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/timothypoon.com\/blog\/wp-json\/wp\/v2\/media\/270"}],"wp:attachment":[{"href":"https:\/\/timothypoon.com\/blog\/wp-json\/wp\/v2\/media?parent=268"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/timothypoon.com\/blog\/wp-json\/wp\/v2\/categories?post=268"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/timothypoon.com\/blog\/wp-json\/wp\/v2\/tags?post=268"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}