
SVG 的 S 路径命令绘制的是三次贝塞尔曲线,而非二次;其首控制点需通过对称方式自动推导,直接套用二次公式会导致路径严重偏移。本文详解 S 命令的控制点解析逻辑与对应数学公式,并提供可验证的 Canvas 实现。
svg 的 `s` 路径命令绘制的是**三次贝塞尔曲线**,而非二次;其首控制点需通过对称方式自动推导,直接套用二次公式会导致路径严重偏移。本文详解 `s` 命令的控制点解析逻辑与对应数学公式,并提供可验证的 canvas 实现。
在 SVG 路径语法中,S x2 y2, x y(即“平滑三次贝塞尔曲线”)是一个相对对称的三次贝塞尔命令,它需要四个控制点:起点 $P_0$、首控制点 $P_1$、次控制点 $P_2$、终点 $P_3$。关键在于:S 不显式指定 $P_1$,而是根据前一条曲线(或起始点)的出向控制点,以 $P_0$ 为对称中心进行镜像反射得到。
以路径 M 0,100 S 27,2, 200,0 为例:
-
M 0,100设定起点 $P_0 = (0, 100)$; - 因为这是第一条曲线(此前无控制点),SVG 规范规定:$P_1$ 取为 $P_0$ 自身,即 $(0, 100)$;
-
S 27,2, 200,0中的27,2是 $P_2$(次控制点),200,0是 $P_3$(终点)。
因此,四点坐标为:
$$
P_0 = (0, 100),\quad
P_1 = (0, 100),\quad
P_2 = (27, 2),\quad
P_3 = (200, 0)
$$
对应的三次贝塞尔参数方程为($t \in [0,1]$):
$$ \begin{aligned} x(t) &= (1-t)^3 x_0 + 3(1-t)^2 t x_1 + 3(1-t) t^2 x_2 + t^3 x_3 \ y(t) &= (1-t)^3 y_0 + 3(1-t)^2 t y_1 + 3(1-t) t^2 y_2 + t^3 y_3 \end{aligned} $$
⚠️ 常见错误:误将 S 当作二次贝塞尔(仅用三点),套用公式 $(1-t)^2 P_0 + 2(1-t)t P_1 + t^2 P_2$,这会完全丢失 $P_1$ 的对称逻辑,导致红色轨迹与蓝色 SVG 路径明显分离。
✅ 正确实现(Canvas 示例):
const c = document.getElementById('c');
const ctx = c.getContext('2d');
// SVG 渲染(基准蓝线)
ctx.strokeStyle = 'blue';
ctx.stroke(new Path2D('M 0,100 S 27,2 200,0'));
// 数学公式渲染(红线,使用三次贝塞尔)
ctx.strokeStyle = 'red';
ctx.beginPath();
ctx.moveTo(0, 100);
for (let t = 0; t <= 1; t += 0.0001) {
const x = Math.pow(1 - t, 3) * 0
+ 3 * Math.pow(1 - t, 2) * t * 0
+ 3 * (1 - t) * t * t * 27
+ t * t * t * 200;
const y = Math.pow(1 - t, 3) * 100
+ 3 * Math.pow(1 - t, 2) * t * 100
+ 3 * (1 - t) * t * t * 2
+ t * t * t * 0;
ctx.lineTo(x, y);
}
ctx.stroke();? 补充说明:
- 若
S前存在其他三次贝塞尔(如C或S),则 $P_1$ 会基于前一个 $P_2$ 关于 $P_0$ 对称计算:$P_1 = 2P_0 - P_2^{\text{prev}}$; -
S命令本质是为保证曲线连接处的一阶连续性($C^1$),因此其设计天然依赖上下文; - 在数值采样时,步长建议 ≤ 0.001(本例用 0.0001 保证平滑),但过小会降低性能,实际应用中可结合自适应细分。
掌握 S 的控制点生成规则与三次参数方程,是精准复现 SVG 贝塞尔路径、实现自定义渲染或动画插值的关键基础。

















