每次重复的 SVG 动画延迟

SVG animation delay on each repetition

我想为 SVG 动画循环的每次迭代添加延迟。这是一个简单的例子。

<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>

使用begin只会延迟第一次迭代,那么,有没有办法延迟次迭代?

您可以将 SMIL 动画元素的 end 事件添加到 begin 属性。
此外,您可以向此 begin 属性添加多个值,以 ; 分隔:

<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>

我认为您正在寻找的是 svg 的 additive/accumulative 属性。这是我从 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>

事实上这里有一个更好的例子(相同来源)

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>

定义虚拟循环并设置相对开始时间。看 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>

下面是 "closing eyes" 的示例...感谢此线程中的建议。

<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>

这是 Danjiro Daiwa 示例的更详细版本,没有隐藏矩形来同步动画,也没有诉诸将橙色圆圈设置在可见区域之外来隐藏它们,而是使用 opacity="0"。同时有四个动画运行,a1/a2移动,o1/o2移动时隐藏橙色分身圈behind/over蓝色圈,r1- r4 改变半径 r 和 f1-f4 改变 fill 颜色。

<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>

如果你想让你的动画交替出现(类似于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

解决方案 1:使用两个动画元素

<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>

解决方案 2:使用 valueskeyTimes 属性的组合

<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>

在这种方法中,您应该计算动画的总持续时间加上延迟并将其分配给 dur,并计算持续时间的 keyTimes 值。对于我的示例,总持续时间为 12s,时间 3s 1s 5s 1s 5s 映射到 keyTimes="0; 0.083; 0.5; 0.583; 1"

示例注释

  • calcMode="..."keySplines="..." 是可选的(它们指定 timing interpolation
  • 初始动画延迟为3秒
  • 动画(收缩和展开)每个需要 1 秒
  • 开始到shrink/expand之前的延迟是5秒

以上两者都会产生以下结果: