3

I'm doing a frame by frame animation with Javascript by animating a sequence of images.

The code for the animation is quite simple.

My problem is, there can be a lot of images, presently 200 but can be up to 1000. Loading the images simultanely can take some times. I'd like to play the animation with 30 images initially and preload the remain in the background. But sometimes, the images take a time to load thus breaking the animation.

How can I pause the animation with a "buffering" and continue the animation when the next image is available ? Also how to skip the preloading when the images are already cached ? Could use some suggestion to improve the code.

HTML

<div class="video-stream">
    <img alt="" src="images/stream/Calque-120.jpg" />
    <img alt="" src="images/stream/Calque-121.jpg" />
    <img alt="" src="images/stream/Calque-122.jpg" />
    <img alt="" src="images/stream/Calque-123.jpg" />
    <img alt="" src="images/stream/Calque-124.jpg" />
    <img alt="" src="images/stream/Calque-125.jpg" />
    <img alt="" src="images/stream/Calque-126.jpg" />
    <img alt="" src="images/stream/Calque-127.jpg" />
    <img alt="" src="images/stream/Calque-128.jpg" />
    <img alt="" src="images/stream/Calque-129.jpg" />
    <img alt="" src="images/stream/Calque-130.jpg" />
    <img alt="" src="images/stream/Calque-131.jpg" />
    <img alt="" src="images/stream/Calque-132.jpg" />
    <img alt="" src="images/stream/Calque-133.jpg" />
    <img alt="" src="images/stream/Calque-134.jpg" />
    <img alt="" src="images/stream/Calque-135.jpg" />
    <img alt="" src="images/stream/Calque-136.jpg" />
    <img alt="" src="images/stream/Calque-137.jpg" />
    <img alt="" src="images/stream/Calque-138.jpg" />
    <img alt="" src="images/stream/Calque-139.jpg" />
    <img alt="" src="images/stream/Calque-140.jpg" />
    <img alt="" src="images/stream/Calque-141.jpg" />
    <img alt="" src="images/stream/Calque-142.jpg" />
    <img alt="" src="images/stream/Calque-143.jpg" />
    <img alt="" src="images/stream/Calque-144.jpg" />
    <img alt="" src="images/stream/Calque-145.jpg" />
    <img alt="" src="images/stream/Calque-146.jpg" />
    <img alt="" src="images/stream/Calque-147.jpg" />
    <img alt="" src="images/stream/Calque-148.jpg" />
    <img alt="" src="images/stream/Calque-149.jpg" />
</div>

CSS

.video-stream
{
    position: relative;
}
.video-stream img
{
    display: none;
    height: auto;
    left: 0;
    max-width: 100%;
    position: absolute;
    top: 0;
    vertical-align: top;
}

Javascript

var current = 0, // current playing image index
    next = 1, // next image index to play
    interval = 60, // animation speed
    hide_delay = 1, // Delay to hide the current image
    img_num = 200, // Total number of image
    pack = 10, // Images being preloaded simultanely
    idx_start = 149, // The images are index-suffixed so this is the index of the first image to preload
    idx_end = 300; // index of the last image in the sequence

var load_more = function()
{
    if(idx_start < idx_end)
    {
        // Preloading images
        var temp = [],
            temp_html = '';

        for(var i = 0; i < pack && idx_start < idx_end; i++)
        {
            temp[i] = 'images/stream/Calque-' + (++idx_start) + '.jpg';
        }

        preloadPictures(temp, function()
        {
            $.each(temp, function(i, v)
            {
                temp_html += '<img src=' + v + ' />';
            });
            // Inject into dom
            $('.video-stream').append(temp_html);

        });
    }    

}

var play_stream = function()
{
    $('.video-stream').find('img').eq(current).delay(interval).fadeOut(hide_delay)
    .end().eq(next).delay(interval).hide().fadeIn(hide_delay, play_stream);

    if(next < img_num - 1)
    {
        next++;
    }
    else
    {
        next = 0;
    }

    if(current < img_num - 1)
    {
        current++;
    }
    else
    {
        current = 0;
    }

    // Background preload
    if(idx_start < idx_end)
    {
        load_more();
    }    
};

$(window).load(function()
{
    play_stream();
});
  • I would suggest to you to convert your image sequence to a video format and use the html5 video tag. You can even control that via javascript. This would have much better cross browser/platform support and probably be faster (video codec compression, native video support, ...). You should be able to convert the images using e.g. imagemagick. – opatut Sep 25 '15 at 11:22
  • My concern is the "autoplay" issue on mobile – Livinphenomenon Sep 25 '15 at 11:23
  • There is a reason why autoplay is disabled on most mobile platforms. Please note that if your total image size exceeds certain limits, the whole page stops loading on some devices, too. I'd rather go with the video. Would would want some site to download a lot of data via your cellular network? – opatut Sep 25 '15 at 11:26
  • From HTML Spec: "User agents do not need to support autoplay, and it is suggested that user agents honor user preferences on the matter. Authors are urged to use the autoplay attribute rather than using script to force the video to play, so as to allow the user to override the behaviour if so desired." https://html.spec.whatwg.org/multipage/embedded-content.html#playing-the-media-resource – opatut Sep 25 '15 at 11:28
  • This is a specific request so I have to stick with it, but thanks for the answers – Livinphenomenon Sep 25 '15 at 11:44

1 Answers1

0

This is a tricky way of doing it but here it is. You just need an array of images to pass through instead of my count;

var count = 0;
var buffer = 1;
var Vbuffer = 2;
setInterval(function() {
  $('#img .' + buffer).prop('src', 'https://placeholdit.imgix.net/~text?txtsize=33&txt=' + count + '&w=150&h=150');
  buffer = buffer % 3 + 1;
  $('#img img').not('.' + Vbuffer).hide();
  $('#img .' + Vbuffer).show();
  Vbuffer = Vbuffer % 3 + 1;
  count++;
}, 1000);



var buffer2 = 1;
var Vbuffer2 = 2;
var arrayOfImg = ['https://placeholdit.imgix.net/~text?txtsize=33&txt=one&w=150&h=150',
  'https://placeholdit.imgix.net/~text?txtsize=33&txt=two&w=150&h=150',
  'https://placeholdit.imgix.net/~text?txtsize=33&txt=three&w=150&h=150',
  'https://placeholdit.imgix.net/~text?txtsize=33&txt=four&w=150&h=150',
  'https://placeholdit.imgix.net/~text?txtsize=33&txt=five&w=150&h=150'
]
var count2 = 0;
var arrayCount = arrayOfImg.length;
setInterval(function() {
  $('#img2 .' + buffer2).prop('src', arrayOfImg[count2]);
  buffer2 = buffer2 % 3 + 1;
  $('#img2 img').not('.' + Vbuffer2).hide();
  $('#img2 .' + Vbuffer2).show();
  Vbuffer2 = Vbuffer2 % 3 + 1;
  count2 = (count2 + 1) % arrayCount;
}, 1000);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
wait 3 seconds while the buffer loads
<div id='img'>
  <img src='' class='1' />
  <img src='' class='2' />
  <img src='' class='3' />
</div>

<div id='img2'>
  <img src='' class='1' />
  <img src='' class='2' />
  <img src='' class='3' />
</div>

EDIT

Added arrays to the results, so you can pass in an array of img sources to role through.

Roger
  • 3,226
  • 1
  • 22
  • 38