Alasdair McLeay
Alasdair McLeay

Reputation: 2632

Restart background SVG animation

I have an SVG set as a background image of an element. The first time the element is displayed, the animation plays correctly.

On subsequent displays (e.g. if a duplicate of the element is injected via JavaScript, or if the background image is removed and added back with CSS/JavaScript), the animation does not start from the beginning. I think this is intended functionality as the image is not considered to have been reloaded by the browser - it uses the in memory version which is already animating.

Here is a demo of this (not mine): http://www.luigifab.info/public/svg-smil/test.html

There are some associated browser bugs reports for Firefox and Chrome, but as above I think this is intended functionality.

Is there any way to get my SVG animation to reset/replay whenever the image is displayed?

I'm ideally looking for a solution using just CSS and SVG - else a solution with JavaScript if this is not possible.

Upvotes: 22

Views: 16386

Answers (7)

Stefan Avramovic
Stefan Avramovic

Reputation: 1353

This has worked for me, Simply adding and removing "play" class to a div element by adding setTimeout to delay classList.add('play') so the class can be removed and then applied

CSS

@keyframes play60 {
        0% {
            background-position: 0px 0px;
        }
        100% {
            background-position: -38400px 0px;
        }
    }
    .shapeshifter {
        animation-duration: 1000ms;
        animation-timing-function: steps(60);
        animation-fill-mode: forwards;
        width: 640px;
        height: 640px;
        background-repeat: no-repeat;
    }
    .shapeshifter.play {
        animation-name: play60;
    }

JS:

document.getElementById('shape').addEventListener('mouseover', () => {
    document.getElementById('shape').classList.remove('play')
    setTimeout(() => {
        document.getElementById('shape').classList.add('play');
    }, 1)
})

HTML

<div class="shapeshifter " id="shape" style="background-image: url(shape.svg)"></div>

Upvotes: 1

Martin R.
Martin R.

Reputation: 1642

I think in many scenarios setCurrentTime(0) is the best solution -- if supported by the browser. Here is an example (assuming you use the <object> tag for embedding, of course):

let content = document.getElementById("object-id").contentDocument;
let svg = content.getElementsByTagName("svg")[0];
if(svg.getCurrentTime() > 10)
  svg.setCurrentTime(0);

More infos about the relevant API can be found here: https://developer.mozilla.org/en-US/docs/Web/API/SVGSVGElement

Upvotes: 2

IvanRF
IvanRF

Reputation: 7265

As @netsurfer said, I solved this issue by using an object. Here is an example:

<object type="image/svg+xml" data="my.svg"></object>

Every time I dynamically inject the SVG object the animation starts from the beginning.

Upvotes: 15

Netsurfer
Netsurfer

Reputation: 5542

I think your guess "... as the image is not considered to have been reloaded by the browser - it uses the in memory version which is already animating" is correct, as the SVG file is cached! So without a (real) 'reload' the animation is not triggered (again).

Well, firstly let's have a look at SVG animations. There are two attributes you can use inside an animation element which are used to repeat the animation - see Repeating Animations and The ‘animate’ element. In your case the animation runs only once (no repetition).

So you would need Javascript to somehow "trigger" the animation.
This is possible in principle (example: Advanced SVG Animation Techniques), but only if the SVG file is part of the DOM, which you can access via Javascript. Therefor you have to include the SVG file as an <object>.

As soon as you use a SVG file in an <img> tag or as a CSS background-image you have no script access to the file.

So the only way I could think of to achieve your goal is to prevent the browser from caching the SVG file (see How (and how not) to Control Caches), or to use the SVG file in an <object> element so that you can control the animation via Javascript.

BTW: luigifab's answer is not that bad. This is an often used "trick" to force reload of a file/ an image - see The Cache Trick

Upvotes: 13

DhruvPathak
DhruvPathak

Reputation: 43235

Use a random key in the url for cache busting. Though your example does not have a long animation to properly test it, I have added repeatition of loading the image to make the difference noticable.

url + "&" + Math.random()

No reload demo with constant URL: http://jsfiddle.net/4ZBLr/8/

Reload demo with random URL src: http://jsfiddle.net/4ZBLr/9/

Upvotes: 1

AzDesign
AzDesign

Reputation: 1199

Implementation for luigifab's answer. put some random things at the end of the url parameter, this will force browser to think that the resource is a "new resource". Demo

Upvotes: 3

luigifab
luigifab

Reputation: 394

A possibility is to change image URL to force browser reload.

Upvotes: 5

Related Questions