学习Canvas入门篇

473 阅读9分钟

定义

Canvas API 提供了一个通过JavaScript 和 HTML的 canvas 元素来绘制图形的方式。它可以用于动画、游戏画面、数据可视化、图片编辑以及实时视频处理等方面。

基本用法

var canvas = document.getElementById('tutorial');
if (canvas.getContext){  //确定浏览器支持<canvas>元素
    var ctx = canvas.getContext('2d');
}

1.canvas 元素创造了一个固定大小的画布,getContext()的方法,传入"2d",就可以获得渲染上下文和它的绘画功能。
2.在使用 canvas 元素之前,首先要检查 getContext() 方法的支持性。

绘制形状

绘制矩形 [ 矩形是唯一一种可以直接在 2D 上下文中绘制的形状。 ]

  • canvas提供了三种方法绘制矩形:

    • fillRect(x, y, width, height) // 绘制一个填充的矩形
    • strokeRect(x, y, width, height) // 绘制一个矩形的边框
    • clearRect(x, y, width, height) // 清除指定矩形区域,让清除部分完全透明。

    fillRect()函数绘制了一个边长为60px的黑色正方形。
    strokeRect()函数绘制了一个边长为60px的正方形边框。

绘制路径 [ 通过路径可以创造出复杂的形状和线条。 ]

  • 绘制路径需要用到的函数:

    • beginPath() // 新建一条路径,生成之后,图形绘制命令被指向到路径上生成路径。
    • stroke() // 通过线条来绘制图形轮廓。
    • fill() // 通过填充路径的内容区域生成实心的图形。
    • closePath() // 闭合路径之后图形绘制命令又重新指向到上下文中。

绘制直线

  • 绘制直线需要用到的函数:
    • moveTo(x, y) // 将绘图游标移动到 (x,y) ,不画线。

    • lineTo(x, y) // 从上一点开始绘制一条直线,到 (x,y) 为止。

      moveTo() 可以理解为起始坐标,lineTo()可以理解为终点坐标;
      即起始坐标(50,150)与终点坐标(200,150)之间绘制一条直线

绘制圆弧

  • 绘制圆弧需要用到的函数:
    • arc(x, y, r, sA, eA, c) // 以 (x,y) 为圆心绘 制半径为 r一条弧线,起始和结束角度(用弧度表示)分别为 sA 和eA 。最后一个参数表示 是否按逆时针方向计算。

    • arcTo(x1, y1, x2, y2, radius) :从上一点开始绘制一条弧线,到 (x2,y2) 为止,并且以 给定的半径 radius 穿过 (x1,y1)

      arc()函数绘制以(150,70)为圆心绘制半径为50的圆形;
      arcTo()函数绘制以(250,20)为起始坐标,到(350,80)坐标绘制半径为50 穿过(250,50)坐标的一条弧线。如果搞不太懂得可以点击查看 其他例子

绘制二次贝塞尔曲线及三次贝塞尔曲线

  • 绘制需要用到的函数:

    • bezierCurveTo(c1x, c1y, c2x, c2y, x, y) // 从上一点开始绘制一条曲线,到 (x,y) 为 止,并且以 (c1x,c1y) 和 (c2x,c2y) 为控制点。

    • quadraticCurveTo(cx, cy, x, y) // 从上一点开始绘制一条二次曲线,到(x,y) 为止,并且以 (cx,cy) 作为控制点。

    开始点、结束点(蓝色)、控制点(红色)

绘制文本

  • canvas 提供了两种方法来渲染文本:

    • fillText(text, x, y [, maxWidth]) // 在指定的(x,y)位置填充指定的文本,绘制的最大宽度是可选的.
    • strokeText(text, x, y [, maxWidth]) // 在指定的(x,y)位置绘制文本边框,绘制的最大宽度是可选的.

    font :表示文本样式、大小及字体,用 CSS 中指定字体的格式来指定,例如 "10px Arial" 。
    textAlign :表示文本对齐方式。可能的值有 "start" 、 "end" 、 "left" 、 "right" 和 "center" 。
    textBaseline :表示文本的基线。可能的值有 "top" 、 "hanging" 、 "middle" 、 "alphabetic" 、"ideographic" 和 "bottom" 。

变换

  • 通过如下方法来修改变换矩阵 :

    • rotate(angle) // 围绕原点旋转图像 angle 弧度 弧度=(Math.PI/180)*角度。

    rotate()是以原点(0,0)为旋转点,例子多加了ctx.translate(75,75)即移动改变原点

    • scale(scaleX, scaleY) // 缩放图像

    scale(scaleX, scaleY) 值即为缩放的倍数

    • translate(x, y) :将坐标原点移动到 (x,y)
    • transform(m1_1, m1_2, m2_1, m2_2, dx, dy) :直接修改变换矩阵
    • setTransform(m1_1, m1_2, m2_1, m2_2, dx, dy) :将变换矩阵重置为默认状态,然后 再调用 transform() 。

绘制图像

  • 使用 drawImage()三种不同的参数组合:

    • drawImage(image, x, y) // (x,y)坐标绘制图片
    • drawImage(image, x, y, w, h); // (x,y)坐标绘制w*h尺寸的图片
    • drawImage(image, x, y, w, h, x1, y1, w1, h1); //在w*h原图(x,y)开始在坐标(x1,y1)绘制w1*h1尺寸的图片

