前言
在早期web端的动画、广告、游戏等基本上都是使用Flash来实现的,要在网页上播放Flash需要一堆代码和插件,因此Flash的使用上比较复杂,还会给开发者带来一堆麻烦。 自从HTML5提供 Canvas 标签以来它就彻底颠覆了Flash的地位,到如今Flash基本已经淡出了人们的视线。那究竟canvas 强在何处呢?接下来我们将深入了解一下。

在早期web端的动画、广告、游戏等基本上都是使用Flash来实现的,要在网页上播放Flash需要一堆代码和插件,因此Flash的使用上比较复杂,还会给开发者带来一堆麻烦。 自从HTML5提供 Canvas 标签以来它就彻底颠覆了Flash的地位,到如今Flash基本已经淡出了人们的视线。那究竟canvas 强在何处呢?接下来我们将深入了解一下。

从翻译其实就能很好的了解到 canvas 是用来干什么的。画布!很好理解就是用来画画的。那具体怎么“画”咱们就得看一下具体的 API 文档了。下面是对 canvas 的一些概述:
Canvas 最早是由 Apple 引入 WebKit,用于Mac OS X 的 Dashboard,随后被各个浏览器实现。如今除一些过时的浏览器不支持Canvas元素外,所有的新版本主流浏览器都支持它。
Canvas元素的学习需要具备一些基本的HTML和JavaScript知识。
下面我们来简单创建一个例子,看看canvas究竟如何使用。
html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>canvas 基本使用title>
head>
<body>
<canvas width="200" height="200">
当前浏览器不支持canvas元素,请升级或更换浏览器!
canvas>
body>
html>
复制代码上面代码就是一个基本的使用Canvas标签的例子。可以看到我们为它设置了宽和高,还在 Canvas标签内部给出一个提示文案。在这里需要说明一下:
可以看一下上面代码在浏览器上的展示样式:

Canvas标签起初只是创造了一个固定大小的画布,它公开了一个或多个渲染上下文,而我们想对它进行绘制就需要找到渲染上下文。
Canvas标签提供了一个方法叫:getContext() ,通过它我们可以获得渲染上下文和绘画功能。简单写个例子:
html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>canvas 基本使用title>
head>
<body>
<canvas id="canvas" width="200" height="200">
当前浏览器不支持canvas元素,请升级或更换浏览器!
canvas>
<script>
// 获取 canvas 元素
var canvas = document.getElementById('canvas');
// 通过判断getContext方法是否存在来判断浏览器的支持性
if(canvas.getContext) {
// 获取绘图上下文
var ctx = canvas.getContext('2d');
}
script>
body>
html>
复制代码这里需要注意一点,getContext方法是有一个接收参数,它是绘图上下文的类型,可能的参数有:
在我们获得绘制上下文以后,就可以根据绘制上下文开始绘制一些基本的形状,比如:直线、三角形、矩形、圆弧和圆。接下来咱们具体实现一下。
绘制直线咱们需要了解三个函数:
设置初始位置,参数为初始位置x和y的坐标点
绘制一条从初始位置到指定位置的直线,参数为指定位置x和y的坐标点
通过线条来绘制图形轮廓
接下里咱们应用上面的三个函数来试着绘制一条直线,代码如下:
html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>canvas - 绘制直线title>
<style>
/* 给画布增加一个阴影和圆角的样式 */
canvas {
box-shadow: 0px 0px 5px #ccc;
border-radius: 8px;
}
style>
head>
<body>
<canvas id="canvas" width="500" height="500">
当前浏览器不支持canvas元素,请升级或更换浏览器!
canvas>
<script>
// 获取 canvas 元素
var canvas = document.getElementById('canvas');
// 通过判断getContext方法是否存在来判断浏览器的支持性
if(canvas.getContext) {
// 获取绘图上下文
var ctx = canvas.getContext('2d');
// 绘制一条从起点(x: 50, y:50)到 另一个点(x: 200, y:200)的直线
ctx.moveTo(50, 50);
ctx.lineTo(200, 200);
ctx.stroke();
}
script>
body>
html>
复制代码为了展示的效果好一点,这里我调整了一下画布的大小:500 x 500,还给画布添加了一个阴影和圆角。得到的直线如图:

知道了如何绘制一条直线,那么绘制三角形也就不难了,咱们只需要画三条直线拼在一起就是一个三角形了,代码如下:
html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>canvas - 绘制三角形title>
<style>
/* 给画布增加一个阴影和圆角的样式 */
canvas {
box-shadow: 0px 0px 5px #ccc;
border-radius: 8px;
}
style>
head>
<body>
<canvas id="canvas" width="500" height="500">
当前浏览器不支持canvas元素,请升级或更换浏览器!
canvas>
<script>
// 获取 canvas 元素
var canvas = document.getElementById('canvas');
// 通过判断getContext方法是否存在来判断浏览器的支持性
if(canvas.getContext) {
// 获取绘图上下文
var ctx = canvas.getContext('2d');
// 绘制一个三角形
ctx.moveTo(50, 50);
ctx.lineTo(200, 200);
ctx.lineTo(200, 50);
ctx.lineTo(50, 50);
ctx.stroke();
}
script>
body>
html>
复制代码具体效果如下: 
知道了三角形的绘制,那么矩形的绘制是不是也用直线来拼凑呢?答案是否定的,矩形虽然可以用四条直线来拼凑成,但那样太复杂了,Canvas API 给提供了三种绘制矩形的方法:
下面我们依次看一下他们有什么异同。
strokeRect(x, y, width, height) 是用来绘制一个矩形的边框,x和y 是矩形的起点坐标,width和height 是矩形的宽高。举个例子,代码如下:
html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>canvas - 绘制矩形title>
<style>
/* 给画布增加一个阴影和圆角的样式 */
canvas {
box-shadow: 0px 0px 5px #ccc;
border-radius: 8px;
}
style>
head>
<body>
<canvas id="canvas" width="500" height="500">
当前浏览器不支持canvas元素,请升级或更换浏览器!
canvas>
<script>
// 获取 canvas 元素
var canvas = document.getElementById('canvas');
// 通过判断getContext方法是否存在来判断浏览器的支持性
if(canvas.getContext) {
// 获取绘图上下文
var ctx = canvas.getContext('2d');
// 绘制一个矩形边框
ctx.strokeRect(50, 50, 200, 100);
}
script>
body>
html>
复制代码如下图,strokeRect方法绘制的就是一个矩形框: 
fillRect(x, y, width, height) 绘制一个填充的矩形,x和y 是矩形的起点坐标,width和height 是矩形的宽高。举个例子,代码如下:
html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>canvas - 绘制矩形title>
<style>
/* 给画布增加一个阴影和圆角的样式 */
canvas {
box-shadow: 0px 0px 5px #ccc;
border-radius: 8px;
}
style>
head>
<body>
<canvas id="canvas" width="500" height="500">
当前浏览器不支持canvas元素,请升级或更换浏览器!
canvas>
<script>
// 获取 canvas 元素
var canvas = document.getElementById('canvas');
// 通过判断getContext方法是否存在来判断浏览器的支持性
if(canvas.getContext) {
// 获取绘图上下文
var ctx = canvas.getContext('2d');
// 绘制一个填充矩形
ctx.fillRect(100, 100, 200, 100);
}
script>
body>
html>
复制代码如下图,fillRect方法实现的是填充了一个矩形:

clearRect(x, y, width, height) 清除指定矩形区域,让清除部分完全透明,x和y 是矩形的起点坐标,width和height 是矩形的宽高。这里需要结合结合另外两种画法来对比一下,才能看出具体的效果,代码如下:
html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>canvas - 绘制矩形title>
<style>
/* 给画布增加一个阴影和圆角的样式 */
canvas {
box-shadow: 0px 0px 5px #ccc;
border-radius: 8px;
}
style>
head>
<body>
<canvas id="canvas" width="500" height="500">
当前浏览器不支持canvas元素,请升级或更换浏览器!
canvas>
<script>
// 获取 canvas 元素
var canvas = document.getElementById('canvas');
// 通过判断getContext方法是否存在来判断浏览器的支持性
if(canvas.getContext) {
// 获取绘图上下文
var ctx = canvas.getContext('2d');
// 绘制一个填充矩形
ctx.fillRect(100, 100, 200, 100);
ctx.fillRect(50, 50, 200, 100);
ctx.clearRect(75, 75, 100, 70);
}
script>
body>
html>
复制代码如下图,中间白色的矩形就是被指定清除的区域:

绘制圆弧或者圆,使用的方法是:arc(x, y, radius, startAngle, endAngle, anticlockwise)。x和Y为圆心的坐标,radius为半径,startAngle为圆弧或圆的开始位置,endAngle为圆弧或圆的结束位置,anticlockwise是绘制的方向(不写默认为false,从顺时针方向)。
下面画一个半圆弧看看效果,代码如下:
html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>canvas - 绘制圆弧title>
<style>
/* 给画布增加一个阴影和圆角的样式 */
canvas {
box-shadow: 0px 0px 5px #ccc;
border-radius: 8px;
}
style>
head>
<body>
<canvas id="canvas" width="500" height="500">
当前浏览器不支持canvas元素,请升级或更换浏览器!
canvas>
<script>
// 获取 canvas 元素
var canvas = document.getElementById('canvas');
// 通过判断getContext方法是否存在来判断浏览器的支持性
if(canvas.getContext) {
// 获取绘图上下文
var ctx = canvas.getContext('2d');
// 绘制一段圆弧
ctx.arc(60, 60, 50, 0, Math.PI, false);
ctx.stroke();
}
script>
body>
html>
复制代码效果如下图:

这里需要注意的是:在画弧的时候,arc()函数中角的单位是弧度而不是角度。角度换算为弧度的表达式为:弧度=(Math.PI/180)*角度。
所以想要画一个圆的弧度就是:Math.PI*2,咱们继续画一个圆弧看一下,代码如下:
html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>canvas - 绘制圆弧title>
<style>
/* 给画布增加一个阴影和圆角的样式 */
canvas {
box-shadow: 0px 0px 5px #ccc;
border-radius: 8px;
}
style>
head>
<body>
<canvas id="canvas" width="500" height="500">
当前浏览器不支持canvas元素,请升级或更换浏览器!
canvas>
<script>
// 获取 canvas 元素
var canvas = document.getElementById('canvas');
// 通过判断getContext方法是否存在来判断浏览器的支持性
if(canvas.getContext) {
// 获取绘图上下文
var ctx = canvas.getContext('2d');
// 绘制一段圆弧
ctx.arc(60, 60, 50, 0, Math.PI, false);
ctx.stroke();
// 绘制一个圆弧
ctx.arc(200, 60, 50, 0, Math.PI*2, false);
ctx.stroke();
}
script>
body>
html>
复制代码但效果似乎不想我们想象的一样,如下图:

如上图所示,先画的半圆弧和后画的圆弧被连在了一起,其实这是因为在咱们每次新建路径的时候都需要开启和闭合路径,这样不同路径之间才不会相互干扰。下面咱们就来介绍一下如何开启和闭合路径。
新建一条路径,生成之后,图形绘制命令被指向到路径上。
闭合路径之后图形绘制命令又重新指向到上下文中。 具体怎么使用这两个函数呢?下面咱们介绍一下,直接上代码:
html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>canvas - 绘制圆弧title>
<style>
/* 给画布增加一个阴影和圆角的样式 */
canvas {
box-shadow: 0px 0px 5px #ccc;
border-radius: 8px;
}
style>
head>
<body>
<canvas id="canvas" width="500" height="500">
当前浏览器不支持canvas元素,请升级或更换浏览器!
canvas>
<script>
// 获取 canvas 元素
var canvas = document.getElementById('canvas');
// 通过判断getContext方法是否存在来判断浏览器的支持性
if(canvas.getContext) {
// 获取绘图上下文
var ctx = canvas.getContext('2d');
// 绘制一段圆弧
ctx.beginPath() // 开启路径
ctx.arc(60, 60, 50, 0, Math.PI, false);
ctx.stroke();
ctx.closePath() // 闭合路径
// 绘制一个圆弧
ctx.beginPath() // 开启路径
ctx.arc(200, 60, 50, 0, Math.PI*2, false);
ctx.stroke();
ctx.closePath() // 闭合路径
}
script>
body>
html>
复制代码如上代码,咱们为每一条路径都设置了开启和闭合。那么看一下效果如何: 
这里有一点需要说明一下,其实在咱们开启和关闭路径的时候,关闭路径其实并不是必须的,对于新路径其实每次都开启新路径就ok。
以上其实都是通过stroke方法来做描边,那么如果想填充有没有对应的方法呢?
stroke方法是通过线条来绘制图形轮廓,而fill方法则是通过填充路径的内容区域生成实心的图形。
具体如何使用举个例子看一下。代码如下:
html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>canvas - 填充title>
<style>
/* 给画布增加一个阴影和圆角的样式 */
canvas {
box-shadow: 0px 0px 5px #ccc;
border-radius: 8px;
}
style>
head>
<body>
<canvas id="canvas" width="500" height="500">
当前浏览器不支持canvas元素,请升级或更换浏览器!
canvas>
<script>
// 获取 canvas 元素
var canvas = document.getElementById('canvas');
// 通过判断getContext方法是否存在来判断浏览器的支持性
if(canvas.getContext) {
// 获取绘图上下文
var ctx = canvas.getContext('2d');
// 绘制一段圆弧
ctx.beginPath() // 开启路径
ctx.arc(60, 60, 50, 0, Math.PI, false);
ctx.stroke();
// 绘制一个圆弧
ctx.beginPath() // 开启路径
ctx.arc(200, 60, 50, 0, Math.PI*2, false);
ctx.stroke();
// 填充一个四分之一圆弧
ctx.beginPath() // 开启路径
ctx.arc(60, 200, 50, 0, Math.PI/2, false);
ctx.fill();
// 填充一个半圆弧
ctx.beginPath() // 开启路径
ctx.arc(200, 200, 50, 0, Math.PI, false);
ctx.fill();
// 填充一个圆弧
ctx.beginPath() // 开启路径
ctx.arc(350, 200, 50, 0, Math.PI*2, false);
ctx.fill();
}
script>
body>
html>
复制代码效果如下图: 
添加椭圆路径。
语法:ellipse(x, y, radiusX, radiusY, rotation, startAngle, endAngle, anticlockwise)
举个例子看一下:
html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>canvas - 裁剪title>
<style>
/* 给画布增加一个阴影和圆角的样式 */
canvas {
box-shadow: 0px 0px 5px #ccc;
border-radius: 8px;
}
style>
head>
<body>
<canvas id="canvas" width="500" height="500">
当前浏览器不支持canvas元素,请升级或更换浏览器!
canvas>
<script>
// 获取 canvas 元素
var canvas = document.getElementById('canvas');
// 通过判断getContext方法是否存在来判断浏览器的支持性
if(canvas.getContext) {
// 获取绘图上下文
var ctx = canvas.getContext('2d');
ctx.beginPath();
ctx.ellipse(100, 150, 50, 100, 0, 0, 2 * Math.PI);
ctx.stroke();
ctx.beginPath();
ctx.ellipse(400, 150, 50, 100, 0, 0, 2 * Math.PI);
ctx.stroke();
ctx.beginPath();
ctx.ellipse(250, 350, 50, 100, Math.PI/2, 0, 2 * Math.PI); // 旋转90°
ctx.fill();
}
script>
body>
html>
复制代码效果如下: 
贝塞尔曲线一般用来绘制复杂有规律的图形,在Canvas中也是一个十分有用的路径类型。
语法:quadraticCurveTo(cp1x, cp1y, x, y),其中cp1x和cp1y为一个控制点,x和y为结束点。
举个例子,代码如下:
html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>canvas - 绘制二次贝塞尔曲线title>
<style>
/* 给画布增加一个阴影和圆角的样式 */
canvas {
box-shadow: 0px 0px 5px #ccc;
border-radius: 8px;
}
style>
head>
<body>
<canvas id="canvas" width="500" height="500">
当前浏览器不支持canvas元素,请升级或更换浏览器!
canvas>
<script>
// 获取 canvas 元素
var canvas = document.getElementById('canvas');
// 通过判断getContext方法是否存在来判断浏览器的支持性
if(canvas.getContext) {
// 获取绘图上下文
var ctx = canvas.getContext('2d');
// 绘制一段二次贝塞尔曲线
ctx.moveTo(50, 50);
ctx.quadraticCurveTo(200, 200, 350, 50);
// 绘制
ctx.stroke();
}
script>
body>
html>
复制代码得到的效果图如下: 
如上图,一段二次贝塞尔曲线是通过一个起点、终点和结束点来控制的。下面通过控制点的变化来看一下二次贝塞尔曲线的变化。
把控制点往左移100像素点,代码如下:
html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>canvas - 绘制二次贝塞尔曲线title>
<style>
/* 给画布增加一个阴影和圆角的样式 */
canvas {
box-shadow: 0px 0px 5px #ccc;
border-radius: 8px;
}
style>
head>
<body>
<canvas id="canvas" width="500" height="500">
当前浏览器不支持canvas元素,请升级或更换浏览器!
canvas>
<script>
// 获取 canvas 元素
var canvas = document.getElementById('canvas');
// 通过判断getContext方法是否存在来判断浏览器的支持性
if(canvas.getContext) {
// 获取绘图上下文
var ctx = canvas.getContext('2d');
// 绘制一段二次贝塞尔曲线
ctx.beginPath() // 开启路径
ctx.moveTo(50, 50);
ctx.quadraticCurveTo(200, 200, 350, 50);
// 绘制
ctx.stroke();
// 绘制一段二次贝塞尔曲线
ctx.beginPath() // 开启路径
ctx.moveTo(50, 250);
ctx.quadraticCurveTo(100, 400, 350, 250);
// 绘制
ctx.stroke();
}
script>
body>
html>
复制代码效果如下: 
这个其实可以借助一个网页版的二次贝塞尔曲线调试工具来看一下效果

和二次贝塞尔曲线不同的是三次贝塞尔曲线有两个控制点。
语法:ctx.bezierCurveTo(cp1x,cp1y, cp2x,cp2y, x, y),其中cp1x和cp1y为一个控制点,cp2x和cp2y为第二个控制点,x和y为结束点。
举个例子,代码如下:
html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>canvas - 绘制三次贝塞尔曲线title>
<style>
/* 给画布增加一个阴影和圆角的样式 */
canvas {
box-shadow: 0px 0px 5px #ccc;
border-radius: 8px;
}
style>
head>
<body>
<canvas id="canvas" width="500" height="500">
当前浏览器不支持canvas元素,请升级或更换浏览器!
canvas>
<script>
// 获取 canvas 元素
var canvas = document.getElementById('canvas');
// 通过判断getContext方法是否存在来判断浏览器的支持性
if(canvas.getContext) {
// 获取绘图上下文
var ctx = canvas.getContext('2d');
// 绘制一段三次贝塞尔曲线
ctx.beginPath() // 开启路径
ctx.moveTo(50, 200);
ctx.bezierCurveTo(150, 50, 250, 350, 350, 200);
// 绘制
ctx.stroke();
}
script>
body>
html>
复制代码效果如下:

这里也可以借助一个网页版的三次贝塞尔曲线调试工具来看一下效果:

在上面的图形绘制中都只是默认的样式。接下来说一下具体有哪些绘制样式。
线条的样式可以通过下面一系列属性来设置。
lineWidth 设置当前绘线的粗细。属性值必须为正数。默认值是 1.0。
html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>canvas - 绘制样式title>
<style>
/* 给画布增加一个阴影和圆角的样式 */
canvas {
box-shadow: 0px 0px 5px #ccc;
border-radius: 8px;
}
style>
head>
<body>
<canvas id="canvas" width="300" height="300">
当前浏览器不支持canvas元素,请升级或更换浏览器!
canvas>
<script>
// 获取 canvas 元素
var canvas = document.getElementById('canvas');
// 通过判断getContext方法是否存在来判断浏览器的支持性
if(canvas.getContext) {
// 获取绘图上下文
var ctx = canvas.getContext('2d');
// 绘制一条宽度为10的直线
ctx.beginPath()
ctx.lineWidth = 10;
ctx.moveTo(50, 20);
ctx.lineTo(250, 20);
ctx.stroke();
ctx.closePath();
// 绘制一条宽度为20的直线
ctx.beginPath()
ctx.lineWidth = 20;
ctx.moveTo(50, 50);
ctx.lineTo(250, 50);
ctx.stroke();
ctx.closePath();
}
script>
body>
html>
复制代码效果如下: 
lineCap 设置线段端点显示的样子。可选值为:butt,round 和 square。默认是 butt。
html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>canvas - 绘制样式title>
<style>
/* 给画布增加一个阴影和圆角的样式 */
canvas {
box-shadow: 0px 0px 5px #ccc;
border-radius: 8px;
}
style>
head>
<body>
<canvas id="canvas" width="300" height="300">
当前浏览器不支持canvas元素,请升级或更换浏览器!
canvas>
<script>
// 获取 canvas 元素
var canvas = document.getElementById('canvas');
// 通过判断getContext方法是否存在来判断浏览器的支持性
if(canvas.getContext) {
// 获取绘图上下文
var ctx = canvas.getContext('2d');
// lineCap 值为 butt
ctx.beginPath()
ctx.lineWidth = 10;
ctx.lineCap='butt'
ctx.moveTo(50, 20);
ctx.lineTo(250, 20);
ctx.stroke();
ctx.closePath();
// lineCap 值为 round
ctx.beginPath()
ctx.lineWidth = 10;
ctx.lineCap='round'
ctx.moveTo(50, 50);
ctx.lineTo(250, 50);
ctx.stroke();
ctx.closePath();
// lineCap 值为 square
ctx.beginPath()
ctx.lineWidth = 10;
ctx.lineCap='square'
ctx.moveTo(50, 80);
ctx.lineTo(250, 80);
ctx.stroke();
ctx.closePath();
}
script>
body>
html>
复制代码效果如下: 
lineJoin 该属性可以设置两线段连接处所显示的样子。可选值为:round, bevel 和 miter。默认是 miter。
html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>canvas - 绘制样式title>
<style>
/* 给画布增加一个阴影和圆角的样式 */
canvas {
box-shadow: 0px 0px 5px #ccc;
border-radius: 8px;
}
style>
head>
<body>
<canvas id="canvas" width="300" height="300">
当前浏览器不支持canvas元素,请升级或更换浏览器!
canvas>
<script>
// 获取 canvas 元素
var canvas = document.getElementById('canvas');
// 通过判断getContext方法是否存在来判断浏览器的支持性
if(canvas.getContext) {
// 获取绘图上下文
var ctx = canvas.getContext('2d');
// lineJoin 值为 miter
ctx.beginPath()
ctx.lineWidth = 10;
ctx.lineJoin='miter'
ctx.moveTo(50, 20);
ctx.lineTo(100, 60);
ctx.lineTo(150, 20);
ctx.lineTo(200, 60);
ctx.lineTo(250, 20);
ctx.stroke();
ctx.closePath();
// lineJoin 值为 round
ctx.beginPath()
ctx.lineWidth = 10;
ctx.lineJoin='round'
ctx.moveTo(50, 100);
ctx.lineTo(100, 140);
ctx.lineTo(150, 100);
ctx.lineTo(200, 140);
ctx.lineTo(250, 100);
ctx.stroke();
ctx.closePath();
// lineJoin 值为 bevel
ctx.beginPath()
ctx.lineWidth = 10;
ctx.lineJoin='bevel'
ctx.moveTo(50, 180);
ctx.lineTo(100, 220);
ctx.lineTo(150, 180);
ctx.lineTo(200, 220);
ctx.lineTo(250, 180);
ctx.stroke();
ctx.closePath();
}
script>
body>
html>
复制代码效果为: 
miterLimit 限制当两条线相交时交接处最大长度;所谓交接处长度(斜接长度)是指线条交接处内角顶点到外角顶点的长度。
线段之间夹角比较大时,交点不会太远,但随着夹角变小,交点距离会呈指数级增大。
如果交点距离大于miterLimit值,连接效果会变成了 lineJoin = bevel 的效果。
举个例子看一下
html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>canvas - 绘制样式title>
<style>
/* 给画布增加一个阴影和圆角的样式 */
canvas {
box-shadow: 0px 0px 5px #ccc;
border-radius: 8px;
}
style>
head>
<body>
<canvas id="canvas" width="300" height="300">
当前浏览器不支持canvas元素,请升级或更换浏览器!
canvas>
<script>
// 获取 canvas 元素
var canvas = document.getElementById('canvas');
// 通过判断getContext方法是否存在来判断浏览器的支持性
if(canvas.getContext) {
// 获取绘图上下文
var ctx = canvas.getContext('2d');
// miterLimit为定值,角度越大
ctx.beginPath()
ctx.lineWidth = 5;
ctx.lineJoin='miter'
ctx.miterLimit = 10
ctx.moveTo(0, 100);
for (i = 0; i < 30 ; i++) {
var dy = i % 2 == 0 ? 200 : 100;
ctx.lineTo(Math.pow(i, 1.5) * 2, dy);
}
ctx.stroke();
ctx.closePath();
}
script>
body>
html>
复制代码效果为:

setLineDash 可以设置当前虚线样式。
getLineDash 则是返回当前虚线设置的样式,长度为非负偶数的数组。
举个例子看一下
html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>canvas - 绘制虚线title>
<style>
/* 给画布增加一个阴影和圆角的样式 */
canvas {
box-shadow: 0px 0px 5px #ccc;
border-radius: 8px;
}
style>
head>
<body>
<canvas id="canvas" width="500" height="500">
当前浏览器不支持canvas元素,请升级或更换浏览器!
canvas>
<script>
// 获取 canvas 元素
var canvas = document.getElementById('canvas');
// 通过判断getContext方法是否存在来判断浏览器的支持性
if(canvas.getContext) {
// 获取绘图上下文
var ctx = canvas.getContext('2d');
// 绘制一条虚线
ctx.setLineDash([5, 10, 20]);
console.log(ctx.getLineDash()); // [5, 10, 20, 5, 10, 20]
ctx.beginPath();
ctx.moveTo(0,100);
ctx.lineTo(400, 100);
ctx.stroke();
// 再绘制一条虚线
ctx.setLineDash([5, 10, 20, 40]);
console.log(ctx.getLineDash()); // [5, 10, 20, 40]
ctx.beginPath();
ctx.moveTo(0,200);
ctx.lineTo(400, 200);
ctx.stroke();
}
script>
body>
html>
复制代码先看效果再讲解,效果如下:

首先这里画两条虚线是想对比一下传参为奇数数组和偶数数组的区别,在我们设置虚线的时候,如果传参为奇数,例如:ctx.setLineDash([5, 10, 20]),那么 setLineDash 会复制一份数组补全为偶数,相当于我们设置的是:ctx.setLineDash([5, 10, 20, 5, 10, 20])。所以这也就是为什么上图中我们设置的是 [5, 10, 20],结果打印出来是 [5, 10, 20, 5, 10, 20]
lineDashOffset 设置虚线样式的起始偏移量。
这里咱们再画第三条虚线来对比一下
html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>canvas - 绘制虚线title>
<style>
/* 给画布增加一个阴影和圆角的样式 */
canvas {
box-shadow: 0px 0px 5px #ccc;
border-radius: 8px;
}
style>
head>
<body>
<canvas id="canvas" width="500" height="500">
当前浏览器不支持canvas元素,请升级或更换浏览器!
canvas>
<script>
// 获取 canvas 元素
var canvas = document.getElementById('canvas');
// 通过判断getContext方法是否存在来判断浏览器的支持性
if(canvas.getContext) {
// 获取绘图上下文
var ctx = canvas.getContext('2d');
// 绘制一段圆弧
ctx.setLineDash([5, 10, 20]);
console.log(ctx.getLineDash()); // [5, 10, 20, 5, 10, 20]
ctx.beginPath();
ctx.moveTo(0,100);
ctx.lineTo(400, 100);
ctx.stroke();
ctx.setLineDash([5, 10, 20, 40]);
console.log(ctx.getLineDash()); // [5, 10, 20, 40]
ctx.beginPath();
ctx.moveTo(0,200);
ctx.lineTo(400, 200);
ctx.stroke();
ctx.setLineDash([5, 10, 20, 40]);
ctx.lineDashOffset = 3;
ctx.beginPath();
ctx.moveTo(0,300);
ctx.lineTo(400, 300);
ctx.stroke();
}
script>
body>
html>
复制代码效果为: 
这里可以明显看出虚线的总长度没有变化,只是起始点向左位移了3像素。
除了绘制实色的图形,还可以绘制有透明度的图形。通过设置 globalAlpha 属性或者使用有透明度的样式作为轮廓或填充都可以实现
举个例子看一下:
html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>canvas - 设置透明度title>
<style>
/* 给画布增加一个阴影和圆角的样式 */
canvas {
box-shadow: 0px 0px 5px #ccc;
border-radius: 8px;
}
style>
head>
<body>
<canvas id="canvas" width="500" height="500">
当前浏览器不支持canvas元素,请升级或更换浏览器!
canvas>
<script>
// 获取 canvas 元素
var canvas = document.getElementById('canvas');
// 通过判断getContext方法是否存在来判断浏览器的支持性
if(canvas.getContext) {
// 获取绘图上下文
var ctx = canvas.getContext('2d');
// 绘制一个矩形
ctx.beginPath();
// 指定透明度的填充样式
ctx.fillStyle = "rgba(0, 255, 0, 0.2)";
ctx.fillRect(10,10,300,100);
// 绘制一个矩形边框
ctx.beginPath();
// 指定透明度的描边样式
ctx.strokeStyle = "rgba(255, 0, 0, 0.7)";
ctx.strokeRect(10, 90, 100, 300);
// 绘制一个圆
ctx.beginPath()
ctx.fillStyle = "rgba(255, 255, 0, 1)";
// 设置透明度值
ctx.globalAlpha = 0.5;
ctx.arc(200, 200, 100, 0, Math.PI*2, true);
ctx.fill();
}
script>
body>
html>
复制代码效果如下:

渐变分为两种,分别是线性渐变和径向渐变,在绘图中我们可以用线性或者径向的渐变来填充或描边。
语法: createLinearGradient(x1, y1, x2, y2),参数分别为 起点的坐标和终点的坐标。
在渐变的设置中还需要一个方法来添加渐变的颜色,语法为:gradient.addColorStop(offset, color),其中color就是颜色,offset 则是颜色的偏移值,只为0到1之间的数。
举个例子看一下:
html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>canvas - 渐变title>
<style>
/* 给画布增加一个阴影和圆角的样式 */
canvas {
box-shadow: 0px 0px 5px #ccc;
border-radius: 8px;
}
style>
head>
<body>
<canvas id="canvas" width="500" height="500">
当前浏览器不支持canvas元素,请升级或更换浏览器!
canvas>
<script>
// 获取 canvas 元素
var canvas = document.getElementById('canvas');
// 通过判断getContext方法是否存在来判断浏览器的支持性
if(canvas.getContext) {
// 获取绘图上下文
var ctx = canvas.getContext('2d');
// 创建渐变
var gradient1 = ctx.createLinearGradient(10, 10, 400, 10);
gradient1.addColorStop(0, "#00ff00");
gradient1.addColorStop(1, "#ff0000");
var gradient2 = ctx.createLinearGradient(10, 10, 400, 10);
// 从0.5的位置才开始渐变
gradient2.addColorStop(0.5, "#00ff00");
gradient2.addColorStop(1, "#ff0000");
ctx.beginPath()
ctx.fillStyle = gradient1;
ctx.fillRect(10, 10, 400, 100);
ctx.beginPath();
ctx.fillStyle = gradient2;
ctx.fillRect(10, 150, 400, 100);
}
script>
body>
html>
复制代码效果如下: 
语法:ctx.createRadialGradient(x0, y0, r0, x1, y1, r1),参数分别为开始圆的坐标和半径以及结束圆的坐标和半径。
举个例子看一下:
html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>canvas - 渐变title>
<style>
/* 给画布增加一个阴影和圆角的样式 */
canvas {
box-shadow: 0px 0px 5px #ccc;
border-radius: 8px;
}
style>
head>
<body>
<canvas id="canvas" width="500" height="500">
当前浏览器不支持canvas元素,请升级或更换浏览器!
canvas>
<script>
// 获取 canvas 元素
var canvas = document.getElementById('canvas');
// 通过判断getContext方法是否存在来判断浏览器的支持性
if(canvas.getContext) {
// 获取绘图上下文
var ctx = canvas.getContext('2d');
// 创建渐变
// 结束坐标为点
var gradient1 = ctx.createRadialGradient(100, 100, 100, 100, 100, 0);
gradient1.addColorStop(0, "#ff770f");
gradient1.addColorStop(1, "#ffffff");
// 结束坐标为半径30的圆
var gradient2 = ctx.createRadialGradient(320, 100, 100, 320, 100, 30);
gradient2.addColorStop(0, "#ff770f");
gradient2.addColorStop(1, "#ffffff");
// 从0.5的位置才开始渲染
var gradient3 = ctx.createRadialGradient(100, 320, 100, 100, 320, 0);
gradient3.addColorStop(0.5, "#ff770f");
gradient3.addColorStop(1, "#ffffff");
// 开始坐标和结束坐标不一样
var gradient4 = ctx.createRadialGradient(320, 320, 100, 250, 250, 0);
gradient4.addColorStop(0, "#ff770f");
gradient4.addColorStop(1, "#ffffff");
ctx.beginPath();
ctx.fillStyle = gradient1;
ctx.fillRect(10, 10, 200, 200);
ctx.beginPath();
ctx.fillStyle = gradient2;
ctx.fillRect(220, 10, 200, 200);
ctx.beginPath();
ctx.fillStyle = gradient3;
ctx.fillRect(10, 220, 200, 200);
ctx.beginPath();
ctx.fillStyle = gradient4;
ctx.fillRect(220, 220, 200, 200);
}
script>
body>
html>
复制代码
效果如下:

Canvas中想绘制图案效果,需要用 createPattern 方法来实现。
语法:createPattern(image, type),参数分别为:Image 参数可以是一个 Image 对象,也可以是一个 canvas 对象,Type 为图案绘制的类型,可用的类型分别有:repeat,repeat-x,repeat-y 和 no-repeat。
首先先看一下如何应用 Image 对象来绘制图案。
举个例子看一下:
html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>canvas - 绘制图案title>
<style>
/* 给画布增加一个阴影和圆角的样式 */
canvas {
box-shadow: 0px 0px 5px #ccc;
border-radius: 8px;
}
style>
head>
<body>
<canvas id="canvas" width="500" height="500">
当前浏览器不支持canvas元素,请升级或更换浏览器!
canvas>
<script>
// 获取 canvas 元素
var canvas = document.getElementById('canvas');
// 通过判断getContext方法是否存在来判断浏览器的支持性
if(canvas.getContext) {
// 获取绘图上下文
var ctx = canvas.getContext('2d');
// 创建一个 image对象
var img = new Image();
img.src = "./image.png";
img.onload = function() {
// 图片加载完以后
// 创建图案
var ptrn = ctx.createPattern(img, 'no-repeat');
ctx.fillStyle = ptrn;
ctx.fillRect(0, 0, 500, 500);
}
}
script>
body>
html>
复制代码上面是一个用image对象绘制的例子,效果如下:

从上面的代码我们可以看出,本来我们想填充的是一个500*500的长方形,但是因为咱们绘制的类型设置为不平铺(no-repeat)所以看到的效果不能让我们满意,那么咱们分别看看这四个类型分别是什么效果。
html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>canvas - 绘制图案title>
<style>
/* 给画布增加一个阴影和圆角的样式 */
canvas {
box-shadow: 0px 0px 5px #ccc;
border-radius: 8px;
}
style>
head>
<body>
<canvas id="canvas" width="500" height="500">
当前浏览器不支持canvas元素,请升级或更换浏览器!
canvas>
<script>
// 获取 canvas 元素
var canvas = document.getElementById('canvas');
// 通过判断getContext方法是否存在来判断浏览器的支持性
if(canvas.getContext) {
// 获取绘图上下文
var ctx = canvas.getContext('2d');
// 创建一个 image对象
var img = new Image();
img.src = "./image.png";
img.onload = function() {
// 图片加载完以后
// 创建图案
var ptrn = ctx.createPattern(img, 'repeat');
ctx.fillStyle = ptrn;
ctx.fillRect(0, 0, 500, 500);
}
}
script>
body>
html>
复制代码设置为平铺(repeat),效果如下:
这其实才是我们想要的效果,那么咱们再看看沿X轴平铺(repeat-x)和沿Y轴平铺(repeat-y)
效果分别是: 

最后看一下如何应用 canvas 对象来绘制图案。 举个例子看一下:
html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>canvas - 绘制图案title>
<style>
/* 给画布增加一个阴影和圆角的样式 */
canvas {
box-shadow: 0px 0px 5px #ccc;
border-radius: 8px;
margin-right: 50px;
}
style>
head>
<body>
<canvas id="canvas" width="200" height="200">
当前浏览器不支持canvas元素,请升级或更换浏览器!
canvas>
<canvas id="canvas2" width="500" height="500">
当前浏览器不支持canvas元素,请升级或更换浏览器!
canvas>
<script>
// 获取 canvas 元素
var canvas = document.getElementById('canvas');
var canvas2 = document.getElementById('canvas2');
// 通过判断getContext方法是否存在来判断浏览器的支持性
if(canvas.getContext && canvas2.getContext) {
// 获取绘图上下文
var ctx = canvas.getContext('2d');
var ctx2 = canvas2.getContext('2d');
// 创建一个 canvas对象
var img = new Image();
img.src = "./image.png";
img.onload = function() {
// 图片加载完以后
// 创建图案
var ptrn = ctx.createPattern(img, 'repeat');
ctx.fillStyle = ptrn;
ctx.fillRect(0, 0, 200, 200);
// 用canvas来绘制canvas2
var ptrn2 = ctx2.createPattern(canvas, 'repeat');
ctx2.fillStyle = ptrn2;
ctx2.fillRect(0, 0, 500, 500);
}
}
script>
body>
html>
复制代码效果如下:

上面的例子可以看出,canvas2是用canvas1来绘制图案的
canvas 中依旧提供了两种方法来渲染文本,一种是描边一种是填充。
语法:ctx.strokeText(text, x, y, maxWidth)参数分别为:
举个例子看一下:
html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>canvas - 绘制文本title>
<style>
/* 给画布增加一个阴影和圆角的样式 */
canvas {
box-shadow: 0px 0px 5px #ccc;
border-radius: 8px;
}
style>
head>
<body>
<canvas id="canvas" width="500" height="500">
当前浏览器不支持canvas元素,请升级或更换浏览器!
canvas>
<script>
// 获取 canvas 元素
var canvas = document.getElementById('canvas');
// 通过判断getContext方法是否存在来判断浏览器的支持性
if(canvas.getContext) {
// 获取绘图上下文
var ctx = canvas.getContext('2d');
ctx.font = "50px serif"; // 设置文案大小和字体
ctx.strokeText("Canvas 详解", 50, 50);
}
script>
body>
html>
复制代码看一下效果: 
语法:ctx.fillText(text, x, y, maxWidth)参数分别为:
举个例子看一下:
html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>canvas - 绘制文本title>
<style>
/* 给画布增加一个阴影和圆角的样式 */
canvas {
box-shadow: 0px 0px 5px #ccc;
border-radius: 8px;
}
style>
head>
<body>
<canvas id="canvas" width="500" height="500">
当前浏览器不支持canvas元素,请升级或更换浏览器!
canvas>
<script>
// 获取 canvas 元素
var canvas = document.getElementById('canvas');
// 通过判断getContext方法是否存在来判断浏览器的支持性
if(canvas.getContext) {
// 获取绘图上下文
var ctx = canvas.getContext('2d');
ctx.font = "50px serif"; // 设置文案大小和字体
ctx.fillText("Canvas 详解", 50, 50);
}
script>
body>
html>
复制代码文本也是可以添加样式的,下面看一下可以设置那些样式
用于绘制文本的样式。默认的字体是 10px sans-serif。
文本对齐的方式。可选值为:left、right、center、start和end。默认值是 start。
文本的方向。可选值为:ltr(文本方向从左向右)、rtl(文本方向从右向左)、inherit(根据情况继承 Canvas元素或者 Document 。)。默认值是 inherit。
需要注意的是 direction 属性会对 textAlign 属性产生影响。如果 direction 属性设置为 ltr,则textAlign属性的 left 和 start 的效果相同,right 和 end 的效果相同,如果 direction 属性设置为 rtl,则 textAlign属性的 left 和 end 的效果相同,right 和 start 的效果相同。
html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>canvas - 绘制图案title>
<style>
/* 给画布增加一个阴影和圆角的样式 */
canvas {
box-shadow: 0px 0px 5px #ccc;
border-radius: 8px;
margin-right: 50px;
}
style>
head>
<body>
<canvas id="canvas" width="500" height="700">
当前浏览器不支持canvas元素,请升级或更换浏览器!
canvas>
<script>
// 获取 canvas 元素
var canvas = document.getElementById('canvas');
// 通过判断getContext方法是否存在来判断浏览器的支持性
if(canvas.getContext) {
// 获取绘图上下文
var ctx = canvas.getContext('2d');
ctx.font = "30px serif"; // 设置文案大小和字体
ctx.direction = "ltr"; // 文本方向从左向右
ctx.textAlign = "left"; // 左对齐
ctx.strokeText("Hi Canvas !", 150, 100);
ctx.direction = "ltr"; // 文本方向从左向右
ctx.textAlign = "center"; // 右对齐
ctx.strokeText("Hi Canvas !", 150, 200);
ctx.direction = "ltr"; // 文本方向从左向右
ctx.textAlign = "right"; // 右对齐
ctx.strokeText("Hi Canvas !", 150, 300);
ctx.direction = "rtl"; // 文本方向从左向右
ctx.textAlign = "left"; // 左对齐
ctx.strokeText("Hi Canvas !", 150, 400);
ctx.direction = "rtl"; // 文本方向从左向右
ctx.textAlign = "center"; // 右对齐
ctx.strokeText("Hi Canvas !", 150, 500);
ctx.direction = "rtl"; // 文本方向从左向右
ctx.textAlign = "right"; // 右对齐
ctx.strokeText("Hi Canvas !", 150, 600);
}
script>
body>
html>
复制代码效果如下:

基线对齐选项,决定文字垂直方向的对齐方式。可选值为:top、hanging、middle、alphabetic、ideographic和bottom。默认值是 alphabetic。
举个例子看一下:
html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>canvas - 绘制图案title>
<style>
/* 给画布增加一个阴影和圆角的样式 */
canvas {
box-shadow: 0px 0px 5px #ccc;
border-radius: 8px;
margin-right: 50px;
}
style>
head>
<body>
<canvas id="canvas" width="500" height="500">
当前浏览器不支持canvas元素,请升级或更换浏览器!
canvas>
<script>
// 获取 canvas 元素
var canvas = document.getElementById('canvas');
// 通过判断getContext方法是否存在来判断浏览器的支持性
if(canvas.getContext) {
// 获取绘图上下文
var ctx = canvas.getContext('2d');
ctx.font = "25px serif"; // 设置文案大小和字体
ctx.strokeStyle = 'red';
const baselines = ['top', 'hanging', 'middle', 'alphabetic', 'ideographic', 'bottom'];
baselines.forEach(function (baseline, index) {
ctx.textBaseline = baseline;
let y = 60 + index * 60;
ctx.beginPath();
ctx.moveTo(10, y + 0.5);
ctx.lineTo(500, y + 0.5);
ctx.stroke();
ctx.fillText('Hi Canvas, Welcome to my world! (' + baseline + ')', 10, y);
});
}
script>
body>
html>
复制代码效果如下:

测量文本,返回一个 TextMetrics对象。
html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>canvas - 绘制图案title>
<style>
/* 给画布增加一个阴影和圆角的样式 */
canvas {
box-shadow: 0px 0px 5px #ccc;
border-radius: 8px;
margin-right: 50px;
}
style>
head>
<body>
<canvas id="canvas" width="500" height="500">
当前浏览器不支持canvas元素,请升级或更换浏览器!
canvas>
<script>
// 获取 canvas 元素
var canvas = document.getElementById('canvas');
// 通过判断getContext方法是否存在来判断浏览器的支持性
if(canvas.getContext) {
// 获取绘图上下文
var ctx = canvas.getContext('2d');
ctx.font = "30px serif"; // 设置文案大小和字体
ctx.beginPath();
ctx.strokeText("Hi Canvas !", 150, 100);
var text = ctx.measureText("Hi Canvas !");
console.log("🚀 ~ 文案宽度:", text.width)
ctx.beginPath();
// 设置了文案最大宽度
ctx.strokeText("Hi Canvas !", 150, 200, 100);
var text1 = ctx.measureText("Hi Canvas !");
console.log("🚀 ~ 文案宽度:", text1.width)
}
script>
body>
html>
复制代码效果如下: 
如上面的效果可以看出,返回的 TextMetrics对象不受最大宽度等外界因素所影响。
那么TextMetrics对象具体有哪些属性?打印看一下:

属性解析:
PS:以上所有属性都是使用 CSS 像素计算的,并且都是只读。
shadowOffsetX 和 shadowOffsetY 用来设定阴影在 X 和 Y 轴的延伸距离,它们是不受变换矩阵所影响的。负值表示阴影会往上或左延伸,正值则表示会往下或右延伸,它们默认都为 0。
shadowBlur 用于设定阴影的模糊程度,其数值并不跟像素数量挂钩,也不受变换矩阵的影响,默认为 0。
shadowColor 是标准的 CSS 颜色值,用于设定阴影颜色效果,默认是全透明的黑色。
举个例子看一下:
html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>canvas - 阴影title>
<style>
/* 给画布增加一个阴影和圆角的样式 */
canvas {
box-shadow: 0px 0px 5px #ccc;
border-radius: 8px;
}
style>
head>
<body>
<canvas id="canvas" width="500" height="500">
当前浏览器不支持canvas元素,请升级或更换浏览器!
canvas>
<script>
// 获取 canvas 元素
var canvas = document.getElementById('canvas');
// 通过判断getContext方法是否存在来判断浏览器的支持性
if(canvas.getContext) {
// 获取绘图上下文
var ctx = canvas.getContext('2d');
ctx.font = "50px serif"; // 设置文案大小和字体
ctx.shadowColor = "#cccccc"; // 设置阴影颜色
ctx.fillStyle = "#ee7934"; // 设置填充颜色
ctx.shadowOffsetX = 10; // X轴上的阴影
ctx.shadowOffsetY = 10; // Y轴上的阴影
ctx.shadowBlur = 5; // 阴影的模糊程度
ctx.fillText("Hi Canvas !", 100, 50);
ctx.fillRect(100, 100, 200, 100);
ctx.shadowOffsetX = -10;
ctx.shadowOffsetY = -10;
ctx.shadowBlur = 5;
ctx.fillText("Hi Canvas !", 100, 300);
ctx.fillRect(100, 350, 200, 100);
}
script>
body>
html>
复制代码效果如下: 
绘制图片和上面的图案样式绘制基本大同小异,不同的是所用方式不一样,绘制图片是使用 drawImage 方法将它渲染到 canvas 里。
这里咱们主要要说的就是drawImage方法的使用,他的用法有三种,是根据不同的传参实现不同的功能。先看看都有哪些参数:
drawImage(image, dx, dy):只有单纯的绘制功能,可以绘制图片、视频和别的Canvas对象等。
举个例子看一下:
html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>canvas - 绘制 - drawImagetitle>
<style>
/* 给画布增加一个阴影和圆角的样式 */
canvas {
box-shadow: 0px 0px 5px #ccc;
border-radius: 8px;
}
style>
head>
<body>
<canvas id="canvas" width="500" height="500">
当前浏览器不支持canvas元素,请升级或更换浏览器!
canvas>
<script>
// 获取 canvas 元素
var canvas = document.getElementById('canvas');
// 通过判断getContext方法是否存在来判断浏览器的支持性
if(canvas.getContext) {
// 获取绘图上下文
var ctx = canvas.getContext('2d');
var img = new Image();
img.src = 'https://gimg2.baidu.com/image_search/src=http%3A%2F%2F5b0988e595225.cdn.sohucs.com%2Fimages%2F20191212%2F556cc408058d4c64a46468761406afe6.png&refer=http%3A%2F%2F5b0988e595225.cdn.sohucs.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1660103116&t=8dd0c641e1e1890fa65ee80dfa428d34';
img.onload = function(){
ctx.drawImage(img, 0, 0);
}
}
script>
body>
html>
复制代码效果如下: 
如上图所示,咱们可以简单地把一个图片绘制到Canvas中。但上面的效果却不是我们预期中的效果,那么如果我们想把图片完整的绘制到canvas中,我们就需要别的参数。
drawImage(image, dx, dy, dWidth, dHeight):在绘制的基础上我们又增加了两个参数,这两个参数能控制绘制元素的大小,整体实现一个缩放的效果。
举个例子看一下:
html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>canvas - 绘制 - drawImagetitle>
<style>
/* 给画布增加一个阴影和圆角的样式 */
canvas {
box-shadow: 0px 0px 5px #ccc;
border-radius: 8px;
}
style>
head>
<body>
<canvas id="canvas" width="500" height="500">
当前浏览器不支持canvas元素,请升级或更换浏览器!
canvas>
<script>
// 获取 canvas 元素
var canvas = document.getElementById('canvas');
// 通过判断getContext方法是否存在来判断浏览器的支持性
if(canvas.getContext) {
// 获取绘图上下文
var ctx = canvas.getContext('2d');
var img = new Image();
img.src = 'https://gimg2.baidu.com/image_search/src=http%3A%2F%2F5b0988e595225.cdn.sohucs.com%2Fimages%2F20191212%2F556cc408058d4c64a46468761406afe6.png&refer=http%3A%2F%2F5b0988e595225.cdn.sohucs.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1660103116&t=8dd0c641e1e1890fa65ee80dfa428d34';
img.onload = function(){
ctx.drawImage(img, 0, 0, 500, 500);
}
}
script>
body>
html>
复制代码效果如下: 
这里需要说明一点,在设置dWidth和dHeight两个参数时,不能只设置其中一个,要么都设置要么都不设置。
drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight):在缩放的基础上又增加了四个参数,整体也是在缩放的基础上增加了裁剪的功能。
举个例子看一下:
html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>canvas - 绘制 - drawImagetitle>
<style>
/* 给画布增加一个阴影和圆角的样式 */
canvas {
box-shadow: 0px 0px 5px #ccc;
border-radius: 8px;
}
style>
head>
<body>
<canvas id="canvas" width="500" height="500">
当前浏览器不支持canvas元素,请升级或更换浏览器!
canvas>
<script>
// 获取 canvas 元素
var canvas = document.getElementById('canvas');
// 通过判断getContext方法是否存在来判断浏览器的支持性
if(canvas.getContext) {
// 获取绘图上下文
var ctx = canvas.getContext('2d');
var img = new Image();
img.src = 'https://gimg2.baidu.com/image_search/src=http%3A%2F%2F5b0988e595225.cdn.sohucs.com%2Fimages%2F20191212%2F556cc408058d4c64a46468761406afe6.png&refer=http%3A%2F%2F5b0988e595225.cdn.sohucs.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1660103116&t=8dd0c641e1e1890fa65ee80dfa428d34';
img.onload = function(){
// 在图片的(100,100)位置,裁剪一个300*300大小的内容,然后缩放到500*500绘制到Canvas中(0, 0)的地方
ctx.drawImage(img, 100, 100, 300, 300, 0, 0, 500, 500);
}
}
script>
body>
html>
复制代码上面代码其实就是:在原图片的(100,100)位置,裁剪一个300300大小的内容,然后再缩放到500500绘制到Canvas中(0, 0)的地方。
效果如下: 
变形算是canvas基础的进阶把,它是一种更强大的方法,可以将原点移动到另一点,还能对网格进行旋转和缩放。
save() 和 restore() 方法是用来保存和恢复 canvas 状态的,方法不需要参数。可以理解为就是对canvas 状态的快照进行保存和恢复。
举个例子看一下:
html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>canvas - 绘制 - drawImagetitle>
<style>
/* 给画布增加一个阴影和圆角的样式 */
canvas {
box-shadow: 0px 0px 5px #ccc;
border-radius: 8px;
}
style>
head>
<body>
<canvas id="canvas" width="500" height="500">
当前浏览器不支持canvas元素,请升级或更换浏览器!
canvas>
<script>
// 获取 canvas 元素
var canvas = document.getElementById('canvas');
// 通过判断getContext方法是否存在来判断浏览器的支持性
if(canvas.getContext) {
// 获取绘图上下文
var ctx = canvas.getContext('2d');
ctx.fillStyle = "#cccccc";
ctx.fillRect(10, 10, 300, 100);
ctx.save(); // 保存状态
ctx.fillStyle = "#ee7034";
ctx.fillRect(10, 150, 300, 100);
ctx.restore(); // 还原到上次保存的状态
ctx.fillRect(10, 300, 300, 100);
}
script>
body>
html>
复制代码效果如下: 
如上图效果我们可以看出,当我们保存一个状态以后,在我们恢复以后可以继续使用这个状态。
Canvas的状态是存储在栈中的,每次调用save()方法后,当前的状态都会被推送到栈中保存起来。
一个绘画状态包括:
PS:保存和恢复可以多次调用, 需要注意的是每一次调用 restore 方法,上一个保存的状态就从栈中弹出,所有设定都恢复。
举个例子看一下:
html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>canvas - 绘制 - drawImagetitle>
<style>
/* 给画布增加一个阴影和圆角的样式 */
canvas {
box-shadow: 0px 0px 5px #ccc;
border-radius: 8px;
}
style>
head>
<body>
<canvas id="canvas" width="500" height="500">
当前浏览器不支持canvas元素,请升级或更换浏览器!
canvas>
<script>
// 获取 canvas 元素
var canvas = document.getElementById('canvas');
// 通过判断getContext方法是否存在来判断浏览器的支持性
if(canvas.getContext) {
// 获取绘图上下文
var ctx = canvas.getContext('2d');
ctx.fillStyle = '#ee7034';
ctx.save();
ctx.save();
ctx.translate(100, 100); // x和y轴都移动了100
ctx.fillRect(0, 0, 100, 100);
ctx.restore();
ctx.rotate(Math.PI / 4); // 旋转了45度,Math.PI=180度
ctx.fillRect(0, 0, 100, 100);
ctx.restore();
ctx.scale(2, 1);
ctx.fillRect(100, 300, 100, 100);
}
script>
body>
html>
复制代码效果如下: 
PS:这里需要注意三点:
save()保存的状态是可以多次保存的,同时保存在栈中的元素遵循的是后进先出的顺序;
旋转的中心点始终是 canvas 的原点;
缩放如果是负值的话,则是一个镜像的效果。
需要注意的是transform方法和setTransform方法中如果任意一个参数是无限大(Infinity),那么变形矩阵也必须被标记为无限大,否则会抛出异常。
参数说明:
举个例子看一下:
html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>canvas - 绘制 - drawImagetitle>
<style>
/* 给画布增加一个阴影和圆角的样式 */
canvas {
box-shadow: 0px 0px 5px #ccc;
border-radius: 8px;
}
style>
head>
<body>
<canvas id="canvas" width="500" height="500">
当前浏览器不支持canvas元素,请升级或更换浏览器!
canvas>
<script>
// 获取 canvas 元素
var canvas = document.getElementById('canvas');
// 通过判断getContext方法是否存在来判断浏览器的支持性
if(canvas.getContext) {
// 获取绘图上下文
var ctx = canvas.getContext('2d');
//
var sin = Math.sin(Math.PI / 6);
var cos = Math.cos(Math.PI / 6);
console.log("🚀 ~ cos, sin", cos, sin)
ctx.translate(250, 250);
var c = 0;
for (var i=0; i <= 12; i++) {
c = Math.floor(255 / 12 * i);
ctx.fillStyle = `rgba(${c}, ${c}, ${c})`;
ctx.beginPath() // 开启路径
ctx.arc(60, 100, 100, 0, Math.PI*2, false);
ctx.fill();
ctx.transform(cos, sin, -sin, cos, 0, 0);
}
// 绘制一个矩形
ctx.fillStyle = "rgba(255, 128, 255, 0.5)";
ctx.fillRect(0, 50, 100, 100);
// 上面绘制的矩形不是我们想要的没因为它带上了上面transform的属性
// 所以需要重置当前变形为单位矩阵
ctx.resetTransform()
ctx.fillStyle = "rgba(255, 128, 255, 0.5)";
ctx.fillRect(0, 50, 100, 100);
}
script>
body>
html>
复制代码效果如下:

合成的图形受限于绘制的顺序。如果我们不想受限于绘制的顺序,那么我们可以利用 globalCompositeOperation 属性来改变这种情况。
语法:globalCompositeOperation = type,type为合成的类型,具体有哪些类型下面我们将分别看一下:
默认值,在现有画布上下文之上绘制新图形。
html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>canvas - 绘制 - drawImagetitle>
<style>
/* 给画布增加一个阴影和圆角的样式 */
canvas {
box-shadow: 0px 0px 5px #ccc;
border-radius: 8px;
}
style>
head>
<body>
<canvas id="canvas" width="500" height="500">
当前浏览器不支持canvas元素,请升级或更换浏览器!
canvas>
<script>
// 获取 canvas 元素
var canvas = document.getElementById('canvas');
// 通过判断getContext方法是否存在来判断浏览器的支持性
if(canvas.getContext) {
// 获取绘图上下文
var ctx = canvas.getContext('2d');
ctx.beginPath();
ctx.fillStyle = "rgba(255, 0, 0, 1)";
ctx.fillRect(50, 100, 300, 150);
ctx.globalCompositeOperation = 'source-over'
ctx.beginPath();
ctx.fillStyle = "rgba(0, 255, 0, 1)";
ctx.fillRect(50, 150, 150, 250);
ctx.globalCompositeOperation = 'source-over'
ctx.beginPath();
ctx.fillStyle = "rgba(0, 0, 255, 1)";
ctx.fillRect(150, 200, 150, 150);
}
script>
body>
html>
复制代码效果如下: 
新图形只在新图形和目标画布重叠的地方绘制。其他的都是透明的。
ctx.globalCompositeOperation = 'source-in'
复制代码效果如下: 
在不与现有画布内容重叠的地方绘制新图形。
ctx.globalCompositeOperation = 'source-out'
复制代码效果如下: 
新图形只在与现有画布内容重叠的地方绘制。
ctx.globalCompositeOperation = 'source-atop'
复制代码效果如下: 
在现有的画布内容后面绘制新的图形。
ctx.globalCompositeOperation = 'destination-over'
复制代码效果如下: 
现有的画布内容保持在新图形和现有画布内容重叠的位置。其他的都是透明的。
ctx.globalCompositeOperation = 'destination-in'
复制代码效果如下:

现有内容保持在新图形不重叠的地方。
ctx.globalCompositeOperation = 'destination-out'
复制代码效果如下:

现有的画布只保留与新图形重叠的部分,新的图形是在画布内容后面绘制的。
ctx.globalCompositeOperation = 'destination-atop'
复制代码效果如下:

两个重叠图形的颜色是通过颜色值相加来确定的。
ctx.globalCompositeOperation = 'lighter'
复制代码效果如下:

只显示新图形。
ctx.globalCompositeOperation = 'copy'
复制代码效果如下:

图像中,那些重叠和正常绘制之外的其他地方是透明的。
ctx.globalCompositeOperation = 'xor'
复制代码效果如下:

将顶层像素与底层相应像素相乘,结果是一幅更黑暗的图片。
ctx.globalCompositeOperation = 'multiply'
复制代码效果如下:

像素被倒转,相乘,再倒转,结果是一幅更明亮的图片。
ctx.globalCompositeOperation = 'screen'
复制代码效果如下:

multiply 和 screen 的结合,原本暗的地方更暗,原本亮的地方更亮。
ctx.globalCompositeOperation = 'overlay'
复制代码效果如下:

保留两个图层中最暗的像素。
ctx.globalCompositeOperation = 'darken'
复制代码效果如下:

保留两个图层中最亮的像素。
ctx.globalCompositeOperation = 'lighten'
复制代码效果如下:

将底层除以顶层的反置。
ctx.globalCompositeOperation = 'color-dodge'
复制代码效果如下:

将反置的底层除以顶层,然后将结果反过来。
ctx.globalCompositeOperation = 'color-burn'
复制代码效果如下:

屏幕相乘(A combination of multiply and screen)类似于叠加,但上下图层互换了。
ctx.globalCompositeOperation = 'hard-light'
复制代码效果如下:

用顶层减去底层或者相反来得到一个正值。
ctx.globalCompositeOperation = 'soft-light'
复制代码效果如下:

一个柔和版本的强光(hard-light)。纯黑或纯白不会导致纯黑或纯白。
ctx.globalCompositeOperation = 'difference'
复制代码效果如下:

和 difference 相似,但对比度较低。
ctx.globalCompositeOperation = 'exclusion'
复制代码效果如下:

保留了底层的亮度(luma)和色度(chroma),同时采用了顶层的色调(hue)。
ctx.globalCompositeOperation = 'hue'
复制代码效果如下:

保留底层的亮度(luma)和色调(hue),同时采用顶层的色度(chroma)。
ctx.globalCompositeOperation = 'saturation'
复制代码效果如下:

保留了底层的亮度(luma),同时采用了顶层的色调 (hue) 和色度 (chroma)。
ctx.globalCompositeOperation = 'color'
复制代码效果如下:

保持底层的色调(hue)和色度(chroma),同时采用顶层的亮度(luma)。
ctx.globalCompositeOperation = 'luminosity'
复制代码效果如下:

裁剪的作用是遮罩,用来隐藏不需要的部分,所有在路径以外的部分都不会在 canvas 上绘制出来。
裁剪的效果和 globalCompositeOperation 属性的 source-in 和 source-atop差不多,但也有区别,最重要的区别是裁剪路径不会在 canvas 上绘制东西,而且它永远不受新图形的影响。这些特性使得它在特定区域里绘制图形时特别好用。
语法:clip() 将当前正在构建的路径转换为当前的裁剪路径。
默认情况下,canvas 有一个与它自身一样大的裁剪路径(也就是没有裁剪效果)。现在可以通过clip()来创建一个裁剪路劲(也就有裁剪效果了)。
直接举个例子看一下:
html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>canvas - 裁剪title>
<style>
/* 给画布增加一个阴影和圆角的样式 */
canvas {
box-shadow: 0px 0px 5px #ccc;
border-radius: 8px;
}
style>
head>
<body>
<canvas id="canvas" width="500" height="500">
当前浏览器不支持canvas元素,请升级或更换浏览器!
canvas>
<script>
// 获取 canvas 元素
var canvas = document.getElementById('canvas');
// 通过判断getContext方法是否存在来判断浏览器的支持性
if(canvas.getContext) {
// 获取绘图上下文
var ctx = canvas.getContext('2d');
var img = new Image();
img.src = 'https://gimg2.baidu.com/image_search/src=http%3A%2F%2F5b0988e595225.cdn.sohucs.com%2Fimages%2F20191212%2F556cc408058d4c64a46468761406afe6.png&refer=http%3A%2F%2F5b0988e595225.cdn.sohucs.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1660103116&t=8dd0c641e1e1890fa65ee80dfa428d34';
img.onload = function(){
// 创建圆形裁剪路径
ctx.arc(250, 250, 200, 0, Math.PI*2, false);
ctx.clip();
// 创建完后绘制
ctx.drawImage(img, 0, 0, 500, 500);
}
}
script>
body>
html>
复制代码效果如下:

Path2D 用来声明路径,语法:Path2D(),它是一个构造函数,可以创建一个新的 Path2D 对象。
Path2D()有不少方法,先了解一下:
下面举例看一下如何应用 Path2D 来创建一个裁剪路径:
html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>canvas - 裁剪title>
<style>
/* 给画布增加一个阴影和圆角的样式 */
canvas {
box-shadow: 0px 0px 5px #ccc;
border-radius: 8px;
}
style>
head>
<body>
<canvas id="canvas" width="500" height="500">
当前浏览器不支持canvas元素,请升级或更换浏览器!
canvas>
<script>
// 获取 canvas 元素
var canvas = document.getElementById('canvas');
// 通过判断getContext方法是否存在来判断浏览器的支持性
if(canvas.getContext) {
// 获取绘图上下文
var ctx = canvas.getContext('2d');
var img = new Image();
img.src = 'https://gimg2.baidu.com/image_search/src=http%3A%2F%2F5b0988e595225.cdn.sohucs.com%2Fimages%2F20191212%2F556cc408058d4c64a46468761406afe6.png&refer=http%3A%2F%2F5b0988e595225.cdn.sohucs.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1660103116&t=8dd0c641e1e1890fa65ee80dfa428d34';
img.onload = function(){
// 创建圆形裁剪路径
ctx.arc(250, 250, 200, 0, Math.PI*2, false);
var path1 = new Path2D();
path1.rect(100, 100, 300, 300);
ctx.clip(path1);
// 创建完后绘制
ctx.drawImage(img, 0, 0, 500, 500);
}
}
script>