## A Quick Look Into The Math Of Animations With JavaScript

Advertisement

In school, I hated math. It was a dire, dry and boring thing with stuffy old books and very theoretical problems. Even worse, a lot of the tasks were repetitive, with a simple logical change in every iteration (dividing numbers by hand, differentials, etc.). It was exactly the reason why we invented computers. Suffice it to say, a lot of my math homework was actually done by my trusty Commodore 64 and some lines of Basic, with me just copying the results later on.

These tools and the few geometry lessons I had gave me the time and inspiration to make math interesting for myself. I did this first and foremost by creating visual effects that followed mathematical rules in demos, intros and other seemingly pointless things.

There is a lot of math in the visual things we do, even if we don’t realize it. If you want to make something look natural and move naturally, you need to add a bit of physics and rounding to it. Nature doesn’t work in right angles or linear acceleration. This is why zombies in movies are so creepy. This was covered here before in relation to CSS animation1, but today let’s go a bit deeper and look at the simple math behind the smooth looks.

### Going From 0 To 1 Without Being Boring

If you’ve just started programming and are asked to go from 0 to 1 with a few steps in between, you would probably go for a `for` loop:

``````for ( i = 0; i <= 1; i += 0.1 ) {
x = i;
y = i;
…
}``````

This would result in a line on a graph that is 45 degrees. Nothing in nature moves with this precision:

A simple way to make this movement a bit more natural would be to simply multiply the value by itself:

``````for ( i = 0; i <= 1; i += 0.1 ) {
x = i;
y = i * i;
}``````

This means that `0.1` is `0.01`, `0.2` is `0.04`, `0.3` is `0.09`, `0.4` is `0.16`, `0.5` is `0.25` and so on. The result is a curve that starts flat and then gets steeper towards the end:

You can make this even more pronounced by continuing to multiply or by using the “to the power of” `Math.pow()` function:

``````for ( i = 0; i <= 1; i += 0.1 ) {
x = i;
y = Math.pow( i, 4 );
}``````

This is one of the tricks of the easing functions used in libraries such as jQuery and YUI, as well as in CSS transitions and animations in modern browsers.

You can use this the same way, but there is an even simpler option for getting a value between 0 and 1 that follows a natural motion.

### Not A Sin, Just A Natural Motion

Sine waves2 are probably the best thing ever for smooth animation. They happen in nature: witness a spring with a weight on it, ocean waves, sound and light.
In our case, we want to move from 0 to 1 smoothly.

To create a movement that goes from 0 to 1 and back to 0 smoothly, we can use a sine wave that goes from 0 to π in a few steps. The full sine wave going from 0 to π × 2 (i.e. a whole circle) would result in values from -1 to 1, and we don’t want that (yet).

``````var counter = 0;

// 100 iterations
var increase = Math.PI / 100;

for ( i = 0; i <= 1; i += 0.01 ) {
x = i;
y = Math.sin(counter);
counter += increase;
}``````

A quick aside on numbers for sine and cosine: Both `Math.sin()` and `Math.cos()` take as the parameter an angle that should be in radians3. As humans, however, degrees ranging from 0 to 360 are much easier to read. That’s why you can and should convert between them with this simple formula:

``````var toRadian = Math.PI / 180;
var toDegree = 180 / Math.PI;

var angle = 30;

var angleInRadians = angle * toRadian;
var angleInDegrees = angleInRadians * toDegree;``````

Back to our sine waves. You can play with this a lot. For example, you could use the absolute value of a full 2 × π loop:

``````var counter = 0;
// 100 iterations
var increase = Math.PI * 2 / 100;

for ( i = 0; i <= 1; i += 0.01 ) {
x = i;
y = Math.abs( Math.sin( counter ) );
counter += increase;
}``````

But again, this looks dirty. If you want the full up and down, without a break in the middle, then you need to shift the values. You have to half the sine and then add 0.5 to it:

``````var counter = 0;
// 100 iterations
var increase = Math.PI * 2 / 100;

for ( i = 0; i <= 1; i += 0.01 ) {
x = i;
y = Math.sin( counter ) / 2 + 0.5;
counter += increase;
}``````

