SVG——新一代Web设计及互动媒体的革新

怎样为你创建的SVG添加交互功能

来源:IBM developerWorks 中国

  可伸缩矢量图(Scalable Vector Graphics SVG)是一种基于XML的语言,用于绘制二维图形。不过,它的能力不局限于简单的静态矢量图形。本文展示了如何将交互元素加入到SVG文档中,使其可以对用户输入作出响应。
  SVG中的交互性可以分为三个领域:链接、事件和脚本。本文将依次讨论这三个领域。

  链接

  最基本的交互形式是链接。在SVG中,通过一个<a>标签提供链接,这与HTML链接的方式几乎相同。将<a>标签与一个xlink:href属性结合使用便可以建立一个链接。在<a>和</a>标签之间的所有内容都作为链接的一部分。代码1展示了一个例子,它有三个元素,设置为链接到三个不同的URL。单击这里以在浏览器中查看它们。
  文本、矩形和多边形元素都有到不同页面的链接,这表明所有SVG元素——不管是文本、圆还是不规则的多边形都可以作为一个链接。注意,如果将鼠标移动到这些元素上面,指针会相应地发生改变,表明这是一个链接。
  其功能与HTML中的image map(或者hotspot)基本上相同。不过,在HMTL中这会是一个很麻烦的过程,要用专门的软件在一个图像上手工绘制热点——如果这个图像或者链接改变了,那么更新它们会非常麻烦。在SVG中,定义和维护链接则容易得多,这主要是因为链接可以随着SVG内容动态移动。

  代码1 链接

<svg>
<a xlink:href="http://www.w3.org//Graphics//SVG//Overview.htm8">
<rect x="10" y="10" width="100" height="30" rx="10" ry="10"
style="fill:lightgrey"/>
<text x="30" y="30" font-size="12">Click here</text>
</a>
<a xlink:href="http://www.ibm.com//developerworks/">
<circle cx="100" cy="100" r="50" style="fill:grey"/>
<text x="80" y="100" font-size="12">Or here</text>
</a>
<a xlink:href="http://www.ibm.com/" target="new">
<polygon
points="60 160,165 172,180 60,290 290,272 280,172 285,250 255"
style="fill:dimgrey"/>
<text x="160" y="200" font-size="12">Or even here</text>
</a>
</svg>

注意在多边形的xlink中使用的target=new属性。它指示查看程序在单击这个元素时打开一个新的浏览器窗口。

  事件

  SVG支持鼠标单击、鼠标移动和鼠标按下这样的用户鼠标事件。代码2展示了一个例子:

  代码2 使用鼠标的交互性

<svg>
<rect x="10" y="10" width="140" height="140" rx="5" ry="5"
style="fill:lightgrey">
<set attributeName="fill" from="lightgrey" to="red"
begin="mouseover" end="mouseout"/>
</rect>
<text x="200" y="75" font-size="30">Move over me and click
<set attributeName="font-size" from="30" to="35"
begin="mouseover" end="mouseout"/>
<set attributeName="fill" from="black" to="red"
begin="mousedown" end="mouseup"/>
</text>
</svg>

 

  单击这里以便观看效果。矩形和文本元素对不同的事件:如移动鼠标和单击做出反应,产生一种简单的滚动效果。试着将鼠标移动到元素上面以观看这些效果。任何可以应用到元素上的SVG属性:如填充颜色、笔划宽度、大小和透明度都可以以这种方式改变。
  文字元素可以对两种事件做出反应:mouseover和mousedown。这表明可以对同一个元素指定多个事件。SVG支持许多不同的事件:有关所有事件类型的完整列表可以参看参考资料中的W3C的SVG站点。
  如果希望一个元素上的事件可以引发对另一个元素的操作,可以对SVG元素指定id属性,然后引用它们。代码3展示了一个例子。

  代码3 改变另一个元素的属性

