Preload image for seamless background image change in JavaScript

463 views Asked by At

I have a Python websocket application which sends an image path to a JavaScript HTML file. When the image path is received, I change the background image of the webpage to the supplied image.

The issue I'm having at the moment, is when the background changes from the old image to the new, there is a momentary 'flash' of which, which suggests that there is a period of time (albeit very brief) where the new image is being loaded.

I've tried various preloading methodologies, but I'm very new to JavaScript, so am not sure which method would provide for a seamless transition between the two images. This is the method I currently have implemented:

var NewImage = new Image();
NewImage = message.data; //This is the image string received from Python
document.body.style.backgroundImage = "url('" + NewImage + "')";

The above displays the image as desired (including my CSS formatting), but the transition is unsightly.

I also had a play around with the following method, which makes more sense to me, but I couldn't get it to work.

var NewImage = new Image();

//Websocket function here
PreloadImage;

function PreloadImage() {

    NewImage.onload = ImageLoadComplete();
    NewImage.src = message.data;

}

function ImageLoadComplete() {

    document.body.style.backgroundImage = "url('" + NewImage + "')"

}

I'm not sure how to pass variables between the functions in this second method. Given the explicit 'onload' call in this method, I feel that this may provide the functionality I'm after.

How can I preload the images in order to seamlessly transition between them?

EDIT: The working code is posted below. Thanks to @blender for pointing me in the right direction :)

var NewImage = new Image;

NewImage.src = message.data; //Data from Python
if (NewImage.complete) {
    NewImage.onload = ImageLoadComplete();
} else {
    NewImage.onload = ImageLoadComplete;
}

function ImageLoadComplete() {
    document.body.style.backgroundImage = "url('" + NewImage.src + "')";
}
1

There are 1 answers

2
Blender On BEST ANSWER

You're not actually passing a callback function:

NewImage.onload = ImageLoadComplete();

You're passing in the result of calling ImageLoadComplete(), which means you call your callback immediately. Don't call the function and your code should work as expected (most of the time):

NewImage.onload = ImageLoadComplete;

One issue that you'll encounter is that onload may not get called by some browsers if the image is loaded from cache. You have to call the callback manually if that's the case:

if (NewImage.complete || NewImage.height > 0) {
    ImageLoadComplete();
} else {
    NewImage.onload = ImageLoadComplete;
}