svg中path贝塞尔曲线和圆弧图文详解

晴空闲云
• 阅读 958

最近研究了一下svg的path标签,功能非常强大,理论上来讲path标签可以画出任意图形。自己记性不太好,记录一下path的使用语法和自己的理解。

path介绍

path用d属性来描述路径,语法格式大概如下:

<svg>
    <path d="路径描述" />
</svg>

其中路径描述包含如下命令:

M = moveto 移动到某点。
L = lineto 画一条直线到某点。
H = horizontal lineto 画一条水平线到某点。
V = vertical lineto 画一条垂直线到某点。
Q = quadratic Bézier curveto 二次贝塞尔曲线
T = smooth quadratic Bézier curveto 平滑二次贝塞尔曲线
C = curveto 三次贝塞尔曲线
S = smooth curveto 平滑三次贝塞尔曲线
A = elliptical Arc 弧形
Z = closepath 从结束点到开始点画一条直线,形成一个闭合的区域。

以上所有命令均允许小写字母:

1. 大写表示绝对定位,绝对的参照点是svg最上角的那一点。
2. 小写表示相对定位,相对的参照点是上一个位置。

每个命令都有自己相关的参数,参考下面介绍。

M(moveto)移动和L(lineto)画直线

其中 M 表示移动到某点,L 表示画一条直接到某点,后面跟一个坐标点,格式如下:

d="M x y" // M是命令:x横轴坐标、y纵轴坐标
d="L x y" // L是命令:x横轴坐标、y纵轴坐标

网上很多文章有各种各样的格式,如:

Mx y
M x y    // 建议是用这种比较容易看,多个坐标用英文逗号,分隔
Mx,y
M x,y 

简单示例:

<svg width="200" height="150" style="border:1px solid steelblue;">
    <path d="
        M 20 30         // 移动到 (20 30) 这个点
        L 180 120     // 画一条直线到 (180 120) 这个点
    " stroke="pink" fill="none"></path>
</svg>

运行效果:

svg中path贝塞尔曲线和圆弧图文详解

H(horizontal lineto)水平线和V(vertical lineto)垂直线

其中H用于画水平线,y值和上一个点保持不变,所以给x值就可以了,格式如下:

d="H x" // H是命令:x横轴坐标

其中V用于画垂直线,x值和上一个点保持不变,所以给y值就可以了,格式如下:

d="V y" // V是命令:y纵轴坐标

简单示例:

<svg width="200" height="150" style="border:1px solid steelblue;">
    <path d="
        M 10 10        // 移动到 (10 10)这个点
        H 190            // 画水平线到 (190 10) 这个点
        V 140            // 画垂直线到 (190 140) 这个点
    " stroke="cadetblue" fill="pink"></path>
</svg>

运行效果:

svg中path贝塞尔曲线和圆弧图文详解

Z(cloasPath)闭合

结束点到开始点画一条直线,形成一个闭合的区域。前面的命令都和英文单词相关,这个命名和单词无关,估计是C命令给占用了。

语法格式就是在d属性最后写一个Z,表示闭合。

d="... Z"

接上面的例子,画一个闭合线,然后改一下轮廓颜色和填充色:

<svg width="200" height="150" style="border:1px solid steelblue;">
    <path d="
        M 10 10        // 移动到 (10 10) 这个点
        H 190            // 画水平线到 (190 10) 这个点
        V 140            // 画垂直线到 (190 140) 这个点
        Z                    // 闭合
    " stroke="cadetblue" fill="pink"></path>
</svg>

运行效果:

svg中path贝塞尔曲线和圆弧图文详解

Q(quadratic Bézier curveto)二次贝赛尔曲线

Q表示二次贝塞尔曲线的命令,需要设置一个控制点和一个终点,语法格式如下:

d="Q x1 y1, x y" // 控制点 (x1,y1),终点 (x,y)

简单示例:

<svg width="200" height="150" style="border:1px solid steelblue;">
    <path d="
        M 10 10                      // 移动到 (10 10) 这个点
        Q 100 70, 190 10        // 控制点 (100 70),终点 (190 10)
    " stroke="pink" fill="none"></path>

    <!-- 辅助查看的线(斜率) -->
    <path d="
        M 10 10
        L 100 70
        L 190 10
    " stroke="#888" stroke-dasharray="5" fill="none"></path>