<svg>
<rect id="changeToRed" x="20" y="20" width="25" height="25" rx="5"
ry="5" style="fill:lightgrey"/>
<text x="50" y="35" font-size="14">Move over for red text</text>
<rect id="bigText" x="20" y="60" width="25" height="25" rx="5"
ry="5" style="fill:lightgrey"/>
<text x="50" y="75" font-size="14">Move over for big text</text>
<rect id="bigRedText" x="20" y="100" width="25" height="25" rx="5"
ry="5" style="fill:lightgrey"/>
<text x="50" y="115" font-size="14">Click me for big red text</text>
<text id="changingText" x="250" y="100" font-size="30"
fill="black">Change me
<set attributeName="fill" from="black" to="red"
begin="changeToRed.mouseover" end="changeToRed.mouseout"/>
<set attributeName="font-size" from="14" to="50"
begin="bigText.mouseover" end="bigText.mouseout"/>
<set attributeName="font-size" from="14" to="50"
begin="bigRedText.click" end="bigRedText.mouseout"/>
<set attributeName="fill" from="black" to="red"
begin="bigRedText.click" end="bigRedText.mouseout"/>
</text>
</svg

  单击这里可以在浏览器中观看效果。当鼠标移动到不同的矩形上时,文本就会改变。有三个矩形被指定了各自的id属性,文字的set元素通过"id.eventName"引用这些属性。触发矩形的事件时,文本的属性就会相应地改变。
  还可以用一个动画响应事件。代码4展示了这样的一个例子:

  代码4 开始一个动画

<svg>
<rect x="20" y="20" width="250" height="250" rx="5" ry="5"
style="fill:red">
<animate attributeName="opacity" from="1" to="0"
begin="click + 1s" dur="1s" fill="restore" />
</rect>
<circle cx="250" cy="250" r="100" style="fill:blue">
<animate attributeName="fill" from="blue" to="green"
begin="mouseover" dur="2s" fill="restore" />
</circle>
</svg

  单击这里以便观看效果。单击矩形时,它会淡出,在圆形上面移动鼠标时,它的颜色会改变。注意可以在begin属性中使用"+Xs"使动画延迟开始。

  按下鼠标键

  虽然SVG上的大部分交互是通过鼠标进行的,但是SVG也支持键盘输入。这是通过事件处理程序accessKey实现的,如代码5所示。
  代码5 捕获键按下

<svg>
<rect x="20" y="20" width="100" height="100" rx="5" ry="5"
style="fill:red">
<animate attributeName="opacity" from="1" to="0"
begin="accessKey(1)" dur="3s" fill="restore" />
</rect>
<rect x="140" y="20" width="100" height="100" rx="5" ry="5"
style="fill:red">
<animateTransform attributeName="transform" type="rotate"
from="0" to="90" begin="accessKey(2)" dur="3s"/>
</rect>
<rect x="260" y="20" width="100" height="100" rx="5" ry="5"
style="fill:red">
<animateColor attributeName="fill" from="red" to="green"
begin="accessKey(3)" dur="3s" />
<animate attributeName="y" from="20" to="100"
begin="accessKey(
)" dur="3s" fill="restore" />
</rect>
</svg

  单击这里以观看效果。三个矩形设置为响应键盘上的数字键1、2和3。试一试按下每一个键,并观察图像相应的反应。
  可以设置一个元素响应任意数量的不同的键。注意第三个矩形设置为监听两个键按下。第三个矩形上的第二个accessKey处理程序设置为监听键,您可能认出它就是回车键(Enter)的标准HTML编码。要指定任何特殊字符或者空格字符,必须使用X这样的HTML编码格式,其中XX是ASCII字符编码。

  脚本

  到目前为止我只讨论了用SVG支持的内置功能响应事件的基本方法。虽然可以只使用这些功能完成很多工作,但是要实现更高级的效果就需要使用脚本了。SVG支持像VBScript和JavaScript这样的脚本语言,对于这里的例子,我将使用JavaScript。
  要让一个SVG对象对脚本中的事件作出响应,要在触发器名上加前缀on,这样click就变为onclick,mouseover就变为onmouseover,等等。代码6展示了一个SVG脚本的例子。

  代码6 用JavaScript编写SVG脚本

<svg>

