Smooth Movements with Javascript
When we're working with CSS and Javascript, sometimes we want to be able to add smooth movements that feel more natural. In this tutorial, we talk about how to rethink your Javascript code to create a weighted speed so any moving object feels a lot more natural and real
Transcript
(upbeat music)[Rik] On the seed.com site,there's this area down the pagewhere this Petri dish kind of follows your mousearound the page.Now I've just made a quick versionof this, mine's a little bit simplerthat looks like this, so,as you move the mouse around the page,you get this little ball moving towards you,it's also this kind of difference effect on the page, too.So what we'll talk about is how to do this kind of effect,so when we move around the page, the mouse follows us,we'll also then add some kind of speed to it,so it doesn't go there instantly,and then we'll add some effects in there, too.(upbeat music)So quickly just set up a page, very basic page,I've got index.html with a and then awith a class of ball, which is kind of empty,no text in there.And in my style sheet, I've got something fairly basic.I've got my body with Helvetica and the black backgroundand white text, my is in the middle of the pageand shifted back over.I've got a font size of 20vmin,which is dependent on the width of the pageor the height of the page,so 20% of the minimum across or below,and div.ball, background color of white,and then the width, 200 pixels by 200,border radius to make it a circle,and then it's just in the top left corner,and then it's shifted over,so the midpoint is what we're thinking about.So if you look right now,we've got our kind of page here,you shift this up and down,you can see the text getting biggerbecause it's vmin,and then obviously the ball is in the top cornerat zero and zero.Now if we do want to move this around the page,what we need to use is some JavaScriptbecause when I move my mouse,or if I touch the page in a certain way,that's how I want to interact.So what I'm gonna do first of allis add a script.So I'm gonna add the script,I'm gonna call it, what should we call it,let's call it ball.js because it's to do with the ball,and at the moment, I've got my script,but I need to add it into my page,I'm just gonna add a script,and the source of the script is ball.js,now to do this in a kind of very basic way,we're just gonna start by making,whenever we move the mouse around the page,the ball is gonna be instantly at the cursor.So to do this, when I move my cursor around the page,we want to do something,what do we want to do?Well, we want to move the ball dependingon where the cursor is.So that's the first thing you wanna think about,so document.addEventListener,what do we want to listen out for?Well, we wanna listen to how anywhere on the page,the mouse movement.What do we wanna do?Well, we wanna do something, so comma, function,round brackets, curly brackets.Now like usual what we could dois pass in the events, the browser passes in,so more info whenever we do something,I'm gonna call it event,it could be called anything you like,doesn't really matter,and again, I'm just gonna open up my curly bracketsto make it a little bit easier to see what's going on.Now what I'm gonna do is save this to some kind of variable,some kind constant, let's call it a constant to begin with,constant, and let's say mouseX.Now where is the mouse currently?This is currently at the event on the pageX,so in the event that's passed to us,something in there says pageX, with the capital Xis where it currently is.We're just saving it to a constant.The next thing I'm gonna do is have another constantfor mouseY, and this is gonna equal to event.pageY,and what do we wanna do next?Well, we know where the mouse is,but we wanna move the balldepending on where these things are,so the first thing I'm gonna dois find out where the ball is.So I'm gonna save the ball,so I'm gonna save a constant called ball,again I've just made that up,this is gonna equal to, well something in my document,
I'm gonna do a .queryselector,now what do I wanna find,well, what is the thing I would select in CSS,well I'd do "div.ball", so we're gonna use the same thing,now this is in quotes because that isn't a special wordin JavaScript.Next thing I'm gonna do is set this into position.We wanna say, the ball, now we don't need to use const againbecause we just saved it, has a style,and we wanna move the left equal to,well, it's based on the mouseX.
Now this is just number mouseX.We also wanna set a pixel unit,so, + "px"and what we get right now,if I look at the page,if I move anywhere across there,the mouse just goes left and right.We want it to go up and down as well of course,so ball.style.top,and this is gonna equal to mouseY + "px"because we those units in there as well.So now what we get is the balljust follows us around the page.Now the issue that we have thoughis if you want to kind of delay this,we could use some transition,so if I add some transition into the ball right now,let's just say transition,and we'll do all, anything it's gonna do over a second,what we'll get is something a bit weirder,so we get this kind of jerky effect.So basically what's happenedis every single time the ball's transition is resetting,so it's not looking very smooth.Now what we wanna do insteadis actually calculate this using some JavaScript.So what I'm gonna do next is,well, first of all, get rid of the transition,but calculate what this transition should bein JavaScript instead.(upbeat music)
The first thing I wanna do is actually refactor my code.Now if you don't know what refactoring code is,it's basically just cleaning up your code.Now the way that I'm gonna do this isI'm first of all gonna move things around the page.So the first thing I'm gonna dois actually move this ball outside,so I'm gonna save this constant ball,I'm just gonna copy and paste it out here,and again I'm just gonna line that first of all.Now the reason I'm doing thatis because I don't wanna do it just on mouse move,but I also wanna do it if my mouse is stoppedbut I also want to keep animating this page.Remember, I'm not using transitions,so we're gonna use JavaScript to calculate this instead.Now the next thing you wanna dois actually save outside of the mouseX and the mouseY,so I'm gonna change this from constant,we have constant mouse and constant Y,and I'm just gonna move it out here,but these are gonna change as well.So this is gonna change from a constant to a let,now let just means it can be changed,constant means it can't be changed after we've set it.Now obviously here,we always wanna save the ball,it's always gonna be the ball,but mouseX and mouseY outside of this functionare gonna change.Now it's gonna change,it's gonna start by the default being zero,so zero and zero,and then, whenever we move the mouse,we do want it to be the pageX and the pageY,so I'm just gonna put in heremouseX = event.pageX and mouseY = event.pageY,now why have I done it this way,this works exactly the same as what we've just done,so if I go back to the page, it doesn't look any different.But I've just kind of cleaned up my code for laterbecause what I want to do nextis actually make something else.I'm gonna make a new thing outside here called animate.So I'm gonna make a new function,and I'm gonna give it a name called animateand do round brackets and then curly brackets.So whenever I have a functionit's usually round brackets and curly brackets,I'm just gonna open these curly brackets out.Now what I wanna do in hereis then update the ball's position.So whenever I move the mouse,that's the new mouse position,but this animate will run every single frame of the page,we haven't done that just yet, but it will,and then we'll set the new ball position.So I'm just gonna take these two lines outand put them in here,and again just kind of clean that up as well.So now what will happen is if I move on the page,my ball doesn't move.Now why doesn't the ball move?It's because I've not used animate yet,so how do I run animate?I just run animate,oops, spell that correctly, animate().So this sets up the function,and then this runs the function.So, next thing you want to do is see what happens.Again, this doesn't movebecause it runs the first time when we loaded the page,and when we've loaded the pagethen mouseX is zero and mouseY is zero,but this runs just once,so it doesn't ever run again.But we wanna do this on a loop,every single page frame.So in here as well I'm going to dorequestAnimationFrame,and in brackets what I want to dois rerun this function again,so every single frame, just keep running this.Update the mouse position,and to do that I'm just gonna runwhich function we're talking aboutcalled animate.So we don't need the round brackets herebecause it's just gonna run this when it's ready.So this runs instantly, whenever we use round brackets,it says, run now,but this we don't have tobecause this is handling it for us.This is the same code as what we started with,so now if I go back to the page,it looks exactly the same.What we'll do in the next stepis actually add some distanceso that we actually have a little bit of lagto this ball moving around.(upbeat music)So when we're moving the mouse around the page,this is actually gonna be a different positionthan where our ball isbecause obviously if we move very quickly,the ball is gonna take some timeto actually catch up to where the mouse position is.So not only do you want to calculatewhere the mouse position is,we also wanna find what the ball position is.So below here I'm gonna add two new lets.So let ballX = 0 and let ballY = 0.
So at the moment, we're not using thembecause we're sayinginstantly the ball should be at the mouse,so mouseX and mouseY.But what we actually wanna dois say the ball should be at ballX and ballY,so instead here I'm just gonna change thisto ballX and then we'll change to ballY.
But this never updates,so at the moment, ballX and ballY are always zero,so now it doesn't move around the page at all.Now obviously what we wanna dois update the ballX and ballY position instead.So in this animate, what we're gonna dois say, well just for now,we'll say that ballX is equal to exactly the same, mouseX.
So whenever we update the mouse position,whenever we do the frame as well,it's just gonna be the same thing,so ballX and ballY is the same thing, that equals that,and then when we update the ball,it's in the same position.So now, again, we're back to what we had,but what we wanna do is actually add some delay.So what we're gonna dois add some kind of speed, let's call it.So I'm gonna make one new let out here.So let equals speed.Now this is gonna be equal to quite a small number.I'll talk about why it's a small number in a minute.So 0.02, now this works good for me,we can change this later on.What we wanna do is find the distancefrom where the ball currently will beand where the mouse isand kind of add some movement towards the mouse.So what we're gonna do is add one more thing into animate.
So in animate, what we're gonna say is,well, what is that distance?Well, if my ball is over here,and then my cursor's over here,we kinda wanna move it quicklythan if it was close.So the first thing we're gonna do is let distance X,now what was the calculation,what is distX?
Well it's where the mouse currently is, mouseX,minus where the ball is.So if my ball's at zero and my cursor's at 1000,that difference, distX, is 1000.And I also want to do that calculationfor distance Y as well, so mouseY - ballY.Now obviously at the moment this is always gonna be zerobecause the mouse and the ball are at the same place.But instead of them always being in the same place,what we wanna do is calculate where it should be next.And the way that we do thatis instead of this being mouseX or mouseY,we're just gonna change this to, well,where it currently is,but let's also do a little bit of the distance towards it.So plus, and we'll do this in brackets,(distX * speed)and we'll do the same thing for Y as well.ballY + (distY * speed) too.
So basically what we're doing hereis we're saying find out where you currently are,then find some of the distanceand times it by some factor,in this point, 0.02.
Now what we'll get nowis we'll see something that looks a lot smoother.Now if I do want to change that speed,all I need to do is change that.So the quicker, or the higher number,the quicker it'll move towards the ball.So for instance if I do 0.1,this will feel very, very quick.Whereas if I do 0.01, which is ten times as slow,what we'll get is something that moves a lot slower.But we get something that looks a lot smootherthan when we did it with transitions earlier.All we've done is a little bit of math.All we said is work out the distancewhere the mouse is currentlyand where the ball is currently,then update the ball's position where it currently is,but add some of that distance and times it by a factor,and then all we're doing is updating the ball's position,and we keep looping on this over and over again.Then later what we're doing is we're saying,if the mouse is moving, update the mouse position,and then when we loop this again,it just recalculates things.What we'll do next is we'll add some extrasto show you some of the CSS things that we can do as well.(upbeat music)
In my final design,I've actually got this kind of effectwhere it kind of does the inverse,kind of almost like a spotlight effect,so how do we actually do that?Well at the moment, what I've got right nowis a white circle over white text.All we need to do to add that inis actually in style, it's a CSS feature.What we're gonna do on our ballis just add one extra thing in here,and that extra thing is similarto what we do with Sketch or Photoshop or Figmais say mix-blend-mode,so the blending is the complete opposite,so the difference between the two,and as soon as we do that,all we'll see is just, here we go, there it is,so we're just doing the difference of the two.Now, if I wanted to do any kind of effectsto the size of the circle,let's say we kind of wanna just expand it,almost like a heartbeat style,how would we do that.Again, this is can be done in CSS as well.We can add in something like a keyframe,keyframes, sorry, plural.And we wanna do something called a heartbeat.Now what we wanna do here is actually change the scaleso it's a little bit bigger,and to usually do that, we'd add in the transform.Now we're already using transform,so we don't wanna override it too much.So we're gonna start off at zeroand say zero is transform.We're gonna keep the translate(-50%, -50%)which is already there,but also add a scale of one.So that's a zero, it starts off as zero,now at 50%, I'm just gonna copy this underneath,at 50% the scale will go to,I'm gonna exaggerate this quite a lot, but 0.5,and then that 100% back to normal, which is 1.
So it goes from 1 to 150% to 100%.Now to add this keyframe into the ball,all I'm gonna do is add the animation,what is the animation called,well this is called heartbeat,how long do we want this animation to go over,let's say five seconds,we could shorten down to make it quicker,and how often do we want to do this,well we wanna do it infinitely,we wanna keep looping over this.So let's see how that looks.So now what we'll seeis you can see it kind of breathe in, in and out,there it goes, up and down.If we wanna do this a little bit quicker,we can just change that five seconds to be even shorter,so say, one second, so it's really, really quick.
And you can see again really big, really, really quick.So if we want to addany of these kind of CSS things in here,it's pretty straightforward to do as well.(upbeat music)