首页 » 编写高质量代码:改善JavaScript程序的188个建议 » 编写高质量代码:改善JavaScript程序的188个建议全文在线阅读

《编写高质量代码:改善JavaScript程序的188个建议》建议184:使用SVG创建动态图形

关灯直达底部

与传统的客户端编程相比,JavaScript操作的对象被限制在DOM模型之内,无法进行图形编程。所以长久以来,在设计网页时都仅仅是在“搭积木”,并且这些积木只有一种形状——长方形。这些“长方形的积木”就是应用在HTML元素上的“盒子”模型(box model)。每个盒子有边框(border)、边缘(margin)和填充(padding)。我们只能控制这些盒子的大小和有限的样式。这些方块的集合对于构建一个传统的文档页面已经足够了,但Web的流行已经使网页承担的任务远远超出了传递文字信息。

SVG(Scalable Vetor Graphics,可缩放矢量图)作为一种通用的数据格式,属于XML语言的一个分支,主要负责描述矢量图的数据结构关系。实际上,SVG不是第一种用XML描述图片的格式,甚至也不是第一种在Web上提出的XML与矢量图的组合的标准。在它之前的VML(Vector Markup Language)和PGML(Precision Graphics Markup Language)都是基于XML的矢量图规范。

SVG中各种元素和属性的详细说明可以参考相关规范文档。下面代码是一个简单的SVG文件。


<?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 xmlns=/"http://www.w3.org/2000/svg/"version=/"1.1/">

<circle cx=/"100/"cy=/"100/"r=/"40/"fill=/"red/"/>

</svg>


第一条语句为XML指令定义版本,并说明此文件引用到其他文件。第二条语句是文档类型定义,规定此XML中哪些是有效的SVG元素。这里引用的http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd正是第一条语句中standalone属性为no的原因。从第三条语句开始是SVG的真正定义,circle元素指定画一个圆,cx、cy和r属性分别指定圆心的横坐标、纵坐标和半径,fill属性指定用红色填充此圆内部的区域。

将这段代码粘贴进任何一个文本编辑器,然后将文件保存为一个SVG文件,如sun.svg,就可以画出一个红色的太阳。各种浏览器对SVG的支持情况不同。总的来说,IE 6、IE 7和IE 8对SVG都没有原生的支持,需要专门的插件(如Adobe SVG Viewer)才能显示,IE 9支持SVG,不过IE有自定义的VML技术可以实现相同的效果。其他主流浏览器都对SVG标准有不同程度的支持。

(1)使用<img>标签显示


<img src=/'sun.svg/'>


将SVG与传统的互联网图片格式同等使用(现在只有Chrome、Safari和Opera支持)。

(2)使用<embed>标签显示


<embed src=/"sun.svg/"

type=/"image/svg+xml/"

pluginspage=/"http://www.adobe.com/svg/viewer/install//"/>


pluginspage属性的值是Adobe公司为不原生支持SVG的浏览器开发的插件Adobe SVG Viewer的安装地址。2009年1月1日,Adobe公司已经终止对该产品的支持。

(3)使用<object>标签显示


<object data=/"sun.svg/"

type=/"image/svg+xml/"

codebase=/"http://www.adobe.com/svg/viewer/install//"/>


(4)使用<iframe>标签显示


<iframe src=/"sun.svg/"border=/"0/">

</iframe>


下面是对在HTML中各种使用SVG的方式是否支持进行判断的页面代码,sun.svg文件与该页面保存于同一目录。


<!DOCTYPE HTML PUBLIC/"-//W3C//DTD HTML 4.0 Transitional//EN/">

<HTML>

<HEAD>

<TITLE>SVG in HTML</TITLE>

</HEAD>

<BODY>

1.使用<img>标签

<br>

<img src=/"sun.svg/">

<br>

2.使用<embed>标签

<br>

<embed src=/"sun.svg/"

type=/"image/svg+xml/"

pluginspage=/"http://www.adobe.com/svg/viewer/install//"/>

<br>

3.使用<object>标签

<br>

<object data=/"sun.svg/"

type=/"image/svg+xml/"

codebase=/"http://www.adobe.com/svg/viewer/install//"/>

<br>

4.使用<iframe>标签

<br>

<iframe src=/"sun.svg/"border=/"0/">

</iframe>

</BODY>

</HTML>


如果仅将SVG作为图片引用,则只发挥了它的静态功能。SVG的动态功能包括两个方面:支持动画和支持脚本编程。

SVG在设计时就加入了对动画的支持,这是通过另一种W3C颁布的动画语言SMIL(Synchronized Multimedia Integration Language)实现的。SMIL在应用时与SVG结合得非常紧密,它与SVG一样,是一种声明性(declarative)的标记语言,通过元素(element)和属性(attribute)来定义动画的行为。这里只给出一个简单的例子,不做详细介绍,因为浏览器对它的支持还很有限,另外SMIL声明性的本质也使其表现力受到限制,不如使用脚本自定义动画灵活。

(5)用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 xmlns=/"http://www.w3.org/2000/svg/">

<polygon points=/"50,100 100,100 75,50/"stroke=/"#660000/"fill=/"#cc3333/">

<animateTransform

attributeName=/"transform/"

begin=/"0s/"

dur=/"10s/"

type=/"rotate/"

from=/"0 0 0/"

to=/"360 60 60/"

repeatCount=/"indefinite/"

/>

</polygon>

</svg>


polygon元素指定画一个多边形,由于这里给定了三个顶点,所以是一个三角形。将上面的代码保存成一个SVG文件,在一个页面中引用该文件,如果此时的浏览器支持SMIL,屏幕上会显示一个不断旋转的红色三角形;如果此时的浏览器只支持SVG,将看到一个静止的红色三角形。

