SVG 快速入门

本文作者:ivweb villainthr

SVG 全称是 Scalable Vector Graphics,即,矢量图。在 Web 中使用 SVG 可以解决位图放大失真的问题。首先,不要把 SVG 和 CSS,Canvas,HTML 搞混。他们之间并没有你中有我,我中有你的关系。SVG 是通过 XML 的形式写在 HTML 文档中的。

如何书写

开篇说过,SVG 就是一个 XML。看一下代码吧:

<svg x="0px" y="0px" width="450px" height="100px" viewBox="0 0 450 100">
     <rect x="10" y="5" fill="white" stroke="black" width="90" height="90"/>
     <circle fill="white" stroke="black" cx="170" cy="50" r="45"/>
     <polygon fill="white" stroke="black" points="279,5 294,35 328,40 303,62
      309,94 279,79 258,94 254,62 230,39 263,35"/>
     <line fill="none" stroke="black" x1="410" y1="95" x2="440" y2="6"/>
     <line fill="none" stroke="black" x1="360" y1="6" x2="360" y2="95"/>
</svg>

大家看 svg 标签中带有一个 viewBox 的属性。这其实是 SVG 中一个很重要的概念,后面的缩放都会与它有关。

说到这里,我们就需要了解一下关于 SVG 的几个基本概念。

基本概念

简单来说有 3 个基本概念:

  • viewport: 物理窗口
  • viewbox: 实物窗口(算了,下面解释)
  • preserveAspectRatio: 保留横纵比

我们接下来,一个一个的进行讲解吧。

viewport

参照上面的 demo,这实际上就是你用 x,y,width,height。这 4 个属性,在页面上固定的矩形区域。

viewbox

定义 SVG 元素在 viewport 中的具体尺寸比例。假设有如下内容:

<svg width="500" height="200" viewBox="0 0 50 20" >
 <rect x="20" y="10" width="10" height="5"
          style="stroke: #000000; fill:none;"/>
</svg>
  • viewport 为 [0,0] 到 [500,200]
  • viewbox 为 [0,0] 到 [50,20]

默认情况下 SVG 是自动填充满 viewport 的。注意,在 SVG 中,子标签的所有尺寸都是不能带单位的,因为初始单位就是根据上面两个概念确定。

当为以上情况,SVG 中基本的尺寸则不是 1px,而是 500/50 = 10px。所以,如下的图形大小为:

 <rect x="20" y="10" width="10" height="5"
          style="stroke: #000000; fill:none;"/>

也就是在 SVG 里面定义的rect图形,它的实际尺寸为 [200,100] 到 [100,50]。

preserveAspectRatio

该属性就是用来定义上面 viewport 和 viewbox 相互对齐的方式。换句话就是说,它的属性可以改变 viewbox 的具体位置。基本格式为: <align> [<meetOrSlice>]

  • align: 定义 viewport 和 viewbox 的对齐方式,分为 x,y 轴两个方向。X 轴方向有三种方式:左边重合(xMin),x 轴中点重合(xMid),右边重合(xMax)。同理,Y 轴也有 顶边重合(YMin),y 轴中点重合(YMid),底边边重合(YMax)
  • meetOrSlice: 主要就是定义该 SVG 是内嵌,还是裁剪或是 none(听天有命)。

其中,align 需要着重理解一下。首先,它的默认值为 xMidYMid,即为中点重合。

可以从图中看出,viewbox 是通过中心进行延展的。注意,它的原点坐标还是在 viewbox 的左上角。如果你是动态增加尺寸的话,此时并不是从左到右增加,而是从中心向两端扩张。同理,如果你使用的是 xMinYMin 的话,那么如果存在尺寸变化,那么相对点则是从左上角开始的。简单来说,align 相对点其实一共有 9 个。

然后就是 meet || slice || none 这三个属性具体干的事情。

在这之前,我们需要了解一个公式--缩放比计算公式:

vb_h rat_y = vp_h; 或者 vb_w rat_x = vp_w;

其中,vb 为 viewbox 简写,vp 为 viewport 的简写。vb_h 代表就是 viewbox height。vb_w 代表就是 viewbox width。rat_x/y 代表的是 x,y 轴的缩放比例。

假设有下列情况:

 <svg width="400" height="200" viewBox="0 0 200 200" preserveAspectRatio="xMinYMin slice" style="border:1px solid #cd0000;">
    <rect x="10" y="10" width="150" height="150" fill="#cd0000"/>
