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