14

I'd like to add a delay to each iteration of an SVG animation loop. Here's a simple example.

<svg xmlns="http://www.w3.org/2000/svg" width="100px" height="100px">
  <circle cx="50" cy="50" r="15" fill="blue">
    <animate id="op" attributeType="CSS" attributeName="opacity"
             from="1" to="0" dur="3s" repeatCount="indefinite" />
  </circle>
</svg>

Using begin only delays the first iteration, so, is there a way to delay every iteration?

Mahozad
  • 18,032
  • 13
  • 118
  • 133
Ben Murden
  • 590
  • 2
  • 6
  • 23
  • Found this link somewhat helpful: http://srufaculty.sru.edu/david.dailey/svg/svgScaleinHTML.htm – Justin Feb 26 '20 at 11:42

6 Answers6

35

You can add the end event of a SMIL animated element to the begin attribute.
Also, you can add multiple values, separated by ; to this begin attribute :

<svg xmlns="http://www.w3.org/2000/svg" width="300px" height="100px">
  <circle cx="50" cy="50" r="15" fill="blue">
    <animate id="op" attributeType="CSS" attributeName="opacity"
             from="1" to="0" dur="3s" begin="3s;op.end+3s" />
  </circle>
</svg>
Kaiido
  • 123,334
  • 13
  • 219
  • 285
  • 2
    Marvellous, thank you! I was confused at first, because I had not realised that this does not work with `repeatCount`. – Ben Murden Jul 29 '15 at 04:18
  • well actually `repeatCount` is still active and the `end` event fires at the end of the finite `repeatCount`. – Kaiido Jul 29 '15 at 04:24
  • 1
    I suppose I should be more specific and say the animation never ends if you have `repeatCount="indefinite"` - the `end` event is never reached! I don't see a specific mention of a default on MDN, but I assume it is set to 1 if not defined. – Ben Murden Jul 29 '15 at 04:30
  • Well actually it is ignored if the duration is set : [specs](http://www.w3.org/TR/2001/REC-smil-animation-20010904/#ComputingActiveDur) but yes if repeatCount is set to `indefinite`, `end` won't fire, ever. That's why I said "at the end of the **finite** `repeatCount`" – Kaiido Jul 29 '15 at 04:38
  • Hello Kaiido, I don't see a repeat count in your example, why does the animation start itself again? In my case the animation doesn't. – Blue Lovag Jul 12 '21 at 13:27
  • @BlueLovag as said in the answer, it uses the `end` event (`op.end`) The syntax is [id of the animate element].end ensure you've set the `id` correctly. – Kaiido Jul 12 '21 at 14:19
3

Define dummy loop and set relative start time. See How to make SVG Loop Animation?

<svg xmlns="http://www.w3.org/2000/svg" width="300px" height="200px">
  <rect>
    <animate id="o1" begin="0;o1.end" dur="10s"
    attributeName="visibility" from="hide" to="hide"/>
  </rect>
  <circle fill="orange" cx="-50" cy="100" r="20">
    <animate begin="o1.begin" 
    attributeName="cx" from="250" to="50" dur="5.05s"/>
  </circle>
  <circle fill="blue" cx="150" cy="100" r="50" />
  <circle fill="orange" cx="-50" cy="100" r="20">
    <animate begin="o1.begin+5s" 
    attributeName="cx" from="50" to="250" dur="5.05s"/>
  </circle>
</svg>
2

Below an example of "closing eyes"... thanks to the suggestions in this thread.

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 80 16"><g>
  <g >
  <ellipse cx="9.45" cy="7.7" rx="0.96" ry="0.96" style="stroke: none; fill: black;">
   <animate id="op" attributeName="ry" attributeType="XML"
             to="0.1"
             begin="3s;op.end+3s" dur="0.15s"
             fill="remove" repeatCount="2"
            />
  </ellipse>
  <ellipse cx="14.6" cy="7.8" rx="0.8" ry="0.8" style="stroke: none; fill: black;">
   <animate id="op" attributeName="ry" attributeType="XML"
             to="0.1"
             begin="3s;op.end+3s" dur="0.15s"
             fill="remove" repeatCount="2"
            />
  </ellipse>
 </g>
</svg>
j3ff
  • 5,719
  • 8
  • 38
  • 51
nelsonmau
  • 21
  • 4
1

If you want your animation to alternate (similar to what animation-direction: alternate; does in CSS), and you want to have a different delay for the initial/start/first repetition vs subsequent repetitions, here I provide two workarounds. See this GitHub issue in SVG Working Group repo.

Solution 1: Using two animation elements

<circle fill="#f5ca20" r="5" cx="12" cy="12">
  <animate id="anim1" attributeName="r" dur="1s" fill="freeze" begin="3s; anim2.end + 5s" to="10" keyTimes="0; 1" calcMode="spline" keySplines="0.37, 0, 0.63, 1"/>
  <animate id="anim2" attributeName="r" dur="1s" fill="freeze" begin="anim1.end + 5s"     to="5"  keyTimes="0; 1" calcMode="spline" keySplines="0.37, 0, 0.63, 1"/>
</circle>

Solution 2: Using combination of values and keyTimes attributes

<circle fill="#f5ca20" r="5" cx="12" cy="12">
  <animate attributeName="r" dur="12s" begin="3s" values="5; 10; 10; 5; 5" keyTimes="0; 0.083; 0.5; 0.583; 1" repeatDur="indefinite" calcMode="spline" keySplines="0.37, 0, 0.63, 1; 0, 0, 1, 1; 0.37, 0, 0.63, 1; 0, 0, 1, 1"/>
</circle>

In this approach you should calculate the total duration of animations plus delays and assign it to dur and also calculate the keyTimes values for your durations. For my example, the total duration is 12s and the times 3s 1s 5s 1s 5s maps to keyTimes="0; 0.083; 0.5; 0.583; 1".

Notes for my examples

  • calcMode="..." and keySplines="..." are optional (they specify timing interpolation)
  • The initial animation delay is 3 seconds
  • The animations (shrinking and expansion) each take 1 second
  • The delay before starting to shrink/expand is 5 Seconds

Both of the above produce the following result:

The animated image

Mahozad
  • 18,032
  • 13
  • 118
  • 133
0

I think what you're looking for is the additive/accumulative attributes of the svg. This is an example that i got from css tricks

svg {
  border: 3px solid #eee;
  display: block;
  margin: 1em auto;
}
<svg width="500" height="100">
  <circle id="orange-circle" r="30" cx="50" cy="50" fill="orange" />

  <animate xlink:href="#orange-circle" attributeName="cx" from="0" to="100" additive="sum" repeatCount="3" calcMode="spline" keyTimes="0;1" keySplines=".42 0 1 1" dur="1s" begin="click" fill="freeze" />
</svg>

In fact here is a better exaample (same source)

svg {
  border: 3px solid #eee;
  display: block;
  margin: 1em auto;
}
<svg width="500" height="150">
  <style>
    rect {
      -moz-transform-origin: 75px 75px;
      transform-origin: 50% 50%;
    }
  </style>
  <rect id="deepPink-rectangle" width="50" height="50" x="50" y="50" fill="deepPink" />
  
  <animateTransform 
           xlink:href="#deepPink-rectangle"
           attributeName="transform" 
           attributeType="XML"
           type="rotate"
           from="0 75 75"
           to="360 75 75" 
           dur="2s"
           begin="0s; 5s; 9s; 17s;"
           end="2s; 8s; 15s; 25s;"
           fill="freeze" 
           restart="whenNotActive"
           />
  
</svg>
Rachel Gallen
  • 27,943
  • 21
  • 72
  • 81
  • Thanks for your answer, but I don't think this specifically addresses the question. I needed a delay on an indefinite number of repetitions, where these examples appear to be finite. – Ben Murden Jul 29 '15 at 04:24
0

Here's a more elaborated version of Danjiro Daiwa's example without the hidden rectangle to synchronise the animation and without resorting to setting the orange circles out of the visible area to hide them, using opacity="0" instead. There are four animation running at the same time, a1/a2 for the movement, o1/o2 to hide the orange doppelganger circles when they're moving behind/over the blue circle, r1-r4 to change the radius r and f1-f4 to change fill colour.

<svg xmlns="http://www.w3.org/2000/svg" width="300px" height="200px">
  <circle fill="#f70" cx="0" cy="100" r="20" opacity="0">
    <animate id="a1" attributeName="cx" begin="0s;a2.end" from="250" to="50" dur="3s"/>
    <animate id="o1" attributeName="opacity" begin="a1.begin" end="a1.end" from="1" to="1"/>
    <animate id="r1" attributeName="r" begin="a1.begin" from="20" to="15" dur="1.5s"/>
    <animate id="r2" attributeName="r" begin="r1.end" from="15" to="20" dur="1.5s"/>
    <animate id="f1" attributeName="fill" begin="a1.begin" from="#f70" to="#c00" dur="1.5s"/>
    <animate id="f2" attributeName="fill" begin="f1.end" from="#c00" to="#f70" dur="1.5s"/>
  </circle>

  <circle fill="blue" cx="150" cy="100" r="50" />

  <circle fill="#f90" cx="0" cy="100" r="20" opacity="0">
    <animate id="a2" attributeName="cx" begin="a1.end" from="50" to="250" dur="2s"/>
    <animate id="o2" attributeName="opacity" begin="a2.begin" end="a2.end" from="1" to="1"/>
    <animate id="r3" attributeName="r" begin="a2.begin" from="20" to="25" dur="1s"/>
    <animate id="r4" attributeName="r" begin="r3.end" from="25" to="20" dur="1s"/>
    <animate id="f3" attributeName="fill" begin="a2.begin" from="#f70" to="#ff0" dur="1s"/>
    <animate id="f4" attributeName="fill" begin="f3.end" from="#ff0" to="#f70" dur="1s"/>
  </circle>
</svg>
Cyberknight
  • 156
  • 2
  • 6