简介
什么是svg
简单来说,SVG 是一种基于 XML 语法的图像格式,全称是可缩放矢量图(Scalable Vector Graphics)。
svg的优势
其他图像格式都是基于像素处理的(像素的图像会有很多问题),SVG 则是属于对图像的形状描述,所以它本质上是文本文件,体积较小,且不管放大多少倍都不会失真。
我们可以得到svg几个最大的优势:
- 可缩放的矢量图——不会失真;
- svg是由数学组成的,它只是一段段的代码,所以文件的体积会非常小——轻量级;
- 每个节点都是单独的dom,可以自由绑定事件和操作内容——易于操作和局部更新;
不足之处
- 不适合非常复杂的内容或者大量节点的场景
基本形状
svg内置了多种形状可以使用
rect 矩形
x、y:距离(0,0)的位置坐标——(0,0)是左上角的点
width、height:宽、高
rx、ry:圆角属性
fill:填充颜色
stroke、stroke-width:边颜色、边宽
opacity:透明度
<svg xmlns="http://www.w3.org/2000/svg" version="2.0">
<rect x="50" y="20" rx="20" ry="20" width="150" height="150" style="fill:red;stroke:black;stroke-width:5;opacity:0.5" />
</svg>
circle 圆形
cx、cy:圆心的坐标位置;
r:半径
<svg>
<circle cx="100" cy="50" r="40" stroke="black" stroke-width="2" fill="red" />
</svg>
ellipse 椭圆
上面的椭圆标准方程告诉我们,约定一个椭圆所需要的元素有:长轴半径、短轴半径、点的坐标;
所以我们绘制一个椭圆需要以下要素:
cx、cy:圆心坐标
rx、ry:水平半径、垂直半径
<svg>
<ellipse cx="240" cy="50" rx="220" ry="30" style="fill:yellow" />
<ellipse cx="220" cy="50" rx="190" ry="20" style="fill:white" />
</svg>
line 直线
x1、y1:直线开始的坐标点
x2、y2:直线结束的坐标点
<svg>
<line x1="0" y1="0" x2="200" y2="200"
style="stroke:rgb(255,0,0);stroke-width:2"/>
</svg>
polygon 多边形
不少于三条边的封闭图形,可以理解为多个点的集合围成的封闭图形
<svg height="210" width="500">
<polygon points="200,10 250,190 160,210"
style="fill:lime;stroke:purple;stroke-width:1"/>
</svg>
polyline 多线段
只有直线的多段形状,也是多个点的集合,不过不会首尾闭合
<svg xmlns="http://www.w3.org/2000/svg" version="1.1">
<polyline points="20,20 40,25 60,40 80,120 120,140 200,180"
style="fill:none;stroke:black;stroke-width:3" />
</svg>
path 路径
path是基本形状中最为强大的一个,可以用它来绘制 线条、曲线、弧形多种形状;
path用于绘制路径,path的d属性表示绘制顺序,它是一个长字符串,每个字母表示一个动作,后面跟着坐标;
所以,属性d的值是一个“命令+参数”的序列,每一个命令都用一个关键字母来表示,比如,字母“M”表示的是“Move to”命令,当解析器读到这个命令时,它就知道你是打算移动到某个点。跟在命令字母后面的,是你需要移动到的那个点的x和y轴坐标。比如移动到(10,10)这个点的命令,应该写成“M 10 10”。这一段字符结束后,解析器就会去读下一段命令。每一个命令都有两种表示方式,一种是用大写字母,表示采用绝对定位。另一种是用小写字母,表示采用相对定位(相对于上一个点移动多少距离)。
path指令集概览
| 指令 | 参数 | 指令说明 |
|---|---|---|
| M | x y | 移动到x,y位置 ( move to ) |
| L | x y | 从当前位置绘制指定线段到 x , y 的位置 ( line to ) |
| H | x | 从当前位置绘制水平线到 x 位置 ( horizontal line to ) |
| V | y | 从当前位置绘制垂直线到 x 位置 ( vertical line to ) |
| C | x1 y1 x2 y2 x y | 从当前位置绘制三次贝塞尔曲线到指定x,y位置:其中 x1, y1 及 x2, y2 为控制点 ( curve ) |
| S | x2 y2 x y | 从当前点的坐标画条反射的贝塞尔曲线到指定的x,y位置:其中 x2, y2 为反射的控制点 ( smooth curve ) |
| Q | x1 y1 x y | 从当前位置绘制二次贝塞尔曲线到指定x,y位置:其中 x1, y1 为控制点 ( quadratic Bézier curve ) |
| T | x y | 从当前点的坐标画条反射的二次贝塞尔曲线到指定的x,y位置:以前一个坐标为反射控制点( smooth quadratic Bézier curve ) |
| A | rx ry x-axis-rotation large-arc-flag sweep-flag x y | 从当前点画一条指定的圆弧到目标 x, y 位置:其中 rx, ry 为椭圆形的 x 轴及 y 轴的半径,x-axis-rotation 是弧线与 x 轴的旋转角度,large-arc-flag 配置为 1(最大角度的弧线)或是 0(最小角度的弧线),sweep-flag 配置方向是 1(顺时针方向)或 0(逆时针方向) |
| Z | 闭合当前路径 ( closepath ) |
Path命令总结有如下规律:
- 区分大小写:每一个命令都有两种表示方式,一种是用大写字母,表示采用绝对位置。另一种是用小写字母,表示采用相对位置
- 最后的参数表示最终要到达的位置
- 上一个命令结束的位置就是下一个命令开始的位置
- 命令可以重复参数表示重复执行同一条命令
- 因为属性d采用的是用户坐标系统,所以不需标明单位
直线命令
首先是“Move to”命令,M,前面已经提到过,它需要两个参数,分别是需要移动到的点的x轴和y轴的坐标。假设,你的画笔当前位于一个点,在使用M命令移动画笔后,只会移动画笔,但不会在两点之间画线。因为M命令仅仅是移动画笔,但不画线。所以M命令经常出现在路径的开始处,用来指明从何处开始画。
M x y
<path d="M0 0" stroke="skyblue"/>
能够真正画出线的命令有三个(M命令是移动画笔位置,但是不画线),最常用的是“Line to”命令,L,L需要两个参数,分别是一个点的x轴和y轴坐标,L命令将会在当前位置和新位置(L前面画笔所在的点)之间画一条线段。
L x y
<path d="M0 0 L50 50" stroke="skyblue"/>
另外还有两个简写命令,用来绘制水平线和垂直线。H,绘制水平线。V,绘制垂直线。这两个命令都只带一个参数,标明在x轴或y轴移动到的位置,因为它们都只在坐标轴的一个方向上移动。
V y
<path d="M0 0 V50" stroke="skyblue"/>
H x
<path d="M0 0 H50" stroke="skyblue"/>
Z命令会从当前点画一条直线到路径的起点,即闭合改路径。
<path d="M0 0 Q50 50, 100 0 T200 0 Z" stroke="black" fill="none"/>
曲线命令
三次贝塞尔曲线,最后一个坐标(x,y)表示的是曲线的终点,另外两个坐标是控制点,(x1,y1)是起点的控制点,(x2,y2)是终点的控制点
C x1 y1, x2 y2, x y
<path d="M0 0 C40 40,60 40,100,0" stroke="skyblue" fill="none"/>
此外,可以将若干个贝塞尔曲线连起来,从而创建出一条很长的平滑曲线。通常情况下,一个点某一侧的控制点是它另一侧的控制点的对称(以保持斜率不变)。这样可以使用一个简写的贝塞尔曲线命令S,如下所示:
S x2 y2, x y
<path d="M0 0 C40 40,60 40,100,0 S150 -40, 200 0" stroke="black" fill="none"/>
S命令可以用来创建与前面一样的贝塞尔曲线,但是,如果S命令跟在一个C或S命令后面,则它的第一个控制点会被假设成前一个命令曲线的第二个控制点的中心对称点。如果S命令单独使用,前面没有C或S命令,那当前点将作为第一个控制点。
另一种可用的贝塞尔曲线是二次贝塞尔曲线Q,它比三次贝塞尔曲线简单,只需要一个控制点,用来确定起点和终点的曲线斜率
Q x1 y1, x y
<path d="M0 0 Q50 50, 100 0" stroke="black" fill="none"/>
与三次贝塞尔曲线类似,二次贝塞尔曲线有一个差不多的T命令,可以通过更简短的参数,延长二次贝塞尔曲线
T x y
<path d="M0 0 Q50 50, 100 0 T200 0" stroke="black" fill="none"/>
命令T会通过前一个控制点,推断出一个新的控制点。
弧形
弧形命令A
A rx ry x-axis-rotation large-arc-flag sweep-flag x y
rx : 椭圆的 x 轴半径(根据不同的终点换算成比例)
ry : 椭圆的 y 轴半径(根据不同的终点换算成比例)
x-axis-rotation : 弧线与 x 轴的夹角
large-arc-flag : 1 表示为大角度弧线,0 表示为小角度弧线
sweep-flag : 1 为顺时针,0 为逆时针
x : 终点的 x 坐标
y : 终点的 y 坐标
<path d="M0 0 A50 100,60 0 0 100 0" stroke="#f90" fill="none"/>
上面对于path的介绍还比较为简单,path详情可以参考mdn的解释:
developer.mozilla.org/zh-CN/docs/…
marker 标注
marker可以作为小工具或者标志图标来理解,常见的可以用marker编写箭头
<svg width="" height="200" viewBox="0 0 120 120"
xmlns="http://www.w3.org/2000/svg" version="1.1">
<defs>
<marker id="markerCircle" markerwidth="8" markerheight="8" refx="5" refy="5">
<circle cx="5" cy="5" r="3" style="stroke: none; fill:#000000;"></circle>
</marker>
</defs>
<polyline points="10,90 50,80 90,20" fill="none" stroke="black"
stroke-width="2" marker-end="url(#markerCircle)" />
</svg>
text 文本
<svg xmlns="http://www.w3.org/2000/svg" version="1.1">
<defs>
<path id="path1" d="M75,20 a1,1 0 0,0 100,0"/>
</defs>
<a xlink:href="https://www.baidu.com" target="_blank">
<text x="0" y="15" fill="red">I love SVG
</text>
</a>
<text x="10" y="100" style="fill:red;">
<textPath xlink:href="#path1">this is test</textPath>
<tspan>span test</tspan>
</text>
</svg>
text结合textPath、tsapn等可以玩出很多的花样,虽然是简单的文本,但是可以拓展的方向还是很多的
a 超链接
只是标签名和html的a标签一样,但并不是一个元素
<svg width="140" height="30">
<a xlink:href="https://www.baidu.com"
target="_blank">
<rect height="30" width="120" y="0" x="0" rx="15"/>
<text fill="white" text-anchor="middle"
y="21" x="60">SVG A TAG</text>
</a>
</svg>
use 复用
use用于复制一个形状
<svg viewBox="0 0 30 10" xmlns="http://www.w3.org/2000/svg">
<circle id="myCircle" cx="5" cy="5" r="4"/>
<use href="#myCircle" x="10" y="0" fill="blue" />
<use href="#myCircle" x="20" y="0" fill="white" stroke="blue" />
</svg>
g 分组
g标签将多个形状分成一个组,方便复用
<svg width="300" height="100">
<g id="myCircle">
<text x="25" y="20">圆形</text>
<circle cx="50" cy="50" r="20"/>
</g>
<use href="#myCircle" x="100" y="0" fill="blue" />
<use href="#myCircle" x="200" y="0" fill="white" stroke="blue" />
</svg>
defs 标签
defs用于自定义形状,但是与直接使用g不同的是,内部的代码不会显示,仅供通过id引用
<svg width="300" height="100">
<defs>
<g id="myCircle">
<text x="25" y="20">circle</text>
<circle cx="50" cy="50" r="20"/>
</g>
</defs>
<use href="#myCircle" x="0" y="0" />
<use href="#myCircle" x="100" y="0" fill="blue" />
<use href="#myCircle" x="200" y="0" fill="white" stroke="blue" />
</svg>
pattern 标签
pattern可以自定义一个形状,改形状可以被引用来铺平一个区域
<svg width="500" height="500">
<defs>
<pattern id="dots" x="0" y="0" width="100" height="100" patternUnits="userSpaceOnUse">
<circle fill="#bee9e8" cx="50" cy="50" r="35" />
</pattern>
</defs>
<rect x="0" y="0" width="100%" height="100%" fill="url(#dots)" />
</svg>
foreignobject
可以包含来自不同的XML命名空间的元素,在浏览器的上下文中,可能是XHTML / HTML
<svg viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg">
<style>
polygon { fill: black }
div {
color: white;
font-size:18px;
height: 100%;
overflow: auto;
}
</style>
<polygon points="5,5 195,10 185,185 10,195" />
<!-- Common use case: embed HTML text into SVG -->
<foreignObject x="20" y="20" width="160" height="160">
<!--
In the context of SVG embeded into HTML, the XHTML namespace could
be avoided, but it is mandatory in the context of an SVG document
-->
<div>
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Sed mollis mollis mi ut ultricies. Nullam magna ipsum,
porta vel dui convallis, rutrum imperdiet eros. Aliquam
erat volutpat.
</div>
</foreignObject>
</svg>
stroke 属性
stroke:线、文本、元素的轮廓颜色
stroke-width:轮廓的宽度
stroke-linecap:终点的形状属性
stroke-dasharray:定义虚线的属性
animate 动画
animate定义在元素的内部,可以指定元素的属性如何改变,动画也可以配置多个
<svg width="500px" height="500px">
<rect x="0" y="0" width="100" height="100" fill="#feac5e">
<animate attributeName="height" to="200" dur="3s" repeatCount="indefinite" />
<animate attributeName="x" from="0" to="500" dur="2s" repeatCount="indefinite" />
</rect>
</svg>
animation 与 滤镜、渐变、模糊、阴影等可以做出很多效果,就不再这展开来讲,可以单独成文
viewport
表示SVG可见区域的大小,或者可以想象成舞台大小,画布大小。
<svg width="500" height="300"></svg>
上面的SVG代码定义了一个视区,宽500单位,高300单位。
width/height如果是纯数字,使用的就是“像素”作为单位的,上面SVG的视区大小就是500px * 300px。
viewBox属性
先看一个svg的例子:
<svg width="400" height="300" viewBox="0,0,40,30" style="border:1px solid #cd0000;">
<rect x="10" y="5" width="20" height="15" fill="#cd0000"/>
</svg>
如果先忽略viewBox,这里svg的尺寸是400*300像素,而的大小只有其1/20,但是显示出来的却明显不止这个大小;
viewBox值有4个数字:
viewBox="x, y, width, height" // x:左上角横坐标,y:左上角纵坐标,width:宽度,height:高度
viewBox顾名思意是“视区盒子”的意思,SVG就像是我们的显示器屏幕,viewBox就是截屏工具选中的那个框框,最终的呈现就是把框中的截屏内容再次在显示器中全屏显示;
更直观的解释:
- 如果没有viewBox, 应该是长这样的:
- viewBox="0,0,40,30"相当于在SVG上圈了下图左上角所示的一个框:
- 然后把这个框,连同框里的小矩形一起放大到整个SVG大小:
perserveAspectRatio
上面的例子,SVG的宽高比正好和viewBox的宽高比是一样的,都是4:3. 显然,实际应用viewBox不可能一直跟viewport同等比例。
preserveAspectRatio属性的值为空格分隔的两个值组合而成:
xMidYMid和meet.
第1个值表示,viewBox如何与SVG viewport对齐;
第2个值表示,如何维持高宽比(如果有)。
其中,第1个值又是由两部分组成的。前半部分表示x方向对齐,后半部分表示y方向对齐,可选如下:
| 值 | 含义 |
|---|---|
| xMin | viewport和viewBox左边对齐 |
| xMid | viewport和viewBox x轴中心对齐 |
| xMax | viewport和viewBox右边对齐 |
| YMin | viewport和viewBox上边缘对齐。注意Y是大写。 |
| YMid | viewport和viewBox y轴中心点对齐。注意Y是大写。 |
| YMax | viewport和viewBox下边缘对齐。注意Y是大写。 |
x,y可以自由组合
| 值 | 含义 |
|---|---|
| meet | 保持纵横比缩放viewBox适应viewport |
| slice | 保持纵横比同时比例小的方向放大填满viewport |
| none | 扭曲纵横比以充分适应viewport |
参考资料
MDN:www.yuque.com/u21340737/k…
菜鸟教程:www.runoob.com/svg/svg-tut…
svg详解(张鑫旭):www.zhangxinxu.com/wordpress/2…
常用工具
SVG Path 设计工具:yqnn.github.io/svg-path-ed…