SVG支持动画。可以通过以下几种方法获得动画效果:
- 使用SVG动画元素。SVG可以描述随时间变化的图形对象,使用不同的动画元素可以定义运动路径,淡入淡出效果和对象的膨胀、收缩、旋转和变换颜色。
- 使用SVG DOM。SVG DOM兼容DOM1和DOM2,而SVG又定义了一套附加的DOM接口,支持脚本动画。通过这个方法可以获得各种动画效果。脚本语言中的定时器对象可以用来启动和控制动画。
- SVG被设计为支持未来版本的SMIL(Sychronized Multimedia Integration Language)。SMIL将被模块化而与SVG及其它基于XML的语言连接,产生动画效果。
一、SVG中的动画元素
SVG中的动画元素有五个,它们都可以随着时间的变化而改变SVG元素的属性或样式值,如下所示:
- <animate>:改变数值的属性或样式的值;
- <set>:改变非数据值的属性或样式的值,如visibility属性等;
- <animateMotion>
沿着某路径移动SVG元素获得动画效果, 该元素提供一种通过指定路径移动元素的简单方法。路径数据与路径元素的 d 属性相同,但用路径元素指定。也可以用 xlink:href 将它链接到 animateMotion 元素。起点和终点由 from 和 to 属性确定,并且可以通过将 rotate 值设为 auto 来设置对象垂直对齐于路径。(也可以将 rotate 属性设为 auto-reverse 以将这个方位改变 180 度。或者可以给定一个特定角度)。如动画和交互性所示: <animateMotion path="M0,300 S150,100 200,200 S400,400 500,0" dur="8s" repeatCount="indefinite" rotate="auto" />
- <animateColor>:改变某些元素与颜色有关的属性或样式的值;
<circle cx="250" cy="100" r="50" fill="red"> <animateColor attributeType="CSS" attributeName="fill" from="rgb(255,0,0)" to="rgb(0,0,255)" dur="8s" repeatCount="indefinite"/> </circle>
- <animateTransform>:改变SVG元素进行坐标变换时候的动画效果;
<rect x="333" y="49" width="50" height="50" fill="none" stroke="purple"> <animateTransform attributeName="transform" attributeType="XML" type="scale" from="1" to="3" additive="sum" begin="3s" dur="6s" fill="freeze" /> <animateTransform attributeName="transform" attributeType="XML" type="translate" from="0,0" to="-222,-45" additive="sum" begin="3s" dur="6s" fill="freeze" /> </rect>
- set:剩下的这个元素可以很容易地设置一个元素在指定时间段内的特殊属性
<circle cx="250" cy="100" r="50" fill="red"> <set attributeName="r" to="100" begin="1s" dur="5s" fill="remove" /> </circle>
attributeName="<attributeName>":批明所作用的SVG元素中哪个属性或样式需要产生动画效果。
attrbuteType="<XML|CSS|auto>":指明产生动画效果的属性或样式值是哪个命名空间定义的。“XML”表示“attributeName”的值是默认XML命名空间里定义的XML属性名;“CSS”表示“attributeName”的值是默认CSS属性的名称;“auto”是默认值,解析器解析时先在CSS属性列表中查找是否有匹配“attributeName”的属性名,然后再在XML的命名空间里找
1.与时间控制相关的常用属性
begin="<clock-time-value>|wallclock-sync-value|indefinite|eventName":定义动画的开始时刻。
- a.时间偏移值,如3S表示3秒后开始播放动画(hh:mm:ss.xxxx)
- b.现实世界中的时间,定义后要保证SVG文档要在这个时间之前打开
- c.Endefinite:表示这个动画不会自动开始,需要使用动态脚本调用"beginElement()"方法或指向动画元素
- d.eventName:表示在某个事件触发时开始播放动画。如begin="mousedown"
- 1.dur="<clock-time-value>|indefinite":定义动画的持续时间
- 2.end="<clock-time-value>|indefinite":定义动画的结束时间
- 3.restart="always|whenNotactive|never":是否重播
- 4.repeatCount:重复播放次数 indefinite表示无限重播
- 5.repeatDur:定义动画播放总时间
- 6.fil="freeze|remove":定义动画播放完毕后是停留在播放的终点还是回到起始位置
2.与过程控制相关的常用属性
from="<value>":定义该动画元素所作用的属性值在开始变化时的值
to="<value>":定义该动画元素所作用的属性值在结束变化时的值
by="<value>":定义该动画元素所作用的属性值每次变化的步长值
calcMode="discrete|linear|paced|spline":定义动画关键点直接过渡的插值计算方式
- discrete表示不采用插值算法,动画是从一个关键点跳跃到另外一个关键点
- linear表示采用线性插值算法,这是<animate>元素和<set>元素采用的默认插值算法
- paced表示采用在埋单上均匀变化的方法来插值
- spline表示采用三次贝塞尔曲线的方式来插值,需要"KeySplines"属性的配合
例子1:
<rect x="50" y="50" width="100" height="50"> <animate attributeType="XML" attributeName="x" from="50" to="300" dur="3s" begin="3s" restart="always" repeatCount="3" > </animate> </rect>
例子2:
<text x="0" y="0" font-size="37" visibility='hidden" stroke="black" stroke-width="2" > <animateMotion path="M0,0 L50,50 L100,150" begin="1s" dur="5s" fill="freeze" rotate="auto"/> </text>
例子3:
<svg width="100%" height="100%" version="1.1" xmlns="http://www.w3.org/2000/svg"> <g transform="translate(100,100)"> <text id="TextElement" x="0" y="0" style="font-family:Verdana;font-size:24; visibility:hidden"> It's SVG! <set attributeName="visibility" attributeType="CSS" to="visible" begin="1s" dur="5s" fill="freeze" /> <animateMotion path="M 50 50 L 300 300" begin="1s" dur="5s" fill="freeze" /> <animateTransform attributeName="transform" attributeType="XML" type="rotate" from="0" to="360" begin="1s" dur="15s" fill="freeze" repeatCount='indefinite'/> <animateTransform attributeName="transform" attributeType="XML" type="scale" from="1" to="3" additive="sum" begin="1s" dur="5s" fill="freeze" /> </text> </g> </svg>
二、事件的脚本编制(DOM动画)
象 HTML 页面一样,可以设置 SVG 图像以捕获某些事件(如点击鼠标和滚动),并用它们启动脚本。在构建简单SVG 图像时,可以通过属性捕获这些事件。最常用的是onclick、onactivate、onmousedown、onmouseup、onmouseover、onmousemove、onmouseout、onload、onresize、onunload 和 onrepeat。
当这些事件之一被触发,就可以将事件对象本身提供给脚本,脚本反过来再用它确定哪个对象触发了该事件(也就是点击了什么对象)。然后脚本可以操纵那个对象的特性,如它的属性。
这一示例回到了图案示例,但在此例中,当用户点击椭圆时,其填充由白色变为使用图案。
<?xml version="1.0"?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"> <svg width="500" height="300" xmlns="http://www.w3.org/2000/svg"> <desc>Scripting the onclick event</desc> <script type="text/ecmascript"> <![CDATA[ function hideReveal(evt) { var imageTarget = evt.target; var theFill = imageTarget.getAttribute("fill"); if (theFill == 'white') imageTarget.setAttribute("fill", "url(#notes)"); else imageTarget.setAttribute("fill", "white"); } ]]> </script> <defs> <pattern id="notes" x="0" y="0" width="50" height="75" patternTransform="rotate(15)" patternUnits="userSpaceOnUse"> <ellipse cx="10" cy="30" rx="10" ry="5"/> <line x1="20" y1="30" x2="20" y2="0" stroke-width="3" stroke="black"/> <line x1="20" y1="0" x2="30" y2="5" stroke-width="3" stroke="black"/> </pattern> </defs> <!-- Outline the drawing area with a blue line --> <rect x="1" y="1" width="350" height="200" fill="none" stroke="blue"/> <ellipse onclick="hideReveal(evt)" cx="175" cy="100" rx="125" ry="60" fill="url(#notes)" stroke="black" stroke-width="5"/> </svg>
三、基本的声明性 (SMIL) 动画
<?xml version="1.0" standalone="no"?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> <svg width="800px" height="800px" viewBox="0 0 800 800" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> <!-- Note that this is required in order to use xlink in the <use> element. --> <!-- THIS EXAMPLE NOT SUPPORTED IN INTERNET EXPLORER --> <title>Simplest SVG Animation</title> <desc>SVG declarative animation is used to rotate a square.</desc> <!-- Create a Cartesian coordinate system (with the y-axis flipped) for the animated square. That is, place the origin at the center of the 800 x 800 SVG viewport. --> <g transform="translate(400, 400)"> <!-- A 200 x 200 square with the upper left-hand corner at (-100, -100). This places the center of the square at the origin (0, 0): --> <rect x="-100" y="-100" width="200" height="200" rx="5" ry="5" style=" fill: orange; stroke: black; stroke-width: 3; stroke-dasharray: 10, 5;"> <animateTransform attributeType="xml" attributeName="transform" type="rotate" from="0" to="90" begin="0" dur="5s" fill="freeze" /> </rect> <line x1="-400" y1="0" x2="400" y2="0" style="stroke: black;" /> <!-- Represents the x-axis. --> <line x1="0" y1="-400" x2="0" y2="400" style="stroke: black;" /> <!-- Represents the y-axis (although up is negative and down is positive). --> </g> </svg>
同样的效果用javascript来实现:
<!DOCTYPE html> <html> <head> <title>JavaScript SVG Animation</title> <meta http-equiv="X-UA-Compatible" content="IE=Edge"/> <!-- Remove this line in production. --> </head> <body> <svg width="800px" height="800px" viewBox="0 0 800 800"> <g transform="translate(400, 400)"> <!-- Create a Cartesian coordinate system (with the y-axis flipped) for the animated square. That is, place the origin at the center of the 800 x 800 SVG viewport: --> <!-- A 200 x 200 square with the upper left-hand corner at (-100, -100). This places the center of the square at the origin (0, 0): --> <rect id="mySquare" x="-100" y="-100" width="200" height="200" rx="5" ry="5" style=" fill: orange; stroke: black; stroke-width: 3; stroke-dasharray: 10, 5;" /> <!-- Represents the x-axis: --> <line x1="-400" y1="0" x2="400" y2="0" style="stroke: black;" /> <!-- Represents the y-axis (although up is negative and down is positive): --> <line x1="0" y1="-400" x2="0" y2="400" style="stroke: black;" /> </g> </svg> <script> "use strict"; /* CONSTANTS */ var initialTheta = 0; // The initial rotation angle, in degrees. var thetaDelta = 0.3; // The amount to rotate the square about every 16.7 milliseconds, in degrees. var angularLimit = 90; // The maximum number of degrees to rotate the square. var theSquare = document.getElementById("mySquare"); theSquare.currentTheta = initialTheta; // The initial rotation angle to use when the animation starts, stored in a custom property. var requestAnimationFrameID = requestAnimationFrame(doAnim); // Start the loop. function doAnim() { if (theSquare.currentTheta > angularLimit) { cancelAnimationFrame(requestAnimationFrameID); // The square has rotated enough, instruct the browser to stop calling the doAnim() function. return; // No point in continuing, bail now. } theSquare.setAttribute("transform", "rotate(" + theSquare.currentTheta + ")"); // Rotate the square by a small amount. theSquare.currentTheta += thetaDelta; // Increase the angle that the square will be rotated to, by a small amount. requestAnimationFrameID = requestAnimationFrame(doAnim); // Call the doAnim() function about 60 times per second (60 FPS), or about once every 16.7 milliseconds until cancelAnimationFrame() is called. } </script> </body> </html>
用SVGDOM来实现:
<!DOCTYPE html> <html> <head> <title>JavaScript SVG Animation</title> <meta http-equiv="X-UA-Compatible" content="IE=Edge" /> <!-- Remove this line in production. --> </head> <body> <svg id="svgElement" width="800px" height="800px" viewBox="0 0 800 800"> <!-- Give the svg element a name so that we can easily access it via JavaScript. --> <g transform="translate(400, 400)"> <!-- Create a Cartesian coordinate system (with the y-axis flipped) for the animated square. That is, place the origin at the center of the 800 x 800 SVG viewport: --> <!-- A 200 x 200 square with the upper left-hand corner at (-100, -100). This places the center of the square at the origin (0, 0). Give the square a name so we can easily access it via JavaScript: --> <rect id="mySquare" x="-100" y="-100" width="200" height="200" rx="5" ry="5" style=" fill: orange; stroke: black; stroke-width: 3; stroke-dasharray: 10, 5;" /> <!-- Represents the x-axis: --> <line x1="-400" y1="0" x2="400" y2="0" style="stroke: black;" /> <!-- Represents the y-axis (although up is negative and down is positive): --> <line x1="0" y1="-400" x2="0" y2="400" style="stroke: black;" /> </g> </svg> <script> "use strict"; /* CONSTANTS */ var initialTheta = 0; // The initial rotation angle, in degrees. var thetaDelta = 0.3; // The amount to rotate the square about every 16.7 milliseconds, in degrees. var angularLimit = 90; // The maximum number of degrees to rotate the square. /* GLOBALS */ var requestAnimationFrameID; var mySquare = document.getElementById("mySquare"); var transformObject; mySquare.currentTheta = initialTheta; // The initial rotation angle to use when the animation starts, stored in a custom property. transformObject = svgElement.createSVGTransform(); // Create a generic SVG transform object so as to gain access to its methods and properties, such as setRotate(). mySquare.transform.baseVal.appendItem(transformObject); // Append the transform object to the square object, now the square object has inherited all the transform object's goodness. requestAnimationFrameID = requestAnimationFrame(doAnim); // Start the animation loop. function doAnim() { var transformObject; if (mySquare.currentTheta > angularLimit) { cancelAnimationFrame(requestAnimationFrameID); // Instruct the browser to stop calling requestAnimationFrame()'s callback. return; } mySquare.transform.baseVal.getItem(0).setRotate(mySquare.currentTheta, 0, 0); // Access the transform object (that was appended to mySquare in the init() function) and use its setRotate method to rotate the square about the point (0, 0) (which is at the center of the SVG viewport). mySquare.currentTheta += thetaDelta; // Place this line here so that the square isn't over rotated on the last call to doAnim(). requestAnimationFrameID = requestAnimationFrame(doAnim); // Call the doAnim() function about every 60 times per second (i.e., 60 FPS). } </script> </body> </html>
参考: