Drawing particles using HTML5 Canvas

ByRaphael Amorim in

Canvas is one of the most fun features of HTML5. The amount of cool things that can be created is absurdly giant. However, many people find it difficult to learn. But the truth is that it is not. Of course, having a good geometry background is very important. But if you do not know much you can create very simple things to go further. See this example:


In your HTML file create a simple structure and add a tag canvas with a random class. For this article, the class name will be “particles”. Before closing the tag body, call the JavaScript file, which is named “particles.js”.

<canvas class="particles"></canvas>
<script src="particles.js"></script>

Then, in particles.js, let’s start canvas magic! I’ll explain the code by parts for better understanding – The code is available on GitHub. First, add a function to match the onload window event and select the body and the canvas on it, and apply some styles to the elements. Note that there is no CSS file. I chose to set the styles within JavaScript, but you can do it the way you want. We also define the update function, which will run from a certain range.

window.onload = function() {
 var body = document.querySelector(‘body’);
 body.style.background = ‘#2C2C44';
 canvas = document.getElementById(‘particles’),
 ctx = canvas.getContext(‘2d’);
 body.style.margin = ‘0px’;
 canvas.style.margin = ‘0px’;
 canvas.style.padding = ‘0px’;
 canvas.width = canvas_width;
 canvas.height = canvas_height;
 draw = setInterval(update, speed);

After that we define some variables, such as the speed of events and canvas size. But keep it clear that it is not good to use global variables, but this use in this experiment is justified by teaching purposes. In this project there is no use of requestAnimationFrame, but I recommend taking a good look on it. With this resource the browser can optimize simultaneous animations in a single stream and reassemble all cycle, leading to greater animation fidelity. For example, serves very well in synchronized animation with CSS or SVG SMIL transitions.

In addition, animations Javascript-based where a animation loop is running on a tab that is not visible, the browser will not keep it running, which means less use of CPU, GPU and memory, leading to much longer battery life. This link provides a good study source for requestAnimationFrame.

// Settings
 var speed = 35,
 canvas_width = window.innerWidth,
 canvas_height = window.innerHeight;

Then there is the definition of other global variables to define a instance in canvas, the number of times that particles have been created, a limit for particles, a list of particles that were created and the colors used. Again, it is not recommended the use of global variables; the computational cost is usually quite high and the application becomes less organized. One of the few cases when applying global scope as variables is advantageous is when the data is constant.

var canvas,
 times = 0,
 limit = 100,
 particles = [],
 colors = [‘#F0FD36', ‘#F49FF1', ‘#F53EAC’, ‘#76FBFA’];

If we are creating something that needs randomness in position, size and color of a particle, why not use a function to deliver this data? This is not the best solution, but it is very practical and easy to understand.

var getRand = function(type) {
 if (type === ‘size’)
 return (Math.floor(Math.random() * 8) * 10)
 if (type === ‘color’)
 return Math.floor(Math.random() * colors.length)
 if (type === ‘pos’)
 return [
 (Math.floor(Math.random() * 200) * 10),
 (Math.floor(Math.random() * 80) * 10)
 return false

Okay, now let’s create a generic function to create particles using as a basis the incoming arguments.

var drawParticle = function(x, y, size, color, opacity){
 ctx.globalAlpha = opacity;
 ctx.arc(x, y, size, 0, 2 * Math.PI);
 ctx.fillStyle = color;
 ctx.strokeStyle = color;

Remember the update function? The one that was set to run in setInterval within the loaded function in the onload event window? In such a function happens the “magic drawing” of the particles, besides controlling the limit of the particles. Note that for each particle designed, it is also saved an object with individual information on the particle in the particle list.

function update(args) {
var color = colors[getRand(‘color’)],
pos = getRand(‘pos’),
size = getRand(‘size’),
opacity = 1;
drawParticle(pos[0], pos[1], size, color, opacity)
particles.push([pos[0], pos[1], color, opacity, size]);
if (times >= limit) {
draw = setInterval(clean, speed);

So far, the experiment only creates particles on the screen, but when it reaches the limit, it does stop.

There is a function named clean, which is executed when the particle limit is reached within the execution of the update method. In this role it performs the reading of each particle and updates its opacity at a lower value as above, all running for a time period defined above, giving a visual effect of particle fadeOut.

function clean() {
 ctx.clearRect(0, 0, canvas_width, canvas_height);
 particles.forEach(function(p) {
 p[0] = x,
 p[1] = y,
 p[2] = color
 p[3] = globalAlpha,
 p[4] = size
 p[3] = p[3] — 0.06;
 drawParticle(p[0], p[1], p[4], p[2], p[3])
 if (p[p.length — 1] &amp;&amp; p[3] &lt;= 0.0) {
 ctx.clearRect(0, 0, canvas_width, canvas_height);
 times = 0;
 particles = []
 draw = setInterval(update, speed);

Now you can run the experiment in your browser. You will see a simple canvas (you can view it running here too). This code needs refactoring and if you want you can send a Pull Request on GitHub.

Leave a comment! 0

read more