javascriptjquerymouseovermouseout

Script for Mouseover to let GIF finish before Mouseout GIF can begin?


I have two play-once GIFs similar to the ones attached. I'd like to have the first GIF replace the original PNG upon mouseover, but even if someone removes the cursor from the image, finish playing the GIF so the last frame is in place before the mouseout GIF, which is the reverse of the previous one, replaces it and plays. I'd also like the original PNG to replace the mouseout GIF when it is finished playing, too. So, original > mouseover long enough to finish playing > mouseout long enough to finish playing > original.

I tried a javascript I found on here, and it worked to replace the images, but the mouseover GIF kept playing every now and again (even while the cursor was still on it) even though it is a play-once GIF (the script must have kept refreshing the GIF or something).

I'd keep the script in an external file as opposed to inline, of course. I know enough javascript to edit scripts, but not write them from scratch. jQuery is available, if needed.

Thanks for your help!

mouseover GIF mouseout GIF original PNG

ETA: This is what I tried before, although this wasn't the final version of it since I was trying different things on that site that lets you try scripts on, and I think I had the timing set to 2888. I don't have the other script since I didn't save it:

$(".as-panel[data-index='0']").mouseover(function() {
$(this).find("img").attr('src','/bouncing-balls.gif');


});

function pausecomp(millis)
{
    var date = new Date();
    var curDate = null;
    do { curDate = new Date(); }
    while(curDate-date < millis);
}


$(".as-panel[data-index='0']").mouseout(function() {
  // `this` is the DOM element that was clicked
    pausecomp(500);     
 $(this).find("img").attr('src','/bouncing-balls-reverse.gif');


});

Solution

  • I guessed the animations to last about 3 seconds, but you can change that. Using setTimeout and a couple boolean values, we can delay the mouse on or off operation and queue up the next one. I also preload the images at the beginning to smooth out any loading flickers.

    const imgs = ["https://i.sstatic.net/02MSs.gif", "https://i.sstatic.net/0rYVD.gif", "https://i.sstatic.net/GOdZ0.png"];
    
    imgs.forEach((img, i) => {
      this["image" + i] = new Image();
      this["image" + i].src = img;
    })
    let imgtimer, allclear = true,
      nextEvent = null
    $('#imghover').mouseover(imgMo).mouseout(imgMo)
    
    function imgMo(e) {
      if (!allclear) {
        if (!nextEvent) nextEvent = e
        else nextEvent = null
        return
      }
    
      $("#imghover").attr('src', e.type === "mouseover" ? imgs[0] : imgs[1]);
      allclear = false;
      imgTimer = setTimeout(function() {
        allclear = true;
        if (nextEvent) imgMo(nextEvent);
        nextEvent = null
      }, 3000)
    }
    #mo {
      padding: 20px;
      background: #f0f0f0;
      text-align: center;
      margin-top: 10px;
    }
    
    html {
      background: #000;
      padding: 20px;
    }
    
    img {
      border: 1px solid #ccc;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <div class='showimg'>
      <img id='imghover' src='https://i.sstatic.net/GOdZ0.png' />
    </div>
    
    <!--
    <div id='mo'> Mouse over and out on this text to see the image change</div>
    -->