内容


XML 问题

使用 SVG 编程

充分利用这一灵活便携的 XML 图形语言

Comments

系列内容:

此内容是该系列 # 部分中的第 # 部分: XML 问题

敬请期待该系列的后续内容。

此内容是该系列的一部分:XML 问题

敬请期待该系列的后续内容。

在 SVG 于 2001 年左右首次出现以前,已有相当多功能强大的矢量图形格式。Postscript 及其类似产品 PDF 广泛应用于许多应用程序。其他特定于应用程序的格式包括基于 Postscript 的 Adobe Illustrator (.ai)、CorelDRAW (.cdr)、Computer Graphics Metafile (.cgm)、Windows Metafile (.wmf)、Autocad (.dxf)、Hewlett-Packard Graphics Language (.hpgl)、WordPerfect (.wpg) 等。对于甚至可以组合动画、声音和交互性的矢量绘图,则常使用 Macromedia 的 SWF/Flash 在万维网上发布相关内容。

SVG 与所有其他格式的主要区别在于,前者是 XML 的一个应用程序。尽管对于同等的图形,使用 SVG 描述比使用多数其他矢量格式描述要复杂得多,但对于编程操作而言,SVG 则是一种更通用的工具。尤其是,您可以在使用 ECMAScript 和其他文档对象模型 (DOM) 的 Web 浏览器(或其他应用程序)中操纵 SVG。而且同样重要的是,您可以使用熟悉的 XML 技术(如 XSLT)或 XML 支持库转换和生成 SVG。可以将 SVG 与其他使用名称空间的 XML 格式混合。而且,甚至可以使用层叠样式表 (CSS) 限定 SVG 的样式。总之,在 XML 和 Web 空间,SVG 是一个友好的播放器。

除了是 XML 格式以外,SVG 还是一个由 W3C 发布的完全开放的标准(请参阅 参考资料)。 与上述多数矢量格式不同,SVG 是完全免费的,没有任何版权或专利权限制,而且其规范完全 有文档记录。与其他 W3C 标准类似,规范文档本身 受版权保护的 —— 但根据 W3C 的非限制性条款的规定,允许广泛传播以及免费复制和使用(例如,规范中没有附带禁止公开协议)。

入门

令人高兴的是,您可以在多数新式 Web 浏览器中查看 SVG,可以在本机也可以通过插件查看。精确的支持状态在不断变动,但通过正确的技术,您应能够使用 Firefox/Mozilla、KHTML(Konqueror 和 Safari)、Opera 或 Amaya 查看 SVG。使用 Adobe 或 Corel 的插件,甚至还可以让 Internet Explorer 显示 SVG。还存在一些独立的 SVG 查看器,特别是使用免费软件 Batik SVG 工具包(是 Apache XML 项目的一部分 —— 请参阅“参考资料”)。

在许多情况下,SVG 文件是作为独立的文档查看的。在这样的情况下,这些文件表现为 MIME 类型 image/svg+xml,并通常有一个文件扩展名 .svg。Gzip 压缩的 SVG 文件应有扩展名 .svgz,可由多数启用 SVG 的工具直接支持。SVG 文件只是具有适当 DTD 的 XML 文件。您将在下面几个例子中了解到这一点。

然而,可能更为常见的是,您可以将一个 SVG 文档嵌入较大的文档中,特别是嵌入 XHTML 页。其他复合 XML 格式(如 OASIS OpenDocument)也可以(或将支持)将 SVG 嵌入其中。将 SVG 图形嵌入 (X)HTML 页有三种方式:

  • 通过 <object> 标签
  • 通过 <embed> 标签
  • 作为嵌入的名称空间

不过,具体使用哪一种方式有效取决于您的浏览器和版本。例如,我创建了下面的 XHTML 文档(使用 doctype 来支持名称空间嵌入):

清单 1. XHTML 文档 (svg-nested.html)
<?xml version="1.0" standalone="no"?>
<!DOCTYPE html PUBLIC
    "-//W3C//DTD XHTML 1.1 plus MathML 2.0 plus SVG 1.1//EN"
