Reputation: 15381
I have a lot of <img>
tags on one HTML page some of whom share the same animated GIF file. The src
URL is set dynamically by JavaScript but with my code the same characters are either played all again or following characters are immediately displayed with the last frame.
The idea: This is for an art project. After some text has been entered the characters are displayed in a special font and some transition is done character per character (one after another) which I can only realize by using animated GIFs. The text is split into single characters and <img>
tags are created like this:
<!-- delivered HTML at page load -->
<img src="initial/f.png"> <!-- I used to PNG here to outline -->
<img src="initial/o.png"> <!-- the animation is NOT set a first -->
<img src="initial/o.png">
When the animation starts the first <img>
's URL is set to transition/f.gif
. Only after it has finished playing (determined by time) the 2nd image is set etc.
<!-- while 2nd animation is running -->
<img src="transition/f.gif"> <!-- already finished, displays last frame -->
<img src="transition/o.gif"> <!-- being animated right now -->
<img src="transition/o.png"> <!-- will be reset to o.gif in next step -->
The problem I can't solve: After o.gif
from the example has been played the animation of the next O doesn't work correctly.
I tried defining a class for every character and assigning the image as background-image
. Once any occurrence of a character had played any following occurrences of the same letter displayed the last frame (end state) of that GIF immediately when displayed.
I also tried setting the src
attribute directly with JavaScript but when the 2nd letter O is set like this the first letter O's animation restarts synchronously. But it shall stay at the last frame.
As the HTML page should also work on the local filesystem I think arguments like o.gif?random=argument
for bypassing cache mechanism won't work or won't have any effect (maybe on some computers, testing on my own won't falsify).
Upvotes: 5
Views: 1847
Reputation: 8136
Consider not using GIFs, but image sequences and Javascript. I've thrown together a rough instantiable Javascript object that does just that:
<html>
<head>
<script>
function Animator(target, frames, delay)
{
var _this = this;
// array of frames (image objects)
var f = [];
// a reference to the object where our frames will appear
var t = document.getElementById(target);
// the interval variable. Used to stop and start
var t_loop;
// create a new image element and remember it
var img_el = document.createElement("img");
// current frame
var c_frame = 0;
t.innerHTML = "";
t.appendChild(img_el);
var i, img;
// preload immediately
for(i = 0; i < frames.length; i++)
{
img = new Image();
img.src = frames[i];
f.push(img);
}
this.play = function()
{
t_loop = window.setInterval(_this.frame, delay);
}
this.stop = function()
{
clearInterval(t_loop);
}
this.gotoFrame = function(frame)
{
c_frame = frame;
_this.frame();
}
this.frame = function()
{
img_el.src = f[c_frame].src;
c_frame++;
if(c_frame >= f.length)
{
c_frame = 0;
}
}
}
function loaded()
{
var quip_frames = [
"http://www.abcteach.com/images/abma_thumb.gif",
"http://www.abcteach.com/images/abcu_thumb.gif",
"http://www.abcteach.com/images/zbma_thumb.gif",
"http://www.abcteach.com/images/zbcu_thumb.gif",
"http://www.abcteach.com/images/dnma_thumb.gif",
"http://www.abcteach.com/images/dncu_thumb.gif"
];
var anim1 = new Animator("target1", quip_frames, 100);
var anim2 = new Animator("target2", quip_frames, 100);
var anim3 = new Animator("target3", quip_frames, 100);
anim1.play();
window.setTimeout(anim2.play, 200);
window.setTimeout(anim3.play, 300);
}
</script>
</head>
<body onload="loaded()">
<div id="target1">
</div>
<div id="target2">
</div>
<div id="target3">
</div>
</body>
</html>
thanks to ABCTeach for the images
The object loads the images in a loop, stores them in an array, then through simple use of setInterval()
swaps out frames at a desired rate. When the page loads it makes three of these objects, each pointing to a different DIV, but each with the same frames. It then tells each to play with a different delay (the first one immediately, the second after 200ms, the third after 300ms). In your case you'd make one array for every letter you'd use:
var A = [*array of URLs to images of the letter A*];
var B = [*array of URLs to images of the letter B*];
...
Then create a new Animator
object for every div on your page, sending it the appropriate letter array:
var letter_so_and_so = new Animator("div_so_and_so", A, 100);
var letter_this_and_that = new Animator("div_this_and_that", B, 100);
var another_letter = new Animator("another_div", B, 100);
Finally give each one either an offset start, or call their Animator.gotoFrame(f)
method to start them on different frames (don't forget to Animator.play()
!).
Try to adopt something like this into your code, I think you'll find it works wonders.
Upvotes: 2
Reputation: 389
You have to create unique urls for the images, so the browser will always reload letters instead of using the cached ones. You could achieve this for example with a small php, which is outputting the correct gif for a parameter.
<img src="gif_printer.php?letter=o&t=1234567">
The t parameter should be the timestamp when you create the img tag. This gives enough difference to redownload.
In the php set headers to limit/disable caching and output type to gif, and simply pour the contents of the image to stdout.
The timestamp parameter and the cache-control headers should be enough for the browser to redownload evert letter.
If your test environment is not reacting correct, you could try htaccess solution, but for that you have to use a web server (and this could already be enough for the previous solution to work).
That means rewrite any url to images/[a-z].gif into images/[a-z].gif, so simply remove additional noise except the first letter and the extension.
Upvotes: 2