So, how can you use this? Having a function that returns -1 to 1 to whatever you feed it can be very cool. All you need to do is multiply it by the values that you want and add an offset to avoid negative numbers.

For example, check out this sine movement demo4:

Looks neat, doesn’t it? A lot of the trickery is already in the CSS:

``````.stage {
width:200px;
height:200px;
margin:2em;
position:relative;
background:#6cf;
overflow:hidden;
}

.stage div {
line-height:40px;
width:100%;
text-align:center;
background:#369;
color:#fff;
font-weight:bold;
position:absolute;
}``````

The `stage` element has a fixed dimension and is positioned relative. This means that everything that is positioned absolutely inside it will be relative to the element itself.

The div inside the stage is 40 pixels high and positioned absolutely. Now, all we need to do is move the div with JavaScript in a sine wave:

``````var banner = document.querySelector( '.stage div' ),
start = 0;
function sine(){
banner.style.top = 50 * Math.sin( start ) + 80 + 'px';
start += 0.05;
}
window.setInterval( sine, 1000/30 );``````

The start value changes constantly, and with `Math.sin()` we get a nice wave movement. We multiply this by 50 to get a wider wave, and we add 80 pixels to center it in the stage element. Yes, the element is 200 pixels high and 100 is half of that, but because the banner is 40 pixels high, we need to subtract half of that to center it.

Right now, this is a simple up-and-down movement. Nothing stops you, though, from making it more interesting. The multiplying factor of 50, for example, could be a sine wave itself with a different value:

``````var banner = document.querySelector( '.stage div' ),
start = 0,
multiplier = 0;
function sine(){
multiplier = 50 * Math.sin( start * 2 );
banner.style.top = multiplier * Math.sin( start ) + 80 + 'px';
start += 0.05;
}
window.setInterval( sine, 1000/30 );``````

The result of this7 is a banner that seems to tentatively move up and down. Back in the day and on the very slow Commodore 64, calculating the sine wave live was too slow. Instead, we had tools to generate sine tables (arrays, if you will), and we plotted those directly. One of the tools for creating great sine waves so that you could have bouncing scroll texts was the Wix Bouncer:

### Circles In The Sand, Round And Round…

Circular motion is a thing of beauty. It pleases the eye, reminds us of spinning wheels and the earth we stand on, and in general has a “this is not computer stuff” feel to it. The math of plotting something on a circle is not hard.

It goes back to Pythagoras8, who, as rumor has it, drew a lot of circles in the sand until he found his famous theorem9. If you want to use all the good stuff that comes from this theorem, then try to find a triangle with a right angle. If this triangle’s hypothenuse is 1, then you can easily calculate the horizontal leg as the cosine of the angle and the vertical leg as the sine of the angle:

How is this relevant to a circle? Well, it is pretty simple to find a right-angle triangle in a circle to every point of it:

This means that if you want to plot something on a circle (or draw one), you can do it with a loop and sine and cosine. A full circle is 360°, or 2 × π in radians. We could have a go at it — but first, some plotting code needs to be done.

### A Quick DOM Plotting Routine

Normally, my weapon of choice here would be canvas, but in order to play nice with older browsers, let’s do it in plain DOM. The following helper function adds div elements to a stage element and allows us to position them, change their dimensions, set their color, change their content and rotate them without having to go through the annoying style settings on DOM elements.

``````Plot = function ( stage ) {

this.setDimensions = function( x, y ) {
this.elm.style.width = x + 'px';
this.elm.style.height = y + 'px';
this.width = x;
this.height = y;
}
this.position = function( x, y ) {
var xoffset = arguments[2] ? 0 : this.width / 2;
var yoffset = arguments[2] ? 0 : this.height / 2;
this.elm.style.left = (x - xoffset) + 'px';
this.elm.style.top = (y - yoffset) + 'px';
this.x = x;
this.y = y;
};
this.setbackground = function( col ) {
this.elm.style.background = col;
}
this.kill = function() {
stage.removeChild( this.elm );
}
this.rotate = function( str ) {
this.elm.style.webkitTransform = this.elm.style.MozTransform =
this.elm.style.OTransform = this.elm.style.transform =
'rotate('+str+')';
}
this.content = function( content ) {
this.elm.innerHTML = content;
}
this.round = function( round ) {
this.elm.style.borderRadius = round ? '50%/50%' : '';
}
this.elm = document.createElement( 'div' );
this.elm.style.position = 'absolute';
stage.appendChild( this.elm );

};``````

