Can you control GIF animation with Javascript?
Is it possible to use javascript to control which frame of a GIF
image is showing and/or stop the animation. I want to be able to load a GIF
with several frames and only show one of them.
I know I could do it with lots of separate images, but if I can do what I want with a GIF
, it will only be one file to worry about.
You can use the libgif library.
It allows you to start/stop the gif and control which frame the gif is on.
<script type="text/javascript" src="./libgif.js"></script>
<img src="./example1_preview.gif" rel:animated_src="./example1.gif"
width="360" height="360" rel:auto_play="1" rel:rubbable="1" />
<script type="text/javascript">
$$('img').each(function (img_tag) {
if (/.*\.gif/.test(img_tag.src)) {
var rub = new SuperGif({ gif: img_tag } );
rub.load(function(){
console.log('oh hey, now the gif is loaded');
});
}
});
</script>
(most of the code is taken directly from their example)
I use x-gif it's pretty cool and easy to setup.
From Github:
<x-gif src="probably_cats.gif"></x-gif>
Where you can add the following as attributes:
- Playback modes:
-
speed="1.0"
(default mode) multiplies the speed by the value of the attribute; -
sync
defers playback to an external object; -
bpm="120"
syncs GIFs to a given beats-per-minute;
-
-
Options:
stopped
prevents the GIF from animating;fill
causes the GIF to expand to cover its container;-
n-times="3.0"
(speed mode only) stops playback (by adding the attribute stopped) after a set number of times; -
snap
(sync & bpm modes only) instead of allowing longer GIFs to sync to multiple beats, force them to fit into only one; -
ping-pong
plays the GIF front-to-back then back-to-front;
- Debugging:
-
debug
turns on debug output from the Gif Exploder; -
exploded
stops playback, and renders each frame out side-by-side.
-
If you are OK with converting your gif to a sprite sheet, you can do it this way (using ImageMagick):
montage animation.gif -coalesce -tile x1 -geometry +0+0 -background None -quality 100 spritesheet.png
It is even likely that the new image will be of lesser size.
Once you have a sprite sheet, use CSS animation. An animation with a fixed frame time is used here:
var el = document.getElementById('anim');
function play() {
el.style.animationPlayState = 'running';
}
function pause() {
el.style.animationPlayState = 'paused';
}
function reset() {
el.style.animation = 'none';
el.offsetHeight; /* trigger reflow to apply the change immediately */
el.style.animation = null;
}
function stop() {
reset();
pause();
}
#anim {
background-image: url('https://i.stack.imgur.com/J5drY.png');
width: 250px;
height: 188px;
animation: anim 1.0s steps(10) infinite;
}
@keyframes anim {
100% { background-position: -2500px; }
}
<div id="anim" title="Animated Bat by Calciumtrice"></div>
<button onclick="play()">Play</button>
<button onclick="pause()">Pause</button>
<button onclick="reset()">Reset</button>
<button onclick="stop()">Stop</button>
If you want the animation to not start automatically, add paused
to the end of animation
rule.
You can do it with a single image using CSS sprites.