0

TL;DR: Is there a way to swap the images reliably while showing whichever image is being loaded at the time without causing page flicker?


I have 2 images and 2 buttons and when I hover over one button it shows the one image. Hovering over the other button swaps to the second image. I was doing it like this:

$('#button1').mouseover(function() {
    $('#image').attr('src', 'image1.png');
});

$('#button2').mouseover(function() {
    $('#image').attr('src', 'image2.png');
});

This works fine but when the first image has loaded and the second hasn't, it doesn't show the second image until it has completed loading. To try to give the user some indication of when the new image is loading (which they're expecting to appear immediately), I forced it to add a null image before these swaps, like this:

$('#button1').mouseover(function() {
    $('#image').attr('src', '#');
    $('#image').attr('src', 'image1.png');
});

$('#button2').mouseover(function() {
    $('#image').attr('src', '#');
    $('#image').attr('src', 'image2.png');
});

This works great when one image is loading by showing the image as it's loading but now once both are loaded, the null image in between them causes a flicker when switching images. I thought I could fix this by turning the null image off once both images are loaded but that has turned out to be unreliable. Both $('#image').prop('complete') and imagesloaded as suggested in other locations on stackoverflow are inconsistent at noticing whether the image has been loaded or not. Detecting loaded images just seems to be a dead end.

I also considered trying to force the images to show and hide before and after they were created but this doesn't seem to work at all though I'm not sure why. The new one doesn't show while loading and I'm not sure if they're swapping properly:

$('#button1').mouseover(function() {
    $('#image').hide();
    $('#image').attr('src', 'image1.png');
    $('#image').show();
});

$('#button2').mouseover(function() {
    $('#image').hide();
    $('#image').attr('src', 'image2.png');
    $('#image').show();
});

Is there a way to swap the images reliably while showing whichever image is being loaded at the time without causing page flicker that I haven't tried?

mdinger
  • 85
  • 1
  • 2
  • 8
  • My question is very similar to [this](http://stackoverflow.com/questions/19924001/changing-an-imgs-src-attribute-and-dispaying-the-new-image-as-it-loads) but my images always load progressively when they're the first image loaded. – mdinger Oct 01 '15 at 18:36

4 Answers4

3

What you're wanting to do is preload the images so that they are cached in the browser. then there's no delay on your mouse over. Here's a jquery plugin to cache the images and a call for them.

$.fn.preload = function() {
    this.each(function(){
        $('<img/>')[0].src = this;
    });
}

// Usage:

$(['image1.png','image2.png']).preload();

This is not my code: credit to James @ Preloading images with jQuery

Community
  • 1
  • 1
Gregg Duncan
  • 2,635
  • 1
  • 14
  • 20
  • This is pretty interesting but I don't understand the final line selector. As far as I [know](http://api.jquery.com/category/selectors/), that isn't a valid selector and I couldn't find it documented. Also, it appears assigning the src to `$('')[0].src` will preload this but I don't know why. Shouldn't the index of this object be incremented with every new addition instead of just being replaced by the newest element? Shouldn't all the pictures be preloaded? – mdinger Sep 30 '15 at 03:56
  • Hmm. All these solutions avoid my main issue: the new picture which is loading must appear as soon as the image is swapped. Whether or not the image is fully loaded is irrelevant. By implementing a preload, I enable possibly many many images to eat up my bandwidth while waiting for just one image to appear. See the images page on [arewecompressedyet.com](https://arewecompressedyet.com/) for how this is being used. – mdinger Sep 30 '15 at 05:26
  • I don't have a clue what arewecompressedyet.com is all about. So that's no help for me. "the new picture which is loading must appear as soon as the image is swapped. Whether or not the image is fully loaded is irrelevant."??? How can the image appear if it hasn't been loaded. This makes no sense. I was trying to give you a way to preload the images to the browser cache so that the image would be available to display when the image is swapped. Your only other option would be to hide the entire page and only show it on $(window).load. Then all the images would be loaded before the page displays – Gregg Duncan Sep 30 '15 at 15:27
  • The $(['image1.png','image2.png']) is simply a jquery array on which you call the preload method. Just like $('') creates an img tag in memory. It's not a 'valid' selector either. It's not selecting an image from your page, that wouldn't have the '<' or '/>'. But it creates the jquery object. The preload method loops through the array and assigns the src of an image tag to the string value of the array item. The index of the image doesn't matter. the purpose is to load the image to browser cache. By setting the src of an image you make the http call to load it. – Gregg Duncan Sep 30 '15 at 15:37
  • Hmm...I thought that site would be more obvious. Sorry about that. The site is an image comparison tool for an WIP video codec. Basically, it generates 100s of images from a specific codec revision. Then, choosing 2 different revisions, you can compare the same image across revisions to see the results of the codec update. Now, these images may look almost perfectly identical because the codec revision may be very minor. The problem is when you mouseover the switcher to compare with the new one and you think they must be identical because the image hasn't downloaded yet. – mdinger Sep 30 '15 at 20:43
  • My solution, mentioned in the OP, was to force the image to go blank before loading the next one. Then, the new image would draw from the top down as it loaded (letting you know the new image is being loaded rather than showing the original which was already loaded). This induced flicker though so I was trying to avoid that also. Preloading all images is impossible. There are gigabytes of them. – mdinger Sep 30 '15 at 20:47
  • So, it should be loading 2 images. If the first is 24% loaded and the second is 58% loaded, when I switch to the 24% loaded image, I want to see as much of the image as has been loaded. Then switching to the other should show it drawn 58% from the top down because it has downloaded that much already. I don't want to wait for the full load before it appears but I don't know how to do that without causing the issues I've already mentioned. It normally shows images partially drawn while they load. I don't know understand why this is difficult to achieve. – mdinger Sep 30 '15 at 21:00
  • I think I discovered how to fix this but this post was very helpful by keeping the images in memory so I'm upvoting it. I'll try to add the complete answer later tonight in a new answer. Thanks so much!!! – mdinger Oct 01 '15 at 18:54
0

Try this:

var preloadImages = ['image1.png', 'image2.png'];
$('#button1').mouseover(function() {
    $('#image').attr('src', preloadImages[0]);
});

$('#button2').mouseover(function() {
    $('#image').attr('src', preloadImages[1]);
});
0

Try storing the sources of the image into JavaScript variables, and use those variables to swap the image sources.

This might avoid the loading, not sure, but it might.

0

The problem is having this HTML content updated by changing the src location makes the browser wait until the image is loaded before displaying the image. This doesn't seem to be modifiable.

The HTML:

<img id="image" src="">

and javascript with this behavior:

$('#button1').mouseover(function() {
    $('#image').attr('src', 'image1.png');
});

$('#button2').mouseover(function() {
    $('#image').attr('src', 'image2.png');
});

Changing the HTML:

<div id='image_container'> </div>

and javascript to:

$('#button1').mouseover(function() {
    // Remove the old image and replace it with the new one
    $('#image_container').empty()
                         .append("<img id='image' src='image1.png'>");

});

$('#button2').mouseover(function() {
    $('#image_container').empty()
                         .append("<img id='image' src='image2.png'>");
});

makes the browser show the image while it is downloaded. I'm not exactly sure why but it seems to just be that new <img>s are handled differently than <img>s with src modifications.

mdinger
  • 85
  • 1
  • 2
  • 8