Search code examples
javascripthtmlimageanimated-gif

Play series of Animated GIF Images on Mouse Hover using Pure JavaScript


I have a requirement where I have an <image> tag linked to a series of animated gif images.

I want to play those animations (gif) on mouse over state, one after another (like a playlist). Then on mouse Out I want to return to some original img source (like a static poster image, waiting for user rollover state).

Please find pseudo code below that I have tried:

function nextSlide() {
    document.getElementsByTagName('img').setAttribute('src', slides[currentSlide]);
    currentSlide = (currentSlide + 1) % slides.length;
}

document.getElementsByTagName('img').addEventListner('mouseover',function(){
    slides = gifImages;
    var slideInterval = setInterval(nextSlide,1000);
});
   document.getElementsByTagName('img').addEventListener('mouseout', function(){
        document.getElementsByTagName('img').src = originalImage;
    });

Challenges (to fix) from using above code:

1. I want gif image to be replaced only after its animation is completed, but its getting replaced after every delay of timer as I am using setInterval.

2. On mouse out it is not returning to original image.

3. First image is also being loaded after 1 sec (since that's rate of setInterval).

Please let me know if there is any way to achieve this.

Update:

  • Issues 2 and 3 is resolved. Now only issue I am facing is to play collection of gif images.

Solution

  • After lot of hours I got answer to my own question.
    I got a code snippet to get duration of GIF Image. And once I have duration of GIF image I can set interval after duration of GIF images.

        function getGIF(url) {
        function downloadFile(url, success) {
            let xhr = new XMLHttpRequest();
            xhr.open('GET', url, true);
            xhr.responseType = 'arraybuffer';
            xhr.setRequestHeader('Cache-Control', 'no-cache');
            xhr.onreadystatechange = function () {
                if (xhr.readyState === 4) {
                    if (success) {
                        success(xhr.response);
                    }
                     const file = new Blob([xhr.response], {type:'image/jpeg'});
                }
            };
            xhr.send(null);
        }
    
        downloadFile(url, function (data) {
            let d = new Uint8Array(data);
    
            let bin = null;
            let duration = 0;
            for (let i = 0; i < d.length; i++) {
                bin += String.fromCharCode(d[i]);
    
                // Find a Graphic Control Extension hex(21F904__ ____ __00)
                if (d[i] === 0x21 &&
                    d[i + 1] === 0xF9 &&
                    d[i + 2] === 0x04 &&
                    d[i + 7] === 0x00) {
                    // Swap 5th and 6th bytes to get the delay per frame
                    let delay = (d[i + 5] << 8) | (d[i + 4] & 0xFF);
    
                    // Should be aware browsers have a minimum frame delay 
                    // e.g. 6ms for IE, 2ms modern browsers (50fps)
                    duration += delay < 2 ? 10 : delay;
                }
            }
        });
        return duration;
    }
    


    Thanks to codepen from where I got the solution: LINK
    REFERENCE:

    1. http://justinsomnia.org/2006/10/gif-animation-duration-calculation/
    2. http://www.w3.org/Graphics/GIF/spec-gif89a.txt