Particles JS Effect with Pure Vanilla JavaScript | Animated Background Tutorial with Examples

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
Hi everyone. Welcome to another video in my canvas animation series, where we use HTML canvas element and pure vanilla JavaScript to create all different kinds of interactive animated backgrounds. The purpose of this tutorial series is to show you how to create animations you can use for your website, show off on your personal portfolio or just to practice your coding skills. So in this video we will build this beautiful animated effect ... how about now is it better? Don't worry that was just my first attempt. I have gone through many many attempts before achieving this. Creating this one in pure vanilla JavaScript with no libraries was kind of a challenge but I figured it out and I will share all the techniques with you in this tutorial. In this video we will build this amazing popular animation you see on the screen right now from particles js website, but we will do it with no libraries, just pure vanilla JavaScript. We will build all the functionality from scratch so we have complete control over the code and we will be able to customize it in any way we want .Don't forget to like the video if you like my stuff and want me to make more, subscribe to the channel and click the bell icon to get notified when I release a new video. Just so you know I listen to your feedback this video was not my idea. In this episode I was going to show you how to draw stars on canvas. thanks Will. Also, I was asked why don't I use ES6 classes instead of constructor functions for this series and there isn't really any reason not to use classes so in this video that's what we will do. Although I should say I still believe everyone who is serious about JavaScript should understand constructor functions first, because ES6 classes are just a new way to do the same thing. They are so-called "syntactic sugar" over function constructors, underneath JavaScript still does the same thing. Functionality stays the same under the hood, classes are just a different syntax which is easier to work with for people come into JavaScript from different programming languages. This is the third video in my vanilla JavaScript and HTML canvas animation series, if you missed the previous episodes you should see the links on the screen right now or you can find it in the video description down below. You might have noticed that the complexity is increasing in with each video, this one will definitely be the most complex one yet, but the result will be worth it so stay with me. I try to make my videos beginner-friendly while also keeping them interesting for advanced developers so if you think I'm going too fast or too slow please let me know in the comments. This is a new channel and I can use your feedback. To create this animation we have three problems to solve we have not encountered in this series yet. First is collision detection with a circle around the mouse. Previously we did only square, which is slightly easier and more intuitive I think. Second, every particle needs to be aware of every other particles current location to decide if they are close enough to be connected with a line. For this one we will need to use "nested loops", which means loop inside of another loop, and we will create one quite complex if statement. Third, if you notice the line connecting the dots is not the same all the time. it animates from being invisible to being fully visible the closer the particles are together. Without this you will get very jiggly effect as the lines snap in and out quickly, like you saw in my first attempt. Also if you stay until the end of the video as usual I will show you a few ways you can modify and customise this effect and create your own unique animations. Let's start. In index.html we link our style.css and script JS files and create html5 canvas element with an ID of "#canvas1". In style.css file we set basic reset rules so we don't get unexpected behaviour in different browsers. We set our canvas to cover the browser window and give it a radial gradient background. Radial gradient is a progressive transition between two colors in a shape of a circle, so the colors are coming from the center of our canvas. That's it for the index HTML and style CSS files, everything else will be done in our JavaScript file. First we declare basic canvas variables. I will target the canvas element with "getElementById" and save it in a constant variable I called canvas. Then we set our context (shortcut CTX) variable with canvas get context 2d. We set canvas width and height to the current window size and declare particle array variable which we will later use to store our randomised particles. We will also need mouse position. I will create custom object I called mouse. Give it X&Y properties and set them to null for now. Also we will give it radius property, which will determine the size of an area around the mouse in which the particles react to it. I want that area to scale depending on canvas size so that's why you see the simple formula there. You can also use static number but you will have to experiment with it a bit to get it. I did a lot of trial and error testing while preparing for this tutorial. To get the current mouse position we will create an event listener for "mousemove". This will fire every time user moves the mouse. This listener has access to the event object, which we will need. I will set mouse x to event.x and mouse y to event.y. Now we create a class for particle. We will use it to create a randomized particle object every time we call it with the "new" keyword. This is how we fill our particle array with individual particles with randomized values. As I said before JavaScript classes are "syntactical sugar" over prototype based inheritance, that was introduced with ES6 in 2015. In the previous videos we use constructor functions, now we are doing the same thing just with a slightly different simplified syntax. We declare the constructor which is a special method for creating and initializing an object created with a class. Each particle will need x and y coordinates, these are different and independent from mouse x and y coordinates so don't confuse the two. DirectionX and directionY, which will hold the value for number of pixels our particles animate each step along the x and y axis. This can be a positive or negative number as the particles will be bouncing back and forth around the canvas. Each particle will also need size and color properties. Now we create a method that will draw individual particle. We will be calling it over and over from our update function I will create soon. it will be called for every particle for every frame of our animation, after we calculated particles current position and mouse interactions. This method will just draw a regular circle on canvas. We use arc method and give it current x and y coordinates and particle size. Another method we will create on our class is update. It's a custom method so you can call it whatever you want. In here I will check the current particles position, check mouse position, move the particle accordingly and call .draw() method from here, once we know where to draw the particle. As the particles are basically bouncing around the canvas we will first check if the particle has reached the edge of the screen. If it has we will reverse its directionX or directionY value, to make it animate in the opposite direction. I've already explained this in the previous videos. Now we need to check if the current mouse position overlaps with the current particle position. We call this "collision detection". In previous videos we checked for collision in a square around the mouse, so basically just if the particle was within certain distance from the mouse on the x and y axis. Now we want to do the same thing, but we want the area to be a circle. To do that we take two center points of our circles one is the center of our particle the other one is the mouse cursor. We check in the distance between two center points is less than two radii added together. Mouse radius is declared in our mouse.radius variable particle radius is it's this.size value because that's what we used in canvas "arc" method to draw our particles as circles. To calculate that we use this common formula. "dx" is the difference between the current mouse position and the particles position on the x axis, and "dy" is the difference between mouse position and particle position on the y axis. Then we calculate the distance by taking square root from dx times dx plus dy times dy. As I said now we compare radii of both circles and check if they are bigger than the distance variable. If they are smaller that means our particles are colliding, so if the distance is smaller than mouse radius plus particle radius represented here by this.size value, we have a collision. Inside this if statement we need to do additional checks to see which side the particle is coming from so we can decide which direction we want to push it. Since we are nesting "if" statements these checks are only done for colliding particles. First we check if mouse.x is smaller than this.x, which is particles current position. If that's true we know the mouse is currently to the left of our particle and we will push the particle to the right. Yes. Which means in plus direction on the x-axis. We also want to check if the particle is far enough from the edge of our canvas to make sure we don't push it over the edge, because it will get stuck there. I chose buffer area of particle size this.size * 10 around the canvas. If the particle is closer to the edge then 10 times its size (actually it's radius - half circle) we will not push it any further. We need to do this for all four sides we check to see if the current mouse coordinates are bigger or smaller than particles position on the X and Y axis and push particles in the appropriate direction so it appears like they are being pushed away from the center of our mouse radius circle. As we push the particles around we also check if there is a buffer of "particle size times 10" between its position and the edge of the screen for all four sides - top, bottom, left, right. After we have checked all of this we will move the other particles that are currently not colliding with the mouse, along their x and y axis by adding their directionX and directionY value to their X&Y coordinates and then we draw it by calling this.draw(). Keep in mind that the entire update method will run for every particle separately over and over for every step of our animation. Now we need to create a function that will randomize values for each particle and push it into our particle array. I call that function "init". First we take a "particleArray" variable we declared on top and assign it to an empty array in case it's not empty at the moment. Then we calculate a number of particles from the current canvas dimensions the bigger canvas the more particles we create. We save that into "numberOfParticles" variable. First we declare size because we will need its value to calculate x and y-coordinates. Size will be a random number between 1 and 5. X and Y coordinates will be a random number between 0 and canvas width and height with particle size value as a buffer around the canvas to make sure we don't get stuck in a wall. DirectionX and directionY, which basically determine how many pixels the particles animate each step in our "update" function (so that's our movement speed) will be random number between "-2.5" and "+2.5" and we set a color as well. Then with the "new" keyword we will use particle class constructor we declared earlier to create a particle object with our randomize values and use array push method to push it into our empty particlesArray. "for" loop will do this over and over until we reach the number defined by the numberOfParticles variable. We will also need animation loop. I will call this function "animate". I will use requestAnimationFrame API for smooth animation. Clear rectangle method with our canvas dimensions to clear the old canvas paint in every step and "for" loop that will call the update method for each individual particle. Update method if you remember, checks if the particle collided with the wall or mouse, updates particles coordinates accordingly and draws it. Now I call "init" to fill our array with randomized particles and I call "animate". Now you can see we already got something going on. Particles are bouncing around the canvas and react to the mouse. There are few bugs here, we will deal with that a bit later. We want to check if particles are close enough to draw a line between them. I will build another function and call it connect. We will use nested loops for this. First we will cycle through variable "a" and inside we will cycle through variable "b". Variable "a" will represent each individual particle in our array and a variable "b" will represent all the consecutive particles in the same array. You can see the inner loop says b equals a. We need to do this to allow us to compare their x and y coordinates and calculate their distance. Basically outer loop will take every particle in our particlesArray one by one and for each of them it will run the inner loop with "b" variable against every other consecutive particle. What we're doing here basically is 1 compared to 2, 1 compared to 3, 1 compared to 4, 1 compared to 5... until we reach the length of the array and we exit the inner loop, outer loop will set "a" to a value of "2" and we enter the inner loop again - 2 compared to 3, 2 compared to 4, 2 compared to 5... I'm not sure if I'm explaining this clearly. Basically it's a lot of calculations and these need to take place for every single frame of our animation, so be careful, if you create too many particles you can give your computer a hard time. I will save this value in a "distance" variable because we will need it for one more thing later. For now we check if the distance is smaller than canvas width divided by seven times canvas height divided by seven. I came up with these numbers by trial and error if you divide the canvas by a smaller number you will get longer lines but more distant particles will be connecting, so this will also affect your performance. You can experiment and find the right balance and effect you like. You can also use a static number here, but I prefer the lines to get longer on larger screens. I want this effect to be dynamic. So for each pair of particles that are close enough to each other we enter the"if" statement. We set stroke color, line width and draw a line from the first particles X and Y coordinates to the second particles X and Y coordinates. I think I made a few typos here. It is spelled "particlesArray" with an S but I spelled it "particleArray" , let's quickly fix that. Now in our animate method, we call "connect", so this entire monsters function will run for every frame of our animation. There's a problem somewhere. Yeah misplaced parenthesis. That's better. Let's move the connect function up to stay organized. We are not done yet. There are few things I don't like about this animation still. We need to polish it up a bit. First problem is that the canvas stretches when we resize our window. To fix that I will create an event listener for window resize event and every time user resizes the browser we will set the canvas width and height to the new innerWidth and innerHeight and we will recalculate mouse radius, as we want bigger radius for bigger canvas size. Then we call "init" to redistribute our particles randomly in the new canvas dimensions. Another problem is that the particles interact with the mouse even when we leave the canvas, because that area becomes the last known mouse position. I will create another event listener for "mouseout" event and I will set mouse x and mouse y as undefined. Now it's fixed. Setting it to null would be a better practice, but for some reason it's not working for me. Right now you can see the lines appear and disappear quickly. Snap in and out with no animation. I would prefer if they were animated as well. To do this we can go up to our custom connect function and create a variable called "opacityValue". I will set it to 1, then down in the "if" statement we will set the value dynamically to 1 minus distance divided by 20,000. I got this number by trial and error. In stroke style we just concatenate the value to our RGBA color declaration. Now the line is at full opacity of 1 while the particles are closed and slowly grows invisible as the distance between the particles grows. Let's add more particles so you can see that the mouse collision area is is a circle. So that's all done for the basic effect. In case you are wondering HTML canvas is well supported now and this code will work in all browsers including Internet Explorer. This video is running long already. I will create another one to show you how to customize this effect. There are few things I want to show you with this one. Links should be on the screen right now and in the description down below. Except for the obvious modifications like changing particle size, color, line width, line length, particle shape and so on with this one we have many more options. I will show you how to modify this code and split the canvas and particles by colors, how to create "sunrays" effect, breaking particle trail that follows the mouse around, "vacuum-cleaner" effect and more. Thank you very much for watching, don't forget to like the video to let me know you like this type of content. Subscribe to the channel and click the bell icon to get notified when I release a new video. Also while you're here you can check out some other content on my channel. For example do you know how to create this effect with pure CSS? See you next time! <3
Info
Channel: Franks laboratory
Views: 108,492
Rating: undefined out of 5
Keywords: particles.js, particlesjs, particles js, particle.js, particles.js tutorial, html canvas, vanilla javascript, pure javascript, animation, background
Id: d620nV6bp0A
Channel Id: undefined
Length: 19min 30sec (1170 seconds)
Published: Fri Sep 27 2019
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.