Animating In Code Using JavaScript

by kirupa   |   17 March 2013

In my Introduction to Animation in HTML tutorial, I mentioned that there are three ways to create an animation. One way is by using the appropriately named CSS animations. Another way is by using CSS transitions. The third and final way is by writing code in JavaScript. If you are a huge JavaScript fan, you'll feel right at home here. If you are not a huge JavaScript fan...well, hopefully you will change your mind once you see all the cool animation things you can do in code that you simply cannot do using CSS.

Why Animate Using JavaScript

When you are animating something in CSS using transitions or animations, your browser does a lot of the actual animating for you. While it may not seem like it, for both transitions and animations, all you really do is just define the starting state and the ending state:

start and end states

 If your animation has keyframes, you define a few intermediate states as well, but that's basically it:

intermediate states

What you have right now is not an animation. You just have arbitrary property values defined at certain points in the animation's life. It is the interpolation of the values between these points that are very important to making the animation work:

animation is ready

It is exactly this sort of work your browser does for you. Life is pretty good when your browser helps you out so much.

When animating via code, you don't get much hand holding from the browser. You define not only the starting, ending, and intermediate states, you also define every single detail of what happens in between. You specify the rate at which property values change. You write the actual code that changes the property values to create the animation. You write the code to handle what happens once your properties hit their final values. End-to-end, you are responsible for every part of your animation's life including the interpolation behavior. This may sound a little scary. You may be wondering why leave the comforts of CSS animations and transitions behind to battle it out in JavaScript territory. The reason is simple.

With animations created in code, you get more control, more variety, and (if you want) more randomness. Try creating curved motion in CSS. You can't do it. If we looked at our earlier example in wireframe with a line indicating its path, this is what you would see:

outlines

Notice that the movement is made up of a series of straight lines. There is nothing you can reasonably do in CSS to change that behavior. Try simulating an object free-falling under the influence of gravity. Try oscillating the values of a property in varying amounts each cycle. Try creating something in CSS that moves as follows:

All of those things I listed are simply not possible using CSS. You need to animate using code, and that's where this tutorial comes in. In this tutorial, you will go where no CSS animation or transition will go. You will learn how to create animations using JavaScript.

Onwards!

Breaking Down a JavaScript Animation

Before we get our hands wet and actually create our own JavaScript animation, let's first understand what happens at a high level. I've generalized JavaScript animations into three stages, and let's look at each one of those stages in detail.

1. Setting up the Initial State

When creating a JavaScript animation, the first thing you do is define the initial values of the properties that you will end up modifying as part of your animation. For example, let's say that your animation consists of altering the opacity of something:

say "hello" to our something!

To specify the initial value of the opacity property, you would have some code that looks as follows:

this.something.style.opacity = 1;

 If applicable, you could also just have something defined in CSS:

#something {
	opacity: 1;
}

The initial state doesn't have to be specified only in JavaScript or only in CSS. Sometimes, you may have a combination of both CSS and JavaScript!

2. Specifying the Property Change

Here is where everything gets interesting. Everything! For the sake of simplicity, let's say our goal is to animate the value of our opacity property on the something element down to 0. You can't just insert some code that looks something like this:

this.something.style.opacity = 0;

This would basically result in your element appearing and immediately disappearing. There would be no animation. More accurately, your something element would actually just never appear in the first place because how of quickly this code would run.

What you want is a gradual reduction in the opacity values:

this.something.style.opacity = .5;
this.something.style.opacity = .45;
this.something.style.opacity = .4;
this.something.style.opacity = .35;
this.something.style.opacity = .3;
this.something.style.opacity = .25;
this.something.style.opacity = .2;
this.something.style.opacity = .15;
this.something.style.opacity = .1;
this.something.style.opacity = .05;
this.something.style.opacity = 0;

What you also want is for this reduction to happen over a period of time:

