12.13 HTML Canvas复杂路径

用来创建多边形和曲线

画布中的路径不仅限于线条和圆,实际上还可以用它们来创建各种奇妙的图形。

单独一条直线路径可以绘制成一条漂亮的线条,下面介绍如何将多个路径连接在一起。

 context.beginPath();
context.moveTo(100, 50); 
context.lineTo(150, 150);
context.lineTo(50, 150); 
context.closePath(); 
context.stroke(); 
context.fill(); 

你应该能够读懂所有这些代码—一它先开始一条路径,将原点移到当前路径,从当前路径原点绘制一条线到一个指定点,再绘制一条线到另一个点,然后再继续,那么我们在这里做了什么呢?我们刚刚做的就是将多个路径连接在一起,我们只需要不停地画线。这确实非常简单,每次调用moveTo或lineTo都会给所谓子路径(subpath)增加一个相应的(x,y)坐标值。事实上,moveTo会创建一条全新的子路径,而lineTo只是沿着一条已有的子路径继续画线。这条子路径会记录我们所添加的最后一个坐标值,因而可以连续多次调用lineTo方法。lineTo的每次调用都是从子路径的最后一个坐标值(由moveTo或lineTo调用留下)开始画线,绘制一条线连接lineTo参数所定义的坐标值,然后再将子路径更新到新的坐标值。

绘制三角形的最后一步是调用closePath方法,它会画一条线连接子路径的最后一个点和第一个点——封闭路径。它也会将起点和终点添加到子路径上,这两个点现在具有相同的坐标值(参见图1)。

通过连接路径绘制一个三角形

贝塞尔曲线

要在画布中绘制一条曲线,我们可以使用arc方法或arcTo方法(在两点间绘制一条弧线),但是这些弧线只是一条具有相同半径的曲线。要创建一条更复杂的曲线,需要使用贝塞尔曲线(Bézier curve)方法:quadraticCurveTobezierCurveTo

注意:不要被贝塞尔曲线的名称误导,它们都是贝塞尔曲线,即使其中一个方法的名称不包含Bézier字样。实际上,quadraticCurveTo是一种二次贝塞尔曲线,而bezierCurveTo是三次贝塞尔曲线。

这两种贝塞尔曲线都是通过控制点将一条直线变成曲线。二次贝塞尔曲线只有一个控制点,这意味着线条中只有一次弯曲;而三次贝塞尔曲线则有两个控制点,这意味着一条线中会有两次弯曲。通过图2,我们可以直观地了解这两种曲线的效果,左边是二次贝塞尔曲线,右边是三次贝塞尔曲线。

图2
贝塞尔曲线的构造

要在画布中创建这两种曲线,只需要直接调用quadraticCurveTo或bezierCurveTo。先尝试使用quadraticCurveTo

context.lineWidth = 5; 
context.beginPath(); 
context.moveTo(50, 250); 
context.quadraticCurveTo(250, 100, 450, 250); 
context.stroke(); 

除了quadraticCurveTo方法,这段代码的其他语句你都理解。这个方法有4个参数:控制点的(x,y)坐标值(图2中的cpx和cpy),以及路径目标点的(x,y)坐标。控制点在水平(x)方向上位于线条的中心,在垂直(y)方向上稍微偏上(如图2所示),图3所示的就是这条漂亮的曲线。

二次贝塞尔曲线

创建三次贝塞尔曲线也很简单:

context.lineWidth = 5; 
context.beginPath(); 
context.moveTo(50, 250); 
context.bezierCurveTo(150, 50, 350, 450, 450, 250); 
context.stroke(); 

bezierCurveTo函数有6个参数:第一个控制点的(x,y)坐标值(如图2中的cplx和cply),第二个控制点(x,y)坐标值(cp2x和cp2y),以及路径目标点的(x,y)坐标。两个控制点都位于如图2所示的位置,屏幕上显示了两次弯曲的曲线(参见图4)。

三次贝塞尔曲线

现在绘制的贝塞尔曲线效果已经很不错了,但是在实践中它们一般不单独使用。贝塞尔曲线的最大用处是组合及附加到其他路径上,从而创建一些非常复杂的图形。你不再受限于只能创建直线和简单弧线的路径了!

注意:如果你现在还不理解实际上应该如何处理复杂图形的所有坐标位置,不要担心。Adobe illustrator有一个名为Ai->Canvas的开源插件(https://github.com/mikeswanson/Ai2Canvas),它允许你将绘制好的矢量图转换成画布代码,这意味着你完全不需要计算这些坐标。