"http://www.w3.org/2002/04/xhtml-math-svg/xhtml-math-svg.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
  <title>SVG as embedded object and nested namespace</title>
</head>
<body>
<h2>Object tag</h2>
<object type="image/svg+xml" data="standalone.svg">
Your browser is currently unable to display SVG images.
</object>
<h2>Nested namespace</h2>
<svg:svg version="1.1" width="5cm" height="4cm"
      xmlns:svg="http://www.w3.org/2000/svg">
  <svg:title>Four rectangles</svg:title>
  <svg:rect x="0.5cm" y="0.5cm" width="2cm" height="1cm"/>
  <svg:rect x="0.5cm" y="2cm" width="1cm" height="1.5cm"/>
  <svg:rect x="3cm" y="0.5cm" width="1.5cm" height="2cm"/>
  <svg:rect x="3.5cm" y="3cm" width="1cm" height="0.5cm"/>
  <!-- Show outline of canvas using 'rect' element -->
  <svg:rect x=".01cm" y=".01cm" width="4.98cm" height="3.98cm"
       fill="none" stroke="blue" stroke-width=".02cm" />
</svg:svg>
<h2>Embed tag</h2>
<embed id="svg3" src="standalone.svg" />
</body>
</html>

通过尝试,Safari/KHTML 在浏览器中表现最好。尽管如此,如果文件使用 .html 扩展名,而不是 .xml 扩展名命名,结果会更好。总之,<embed> 也许是最成功的方法。您可能会看到文档呈现为:

图 1. Web 浏览器显示的 svg-nested.html
Web 浏览器显示的 svg-nested.html

另外,本文提供的示例是组合基本形状、文本、颜色等内容的较为简单的示例 —— 但 SVG 完全能够表现复杂和引人入胜的绘图。为了提高读者的兴趣,下面是 Ghostscript 和其他工具中包括的著名的 PostScript 老虎图片,它使用 SVG 呈现(我仅调整了它的总体大小):

图 2. Web 浏览器将老虎图像显示为 SVG
Web 浏览器将老虎图像显示为 SVG
Web 浏览器将老虎图像显示为 SVG

SVG 文档的特点

前面的 XHTML 例子(参阅 清单 1)为您显示了非常基本的 SVG 绘图。引用的外部文件 (standalone.svg) 所包含的元素与 XHTML 中嵌入的相同,只是去掉了标签中额外的名称空间限定符。SVG 为您提供了许多图形元件,而且每个图元都有可以进一步指定图形的多种 XML 属性:颜色、大小、位置、填充、轮廓等。不过,直观的图形元件(如椭圆、矩形或多边形)或者一些可能包括立方体或二次贝塞尔曲线等的更为复杂的 <path> 元素,常常包括在 <g> 元素中,以便将若干个图元组合在一起。<g> 组的优点是,您可以对它进行整体缩放、移动、设定样式或修改。 对组的修改通用于其中的形状集合(包括嵌入的 <g> 组)。在编写 SVG 文档脚本时这特别有用。

始终如一

有关 SVG 文档需要注意的一点是,它们并非完全 是真正的 XML。从语句上说,SVG 确实是 XML,但在 SVG 属性中,SVG 绘图信息内容的重要部分包含在逗号和空格分隔的数据中。这里所说的信息内容 并不是指 XML Infoset,仅指它包含什么?的更加非正式的概念。这样做是一种合理的折衷方法,因为对定义曲线的每个点或句柄都使用子元素将会使 SVG 更加繁琐。但是,XML 级处理技术(如 XSLT)因此能够不用真正处理太多的路径数据。例如,下面是一个二次贝塞尔曲线路径元素:

<path d="M200,300 Q400,50 600,300 T1000,300"
      fill="none" stroke="red" stroke-width="5"  />

下面是一个描述五角星形的多边形:

<polygon fill="red" stroke="blue" stroke-width="10"
          points="350,75  379,161 469,161 397,215
                  423,301 350,250 277,301 303,215
                  231,161 321,161" />