this.something.style.opacity = .5;
//pause for a few milliseconds
this.something.style.opacity = .45;
//pause for a few milliseconds
this.something.style.opacity = .4;
//pause for a few milliseconds
this.something.style.opacity = .35;
//pause for a few milliseconds
this.something.style.opacity = .3;
//pause for a few milliseconds
this.something.style.opacity = .25;
//pause for a few milliseconds
this.something.style.opacity = .2;
//pause for a few milliseconds
this.something.style.opacity = .15;
//pause for a few milliseconds
this.something.style.opacity = .1;
//pause for a few milliseconds
this.something.style.opacity = .05;
//pause for a few milliseconds
this.something.style.opacity = 0;

What you don't want is to write code that looks like what I've shown above where each new value for the opacity property requires a new line. You want something that is a lot more compact and more along the lines of something like this:

var opacityValue = 1;

function animate() {
	this.something.style.opacity = opacityValue;
	opacityValue -= .05;

	// Let's assume animate will allow the screen to update
	// before continuing
	animate();
}

You should note that if you literally use this code, your animation will not work. The reason is that your animate function will be called recursively without pause.

Despite this function not being functional, working code, the ideas it contains are very relevant. When the animate function is called, it reduces the variable that stores the current opacity, opacityValue, by .05. Once that happens, this function calls the animate function again. This function gets called repeatedly and, with each call, the opacityValue is decreased by .05. Eventually, your opacity will get down to 0.

3. Dealing With the End State

While your animate function may run forever, your animation itself won't without you maintaining the state of the various variables that are changing. There will a come a time, in your animation, when a property you are animating reaches its final value and needs to be reset. For our opacity property, its end is when its value goes below 0. When the opacity goes below 0, reducing the value further won't do anything. Your something element is already invisible. Let's deal with this.

Inside the animate where the opacity value is being decremented, I modify the existing code to continue decrementing the opacity by .05. The only difference is that, now, we reset our opacity property's value back to 1 once it goes below 0:

function animate() {
	this.something.style.opacity = opacityValue;

	if (opacityValue > 0) {
		opacityValue -= .05;
	} else {
		opacityValue = 1;
	}

	// Let's assume magicalLoop will allow the screen to update
	// before continuing
	animate();
}

This code ensures my animation will run forever...and be seen in the process. Once the something element becomes invisible, its opacity gets reset back to 1 and the animation continues. Depending on what property or properties you are animating, you will handle the end state for each one similarly.

Looking at a Real Example

Now that you have an idea of how an animation in JavaScript is structured and setup, let's go one step further and look at a simple example that actually works.

The simple example that we will look at is as follows:

Just like the animation you saw at the beginning, you have a blue donut on a yellow background that is moving. Unlike the animation at the beginning, this one is literally much simpler in what it does. It moves linearly from left to right. There is no bouncing or variations in speed like the initial one, but this is still a useful study in putting what you learned so far into practice.

The markup and code that makes this animation work looks as follows:

<!DOCTYPE html>
<html>
 
<head>
<meta content="en-us" http-equiv="Content-Language">
<meta charset="utf-8">
<meta content="stuff, to, help, search, engines, not" name="keywords">
<meta content="What this page is about." name="description">
<meta content="An Interesting Title Goes Here" name="title">
<title>Move to Click Position</title>
<style>
body {
	background-color: #FFF;
	margin: 30px;
	margin-top: 10px;
}
#contentContainer {
	width: 550px;
	height: 350px;
	border: 5px black solid;
	overflow: hidden;
	background-color: #FFFF00;
}
#thing {
	position: relative;
	left: 50px;
	top: 25px;
}
</style>
</head>

<body>
<div id="contentContainer">
	<img id="thing" alt="the thing" height="300" src="//www.kirupa.com/images/donut.png" width="300">
</div>

<script src="//www.kirupa.com/html5/examples/js/prefixfree.min.js"></script>
<script>
var theThing = document.querySelector("#thing");
var currentPos = 0;

var requestAnimationFrame = window.requestAnimationFrame || 
							window.mozRequestAnimationFrame || 
							window.webkitRequestAnimationFrame || 
							window.msRequestAnimationFrame;
 
function moveThing() {
	currentPos += 5;
	
	theThing.style.left = currentPos + "px";
	
	if (Math.abs(currentPos) >= 900) {
		currentPos = -500;
	}
	
    requestAnimationFrame(moveThing);
}
moveThing();

