Ch12 三次贝塞尔曲线

bezierCurveTo()方法

绘制三次贝塞尔曲线代码如下。

  1. context.bezierCurveTo(cp1x,cp1y,cp2x,cp2y,x,y);

这个方法可谓是绘制波浪线的神器。根据之前的结论,n阶贝塞尔曲线就有n-1个控制点,所以三次贝塞尔曲线有1个起始点、1个终止点、2个控制点。因此传入的6个参数分别为控制点cp1 (cp1x, cp1y),控制点cp2 (cp2x, cp2y),与终止点 (x, y)。

这个方法也是不用大家去掌握参数具体是怎么填的,只要知道参数的意义就行。和quadraticCurveTo()方法一样,bezierCurveTo()的三次贝塞尔曲线网上也能找到互动的网页工具。这里提供一个网页:Canvas Bézier Curve Example,大家可以动手试一下。

三次贝塞尔曲线交互工具

绘制XP壁纸

这里我们拿XP的壁纸开刀,来练习一下我们之前学习过的绘制方法。

  1. <!DOCTYPE html>
  2. <html lang="zh">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>XP壁纸</title>
  6. <style>
  7. body { background: url("./images/bg3.jpg") repeat; }
  8. #canvas { border: 1px solid #aaaaaa; display: block; margin: 50px auto; }
  9. </style>
  10. </head>
  11. <body>
  12. <div id="canvas-warp">
  13. <canvas id="canvas">
  14. 你的浏览器居然不支持Canvas?!赶快换一个吧!!
  15. </canvas>
  16. </div>
  17. <script>
  18. window.onload = function(){
  19. var canvas = document.getElementById("canvas");
  20. canvas.width = 800;
  21. canvas.height = 600;
  22. var context = canvas.getContext("2d");
  23. context.fillStyle = "#FFF";
  24. context.fillRect(0,0,800,600);
  25. drawPrairie(context);
  26. drawSky(context);
  27. for(var i=0; i <5; i++){
  28. var x0 = 500 * Math.random() + 50;
  29. var y0 = 200 * Math.random() + 50;
  30. var c0 = 100 * Math.random() + 50;
  31. drawCloud(context, x0, y0, c0);
  32. }
  33. };
  34. function drawSky(cxt){
  35. cxt.save();
  36. cxt.beginPath();
  37. cxt.moveTo(0, 420);
  38. cxt.bezierCurveTo(250, 300, 350, 550, 800, 400);
  39. cxt.lineTo(800,0);
  40. cxt.lineTo(0,0);
  41. cxt.closePath();
  42. var lineStyle = cxt.createRadialGradient(400, 0, 50, 400, 0, 200);
  43. lineStyle .addColorStop(0, "#42A9AA");
  44. lineStyle .addColorStop(1, "#2491AA");
  45. cxt.fillStyle = lineStyle;
  46. cxt.fill();
  47. cxt.restore();
  48. }
  49. function drawPrairie(cxt){
  50. cxt.save();
  51. cxt.beginPath();
  52. cxt.moveTo(0, 420);
  53. cxt.bezierCurveTo(250, 300, 350, 550, 800, 400);
  54. cxt.lineTo(800,600);
  55. cxt.lineTo(0,600);
  56. cxt.closePath();
  57. var lineStyle = cxt.createLinearGradient(0, 600, 600, 0);
  58. lineStyle .addColorStop(0, "#00AA58");
  59. lineStyle .addColorStop(0.3, "#63AA7B");
  60. lineStyle .addColorStop(1, "#04AA00");
  61. cxt.fillStyle = lineStyle;
  62. cxt.fill();
  63. cxt.restore();
  64. }
  65. /*渲染单个云朵
  66. context: canvas.getContext("2d")对象
  67. cx: 云朵X轴位置
  68. cy: 云朵Y轴位置
  69. cw: 云朵宽度
  70. */
  71. function drawCloud(cxt, cx, cy, cw) {
  72. //云朵移动范围即画布宽度
  73. var maxWidth = 800;
  74. //如果超过边界从头开始绘制
  75. cx = cx % maxWidth;
  76. //云朵高度为宽度的60%
  77. var ch = cw * 0.6;
  78. //开始绘制云朵
  79. cxt.beginPath();
  80. cxt.fillStyle = "white";
  81. //创建渐变
  82. var grd = cxt.createLinearGradient(0, 0, 0, cy);
  83. grd.addColorStop(0, 'rgba(255,255,255,0.8)');
  84. grd.addColorStop(1, 'rgba(255,255,255,0.5)');
  85. cxt.fillStyle = grd;
  86. //在不同位置创建5个圆拼接成云朵现状
  87. cxt.arc(cx, cy, cw * 0.19, 0, 360, false);
  88. cxt.arc(cx + cw * 0.08, cy - ch * 0.3, cw * 0.11, 0, 360, false);
  89. cxt.arc(cx + cw * 0.3, cy - ch * 0.25, cw * 0.25, 0, 360, false);
  90. cxt.arc(cx + cw * 0.6, cy, cw * 0.21, 0, 360, false);
  91. cxt.arc(cx + cw * 0.3, cy - ch * 0.1, cw * 0.28, 0, 360, false);
  92. cxt.closePath();
  93. cxt.fill();
  94. }
  95. </script>
  96. </body>
  97. </html>

演示 12-1

运行结果:

仿XP壁纸

是不是很萌?是不是非常的酷!这个案例几乎用到了之前所传授给你们的所有武功——三次贝塞尔曲线,径向渐变,线性渐变,绘制圆弧等等。分开写了三个函数,一个绘制草原、一个绘制蓝天、一个绘制白云……大家尝试自己实现一下,当做一次阶段性复习~

保存和恢复Canvas状态

这里还使用到了两个新方法save()restore()。之前说过了canvas是基于状态的绘制(说了好多次,感觉自己好啰嗦)。保存(推送)当前状态到堆栈,调用以下函数。

  1. context.save();

调出最后存储的堆栈恢复画布,使用以下函数。

  1. context.restore();

不知道大家壁纸绘制的如何,肯定非常的酷有没有?到此为止路径的知识和填充样式我们已经全部讲完了,大家也画出了很多或优美、或抽象的艺术作品。不管怎么样,这是属于我们的艺术,我们继续前进!😋