> For the complete documentation index, see [llms.txt](https://lizh.gitbook.io/knowledge/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://lizh.gitbook.io/knowledge/javascript-xi-lie/06svg-ji-chu-ru-men-pian.md).

# SVG基础入门篇

可缩放矢量图形（Scalable Vector Graphics，SVG），是一种用于描述二维矢量图形、基于 XML 的标记语言。作为一个基于文本的开放网络标准，SVG 能够优雅而简洁地渲染不同大小的图形，并和 CSS、DOM、JavaScript 和 SMIL 等其他网络标准衔接。本质上，SVG 相对于图像，就好比 HTML 相对于文本。

和传统的点阵图像（如 JPEG、PNG）不同，SVG 提供的是矢量图：可以放大而不失真，也便于改内容。

SVG 是由万维网联盟（W3C）自 1999 年开始开发的开放标准。

* SVG 是指可伸缩矢量图形
* SVG 用来定义用于网络的基于矢量的图形
* SVG 使用 XML 格式定义图形
* SVG 图像在放大或缩小（改变尺寸）时，图形质量不会受损失
* SVG 是 W3C 的一个标准

## SVG 有哪些优缺点

与其他图像格式相比，使用 SVG 的优势在于：

* SVG 是矢量格式，可呈现任何大小而不降低其质量
* SVG 支持静止或动态图像
* SVG 支持透明度
* SVG 可被非常多的工具读取和修改（比如：代码或文本编辑器）
* SVG 可以从 Adobe Illustrator 或 Sketch 等设计软件中导出
* SVG 因为基于文本，是可搜索的（很适合制作地图）
* SVG 是开放的标准。现代浏览器支持 SVG 格式，并且面向未来
* SVG 文件是纯粹的 XML
* SVG 格式具有高度可压缩性和轻量级

SVG 也有一些缺点：

* 复杂图形会让 SVG 源码变得很长、难维护
* 在过低版本的浏览器上无法呈现
* 电子邮件客户端支持有限
* 复杂路径、节点很多时，运行时计算和栅格化会比同等观感的 PNG 更耗。
* 渲染效果不一致。不同浏览器乃至不同平台的抗锯齿处理差别很大，尤其是关掉抗锯齿时，边数较多的多边形图标会很难看。

## 浏览器中如何使用 SVG 元素

**注意：** 若要用脚本访问外部 SVG 的内部 DOM（`iframe`、`object`、内联），须同源。`img` 和 CSS 背景把 SVG 当图片加载，内部脚本不会执行。

要在浏览器中显示，可以通过几种方法来实现：

* HTML 元素引入 SVG 文件
  * 使用 `iframe` 元素来嵌入 SVG 图像
  * 使用 `img` 元素来嵌入 SVG 图像

![image-20200905141904001](https://my-files-1259410276.cos.ap-chengdu.myqcloud.com/md_images/image-20200905141904001.png)

```html
<iframe src="snowman.svg" width="200" height="200"></iframe>
<img src="snowman.svg" width="300" />
```

[引入 DEMO](https://github.com/1927344728/fed-knowledge/tree/master/demo/21-svg01.html?type=1)

* 在 CSS 样式中使用 SVG 来对 HTML 内容应用图像效果

  * 将 SVG 图像作为背景图像嵌入

  ```css
  div {
      background: url(snowman.svg) no-repeat center;
      background-size: 300px 200px;
  }
  ```

  * 现代浏览器支持在 CSS 样式中使用 SVG 来对 HTML 内容应用图像效果。

    你可以在同一文件中使用 SVG 样式，也可以通过外部样式表引入。有三个属性可以使用：`mask`、`clip-path`、`filter`。

    ```html
    <svg>
        <mask id="mask-1"> ... </mask>
        <clipPath id="clipping-path-1"> ... </clipPath>
        <filter id="f1"> ... </filter>
    </svg>
    ```

    ```css
    .target {
        mask: url(#mask-1);
        clip-path: url(#clipping-path-1);
        filter: url(#f1);
    }
    .target2 { /* 使用外部引用 */
        clip-path: url(resources.svg#c1);
    }
    ```
* 将 SVG 直接嵌套在 HTML 中

  * 直接使用 `svg` 元素，通过代码将 SVG 图像嵌入到 HTML 代码中。

  ```html
  <section class="box_02">
    <svg width="447.64197" height="631.57538">
      ...
    </svg>
  </section>
  ```

  [直接嵌套 DEMO](https://github.com/1927344728/fed-knowledge/tree/master/demo/21-svg01.html?type=2)

  * 使用 `embed`、`object` 元素来嵌入 SVG 图像（不推荐）。

  ```html
  <embed src="snowman.svg" width="300" height="220" type="image/svg+xml" />
  <object data="snowman.svg" width="300" height="200" type="image/svg+xml"></object>
  ```

## SVG 文档基本结构

一个独立的 SVG 文件，也就是平时看到的以扩展名 `.svg` 结尾的文件。一个简单的 SVG 图形例子：

```xml
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<svg xmlns="http://www.w3.org/2000/svg" version="1.1">
    <circle cx="100" cy="50" r="40" stroke="black" stroke-width="2" fill="red" />
</svg>
```

* XML 声明：和 HTML 文档的 DTD 声明是类似的。

  ```xml
  <!-- 类似于 HTML 文档的 DTD 声明 <!DOCTYPE html> -->
  <?xml version="1.0" encoding="UTF-8" standalone="no"?>
  ```

  `version="1.0"` 和 `encoding="utf-8"` 是 XML 声明里常见的默认写法。

  `standalone` 规定此文件在 XML 意义上是否「独立」。`standalone="no"` 表示文档可以引用外部标记声明（如 DTD），并不等于「一定引用了另一张图」。
* `svg` 根元素包括用来描述 SVG 的 XML 命名空间。

  ```xml
  <!-- 类似于 HTML 中的命名空间声明 <html xmlns="http://www.w3.org/1999/xhtml"> -->
  <svg xmlns="http://www.w3.org/2000/svg">
  ```

嵌入 HTML5 文档中的 SVG 不应再写一份 XML 声明（格式良好的 XML 只允许文档最顶部有一个 XML 声明）。独立 `.svg` 文件可以写 XML 声明，但不是必须；通过 `img` 或 CSS `background-image` 引用的 SVG 按图片解析，有无 XML 声明都能显示。HTML5 里内联的 `<svg>` 也可省略 `xmlns`，独立文件仍应写上。

## 几个重要的 SVG 概念

### 1. viewport

视口，表示 SVG 可见区域的大小，或者可以想象成画布大小（与 canvas 的画布概念相似）。SVG 中超出视窗边界的区域会被裁切并且隐藏。

```html
<svg width="500" height="300"></svg>
```

### 2. viewBox 属性

`viewBox` 是「视区盒子」的意思，即创建一个可伸展的盒子，用以承载一组图形。当 `viewBox` 的大小与 viewport 不一致时，盒子会自动伸缩（与 `preserveAspectRatio` 属性有关）。

```
viewBox="min-x min-y width height"
```

`viewBox` 大小默认与 viewport 相同。不允许宽度和高度为负值；为 0 则禁用该元素的呈现。

![image-20200905212643005](https://my-files-1259410276.cos.ap-chengdu.myqcloud.com/md_images/image-20200905212643005.png)

```html
<section class="box_16">
    <svg width="400" height="300" viewBox="0,0,40,30" style="border: 1px solid #eee;">
        <rect x="10" y="5" width="20" height="15" fill="#0aa" />
        <line x1="20" y1="15" x2="20" y2="30" stroke="orange" stroke-width="2" />
    </svg>
</section>
```

[viewBox 属性 DEMO](https://github.com/1927344728/fed-knowledge/tree/master/demo/21-svg02.html?type=16)

如上所示，`viewBox` 的大小是 `40 * 30`，viewport 的大小是 `400 * 300`。实现渲染时，会将 viewBox 放大 10 倍。

有 `marker`、`pattern`、`svg`、`symbol`、`view` 等五个 SVG 元素可以有这个属性。

### 3. preserveAspectRatio 属性

有时候使用 `viewBox` 时希望图形拉伸占据整个视口；其他情况下为了保持长宽比，必须使用统一的缩放比例。**`preserveAspectRatio` 表示是否强制进行统一缩放。**

对于支持该属性的元素，除了 `image` 之外，`preserveAspectRatio` 只在提供了 `viewBox` 时生效；没有 `viewBox` 则忽略该属性。

```
preserveAspectRatio="<align> <meetOrSlice>"
```

* **align：** 表示对齐方式和是否强制统一缩放。当 SVG 的 `viewBox` 与视口宽高比不一致时使用。默认值 **xMidYMid**，即居中。

  `align` 的值一定是下列之一：

  * **none**：不强制统一缩放，可以拉伸变形。此时 `meetOrSlice` 会被忽略。
  * **xMinYMin**：强制统一缩放。viewBox 与 viewport 在 X 方向左对齐、Y 方向上对齐。
  * **xMidYMin**：强制统一缩放。viewBox 与 viewport 在 X 方向居中、Y 方向上对齐。
  * **xMaxYMin**：强制统一缩放。viewBox 与 viewport 在 X 方向居右、Y 方向上对齐。
  * **xMinYMid**：强制统一缩放。viewBox 与 viewport 在 X 方向左对齐、Y 方向居中。
  * **xMidYMid**（默认值）：强制统一缩放。viewBox 与 viewport 在 X 方向、Y 方向都居中。
  * **xMaxYMid**：强制统一缩放。viewBox 与 viewport 在 X 方向右对齐、Y 方向居中。
  * **xMinYMax**：强制统一缩放。viewBox 与 viewport 在 X 方向左对齐、Y 方向下对齐。
  * **xMidYMax**：强制统一缩放。viewBox 与 viewport 在 X 方向居中、Y 方向下对齐。
  * **xMaxYMax**：强制统一缩放。viewBox 与 viewport 在 X 方向右对齐、Y 方向下对齐。
* **meetOrSlice：** 可选。只有 `meet` 和 `slice` 两个值，默认 **meet**。`none` 属于上面的 `align`，不是 `meetOrSlice`。
  * **meet：** 默认值。保留宽高比，尽可能放大 viewBox，同时保证整个 viewBox 都在视口内可见（类似 CSS `contain`）。
  * **slice：** 保留宽高比，尽可能放大 viewBox，并保证宽、高都覆盖整个视口（类似 CSS `cover`），多出的部分被裁掉。

## SVG 中的坐标系统

SVG 的坐标系统分为三种类型：

* 初始坐标系统
* 转换坐标系统
* 嵌套坐标系统

### 初始坐标系统

初始视窗坐标系是建立在视窗（viewport）上的坐标系。原点 (0, 0) 在视窗的左上角，X 轴正向指向右，Y 轴正向指向下，初始坐标系中的一个单位等于视窗中的一个「像素」（更确切地说是一个用户单位）。

初始用户坐标系是通过 `viewBox` 建立在 SVG 画布上的坐标系。一开始它和初始视窗坐标系完全一样：原点位于视窗左上角，x 轴正向指向右，y 轴正向指向下。

```html
<svg width="300" height="300"></svg>
```

### 转换坐标系统

可以使用 `transform` 属性来对元素的坐标系统进行变换。**`transform` 属性的作用对象是元素所在的坐标系统，而不是元素本身。**

在 SVG 规范中，`transform` 属性的作用是 **在被添加的元素上建立新用户空间坐标系（当前坐标系）**（效果与 `viewBox` 类似）。

它和 CSS 中 `transform` 的变换函数，都是基于坐标系变换的。区别在于：HTML 元素的坐标系建立在元素自身上；SVG 属性 `transform` 基于**初始坐标系**或**当前用户空间坐标系**。现行浏览器里，给 SVG 元素写 CSS `transform` 时，行为更接近 CSS 盒子模型，和 SVG 属性 `transform` 仍有差别。

![image-20200907235008085](https://my-files-1259410276.cos.ap-chengdu.myqcloud.com/md_images/image-20200907235008085.png)

> svg 元素有多个变换时，下一个变换的坐标系是基于上一个变换完成后的坐标系创建的，并且其子元素变换的坐标系，也是基于父元素变换后的坐标系创建的。

### 嵌套坐标系统

在 `svg` 元素中可以嵌套 `svg` 元素。外面的 svg 创建一个 Viewport 和坐标系统，嵌套在里面的 svg 也可以创建一个 Viewport 和坐标系统。

如果不声明子 SVG 的 `x` 和 `y` 属性，它们默认是 0。如果不声明 `height` 和 `width` 属性，子 svg 会是父 SVG 宽度和高度的 100%。

除了嵌套 `svg`，也可以使用 `use`、`symbol` 等元素来建立新的 viewport 和用户坐标系。

## SVG 的基本组成元素

一个简单的 SVG 文档由 svg 根元素和基本的形状元素构成。另外还有一个 g 元素，它用来把若干个基本形状编成一个组。

从这些开始，SVG 可以变得更加复杂。SVG 支持渐变、旋转、动画、滤镜效果、与 JavaScript 交互等等功能，但是所有这些额外的语言特性，都需要在一个定义好的图形区域内实现。

### 1. line 元素（直线）

`line` 元素是一个 SVG 基本形状，用来创建一条连接两个点的线。

* `x1`：起点 x 坐标
* `y1`：起点 y 坐标
* `x2`：终点 x 坐标
* `y2`：终点 y 坐标

![image-20200905150943301](https://my-files-1259410276.cos.ap-chengdu.myqcloud.com/md_images/image-20200905150943301.png)

```html
<section class="box_03">
    <svg width="300px" height="300px" style="border: 1px solid #ccc;">
        <line x1="0" y1="200" x2="250" y2="0" stroke="#0aa" stroke-width="5" />
    </svg>
</section>
```

[line 元素 DEMO](https://github.com/1927344728/fed-knowledge/tree/master/demo/21-svg01.html?type=3)

### 2. rect 元素（矩形）

`rect` 元素是 SVG 的一个基本形状，用来创建矩形，基于一个角位置以及它的宽和高。它还可以用来创建圆角矩形。

* `x`：左上角 x 坐标
* `y`：左上角 y 坐标
* `width`：宽度
* `height`：高度
* `rx`：x 方向的圆角半径
* `ry`：y 方向的圆角半径

![image-20200905151025386](https://my-files-1259410276.cos.ap-chengdu.myqcloud.com/md_images/image-20200905151025386.png)

```html
<section class="box_04">
    <svg width="300px" height="150px" style="border: 1px solid #ccc;">
        <rect x="20" y="20" width="250px" height="125px" rx="5" ry="5" fill="teal" />
    </svg>
</section>
```

[rect 元素 DEMO](https://github.com/1927344728/fed-knowledge/tree/master/demo/21-svg01.html?type=4)

### 3. circle 元素（圆）

`circle` 元素是一个 SVG 的基本形状，用来创建圆，基于一个圆心和一个半径。

* `cx`：圆心 x 坐标
* `cy`：圆心 y 坐标
* `r`：半径

![image-20200905151513091](https://my-files-1259410276.cos.ap-chengdu.myqcloud.com/md_images/image-20200905151513091.png)

```html
<section class="box_05">
    <svg width="300px" height="300px" style="border: 1px solid #ccc;">
        <circle cx="100" cy="100" r="50" fill="#0aa"></circle>
    </svg>
</section>
```

[circle 元素 DEMO](https://github.com/1927344728/fed-knowledge/tree/master/demo/21-svg01.html?type=5)

### 4. ellipse 元素（椭圆）

`ellipse` 元素是一个 SVG 基本形状，用来创建一个椭圆，基于一个中心坐标以及它们的 x 半径和 y 半径。

* `cx`：圆心 x 坐标
* `cy`：圆心 y 坐标
* `rx`：x 方向半径
* `ry`：y 方向半径

![image-20200905151925222](https://my-files-1259410276.cos.ap-chengdu.myqcloud.com/md_images/image-20200905151925222.png)

```html
<section class="box_06">
    <svg width="300px" height="300px" style="border: 1px solid #ccc;">
        <ellipse cx="150" cy="150" rx="100" ry="75" fill="#0aa" />
    </svg>
</section>
```

[ellipse 元素 DEMO](https://github.com/1927344728/fed-knowledge/tree/master/demo/21-svg01.html?type=6)

### 5. polygon 元素（闭合多边形）

`polygon` 元素是由连接一组点集的直线构成。`polygon` 的路径在最后一个点处自动回到第一个点。需要注意的是，矩形也是一种多边形。

* `points`：定义用来画 `polygon` 或 `polyline` 的点列。每个点用用户坐标系统中的一个 X 坐标和 Y 坐标定义，点与点之间用空格或逗号分开。

![image-20200905152811262](https://my-files-1259410276.cos.ap-chengdu.myqcloud.com/md_images/image-20200905152811262.png)

```html
<section class="box_07">
    <svg width="300px" height="300px" style="border: 1px solid #ccc;">
        <polygon points="0,50 50,0 150,0 200,50 150,100 50,100" fill="#0aa"></polygon>
    </svg>
</section>
```

[polygon 元素 DEMO](https://github.com/1927344728/fed-knowledge/tree/master/demo/21-svg01.html?type=7)

### 6. polyline 元素（折线）

`polyline` 元素是 SVG 的一个基本形状，用来创建一系列直线连接多个点。典型的一个 polyline 是用来创建一个开放的形状，最后一点不与第一点相连。

![image-20200905153443196](https://my-files-1259410276.cos.ap-chengdu.myqcloud.com/md_images/image-20200905153443196.png)

```html
<section class="box_08">
    <svg width="300px" height="180px" style="border: 1px solid #ccc;">
        <polyline points="10 10,50 50,75 175,175 150,175 50,225 75,225 150,300 150" fill="none" stroke="#0aa" />
    </svg>
    <svg width="300px" height="180px" style="border: 1px solid #ccc;">
        <polyline points="10 10,50 50,75 175,175 150,175 50,225 75,225 150,300 150" fill="#0aa" stroke="none" />
    </svg>
</section>
```

[polyline 元素 DEMO](https://github.com/1927344728/fed-knowledge/tree/master/demo/21-svg01.html?type=8)

### 7. image 元素（图片）

允许在一个 SVG 对象内部呈现光栅图像，也可以引用其他 SVG 文件。规范要求至少支持 JPEG、PNG；GIF 不是必须格式，浏览器支持不一致。

* `x`：图像水平方向上到原点的距离
* `y`：图像竖直方向上到原点的距离
* `width`：图像宽度。SVG 1.1 中是必须的，缺省为 0 则不绘制；SVG 2 可用图像固有尺寸。
* `height`：图像高度。同上。
* `href`、`xlink:href`：图像的 URL。现行用 `href`，`xlink:href` 仍可用于兼容。
* `preserveAspectRatio`：控制图像比例

```html
<section class="box_26">
    <svg width="500" height="300">
        <image xlink:href="https://my-files-1259410276.cos.ap-chengdu.myqcloud.com/md_images/飞舞.png" x="0" y="0" height="300" width="300" />
    </svg>
</section>
```

[image 元素 DEMO](https://github.com/1927344728/fed-knowledge/tree/master/demo/21-svg03.html?type=26)

* 如果没有设置 `x` 或 `y`，它们自动被设置为 0
* SVG 1.1 下如果没有设置 `height` 或 `width`，它们自动被设置为 0；为 0 则不呈现该图像

### 8. text 元素（文本）

`text` 元素定义了一个由文字组成的图形。

注意：我们可以将渐变、图案、剪切路径、遮罩或者滤镜应用到 `text` 上。

* `x`、`y`：在用户坐标系统中标识了一个 x 轴、y 轴坐标。
* `dx`、`dy`：一个元素或其内容在 x 轴、y 轴方向上的偏移，偏移量取决于设置该属性的元素。
* `text-anchor`：用来描述该文本与所给点的对齐方式（开头、中间、末尾对齐）。取值：`start`、`middle`、`end`。
* `rotate`：旋转各个字形的角度（可以是一个数，也可以是与字形对应的一组数）。
* `textLength`：指定文本将绘制到的空间的宽度。
* `lengthAdjust`：控制文本如何拉伸到 `textLength` 定义的长度。取值：`spacing`、`spacingAndGlyphs`。

### 9. textPath 元素（文本路径）

除了笔直地绘制一行文字以外，SVG 也可以根据 `path` 元素的形状来放置文字。只要在 `textPath` 元素内部放置文本，并通过其 `href`（或兼容用的 `xlink:href`）引用 `path` 元素，就可以让文字块呈现在路径上。

* `startOffset`：将路径转换到 textPath 的坐标系后，沿路径的初始文本位置相对于路径起点的偏移量。
* `method`：沿路径呈现文本的方法。取值：`align`、`stretch`。
* `spacing`：如何确定沿路径呈现的字符之间的间距。
* `href`、`xlink:href`：引用的路径。现行用 `href`。

![image-20200912022433702](https://my-files-1259410276.cos.ap-chengdu.myqcloud.com/md_images/image-20200912022433702.png)

```html
<section class="box_27">
    <svg width="500" height="300" style="border: 1px solid #eee;">
        <defs>
            <path id="MyPath" d="M 50 200 C 200 400 900 -200 900 100" />
        </defs>
        <use xlink:href="#MyPath" fill="none" stroke="orange" stroke-width="3" />

        <text font-family="Verdana" font-size="30" fill="#0aa">
            <textPath startOffset="-50" xlink:href="#MyPath" spacing="exact"> 君子之交淡如水，茶人之交醇如茶。 </textPath>
        </text>
        <text x="120" y="30" dx="0" dy="30" font-weight="bold" font-size="30" fill="#0aa" text-anchor="middle">
            君子之交淡如水，茶人之交醇如茶。 </text>
        <text x="20" y="100" font-weight="bold" font-size="30" fill="#0aa" textLength="300"> 君子之交淡如水，茶人之交醇如茶。 </text>
        <text x="20" y="140" font-weight="bold" font-size="30" fill="#0aa" textLength="300"
              lengthAdjust="spacingAndGlyphs" rotate="30"> 君子之交淡如水，茶人之交醇如茶。 </text>
    </svg>
</section>
```

[textPath 元素 DEMO](https://github.com/1927344728/fed-knowledge/tree/master/demo/21-svg03.html?type=27)

### 10. pattern 元素（图案）

使用预定义的图形对一个对象进行填充或描边，就要用到 pattern 元素。pattern 元素让预定义图形能够以固定间隔在 x 轴和 y 轴上重复（或平铺）从而覆盖要涂色的区域。先使用 pattern 元素定义图案，然后在给定的图形元素上用属性 fill 或属性 stroke 引用用来填充或描边的图案。

* `patternUnits`：指示将哪个坐标系用于 `pattern` 元素的几何属性。
* `patternContentUnits`：指示要用于 `pattern` 元素内容的坐标系。
* `patternTransform`：定义应用于图案的变换列表。
* `x`、`y`：在用户坐标系统中标识了一个 x 轴、y 轴坐标。
* `width`、`height`：在用户坐标系统中标识了一个水平长度、垂直长度。
* `href`、`xlink:href`：引用另一个图案。
* `preserveAspectRatio`：表示是否强制进行统一缩放。

![image-20200912172113635](https://my-files-1259410276.cos.ap-chengdu.myqcloud.com/md_images/image-20200912172113635.png)

```html
<section class="box_28">
    <svg width="400" height="400">
        <defs>
            <linearGradient id="Gradient7">
                <stop offset="5%" stop-color="white" />
                <stop offset="95%" stop-color="#0aa" />
            </linearGradient>
            <linearGradient id="Gradient8" x1="0" x2="0" y1="0" y2="1">
                <stop offset="5%" stop-color="white" />
                <stop offset="95%" stop-color="orange" />
            </linearGradient>
            <pattern id="Pattern" x="0" y="0" width=".25" height=".25">
                <rect x="0" y="0" width="50" height="50" fill="#0aa" />
                <line x1="25" y1="25" x2="50" y2="50" stroke-width="5" stroke="url(#Gradient8)" />
                <circle cx="25" cy="25" r="20" fill="url(#Gradient7)" fill-opacity="0.8" />
            </pattern>
        </defs>
        <rect fill="url(#Pattern)" x="0" y="0" width="200" height="200" />
    </svg>
</section>
```

[pattern 元素 DEMO](https://github.com/1927344728/fed-knowledge/tree/master/demo/21-svg03.html?type=28)

## SVG 中的路径

`path` 是 SVG 中最常见的形状。你可以用 `path` 元素绘制矩形（直角矩形或者圆角矩形）、圆形、椭圆、折线形、多边形，以及贝塞尔曲线、二次曲线等。

路径可以被填充、描边或者用于剪裁其他元素。

* `d`：一个字符串，包含了一系列路径描述。可以使用不同的指令，移动到一个新的点，然后绘制不同的直线和曲线。

注意：**指令字母大写表示坐标位置是绝对坐标，指令字母小写表示坐标位置是相对坐标。x、y 坐标之间可以用空格或逗号隔开。**

以下用 `path` 元素，绘制上个 `polyline` 示例：

```html
<section class="box_09">
  <svg width="300px" height="180px" style="border: 1px solid #ccc;">
      <path d="
        M10 10
        L50 50
        L75 175
        L175 150
        L175 50
        L225 75
        L225 150
        L300 150
      "
      fill="none"
      stroke="#0aa"
      stroke-width="2px"
    />
  </svg>
</section>  
```

[path 元素 DEMO](https://github.com/1927344728/fed-knowledge/tree/master/demo/21-svg01.html?type=9)

### 1. 直线指令

这里有五种不同的直线指令，你可以使用它们来创建路径。

* `moveto`（`M` 或 `m`）：移动到新的位置
* `lineto`（`L` 或 `l`）：从当前坐标画一条直线到一个新坐标
* `horizontal lineto`（`H` 或 `h`）：画一条水平线到新坐标。只带一个参数，标明在 x 轴移动到的位置
* `vertical lineto`（`V` 或 `v`）：画一条垂直线到新坐标。只带一个参数，标明在 y 轴移动到的位置
* `closepath`（`Z` 或 `z`）：关闭当前路径。它是最简单的命令，而且不带有任何参数。`Z` 或 `z`，两种写法作用都一样

**注意：** 指令的参数用空格或逗号隔开，多个指令之间不需要隔开。

```
d="M10 10L50 50L75 175L175 150L175 50L225 75L225 150L300 150"
d="M10,10 L50,50 L75,175 L175,150 L175,50 L225,75 L225,150 L300,150"
```

**注意：** 实际应用中使用指令字母即可。**指令字母大写表示绝对位置，指令字母小写表示相对位置。**

![image-20200905161857928](https://my-files-1259410276.cos.ap-chengdu.myqcloud.com/md_images/image-20200905161857928.png)

```html
<section class="box_10">
    <svg width="300px" height="300px" style="border: 1px solid #ccc;">
        <g fill="none">
            <path d="M 0 300 l 150 -300" stroke="red" />
            <path d="M 150 0 l 150 300" stroke="red" />
            <path d="M 50 200 h 200" stroke="#0aa" />
            <path d="M 0 300 q 150 -300 300 0 z" stroke="orange" stroke-width="3px" />
        </g>
    </svg>
</section>
```

[直线指令 DEMO](https://github.com/1927344728/fed-knowledge/tree/master/demo/21-svg01.html?type=10)

### 2. 曲线指令

绘制平滑曲线的命令有三个，其中两个用来绘制贝塞尔曲线，另外一个用来绘制弧形或者说是圆的一部分：

* Curveto：三次贝塞尔曲线指令（`C`、`c`、`S`、`s`），需要一个初始点的控制点和一个结束点的控制点，还有一个结束点。

  ```
  C (or c) x1,y1 x2,y2 x,y
  S (or s) x2,y2 x,y
  ```

  * `x1`、`y1` 是曲线起点的控制点坐标
  * `x2`、`y2` 是曲线终点的控制点坐标
  * `x`、`y` 是曲线的终点坐标（曲线的起点是上一条指令的终点）
* Curveto：二次贝塞尔曲线指令（`Q`、`q`、`T`、`t`），只需要一个控制点，同时作为起点控制点和终点控制点。

  ```
  Q (or q) x1,y1 x,y
  T (or t) x,y
  ```

  * `x1`、`y1` 是曲线起点和终点共用的控制点坐标（仅 `Q`、`q`）
  * `x`、`y` 是曲线的终点坐标
  * `T`、`t` 只写终点，控制点由前一段的控制点关于前终点反射得到

  ```html
  <section class="box_11">
      <svg width="300px" height="150px" style="border: 1px solid #ccc;">
          <path d="M0 30 C 100 30 150 150 300 30" fill="none" stroke="#0aa" stroke-width="3px" />
          <path d="M0 100 Q 150 180 300 100" fill="none" stroke="orange" />
      </svg>
  </section>
  ```

  [曲线指令 DEMO](https://github.com/1927344728/fed-knowledge/tree/master/demo/21-svg02.html?type=11)

> 为了连缀平滑的贝塞尔曲线，还可以使用 T 和 S 命令。它们的语法比别的 Curveto 命令简单。因为它假定第一个控制点是前一个控制点关于前一个点的反射（即，关于前一个点对称），或者说如果没有前一个控制点的话它实际上就是前一个点。

* Arcto：椭圆弧线（`A`、`a`），用于绘制一段椭圆片段。若 `rx` 和 `ry` 的值相同，则绘制出圆。

  ```
  A (or a) rx ry  xAxisRotate  large-arc-flag  sweep-flag  x y
  ```

  * `rx`、`ry`：弧线在 x 轴、y 轴方向的半径
  * `xAxisRotate`：与 x 轴夹角的度数
  * `large-arc-flag`：0 或 1，用来确定是要画小弧（0）还是画大弧（1）
  * `sweep-flag`：0 或 1，用来确定弧是顺时针方向（1）还是逆时针方向（0）
  * `x`、`y`：弧线的终点

  ![image-20200905170936292](https://my-files-1259410276.cos.ap-chengdu.myqcloud.com/md_images/image-20200905170936292.png)

  ```html
  <section class="box_12">
      <svg width="600" height="300" style="border: 1px solid #eee;">
          <path d="M250,100 A120,80 0 0 0 250,200" fill="none" stroke="red" stroke-width="5" />
          <path d="M250,100 A120,80 0 1 1 250,200" fill="none" stroke="#0aa" stroke-width="3" />
          <path d="M250,100 A120,80 0 1 0 250,200" fill="none" stroke="orange" stroke-width="1" />
          <path d="M250,100 A120,80 0 0 1 250,200" fill="none" stroke="#a0a" stroke-width="3" />
      </svg>
  </section>
  ```

  [椭圆弧线指令 DEMO](https://github.com/1927344728/fed-knowledge/tree/master/demo/21-svg02.html?type=12)

## SVG 中的其他元素

### SVG 中的标记（Marker）

`marker` 元素定义了在特定的 `path`、`line`、`polyline`、`polygon` 元素上绘制的箭头或者多边标记图形。

* `markerUnits`：标记的坐标系。取值 `userSpaceOnUse`（用户坐标）或 `strokeWidth`（相对描边宽度，默认）。
* `refX`、`refY`：定义元素参考点的 x、y 坐标
* `markerWidth`、`markerHeight`：定义 marker 元素的宽度、高度。
* `orient`：指示将标记放置在形状上时如何旋转。

> `marker-start`、`marker-mid`、`marker-end` 这三个 CSS 属性会将标记分别放置在路径的开始、中间和结束位置。
>
> 可以设置 `markerUnits="strokeWidth"` 使得标记进行缩放来适应路径描边的大小

![image-20200905174739391](https://my-files-1259410276.cos.ap-chengdu.myqcloud.com/md_images/image-20200905174739391.png)

```html
<section class="box_13">
    <svg width="300" height="150" style="border: 1px solid #eee;">
        <defs>
            <marker id="markerCircle" markerWidth="20" markerHeight="20" refX="5" refY="5">
                <circle cx="5" cy="5" r="3" style="stroke: none; fill: orange;" />
            </marker>
            <marker id="markerCircle2" markerWidth="8" markerHeight="8" refX="5" refY="5">
                <circle cx="5" cy="5" r="5" style="stroke: none; fill: red;" />
            </marker>
            <marker id="markerArrow" markerWidth="13" markerHeight="13" refX="2" refY="6" orient="auto"
                    markerUnits="strokeWidth">
                <path d="M2,2 L2,11 L10,6 L2,2" style="fill: orange;" />
            </marker>
        </defs>
        <path d="M75 25 h150 v100 l -100 -50"
              style="stroke: #0aa; fill: none; marker-start: url(#markerCircle); marker-mid: url(#markerCircle2);  marker-end: url(#markerArrow); " />
    </svg>
</section>
```

[标记 DEMO](https://github.com/1927344728/fed-knowledge/tree/master/demo/21-svg02.html?type=13)

### SVG 中的 clipPath

SVG 剪裁路径是指根据指定的路径或形状来剪裁 SVG 图形。应用了剪裁路径的图形，在剪裁路径内部的图形可以被显示出来，在剪裁路径之外的图形会被隐藏。

你可以使用任何图形来作为剪裁路径或者被剪裁的对象。可以是文字、圆形、椭圆、多边形或自定义路径。

![image-20200905180428246](https://my-files-1259410276.cos.ap-chengdu.myqcloud.com/md_images/image-20200905180428246.png)

```html
<section class="box_14">
    <svg viewBox="0 0 100 100" style="width: 300px; border: 1px solid #eee;">
        <clipPath id="myClip">
            <circle cx="40" cy="35" r="35" />
        </clipPath>
        <path id="heart" d="M10 30 A20 20 0 0 1 50 30 A20 20 0 0 1 90 30 Q90 60 50 90 Q10 60 10 30 Z"
              style="clip-path: url(#myClip);" fill="#0aa" />
    </svg>
</section>
```

[clipPath DEMO](https://github.com/1927344728/fed-knowledge/tree/master/demo/21-svg02.html?type=14)

### SVG defs 元素、symbol 元素和 use 元素

* `defs` 元素：用于预定义一个元素使其能够在 SVG 图像中重复使用。在 `defs` 元素中定义的图形元素不会直接呈现。
* `symbol` 元素：用于定义可重复使用的符号。

  `symbol` 能够创建自己的视窗，所以能够应用 `viewBox` 和 `preserveAspectRatio` 属性。
* `use` 元素：可以在 SVG 图像中多次重用一个预定义的 SVG 图形，包括 `<g>` 元素和 `<symbol>` 元素。`use` 元素可以引入在 `defs` 元素中定义的图形。

  出于安全原因，浏览器会对 `use` 的跨源引用应用同源策略，跨源 URI 会被拒绝。

![image-20200905201129540](https://my-files-1259410276.cos.ap-chengdu.myqcloud.com/md_images/image-20200905201129540.png)

```html
<section class="box_15">
    <svg viewBox="0 0 300 300" style="width: 300px; border: 1px solid #eee;">
        <defs>
            <g id="shape" stroke-width="1">
                <line x1="150" y1="150" x2="150" y2="300" />
                <circle cx="150" cy="150" r="120" />
            </g>
        </defs>
        <symbol id="shape2">
            <circle cx="75" cy="75" r="75" style="fill: orange;" />
        </symbol>
        <use xlink:href="#shape" style="stroke: #0aa; fill: none;" />
        <use xlink:href="#shape2" x="150" y="75" />
    </svg>
</section>
```

[defs-symbol-use DEMO](https://github.com/1927344728/fed-knowledge/tree/master/demo/21-svg02.html?type=15)

## SVG 元素的样式属性

SVG 元素不同于普通的 HTML 元素，具有特殊的一些样式属性。这些属性的声明可以通过 SVG 元素属性直接声明，也可以通过 CSS 样式表声明。

语法和在 HTML 里使用 CSS 一样，只不过你要把 `background-color`、`border` 改成 `fill` 和 `stroke`。

注意：不是所有属性都能用 CSS 设置。上色和描边一般可以，比如 `fill`、`stroke`、`stroke-dasharray` 等，渐变和图案本身仍要写在 SVG 里再以 `url()` 引用。SVG 1.1 里 `width`、`height` 以及路径的 `d` 等几何属性不能用 CSS；**SVG 2 起其中不少已成为演示属性**，现行浏览器可以用 CSS 改 `width`、`height`，部分引擎也支持 CSS 的 `d`。

> SVG 规范将属性区分成 properties 和其他 attributes，前者是可以用 CSS 设置的，后者不能。

以下是一些 CSS 2 里没有、SVG 里常用的样式属性：

* fill：元素的填充颜色
* fill-opacity：元素的填充颜色透明度
* stroke：元素的笔画颜色
* stroke-width：元素的笔画宽度
* stroke-linecap：定义元素顶点样式
* stroke-dasharray：虚线样式虚线长度
* stroke-dashoffset：虚线样式的偏移长度
* stroke-linejoin：定义元素之间的连接点的形状
* stroke-opacity：元素的笔画颜色透明度

我们可以通过以下方法引用样式属性：

1. 使用属性来添加 CSS 样式。

   ```html
   <circle stroke="none" fill="#0aa" />
   ```
2. 使用 STYLE 属性。

   ```html
   <circle style="stroke: none; fill: #0aa;" />
   ```
3. 使用内联样式表。

   这种使用内联样式表的工作方式和在 HTML 元素上使用内联样式表是完全相同的。样式可以定义在 svg 元素外，也可以定义在 svg 元素内。

   ```html
   <style>
       .class_name2 { stroke: #0aa; fill: #a0a; }
   </style>
   <svg>
       <style type="text/css" >
           <![CDATA[
           circle { stroke: #0aa; fill: orange; }
           .class_name1 { stroke: #0aa; fill: red; }
           ]]>
       </style> 
       <circle cx="40" cy="40" r="25"/>
       <circle class="class_name1" cx="120" cy="40" r="25"/>
       <circle class="class_name2" cx="200" cy="40" r="25"/>
   </svg>
   ```
4. 使用外部样式表来添加 CSS 样式。

   ```html
   <?xml-stylesheet type="text/css" href="svg-stylesheet.css" ?>
   ```

## SVG 中的渐变效果

SVG 可以创建并在填充和描边上应用渐变色。

有两种类型的渐变：线性渐变和径向渐变。你必须给渐变内容指定一个 `id` 属性，否则文档内的其他元素就不能引用它。为了让渐变能被重复使用，渐变内容需要定义在 `defs` 标签内部，而不是定义在形状上面。

### 线性渐变

线性渐变沿着直线改变颜色，要插入一个线性渐变，你需要在 SVG 文件的 `defs` 元素内部，创建一个 `linearGradient` 元素。

* `gradientUnits`：定义用于渐变几何属性的坐标系。取值：`userSpaceOnUse`、`objectBoundingBox`，默认值为 `objectBoundingBox`。`objectBoundingBox` 相对被填充图形的包围盒（0～1 或百分比），不是相对整个 SVG 视口。`userSpaceOnUse` 使用当前用户坐标系的绝对单位。
* `gradientTransform`：定义从渐变坐标系到目标坐标系的转换。
* `x1`、`y1`、`x2`、`y2`：起点和结束点的坐标。用于定义渐变的方向和范围。
* `spreadMethod`：确定如何填充超出定义的渐变边的形状。
  * `pad`（默认值）：该值表示渐变的最终颜色填充了超出渐变边缘的形状。
  * `reflect`：此值表示渐变超过其边缘反向重复。
  * `repeat`：此值指定渐变以原始顺序重复其边缘。
* `xlink:href`：引入其他 `linearGradient` 元素

![image-20200910001740691](https://my-files-1259410276.cos.ap-chengdu.myqcloud.com/md_images/image-20200910001740691.png)

```html
<section class="box_24">
    <svg width="500" height="300">
        <defs>
            <linearGradient id="Gradient1">
                <stop stop-color="orange" offset="0%" />
                <stop stop-color="white" stop-opacity="0.5" offset="50%" />
                <stop stop-color="#0aa" offset="100%" />
            </linearGradient>
            <linearGradient id="Gradient2" x1="0" y1="0" x2="1" y2="1" xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#Gradient1" />
            <linearGradient id="Gradient3" x1="33%" x2="67%" y1="33%" y2="67%" spreadMethod="reflect" xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#Gradient1" />
        </defs>
        <rect x="0" y="50" rx="30" ry="30" width="150" height="150" fill="url(#Gradient1)" />
        <rect x="175" y="50" rx="30" ry="30" width="150" height="150" fill="url(#Gradient2)" />
        <rect x="350" y="50" rx="30" ry="30" width="150" height="150" fill="url(#Gradient3)" />
    </svg>
</section>
```

[线性渐变 DEMO](https://github.com/1927344728/fed-knowledge/tree/master/demo/21-svg03.html?type=24)

可以在 `stop` 元素中定义 `stop-color`、`stop-opacity`、`fill` 属性，也可以定义在 CSS 中：

```html
<style type="text/css"><![CDATA[
    #rect { fill: url(#Gradient1); }
    .stop { stop-color: black; stop-opacity: 0; }
    ]]></style>
```

`linearGradient` 元素还需要一些其他的属性值，它们指定了渐变的大小和出现范围。渐变的方向可以通过两个点来控制，它们分别是属性 `x1`、`x2`、`y1` 和 `y2`，这些属性定义了渐变路线走向。

> 可以在渐变上使用 `href`（或兼容的 `xlink:href`），使一个渐变的属性和颜色中值（stop）可以被另一个渐变引用。

```html
<linearGradient id="Gradient2" x1="0" y1="0" x2="1" y2="1" xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#Gradient1"/>
```

### 径向渐变

径向渐变与线性渐变相似，只是它是从一个点开始发散绘制渐变。创建径向渐变需要在文档的 `defs` 中添加一个 `radialGradient` 元素。

* `cx`、`cy`：中心点的 x、y 轴坐标。
* `r`：定义圆的半径
* `fx`、`fy`：定义径向渐变的焦点的 x、y 轴坐标。如果该属性没有被定义，就假定它与中心点是同一位置。
* `fr`：定义径向渐变的焦点的半径。若该属性没有被定义，默认值为 0%。

![image-20200910003119521](https://my-files-1259410276.cos.ap-chengdu.myqcloud.com/md_images/image-20200910003119521.png)

```html
<section class="box_25">
    <svg width="500" height="300">
        <defs>
            <radialGradient id="Gradient4">
                <stop stop-color="orange" offset="0%" />
                <stop stop-color="white" stop-opacity="0.5" offset="50%" />
                <stop stop-color="#0aa" offset="100%" />
            </radialGradient>
            <radialGradient id="Gradient5" cx="0.5" cy="0" r="1" xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#Gradient4" />
            <radialGradient id="Gradient6" fx="0.5" fy="0.35" fr="0.25" spreadMethod="reflect" xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#Gradient4" />
        </defs>
        <rect x="0" y="50" rx="30" ry="30" width="150" height="150" fill="url(#Gradient4)" />
        <rect x="175" y="50" rx="30" ry="30" width="150" height="150" fill="url(#Gradient5)" />
        <rect x="350" y="50" rx="30" ry="30" width="150" height="150" fill="url(#Gradient6)" />
    </svg>
</section>
```

[径向渐变 DEMO](https://github.com/1927344728/fed-knowledge/tree/master/demo/21-svg03.html?type=25)

## SVG 中的 SMIL 动画

SMIL 是 Synchronized Multimedia Integration Language（同步多媒体集成语言）的首字母缩写。SMIL 开发组和 SVG 开发组合作开发了 SMIL 动画规范，在规范中制定了一个基本的 XML 动画特征集合。SVG 吸收了其中的动画能力，并提供了 SVG 自己的实现。现行主流浏览器仍支持这些动画元素；也可用 CSS 或 Web Animations API 做同类效果。

SMIL 允许你做下面这些事情：

* 动画元素的数值属性（X、Y、…）
* 动画属性变换（平移或旋转）
* 动画颜色属性
* 沿着运动路径运动

不论使用下面 4 个动画元素中的哪一个，你都需要为它指定一个动画目标。可以使用 `href`（或兼容的 `xlink:href`）指向将要执行动画的元素，该元素必须在当前 SVG 文档中。动画元素也可以嵌套在目标 SVG 元素里。如果没有指定引用，那么动画的目标就是当前动画元素的直接父元素。

```html
<rect id="cool_shape" ... />
<animate xlink:href="#cool_shape" ... />
```

### SVG 四个动画元素

#### set 元素

此元素没有动画效果。可以实现基本的延迟功能。即，可以在特定时间之后修改某个属性值（也可以是 CSS 属性值）

```html
<section class="box_18">
    <svg width="320" height="320">
        <g>
            <text font-family="microsoft yahei" font-size="80" y="160" x="160" fill="#0aa">
                SVG
                <set attributeName="x" attributeType="XML" to="60" begin="2s" />
            </text>
        </g>
    </svg>
</section>
```

[set 元素 DEMO](https://github.com/1927344728/fed-knowledge/tree/master/demo/21-svg02.html?type=18)

#### animate 元素

基础动画元素。实现单属性的动画过渡效果。类似于 CSS 中的 `transition` 属性。

```html
<section class="box_19">
    <svg width="320" height="320">
        <g>
            <text font-family="microsoft yahei" font-size="80" y="160" x="160" fill="#0aa">
                SVG
                <animate attributeName="x" from="160" to="60" begin="0s" dur="3s" repeatCount="indefinite" />
            </text>
        </g>
    </svg>
</section>
```

[animate 元素 DEMO](https://github.com/1927344728/fed-knowledge/tree/master/demo/21-svg02.html?type=19)

#### animateTransform 元素

实现 transform 变换动画效果的。

```html
<section class="box_20">
    <svg width="640" height="640">
        <g>
            <text font-family="microsoft yahei" font-size="80" y="160" x="160" fill="#0aa">
                SVG
                <animateTransform attributeName="transform" begin="0s" dur="3s" type="scale" from="1" to="1.5" repeatCount="indefinite" />
            </text>
        </g>
    </svg>
</section>
```

[animateTransform 元素 DEMO](https://github.com/1927344728/fed-knowledge/tree/master/demo/21-svg02.html?type=20)

#### animateMotion 元素

可以让 SVG 图形沿着特定的 path 路径运动。

```html
<section class="box_21">
    <svg width="360" height="200">
        <text font-family="microsoft yahei" font-size="40" x="0" y="0" fill="#0aa">SVG
            <animateMotion path="M10,80 q100,120 120,20 q140,-50 160,0" begin="0s" dur="3s" rotate="auto"
                           repeatCount="indefinite" />
        </text>
        <path d="M10,80 q100,120 120,20 q80,-80 160,0" stroke="#0aa" stroke-width="2" fill="none" />
    </svg>
</section>
```

[animateMotion 元素 DEMO](https://github.com/1927344728/fed-knowledge/tree/master/demo/21-svg03.html?type=21)

### 与使用 CSS 动画的区别

SVG 元素可以像 HTML 元素一样，使用 CSS `keyframes` 和 `animation` 属性或者 CSS `transitions` 来制作各种动画效果。大多数情况下，一个复杂的动画效果需要组合多种变换效果：旋转、倾斜、缩放以及它们的转换和过渡效果。

多数情况下，SVG 元素和 HTML 元素在使用 `transform` 和 `transform-origin` 上是相同的。但它们之间也有不同之处：

* SVG 元素不能使用 box model 来管理，因此，它没有 `margin`、`padding`、`border` 或 content boxes。
* 默认情况下，一个 HTML 元素的 transform 原点位于该元素的 (50%, 50%) 的地方，这里是元素的中心点。与之不同，SVG 属性 `transform` 的原点位于当前用户坐标系统的原点上，这个点是画布的左上角位置。CSS `transform` 作用在 SVG 元素上时，现行浏览器更接近 CSS 盒子。

## SVG 动画的参数详解

#### attributeName 属性

动画属性的名称

* 可以是元素直接暴露的属性，例如 `text` 元素上的 `x`、`y` 或者 `font-size`；
* 可以是 CSS 属性。例如，透明度 `opacity`。

#### attributeType 属性

动画属性所属的命名空间。取值：`CSS`、`XML`、`auto`。

`x`、`y` 以及 `transform` 属于 XML，`opacity` 属于 CSS。`auto` 为默认值，表示自动判别。SVG 2 已不再强调此属性，现行可省略。

#### from、to、by、values

类似于 CSS 中的关键帧定义。

* `from`：动画的起始值，缺省为默认值
* `to`：指定动画的结束值
* `by`：动画的相对变化值
* `values`：用**分号**分隔的一个或多个值，可以看成是动画的多个关键值点

```html
<svg width="320" height="320">
    <g> 
        <text font-family="microsoft yahei" font-size="80" y="160" x="160" fill="#0aa">
            SVG
            <animate attributeName="x" from="160" to="60" begin="0s" dur="3s" repeatCount="indefinite" />
        </text>
    </g>
</svg>
```

#### begin、end

可选值包括：

* `time-value`：表示具体的时间值。常见单位有 `h`、`min`、`s`、`ms`，默认单位为 `s`。时间值还支持 `hh:mm:ss` 这种写法，因此 `90s` 也可以写成 `01:30`。
* `offset-value`：表示偏移值，数值前面有 `+` 或 `-`。相对于文档的 `begin` 而言。
* `syncbase-value`：基于同步确定的值。语法为：`[元素的 id].begin` 或 `.end`，再加减时间值。可以用来把两个独立元素的动画级联起来。
* `event-value`：与事件相关联的值。语法是：`[元素的 id].[事件类型] +/- 时间值`。
* `repeat-value`：指某动画重复多少次结束之后开始执行动画。语法为：`[元素的 id].repeat(整数) +/- 时间值`。
* `accessKey-value`：定义快捷键。即按下某个按键动画开始。语法为：`accessKey(character)`。`character` 表示快捷键所在的字符。
* `wallclock-sync-value`：指真实世界的时钟时间。时间语法基于 ISO 8601。
* `indefinite`：表示无限等待。需要 `beginElement()` 方法触发，或者指向该动画元素的超链接（SVG 中的 `a` 元素）。

#### dur 属性

该属性标识了动画的简单持续时间。常规时间值：clock-value | indefinite。

指定简单持续时间的时长。值必须大于0。可以用小时（h）、分钟（m）、秒（s）、毫秒（ms）表达这个值。可以组合这些时间表达式以提供一个复合的持续时间，比如这样：`hh:mm:ss.iii` 或者这样：`mm:ss.iii`。

如果一个动画元素不带有 dur 属性，简单持续时间就是无限期的。

#### calcMode、keyTimes、keySplines

`calcMode` 属性支持 4 个值：`discrete`、`linear`、`paced`、`spline`。

* `discrete`：from 值直接跳到 to 值。类似于 `step(1, end)`。
* `linear`：`animateMotion` 以外元素的 `calcMode` 默认值。动画从头到尾的速率都是一致的。
* `paced`：通过插值让动画的变化步调平稳均匀。仅支持线性数值区域内的属性，这样点之间「距离」的概念才能被计算（如 position、width、height 等）。如果指定了 `paced`，任何 `keyTimes` 或 `keySplines` 值将会失效。
* `spline`：插值定义贝塞尔曲线。spline 点的定义在 `keyTimes` 属性中，每个时间间隔控制点由 `keySplines` 定义。

**keyTimes：** 是关键时间点的意思。一个以分号分隔的时间值列表，用于控制动画的执行步骤。列表中的每个值与 `values` 中的值一一对应，定义了 `values` 中的值在动画中何时执行。`keyTimes` 列表中的每一个值都是指定在 \[0, 1] 之间的浮点数，表示动画的完成时间。

前面提到过 `values` 也是多值，这里有一些约定的规则：首先，`keyTimes` 值的数目要和 `values` 一致，如果是 `from`、`to`、`by` 动画，`keyTimes` 就必须有两个值。然后对于 `linear` 和 `spline` 动画，第一个数字要是 0，最后一个是 1。

最后，每个连续的时间值必须比它前面的值大或者相等。

#### repeatCount、repeatDur

`repeatCount` 表示动画执行次数，可以是合法数值或者 `indefinite`（无限循环）。

`repeatDur` 定义重复动画的总时间。可以是普通时间值或者 `indefinite`（无限循环）。

#### fill

这里的 `fill` 是 SMIL 属性，不是上色的 `fill`。表示动画结束后如何处理。支持参数：`freeze`、`remove`。其中 `remove` 是默认值，表示动画结束直接回到开始的地方。`freeze` 表示动画结束后保持结束时的状态。

#### accumulate、additive

`accumulate` 是累积的意思。支持参数：`none`、`sum`。默认值是 `none`。如果值是 `sum` 表示动画结束时候的位置作为下次动画的起始位置。

`additive` 控制动画是否附加。支持参数：`replace`、`sum`。默认值是 `replace`。如果值是 `sum` 表示动画的基值会附加到其他低优先级的动画上。

#### restart

`restart` 控制重新开启动画的规则。支持的参数有：`always`、`whenNotActive`、`never`。

* `always` 是默认值，表示随时可以重新开始。
* `whenNotActive` 表示动画正在进行的时候，不能重启动画。
* `never` 表示动画开始后不能再由外部条件重启。

## SVG 与 JavaScript

当 SVG 嵌入到 HTML 页面的时候，你可以使用 JavaScript 来操作 SVG 元素，就像操作其他 HTML 元素一样。

* 通过 ID 或 class 获取 SVG 元素
* 可以读取/修改 SVG 元素的属性值
* 可以读取/修改 SVG 元素的 CSS 属性值
* 可以给 SVG 元素及其子元素添加事件监听
* 动画的暂停与播放

  ```javascript
  // svg 指当前 svg DOM 元素（SVGSVGElement）
  svg.pauseAnimations(); // 暂停
  svg.unpauseAnimations(); // 继续
  ```

## 参考链接

[SVG元素在移动H5页面动画的应用](http://genie88.github.io/2015/10/23/mobile-html5-page-development-skills-part5/)

[SVG 动画精髓](https://juejin.im/entry/5907dd4cda2f60005d0fd6c3)

[MDN SVG](https://developer.mozilla.org/zh-CN/docs/Web/SVG)

[MDN SVG 教程](https://developer.mozilla.org/zh-CN/docs/Web/SVG/Tutorial)
