在SVG viewBox上使用<animate>只能使用两次</animate>

时间:2014-04-11 19:06:29

标签: xml animation svg smil

我一直在尝试在SVG viewBox上使用2个不同的s来在大小之间循环,但是虽然两个动画都独立工作,但如果第一个动画在它之后再次开始,则第二个动画不会运行。对我来说奇怪的是,第一个将继续运行,表明它“识别”另一个动画的结束,即使它没有显示。如果我删除'small.end'它甚至会以他们应该的方式运行....但这意味着他们不会一个接一个地重复。

<svg viewBox = "0 0 300 300">
    <animate id = "big" attributeName = "viewBox" begin = "0;small.end" dur = "0.96s" from = "0 0 300 300" to = "0 0 650 390" fill = "freeze" />
    <animate id = "small" attributeName = "viewBox" begin = "big.end" dur = "0.96s" from = "0 0 650 390" to = "0 0 300 300" fill = "freeze" />
  <circle cx="50" cy="50" r="40" stroke="black" stroke-width="3" fill="red" />
</svg>

http://jsfiddle.net/yXDZ2/

我一直在研究各种各样的事情,比如坐标系,加法和累积动画等,但似乎无法理解为什么这样做。我怀疑这可能是一个“重置”动画状态的问题,但我得到了一些我的深度 - 我不介意使用javascript或任何库来实现这一点。任何帮助或指针将不胜感激。谢谢!

2 个答案:

答案 0 :(得分:1)

使用带有数组数组的单个animate元素。

<svg viewBox = "0 0 300 300">
    <animate attributeName = "viewBox" dur="1.92s" values="0 0 300 300; 0 0 650 390;0 0 300 300" fill="freeze"/>
  <circle cx="50" cy="50" r="40" stroke="black" stroke-width="3" fill="red" />
</svg>

答案 1 :(得分:1)

迈克尔·穆拉尼的建议绝对是一种更容易实现的方法,但值得进行更详细的检查:

首先要提到的是,问题只发生在Webkit / Blink浏览器中;在Firefox中,您可以获得预期的弹跳动画。

Chrome(和其他网络套件浏览器)中似乎发生的事情是它让#&#34;冻结&#34;第一个动画的值覆盖第二个动画所做的任何更改。如果你摆脱了第一个动画的冻结属性,那么第二个动画的冻结值会阻止第一个动画显示。

这是它应该如何工作,影响同一属性的两个动画的默认行为是后来的动画应该比之前的动画具有更高的优先级。具体来说,SMIL规范说:

  

Higher priority animations that are not additive will override all earlier (lower priority) animations, and simply set the attribute value.

问题似乎源于additive属性(或者至少是指定additive="sum"的选项)仅适用于某些类型的动画属性:长度,颜色和向量。它适用于像#34; viewBox&#34;这样的复杂属性。因此,webkit浏览器似乎忽略默认的additive="replace"行为。

为了演示,如果我们添加可能可能添加的动画,比如颜色的变化,那么然后两个动画正确地互相替换,尽管&# 34;冻结&#34;设定:

http://jsfiddle.net/yXDZ2/2/

然而,仅此一点并不能解释为什么你的第二个动画正常如果第一个动画在第二个动画结束后没有设置为重新启动。我的猜测是,这与webkit计算&#34;优先级&#34;的方式中的错误有关。多个动画。对于同时开始的多个动画,优先级是通过查看一个人的开始时间是否依赖于另一个来确定的。但是,该计算不应该影响在不同时间开始的动画 - 对于这种情况,后面的动画应该始终优先。

无论哪种方式,我都会将此称为webkit实现中的错误。我无法在webkit Bugzilla上找到任何相关的错误报告,如果找不到,可能需要进行更彻底的搜索并提出问题。


在此期间如何处理问题:

根据建议,您可以将两个动画组合成一个多值动画。这可能是最简单的方法,可以清理代码。

因为你实际上并没有&#34;冻结&#34;两端的值,另一种做你想要的方法就是从两者中删除fill="freeze"参数:

<svg viewBox = "0 0 300 300">
    <animate id = "big" attributeName = "viewBox" begin = "0;small.end" 
             dur = "0.96s" from = "0 0 300 300" to = "0 0 650 390" />
    <animate id = "small" attributeName = "viewBox" begin = "big.end" 
             dur = "0.96s" from = "0 0 650 390" to = "0 0 300 300"  />
  <circle cx="50" cy="50" r="40" stroke="black" stroke-width="3" fill="red" />
</svg>

http://jsfiddle.net/yXDZ2/1/

但是,如果您想要运行动画,冻结它,然后在开始反向动画之前等待指定的时间,则无法工作。要实现这一点,您需要

  • 将其定义为具有多个值的单个动画,其中一些值重复两次到#34;冻结&#34;该值,以及每个步骤的指定关键时间;
  • 定义set动画元素,这些动画元素在每个过渡动画完成后开始,并保持指定值一段时间而不会无限期冻结。