L84
L84

Reputation: 46308

Replay a GIF Animation/Reload GIF on Click

I have a GIF animation that is large and I am having it display a loading icon until the GIF is loaded. Once it is loaded the GIF shows. Works great but I want to add a "replay" button to trigger the GIF to replay (reload).

Code for the loading and GIF:

HTML

<div id="loader" class="loading img-center"></div>

CSS

#loader {
 width: 600px;
 height: 450px;
 margin: auto; 
}

#loader.loading {
  background: url(/Images/ajax-loader.gif) no-repeat center center;
  width:32px;
  margin:auto ; 
}

JS

var $j = jQuery.noConflict();
$j(function () {
  var img = new Image();
  $j(img)
   .load(function () { 
     $j(this).hide();
     $j('#loader') 
      .removeClass('loading')
      .append(this);

  $j(this).fadeIn();
   })
 .error(function () {
   })
 .attr('src', '/2012/images/august/sailboat.gif');
});

The above code works fine. Now for the "Replay" or "Reload" Code that Does not Work:

HTML

<a id="refresh" href="#"> Replay Animation </a>

JS

$j(function() {
  $j("#refresh").click(function() {
     $j("#loader").load("/2012/images/august/sailboat.gif")
  })
})

I know there is some error with the JS but with my lack of skill in JS I do not know what I should be doing or trying. Any help or advice is greatly appreciated!

Thanks!

Upvotes: 3

Views: 20302

Answers (3)

Pooya Estakhri
Pooya Estakhri

Reputation: 1289

The question has been asked 11 years ago but still there isn't a universal solution for it.

There are multiple ways to tackle this issue, none of them are optimal but depending on your needs one might be better than the other. for the record when i say gif i mean all animated image formats including .gif .webp .apng and .avif

One way is to convert your gifs to mp4 file format, this would give you many more control APIs and generally a smaller file for same media. but be aware that you should

A) serve the gif yourself or have access to video format to be able to show a converted version.

B) forget about transparent parts either by converting gifs that don't have transparent parts or settle for a background same as the page background.

Another way mentioned is to change src attribute of img element either by resetting the src or by appending a query string. resetting might not be functional in some format/browser pairs and in some cases it would reset all instances of the image in DOM, and although it's likely to hit cache this is not for sure and a reload means a bad user experience.

Appending a query string will help by making sure a reset will happen and also the appended element is only affected element but this means that cache will always be bypassed and apart from more pressure and bandwidth usage on server-side a slower website with high data usage for client is not what we are striving for.

the solution that comes to my mind if converting to mp4 is not a viable option is to append a query string but while leveraging service worker caching.

The code bellow is from MDN to cache requests

const putInCache = async (request, response) => {
    const cache = await caches.open("v1");
    await cache.put(request, response);
};

const cacheFirst = async ({ request, fallbackUrl }) => {
    // First try to get the resource from the cache
    const responseFromCache = await caches.match(request);
    if (responseFromCache) {
        return responseFromCache;
    }

    // Next try to get the resource from the network
    try {
        const responseFromNetwork = await fetch(request);
        // response may be used only once
        // we need to save clone to put one copy in cache
        // and serve second one
        putInCache(request, responseFromNetwork.clone());
        return responseFromNetwork;
    } catch (error) {
        const fallbackResponse = await caches.match(fallbackUrl);
        if (fallbackResponse) {
            return fallbackResponse;
        }
        // when even the fallback response is not available,
        // there is nothing we can do, but we must always
        // return a Response object
        return new Response("Network error happened", {
            status: 408,
            headers: { "Content-Type": "text/plain" },
        });
    }
};

self.addEventListener("fetch", (event) => {
    event.respondWith(
        cacheFirst({
            request: event.request
        })
    );
});

but we need to make some changes in event listener

self.addEventListener("fetch", (event) => {
    let url = event.request.url
    if (url.includes('reqcacheqs')) {
        url = url.replace(/reqcacheqs=([^&]*)&?/, '')
        const request = event.request
        request.url = url
        event.respondWith(
            cacheFirst({
                request: event.request
            })
        );
    }
});

here we basically ignore reqcacheqs in service worker and can change it's value in our img element without worrying about requesting again and again from server. i haven't tested this code and there might be some bugs but the base idea is as presented.

Upvotes: 0

thecodeparadox
thecodeparadox

Reputation: 87073

Check this:

$j("#refresh").click(function() {
  $j("#loader").find('img').attr("src", "/2012/images/august/sailboat.gif");
});

As in your previous code you're append the image within #loader so, $('#loader').load(..) will not work. Find the image within #loader and then change the src of that image.

Upvotes: 4

Sudhir Bastakoti
Sudhir Bastakoti

Reputation: 100175

You could also append timestamp to avoid image loading from cache if needed:

$j("#refresh").click(function() {
  var timestamp = new Date().getTime();
  $j('#loader').find('img').attr('src', '/2012/images/august/sailboat.gif'+'?'+timestamp);
});

Upvotes: 3

Related Questions