The only things that might be new here are the transformation with different browser prefixes and the positioning. People often make the mistake of creating a div with the dimensions `w` and `h` and then set it to `x` and `y` on the screen. This means you will always have to deal with the offset of the height and width. By subtracting half the width and height before positioning the div, you really set it where you want it — regardless of the dimensions. Here’s a proof10:

Now, let’s use that to plot 10 rectangles in a circle13, shall we?

``````var stage = document.querySelector('.stage'),
plots = 10;
increase = Math.PI * 2 / plots,
angle = 0,
x = 0,
y = 0;

for( var i = 0; i < plots; i++ ) {
var p = new Plot( stage );
p.setBackground( 'green' );
p.setDimensions( 40, 40 );
x = 100 * Math.cos( angle ) + 200;
y = 100 * Math.sin( angle ) + 200;
p.position( x, y );
angle += increase;
}``````

We want 10 things in a circle, so we need to find the angle that we want to put them at. A full circle is two times `Math.PI`, so all we need to do is divide this. The x and y position of our rectangles can be calculated by the angle we want them at. The x is the cosine, and the y is the sine, as explained earlier in the bit on Pythagoras. All we need to do, then, is center the circle that we’re painting in the stage (`200,200` is the center of the stage), and we are done. We’ve painted a circle with a radius of 100 pixels on the canvas in 10 steps.

The problem is that this looks terrible. If we really want to plot things on a circle, then their angles should also point to the center, right? For this, we need to calculate the tangent of the right-angle square, as explained in this charming “Math is fun” page16. In JavaScript, we can use `Math.atan2()`17 as a shortcut. The result looks much better:

``````var stage = document.querySelector('.stage'),
plots = 10;
increase = Math.PI * 2 / plots,
angle = 0,
x = 0,
y = 0;

for( var i = 0; i < plots; i++ ) {
var p = new Plot( stage );
p.setBackground( 'green' );
p.setDimensions( 40, 40 );
x = 100 * Math.cos( angle ) + 200;
y = 100 * Math.sin( angle ) + 200;
p.rotate( Math.atan2( y - 200, x - 200 ) + 'rad' );
p.position( x, y );
angle += increase;
}``````

Notice that the rotate transformation in CSS helps us heaps in this case. Otherwise, the math to rotate our rectangles would be much less fun. CSS transformations also take radians and degrees as their value. In this case, we use `rad`; if you want to rotate with degrees, simply use `deg` as the value.

How about animating the circle now? Well, the first thing to do is change the script a bit, because we don’t want to have to keep creating new plots. Other than that, all we need to do to rotate the circle is to keep increasing the start angle19:

``````var stage = document.querySelector('.stage'),
plots = 10;
increase = Math.PI * 2 / plots,
angle = 0,
x = 0,
y = 0,
plotcache = [];

for( var i = 0; i < plots; i++ ) {
var p = new Plot( stage );
p.setBackground( 'green' );
p.setDimensions( 40, 40 );
plotcache.push( p );
}

function rotate(){
for( var i = 0; i < plots; i++ ) {
x = 100 * Math.cos( angle ) + 200;
y = 100 * Math.sin( angle ) + 200;
plotcache[ i ].rotate( Math.atan2( y - 200, x - 200 ) + 'rad' );
plotcache[ i ].position( x, y );
angle += increase;
}
angle += 0.06;
}

setInterval( rotate, 1000/30 );``````

Want more? How about a rotating text message20 based on this? The tricky thing about this is that we also need to turn the characters 90° on each iteration:

``````var stage = document.querySelector('.stage'),
message = 'Smashing Magazine '.toUpperCase(),
plots = message.length;
increase = Math.PI * 2 / plots,
angle = -Math.PI,
turnangle = 0,
x = 0,
y = 0,
plotcache = [];