</svg>

那么,rat_x 和 rat_y 分别为:

  • rat_x = 400/200 = 2
  • rat_y = 200/200 = 1

现在,针对上面 meet/slice 不同的取值,实际应用到 svg 里面的缩放比例是不同的。

  • meet(默认值): 本意是让 svg 尽可能的显示在 viewport 里,即,会在 rat_x 和 rat_y 中选择最小的值作为缩放标准。
  • slice: 本意是让 svg 完全铺满 viewport,即,会在 rat_x 和 rat_y 中选择最大的值作为缩放标准。

所以针对不同的取值,基准比例也不同。

当为 meet 的情况,那么实际缩放比例为 1。则里面实际矩形的大小就为 (10,10) 到 (150,150)。

当为 slice 的情况,那么实际缩放比例为 2。则里面实际矩形的大小就为 (20,20) 到 (300,300)。

如果你的值为 none 的话,他会直接铺满整个 viewport,即,实际矩形大小为:(20,10) 到 (300,150)。

响应式 SVG

虽然讲起响应式,一些童鞋会想这 TM 又是啥奇技淫巧?

对不起,并不是。。。就是一个 viewbox 并且不带 width/height 而已。

看个实际的例子吧:

 <svg viewBox="0 0 218.8 87.1">
     <g fill="none" stroke="#000">
       <path d="M7.3 75L25.9 6.8s58.4-6.4 33.5 13-41.1 32.8-11.2 30.8h15.9v5.5s42.6
         18.8 0 20.6" />
       <path d="M133.1 58.2s12.7-69.2 24.4-47.5c0 0 4.1 8.6 9.5.9 0 0 5-10 10.4.9 0
         0 12.2 32.6 13.6 43 0 0 39.8 5.4 15.8 15.4-13.2 5.5-53.8
         13.1-77.4 5.9.1 0-51.9-15.4 3.7-18.6z" />
</g> 
</svg>

可以看到,上面的 svg 标签并没有带上啥 width/height 属性,只是简单描述了 viewBox 的范围而已。当然,里面的尺寸标准都是在这 viewBox 的范围内进行设置的。

另外,在这里声明一下,本文章并不是新手教程,也就是说,不会教你一步一步的画直线啊,圆啊,矩形啊等等这些基本图形。这些直接 google 一下,一搜一大把。所以,这里假设大家的水平是处于,能对 SVG 基本的图形属性熟悉即可,对一些高级属性还不是很清楚和熟练。OK,继续~

在 SVG 中,能够直接使用的图形有:

  • rect
  • circle
  • ellipse
  • line
  • polyline
  • polygon

上面没有啥说的,后面我详细说一下两个比较重要的概念,分组和 Path。

分组和 Path

通常 Path 和 分组通常是一起使用的,如上:

 <g fill="none" stroke="#000">
    <path d="M7.3 75L25.9 6.8s58.4-6.4 33.5 13-41.1 32.8-11.2 30.8h15.9v5.5s42.6
      18.8 0 20.6" />
    <path d="M133.1 58.2s12.7-69.2 24.4-47.5c0 0 4.1 8.6 9.5.9 0 0 5-10 10.4.9 0
      0 12.2 32.6 13.6 43 0 0 39.8 5.4 15.8 15.4-13.2 5.5-53.8
      13.1-77.4 5.9.1 0-51.9-15.4 3.7-18.6z" />
</g>

分组我们放到后面进行讲解,这里先看一下 Path。

Path

Path 在 SVG 中的地位应该是比较高的,实际上,利用 Path 这个一个标签可以画出任意的图形。path 中 d(data) 属性是用来定义相关线条数据,通常是以 M/m 为起始,代表的就是move to的意思。在 path 中,一共可以定义 10 种不同的图形。例如 M/m,L/l。 大家可以注意,每种标识符有两种书写方式,即,大小写。

  • 大写: 参照的是绝对坐标,即,SVG 的右上角
  • 小写: 参照的相对坐标,即,前一个点的坐标。

而在 10 中不同表示符中,又可以分为直线和曲线两种不同的标识符。这里,我们分类来讲解一下。

线型

M/m

该使用定义起始点的,没啥特殊的作用。 <path d="M10 10"/>

表示,以 (10,10) 为起始点。

L/l

原意是 Line to,用来画线段的。格式和 M/m 差不多: L x y (or l dx dy)

H/h

