位图和矢量图
- 位图: 经常用到的图像格式,如 PNG/JPEG 等文件, 它的像素都是固定的, 放大后会失真
- 矢量图: 与位图不同放大后不会失真, 它是根据数据动态计算的, 所以放大后不会失真
SVG 介绍
- SVG 是一种基于 XML 的图形语言,它可以用于创建各种图形和图像。
- SVG 文件是一个 XML 文档,它包含一个
<svg>元素,该元素包含其他元素。 <svg>元素可以包含其他元素,如<rect>、<circle>、<line>、<path>、<polygon>、<polyline>、<text>等。- SVG 文件可以用于创建各种图形和图像,包括矢量图形、线条图形、圆形图形、椭圆形图形、文本图形、图像图形等。
快速开始
注意
SVG 也可以通过标签的属性直接设置宽度和高度, 同时也能够使用 CSS 来设置宽度和高度 不同与 canvas 的是, 使用 SVG 设置宽度和高度并不会缩放和失真
html
<svg width="500" height="500">
<!-- 画圆 -->
<circle cx="50" cy="50" r="40" fill="blue" />
<!-- 绘制文字 -->
<text x="10" y="120">Hello World</text>
</svg>使用 SVG 的四种常见方式
1.内嵌到 HTML 标签中
html
<svg width="500" height="500">
<circle cx="50" cy="50" r="40" fill="blue" />
</svg>2.通过浏览器打开 SVG 图片
可以将这个 xml 保存成一个单独的 demo.svg 文件, 然后用浏览器打开
html
<!-- 注意: 如果保存成单独的文件, 比如加上 xmlns 属性, 且值必须是这个地址 -->
<svg width="500" height="500" xmlns="http://www.w3.org/2000/svg">
<circle cx="50" cy="50" r="40" fill="blue" />
</svg>3.在 html 的 img 标签中应用
html
<img src="./demo.svg" />4.作为 css 的背景来使用
css
#box {
width: 500px;
height: 500px;
background-image: url("./demo.svg");
}绘制矩形标签
html
<svg width="500" height="500" xmlns="http://www.w3.org/2000/svg">
<!--
rect: 绘制矩形标签, 参数与 canvas 类似
x,y: 确定矩形开始绘制的位置
width,height: 确定矩形的宽度和高度
fill: 填充的颜色
stroke: 修改描边的颜色
stroke-width: 修改描边的宽度
rx,ry: 设置圆角的半径
-->
<rect x="100" y="100" width="100" height="100" fill="#f00" stroke="#0f0" stroke-width="10" rx="10" ry="10"></rect>
</svg>绘制椭圆/圆形标签
html
<svg width="500" height="500" xmlns="http://www.w3.org/2000/svg">
<!-- 利用矩形+圆角可以画圆 -->
<rect x="100" y="100" width="100" height="100" rx="50"></rect>
<!-- 直接使用 circle 标签画圆
cx,cy: 圆心的位置
r: 圆的半径
-->
<circle cx="300" cy="300" r="50"></circle>
</svg>
<svg width="500" height="500" xmlns="http://www.w3.org/2000/svg">
<!-- 使用 rect + 圆角 绘制椭圆形 -->
<rect x="100" y="100" width="200" height="100" rx="100" ry="50"></rect>
<!-- ellipse 直接绘制椭圆
cx,cy: 圆心的位置
rx: 水平方向的半径
ry: 垂直方向的半径
-->
<ellipse cx="300" cy="300" rx="100" ry="50"></ellipse>
</svg>绘制直/折线和多边形
html
<!--- 绘制折线-->
<svg width="500" height="500" xmlns="http://www.w3.org/2000/svg">
<!-- line 绘制直线:
x1,y1: 直线起点的坐标
x2,y2: 直线结束点的坐标
stroke: 绘制的颜色
-->
<line x1="100" y1="100" x2="300" y2="100" stroke="#f00"></line>
<!-- polyline 绘制折线
points: 设置绘制线的所有点, 两两一对
stroke: 设置绘制线的颜色
fill: 默认填充黑色, none 表示不需要填充
-->
<polyline points="100 200 300 200 300 300" stroke="#f00" fill="none"></polyline>
<!-- polyline 绘制多边形: 将最后一个点和坐标和第一个坐标相同即可, 但是这样做比较麻烦 -->
<!--<polyline points="100 200 300 200 300 300 100 200" stroke="#f00" fill="none"></polyline>-->
</svg>
<!--- 绘制多边形-->
<svg width="500" height="500" xmlns="http://www.w3.org/2000/svg">
<!-- polygon 绘制多边形: 他会自动关闭路径, 将最后一个点与第一个点链接起来
points: 与 polyline 参数一样, 只是polygon会自动关闭路径, 而 polyline 不会
-->
<polygon points="100 200 300 200 300 300" stroke="#f00" fill="none"></polygon>
</svg>SVG 常用属性
| 属性 | 作用 |
|---|---|
| fill | 修改填充颜色 |
| fill-opacity | 修改填充颜色的透明度 |
| stroke | 修改描边颜色 |
| stroke-width | 修改描边的宽度 |
| stroke-opacity | 修改描边颜色的透明度 |
| stroke-linecap | 修改线段两端的样式 butt(默认)/square/round |
| stroke-dasharray | 设置虚线 |
| stroke-dashoffset | 设置虚线偏移位置 |
| stroke-linejoin | 设置折线转角样式 miter/bevel/round |
注意这些属性都是可以在 css 中直接使用的
html
<!DOCTYPE html>
<html lang="zh-cn">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="referrer" content="no-referrer" />
<title>Canvas and SVG</title>
<style>
svg {
border: 1px solid #f00;
}
svg polygon {
fill: none;
stroke: #f00;
}
</style>
</head>
<body>
<svg width="500" height="500" xmlns="http://www.w3.org/2000/svg">
<polygon points="100 200 300 200 300 300"></polygon>
</svg>
</body>
</html>path 路径
- 字母指令与数字坐标中间可以不使用空格隔开
- 路径的字母指令是区分大小写的
- 大写: 绝对定位(以 svg 的左上角作为参考点)
- 小写: 相对定位(以上一个点作为参考点)
- 路径的字母指令表如下
| 指令 | 说明 |
|---|---|
| M | moveTo 起点坐标 |
| L | lineTo 其他点的坐标 |
| H | horizontal lineTo 和上一个点的 Y 坐标相同 |
| V | vertical lintTo 和上一个点的 X 坐标相同 |
| A | 绘制椭圆弧度 A(rx,ry,xr,laf,sf,x,y) |
| Z | closePath 闭合路径 |
html
<!DOCTYPE html>
<html lang="zh-cn">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="referrer" content="no-referrer" />
<title>Canvas and SVG</title>
<style>
svg {
border: 1px solid #f00;
}
</style>
</head>
<body>
<svg width="500" height="500" xmlns="http://www.w3.org/2000/svg">
<!-- 这种情况和 canvas 类似, 无法很好的闭合路径, 会有"瑕疵" -->
<!--<path d="M 100 100 L 300 100 L 300 300 L 100 100" stroke="#f00" stroke-width="10" fill="none"></path>-->
<!-- 使用Z闭合路径, 但是这样写起来比较复杂, 可以用 HV 两个属性来简化下 -->
<!--<path d="M 100 100 L 300 100 L 300 300 Z" stroke="#f00" stroke-width="10" fill="none"></path>-->
<!-- SVG 路径: 可以绘制任意图形, 不过参数比较多一些
d: 绘制路径的数据, 需要用字母指令来确定
-->
<path d="M100 100 H300 V300 Z" stroke="#f00" stroke-width="10" fill="none"></path>
</svg>
<svg width="500" height="500" xmlns="http://www.w3.org/2000/svg">
<!-- M100 100 和 L300 100 都是相对与 svg 左上角的位置来定位的 -->
<path d="M 100 100 L 300 100" stroke="#f00" stroke-width="10" fill="none"></path>
</svg>
<svg width="500" height="500" xmlns="http://www.w3.org/2000/svg">
<!-- l300 100 是相对于 M100 100 的位置来定位的 -->
<path d="M 100 100 l 300 100" stroke="#f00" stroke-width="10" fill="none"></path>
</svg>
</body>
</html>绘制文本
html
<svg width="500" height="500" xmlns="http://www.w3.org/2000/svg">
<line x1="0" y1="250" x2="500" y2="250" stroke="#f00"></line>
<line x1="250" y1="0" x2="250" y2="500" stroke="#f00"></line>
<!-- text 绘制文字, 与 canvas 一样, x,y是设置文字的左下角
x,y: 确定文字绘制的位置(左下角)
style: 设置文字的样式
fill: 设置文字填充颜色(默认是填充而不是描边)
stroke: 设置文字描边的颜色
text-anchor: 文字水平方向的对齐方式(取值有: start/end/middle)
dominant-baseline: 文字垂直方向的对齐方式(取值有: text-after-edge/middle)
dx: 指定一个字符与上一个字符的间隙宽度
dy: 指定一个字符在垂直方向的偏移量
-->
<text
x="250"
y="250"
style="font-size: 30px"
fill="f00"
text-anchor="middle"
dominant-baseline="middle"
dx="10 20 30 40 50"
dy="10 20 30 40 50"
>
Hello
</text>
</svg>
<!-- 绘制多行文本 -->
<svg width="500" height="500" xmlns="http://www.w3.org/2000/svg">
<text fill="#00f">
<!-- 如果自己有 fill 属性会使用自己的fill 属性 -->
<tspan x="100" y="100" fill="#f00">hello</tspan>
<tspan x="100" y="200" fill="#0f0">world</tspan>
<!-- 没有会继承 text 的 fill 属性 -->
<tspan x="100" y="300">SVG</tspan>
</text>
</svg>绘制超链接
html
<svg width="500" height="500" xmlns="http://www.w3.org/2000/svg">
<!-- a 标签的用法与 html 的 a 标签类似:
只要将需要添加超链接的内容放到标签中间即可添加超链接
xlink:href 指定需要跳转的url
xlink:title 鼠标移动上去后显示的提示文本
target 超链接在浏览器中打开的方式
_self (默认值)当前标签页打开
_blank 新标签页打开
-->
<a xlink:href="https://github.com" xlink:title="Github" target="_blank">
<text x="100" y="100">open github.com</text>
</a>
</svg>绘制图片
html
<svg width="600" height="600" xmlns="http://www.w3.org/2000/svg">
<!--
image 绘制图片 默认情况下, 原图是多大, 绘制出来就是多大
xlink:href 设置图片的 url
width: 设置图片的宽度
height: 设置图片的高度
当设置的尺寸和原图的实际尺寸不一样时: 高度填满, 宽度等比拉伸
x,y: 设置图片绘制的位置
-->
<image
width="400px"
height="200px"
x="100"
y="100"
xlink:href="https://raw.githubusercontent.com/liaohui5/images/refs/heads/main/images/20220420132604.png"
></image>
</svg>结构标签
| 标签 | 作用 |
|---|---|
| g | g 是 group 的缩写, 可以将多个元素组合成一组元素, 以便于统一操作: 比如旋转,缩放,添加样式等, 对 g 标签设置的所有样式都会应用这组元素中的所有子元素 |
| use | g 结构元素封装的原数组, 可以通过 use 来进行复制使用 |
| defs | defs 包裹的元素/元素组默认不会显示出来, 只有用到后才会显示出来 |
| symbol | 与 defs 类似, 包裹的元素默认不会显示 |
symbol 与 g 标签的区别, symbol 可以自定义 viewBox 和 preserveAspectRatio 属性
html
<svg width="600" height="600" xmlns="http://www.w3.org/2000/svg">
<!-- 统一给组内的所有元素设置 fill 属性, 如果组内的子元素有 fill 就不设置 -->
<g fill="red" id="rects">
<rect x="10" y="10" width="100" height="100"></rect>
<rect x="10" y="120" width="100" height="100"></rect>
<rect x="10" y="230" width="100" height="100" fill="blue"></rect>
</g>
<!-- 使用已经编组的元素 -->
<use xlink:href="#rects" x="150"></use>
</svg>
<svg width="600" height="600" xmlns="http://www.w3.org/2000/svg">
<!-- 使用 defs 后, 默认不会显示, 相当于只是定义了一个模板 -->
<defs>
<g id="rects1">
<rect x="10" y="10" width="100" height="100"></rect>
<rect x="10" y="120" width="100" height="100"></rect>
<rect x="10" y="230" width="100" height="100" fill="blue"></rect>
</g>
</defs>
<!-- 只有 use 到后, 才会显示 -->
<use xlink:href="#rects1" x="10" fill="red"></use>
<use xlink:href="#rects1" x="150" fill="red"></use>
</svg>
<svg width="600" height="600" xmlns="http://www.w3.org/2000/svg">
<!-- 使用 symbol 后, 默认不会显示, 相当于只是定义了一个模板 -->
<symbol>
<g id="rects2">
<rect x="10" y="10" width="100" height="100"></rect>
<rect x="10" y="120" width="100" height="100"></rect>
<rect x="10" y="230" width="100" height="100" fill="blue"></rect>
</g>
</symbol>
<!-- 只有 use 到后, 才会显示 -->
<use xlink:href="#rects2" x="10" fill="red"></use>
<use xlink:href="#rects2" x="150" fill="red"></use>
</svg>裁剪 & 蒙版
- clipPath: 裁剪, 只有这个路径范围内的内容才会显示, 路径外的内容不会显示
- mask: 蒙版与裁剪类似
- 裁剪路径是可见与不可见的
突变 - 蒙版路径是可见与不可见的
渐变, 简单来说就是蒙版可以设置透明度
- 裁剪路径是可见与不可见的
使用裁剪/蒙版: 需要通过这种格式 url(#clipPathId) 来指定
html
<!-- 默认: 圆形盖住矩形 -->
<svg width="600" height="600" xmlns="http://www.w3.org/2000/svg">
<rect x="100" y="100" width="300" height="200" fill="blue"></rect>
<circle cx="200" cy="200" r="100" fill="red"></circle>
</svg>
<!-- 裁剪: 矩形只显示被圆形盖住的部分 -->
<svg width="600" height="600" xmlns="http://www.w3.org/2000/svg">
<clipPath id="myClipPath">
<circle cx="200" cy="200" r="100" fill="red"></circle>
</clipPath>
<rect clip-path="url(#myClipPath)" x="100" y="100" width="300" height="200" fill="blue"></rect>
</svg>
<!-- 蒙版: 矩形只显示被圆形盖住的部分, 但是两者的颜色会混合变为紫色 -->
<svg width="600" height="600" xmlns="http://www.w3.org/2000/svg">
<mask id="myMask">
<!-- 设置蒙版的透明度可以用 rgba 的格式来设置 -->
<circle cx="200" cy="200" r="100" fill="rgba(255, 0, 0, 0.5)"></circle>
</mask>
<rect mask="url(#myMask)" x="100" y="100" width="300" height="200" fill="blue"></rect>
</svg>渐变色
和 canvas 中类似, 在 svg 中也可以设置渐变色
- 线性渐变: linearGradient
- 径向渐变: radialGradient
html
<svg width="600" height="600" xmlns="http://www.w3.org/2000/svg">
<!-- 默认不要显示渐变 -->
<defs>
<!--
默认情况下: 与 canvas 渐变方案不同的是, x1 和 y1 的取值不是具体的坐标位置
而是从左到右的百分比: 取值为 0~1(比如x: 最左边是0 最右边是 1)
x1, y1: 线性渐变的起点
x2, y2: 线性渐变的终点
x1=0,y1=0: 表示左上角的位置
x2=1,y2=1: 表示右下角的位置
如果需要修改成类似 cnavas 那样的指定具体的坐标, 可以使用:
gradientUnits="objectBoundingBox": 百分比(默认值)
gradientUnits="userSpaceOnUse": 举例svg左上角具体坐标
注意这个取值是区分大小写的, 不能写错
-->
<linearGradient id="myColor" x1="0" y1="0" x2="1" y2="1" gradientUnits="objectBoundingBox">
<!-- stop 标签表示渐变的进度和颜色
offset: 渐变的进度
stop-color: 渐变的颜色
-->
<stop offset="0" stop-color="red"></stop>
<stop offset="0.5" stop-color="green"></stop>
<stop offset="1" stop-color="blue"></stop>
</linearGradient>
<linearGradient id="myColor2" x1="100" y1="350" x2="400" y2="550" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="red"></stop>
<stop offset="0.5" stop-color="green"></stop>
<stop offset="1" stop-color="blue"></stop>
</linearGradient>
</defs>
<!-- 注意使用渐变颜色方案的格式为: url(#gradientId) -->
<rect x="100" y="100" width="300" height="200" fill="url(#myColor)"></rect>
<rect x="100" y="350" width="300" height="200" fill="url(#myColor2)"></rect>
</svg>画笔
用自定义的图形来填充其他图形
html
<svg width="600" height="600" xmlns="http://www.w3.org/2000/svg">
<defs>
<!--
默认情况下: patternUnits="objectBoundingBox"
width: 被填充图形的总宽度的 20%
height: 被填充图形的总高度的 20%
可以修改为: patternUnits="userSpaceOnUse"
width: 20 个像素
height: 20 个像素
-->
<pattern id="myPattern" width="0.2" height="0.2">
<circle cx="10" cy="10" r="10" fill="red"></circle>
</pattern>
<pattern id="myPattern2" width="20" height="20" patternUnits="userSpaceOnUse">
<circle cx="10" cy="10" r="10" fill="red"></circle>
</pattern>
</defs>
<!-- 应用画笔来填充这个矩形 -->
<rect x="100" y="100" width="300" height="200" fill="url(#myPattern)"></rect>
<rect x="100" y="400" width="300" height="200" fill="url(#myPattern2)"></rect>
</svg>形变
SVG 的形变和 canvas 的形变规则一样, 操作的是整个坐标系而不是具体的元素
html
<svg width="600" height="600" xmlns="http://www.w3.org/2000/svg">
<rect x="100" y="100" width="300" height="200" fill="red"></rect>
<rect x="100" y="100" width="300" height="200" fill="blue" transform="translate(100, 100)"></rect>
</svg>ViewBox
viewBox
viewBox 就是可视区域, 用户能用眼睛看到的区域 默认情况下, 可视区域和内容区域的大小是一样的 但是我们可以手动修改可视区域的大小
viewBox 属性格式:
viewBox="x y width height"
- x: 修改可视区域的 x 方向位置
- y: 修改可视区域的 y 方向位置
- width/height: 修改可视区域的尺寸, 近大远小
html
<!-- 默认情况 viewBox="0 0 200 200" -->
<svg width="200" height="200" xmlns="http://www.w3.org/2000/svg">
<rect x="50" y="50" width="100" height="100" fill="red"></rect>
</svg>
<!-- viewBox="50 50 200 200": 表示: 将可视区域向右下各偏移 50 像素 -->
<svg viewBox="50 50 200 200" width="200" height="200" xmlns="http://www.w3.org/2000/svg">
<rect x="50" y="50" width="100" height="100" fill="red"></rect>
</svg>
<!-- viewBox="-50 -50 200 200": 表示: 将可视区域向左上各偏移 50 像素 -->
<svg viewBox="-50 -50 200 200" width="200" height="200" xmlns="http://www.w3.org/2000/svg">
<rect x="50" y="50" width="100" height="100" fill="red"></rect>
</svg>
<!-- viewBox="0 0 400 400": 表示将可视区域放大到400,里面的内容会随之缩放 -->
<svg viewBox="0 0 400 400" width="200" height="200" xmlns="http://www.w3.org/2000/svg">
<rect x="50" y="50" width="100" height="100" fill="red"></rect>
</svg>
<!-- viewBox="0 0 100 100": 表示将可视区域缩小到100,里面的内容会随之缩放 -->
<svg viewBox="0 0 100 100" width="200" height="200" xmlns="http://www.w3.org/2000/svg">
<rect x="50" y="50" width="100" height="100" fill="red"></rect>
</svg>preserveAspectRatio
preserveAspectRatio 的取值有这些:
- xMin: viewport 和 viewBox 左边对齐
- xMid: viewport 和 viewBox x 轴的中心对齐
- xMax: viewport 和 viewBox 右边对齐
- YMin: viewport 和 viewBox 上边对齐
- YMid: viewport 和 viewBox y 轴的中心对齐
- YMax: viewport 和 viewBox 下边对齐
注意: 这些取值必须严格遵循大小写
html
<svg viewBox="0 0 200 200" width="200" height="200" xmlns="http://www.w3.org/2000/svg">
<circle cx="50" cy="50" r="50" fill="#f00" />
</svg>
<!-- 放大视口: 在原宽高基础上等比例放大 -->
<svg viewBox="0 0 400 400" width="200" height="200" xmlns="http://www.w3.org/2000/svg">
<circle cx="50" cy="50" r="50" fill="#f00" />
</svg>
<!-- 缩小视口: 在原宽高基础上等比例缩小 -->
<svg viewBox="0 0 150 150" width="200" height="200" xmlns="http://www.w3.org/2000/svg">
<circle cx="50" cy="50" r="50" fill="#f00" />
</svg>
<!-- 缩小视口: 但不是等比例缩小 -->
<svg viewBox="0 0 50 150" width="200" height="200" xmlns="http://www.w3.org/2000/svg">
<circle cx="50" cy="50" r="50" fill="#0f0" />
</svg>
<!-- 缩小视口: 但不是等比例缩小 -->
<svg viewBox="0 0 150 50" width="200" height="200" xmlns="http://www.w3.org/2000/svg">
<circle cx="50" cy="50" r="50" fill="#0f0" />
</svg>
<!--
默认情况下: 如果viewBox 的尺寸是根据原宽高的尺寸等比例缩放, 那么调整后的viewBox区域的xy
和内容区域的 x/y 对齐, 如果 viewBox 不是根据原宽高的尺寸等比例缩放的, 那么系统就会自动调
整 viewBox 的位置, 我们设置的 x/y 就会失效, 此时就需要 viewBox x/y 和内容区域的 xy 保持重
合, 那么就需要设置 preserveAspectRatio 属性, 来手动控制对齐方式
-->
<!-- 放大视口: 但不是等比例放大, 同时设置 preserveAspectRatio -->
<svg viewBox="0 0 50 150" preserveAspectRatio="xMinYMin" width="200" height="200" xmlns="http://www.w3.org/2000/svg">
<circle cx="50" cy="50" r="50" fill="#00f" />
</svg>
<!-- 缩小视口: 但不是等比例缩小, 同时设置 preserveAspectRatio -->
<svg viewBox="0 0 150 50" preserveAspectRatio="xMinYMin" width="200" height="200" xmlns="http://www.w3.org/2000/svg">
<circle cx="50" cy="50" r="50" fill="#00f" />
</svg>SVG 动画
在 svg 中, 总共有3种动画标记:
- animate
- animateTransform
- animateMontion
在 svg 中, 总共有2种类使用动画的方式
- 创建动画, 告诉动画标记哪个元素需要执行动画
- 插件元素, 在元素中说明需要执行什么动画
- 借助CSS, 利用CSS来选中SVG元素, 然后执行动画
svg 中的动画属性:
- attributeType: 属性类型, 可以是 CSS 属性, 也可以是 SVG 属性
- attributeName: 属性名称
- from/to: 动画运行的过程, 从哪到哪
- dur: 动画持续时间
- fill: 动画结束之后的状态(freeze:保持执行动画后的状态, remove:(默认值)恢复执行动画前的状态)
基本使用
html
<!-- 先创建动画, 然后用 xlink:href 应用到元素上 -->
<svg width="200" height="200" xmlns="http://www.w3.org/2000/svg">
<circle id="myCircle" cx="100" cy="100" r="50" fill="#f00" />
<!-- 将 #myCircle 的 r 属性 从 50 慢慢的变成 100, 动画持续3s钟 -->
<animate attributeName="r" from="50" to="100" dur="3s" xlink:href="#myCircle" />
</svg>
<!-- 先创建元素, 然后说明要如何执行动画 -->
<svg width="200" height="200" xmlns="http://www.w3.org/2000/svg">
<circle cx="100" cy="100" r="50" fill="#0f0">
<animate attributeName="r" from="50" to="100" dur="3s" fill="freeze" />
</circle>
</svg>
<!-- 直接使用 css 来让 SVG 执行动画 -->
<svg width="300" height="300" viewBox="0 0 300 300" xmlns="http://www.w3.org/2000/svg">
<style>
@keyframes pulse {
0% {
transform: scale(1);
}
50% {
transform: scale(0.5);
}
100% {
transform: scale(1);
}
}
.heart {
animation: pulse 1s linear infinite;
transform-origin: 50% 50%;
}
</style>
<g class="heart">
<path
d="M150 270 Q75 225 45 150 Q30 105 75 75 Q120 45 150 90 Q180 45 225 75 Q270 105 255 150 Q225 225 150 270"
fill="red"
/>
<path
d="M150 270 Q225 225 255 150 Q270 105 225 75 Q180 45 150 90 Q120 45 75 75 Q30 105 45 150 Q75 225 150 270"
fill="red"
/>
</g>
</svg>动画的常用属性
- repeatCount: 执行动画的次数(indefinite: 无限次执行)
- repeatDur: 总共执行动画的时间
- begin: 执行动画的触发事件+执行动画的延迟时间
- restart: 动画开始之后,是否可以立即重新开始执行
- always: 不管是否执行完, 立即重新开始执行
- whenNotActive: 只有执行完之后才能重新开始执行
- never: 动画执行完之后不重置, 就只执行一次
- calcMode: 设置每个动画片段的动画表现
- linear: (默认) 匀速动画
- discrete: 非连续动画,瞬间完成
- paced: 整个动画始终以相同的速度进行
- spline: 自定义动画, 需配合
keySplines属性来动画过度效果
- keyTimes: 划分动画片段(类似CSS 的 keyfames)
- values: 划分对应取值片段的值
html
<svg width="200" height="200" xmlns="http://www.w3.org/2000/svg">
<circle cx="100" cy="100" r="50" fill="#f00">
<animate attributeName="r" from="50" to="100" dur="1s" repeatCount="indefinite" />
</circle>
</svg>
<svg width="200" height="200" xmlns="http://www.w3.org/2000/svg">
<circle cx="100" cy="100" r="50" fill="#0f0">
<animate attributeName="r" from="50" to="100" dur="1s" repeatDur="3s" />
</circle>
</svg>
<svg width="200" height="200" xmlns="http://www.w3.org/2000/svg">
<circle cx="100" cy="100" r="50" fill="#00f">
<animate attributeName="r" from="50" to="100" dur="1s" begin="2s" />
</circle>
</svg>
<svg width="200" height="200" xmlns="http://www.w3.org/2000/svg">
<circle cx="100" cy="100" r="50" fill="gray">
<animate attributeName="r" from="50" to="100" dur="1s" begin="click" />
</circle>
</svg>
<svg width="200" height="200" xmlns="http://www.w3.org/2000/svg">
<circle cx="100" cy="100" r="50" fill="#ff0">
<animate attributeName="r" from="50" to="100" dur="1s" begin="click+1s" />
</circle>
</svg>
<svg width="200" height="200" xmlns="http://www.w3.org/2000/svg">
<circle cx="100" cy="100" r="50" fill="#f0f">
<animate attributeName="r" from="50" to="100" dur="1s" restart="whenNotActive" />
</circle>
</svg>
<svg width="200" height="200" xmlns="http://www.w3.org/2000/svg">
<circle cx="100" cy="100" r="50" fill="skyblue">
<animate attributeName="r" keyTimes="0;0.5;1" dur="1s" values="25;50;100" />
</circle>
</svg>复合动画
html
<!-- 1.动画执行过程中改变多个属性 -->
<svg width="200" height="200" xmlns="http://www.w3.org/2000/svg">
<circle cx="100" cy="100" r="50" fill="#f00">
<!-- 如果要改变多个属性, 那么需要多个 animate 元素 -->
<animate attributeName="r" from="50" to="100" dur="1s" repeatCount="indefinite" />
<animate attributeName="fill" from="#f00" to="#0f0" dur="1s" repeatCount="indefinite" />
</circle>
</svg>
<!-- 2.按照顺序执行动画 -->
<svg width="400" height="200" xmlns="http://www.w3.org/2000/svg">
<circle cx="100" cy="100" r="50" fill="#f00">
<animate id="toRight" attributeName="cx" from="100" to="300" dur="1s" />
<!-- toRight.end 表示等待 id="toRight" 的动画结束时才执行 -->
<animate attributeName="cx" from="300" to="100" dur="1s" begin="toRight.end" />
</circle>
</svg>
<!-- 3.互相等待, 无限往返 -->
<circle cx="100" cy="100" r="50" fill="#f00">
<!-- 0;toLeft.end 表示:
第一次不等待执行执行, 必须这样, 否则一直互相等待, 根本无法开始执行动画
后续等待 id="toRight" 的动画结束时才执行
-->
<animate id="toRight" attributeName="cx" from="100" to="300" dur="1s" begin="0;toLeft.end" />
<animate id="toLeft" attributeName="cx" from="300" to="100" dur="1s" begin="toRight.end" />
</circle>形变动画
类似CSS的形变动画, 如果更熟悉CSS的话, 也可以直接使用CSS
html
<svg width="400" height="400" xmlns="http://www.w3.org/2000/svg">
<rect x="0" y="0" width="100" height="100">
<!-- type: 形变的类型, 比如: translate, rotate, scale 等 -->
<animateTransform attributeName="transform" type="translate" from="0 0" to="100 100" dur="1s" fill="freeze" />
</rect>
</svg>路径动画
所谓的路径动画, 就是沿着一个 path 执行动画
html
<svg width="600" height="600" xmlns="http://www.w3.org/2000/svg" viewBox="-100 -100 600 600">
<!-- 这个Path仅仅作为参考,并不是必须的 -->
<path d="M0 0 C0 300 300 300 300 0" stroke="#f00" stroke-widht="2" fill="none"></path>
<rect x="0" y="0" width="40" height="40" fill="rgba(255,0,0,0.5)">
<animateMotion path="M0 0 C0 300 300 300 300 0" dur="3s" fill="freeze" rotate="auto"></animateMotion>
</rect>
</svg>SVG 脚本编程
所谓的 SVG 脚本编程, 就是使用 JS 来操作 SVG 元素, 了解一下开源库
js
window.onload = () => {
// 注: 如果要使用 JS 动态的创建 svg 元素, 必须指定 namespace, 否则不生效
const SVG_NS = "http://www.w3.org/2000/svg";
const svgDom = document.createElementNS(SVG_NS, "svg");
svgDom.setAttribute("width", "600");
svgDom.setAttribute("height", "600");
const circleDom = document.createElementNS(SVG_NS, "circle");
circleDom.setAttribute("cx", "50");
circleDom.setAttribute("cy", "50");
circleDom.setAttribute("r", "50");
circleDom.setAttribute("fill", "#f00");
svgDom.appendChild(circleDom);
// 注: 如果要设置带有 xlink:xxx 这样的属性必须要指定 namespace, 否则不生效
const imageDom = document.createElementNS(SVG_NS, "image");
const XLinkNS = "http://www.w3.org/1999/xlink";
imageDom.setAttributeNS(XLinkNS, "xlink:href", "https://avatars.githubusercontent.com/u/29266093");
imageDom.setAttribute("x", "100");
imageDom.setAttribute("y", "100");
imageDom.setAttribute("width", "200");
imageDom.setAttribute("height", "200");
svgDom.appendChild(imageDom);
document.body.appendChild(svgDom);
};html
<!doctype html>
<html lang="zh-cn">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="referrer" content="no-referrer" />
<title>Canvas and SVG</title>
<style>
svg {
border: 1px solid #f00;
}
</style>
</head>
<body>
<svg width="600" height="600" xmlns="http://www.w3.org/2000/svg">
<circle cx="50" cy="50" r="50" fill="#f00" />
<image xlink:href="https://avatars.githubusercontent.com/u/29266093" x="100" y="100" width="200" height="200" />
</svg>
<script src="./index.js" type="module"></script>
</body>
</html>