for( var i = 0; i < plots; i++ ) {
var p = new Plot( stage );
p.content( message.substr(i,1) );
p.setDimensions( 40, 40 );
plotcache.push( p );
}
function rotate(){
for( var i = 0; i < plots; i++ ) {
x = 100 * Math.cos( angle ) + 200;
y = 100 * Math.sin( angle ) + 200;
// rotation and rotating the text 90 degrees
turnangle = Math.atan2( y - 200, x - 200 ) * 180 / Math.PI + 90 + 'deg';
plotcache[ i ].rotate( turnangle );
plotcache[ i ].position( x, y );
angle += increase;
}
angle += 0.06;
}

setInterval( rotate, 1000/40 );``````

Again, nothing here is fixed. You can make the radius of the circle change constantly23, as we did with the bouncing banner message earlier (below is only an excerpt):

``````multiplier = 80 * Math.sin( angle );
for( var i = 0; i < plots; i++ ) {
x = multiplier * Math.cos( angle ) + 200;
y = multiplier * Math.sin( angle ) + 200;
turnangle = Math.atan2( y - 200, x - 200 ) * 180 / Math.PI + 90 + 'deg';
plotcache[ i ].rotate( turnangle );
plotcache[ i ].position( x, y );
angle += increase;
}
angle += 0.06;``````

And, of course, you can move the center of the circle24, too:

``````rx = 50 * Math.cos( angle ) + 200;
ry = 50 * Math.sin( angle ) + 200;
for( var i = 0; i < plots; i++ ) {
x = 100 * Math.cos( angle ) + rx;
y = 100 * Math.sin( angle ) + ry;
turnangle = Math.atan2( y - ry, x - rx ) * 180 / Math.PI + 90 + 'deg';
plotcache[ i ].rotate( turnangle );
plotcache[ i ].position( x, y );
angle += increase;
}
angle += 0.06;``````

For a final tip, how about allowing only a certain range of coordinates25?

``````function rotate() {
rx = 70 * Math.cos( angle ) + 200;
ry = 70 * Math.sin( angle ) + 200;
for( var i = 0; i < plots; i++ ) {
x = 100 * Math.cos( angle ) + rx;
y = 100 * Math.sin( angle ) + ry;
x = contain( 70, 320, x );
y = contain( 70, 320, y );
turnangle = Math.atan2( y - ry, x - rx ) * 180 / Math.PI + 90 + 'deg';
plotcache[ i ].rotate( turnangle );
plotcache[ i ].position( x, y );
angle += increase;
}
angle += 0.06;
}
function contain( min, max, value ) {
return Math.min( max, Math.max( min, value ) );
}``````

#### Summary

This was just a quick introduction to using exponentials and sine waves and to plotting things on a circle. Have a go with the code, and play with the numbers. It is amazing how many cool effects you can create with a few changes to the radius or by multiplying the angles. To make it easier for you to do this, below are the examples on JSFiddle to play with:

(il) (al)

#### Footnotes

An international Developer Evangelist working for Mozilla in the lovely town of London, England.

## Related Articles

### Enhancing User Experience With The Web Speech API

Advertising

Note: Our rating-system has caused errors, so it's disabled at the moment. It will be back the moment the problem has been resolved. We're very sorry. Happy Holidays!

1. 1

### Kevin

Very cool and interesting article!

2. 2

### Yves Van Broekhoven

Now this is an extremely useful article!

3. 3

### Eyas

My first time to comment. Thank you Christian, this is a wonderful article.

4. 4

### RiaanP

This is outstanding. Well written and clearly explained! I nearly confused the syntax with ActionScript. :) A lot of new programmers struggle with this stuff. Good resource.

5. 5

### William Lepinski

Yes indeed. Interesting see how daily things works under the hood.

6. 6

### Upendra

Good Approach., Like it !!!

7. 7

### kasakka

Excellent. Good stuff for those of us who mostly suck at math. :)

8. 8

### Jonathan

Great article. Sine really is indispensable. I recently made a scrolling web site where the animation was basically just lots of sine functions with different amplitudes and different periods. The maths isn’t really that hard, but it looks quite complex: http://www.flightofthefireflies.com

