HTML5 Canvas Particle Animation
UPDATE: yes, I know some people out there will see some flickering when viewing the demo. This is because a) I didn’t implement a double buffer, and b) there is no built-in canvas support for double buffering. There is a very simple solution, but I’ll save that for another time.
Having never really been a user of Apple products, I guess it’s not all that surprising that I’ve never been to the MobileMe website. However, after Googling something like the lines of “most popular e-mail providers,” I came across its login page and was blown away.
Holy moly, that looks amazing. Not only is the design great and the colors are just about perfect, but those little sparkles are crazy! They move in what appears to be 3D space, pulsing from behind the cloud to further into the background amongst and into (while highlighting) the iPads and iPhones, and follow your mouse movements for extra fun.
After poking around the source and giving up on 100% comprehension, I decided it might be fun to take a whack at my own thoroughly underwhelming homage to the MobileMe page.
The Setup
For some reason or another, I decided to make a night scene of some mountains and grass for some stars to streak across (I also threw in some parallax, but that’s for another post). Here’s what I’m starting out with prior to any canvas magic:
And here’s the accompanying code to make that happen (it’s pretty simple, but I’m including it anyways so as little is left out as possible):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | #container { overflow:hidden; position:relative; } #pixie { z-index:0; background:-moz-linear-gradient(top, #040429, #257eb7); background:-webkit-gradient(linear, left top, left bottom, color-stop(0%,#040429), color-stop(100%,#257eb7)); } #mountains, #grass { width:100%; position:absolute; bottom:0; } #mountains { height:156px; z-index:1; background:url(mountains.png) repeat-x 0 0; } #grass { height:62px; z-index:2; background:url(grass.png) repeat-x left 10px; } |
1 2 3 4 5 |
But that’s child’s play compared to what you really came here for: HTML5 canvas! (You should note, though, that the actual height and width attributes of the canvas element must be set in the HTML or dynamically through JavaScript and not just the CSS, otherwise you’ll get something…weird)
The JavaScript
What first needs to happen is setting up the drawing environment. This includes grabbing the appropriate elements and getting the drawing dimensions.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | var WIDTH = window.innerWidth, HEIGHT = window.innerHeight, MAX_PARTICLES = 100, DRAW_INTERVAL = 60, container = document.querySelector('#container'), canvas = document.querySelector('#pixie'), context = canvas.getContext('2d'), gradient = null, pixies = new Array(); function setDimensions(e) { WIDTH = window.innerWidth; HEIGHT = window.innerHeight; container.style.width = WIDTH+'px'; container.style.height = HEIGHT+'px'; canvas.width = WIDTH; canvas.height = HEIGHT; } setDimensions(); window.addEventListener('resize', setDimensions); |
This ensures that on window resizes, everything gets set again and updated to the new dimensions. You can also tinker with MAX_PARTICLES
and DRAW_INTERVAL
to your liking.
Next up is the Circle
object. It contains the bulk of the logic of how the particles will behave.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | function Circle() { this.settings = {ttl:8000, xmax:5, ymax:2, rmax:10, rt:1, xdef:960, ydef:540, xdrift:4, ydrift: 4, random:true, blink:true}; this.reset = function() { this.x = (this.settings.random ? WIDTH*Math.random() : this.settings.xdef); this.y = (this.settings.random ? HEIGHT*Math.random() : this.settings.ydef); this.r = ((this.settings.rmax-1)*Math.random()) + 1; this.dx = (Math.random()*this.settings.xmax) * (Math.random() < .5 ? -1 : 1); this.dy = (Math.random()*this.settings.ymax) * (Math.random() < .5 ? -1 : 1); this.hl = (this.settings.ttl/DRAW_INTERVAL)*(this.r/this.settings.rmax); this.rt = Math.random()*this.hl; this.settings.rt = Math.random()+1; this.stop = Math.random()*.2+.4; this.settings.xdrift *= Math.random() * (Math.random() < .5 ? -1 : 1); this.settings.ydrift *= Math.random() * (Math.random() < .5 ? -1 : 1); } this.fade = function() { this.rt += this.settings.rt; } this.draw = function() { if(this.settings.blink && (this.rt <= 0 || this.rt >= this.hl)) { this.settings.rt = this.settings.rt*-1; } else if(this.rt >= this.hl) { this.reset(); } var newo = 1-(this.rt/this.hl); context.beginPath(); context.arc(this.x, this.y, this.r, 0, Math.PI*2, true); context.closePath(); var cr = this.r*newo; gradient = context.createRadialGradient(this.x, this.y, 0, this.x, this.y, (cr <= 0 ? 1 : cr)); gradient.addColorStop(0.0, 'rgba(255,255,255,'+newo+')'); gradient.addColorStop(this.stop, 'rgba(77,101,181,'+(newo*.6)+')'); gradient.addColorStop(1.0, 'rgba(77,101,181,0)'); context.fillStyle = gradient; context.fill(); } this.move = function() { this.x += (this.rt/this.hl)*this.dx; this.y += (this.rt/this.hl)*this.dy; if(this.x > WIDTH || this.x < 0) this.dx *= -1; if(this.y > HEIGHT || this.y < 0) this.dy *= -1; } this.getX = function() { return this.x; } this.getY = function() { return this.y; } } |
The first line is some settings for each particle, each of which is named in a pretty self-explanatory manner.
- time_to_live – used to calculate hl–or the half-life–of each particle
- x_maxspeed and y_maxspeed – defines the maximum number of pixels a particle can move each frame
- radius_max – maximum radius a particle can achieve
- rt – used in conjunction with hl to determine how the ratio of maximum speed and full opacity of each particle in each frame
The reset()
function just sets up the particle in a new location if it’s the first iteration or if random is set to true and the move()
function just moves the particle according to the settings (you’ll notice I have them moving faster as they get smaller and more transparent). The good stuff comes in the draw()
function.
Within draw()
, you see that a new path is started for each particle and drawn into a circle with the arc() function. Normally you would use this just to draw an arc, but by supplying 2Π, or the radian equivalent to a full circle, as the fifth argument, you get a circle.
Then you can call createRadialGradient() to fill in the circles we just created with color, which I have set with three color stops at various opacities to really make the particles look like they’re glowing. You should note, though, that the con and g variables are set outside of the Circle object and treated as member variables.
Animating the Particles
Finally, you need to create all of the particles and iterate through each one to move and render:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | for (var i = 0; i < MAX_PARTICLES; i++) { pixies.push(new Circle()); pixies[i].reset(); } function draw() { context.clearRect(0, 0, WIDTH, HEIGHT); for(var i = 0; i < pixies.length; i++) { pixies[i].fade(); pixies[i].move(); pixies[i].draw(); } } setInterval(draw, DRAW_INTERVAL); |
The first part creates each new particle (or Circle()
in this case) and stores it in an array. We then set a function to run at a certain interval based on what frames per second we desire to run at.
The draw()
function simply iterates over the array and calls each necessary function of each particle to animate its movement. It’s necessary, though, to point out the clearRect()
call. Without it, you wouldn’t get an animation of moving stars in the night sky but rather streaking purple circles.
With any luck, you should get something like this:
This is a very base attempt at particle animation with HTML5′s canvas element. You can do a lot of other, crazier things with canvas, but this is a good place to start understanding how it works and how to get animated things moving with JavaScript.
You can also click and drag left and right on the screen to get some parallax going between the mountains and the grass. I’ll go into detail on how to achieve that effect later on in life at some point maybe perhaps.
View the demo (requires you to be running an HTML5-capable browser).
hey bro,
I am Priyanshu chandra a C# and python programmer and know as (Html, css, w3.css) a litle bit..I decided to make my website for blog and for my book…But, reallly had no idea how to make a prefect web…for my blog and book..your site helped me a lot…and love you soo much bro
Excellent post. Keep writing such kind of info on your page.
Im really impressed by it.
Hey there, You’ve done a great job. I’ll definitely digg it and for my part suggest to my friends.
I’m sure they’ll be benefited from this website.
Hurrah, that’s what I was exploring for, what a material!
present here at this webpage, thanks admin of this web
site.
Thanks , I’ve recently been looking for info about this topic for
a long time and yours is the best I’ve discovered so far.
But, what in regards to the bottom line? Are you positive concerning the supply?
halo guys kali ini aku dapat memperkenalkan aplikasi hack slot online terakhir untuk Anda semua aplikasi ini adalah rancangan akhir yang mampir dari kami, tim kita di dedikasikan untuk semua pemain slot
yang ada di Indonesia. Sebagai hacker, kita terlampau paham keluhan yang Anda
alami sepanjang ini. Karena awalannya aku bukanlah korban dari permainan slot online.
Namun, aku dan tim mempelajari sistem bermain slot online.
Thank you a lot for sharing this with all folks you really understand what you are speaking approximately!
Bookmarked. Please also consult with my website =). We may have
a link trade contract among us
Thanks in support of sharing such a pleasant idea, article is good,
thats why i have read it completely
Hello
YOU NEED HELP TO BUILD SEO BACKLINKS FOR: timothypoon.com ?
WE SELL HIGH-QUALITY DOFOLLOW POWERFUL BACKLINKS WITH HIGH DOMAIN AUTHORITY, PA, TF, CF…
► Rank Higher In Google (google backlinks, DoFollow backlinks, SEO DoFollow backlinks)
► Rank Higher Video in Youtube & Google (youtube backlinks, video backlinks, video embedded)
► Rank Higher GMB In Google Maps (Google maps backlinks, GMB maps backlinks, GMB embedded, NAP embedded)
► Rank Higher Images In Google (google images backlinks, google backlinks)
You Can Increase Traffic to your websites which will lead to a higher number of customers and much more sales for you.
CLAIM YOUR FREE TEST HERE => http://trentonlvci19876.bloggerbags.com/11147340/get-quality-powerful-backlinks
Thanks, Raul Hecht
[…] Animación de partículas de lienzo HTML5 […]
Not each website is offered at a fair worth, so be prepared to
spend a lot of time researching websites for sale.
post any free guest post on iCiuta for a high quality backlink
Appear at some of my older posts and you will notice that they have tens of comments.
Actuakly when someone doesn’tunderstand after that its up to other users
that they will help, so here it occurs.
You might think It’s the end of your life. Addiction can be fought with the help of experts.
I would definitely recommend them with someone out
there who is in despair. Achieve sobriety here.
Thanks , I have just been looking for info approximately this subject for ages and yours is the greatest I’ve discovered so far.
But, what about the bottom line? Are you certain about the source?
It was hard enough, it’s crazy to know that I still used
it for a month after finding my sister died from an overdose of fentanyl.
That’s how hard this thing is. It wasn’t easy to take the first step,
even after that. Don’t ever underestimate the power of addiction. I did what I had to do.
I can’t be in the same situation as my sister. I still have the chance to live to my fullest.
Look for the glory casino’s
presence on platforms like Instagram and Telegram (@glorycasino_official).
clear plastic storage box small [kindersen.wordpress.com]
A really good credit rating can easily assist you secure lower rates for Car insurance
in Pasadena TX. Financial accountability is actually frequently
awarded with even more economical premiums for Car insurance coverage in Pasadena TX.