(6)脚本可编程性

SVG是一个XML文件,用于XML编程的两种模型DOM和SAX也适用于它。因为SVG是被设计用于互联网的,所以通过JavaScript和DOM访问它就是最重要的应用模式。我们已经熟悉了通过JavaScript和DOM动态地修改HTML,同样也可以在浏览器中动态地创建、修改和删除图片,这也是接下来要介绍的在SVG方面的重点。

为了演示这些动态功能,可以采取和前面的在页面中使用SVG不同的方式——在XHTML中直接写入SVG的源文本,而在前面的4种方式中,SVG的定义都保存在和页面不同的另一个文件中。这样做有两个原因:一是在支持XHTML和SVG的浏览器中,可以通过JavaScript直接访问和修改SVG;二是在互联网的未来标准HTML 5中,SVG可以这样直接在HTML中定义,就像其他HTML元素一样。

下面设计一个进度条,显示一个绿色的运动的进度条。


<html xmlns=/"http://www.w3.org/1999/xhtml/">

<head>

<title>进度条</title>

<script language=/'Javascript/'>

/*<![CDATA[*/

function ProgressBar(info){

var stem={};//此函数最后返回的代表进度条的对象

var done=0,length,outline,bar;//声明内部变量

bar=document.getElementById(/'done/');//进度条中绿色的变化部分

length=80;

//重置进度到零

function reset{

return to(0);

}

//设置进度到某个值

function to(value){

if(value>=100){

done=100;

bar.setAttribute(/'width/',length);

}

else{

done=value;

bar.setAttribute(/'width/',Math.round(done*length/100));

}

return stem;

}

//进度变化某个值

function advance(step){

return to(done+step);

}

//以下为进度条对象添加方法

//获得当前进度值

stem.getDone=function{

return done

};

stem.reset=reset;

stem.to=to;

stem.advance=advance;

return stem;//返回可供脚本使用的进度条对象

}

//测试进度条对象

function testBar{

var bar=ProgressBar;

//此内部函数每运行一次,增加进度值1,直到进度值为100

function test{

if(bar.getDone===100){

clearInterval(id);

}

else{

bar.advance(1);

}

}

//每0.1秒改变一次进度

var id=setInterval(test,100);

}

//页面载入后开始测试

window.addEventListener(/'load/',testBar,true);

/*]]>*/

</script>

</head>

<body>

<p id=/'svgDiv/'>

<svg xmlns=/"http://www.w3.org/2000/svg/"version=/"1.1/"

viewBox=/"0 0 100 100/">

<g id=/'progBar/'>

<rect x=/'10/'y=/'45/'width=/'80/'height=/'10/'stroke=/'grey/'fill=/'white/'/>

<rect id=/'done/'x=/'10/'y=/'45/'width=/'0/'height=/'10/'fill=/'green/'/>

</g>

</svg>

</p>

</body>

</html>


<svg xmlns=/"http://www.w3.org/2000/svg/"version=/"1.1/"viewBox=/"0 0 100 100/">表示在XHTML中直接插入svg元素,并且指定命名空间等其他属性。

viewBox定义矢量图可见的坐标空间,4个数字依次是原点的x坐标、y坐标以及平面的宽度、高度。SVG的坐标空间符合计算机中指定屏幕空间的惯例,x坐标轴的正方向向右,y坐标轴的正方向向下。

style属性指定svg元素的各种外观特性。SVG与HTML一样,可以应用CSS定义外观,并且有一些专门的特性——XHTML中的JavaScript代码被包含在/*<![CDATA[*/和/*]]>*/之间。

在HTML文件中不需要这样做,因为在HTML中<script>标签内的JavaScript代码被解释为CDATA(Character Data,XML中的一种类型,用于包含任意的字符数据);而在XHTML中<script>标签内的部分被解释为PCDATA(Parsed Character Data,也是XML中的一种类型,为字符数据和元素的混合内容),也要通过XML的语法检查,而JavaScript代码显然不符合XML的标签的定义语法。解决方法就是在代码外人工加上![CDATA[和]]>标注,使XML的语法校验器忽略这段内容。但这样会带来另一个问题,有些浏览器不认识CDATA标注,导致这些代码又无法通过JavaScript的语法检查。因此在CDATA标注两侧再加上JavaScript的注释标记,这样<script>标签内的代码既能通过XML的语法检查,又能被JavaScript引擎识别。

<svg>标签内有一个<g>标签和两个<rect>标签。g元素用于分组。分组不仅可以使SVG的内容结构清晰,还可以使同一组内的对象被集体操作。rect元素代表一个矩形,x、y、width和height属性分别指定矩形左上顶点的横坐标、纵坐标,以及矩形的宽度和长度;stroke属性指定图形外框的线条颜色。我们用第一个空心的矩形显示进度条的外框,第二个实心的绿色矩形显示变化的进度。为了在脚本中方便地访问,我们设置了绿色矩形的id属性。

在JavaScript脚本中用DOM先后获得绿色矩形对象并修改它的宽度属性。getElementById和setAttribute的用法和在HTML中没有两样。注意,有些在操作HTML时使用的方法,在XML中是不存在的,如根据名称获取元素的getElementsByName。

在这个例子中,前三点特别设定有些麻烦,不过这些在正在获得越来越多支持并且很快将成为互联网的现实标准的HTML 5中都不是必须的。在HTML 5中,不需要在html和svg元素中指定命名空间,svg和其中的各种标签会被自动识别,JavaScript代码也会和在目前的HTML页面中一样,不需要在两侧加上CDATA标注。

SVG中的元素同样支持用户界面的事件,因此可以通过鼠标和键盘触发的各种事件改变SVG中的图形,使得在整个页面上可以进行丰富的图形互动,而不需要借助于Flash插件。