| 文章索引 |
|---|
| 蓝骑士SVG教程:SVG动态与动画 |
| 第一课 SVG的变形属性 |
| 第二课 SVG动画 |
| 第三课 结合JavaScript产生SVG动画 |
| 第四课 SVG鼠标事件 |
| 第五课 SVG键盘事件 |
| 第六课 动态插入SVG元素 |
| 所有页面 |
本教程是蓝骑士SVG教程的第四部分,介绍了SVG的变形属形、SVG动画、结合JavaScript的SVG动画,SVG鼠标事件,SVG键盘事件及怎样动态插入SVG元素。
目录结构
- 第一课 SVG的变形属性
- 第二课 SVG动画
- 第三课 结合JavaScript产生SVG动画
- 第四课 SVG鼠标事件
- 第五课 SVG键盘事件
- 第六课 动态插入SVG元素
所有的SVG图片中的元素都有一个"变形"属性.通过设置和改变元素的值,我们能够移动和变形SVG图片中的元素.一个变形属性包含一系列的"变化",这些"变化"包括:
"矩阵"( (a)(b)(c)(d)(e)(f) )
"矩阵"定义了一个2*3的矩阵(或者看作六个数的一个数列). 它和元素相匹配.详细请参看下面其他"变化"的解释来理解.
"移动"( (tx)[(ty)] )
"移动"属性的设置将移动元素.(tx)的值沿着x轴,(ty)的值沿着y轴.在六数数列中(即一个矩阵),数列的最后两位为(tx)(ty).
"比例"( (sx)[(sy)] )
"比例"属性的设置将会从元素中心点根据(sx)(sy)的值放缩元素.如果(sy)没有被给出,那么它将默认为(sx)的值.例如,如果(sx)的值 是0.5,元素将会缩小到原始尺寸的50%.在六数数列中(即一个矩阵),(sx)和(sy)对应的是第一和第四位的数值.
如果要放缩元素而元素又不在中心点(0,0),那么你必须先将元素移动使元素中心在中心点,然后执行"比例',元素放缩后,再将元素移动回到原来的位置.例如,要把一个在(150,100)出的元素缩小到50%,你需要执行下列步骤:
1. "移动"(150,100)
2. "比例" .5
3. "移动"(-150,-100)
(请注意次序)
"旋转"( (rotate-angle) )
"旋转"属性的设置可以控制元素绕着中心点(0,0)旋转任意角度(rotate-angle).例如,如果角度值(rotate-angle)为45 度,元素将会顺时针旋转45度.就像在"比例"中我们做的,如果元素不在中心点,我们首先要将它移动到中心点,然后旋转,再将它移回原来的位置.
"x轴倾斜"
"x轴倾斜"将在中心点(0,0)把元素在x轴轴向倾斜一定角度(angle).在六数数列中(即一个矩阵),"x轴倾斜"角度(angle)在第三位以弧度表示.
"y轴倾斜"
"y轴倾斜"将在中心点(0,0)把元素在y轴轴向倾斜一定角度(angle).在六数数列中(即一个矩阵),"y轴倾斜"角度(angle)在第二位以弧度表示.
在下面的表中,在文本框键入不同变化的不同数值,然后点击add来查看它们的效果."变化"将会被累计,在下面的多行文本框中显示"变化"结果.点击reset可以取消"变化".
"""
***附js
SVG规范包含了基于时间的简单SVG动画元素.使用这一属性,一个SVG创作者能够创作大量小到颜色渐变,大到动态滤镜效果的SVG作品,以及包含放 缩和旋转的变形,沿着一定路径的运动,甚至是根据实时键盘输入的复杂效果.这一课简单的讨论一些动画元素,如果想了解更多的细节,请参看SVG规范书.
颜色动画
我们从一些简单的颜色动画效果开始.(animateColor)元素定义了SVG颜色动画的属性."""
在上面的例子中,色彩渐变的颜色动画描述包含在了自定义的一个URI标识"gradient_star"的标签里.就像其他的SVG属性所共有的的,给 定确切的URI标识可以精确的控制某一个SVG元素.如果没有确定的URI标识,SVG将会默认的将当前描述给最近的一个目标.
现在,需要产生动画的元素知道了要对什么进行动画,(上面的例子中元素就是被标识的"gradient_star"),它还需要知道怎样进行变化来长生动画.这需要下面的属性值来描述:
- from 定义起始数值
- to 定义结束数值
- by 定义相对的偏移值
- values 一张相对分离的数值表
运动路径
(animateMotion)标签允许元素产生一些简单的旋转,放缩,移动和倾斜变化.在(animateMotion)标签里添加路径数据,SVG元素将可以沿着路径产生运动."旋转"rotate属性控制SVG元素沿着特定路径运动时 的的旋转性质.旋转的值可以是一个相对于当前用户的图形系统中所给定的x轴定义的一个角度值,也可默认为"auto",即沿着路径方向旋转,或 是"auto-reflect",沿着路径方向的180度反方向旋转.在上面的例子中,沿垂直的八字形运动的元素旋转的值是-45度,沿着水平八字形运动 的元素旋转的值是"auto".
运动控制
默认的运动一般是线性运动.calcMode的下列属性能进一步控制元素的运动:离散
动画将在两个数值之间产生跳跃的变化.线性
默认设置.步进
类似于线性,但定义了类线性变化的间隔值.曲线
对应于按照贝赛尔曲线定义的时间-位置曲线.关键曲线
使用"曲线"模式,能够用最小的定义产生很复杂的变化.例如,实时的控制元素的x和y值,就能对应的实时控制元素的运动.使用"曲线"模式,动画元素需要包含keySplines属性值.keySplines定义了贝赛尔曲线的关键控制点,来控制动画的变化.这样的控制允许平滑的产生变化(类似于淡入淡出的平滑效果),这一点在动画中非常重要.
上面的例子,每一个小圆给定了相同的起始点和终点,但不同的keySpline值产生了不一样的效果.
下面的图表显示了每一个运动开始和结束的加速度和减速度,这些都在贝赛尔曲线中被定义.请注意上例的小圆在y轴方向的加速度和减速度的变化.
你可以更多的参看在"演示与举例"中的其他动画。
尽管SVG规范书中定义的动画特征已经非常广泛,包含了很多普遍意义的动画特征,但SVG动画结合javascript能产生更加丰富的效果.
有时仅仅使用一般的标准SVG动画元素并不能达到所需的动画效果.例如,也许你想产生一些无级变化(类似无级变速),或者是随机的改变一个属性值,或者根据 某一个非线性公式来确定运动中的某些变化数值,这时候,结合与SVG相关联的JavaScript和DOM,你依然可以得到你所需要的.
下面是一个JavaScript动画的例子.
上面的例子实时的在改变紫色部分元素的"d"属性.
所有的动画所需要的JavaScript代码都在SVG文件中被写入.这时图像更容易的在任何网页中被使用.
动画由SVG标签中的"被载入"(onload)引发."onload"句柄保存了动画的初始值,通过调用系统中的setInternal函数让浏览器开始播放动画.
{
// Save a pointer to the SVGDocument object
// so that we can use it to retrieve various
// named elements inside the animation function.
svgdoc = event.getCurrentNode().getOwnerDocument();
// Start the animation loop.
setInterval ('next_frame()', 100);
}
上述的过程构成了绝大多数的JavaScript动画原理.在next_frame方程中,使用svgdoc的值,你可以定义任何在SVG文件中你所需要定义的元素.看看下面的解释让我们更进一步的了解next_frame函数.
动态变化的线段是贝赛尔曲线在SVG文件宽度上的一段线段.贝赛尔曲线需要两个控制点.动画的形成就是经常性的改变这两个控制点而保持线段首尾的固定.我们 随机的产生一些"目标"target数值来控制点的一致性,也就是我们逐渐的减少或增加当前点的数值使之逐渐逼近"目标"target的数值.
在next_frame方程中,我们使用4个通用的变量来保持当前的点的一致,它们分别是:(x0,y0)第一控制点.(x1,y1)第二控制点;我们也使用另4个通用的变量,来获得目标的坐标值:(tx0,ty0),(tx1,ty1).
next_frame方程的第一步是使用DOM的方法重新获取(path)元素的句柄.svgdoc的句柄的获得则在SVG文件被调用的同时,由on-load时间触发.
if (!linenode)
return;
|| (tx0 == x0 && ty0 == y0 && tx1 == x1 && ty1 == y1))
{
tx0 = Math.floor (400*Math.random());
ty0 = Math.floor (300*Math.random());
tx1 = Math.floor (400*Math.random());
ty1 = Math.floor (300*Math.random());
}
y0 = change_coord (y0, ty0);
x1 = change_coord (x1, tx1);
y1 = change_coord (y1, ty1);
('d', 'M0,300L0,150C'+x0+','+y0+','+x1+','+y1+',400,150L400,300z');
交互和事件驱动也是SVG规范中的一部分.超链接,鼠标事件,键盘事件和状态改变事件组成了SVG的动态特性.标签(a)用于指明当前浏览器的哪一部分将被新的URL链接的内容重绘.下面是一个超链接的实例,这里绘制了一个新的三角形:
<path d="M 0 0 L 200 0 L 100 200 Z">
</a>
如果点击三角形,当前浏览器的内容将被W3C组织的主页所代替(http://www.w3.org).
SVG的一个独特特征是相对独立的图像可以被链接独立引用,下例的鼠标掠过(rollover)动态效果就是由此获得.让你的鼠标在右边的html超链 接(s,v,g)上慢慢掠过,然后再让鼠标直接在图片上慢慢掠过,观察一下效果.(注意:"掠过"效果只能在IE4.0和NS3.0以上版本可获得)
通过改变一定的属性值,我们就能创建鼠标掠过的动态效果.
例如,在上面的SVG图像中的linkS元素"fill-opacity"属性值从"0"变化到".7",获得了鼠标掠过的动态变化.
这里的脚本script使用了与SVG元素关联的事件句柄.我们使用"鼠标掠入"mouseOver"和"鼠标掠出"mouseOut这两个事件,定义 了两个分离的过程函数,每一个事件分别的命名为 mouse_over_a 和 mouse_out_a.在SVG中的事件句柄调用就像在HTML中调用一样.例如:
就像在HTML中一样,事件句柄的只能被任何有效的JavaScript语言声明.特别地,它也能被JavaScript过程函数从上一个HTML文件 或当前的SVG文件本身引用.事件对象也能直接在JavaScript里被声明.这个对象包含了更多的事件属性,例如事件类型,鼠标位置等等.
在下面的例子中,鼠标掠过第一幅图像将触发过程函数操纵第二幅图像.注意,这里两个图像是相对分离的.将你的鼠标掠过图像下方标有数字的盒子,然后试着点击一下.
***附js
虽然交互作用相当的复杂,但建立一定的脚本语句,我们能够克服这一点.查看脚本请点击"查看JavaScript源文件".注意这里面有大量的函数和特 征我们在以前的例子中已经使用过.例如,使元素可见(特别应用在鼠标掠过时),操纵已经存在的元素和使他们产生持续的动态变化(前面 的"gradient_star"这个例子很好的描述了这样的控制).
和鼠标事件一样,键盘事件也能用脚本语言编写.组合键盘事件和文本元素,SVG创作者可以产生动态的交互.
在下面的例子中,先用鼠标在图片上点一下,然后试试用键盘敲如一些字母.
在上一课中,动画脚本引用的是与SVG元素关联的事件句柄.这里,我们使用键盘事件和定义的key_press过程函数来获取对元素的控制.
{
// Get the character-code of the key that was pressed.
var key = event.getCharCode();
// Get string equivalent of input character-code.
var input_text = String.fromCharCode(key);
// Determine which SVG text element to use for
// showing the entered key.
var elem_idx = next_letter + 1;
var elem_name = 'letter' + elem_idx;
var svgobj = svgdoc.getElementById(elem_name);
var svgstyle = svgobj.getStyle();
// To change the element's text, we set the data
// of its first child node.
svgobj.getFirstChild().setData (input_text);
...
}
key_press过程函数中使用的技术我们已经在前面的"文本"和"动画"中讨论过了.对于每一个键盘敲击,它自动在SVG图像中设置一个文本元素,然后触发一个动画序列来完成文本元素的淡入背景效果.
我们已经看到(defs)和(style)这两个元素能够在定义之后被后续的过程引用产生更多的元素.类似的,(use)元素也能定义为一个SVG元素或SVG物件,在SVG文件中被成倍的调用.
SVG的一个特征是它支持W3C DOM标准.这意味着,使用如JavaScript这样的语言,你能够完成非常流畅的SVG作品.在浏览器中,每一个SVG文件中的独立部分成为文件树状 结构的一个节点."引用JavaScript",你能够定义,删除和改变它在文件树状结构的位置,或者简单的添加一些新节点.这是发展SVG动态图像文件 的关键点.让我们来看一个简单的文件:
<rect id="box" x="0" y="0" width="145" height="70" style="fill:none"/>
<g id="contents">
<circle cx="10" cy="10" r="50" style="fill:red"/>
<text x="23" y="45">ABC!</text>
</g>
</svg>
我们已经看了几个利用JavaScript访问文件树状结构的节点的例子.特别是我们已经使用了SVG规范中的getElementById()的方法 来重新获得一个已命名的节点.我们也使用了XML Core DOM中的getFirstChild()来获得文本元素(text)的节点.
在本教程中,我们也检验另一些移动和插入新节点的方法.在下面的例子中,试着点击中央被分层的物件(在底座上的),我们能看到物件被移动到最下面的层中,这就是说,物件被移动到文件树状结构的更高处,所以被安置在表层物件之后.
请在下面的图像中的底座上方点击鼠标:
当你点击图像中的物体时,SVG元素触发了onclick事件的arrange_me() JavaScript过程函数.例如:
1.我们使用父节点的removeChild()函数在文件树状结构中移动物件:groupnode.removeChild (target);
2.我们使用insertBefore()和getFirstChild()函数重新定位并插入节点,使之成为新节点:groupnode.insertBefore (target, groupnode.getFirstChild());
利用类似的概念,我们可以把物件移动到前方,后方,某一个物件前或另一组物件中.
现在让我来看看一种在SVG文件中加入节点的方法.在上面同一个例子中,请点击底部一行任意一个黑色图标.这能随即在图像中自动复制出一个图案,这就是说,图标物件被复制并在文件树状结构中加入了一个新节点.
这里,当你点击一个图标时,SVG元素触发了onclick事件的clone_me() JavaScript过程函数.例如:
在clone_me() JavaScript过程函数中,一旦我们获得物件节点(事件的目标),我们就能通过下面的步骤在SVG文件中复制并加入新的节点:
1.我们使用cloneNode()函数"克隆"物件节点:var newnode = target.cloneNode(false);
2.克隆的节点能够像其他的节点一样被自由的控制,我们能够改变它的形状和属性,例如: newnode.setAttribute ('x', x); newnode.setAttribute ('y', y); newnode.getStyle().setProperty ('fill', fill);
3.最后,我们使用getElementById()函数重新获得原来节点的标识,使用 appendNode()函数在文件中添加克隆的节点: var contents = svgdoc.getElementById ('contents'); newnode = contents.appendChild (newnode);
我们自由的复制了节点,你也同样可以自由的创建一些新节点,使用一些方法插入到文件树状结构中去.
继续下一步学习,请进入“蓝骑士SVG教程:SVG后续工作”部分。
(THE END)