</svg>

运行效果:

svg中path贝塞尔曲线和圆弧图文详解

图中黑色线就是实际画的贝塞尔曲线,虚线是斜率。

T(smooth quadratic Bézier curveto) 二次贝塞尔曲线

T命令只需要设置一个终点,它的控制点是通过前一个Q命令或者是T命令计算出来。

d="Q命令 T x y"     // 终点 (x y),控制点通过前面的Q命令计算得出

简单示例:

<svg width="200" height="150" style="border:1px solid steelblue;">
    <path d="
        M 10 75                    // 移动到 (10 75) 这个点
        Q 55 10 100 75    // 控制点 (55 10),终点 (100 75)
        T 190 75                // 终点 (190 75),控制器是通过前面Q命令计算出来的
    " stroke="black" fill="none"></path>

    <!-- Q命令辅助查看线(斜率) -->
    <path d="
        M 10 75
        L 55 10
        L 100 75
    " stroke="blue" stroke-dasharray="5" fill="none"></path>
    <!-- T命令辅助查看线(斜率) -->
    <path d="
        M 100 75
        L 145 140
        L 190 75
    " stroke="pink" stroke-dasharray="5" fill="none"></path>
</svg>

运行效果:

svg中path贝塞尔曲线和圆弧图文详解

其中:

黑色色是实际画出的贝塞尔曲线。
蓝色虚线是Q命令的斜率。
粉色虚线是T命令的斜率,其中控制点是电脑计算的。

C(curveto)三次贝塞尔曲线

三次贝塞尔曲线和二次贝塞尔曲线相比就是多一个控制点,MDN画的一个图很好的表达了这个意思:

svg中path贝塞尔曲线和圆弧图文详解

通过两个控制点,可以画出任意的曲线。语法格式:

d="C x1 y1, x2 y2, x y" // 控制点1 (x1,y1),控制点2 (x2,y2),终点 (x,y)

简单示例:

<svg width="200" height="150" style="border:1px solid steelblue;">
    <path d="
        M 10 10                                 // 移动到(10 10) 这个点
        C 20 130, 160 130, 170 20        // 控制点1(20 130),控制点2(160 130),终点(170 20)
    " stroke="black" fill="none"></path>

    <!-- C命令辅助查看的线(斜率) -->
    <path d="
        M 10 10 
        L 20 130
        M 160 130
        L 170 20
    " stroke="blue" fill="none" stroke-dasharray="5"></path>
</svg>

运行效果:

svg中path贝塞尔曲线和圆弧图文详解

S(smooth curveto) 平滑三次贝塞尔曲线

这个东西和T命令类似,T是Q的简写方式,S是C的简写方式,为了方便对比,我们把C和S的命令格式放在一起。

d="C x1,y1 x2,y2 x,y" // 控制点1 (x1,y1),控制点2 (x2,y2),终点 (x,y)
d="S x2,y2 x,y"             // S只要控制点2就可以了

简单示例,为了方便查看,我们同样画出辅助线:

<svg width="200" height="150" style="border:1px solid steelblue;">
    <path d="
        M 10 75 
        C 30 10, 80 10, 100 75        // 控制点1(30 10),控制点2(80 10),终点(100 75)
        S 170 140, 190 75                    // 控制点2(190 75),终点(190 75)
    " stroke="black" fill="none"></path>

    <!-- C命令辅助查看的线(斜率) -->
    <path d="
        M 10 75
        L 30 10
        M 80 10
        L 100 75
    " stroke="blue" fill="none" stroke-dasharray="5"></path>
    <!-- S命令辅助查看的线(斜率) -->
    <path d="
        M 100 75
        L 120 140
        M 170 140
        L 190 75
    " stroke="pink" fill="none" stroke-dasharray="5"></path>
</svg>

运行效果:

svg中path贝塞尔曲线和圆弧图文详解

其中:

粉丝的虚线就是S的辅助线。
120 140这个点就是电脑计算出来的。

A(elliptical Arc)弧形