</script>
</body>
</html>

If you copy and paste all of this into a HTML document and preview in your browser, you should see something that is identical to the example I posted above. Let's look at why it works next.

The full code that makes the donut slide from left to right looks as follows:

var theThing = document.querySelector("#thing");
var currentPos = 0;

var requestAnimationFrame = window.requestAnimationFrame || 
							window.mozRequestAnimationFrame || 
							window.webkitRequestAnimationFrame || 
							window.msRequestAnimationFrame;
 
function moveThing() {
	currentPos += 5;
	
	theThing.style.left = currentPos + "px";
	
	if (Math.abs(currentPos) >= 900) {
		currentPos = -500;
	}
	
    requestAnimationFrame(moveThing);
}
moveThing();

The code provided here follows the three steps that you saw in the previous section. The initial state of the animation along with some setup work is handled in the first three lines:

var theThing = document.querySelector("#thing");
var currentPos = 0;

var requestAnimationFrame = window.requestAnimationFrame || 
							window.mozRequestAnimationFrame || 
							window.webkitRequestAnimationFrame || 
							window.msRequestAnimationFrame;

Our donut image is going to be formally referenced by theThing variable, and the currentPos variable helps store the current position of the donut. The next line returns a pointer to the browser-specific requestAnimationFrame function. This function is the magic detail that helps you to call a function over and over again and have your screen update without locking your code up.

The next set of lines help your donut to actually change its position:

function moveThing() {
	currentPos += 5;
	
	theThing.style.left = currentPos + "px";
	
	if (Math.abs(currentPos) >= 900) {
		currentPos = -500;
	}
	
    requestAnimationFrame(moveThing);
}
moveThing();

You have your moveThing function that starts off by incrementing the currentPos variable by 5. The next thing you see is the currentPos variable value being used to actually set the position of our donut:

theThing.style.left = currentPos + "px";

In order to have an animation, these two lines need to be called many MANY times. What we need is basically a loop. The way we loop moveThing is by using the requestAnimationFrame function.

requestAnimationFrame(moveThing);

The requestAnimationFrame function is quite awesome because it doesn't call the moveThing function immediately and cause your entire application to hang. It calls the moveThing function only as part of when the browser is about to refresh what is visible. This important detail ensures that your application is still responsive while still allowing you to rapidly call your moveThing function to make your animation run.

The frequency at which requestAnimationFrame calls moveThing will vary depending on what else your application is doing and the capabilities of your hardware, but in general it is 60 times a second. That's pretty fast! To learn more about requestAnimationFrame, check out my Animating with requestAnimationFrame tutorial.

The last thing from our code we will look at revolves around what happens once our donut has slid off the screen...you know, the end state:

if (Math.abs(currentPos) >= 900) {
	currentPos = -500;
}

When the value of currentPos exceeds 900, the donut is effectively out of view on the right hand side. To get our donut to loop, we set its position to -500 so that the donut is now outside of the viewing area on the left side of the container instead. Remember, thanks to the loop we have setup with the requestAnimationFrame, we are continuously incrementing the donut's position by 5 pixels. Your donut will be in full view within a few seconds, slide out of view to the right, and start all over back on the left side again.

Going a Little More Crazy

We are in a good spot right now. So far, you learned the three stages of how a JavaScript animation is setup, and (in the previous section) you caught a live JavaScript animation and saw how it worked. There is one problem with the previous example. That sliding donut could easily be done using a CSS animation involving just two keyframes. You don't need to write any code whatsoever for it.

In this section, let's make some alterations to our previous example so that it truly shows off the capabilities of an animation created entirely in code. The alterations will turn your simple sliding donut into the happy bouncing/sliding donut that you saw at the very beginning. To make this happen, reuse the previous example's markup and replace all of the code inside the script tag with the following:

var theThing = document.querySelector("#thing");
var currentPos = 0;
var angle = 0;
var incrementer = .1;

var requestAnimationFrame = window.requestAnimationFrame || 
							window.mozRequestAnimationFrame || 
							window.webkitRequestAnimationFrame || 
							window.msRequestAnimationFrame;

