Tuesday, June 02, 2009

Javascript variable width animation fun

Working on yet another web site I took the opportunity to tweak the animation horizontal sliding javascript code. Using offsetwidth to determine length divide by time to get a floored pixel shift that runs through a for loop pixel at a time every setInterval. Still a hit on the CPU but definitely not as nasty as before and the animation is much smoother.

Rather than manipulate fixed length divs I'm looking at images. In this case they're all the same width, but I wondered if I could generalise the code for various widths.

In theory create a two-dimensional array such that you store source image location in [0][0] and width in [0][1], make it three-dimensional and you can have location, width and current position. Shame multi-dimensional arrays in javascript are just so useless that you might as well use three one-dimensional ones.

Now the basic premise of the animation was taking the number of items (say three) and scrolling them across the screen with the number of images being two more than fit on the screen at one time. So Item1 scrolls to the left and Item2 scrolls in after it while Item3 is still off-screen. When Item1 clears the screen and Item3 is about to appear Item1 is shifted to the back of the queue next to Item3 and so on.

Means you're only manipulating a small number of containers rather than creating one per Item and either doing exactly the same thing, or shifting the entire queue at a time. Of course if you have more Items then containers you need to switch them out and that I've already accomplished. That, however, was for fixed widths. Variable widths is a whole new show.

The problem is with either a small number of Items or short width Items. Imagine a screen 100px across and three Items to scroll across it - 100px, 50px, 100px in width. Item0 fills the screen then scrolls left and Item1 appears. From the queue point of view at position -51px Item2 just appears. At position -100px Item0 is moved to the end of the queue, but where is the end of the queue? It's Item1's width + Item2's width - 150px. So at queue position -50px Item0 is about to reappear and Item1 is moved to the end of the queue. And that would be at Item2's width + Item0's width - 200px.

So a bit od pseudo code comes out to

If Position[n] is equal or less than -Item[n].width (where n is any Item)
then
change Position[n] to width[n+1]+width[n+2]

seems easy so Item0 is moved to Item1+Item2 and Item1 is moved to Item2+Item3 ah no Item3.

So time to get creative. Javascript has a modulus function. What that does is divide one number by another and returns the remainder. So:

change Position[n] to width[n+1 % 3]+width[n+2 % 3]

Position[0]=width[0+1 % 3= 1]+width [0+2 % 3 = 2]
Position[1]=width [1+1 % 3= 2]+width [1+2 % 3 = 0]
Position[2]=width [2+1 % 3= 0]+width [2+2 % 3 = 1]

Okay, but what if you're substituting in a different Item with a different width? Then you change the width data in the array.

So just to work out the sequence and not showing the stored positions for every movement.

image[0] = "image0.jpg";
image[1] = "image1.jpg";
image[2] = "image2.jpg";
image[3] = "image3.jpg";
image[4] = "image4.jpg";

imgwidth[0]=100;
imgwidth[1]=50;
imgwidth[2]=100;
imgwidth[3]=75;
imgwidth[4]=25;

container[0]=0;
container[1]=1;
container[2]=2;

containerwidth[0]=imgwidth[0];
containerwidth[1]=imgwidth[1];
containerwidth[2]=imgwidth[2];

container[0] moves off screen at -containerwidth[0] (i.e.-100).
container[0] is moved to containerwidth[1]+containerwidth[2]; 50+100=150.
container[0] source is container[n]+3%5; 0+3%5=3; image[3]
container[0]=3;
containerwidth[0]=imgwidth[3];

container[1] moves off screen at -containerwidth[1] (i.e.-50).
container[1] is moved to containerwidth[2]+containerwidth[0]; 100+75=175.
container[1] source is container[n]+3%5; 1+3%5=4; image[4]
container[1]=4;
containerwidth[1]=imgwidth[4];

container[2] moves off screen at -containerwidth[2] (i.e.-100).
container[2] is moved to containerwidth[0]+containerwidth[1]; 75+25=100.
container[2] source is container[n]+3%5; 2+3%5=0; image[0]
container[2]=0;
containerwidth[2]=imgwidth[0];

container[0] moves off screen at -containerwidth[0] (i.e.-75).
container[0] is moved to containerwidth[1]+containerwidth[2]; 25+100=125.
container[0] source is container[n]+3%5; 3+3%5=1; image[1]
container[0]=1;
containerwidth[0]=imgwidth[1];

So it all pans out all you have to do is ensure that the for the number of visible containers (in this case two) the same number of widths sum to equal or greater than the screen width.

Okay here ends another aid to memory.

0 comments: