0efe0ea6525c7ac954fe41bbcda0c0ea
canvas基础知识回顾

什么是 canvas

canvas 是H5新定义的标签。使用JavaScript调用canvas的API接口,可以实现绘画功能。
canvas相当于是一个画布,默认大小是300*150的矩形区域。我们可以通过标签属性‘width’、‘height’来设置画布内容的宽和高;在必要的时候,还会使用css属性来设置其CSS的宽和高(相当于画布组件本身的宽和高)。有关这两者的区别,会在后面的章节说明。
默认情况下,canvas没有内容,是一个透明的区域。canvas拥有可以绘制路径、基本形状(比如矩形 圆形)、文字和图像(png、svg等)的功能,同时canvas还可以实现像素级别的操作。

创建canvas

要创建canvas,有两种方法。
一种是在HTML标签中定义一个canvas标签,比如如下代码:

<canvas  width = "300" height="300"></canvas>

另外一种方法是通过document.createElement方法直接创建,比如如下代码:

let canvas = document.createElement('canvas');
canvas.width = 300;
canvas.height = 300;

以上两处示例代码均创建了一个画布内容宽和高均为300的画布。

获取绘制上下文context

如果把canvas比作一张白纸,那么要在白纸上面绘制图像,我们得有一只水彩笔。

为什么一定要比喻成水彩笔。 因为水彩笔不仅有绘图功能,还带有涂改液可以实现擦除功能,而绘制上下文也同样有擦除功能;而且水彩笔拥有丰富的配色。

canvas的绘制上下文context,就相当于是这只水彩笔,所以我们也会称之为画笔。context 是一个封装了很多绘图功能(API接口)的对象。
我们在创建canvas之后,可以通过canvas的getContext函数来获取canvas的绘制上下文对象context。getContext函数可以传递一个参数,表示获取的上下文的类型。其中参数‘2d’表示获取的是2d的绘制上下文。另外还有参数’webgl‘和’webgl2‘,分别表示获取webgl和webgl2的绘制上下文,webgl不在本文的讨论范围之内。比如如下代码获取了canvas的2d绘制上下文:

let ctx = canvas.getContext('2d');

在获取了绘制上下文之后,便可以通过该对象来实现路径、基本图形、图片和文字的绘制。下面会介绍这些基本的绘制功能。

为了简化,后续的文章,绘制上下文都会简称为画笔。

绘制路径

绘制一条线段

首先我们介绍如何绘制一条直线,想象一下,如果你要在一张纸上面画一条线段AB(其中A为起点,B为终点),你会怎么做?首先你会把画笔移动到A点,然后按下画笔拖动画笔到B点。需要注意的是,第一次移动画笔的时候,画笔是悬空的,也就是移动的过程只是改变了画笔的位置,并不会再纸上留下痕迹。在绘制上下文中,有两个类似的方法:

  • moveTo 移动画笔。比如ctx.moveTo(100,100),这句代码的意思是移动画笔至(100,100)这个点(单位是px)。注意canvas画布的左上角为原点,且y轴的正方向向下,x轴的正方向向右。(有关坐标系的介绍,后面的章节会详细介绍)
  • lineTo 拖动画笔绘制直线路径。比如ctx.lineTo(500,500)。这句的意思从画笔当前点绘制到(500,500),并且画笔的当前位置更新为(500,500)。
    以上两个的方法的代码演示如下:
ctx.moveTo(100,100);
ctx.lineTo(500,500);

描边和填充

然而,如果你自己动手写了上面这段代码,你可能会感到惊奇,上面代码并不会在画布上面绘制出一条从点(100,100)到点(500,500)的线段。
这是因为canvas是基于状态管理的,上面代码只是确定了canvas的内部绘制状态,并没有执行真正的绘制动作。这一点是和我们的在纸上绘制图像的直观直觉是有差异的。
路径真正的绘制动作,包括两个函数。

  • 一个是stroke,表示对路径进行描边。
  • 一个是fill,表示对路径进行填充,如果路径不是封闭路径,会自动进行封闭。

由于此处示例是绘制一条线段,所以调用stroke方法就可以了,后面会介绍到fill方法。代码如下:

ctx.moveTo(100,100);
ctx.lineTo(500,500);
ctx.stroke();

以上代码会在画布上面画出一条从点(100,100)到点(500,500)、黑色的、线宽为1px的线段。如下图所示所示:
线段

线段

描边样式

如果你是一个画家,想要画一幅优雅好看的图画。 但是只有一种黑色的笔,那一定是一件糟糕的事情。假如世界没有色彩,那么世界将多么悲哀。
幸运的是,canvas的画笔可以设置不同的颜色、样式、线条宽度等。让我们可以绘制出丰富多彩的图形。以下介绍与线条有关的样式:

  • 描边样式strokeStyle
    strokeStyle设置画笔描边颜色或者样式。可以设置颜色值或者样式,样式包括渐变色,pattern纹理。
  • 线宽lineWidth
    线宽lineWidth 设置画笔的描边宽度
  • 线帽lineCap
    线帽lineCap 设置画笔的线段端点样式,可以有以下 3 个值:
    butt:默认值,端点是垂直于线段边缘的平直边缘。
    round:端点是在线段边缘处以线宽为直径的半圆。
    square:端点是在选段边缘处以线宽为长、以一半线宽为宽的矩形。
  • 线条连接lineJoin
    线条连接lineJoin设置画笔的线条连接点的样式,可以是以下三个值:
    miter:默认值,在连接处边缘延长相接。miterLimit 是角长和线宽所允许的最大比 例(默认是 10)。
    bevel:连接处是一个对角线斜角。
    round:连接处是一个圆。
    增加画笔样式的代码如下,为了说明连接lineJoin属性,在代码中增加一个lineTo,这样会有两条线段:
ctx.moveTo(100,100);
ctx.lineTo(500,500);
ctx.lineTo(500,100);
ctx.strokeStyle = 'red';
ctx.lineWidth = 5;
ctx.lineCap = 'round';
ctx.lineJoin = 'round';
ctx.stroke();

注意 样式的设置,必须要在真正的绘制函数stroke(后面还会说的fill函数)之前。比如你想在白纸上面画红色的画,你拿起了黑色的笔(默认),画完之后在拿出红色的笔是没有用的。最终效果如下图,读者可以尝试改变样式:

路径绘制

路径绘制

专栏的源代码将会上传到地址:
https://dev.tencent.com/u/flyfox1982/p/canvas_high
本篇文章的全部代码在该地址下面的beginner目录下。 路径绘制的网站代码请参考 segment.html和segment.js。

绘制形状

上面说了如何绘制线段。事实上,通过线段的组合也可以形成一些基本的形状。

路径组合形状

前面介绍过绘制线段,那么如果把多个线段进行组合,就可以绘制出路径组合的形状。比如下面的代码,会绘制一个三角形:

ctx.moveTo(100,100);
ctx.lineTo(500,500);
ctx.lineTo(500,100);
ctx.lineTo(100,100);
ctx.stroke();

上面的绘制方法是:最后一个点和起点重合了,最终绘制效果是一个闭合的三角形。实际上,还有另外一个方法可以绘制闭合的三角形,代码如下:

ctx.moveTo(100,100);
ctx.lineTo(500,500);
ctx.lineTo(500,100);
ctx.closePath();
ctx.stroke();

上面的代码中,去掉了ctx.lineTo(100,100),起点和重点没有重合,但是增加了ctx.closePath()。画笔的closePath函数表示自动闭合当前路径。此种方法也可以绘制一个闭合的三角形。
绘制效果如下:
路径形状

路径形状

实际上以上两种绘制三角形的方法还是会有些许差别的,这会在后续的章节专门说明这个问题。

上面的代码绘制的是一个三角形边框,是因为绘制的时候使用了stroke函数。实际上还可以绘制一个实心的三角形,代码改动也很小,就是把stroke函数改成填充绘制fill函数即可。代码如下:

ctx.moveTo(100,100);
ctx.lineTo(500,500);
ctx.lineTo(500,100);
ctx.closePath();
ctx.fill();

形状的填充样式

上面绘制实心三角形使用了fill函数,使用填充绘制时,可以指定填充的样式:

  • 填充样式fillStyle
    设置画笔的填充颜色(样式)。可以是颜色、渐变色、纹理等。示例代码如下:
ctx..fillStyle = 'red';// 设置填充颜色为红色

除此之外,canvas还提供了一些内置的绘制基本形状的函数。

绘制一个矩形

canvas内置了绘制矩形的函数,包括如下方法:

  • ctx.rect(x,y,width,height);
    指定路径为起始点为(x,y) 宽为width,高为height的矩形。并不执行真正的绘制。
  • ctx.strokeRect(x,y,width,height)
    指定路径为起始点为(x,y) 宽为width,高为height的矩形,并绘制矩形描边。 ctx.strokeRect(x,y,width,height)相当于先调用ctx.rect(x,y,width,height)再调用ctx.stroke();
  • ctx.fillRect(x,y,width,height);
    指定路径为起始点为(x,y) 宽为width,高为height的矩形,并填充矩形。 ctx.fillRect(x,y,width,height)相当于先调用ctx.rect(x,y,width,height)再调用ctx.fill();
    绘制矩形参考代码如下,首先绘制一个矩形的描边,然后绘制一个实心矩形
ctx.strokeRect(100,100,100,100);
ctx.fillRect(300, 100, 100, 100);

矩形绘制效果如下:

绘制矩形

绘制矩形

绘制圆形

指定圆形路径的函数为arc,签名如下:
context.arc(x, y, radius, starAngle,endAngle, anticlockwise)。其中:

  • x : 圆心的 x 坐标
  • y:圆心的 y 坐标
  • radius : 半径
  • startAngle :开始角度
  • endAngle:结束角度
  • anticlockwise :是否逆时针(true)为逆时针,(false)为顺时针

当指定了圆形路径之后,便可以调用stroke和fill函数来分别绘制空心圆和实心圆,比如下面代码会绘制一个实心圆:

ctx.beginPath();
ctx.arc(300, 300, 100, 0, Math.PI * 2, true);
ctx.closePath();
ctx.fill();

效果如下:
圆形

圆形

上面代码用到了beginPath,beginPath表示当前路径的开始。后面中高级部分将会有章节对该函数进行详细的讲解,所以此处不在详细讲解。

形状绘制的完整代码参考:shape.html和shape.js两个文件。

绘制文字

通过以下两种方法,可以绘制文字:
ctx.strokeText(text,x,y) // 绘制空心文字(文字描边)
ctx.fillText(text,x,y); // 绘制实心文字
其中参数解释如下:

  • text 要绘制的文字
  • x,y 要绘制文字的x,y坐标

其中,与绘制文字相关的样式包括:

  • font:设置文本字体属性
  • textAlign:设置文本的对齐方式
  • textBaseline:设置绘制文本时使用的文本基线
    比如以下代码绘制一段空心文字:
context.font="40px Arial";
context.strokeText("Hello world",200,300)

绘制效果如下:
绘制文字

绘制文字

文字绘制的完整代码参考:text.html和text.js两个文件。

绘制图像

canvas提供了绘制图像(包括image对象、canvas、视频对象)。绘制函数为drawImage,该函数有3个不同的版本:

  1. context.drawImage(img,x,y)
    在画布的x,y位置绘制图像img。
  2. context.drawImage(img,x,y,width,height)
    在画布的x,y位置绘制图像img,并规定绘制的宽度为width,高度为height。
  3. context.drawImage(img,sx,sy,swidth,sheight,x,y,width,height)
    剪切图像,并在画布上绘制被剪切的部分:
  • img:规定要绘制的图像、画布或视频。
  • sx:可选。图像剪切的 x 坐标位置。
  • sy:可选。图像剪切的 y 坐标位置。
  • swidth:可选。图像剪切的宽度。
  • sheight:可选。图像剪切的高度。
  • x:在画布上绘制图像的 x 坐标位置。
  • y:在画布上绘制图像的 y 坐标位置。
  • width:可选。绘制的宽度。(伸展或缩小图像)
  • height:可选。绘制的高度。(伸展或缩小图像)

上面第3个版本的drawImage函数,可以用于绘制放大镜效果,这在后面章节会详细讲解,此处不详细讲解。

下面是绘制图像的示例代码:

var img = new Image();
img.onload = function () {
   ctx.drawImage(img, 100, 100,300,300)
}
img.src = './images/bg.jpg'

绘制效果如下:

绘制图像

绘制图像

图像绘制的完整代码参考:image.html和image.js两个文件。

渐变颜色

canvas中支持两种渐变颜色,一种是线性渐变,另外一种是径向渐变。

线性渐变

创建线性渐变的函数是:
context.createLinearGradient(xStart,yStart,xEnd,yEnd)
其中参数(xStart,yStart)表示渐变的起始点,(xEnd,yEnd)的表示渐变的终止点。该函数会返回一个线性渐变对象。如下:

var grd = ctx.createLinearGradient(100,100,500,100)

渐变对象上面有一个可以添加颜色点的函数:
grd.addColorStop(stop,color);
这里的stop传递的是 0 ~ 1 的浮点数,代表点到(xStart,yStart)的距离占整个渐变长度是比例。

top Created with Sketch.