SVG 之椭圆弧
绘制直线段相对简单,因为路径上的两个点就唯一确定了它们之间的线段。但如果是曲线的话,由于在两个点之间可以绘制无限条曲线,因此我们必须给出额外信息,以便在它们之间绘制一条曲线路径。这里要研究的最简单的曲线为椭圆弧,也就是绘制一个连接两个点的椭圆的一部分。
尽管弧是视觉上最简单的曲线,但是指定一条唯一的曲线所需要的信息却是最多的。需要指定的第一部分信息是点所在椭圆的 x 半径和 y 半径。椭圆的范围可以缩小为两个,正如在图中(a)部分可以看到的。两个点将两个椭圆划分为 4 个圆弧。其中(b)和(c)是小于 180 度的弧,(d)和(e)都大于 180 度。看看(b)和(c),你会发现它们的方向不同,(b)是按照负角度增加(逆时针)方向绘制的,(c)是按照正角度增加(顺时针)方向绘制的。同样的关系在(d)和(e)之间也成立。
这还并没有唯一确定潜在的弧!因为并没有规定说椭圆的 x 半径必须平行于 x 轴。图中的(f)部分展示了两个点和它们所在的相对于 x 轴旋转了 30 度的椭圆。(上图改编自 W3C SVG 规范的 8.3.8 小节。)
圆弧命令以字母 A(绝对坐标的缩写)或者 a(相对坐标的缩写)开始,后面紧跟以下 7 个参数。
- 点所在椭圆的 x 半径和 y 半径。
- 椭圆的 x 轴旋转角度
x-axis-rotation。 large-arc-flag,如果需要圆弧的角度小于 180 度,其为 0;如果需要圆弧的角度大于或等于 180 度,则为 1。sweep-flag,如果需要弧以负角度绘制则为 0,以正角度绘制则为 1。- 终点的 x 坐标和 y 坐标(起点由最后一个绘制的点或者最后一个
moveto命令确定)。
下面的路径绘制了图上中(b)到(e)部分的椭圆弧:
<path d="M 125,75 A100,50 0 0,0 225,125"/> <!-- b -->
<path d="M 125,75 A100,50 0 0,1 225,125"/> <!-- c -->
<path d="M 125,75 A100,50 0 1,0 225,125"/> <!-- d -->
<path d="M 125,75 A100,50 0 1,1 225,125"/> <!-- e -->
在下面的互动示例中,你可以尝试所有圆弧参数来看看它们的作用:
我们不能使用一个路径命令绘制一个完整的椭圆;如果弧形的起点和终点相同,则有无数种方式定位椭圆。SVG 阅读器会跳过这样的圆弧命令。如果你指定的椭圆半径太小,导致不能覆盖起点和终点,则 SVG 阅读器会扩大椭圆直到它足够覆盖起点和终点。
绘制要一个独立的半椭圆弧的代码如下:
<svg width="600" height="600" viewBox="0 0 600 600" style="border: 1px solid #ccc;">
<!-- 左上角 - 上半圆 -->
<path d="M 50 150 A 100 100 0 1 1 250 150" stroke="#ffff00" stroke-width="4" fill="none" />
<!-- 右上角 - 右半圆 -->
<path d="M 450 50 A 100 100 0 1 1 450 250" stroke="#ff0000" stroke-width="4" fill="none" />
<!-- 右下角 - 下半圆 -->
<path d="M 350 450 A 100 100 0 1 0 550 450" stroke="#00ff00" stroke-width="4" fill="none" />
<!-- 左下角 - 左半圆 -->
<path d="M 150 350 A 100 100 0 1 0 150 550" stroke="#0000ff" stroke-width="4" fill="none" />
</svg>
A 标签也可以也可以连续设置,下面太极图中的右侧黑色部分就是如此绘制出来的。代码如下:
<svg width="400" height="400" viewBox="0 0 400 400" xmlns="http://www.w3.org/2000/svg"
style="border: 1px solid #ccc; margin: auto; display: block">
<!-- 从200,50出发的黑色填充图形 -->
<path d="M 200 50 A 150 150 0 0 1 200 350 A 75 75 0 0 1 200 200 A 75 75 0 0 0 200 50"
style="fill: #000000;" />
<!-- 正中心无色,黑色边框,半径150的圆 -->
<circle cx="200" cy="200" r="150" fill="none" stroke="#000000" stroke-width="4" />
<!-- 200,87.5处黑色圆,半径20 -->
<circle cx="200" cy="125.5" r="20" fill="#000000" />
<!-- 200,312.5处白色圆,半径20 -->
<circle cx="200" cy="274.5" r="20" fill="#ffffff" />
</svg>
从其他弧线格式转换
你可能疑惑,为什么 SVG 选择一种看似古怪的方法来指定弧形,为什么不能像其他矢量图形系统那样,通过给椭圆定义一个中心点、x 和 y 半径、起始角度和弧形角度来指定一个弧形。这是因为在 SVG 中,弧形并不能单独存在,它要成为线和曲线连接路径的一部分(比如,一个圆角矩形就是由一系列线和椭圆弧组成的)。因此,通过终点指定弧形是合理的。
若想要绘制一个指定中心和角度的任意弧,并将它转换为 SVG 的终点和范围格式,可以用下面的 JavaScript 代码实现,用于将中心和角度格式的圆弧转换为适当的形式,放到 SVG <path> 中。在上面的互动程序中,右侧的选项卡“变换的圆弧参数”演示的就是这个功能。
/*
将一个围绕中心的椭圆弧转换为适用于SVG的参数化的椭圆弧
参数:
中心x坐标
中心y坐标
椭圆x半径
椭圆y半径
圆弧开始角度
圆弧所跨度数
x轴旋转角度
返回一个数组,包含:
弧起点的x坐标
弧起点的y坐标
椭圆x半径
椭圆y半径
x轴旋转角度
SVG规范中定义的大弧形标志
SVG规范中定义的范围标志
弧末端的x坐标
弧末端的y坐标
*/
function centeredToSVG(cx,cy,rx,ry,theta,delta,phi)
{
var endTheta, phiRad;
var x0, y0, x1, y1, largeArc, sweep;
/* 将角度转换为弧度。需要一个单独的变量把phi变为弧度,因为必须保持phi为度数形式用于返回值 */
theta = theta * Math.PI / 180.0;
endTheta = (theta + delta) * Math.PI / 180.0;
phiRad = phi * Math.PI / 180.0;
/*
找出起点和终点的坐标
*/
x0 = cx + Math.cos(phiRad) * rx * Math.cos(theta) +
Math.sin(-phiRad) * ry * Math.sin(theta);
y0 = cy + Math.sin(phiRad) * rx * Math.cos(theta) +
Math.cos(phiRad) * ry * Math.sin(theta);
x1 = cx + Math.cos(phiRad) * rx * Math.cos(endTheta) +
Math.sin(-phiRad) * ry * Math.sin(endTheta);
y2 = cy + Math.sin(phiRad) * rx * Math.cos(endTheta) +
Math.cos(phiRad) * ry * Math.sin(endTheta);
largeArc = (delta > 180) ? 1 : 0;
sweep = (delta > 0) ? 1 : 0;
return [x0, y0, rx, ry, phi, largeArc, sweep, x1, y1];
}
发布时间:2026/1/22 下午10:23:26 阅读次数:102