添加样式

前面提到过您可以使用 CSS 选择器和语法来修改 SVG 绘图的外观。对于 HTML 和其他支持 CSS 的格式,既可以指定内嵌 CSS 信息,也可以作为对外部样式表的引用。下面是一个非常简单的内嵌 CSS 的例子:

清单 2.一个 简单的 CSS 例子 (inline-styled.svg)
<?xml version="1.0" standalone="no"?>
<!-- By ref:
  <?xml-stylesheet href="mystyle.css" type="text/css"?>
-->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="10cm" height="5cm" viewBox="0 0 1000 500"
    xmlns="http://www.w3.org/2000/svg" version="1.1">
  <defs>
    <style type="text/css"><![CDATA[
      rect {
        fill: red;
        stroke: blue;
        stroke-width: 3
      } ]]>
    </style>
  </defs>
  <rect x="200" y="100" width="600" height="300"/>
</svg>

尽管使用 CSS 无疑可以限定整个标签的样式,但您可能会发现,对 CSS 和 SVG 使用类选择器会更好。例如,您可以在样式表中定义各种类型的矩形,然后将一个 class XML 类属性附加到绘图中的每个矩形,而不用重复使用为类定义的整个颜色、填充、描边和其他属性列表。只须更改样式表,就可以更改图表的整体外观,使之更适用于不同的环境。

重复使用元素

除使用 CSS 之外,清单 2 显示了 SVG 另一种很好的功能:您可以在 SVG 文档中包括预定义的内容 —— 在呈现的文档内或文档之外定义的内容。

使用预定义内容作为 SVG 绘图一部分的方法之一是使用 <image> 元素。在概念上,SVG 中的 <image> 与 HTML 中的 <img> 非常类似:该元素只须指示呈现客户机在当前的 SVG 环境中绘制外部图像的内容 —— 其本身可能是 SVG 或者是 JPEG 或 PNG 格式的光栅图像。您几乎可以像调整一个规则的图形元素那样来调整外部图像的大小和改变其位置。例如:

清单 3. 在当前图像中包括一个外部 SVG 绘图
<image x="200" y="200" width="100px" height="100px"
xlink:href="http://example.org/external.svg">

<image> 标签更有意思的也许是令人叫好的 <defs><use> 元素。首先,您可以使用 CSS 例子中所看到的内容 创建 SVG 元素,这些元素在定义时没有直接呈现 —— 通常,SVG 呈现模型严格按照 SVG 文档中出现的顺序绘制每个对象,每个对象均覆盖最后一个。但 <style> 不是典型的样式,以后不能真正呈现其本身

您可以在诸如 <defs> 节中包括想要包括的任何图形元素,其中包括 <g> 组和 <symbol> 元素(符号与组类似;由于本文篇幅所限,这里不对其区别进行说明)。在定义的外部,您可以使用在 <defs> 节中定义的图形元素 —— 甚至可使用在外部 SVG 文档的 <defs> 节中定义的图形元素。例如:

清单 4. 使用预定义的图形元素
<?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="7cm" height="3cm" viewBox="0 0 70 30" version="1.1"
     xmlns="http://www.w3.org/2000/svg"
     xmlns:xlink="http://www.w3.org/1999/xlink">
  <desc>'use' with a 'transform' attribute</desc>
  <defs>
    <rect id="MyRect" x="0" y="0" width="40" height="5"/>
  </defs>
  <use xlink:href="#MyRect" transform="translate(10,23) rotate(-30)" />
  <use xlink:href="#MyRect" transform="translate(20,3) rotate(30)" />
  <use xlink:href="http://example.org/foo.svg#OtherRect"/>
</svg>

清单 4 中,定义相同的矩形使用两种不同的转换呈现,然后还呈现了外部定义的元素。(id 名称表明它也是一个矩形,但从该片断中不能明显确定 —— 事实上,外部内容可以在呈现之间更改)。

动画和脚本

