views:

1146

answers:

4

I have some Javascript which "animates" a colour change on an HTML element, as follows:

var element = document.getElementById("someid");
while (i < 255) {
    element.style.color = 'rgb(' + i + ',' + i + ',' + i + ')';
    i++;
    slowMeDown(); // This function runs for a few ms to slow the process down
}

As you can see, this changes the color from black to white going through 255 shades of grey in between. I would like to make it visibly "fade" so that the user can see the text gradually disappear.

However, the browser (Chrome and IE - not tested on Firefox yet) only refreshes at the end of the function, so the color simply changes from black to white. Does anyone know how to make the browser repaint during the loop so that I can see the text fade?

A: 

I'd use colourChangeTimer = setInterval(function() { //colour change code }, 100);

Then after it's reached 255 on all values use clearTimeout(colourChangeTimer)

Excuse my Australian spelling.

alex
+2  A: 

You should look into JQuery. It will do all of this for you using the Effects functions or plugins.

However in answer to the question:

Normally web browsers only use a single UI update thread that is also used to execute Javascript code. Therefore the browser will execute your loop entirely and only then update the page once it is complete (ie all RGG = 255,255,255).

Try using window.setTimeout or window.setInterval to call a function that increments the RGB values. This allows the browser UI update thread to update the display after each call (between the interval or timeout).

(I believe all the major browsers operate this way including Firefox).

Note: setInterval and setTimeout execute code on the single same UI thread. They simply add a timer callback to the window message loop and this gets called and executed at the correct time.

Therefore, if other Javascript code or a UI update was executing at the time, the timer function must wait. So the function is not guaranteed to occur at exactly the time specified. Also (on Windows) the maximum resolution is much less then 1 millisecond, often about 1/20th of a second or about 50 milliseconds.

Ash
+8  A: 
function changeColor()
{
    changeColorIncremental(0);
}

function changeColorIncremental(i)
{
    var element = document.getElementById("someid");

    element.style.color = 'rgb(' + i + ',' + i + ',' + i + ')';

    if (i < 255) {
        // Note the 50 millisecond wait below.  Decrease this to speed up
        // the transition, and increase it to slow it down.
        setTimeout('changeColorIncremental(' + (i + 1) + ')', 50);
    }
}
Sean Bright
+1  A: 

Your slowMeDown() function is a bad way to delay things in Javascript. The reason is that JS implementations in browsers are single-threaded. This means only one task ever gets performed at a time. Often, the browser itself gets "frozen" waiting for JS to finish. This is what happens in your case - your loop never returns control to the browser in order to actually update the DOM element.

Using setTimeout() or setInterval() as proposed by some of the others here, works around this by returning flow control to the browser and requesting it to call you back in a specified number of milliseconds.

Also, if what you intend to do is trying to have the text fade, consider using the various ways to set CSS opacity (unfortunately given the state of browser support, you will have to set three different values on the style object).

levik