首先,我建议使用一个好的图形库,例如raphael。它将简化实际使用 javascript 执行绘图的过程。
一种非常简单的平滑方法是将所有 lineto 命令转换为等效的 curveto 命令,并根据每条线段的角度计算一些控制点。例如,
<svg width="1000" height="1000" version="1.1"
xmlns="http://www.w3.org/2000/svg">
<path d="
M250 150
L150 350
L350 350
L250 150
" />
</svg>
becomes
<svg width="1000" height="1000" version="1.1"
xmlns="http://www.w3.org/2000/svg">
<path d="
M250 150
C250 150 150 350 150 350
C150 350 350 350 350 350
C350 350 250 150 250 150
" />
</svg>
这两个都应该画一个等边三角形
下一步是计算控制点的位置。通常,您希望平滑角两侧的控制点落在穿过顶点的假想线上。对于等边三角形的顶点,这将是水平线。经过一些操作,你可以得到这样的结果:
<svg width="1000" height="1000" version="1.1"
xmlns="http://www.w3.org/2000/svg">
<path d="
M250 150
C230 150 140 333 150 350
C160 367 340 367 350 350
C360 333 270 150 250 150
" />
</svg>
棘手的部分是计算控制点,但这只不过是一个简单的三角问题。正如我之前提到的,这里的目标是将两个控制点放在平分角顶点的线上。例如,假设我们有两条线段:
A. (0,0) to (3,2)
B. (0,0) to (1,-4)
the absolute angle of A is arctan(2/3) = 33.69 deg
the absolute angle of B is arctan(-4/1) = -75.96 deg
the bisection angle of AB is (33.69 + -75.96)/2 = -21.135
the tangent angle is AB is (-21.135 + 90) = 68.865
知道了切线角度,我们就可以计算出控制点位置
smoothness = radius = r
tangent angle = T
Vertex X = Xv
Vertex Y = Yv
Control Point 1:
Xcp1 = cos(T)*r
Ycp1 = sin(T)*r
Control Point 2:
Xcp2 = cos(T)*(-r)
Ycp2 = sin(T)*(-r)
最后一个问题是在实际的 curveTo 命令中将每个控制点放在哪里:
CX1 Y1 X2 Y2 X3 Y3
X3 和 Y3 定义顶点位置。 X1 Y1 和 X2 Y2 定义控制点。您可以将 X1 Y1 视为定义如何进入顶点的向量,将 X2 Y2 视为定义如何离开顶点的向量。现在您已经有了必须决定的两个控制点
CXcp1 Ycp1 Xcp2 Ycp2 0 0
or
CXcp2 Ycp2 Xcp1 Ycp1 0 0
这是一个重要的决定。如果你把它们倒过来,形状就会看起来像一个循环。至此,您应该能够确定如何做出这个决定......
同样,这是一个非常简单的解决方案,但它对于手绘路径来说往往看起来不错。更好的解决方案可能更进一步,将交点向内移动到每个线段交点的凹部分。这更具挑战性。