A命令也可以用来画弧形,可以理解是圆或者椭圆的一部分。

语法格式如下:

d="A rx ry x-axis-rotation large-arc-flag sweep-flag x y" 

其中:

rx ry 分别是是椭圆的x轴半径和y轴半径。
x-axis-rotation 是椭圆相对于坐标系的旋转角度。
large-arc-flag 是标记绘制大弧(1)还是小弧(0)部分。
sweep-flag 是标记向顺时针(1)还是逆时针(0)方向绘制。
x y 是圆弧终点的坐标。

rx和rx容易理解,最后的重点x和y也容易理解,关键就是中间三个参数:x-axis-rotation、large-arc-flag、sweep-flag 比较难以理解。

large-arc-flag 和 sweep-flag 参数

这边先突破一下 large-arc-flag、sweep-flag 两个参数,每个参数都有两个值,那么组合来看就是4种情况,下面挨个情况看看。

1)large-arc-flag=0(小弧),sweep-flag=0(逆时针)。

我们先看其中都为0的情况:

<svg width="200" height="150" style="border:1px solid steelblue;">
    <!-- 黑色圆弧  -->
    <path d="
        M 120 45 
        A 60 45 0 0 0 80 125  // large-arc-flag=0(小弧),sweep-flag=0(逆时针)
    " stroke="black" fill="none"></path> 
</svg>

运行效果:

svg中path贝塞尔曲线和圆弧图文详解

这边还不容易看出其中意思,为什么是画出这样的线呢?规律到底是什么呢?我们再看下都是1的情况。

2)large-arc-flag=1(大弧),sweep-flag=1(顺时针)。

增加一条弧线,和上例的的弧线一致,就是调整一下这两个参数:

large-arc-flag=1(大弧),sweep-flag=1(顺时针)

然后把颜色设置为蓝色:

<!-- 蓝色圆弧  -->
<path d="
    M 120 45 
    A 60 45 0 1 1 80 125 // large-arc-flag=1(大弧),sweep-flag=1(顺时针)
" stroke="blue" stroke-dasharray="2" fill="none"></path>

运行效果:

svg中path贝塞尔曲线和圆弧图文详解

这下就有点清楚了,就是一个椭圆上的两个点可以顺时针画大弧,也可以逆时针画小弧,两个弧组合成一个椭圆了。

那另外两组参数是什么意思呢?再一起来看看。

3)large-arc-flag=0(小弧),sweep-flag=1(顺时针)。

再增加一条弧线,和上例的的弧线一致,就是调整一下这两个参数:

large-arc-flag=0(小弧),sweep-flag=1(顺时针)

然后把颜色设置为粉色:

<!-- 粉色圆弧  -->
<path d="
    M 120 45 
    A 60 45 0 0 1 80 125 // large-arc-flag=0(小弧),sweep-flag=1(顺时针)
" stroke="pink" stroke-dasharray="4" fill="none"></path> 

运行效果:

svg中path贝塞尔曲线和圆弧图文详解

到这边就更加清晰了,粉色圆弧实际和黑色圆弧对称。

剩下最后估计就能猜到了,补上最后一个。

4)large-arc-flag=1(大弧),sweep-flag=0(逆时针)。

再增加一条弧线,和上例的的弧线一致,就是调整一下这两个参数:

large-arc-flag=1(大弧),sweep-flag=0(逆时针)

然后把颜色设置为深粉色:

<!-- 深粉色圆弧  -->
<path d="
    M 120 45 
    A 60 45 0 1 0 80 125 // large-arc-flag=1(大弧),sweep-flag=0(逆时针)
" stroke="deeppink" stroke-dasharray="6" fill="none"></path>

运行效果:

svg中path贝塞尔曲线和圆弧图文详解

这边两个参数就介绍完了。

x-axis-rotation

这个参数就是用来旋转用的,可以为正和负数:

整数表示顺时间旋转。
负数表示逆时针旋转。

我们把上面的例子做一下旋转,顺时针旋转30度:

<svg width="200" height="150" style="border:1px solid steelblue;">
    <!-- 黑色圆弧  -->
    <path d="
        M 120 45 
        A 60 45 30 0 0 80 125 
    " stroke="black" fill="none"></path>

    <!-- 蓝色圆弧  -->
    <path d="
        M 120 45 
        A 60 45 30 1 1 80 125
    " stroke="blue" stroke-dasharray="2" fill="none"></path>

    <!-- 粉色圆弧 -->
    <path d="
        M 120 45 
        A 60 45 30 0 1 80 125
    " stroke="pink" stroke-dasharray="4" fill="none"></path>

    <!-- 深粉色圆弧  -->
    <path d="
        M 120 45 
        A 60 45 30 1 0 80 125
    " stroke="deeppink" stroke-dasharray="6" fill="none"></path>
</svg>

运行效果:

svg中path贝塞尔曲线和圆弧图文详解

逆时针也是一样的道理,就是不再演示了。

相对位置

前面演示的例子,都是绝对位置,相对位置也很简单,写个例子看看就明白了。我们用最开始画线的例子,然后改成相对定位。

<!-- 绝对定位 -->
<svg width="200" height="150" style="border:1px solid steelblue;">
    <path d="
        M 20 30 
        L 180 120
    " stroke="pink" fill="none"></path>
</svg>

这边的L是绝对位置 180 120,是相对于svg左上角的坐标0 0,那么相对的写法就是:

L点坐标(180 120) - M点坐标(20 30)
= 相对位置(160 90)

再颜色修改成深粉色,方便看出效果,最后给出代码:

<!-- 相对定位 -->
<svg width="200" height="150" style="border:1px solid steelblue;">
    <path d="
        M 20 30
        l 160 90 // 相对定位
    " stroke="deeppink"></path>
</svg>

运行效果:

svg中path贝塞尔曲线和圆弧图文详解

其它命令的原理都是类似的,就不再赘述了。

至此path相关的命令就介绍完毕了,欢迎大家一起学习交流。

参考资料

MDN svn路径:https://developer.mozilla.org/zh-CN/docs/Web/SVG/Tutorial/Paths

点赞
收藏
评论区
推荐文章
blmius blmius
2年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Stella981 Stella981
2年前
Qt加载SVG图片以及改变SVG图片颜色
1Qt加载SVG图片QTreeWidgetItemitemnewQTreeWidgetItem;//svg_path为SVG图片路径QSvgRenderersvg_rendernewQSvgRenderer(svg_path);QPixmappixmapnewQPixmap(32
Stella981 Stella981
2年前
AndroidStudio封装SDK的那些事
<divclass"markdown\_views"<!flowchart箭头图标勿删<svgxmlns"http://www.w3.org/2000/svg"style"display:none;"<pathstrokelinecap"round"d"M5,00,2.55,5z"id"raphael
Stella981 Stella981
2年前
SVG跟随父级DIV自适应
后台返回过来的是这样的SVG标签<svgwidth"100%"height"100%"version"1.1"xmlns"http://www.w3.org/2000/svg"<gtransform"translate(00)"
Easter79 Easter79
2年前
SVG跟随父级DIV自适应
后台返回过来的是这样的SVG标签<svgwidth"100%"height"100%"version"1.1"xmlns"http://www.w3.org/2000/svg"<gtransform"translate(00)"
Stella981 Stella981
2年前
HIVE 时间操作函数
日期函数UNIX时间戳转日期函数: from\_unixtime语法:   from\_unixtime(bigint unixtime\, string format\)返回值: string说明: 转化UNIX时间戳(从19700101 00:00:00 UTC到指定时间的秒数)到当前时区的时间格式举例:hive   selec
Stella981 Stella981
2年前
Flutter 之贝塞尔曲线(一)
贝塞尔曲线简介!(https://oscimg.oschina.net/oscnet/863784996212c918a1feef7a916bce28f31.png"bezier1.png")bezier1.png由上图可以看出:A,C依据控制点B不断的取点使得AD:ABBE:BCDF:DE,构成一个二阶贝塞尔曲线。AD:
Wesley13 Wesley13
2年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Wesley13 Wesley13
2年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
2个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这
晴空闲云
晴空闲云
Lv1
男 · 教师
专注前端,把复杂的编程讲简单,又不失深度。@公众号:晴空闲云
文章
26
粉丝
7
获赞
35