来源: IBM developerWorks 中国
--------------------
坐标和变换
元素在整个教程中都是通过坐标定位的。现在是该讨论这些坐标所适应的系统的时候了。
当首次访问文档时,用户代理(在大多数情况下,即浏览器)确定图像的观察口。观察口是文档实际可见的部分并且由一个坐标系统组成,该坐标系统以左上角的点(0,0)为原点,其正的 x 轴向右而正的 y 轴向下。坐标系统中的一个像素对应观察口中的一个像素。
有几个操作可以创建新的坐标系统。变换(接下来介绍)在被变换元素内部创建新的坐标系统,不过可以通过向文档添加另一个 <svg></svg> 元素来直接创建新的坐标系统。考虑下面的示例:具有相同 x 和 y 属性的同一元素在不同的位置显示,这是因为第二个元素实际上属于另一个坐标系统,它从第一个元素偏移 100 个像素:
<?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="400" height="200" xmlns="http://www.w3.org/2000/svg">
<desc>Coordinates</desc>
<g>
<ellipse cx="100" cy="100" rx="75" ry="60"
fill="pink" stroke="purple" stroke-width="5"
fill-opacity=".5"/>
<svg x="100" y="0">
<ellipse cx="100" cy="100" rx="75" ry="60"
fill="pink" stroke="purple" stroke-width="5"
fill-opacity=".5"/>
</svg>
</g>
</svg>

执行变换改变了元素所在的坐标系统,改变了它的外观。变换可以用来以数种方式改变元素的外观:
translate(x,y):该变换按指定数量偏移元素。
scale(x, y):该变换更改元素的大小。可以分别控制 x 和 y 方向上缩放量,但如果只指定一个值,那么它将用于两个方向。
rotate(n):该变换按指定的角度旋转元素。
skewX(n)/ skewY(n) :这两种变换根据适当的轴按指定的像素数量偏斜元素。
也可以使用矩阵指定变换,不过这超出了本教程的范围。
变换是累积的,并且既可以指定为单个变换属性的一部分也可以指定为嵌套元素的一部分,如下所示:
<?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="400" height="200" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<desc>Coordinates</desc>
<defs>
<rect id="refBox" x="0" y="0" height="100" width="100"
stroke="purple" stroke-width="3" fill="none"/>
</defs>
<g>
<!-- Top lines -->
<g transform="scale(1, .5) translate(0, 50)">
<path stroke="purple" stroke-width="3"
d="M25 50 L 125 5 L 225 50" fill="none"/>
</g>
<!-- Left box -->
<use xlink:href="#refBox" mce_href="#refBox"
transform="translate(25, 50) skewY(15)"/>
<!-- Right box -->
<g transform="translate(25,25)">
<g transform="skewY(-15)">
<g transform="translate(100, 79)">
<use xlink:href="#refBox" mce_href="#refBox"/>
</g>
</g>
</g>
<!-- Text along the side -->
<g transform="rotate(90) translate(0, -250)">
<text font-size="35">Transform!</text>
</g>
</g>
</svg>
在这个示例中要注意的可能最重要的事就是正在变换的是实际坐标系统。对象本身实际上没有变换,但它所在的坐标系统中的更改使它看起来发生变化。考虑上面的“Transform!”文本。现在正在沿 y 方向将它平移负 250 个像素,因此显而易见文本应该消失,它会在观察口顶部以上显示。然而在平移发生前,坐标系统进行了 90 度旋转,所以负的 y 值实际上使文本向右移动了 250 个像素。

