《SVG精髓》 – [美] J. David Eisenberg / [加] Amelia Bellamy-Royds 著 / 易郑超 何鹏飞 译

读完时间:2021 年 9 月 30 日

出版时间:2015 年 9 月

1.1 图形系统

计算机中描述图形信息的两大系统是栅格图形(raster graphics)和矢量图形(vector graphics)。

在栅格图形系统中,图像被表示为图片元素或者像素的长方形数组(如图1-1所示)。每个像素用其RGB颜色值或者颜色表内的索引表示。这一系列像素也称为位图(bitmap),通常以某种压缩格式存储。由于大多数现代显示设备也是栅格设备,显示图像时仅需要一个阅读器将位图解压缩并将它传输到屏幕上。

图1-1:栅格长方形

在矢量图形系统中,图像被描述为一系列几何形状(如图1-2所示)。矢量图形阅读器接受在指定坐标集上绘制形状的指令,而不是接受一系列已经计算好的像素。

图1-2:矢量长方形

2.1 将SVG作为图像

将SVG文件作为图像包含进来时,无论使用哪种方法,都具有一定的局限性。图像渲染(即“绘制”,也就是SVG代码被转换为栅格图像以用于显示)时与主页面是分离的,而且无法在两者之间进行通信。

图2-1:使用四种方式在Web页面中插入SVG的屏幕截图

2.3 混合文档中的SVG标记

将标记合并到一个文件中可以缩短Web页面的加载时间,因为浏览器无需单独下载图像文件。

第3章 坐标系统

SVG的世界就是一张无限大的画布。

3.1 视口

文档打算使用的画布区域称作视口。我们可以在 <svg> 元素上使用width和height属性确定视口的大小。属性的值可以是一个数字,该数字会被当作用户坐标下的像素。也可以指定width和height为带有单位的数字,单位的取值是下列值之一。

  • em
    默认字体的大小,通常相当于文本行高。
  • ex
    字母 x 的高度。
  • px
    像素(在支持 CSS2的图形系统中,每英寸为96像素)。
  • pt
    点(1/72英寸)。
  • pc
    12点(1/6英寸)。
  • cm
    厘米。
  • mm
    毫米。
  • in
    英寸。

3.4 保留宽高比

果视口的宽高比和viewBox不一样,会发生什么情况?如同在这个示例中,viewBox的宽高比为1∶1(宽度和高度相同),但是视口的宽高比为1∶3(高度是宽度的3倍)。

<svg width="45px" height="135px" viewBox="0 0 90 90">

在这种情况下,SVG可以做三件事。

● 按较小的尺寸等比例缩放图形,以使图形完全填充视口。在这个例子中,图片将变为原始宽高的一半。在3.4.2节会看到相关的例子。

● 按较大的尺寸等比例缩放图形并裁剪掉超出视口的部分。在这个例子中,图片会变成原始宽高的1.5倍。在3.4.3节会看到相关的例子。

● 拉伸和挤压绘图以使其恰好填充新的视口(也就是说,完全不保留宽高比)。在3.4.4节可查看详情。

3.5 嵌套坐标系统

如果你尝试为一个 <svg> 的preserveAspectRatio属性使用meet或者slice值,而这个 <svg> 嵌套在另一个具有preserveAspectRatio="none"属性的 <svg> 元素内,其结果可能会让你大吃一惊。嵌套元素的视口的宽高比,将按照父SVG被压缩或者拉伸的坐标来求值以适配视口,这可能导致图像被挤压和裁剪或者缩放。

4.2 笔画特性

SVG的坐标网格线可能是无穷细的,但是你的电脑屏幕却是由固定大小的像素组成的。对角线的边缘看起来会很毛躁,这是因为电脑屏幕在显示的时候通过计算将它放到了最邻近的像素块中,这就是所谓的锯齿(aliasing)。电脑也可以使用反锯齿(anti-aliasing)技术来使边缘看起来更柔和,具体做法是对那些斜线只经过了一部分的像素点进行模糊处理。

大部分SVG阅读器都会默认开启反锯齿功能,这会使得1像素的黑线有时候看起来看2像素的灰线,因为它位于屏幕上两个像素的正中间。你可以通过指定CSS属性shape-rendering的值来控制反锯齿特性。取值crispEdges(在元素上,或者在整个SVG上)会关闭反锯齿特性,得到清晰的图像(有时候看起来很毛躁)。取值geometricPrecision则会使边缘圆滑(有时候看起来很模糊)。

4.3 矩形

如果你熟悉 CSS的border-radius属性,可能知道通过设置圆角半径为宽高的50%,可使矩形变成一个圆或椭圆。在SVG中你也可以通过百分比来指定圆角半径的值,但会被解析为相对视口的宽高的百分比(和使用百分比来设置矩形的宽或高一样),而不是相对矩形本身的宽高的百分比。不过好在要创建圆和椭圆的话,SVG有更简单的方法。

4.5 多边形

图4-12:不同填充规则的效果

填充规则的解释