用来画水平线,即,Horizontal。既然方向已经定了,剩下的就是距离,格式很简单: H x (or h dx)

V/v

用来画竖直线,即,vertical。同上,方向也定了,格式为: V y (or v dy)

看个例子吧: <path d="M10 10 H 90 V 90 H 10 L 10 10"/>

该 path 实际上就是画了一个正方形,宽 = 高 = 90。

Z/z

该标识符用来表示 path 的结束,并且将最后一点和 M/m 标识开头的一点连接起来。所以,它不存在什么表示点之类的,格式为: Z (or z)

而上面也可以进行相关的优化,最终的结果为:

<path d="M10 10 H 90 V 90 H 10 L 10 10"/>
// 使用 Z
<path d="M10 10 H 90 V 90 H 10 Z" fill="transparent" stroke="black"/>

曲线

曲线就是 Web 画图中常见的 Bezier Curves(贝塞尔),Arcs,several Bezier curves(很多贝塞尔 - .-)等。

我们简单看一下:

C/c

这是正统的贝塞尔曲线,需要 4 个参考点,下图应该说比较确切表示了二次贝塞尔所需要的点。所以,C/c 需要定义三个点。

基本格式为: C x1 y1, x2 y2, x y (or c dx1 dy1, dx2 dy2, dx dy)

例如: <path d="M10 10 C 20 20, 40 20, 50 10" stroke="black" fill="transparent"/>

S/s

该标识符实际上使用来表示一个反射贝塞尔,即,在原有贝塞尔上再加一段贝塞尔曲线,所以,S/s 一般和 C/c 一起使用。

基本格式为: S x2 y2, x y (or s dx2 dy2, dx dy)

实际样式图为:

相当于原有的贝塞尔曲线的最后一段进行反向延长并对称。然后加上新定义的一段限制曲线。

具体实例为: <path d="M10 80 C 40 10, 65 10, 95 80 S 150 150, 180 80" stroke="black" fill="transparent"/>

Q/q

该标识符是用来定义二次(quadratic)贝塞尔曲线,该曲线相当于上面传统的贝塞尔来说,更加简单,它只需要定义三个点,即可完整一个贝塞尔曲线,具体作图过程如下:

基本格式为:

 Q x1 y1, x y (or q dx1 dy1, dx dy)

即为图上点, P1(x1,y1),P2(x,y)

起始点为 M 定义的点,例如: <path d="M10 80 Q 95 10 180 80" stroke="black" fill="transparent"/>

T/t

该标识符和 S 差不多,也是一个贝塞尔曲线的延长。相当于原曲线的控制点 P1 相当于 end point P2 做对称,然后,只需要定义一个终点即可,即,T/t 只需要定义贝塞尔曲线里面的终点即可: T x y (or t dx dy)

如图:

所以,简单来说,C/S,Q/T 是两两搭配一起使用的。在使用的时候,千万不要搞混即可。

弧线

A/a

该曲线是用来画弧线(Arcs),而,弧线通常是圆/椭圆的一部分。当,椭圆的两个轴径长相等则为圆,所以,A/a 是按照椭圆作为基准格式:

A rx ry x-axis-rotation large-arc-flag sweep-flag x y
 a rx ry x-axis-rotation large-arc-flag sweep-flag dx dy

说实在的,这个比较复杂。因为,他画椭圆的方式和我们平常不一样,一般情况下,椭圆只要确定一个中心,然后是长短轴,然后是弧度范围即可。

但是,它这里是通过椭圆上的两点来确定的,在加上旋转角度,俩轴径等因素来确定的。另外,需要注意,它的起始点是从上一个命令的结束点位置开始计算的。OK,我们首先简单了解一下格式里面的参数:

  • rx,ry: 代表的就是长轴短轴,没得说。
  • x,y: 代表的是弧长的结束点。开始点就是上一个命令的终点。
  • x-axis-rotation: x 轴的旋转角度。顺时针为正
  • large-arc-flag[0,1]: 表示取大弧还是小弧。因为两点之间的弧长有两部分。
  • sweep-flag[0,1]: 取顺时针的弧,还是逆时针的弧长。参考点是以起始点开始的。

上面几个属性中,比较难理解的就是 large-arc-flagsweep-flag。这么说吧,前面几个属性充其量只能确定椭圆的位置,和经过椭圆的两个点,不过,一般能通过指定两点的椭圆有两个,而通过这两点划分又会出现 4 段弧长。为了确定 4 个弧长中,是哪一个,需要两个值来确定。即,4 抽 2,2 抽 1。