没有任何更改时,初始观察口指定一个大小,其左上方坐标为 0,0,右下方坐标为介于该大小值与 0,0 之间的像素数目。但有时候期望的效果是按可用的大小(不管大小是多少)而不是按图像进行缩放。那就要用到 viewBox 属性了。
viewBox 属性重新映射观察口,它指定将在观察口左上角和右下角出现的新值。请记住:当在 Web 页面上放置 SVG 图形时,<object></object> 标记的尺寸决定观察口的大小。
例如,如果眼睛和眼镜添加了 viewBox 属性,如下所示:
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN"
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg width="300px" height="200px"
viewBox="50 0 350 200" preserveAspectRatio="xMinYMin"
xmlns="http://www.w3.org/2000/svg">
<desc>ViewBox</desc>
<defs>
<linearGradient id="lineGradient">
<stop offset="0%" stop-color="red" />
<stop offset="100%" stop-color="yellow" />
</linearGradient>
. . .
页面会在任何分配给该图像的框内显示图像,进行适当的缩放。因此下面的 Web 页面:
<html>
<head><title>SVG Demonstration</title></head>
<body>
<object type="image/svg+xml" data="test.svg"
height="100" width="300">
<img src="NonSVG.gif" mce_src="NonSVG.gif" alt="SVG 图像静态版本" />
</object>
<object type="image/svg+xml" data="test.svg"
height="100" width="100">
<img src="NonSVG.gif" mce_src="NonSVG.gif" alt="SVG 图像静态版本" />
</object>
<object type="image/svg+xml" data="test.svg"
height="300" width="300">
<img src="NonSVG.gif" mce_src="NonSVG.gif" alt="SVG 图像静态版本" />
</object>
</body>
</html>
以不同大小显示该图像三次:

preserveAspectRatio 属性确定如何实现缩放。none 值将使图像伸展以适应框,即使这样会引起图像失真。xMinYMin值(如上所示)将图像的最小 x 和 y 值与框的最小 x 和 y 值对齐。其它可能的值有 xMinYMid、xMinYMax、xMidYMin、xMidYMid(缺省值)、xMidYMax、xMaxYMin、xMaxYMid 和 xMaxYMax。
________________________
路径
SVG 提供的预定义形状当然是有用的,但有时它们还不足以完成工作。特别是在这两种情况下:第一,当图像需要曲线,它不能由多边形或折线创建,第二,当动画或文本需要沿页面上的特定形状前进时。
这就需要路径了。路径是一系列命令,用来创建作为图像一部分精确定义的形状。该形状可以是开放的(如线)或闭合的(如多边形),并可以包含一条或多条线、曲线和线段。
最基本的路径由几条线段组成。例如:
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN"
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg width="400" height="400"
xmlns="http://www.w3.org/2000/svg">
<desc>A simple path</desc>
<rect x="1" y="1" width="350" height="350"
fill="none" stroke="blue" />
<path d="M 100 100 L 300 50 L 300 250 L 100 300 Z"
fill="red" stroke="blue" stroke-width="3" />
</svg>
上述代码根据提供的指令生成一个简单的多边形。这些指令如下所示:
M 100 100 :移至点 100, 100。
L 300 50 :画一条线至点 300, 50。
L 300 250 :画一条线至点 300, 250。
L 100 300 :画一条线至点 100, 300。
Z :通过将线画回到原始点闭合此形状。(更具体地说,回到最近一条“move”命令所指定的点。)
最终结果显示如下:

请注意这里显示的所有命令都是大写字母,这说明这些坐标是相对于整个坐标系统的绝对坐标。使用小写字母命令则指明为相对坐标。因此命令 l 50 50 从当前点创建一条线至距当前点下方和右方各 50 像素的点,那一点可能在任何位置。
其它简单的线命令包括作水平线的 H (或 h)和作垂直线的 V (或 v)。
路径命令可以创建三种类型的曲线:
椭圆曲线是椭圆的一部分,也称为弧。A (或 a)命令通过指定起点、终点、x 和 y 轴半径、旋度和方向来创建它们,如下所示。
三次贝塞尔曲线由一个起点、一个终点和两个将曲线“拖”向自己的控制点定义。C (或 c)命令(指定起点和终点)和 S (或 s)命令(假设这条曲线从最近的命令终止的地方继续)创建这些曲线。
二次贝塞尔曲线与其三次贝塞尔曲线类似,不过仅包含一个控制点。Q(或 q)和 T(或 t)命令可以创建这些曲线。
下面的示例显示了一些样本弧,为了清楚除去了文本。弧命令的格式如下:
A radiusX, radiusY rotation large arc flag, sweep flag endX, endY
因此一个半径为 50 和 25,没有旋度, 使用椭圆长轴部分以及曲线的下段,在距起点右边 50 个像素和下方 25 个像素处终止的弧将使用:
a50,25 0 1,0 50,25
一些变体如下所示:
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN"
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg width="4cm" height="4cm" viewBox="0 0 400 400"
xmlns="http://www.w3.org/2000/svg">
<desc>Curved paths</desc>
<rect x="1" y="1" width="398" height="300"
fill="none" stroke="blue" />
<!-- First row -->
<text x="25" y="30">Large arc flag=1</text>
<text x="25" y="45">Sweep flag=0</text>
<text x="25" y="60">Rotation=0</text>
<path d="M75,100 a50,25 0 1,0 50,25"
stroke="blue" stroke-width="5" fill="none" />
. . .
<path d="M150,100 a50,25 0 1,1 50,25"
stroke="blue" stroke-width="5" fill="none" />
. . .
<path d="M275,100 a50,25 -45 1,1 50,25"
stroke="blue" stroke-width="5" fill="none" />
<!-- Second row -->
. . .
<path d="M100,225 a50,25 0 0,1 50,25"
stroke="blue" stroke-width="5" fill="none" />
. . .
<path d="M225,225 a50,25 0 0,0 50,25"
stroke="blue" stroke-width="5" fill="none" />
</svg>
请注意所有的弧形都有相同的起点和终点,但形状不同。

贝塞尔曲线的形状由起点和终点以及控制点的位置确定。这些命令的格式如下:
C control1x, control1y, control2x, control2y, endx, endy
S control2x, control2y, endx, endy
Q controlx, controly, endx, endy
T endx, endy
对于 S 和 T 命令,假设第一个控制点为前一条曲线的第二个控制点的反射。例如:
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN"
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg width="4cm" height="4cm" viewBox="0 0 400 400"
xmlns="http://www.w3.org/2000/svg">
<desc>Curved paths</desc>
<rect x="1" y="1" width="398" height="300"
fill="none" stroke="blue" />
<!-- First row -->
<path d="M75,100 c25,-75 50,50 100,0 s50,-50 150,50"
stroke="blue" stroke-width="5" fill="none" />
<circle cx="175" cy="100" r="5" fill="red" />
<circle cx="75" cy="100" r="5" fill="red" />
<circle cx="325" cy="150" r="5" fill="red" />
<path d="M75,225 q25,-75 100,0 t150,50"
stroke="blue" stroke-width="5" fill="none" />
<circle cx="175" cy="225" r="5" fill="red" />
<circle cx="75" cy="225" r="5" fill="red" />
<circle cx="325" cy="275" r="5" fill="red" />
</svg>

标记是对路径的自然补充。它们是可以添加到线和路径起点、终点和顶点的元素。最常用的是将箭头添加到线的终点,不过可以使用任何对象。
过程很简单:定义标记,然后使用 marker-start、marker-end 和 marker-mid 属性将其赋值给相关元素。例如:
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN"
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg width="4cm" height="4cm" viewBox="0 0 400 400"
xmlns="http://www.w3.org/2000/svg">
<desc>Markers</desc>
<defs>
<marker id="arrow"
viewBox="0 0 10 10" refX="0" refY="5"
markerUnits="strokeWidth" markerWidth="3" markerHeight="10"
orient="auto">
<path d="M 0 0 L 10 5 L 0 10 z" fill="yellow" stroke="black"/>
</marker>
</defs>
<rect x="1" y="1" width="398" height="300"
fill="none" stroke="blue" />
<!-- First row -->
<path d="M75,100 c25,-75 50,50 100,0 s50,-50 150,50"
stroke="purple" stroke-width="5" fill="none"
marker-start="url(#arrow)"
marker-mid="url(#arrow)"
marker-end="url(#arrow)" />
<!-- Second row -->
<path d="M75,200 c25,-75 50,50 100,0 s50,-50 150,50"
stroke="purple" stroke-width="3" fill="none"
marker-start="url(#arrow)"
marker-mid="url(#arrow)"
marker-end="url(#arrow)" />
</svg>
这个标记本身由一个简单的三角形路径组成,它由标记属性决定。已经设置了 viewBox,以便不管框是什么,标记本身总是会填充整个框。因为 markerUnits 值的缘故,框本身受应用标记线的大小影响。markerUnits 属性也被设置为 userSpaceOnUse,这使标记使用常规坐标系统。refX 和 refY 属性确定标记(该标记“附加”到它所标记的线)内的点。最后,标记的方位设为 auto,使它的 Y 轴与线的切线垂直。(为了理解这一方位,标记构建为指向 X 轴方向)。
请注意标记大小随笔划大小的改变而改变:

————————————————————
文本
SVG 的强大能力之一是它可以将文本控制到标准 HTML 页面不可能有的程度,而无须求助图像或其它插件(后者会带来可访问性挑战)。任何可以在形状或路径上执行的操作(如绘制或滤镜)都可以在文本上执行。
一个不足之处是 SVG 不执行自动换行。如果文本比允许空间长,则简单地将它切断。多数情况下,创建多行文本需要多个文本元素。
可以使用 tspan 元素将文本元素分成几部分,允许每部分有各自的样式。在 text 元素中,空格的处理与 HTML 类似;换行和回车变成空格,而多个空格压缩成单个空格,如下面的早期示例所示:
<?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="400" height="200" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<desc>Text</desc>
<defs>
</defs>
<g>
<text x="20" y="50" font-size="30">
Colors can be specified
</text>
<text x="20" y="100" font-size="30">by their
<tspan fill="rgb(255,0,0)">R</tspan>
<tspan fill="rgb(0,255,0)">G</tspan>
<tspan fill="rgb(0,0,255)">B</tspan>
values</text>
<text x="20" y="150" font-size="30">
or by keywords such as
</text>
<text x="20" y="200" font-size="30">
<tspan fill="lightsteelblue">lightsteelblue</tspan>,
</text>
<text x="20" y="250" font-size="30">
<tspan fill="mediumseagreen">mediumseagreen</tspan>,
</text>
<text x="20" y="300" font-size="30">and
<tspan fill="darkorchid">darkorchid</tspan>.
</text>
</g>
</svg>

实际上,所有的属性(对于所有元素,不仅是文本)都可以用级联样式表与一个元素关联,并且文本的所有 CSS 属性都在 SVG 图像中可用。
可以直接用样式属性设计元素的样式,或者引用样式表设计元素的样式。不应该解析样式表(因为它们偶尔包含会引起问题的字符),因此将它们置于 XML CDATA 节。
<?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="400" height="200" xmlns="http://www.w3.org/2000/svg">
<desc>Text</desc>
<defs>
<style type="text/css">
<![CDATA[
.abbreviation { text-decoration: underline; }
]]>
</style>
</defs>
<g>
<text x="20" y="50" font-size="30">Colors can be specified</text>
<text x="20" y="100" font-size="30">by their
<tspan fill="rgb(255,0,0)" class="abbreviation">R</tspan>
<tspan fill="rgb(0,255,0)" class="abbreviation">G</tspan>
<tspan fill="rgb(0,0,255)" class="abbreviation">B</tspan>
values</text>
<text x="20" y="150" font-size="30">or by keywords such as</text>
<text x="20" y="200">
<tspan style="fill: lightsteelblue; font-size:30">
lightsteelblue
</tspan>,
</text>
. . .
</g>
</svg>
