1

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.
VC.One
  • 14,790
  • 4
  • 25
  • 57
Tavish Aggarwal
  • 1,020
  • 3
  • 22
  • 51
  • Please let me know will all picture play in series? when mouse out will picture set to initial? –  Oct 06 '17 at 06:50
  • Yes.. @TAHATEMURII all gif images will be played in series and on mouse out it will be set to original image using JavaScript. NOTE: I have gif images. – Tavish Aggarwal Oct 06 '17 at 08:01
  • @TavishAggarwal are you playing **animated** GIFs? Is that your problem, **how to detect GIF animation ending** then play next one from a playlist? – VC.One Oct 10 '17 at 15:28
  • Yes @VC.One. Exactly, you got it correct. – Tavish Aggarwal Oct 11 '17 at 05:29

3 Answers3

3

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
Tavish Aggarwal
  • 1,020
  • 3
  • 22
  • 51
1

To load the GIF duration you can use gify. Then on mouseover you change the image and set a timeout function that changes the image with the current GIFs duration.

(function () {
    var slideUrls = [
        'https://media.giphy.com/media/9zXWAIcr6jycE/giphy.gif',
        'https://media.giphy.com/media/3ohzdFhIALkXTBxPkQ/giphy.gif'
    ];
    var originalUrl = 'http://via.placeholder.com/350x150';

    // Loads the duration information for each GIF
    var gifDurations = {};
    function loadDurations(i) {
        if (i >= slideUrls.length) return;

        var blob = null;
        var xhr = new XMLHttpRequest();
        xhr.open("GET", slideUrls[i]);
        xhr.responseType = 'blob';

        xhr.onload = function () {
            blob = xhr.response;
            var reader = new FileReader();

            reader.onload = function (event) {
                var gifInfo = gify.getInfo(reader.result);
                gifDurations[slideUrls[i]] = gifInfo.duration;
                loadDurations(i + 1)
            }

            reader.readAsArrayBuffer(blob);
        }
        xhr.send();
    }
    loadDurations(0);

    var element = document.getElementById('id');
    var timeout;
    var currentSlide = 0;

    function nextSlide() {
        var url = slideUrls[currentSlide];
        var duration = gifDurations[url];
        element.setAttribute('src', slideUrls[currentSlide]);
        currentSlide = (currentSlide + 1) % slideUrls.length;

        timeout = setTimeout(function () {
            nextSlide();
        }, duration);
    }

    element.addEventListener('mouseover', function () {
        nextSlide();
    });

    element.addEventListener('mouseout', function () {
        clearTimeout(timeout);
        element.src = originalUrl;
    });

})();
Frederik Hansen
  • 506
  • 4
  • 21
  • I have GIF images, and the set interval is not a solution. – Tavish Aggarwal Oct 08 '17 at 11:18
  • [Here](https://jsfiddle.net/frbaha/ztm5m2k2/2/) is a working JSFiddle. If this isn't what you want, please elaborate. – Frederik Hansen Oct 08 '17 at 11:27
  • Using setInterval, GIF image is getting replaced after every 1sec, I have GIF images which run for 10sec as well, so I am looking for the solution where I can find the duration of each GIF image and rotate it at an interval which is a duration of each GIF image. – Tavish Aggarwal Oct 08 '17 at 12:12
  • Updated comment. – Frederik Hansen Oct 08 '17 at 13:01
  • Thanks for your time @Frederik but I dont want to use any third party plugin. I want to do it in pure JavaScript. – Tavish Aggarwal Oct 09 '17 at 05:25
  • Gify is JavaScript. I don't see any reason as to why you shouldn't use this opposed to making it yourself. There is no reason to reinvent the wheel. – Frederik Hansen Oct 09 '17 at 11:45
  • 1
    Then your best bet to solving this is to implement what this plugin is already doing. That would be analysing the GIF-file in order to determine the duration of the file. You can find information about the structure of a GIF-file [here](http://www.matthewflickinger.com/lab/whatsinagif/bits_and_bytes.asp). – Frederik Hansen Oct 09 '17 at 11:49
  • 1
    @VC.One I'm aware of his problem, and I have offered a solution that works. However, he doesn't want to use any third party code, and analysing a GIFs data is not a trivial task, so I can't be of any further assistance. – Frederik Hansen Oct 11 '17 at 16:39
  • 1
    Thanks @FrederikHansen for your support! I got solution to my problem. Please check my answer. – Tavish Aggarwal Oct 12 '17 at 07:16
0

Using jQuery .hover() with one static image and one .gif - JSFiddle

Had a good read on this thread first before writing this.

$("#gifdiv").hover(
  function () {
    $(this).find("img").attr("src", "https://upload.wikimedia.org/wikipedia/commons/2/2c/Rotating_earth_%28large%29.gif");
    }, function() {
     $(this).find("img").attr("src", "https://lh4.googleusercontent.com/__LWblq_sBitgvSmldccaKsEqt0ADBGpPmYFsl3l0Jkxenqti4Jt05EN9EUJPDlHrM5DprN2-hrX3MM=w1680-h944");
    }
);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="gifdiv">
  <img src="https://lh4.googleusercontent.com/__LWblq_sBitgvSmldccaKsEqt0ADBGpPmYFsl3l0Jkxenqti4Jt05EN9EUJPDlHrM5DprN2-hrX3MM=w1680-h944" class="static" />
</div>
Tiramonium
  • 557
  • 5
  • 15