阴影

  • 通过如下方法来设置阴影 :

    • shadowColor = color //用 CSS 颜色格式表示的阴影颜色,默认为黑色
    • shadowOffsetX = float // 形状或路径 x 轴方向的阴影偏移量,默认为 0
    • shadowOffsetY = float // 形状或路径 y 轴方向的阴影偏移量,默认为 0
    • shadowBlur = float // 模糊的像素数,默认 0,即不模糊

渐变

  • 通过如下方法来设置渐变 :

    • createLinearGradient(x1, y1, x2, y2) //表示渐变的起点 (x1,y1) 与终点 (x2,y2)
    • createRadialGradient(x1, y1, r1, x2, y2, r2) // 前三个定义一个以 (x1,y1) 为原点,半径为 r1 的圆,后三个参数则定义另一个以 (x2,y2) 为原点,半径为 r2 的圆
    • addColorStop(position, color) // position表示渐变中颜色所在的相对位置,color 参数必须是一个有效的 CSS 颜色值

模式

  • 模式其实就是重复的图像,可以用来填充或描边图形

    • createPattern(image, type) //type的值包括 "repeat" 、 "repeat-x" 、"repeat-y" 和 "no-repeat" 。

使用图像数据

  • 通过如下方法来修改图片数据 :
    • getImageData(x, y, w, h) //取得坐标为(x,y)、大小为 w×h 像素的区域的图像数据
    • putImageData() // 方法把图像数据绘制到画布上

合成

  • 通过如下方法来合成 :

    • globalAlpha // 指定所有绘制的透明度。默认值为 0
    • globalCompositeOperation //表示后绘制的图形怎样与先绘制的图形结合

实践1-手画时钟

看完前面有关Canvas的语法,接下里就实践画一个时钟,基本可以把前面的知识点串起来。最终效果如下:

分析:

  • 边框:绘制矩形
  • 刻度线:绘制直线
  • 原点:绘制圆弧
  • 时间点:绘制文本
  • 时针/分针/秒针:绘制直线

实现过程:

  • 绘制边框

在坐标(450,150)绘制一个150*150的矩形

  • 绘制原点

由前面的矩形的坐标和大小就可以得出原点的坐标:
x坐标:起始点X坐标+矩形宽度的一半
y坐标:起始点Y坐标+矩形高度的一半
建议先画原点,以原点为基线画刻度线。

  • 绘制刻度线

12个刻度线,根据规律可以分为6组:(12,6)(3,9)(1,2)(4,5)(7,8)(10,11)

举例. 绘制(12,6)的刻度线:
12的X坐标:起始点X坐标+矩形宽度的一半;
12的Y坐标:即起始点Y坐标,可以得到12的起始坐标(525, 150),
但刻度线是有一定长度的,所以把起始坐标向下移动10个像素,最终得到(525, 160)。

6的X坐标:起始点X坐标+矩形宽度的一半;
6的Y坐标:即起始点Y坐标+矩形高度,可以得到6的起始坐标(525, 300),
然后把起始坐标向上移动10个像素,最终得到(525, 290)。

举例. 绘制(1,2)的刻度线:
1的X坐标:起始X坐标+3/4矩形宽度;
1的Y坐标:即起始点Y坐标,可以得到1的起始坐标(572,150),
由于1的坐标有一定倾斜,这里采用的方法X坐标左下移动5个像素,Y坐标向下移动10个像素,最终得到(567, 160)。

2的X坐标:起始X坐标+矩形宽度;
2的Y坐标:即起始点Y坐标+1/4矩形高度,可以得到2的起始坐标(600,182),
然后把起始坐标左下方移动Y坐标10的像素,最终得到(590, 187)。

其他刻度线如同上面推算即可。

  • 绘制数字和时针/分针/秒针

如果绘制刻度线顺利完成,到这一步就雷同了,应该没什么难度了~

实践2-动态填充圆弧背景色

完成实践1,应该基本熟悉和掌握Canvas的基本绘制形状的语法,接下来会实现动态填充圆形的背景色的例子,来熟悉Canvas中有点弧和角度的知识点。最终效果如下:

组成分析:

  • 最外层的圆弧
  • 内层的圆弧
  • 填充背景的圆弧
  • 白色的圆弧
  • 数字
  • 滑动条

实现过程:

  • 最外层的圆弧/内层的圆弧/白色的圆弧

  • 填充背景的圆弧

如何把滑动条选中的值换算为对应的弧度是实现效果的重点:
由于滑动条的最大值为100,圆弧刚好分为4区,即每区占0.25,而每区的弧度为0.5*PI,即滑动条的数组*2=每区的弧度。
从上图可以看到1.5*PI在起始点,如果滑动值为100时,结束角也为1.5*PI,即起始角和结束角一样,就跟我们预期不一致。所以我们的开始角只能为-0.5*PI,这样就达到我们的预期效果了。

  • 获取滑动条的值

在获取滑动条值,更新到画布时,记得要清除数字区域,要不就会重叠了。

相关代码

有需要例子代码的同学,可以前往查看

参考

  • 《JavaScript高级程序设计(第3版)》
  • 《JavaScript权威指南(第6版)》
  • MDN web docs

结语

Canvas很强大,能实现各种炫酷的图形效果,本文章只是简单介绍Canvas的基本语法,仅入门篇,后续会推出一些实践的例子。互相学习!一起进步!