Paths
撰写时间:2025-04-20
修订时间:2024-04-28
path只有一个d属性,其值中又含有各个非常灵活的命令,可绘制出丰富多彩的图形。
绘制直线
M意为move
,用以移动当前光标位置。L命令意为line to
,指定一个点的位置后,将在当前光标位置与该点绘制一条直线。Z命令用以闭合图形。
因为可能需要多次调用L命令,因此多条连续的L命令可合并为1条L命令,其后跟着一系列的点的坐标。
上面,原来的L 100 400 L 600 400
合并为L 100 400, 600 400
。
多数命令,如上面的M命令与L命令,有大小写之分,大写的命令使用绝对坐标值,小写的命令使用相对坐标值。
使用小写命令l,用以指定偏移值,可清楚地看到,三角形的高为300px,底边为500px。
L命令后面的数据必须至少两个以上的分别代表(x, y)坐标轴的数值,不够简练。我们可以使用H或h命令来绘制水平直线,使用V或v命令来绘制垂直直线。这两个命令,因为已经明确了方向,因此只需跟有一个数值就行了。
可见,使用小写的h或v命令,可让我们十分便捷地完成绘图任务。它具有以下优点:
- 直观
- 便于添加众多顶点
- 方便修改
绘制圆弧
由于需要以声明式的方式来绘制一个相对较为复杂的圆弧,SVG中绘制圆弧的算法比较独特。
上图中,我们需要从点Arc start
绘制一条圆弧至点Arc end
。
可以看出,这两个点为两个形状相同的椭圆的交点,或者说,这两个点来自两个椭圆。而若给定椭圆的长半径与短半径,从点Arc start
绘制一条圆弧至点Arc end
,共有4种绘制方法,根据这4种方法所绘制出来的圆弧在图中均已用红色标出。
4种结果依赖于需要绘制长圆弧还是短圆弧,以及是按逆时针还是按顺时针的方向来绘制。
假设我们需要绘制短圆弧。则图中第1行的第2列及第3列均为符合条件的短圆弧。第2列为按逆时针方向所绘制的短圆弧,它取自右上角这个椭圆的一小段圆弧。第3列为按顺时针方向所绘制的短圆弧,它取自左下角这个椭圆的一小段圆弧。
在这里,由于起点与终点已经确定下来,而从起点按逆时针方向绘制圆弧至终点,以及从起点按顺时针方向绘制圆弧至终点,将导致绘制出完全不同的两条圆弧。
现在,假设我们需要绘制长圆弧。则图中第2行的第2列及第3列均为符合条件的长圆弧。第2列为按逆时针方向所绘制的长圆弧,它取自左下角这个椭圆的一大段圆弧。第3列为按顺时针方向所绘制的长圆弧,它取自右上角这个椭圆的一大段圆弧。
换句话说,给定圆弧的起点与终点、长半径与短半径,这段圆弧可来自两个椭圆的相应部位。随着我们再接着确定长短圆弧及绘制方向的具体需求,这段圆弧也就随之确定下来。
我们注意到,尽管圆弧来自两个椭圆,但我们无需理会这两个椭圆如何绘制、它们的圆心各在哪里,以及所绘制的圆弧如何取自哪一个椭圆的哪一部位。所有这些,SVG的内部算法会自动帮我们确定。
可见,确定了圆弧的起点与终点,长半径与短半径,长弧或短弧,顺时针还是逆时针这几种关键因素后,这条圆弧也随之确定下来了。这就是SVG中使用A命令或a命令绘制圆弧的参数的由来,其原型如下:
- floatrx, ry
- numberx-axis-rotation
- booleanlarge-arc-flag
- booleansweep-flag
- floatx, y
A或a命令从当前点的位置,绘制一条长短半径分别为rx及ry的圆弧至(x, y)。参数large-arc-flag指定是否需要绘制长圆弧,参数sweep-flag指定是按顺时针还是按逆时针的方向来绘制,这两个参数默认值为0,表示默认按逆时针方向绘制短弧。
参数x-axis-rotation是椭圆的旋转值,以角度为单位。
下面是绘制圆弧的代码:
上面的代码,先从画布的中心(450, 300)绘制一条直线到(600, 300),则当前位置位于(600, 300)。A命令从该位置绘制了一条圆弧至(450, 150),圆弧的长短半径各为200及150。图中起点为红色,终点为绿色。
分别将代码中的large-arc-flag参数及sweep-flag参数的值改为1,尝试不同的组合,即可看到不同的效果。检查运行结果是否与上面图片中的效果一致。
绘制曲线
发明了Bézier曲线绘制方法的科学家真是太给力了。对于任意的一条线段,仅额外加入2个、甚至仅加入1个控制点,直线立即转变为千变万化的、姿态曼妙的弧线。计算机绘图从未如此轻松、如此优雅。
Cubic Bézier曲线
C, c命令
C命令是一个三阶的贝塞尔曲线,使用两个端点及两个控制点来绘制曲线。
图像虽然绘制出来了,但很难看出4个端点与所生成图像的内在关系。下面通过拖动节点的方式来交互式地生成图像。
拖动4个节点,曲线随之而变化,下面的文本则输出其d属性值。
代码使用了MVC模式,dataWrapper为数据模型,修改该模型的值,可改变曲线的初始状态。
可以看出,由于SVG内置支持其各个元素的事件响应,因此在SVG中编写drag and drop
事件的代码非常轻松。
利用这个小工具,拖出我们想要的曲线后,复制其d属性值,再粘帖进其他的SVG代码,可方便地进行后续编辑。
这个功能可是PhotoShop, C4D等大腕软件的镇店之宝,而我们却仅用不到百行的代码就轻松地实现了此超酷的功能。
S, s命令
S命令属于一个连续绘制Cubic Bézier曲线的命令,在调用它之前,通常已有一个绘制Cubic Bézier曲线的命令。
上面代码,有两个绘制Cubic Bézier曲线的命令,第一个是C命令,第二个是S命令。
S命令的参数较简单,只有一个终止端点的控制节点(303, 216),以及一个终止端点(312, 120)。
实际上,S命令照样使用两个端点及两个控制点,但起始端点取自于当前点(204, 119)(也即S命令之前的C命令中的终止端点),起始端点的控制节点取自于上条曲线的第二个控制节点(260, 47)相对于当前点(204, 119)的镜像。
理解起来很费劲,但在交互式的图形应用中,这些概念立即变得清晰起来。
橙色的点,既是第一条C命令的终止端点,也成为第二条S命令的起始端点。
而黑色虚框的圆点,是S命令的起始端点的控制节点,它是C命令的终止控制节点(蓝色)相对于C命令终止端点(橙色)的镜像。由于它是SVG引擎自动求出的,因此在交互界面中不能拖动。相反,拖动蓝色控制节点,则可看到黑色控制节点的即时反应。
没有平滑曲线时的区别
可以看出,当第2个节点不使用S命令,而使用C命令时,则可以独立地控制2个控制点;移动其中一个控制点,另一条曲线不受任何影响。
两个控制点与黄色端点分别组成了两条直线。当这两条直线的夹角为180°时,曲线的弧度过渡得最为平滑。因此使用S命令所绘制出来的曲线,也称为平滑曲线(smooth curve)。
Quadratic Bézier曲线
Q命令
Q命令是一个二阶的贝塞尔曲线,使用两个端点及一个控制点来绘制曲线。
交互。
T命令
交互。
Path DOM
本节部分的APIs只适用于Safari,Chrome目前尚未支持。
Canvas的Path2D不能直接操控子路径。而SVG的SVGPathElement则提供了直接操控子路径的方法。
path的类为SVGPathElement,有以下添加各种子路径的方法:
类别 | 方法名称 | d属性中的命令 | 作用 |
---|---|---|---|
指定当前位置 | createSVGPathSegMovetoAbs | M | 使用绝对值,将指定位置设置为当前位置 |
createSVGPathSegMovetoRel | m | 使用相对值,将指定位置设置为当前位置 | |
绘制直线 | createSVGPathSegLinetoAbs | L | 使用绝对值,从当前位置绘制一条直线至指定位置 |
createSVGPathSegLinetoRel | l | 使用相对值,从当前位置绘制一条直线至指定位置 | |
createSVGPathSegLinetoHorizontalAbs | H | 使用绝对值,从当前位置绘制一条水平直线至指定位置 | |
createSVGPathSegLinetoHorizontalRel | h | 使用相对值,从当前位置绘制一条水平直线至指定位置 | |
createSVGPathSegLinetoVerticalAbs | V | 使用绝对值,从当前位置绘制一条竖直的直线至指定位置 | |
createSVGPathSegLinetoVerticalRel | v | 使用相对值,从当前位置绘制一条竖直的直线至指定位置 | |
绘制圆弧 | createSVGPathSegArcAbs | A | 使用绝对值,从当前位置绘制一条圆弧至指定位置 |
createSVGPathSegArcRel | a | 使用相对值,从当前位置绘制一条圆弧至指定位置 | |
绘制Cubic Bézier曲线 | createSVGPathSegCurvetoCubicAbs | C | 使用绝对值,从当前位置绘制一条Cubic Bézier曲线至指定位置 |
createSVGPathSegCurvetoCubicRel | c | 使用相对值,从当前位置绘制一条Cubic Bézier曲线至指定位置 | |
createSVGPathSegCurvetoCubicSmoothAbs | S | 使用绝对值,从当前位置绘制一条平滑的Cubic Bézier曲线至指定位置 | |
createSVGPathSegCurvetoCubicSmoothRel | s | 使用相对值,从当前位置绘制一条平滑的Cubic Bézier曲线至指定位置 | |
绘制Quad Bézier曲线 | createSVGPathSegCurvetoQuadraticAbs | Q | 使用绝对值,从当前位置绘制一条Quad Bézier曲线至指定位置 |
createSVGPathSegCurvetoQuadraticRel | q | 使用相对值,从当前位置绘制一条Quad Bézier曲线至指定位置 | |
createSVGPathSegCurvetoQuadraticSmoothAbs | T | 使用绝对值,从当前位置绘制一条平滑的Quad Bézier曲线至指定位置 | |
createSVGPathSegCurvetoQuadraticSmoothRel | t | 使用相对值,从当前位置绘制一条平滑的Quad Bézier曲线至指定位置 | |
关闭路径 | createSVGPathSegClosePath | z, Z | 关闭路径 |
下面使用上述方法来构建一个正方形,然后,通过SVGPathElement的pathSegList来检视每个子路径。
了解这些APIs的细节后,我们就可以通过代码来创建可动态交互的路径了。