9. 9

### Abe Pazos

Nice! I learnt math and programming the same way, using old Commodore computers and playing with sines and cosines :) It would be very useful if kids learnt math and programming in the school at the same time, because then they could SEE the math. It then becomes a game, not just theory.

10. 10

### Paul R

Actually one of the best articles on Smashing for a while! Excellent :)

11. 11

### mUhAmAr

Love this. A far cry from my time at school doing geometry and trigonometry…..

12. 12

### Rommel Castro A.

this is a really great article!

13. 13

### Cécile

Love it! Thanks!

14. 14

### David Higgins

Great code to hack with. Now all one has to do is put the progress element into these to make for mad hybrid animations:

(FF6+) Only folks, sorry

http://jsfiddle.net/higgo85/we54x/2/

15. 15

### Jason

Tip: There are tons of used, dusty ol’ Flash math-based animation books out there in second-hand book shops; cheap. The math is the same and effects still cool.

16. 16

### Buzzedword

I wonder how I would do this to pull off a captain skyhawk text effect? Playing now!

17. 17

### Frank

Exactly what I need just right now! Thank you! :-)

18. 18

### Treferwynd

Wow, that’s great!
But I can’t get the code working, your code works, but the other codes in the article won’t work at all :|
(by “works” I mean they work on jsfiddle.net and if i create an html with that code in it, it will display this frigging rotating cubes)
I took the “plot” code and then copy/paste the other codes –>blank screen, or at least a grey square due to the css code…
Do someone have any ideas on what am I doing wrong?
BTW nice article!

19. 19

### Treferwynd

Ok, is working, sort of:
http://jsfiddle.net/zdt4G/

Half blue, half green :|

20. 20

### pelumi

Hmmm … this real good!

21. 21

### Phil

If you want to play arround a little bit more with Animations (using real Math ;-) in JavaScript you might want to check out the Processing.js which is a port of the Processing Visualization Language (Ben Fry and Casey Reas).

22. 22

### Hitesh Chavda

very useful, Thanks.

23. 23

### adi tpw

thanks a lot.
useful

24. 24

### karlwestin

If you look in the last pic, the letters in “Smashing Magazine” is not pointing exaclty to the middle of the circle, rather each of them is pointing a little bit off-center. Seems like the right compensation isn’t 0.5*PI radians (90 deg) but rather 0.45*PI radians (80 deg).
Had same problem in FF7 and chrome. Tried to set the dimensions of each box smaller, to 10,10. Then it got better. Just a little tip, if you’re using this and seeing the problem, make sure the box size is fairly close to word size.

Thanks for a cool article!

25. 25

### Antonio Santiago

Some time ago I write a short introductory post related to JavaScript and the importance of Maths:

http://acuriousanimal.com/blog/2010/12/18/javascript-animations-why-maths-are-important/

Hope can help.

26. 26

### ThA-B

Top fav article in sm for a while. Less wordpress nonsense, more similar articles. back to roots.

27. 27

### Edison Leon

Love it, I knew math will come handy some day (well I’d hoped)

28. 28

### David Higgins

You are missing some CSS. Try copying and pasting the CSS from: http://jsfiddle.net/higgo85/we54x/2/ into your document, and you should be fine

29. 29

### wrtn

turnangle = Math.PI/2 + angle +’rad';

wont this give the same result? (and get rid of atan2)

30. 30

### Ken

Beautifully done! Now I must go and play…!

31. 31

### Hermes

This is great. It is precisely the kind of practical maths that a developer might need to perform some basic angular and vector motion or behaviour, compared to the usual rectangular or linear motion. The advances in implementation of CSS3 and HTML5 plus the power of javascript allow to get into an area closer to a video game than a document oriented page. I had a lot of fun programming the wavy random trajectory of a fish that was swimming within a closed area and performed nice turns before hitting the limits. With just this kind of basic trigonometry one can achieve wonderful results, and working at this low level of the animation, the degree of freedom is amazing. Implementing very simple physics with collisions and bounces does not require any more knowledge, just imagination.

32. 32

### joe