刚才已提到,使用 ECMAScript 可以编写 SVG 脚本。原则上,这可让 SVG 文档与用户操作交互。为了支持 Web 应用程序空间,SVG 还包含一个用于超链接的与 HTML 类似的 <a> 元素。根据鼠标在特定的图形元素上单击,SVG 中的简单交互可以修改文档。清单 5 中的例子虽然很普通,但您可以方便地让 SVG 图形响应。例如,在下面的流程图中的图形或对象区域上单击:

清单 5. 让 SVG 形状响应单击
<svg>
  <title>ECMAScript function for an onclick event</title>
  <desc>Simplified from 
   http://www.w3.org/TR/SVG11/images/script/script01.svg</desc>
  <script type="text/ecmascript"> <![CDATA[
      function circle_click(evt) {
      var circle = evt.target;
      var currentRadius = circle.getAttribute("r");
      if (currentRadius == 100)
        circle.setAttribute("r", currentRadius*2);
      else
        circle.setAttribute("r", currentRadius*0.5);
    } ]]>
  </script>
  <!-- Act on each click event -->
  <circle onclick="circle_click(evt)" cx="300" cy="225" r="100" fill="red"/>
</svg>

您还可以使用 ECMAScript 和 DOM 让 SVG 图形产生动画效果。例如,清单 6 中的代码可以使文本产生一个好看的效果,即增加和更改不透明度:

清单 6. 使用 JavaScript 让 SVG 产生动画效果
<svg viewBox="0 0 400 200"
     onload="StartAnimation(evt)" version="1.1"
     xmlns="http://www.w3.org/2000/svg">
  <script type="text/ecmascript"><![CDATA[
    var txt, step=0;
    function StartAnimation(evt) {
      txt = evt.target.ownerDocument.getElementById("Text");
      ShowAndGrowElement();
    }
    function ShowAndGrowElement() {
      step = step+1;
      if (step > 200) return;
      // Scale text string gradually until it is 20 times larger
      txt.setAttribute("transform", "scale("+ step/10 +")" );
      // Make the string more opaque
      txt.setAttribute("opacity", step/200);
      // Call ShowAndGrowElement again 50 milliseconds later.
      setTimeout("ShowAndGrowElement()", 50)
    }
    window.ShowAndGrowElement = ShowAndGrowElement
  ]]></script>
  <g transform="translate(50,150)" fill="red" font-size="7">
    <text id="Text">SVG</text>
  </g>
</svg>

纯粹的 SVG 脚本

使用 ECMAScript 可为您提供完美的编程灵活性,但如果您所需要的只是动画,SVG 还提供了 <animate> 和相关的标签(如 <animateMotion><animateColor>)。它们都非常灵活,可让您以各种方式分别赋予 SVG 文档中每个元素动画效果。例如,清单 6 中的代码可产生与 清单 5 中所示技术相同的增加和呈现不透明效果:

清单 6. 单独使用 SVG 表现动画效果
<svg viewBox="0 0 400 200" xmlns="http://www.w3.org/2000/svg">
  <g transform="translate(50,150)" fill="red" font-size="7">
    <text id="Text">SVG
      <animateTransform attributeName="transform" attributeType="XML"
              type="scale" from="0" to="20" begin="0s" dur="10s"
              fill="freeze" />
      <animate attributeName="opacity" attributeType="CSS"
               from="0" to="1" begin="0s" dur="10s" repeatCount="1" />
    </text>
  </g>
</svg>

结束语

本文初步探讨了 SVG 格式的一些基本知识。撰写本文让我对 SVG 作为一种格式而感到兴奋不已。Web 确实需要矢量格式以与比例无关的方式有效地传达复杂图形。再加上脚本、动画、链接和所有其他内容使 SVG 更加有用。所幸的是,多数 Web 浏览器现在能够很好地支持 SVG,因此部署基于 SVG 的图形和简单的 Web 应用程序实际上并不存在什么障碍。


相关主题


评论

添加或订阅评论,请先登录注册

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=XML, Web development
ArticleID=83398
ArticleTitle=XML 问题: 使用 SVG 编程
publish-date=05162005