为了保持完整性,还是解释一下fill-rules的原理,但是你在使用时并不一定要知道这些细节。nonzero规则在判断某个点是否在图形内部时,从这个点画一条线到无穷远,然后数这条线与图形边线有多少次交叉。如果交叉的边线是从右往左画,则总数加1;如果交叉的边线是从左往右画,则总数减1。如果最后总数为0,则认为该点在图形外部,否则认为在图形内部。

evenodd规则也画了同样一条线,但它只算与边线相交的次数。如果总数是奇数,则认为点在图形内部,否则认为点在图形外部。

5.3 分组和引用对象

<g> 元素可以组合元素,并为它们提供一些注解,这使得我们的文档结构更为清晰。除此之外,<g> 元素还提供了一些书写上的便利。在起始 <g> 标签中指定的所有样式会应用于组合内的所有子元素。

通过在起始和结束 <defs> 标记之间放置这些组合对象,我们可以告诉SVG只定义但不显示它们。

<use> 元素并不限制只能使用同一文件内的对象,事实上xlink:href属性可以指定任意有效的文件或者 URI。这使得我们可以将一组公用元素集合在一个SVG文件内,然后在其他文件中选择性地使用它们。比如,我们可以创建一个名为 identity.svg的文件,该文件包含你的组织要使用的所有标识图形:

<g id="company_mascot">
   <!-- 绘制企业吉祥物 -->
</g>

<g id="company_logo" style="stroke: none;">
   <polygon points="0 20, 20 0, 40 20, 20 40" style="fill: #696;"/>
   <rect x="7" y="7" width="26" height="26" style="fill: #c9c;"/>
</g>

<g id="partner_logo">
    <!-- 绘制合作伙伴的Logo -->
</g>

然后使用如下方式引用它们:

<use xlink:href="identity.svg#company_logo" x="200" y="200"/>

<symbol> 元素提供了另一种组合元素的方式。和 <g> 元素不同,<symbol> 元素永远不会显示,因此我们无需把它放在 <defs> 规范内。然而,我们仍然习惯将它放到 <defs> 中,因为 symbol也是我们定义的供后续使用的元素。symbol还可以指定viewBox和preserveAspectRatio属性,通过给 <use> 元素添加width和height属性就可以让 symbol适配视口大小。

6.4 技巧:笛卡儿坐标系统转换

要把图片翻转回正面朝上,我们可以利用这一事实:通过负值缩放形状会反转坐标顺序。然而,由于整个网格最终会翻转到坐标0点的另一侧,我们还需要将形状平移回画布的可视部分。这一转换遵循以下步骤。

(1)在原始绘图中找到最大 y 坐标。在本例中是 100,也就是原始 y 轴的末端。

(2)将整个绘图放入 <g> 元素中。

(3)启用平移,根据最大 y 值向下移动坐标系统:transform="translate(0, max-y)"。

(4)接下来的变换就是缩放 y 轴 -1 倍,让它倒置翻转:transform="translate(0, max-y) scale(1, -1)"。

6.5 rotate变换

很多时候,我们并不想围绕原点旋转整个坐标系统,而是希望围绕某个点旋转单个对象。我们可以通过一系列变换做到这一点:translate(centerX, centerY) rotate(angle) translate(-centerX, -centerY)。SVG提供了另一个版本的rotate,让处理这一常见任务更容易。在rotate变换的第二种形式中,指定角度以及想要围绕其旋转的中心点即可。

9.3 文本对齐

<text> 元素让你指定了起始点,但是你并不能事先知道它的终点。这使得让文本居中对齐或者右对齐变得很困难。我们可以使用text-anchor属性来指定文本坐标生效的位置,它的值可以是start、middle或者end。如果文字是从左向右书写的,这三个值分别表示左对齐、居中对齐和右对齐。

12.1 动画基础

<animate> 元素指定了下列信息。

● attributeName,动画中应该持续改变的值;在这里就是width。

● attributeType。width属性是一个XML属性。另一个常用的attributeType值是CSS,表示我们想要改变的属性是一个 CSS属性。如果忽略这一属性,它的默认值是auto;它首先会搜索 CSS属性,然后才是XML属性。

● 属性的起始(from)和结束(to)值。在这个例子中,起始值是200,结束值是20。from值是可选的;如果不指定,则会使用父元素的值。此外,还有一个by属性,可以代替to,它是一个从from值开始的偏移量;动画结束时属性的值为结束值。

● 动画的开始时间和持续时间。在这个例子中,时间以秒为单位,通过在数字后面使用s指定。定义时间的其他方式会在12.2节中描述。

● 动画结束时做什么。在这个例子中,持续5秒之后,属性会“冻结”(freeze)为to值。也就是SMILfill属性,它会告诉动画引擎如何填补剩下的时间。不要把它跟SVG的fill属性混淆了,该属性用于告诉SVG如何描绘对象。如果我们移除这一行,会使用默认值(remove),5秒的动画完成之后width属性会返回它的原始值200。

发表评论

电子邮件地址不会被公开。 必填项已用*标注