Another really good method for easing (for animation, object/camera movement in games, ui etc.) is to move the percentage of distance left to a target point. Then when you are a set small distance away snap to the target. Using this you can vary the percentage to speed up or slow down the movement, you can also move the target point whenever you want and it smoothly moves to the new point (think about beginning an animate out during an animate in without waiting for the first to finish).

At higher percentages it really feels great, like something flying in and then slamming on the breaks to a smooth stop…

I’ve used this techniques in many UI’s, games, AI, camera systems etc… There is also the possibly adding an ease out when starting the animation — but those usually soften the *pop* of the animation reducing the impact you want it to have and making it feel sluggish instead of smooth.

This also works in any dimensionality… 1D for in/out slide type animation, 2D for UI elements, 3D for camera/object movement, (even 4D for quaternion slerp() animation… but I won’t go into that :)

Basically transcendentals are usually really slow and never looked as natural to me, but your mileage may vary :)

33. 33

### moabi

awesome…we need more of this ^^

34. 34

### Vikas

awesome……..the explain of code is written precisely. it is easy to understand and get more interested in math.

35. 35

### jameschiny@gmail.com

This is a great. Trying to translate it into python which for me is proving pretty hard as Im new to programming. Any tips?

36. 36

### James

Great article, trying to convert it to Python but finding it tough as Im new to programming. Any one got any tips?

37. 37

### alex

Great article! Does anyone know if there are any books or resources solely for things like this?

38. 38

### satish kumar chaudhary

this article is very useful for us……great job…i like it!!!!!!!

39. 39

### Andrej Badin

Really cool! Interesting reading, awesome showcase

40. 40

### Jake

Brilliant article. I remember feeling very sheepish upon using SohCahToa (among other trigonometric functions) in a jQuery plugin having previously (and somewhat arrogantly) asked “when am I ever going to use this in the real world” while at school.

41. 41

### Bubble Shooter

This posting was saved like a favorite :), I really like your site!

42. 42

### Mochamad Gufron

Waw, that’s a simple, pretty, and cool article. Nice idea man.

43. 43

### Elisabeth Hölzl

Thanks for this interesting article. Makes me want to think about more stuff from Maths that might come in handy as well.
Love it!

44. 44

### prowebguru

very nice article ! very useful !

Are there any more examples like this ? Would like to know more on animations in javascript.

45. 45

### Penuel

Super Article. Will read it again for sure.

46. 46

### ali

WoooWW!! That’s Great :)

47. 47

### code[enabled]

Nice one!

May i ask – in the ‘A Quick DOM Plotting Routine’ subsection you are saying

this.elem = document.createElement(‘div);

then in the constructor you are using them direct e.g
[CODE SAMPLE1]
this.elem.style.width = x + ‘px';
this.elem.style.height = y + ‘px';

aren’t you creating a new div for each, whereby you are setting the width for a div1 and the height for div2 in [CODE SAMPLE1]

It’s quite tricky

48. 48

### code[enabled]

Nice work!

for the rotating ‘smashing magazine’ am wondering whether when you call the setInterval( ) the angle value will be the last one from the for loop such that in the second call of the rotate( ) function the angle will be the last one of the last element in the for loop and that’s why you are adding 0.06?

Like you should be saving the angle property in the respective plotcache[i] and thats what should be incremented …….. i have not done this for long…..it was quite challenging to me

49. 49

### code[enabled]

i got it ! thanks

50. 50

### TJ Fogarty

This is something I’ve been meaning to dissect. I’ve read over this a couple of times now, but I’m looking forward to giving this much more attention :) extremely interesting. Thanks!

51. 51

### DavidASG

like 3 years 2011
http://jsfiddle.net/Davidasg/CuNv8/
only change de uppercase “B” to lowercase “b” on ( p.setBackground(“the color”) )=> ( p.setbackground(“the color”) )

52. 52

### Oscar Huaynalaya Falcon

I can not run it in my Notepad your code of Oscillating Rotating message. Can you help me ? Please. I like your work a lot. I put it together with style, script, and ajax.googleapis.com etc, etc. Then I can not run it. Thank you.

↑ Back to top