简单说一种,例如当,laf 和 sf 都为 0的情况。首先,laf 为 0 选择的是小弧长。所以,里面两段比较小的弧长被抽出来。然后,sf 为 0 选择的是逆时针。即,以起始点为参考,选择通过逆时针方向到达终点的那段弧。即,2 抽 1。最终得出我们需要的弧。

说实在的,这个是真 TM 复杂。。。

给一个参考 codepen

一般情况下,我们并不需要手动来确定 path,有工具为啥不用工具呢!

比如,Illustrator, Sketch 等,都可以自动生成 SVG。不过,生成之后,需要对代码做相关的压缩优化,这些都可以直接在编译器里面找到。

你也可以用一下可视化工具 SVGOMG 来简单看一下。

分组

SVG 中的分组你可以理解为 PS 中的图层,一块图层里面通常只会放一下高内聚的图形,这样既方便移动又方便做动画。SVG 中的分组标签就是g,使用g 标签包裹的所有子元素都认同为一组。

例如:

 <g>
    <circle cx="20" cy="20" r="20" fill="green" />
    <circle cx="70" cy="70" r="20" fill="purple" />
  </g>
  <g>
    <rect x="110" y="110" height="30" width="30" fill="blue" />
    <rect x="160" y="160" height="30" width="30" fill="red" />
  </g>

需要注意的是,使用 g 进行分组,并不会改变原有元素的在屏幕上展示的效果。

不过,g标签除了分组,还有另外一个很重要的功能--动画

分组动画

在分组重定义动画是直接写在 transform 属性当中的。实际上,每个子标签都可以使用 transform 的相关属性。

 <g transform="translate(...) scale(...) rotate(...) translate(...) rotate(...)">
  ...
</g>

每种变换动画之间是通过 空格逗号 连接的。它的执行顺序是从右到左。为啥呢?实际上可以理解为,这就是几个嵌套的 g 叠在一起。

 <g transform="translate(...) scale(...) rotate(...) translate(...) rotate(...)">
    ...
  </g>

  // Being Equivalent to this:
  <g transform="translate(...)">
   <g transform="scale(...)">
     <g transform="rotate(...)">
       <g transform="translate(...)">
         <g transform="rotate(...)">
           ...
         </g>
       </g>
     </g>
   </g>
 </g>

具体可以使用的动画形式和 CSS 动画一模一样,详情可以参考: SVG 动画

原文链接:http://www.ivweb.io/topic/58f4ada3576f6720749cb376

原创声明,本文系作者授权云+社区-专栏发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

编辑于

我来说两句

5 条评论
登录 后参与评论

相关文章

来自专栏WOLFRAM

罗马曲面的旋转

1217
来自专栏移动开发面面观

Handler源码分析

1025
来自专栏一个会写诗的程序员的博客

java.base.jmod

/Library/Java/JavaVirtualMachines/jdk-9.jdk/Contents/Home/jmods$ jmod list java....

812
来自专栏CSDN技术头条

大数据与Hadoop最有影响力150人(英)

There are more than 284 million activeusers on twitter. This makes following t...

2677
来自专栏搞前端的李蚊子

Html5模拟通讯录人员排序(sen.js)

// JavaScript Document  var PY_Json_Str = ""; var PY_Str_1 = ""; var PY_Str_...

4606
来自专栏运维前线

CentOS 6.X 安装中文字体

由于业务需要,需要对CentOS6.9添加中文字体支持 安装工具包 yum install -y fontconfig mkfontscale 安装完成后...

2106
来自专栏前端架构

程序猿的字体选择

gitHub地址:https://github.com/adobe-fonts/source-code-pro

902
来自专栏闵开慧

eclipse中运行hbase时显示Connection refused: no furthe...

java.net.ConnectException: Connection refused: no further information at ...

4097
来自专栏腾讯数据中心

敬请收藏:数据中心常用标识的中英文对照

中国的数据中心在不断走向国际化,同时数据中心内的关键标识也逐渐采取了中英文双语标识。 今天,我们整理出腾讯数据中心内部使用的中英文标识对照。敬请收藏以备后续参考...

3164
来自专栏数据小魔方

动态地理信息可视化——leaflet构造路径图

根据先前几篇内容的框架,今天介绍leaflet在线地图的第三篇,以线条元素构造的路径图。 library(leaflet) library(dplyr) ...

2665

扫码关注云+社区