<script type="text/javascript">
<![CDATA[
var redVal=0;
var greenVal=0;
var blueVal=0;
function changeCol(evt)
{
var targetshape = evt.getTarget();
redVal = Math.round(Math.random()*255);
greenVal = Math.round(Math.random()*255);
blueVal = Math.round(Math.random()*255);
targetshape.setAttribute("fill",
"rgb(" + redVal + "," + greenVal + "," + blueVal + ")");

}
// ]]>
</script>
<circle cx="200" cy="200" r="100" fill="blue"
onclick="changeCol(evt)" />
</svg

  下面逐步分析代码6:

  1. 编写 SVG 脚本的第一步是通知查看程序不再使用 SVG,而是使用脚本语言。还必须用 type 属性定义使用哪种脚本语言编码。在这里它设置为 text/javascript 。
  2. <![CDATA[是XML命令,它告诉查看程序停止解析代码,并读取接下来的块中的代码,这里的代码是字符数据的形式。这可以防止查看程序将括号和其他特殊字符按SVG元素处理,并使脚本编写更容易。
  3. 现在就可以开始脚本了。首先,定义三个变量:redVal、greenVal和blueVal。这些变量分别具有red、green和blue值,它们将 在函数中用到。这个函数名为changeCol,它带有一个参数(evt)。evt是一个SVG保留字,它描述刚发生的事件。这里,evt方法称为 getTarget(),这个方法返回对触发该事件的SVG对象的一个引用。这个引用被存储在变量targetShape中。
  4. 用简单的JavaScript函数Math生成三个值在0到255之间的随机数。
  5. 最后,对targetshape调用setAttribute方法。用前一步中生成的三个随机数将该对象的fill属性设置为一个RGB值(如rgb(150,200,50))。
  6. 关闭CDATA块和脚本后,返回SVG。画出一个圆,通过onClick元素,在单击时让它调用函数changeCol(evt)。

  单击这里以便观看效果。单击这个圆时,每次单击它时填充都会变为一个随机颜色。

  当一个函数要应用到多个SVG元素时,脚本是最有用的。例如,可以在代码6中添加一个矩形,如下所示:

<rect x="400" cy="400" width="100" height="100" fill="blue"
onclick="changeCol(evt)" />

  单击时,这个矩形会与前面的圆形一样调用同一个脚本改变其颜色。

  要查看这一点,可以看一下其他例子。如果查看源代码,您会看到三个方法:changeCol、changeEdge和resetEdge。试着将鼠标移动矩形上面并单击。所有矩形都设置为响应onclick、onmouseover和onmouseout事件,它们为此调用的是同一个脚本函数。还要注意onload属性:第一次装载SVG文档时要调用这个属性,它对于您的SVG初始化很有用。

  交互文本

  在SVG中创建交互文本比您想象中的要复杂一些。在定义文本元素时,显示的文本是文本元素的子元素,而不是像font-size这样的属性,因此不能像前面那样简单地调用setAttribute来修改其内容。相反,必须创建一个新的文本元素,并用它替换当前的文本元素。代码7展示了一个例子。

  代码7 编写文本变化的脚本

<svg> 
<script type="text/javascript">
<![CDATA[
function changeText(evt)
{
targetXtext=svgDocument.getElementById("XPos");
targetYtext=svgDocument.getElementById("YPos");
var XPos = evt.getClientX();
var YPos = evt.getClientY();
var newXPosText = svgDocument.createTextNode("X Position : " + XPos);
var newYPosText = svgDocument.createTextNode("Y Position : " + YPos);
targetXtext.replaceChild(newXPosText,targetXtext.getFirstChild());
targetYtext.replaceChild(newYPosText,targetYtext.getFirstChild());
}
function changeTextNotOver(evt)
{
targetXtext=svgDocument.getElementById("XPos");
targetYtext=svgDocument.getElementById("YPos");
var newXPosText =
svgDocument.createTextNode("X Position : Not over Rectangle");
var newYPosText =
svgDocument.createTextNode("Y Position : Not over Rectangle");
targetXtext.replaceChild(newXPosText,targetXtext.getFirstChild());
targetYtext.replaceChild(newYPosText,targetYtext.getFirstChild());
}
function recordClick(evt)
{
targetClickText=svgDocument.getElementById("ClickPos");
var XPos = evt.getClientX();
var YPos = evt.getClientY();
var newClickText =
svgDocument.createTextNode("Last Click made at X=" + XPos + " Y=" + YPos);
targetClickText.replaceChild(newClickText,
targetClickText.getFirstChild());
}
// ]]>
</script>
<text id="XPos" x="50" y="50"<X Position :</text>
<text id="YPos" x="50" y="70"<Y Position :</text>
<text id="ClickPos" x="50" y="90"<Last Click made at : </text>
<rect x="50" y="100" width="200" height="200" style="fill:blue"
onmousemove="changeText(evt)" onmouseout="changeTextNotOver(evt)"
onclick="recordClick(evt)"/>
</svg>

  单击这里以便观看效果。将鼠标移动到矩形上面时,会显示鼠标的X和Y位置,并且这两个显示的值会随着鼠标的移动而改变,在矩形上单击鼠标会记录下单击的位置。
  分析函数changeText(evt)可揭示创建交互文本的步骤:
  1 为所使用的每一个文本元素指定id,这样脚本就可以提取它们。
  2 第一次调用svgDocument.getElementById(),其中传递的参数是要改变的文本元素的ID。它被存储在一个变量中以供以后使用。
  3 调用evt方法getClientX()和getClientY()以得到指针的X和Y坐标,并将它们存储在变量XPos和YPos中。
  4 调用svgDocument.createTextNode()创建一个新文本节点。将更新过的文本字符串传递给这个函数。
  5 最后,对这个文字元素调用replaceChild方法。它带两个参数:-替换文本节点和被替换的子元素。对getFirstChild()的调用保证更新的文本放置正确。

  参照代码7,您应该可以将交互文本加入到自己的SVG文档中。

  结束语

  可以使用本文中描述的各种交互技术使您的SVG文档对用户有更大的用途。设法将这些技术结合在一起以得到您想要的功能。
  看一下这个小例子以了解如何综合使用这些技术制作一个交互菜单。

  参考资料

  您可以参阅本文在developerWorks全球站点上的英文原文.
  下载本文中的所有样本文件。
  阅读可伸缩矢量图(SVG)1.0规范或者最新的1.2规范。
  阅读W3C站点上完整的支持的事件列表。
  请访问Adobe的SVG Zone以获得众多的SVG资源,其中包括一个可以下载SVG查看程序的专区。
  学习Brian Venn在developerWorks上的文章"产生可伸缩向量图形",它介绍了如何在SVG文档中创建动画(2003年6月)。
  请学习Nicholas Chase的developerWorks教程"Introduction to SVG",该教程是学习SVG的一个好起点(2002年2月)。
  学习Andrew Watts在developerWorks上的教程"Interactive,dynamic Scalable Vector Graphics"以将交互性提高到一个新的水平(2003年6月)。
  在developerWorks的XML专区可以找到更多XML参考资料。
  IBM的DB2数据库不仅提供了关系数据库存储,而且提供了像DB2XML Extender这样提供XML和关系系统之间桥梁的XML相关工具。请访问DB2开发者园地以了解更多关于DB2的内容。
  查明如何才能成为一名IBM认证的XML和相关技术的开发人员。

  关于作者

  本文作者Brian Venn照片

  Brian Venn在英国太空防御系统(British Aerospace Defence Systems)工作了三年后,于2000年10月加入IBM。他毕业于南安普敦大学,获得了天体物理学学士学位,并且通过了DB2和软件测试方面的认证。他目前在Hursley Park从事集成测试工作。

  本篇文章属转载文章,原文链接:http://www.ibm.com/developerworks/cn/xml/x-svgint/  英文版本链接:http://www.ibm.com/developerworks/library/x-svgint/index.html?S_TACT=105AGX52&S_CMP=cn-a-x

(THE END)

 

将要更新