function moveThing() {
	currentPos += 5;
	angle += incrementer;
	
	theThing.style.left = currentPos + 5 * Math.cos(angle) + "px";
	theThing.style.top = 25 + 50 * Math.sin(angle) + "px";
	
	if (Math.abs(currentPos) >= 900) {
		currentPos = -500;
		incrementer = .05 + Math.random() / 2;
	}
	
	if (angle > 2 * Math.PI) {
		angle = 0;
	}
	
    requestAnimationFrame(moveThing);
}
moveThing();

Once you have made these changes, preview in your browser to make sure that your donut image now bounces and slides. There is no reason why it wouldn't do that! After you've changed your script and got your example working, take a few moments and study the revised code. It should look very similar to the code you saw for the simple example in the previous section.

If you feel you have a good understanding of what is going on, let's review the changes and see what we have.

The initial setup is pretty straightforward:

var theThing = document.querySelector("#thing");
var currentPos = 0;
var angle = 0;
var incrementer = .1;

var requestAnimationFrame = window.requestAnimationFrame || 
							window.mozRequestAnimationFrame || 
							window.webkitRequestAnimationFrame || 
							window.msRequestAnimationFrame;

The usual suspects theThing, currentPos, and requestAnimationFrame make their appearance again. They are joined, though, by angle and incrementer who both play an essential role in making our bounce actually work. You'll see them shortly.

With the initial setup out of the way, let's look at our moveThing function that is responsible for making the animation work:

function moveThing() {
	currentPos += 5;
	angle += incrementer;
	
	theThing.style.left = currentPos + 5 * Math.cos(angle) + "px";
	theThing.style.top = 25 + 50 * Math.sin(angle) + "px";
	
	if (Math.abs(currentPos) >= 900) {
		currentPos = -500;
		incrementer = .05 + Math.random() / 2;
	}
	
	if (angle > 2 * Math.PI) {
		angle = 0;
	}
	
    requestAnimationFrame(moveThing);
}
moveThing();

The first part of this function is made up of code that increments the currentPos and angle variables and assigns them to our donut image's left and top style properties:

currentPos += 5;
angle += incrementer;

theThing.style.left = currentPos + 5 * Math.cos(angle) + "px";
theThing.style.top = 25 + 50 * Math.sin(angle) + "px";

Notice what we are assigning to the left and top properties. You have a mathematical expression involving some numbers and the Math.cos and Math.sin trigonometric functions. These two functions are responsible for actually giving your blue donut the bouncing effect that you see. I'll discuss the coolness of using trigonometric functions like Math.cos and Math.sin in a later tutorial, but just know that all the time you spent in school learning about them will be coming in handy!

Once the donut has happily bounced and slid its way out of our view, we get to our end state. I reset the position to have it start all over from the left side of the container:

if (Math.abs(currentPos) >= 900) {
	currentPos = -500;
	incrementer = .05 + Math.random() / 2;
}

One additional thing I do is set our incrementer variable to be randomly assigned a new value. This ensures that our blue donut will slide and bounce a bit differently each time its position gets reset. That's pretty awesome.

Try creating something like that in CSS without writing a lot of JavaScript in addition to it!

Further Reading

What you've seen in this tutorial is just an introduction to animating things using JavaScript. The following articles explore the ideas introduced here further...a lot further:

Getting Help

If you have questions, need some assistance on this topic, or just want to chat - post in the comments below or drop by our friendly forums (where you have a lot more formatting options) and post your question. There are a lot of knowledgeable and witty people who would be happy to help you out

Share

Did you enjoy reading this and found it useful? If so, please share it with your friends:

If you didn't like it, I always like to hear how I can do better next time. Please feel free to contact me directly via e-mail, facebook, or twitter.

Kirupa Chinnathambi
I like to talk a lot - A WHOLE LOT. When I'm not talking, I've been known to write the occasional English word. You can learn more about me by going here.

Add Your Comment (or post on the Forums)

blog comments powered by Disqus

Awesome and high-performance web hosting!
BACK TO TOP
new books - yay!!!