是HTML5新增的一种标签,一个可以使用脚本(通常为JavaScript)在其中绘制图的HTML元素。它可以用来制作照片集或者制作简单(也不是那么简单)的动画,甚至可以进行实时视频处理和渲染。
注意:canvas 标签是行内块元素,如果需要设置他的布局,可以设置为块级元素
1.1.获取canvas 标签(通过标签选择器来选择)
1.2.拿到canvas 的上下文对象(通过ctx.getContext('2d')来获取)
1.3.开启一条路径 beginPath();
1.4.确定起始点 moveTo(x,y)
1.5.确定终点 lineTo(x,y) ,这里可以连写lineTo(x,y) 终点位置,实现连笔画,及以上一个结束坐标作为下一个点的开始坐标;
1.6.进行上色
1.7.关闭路劲
- /* 1.获取canvas 标签 */
- let canvas = document.querySelector('canvas')
- /* 2.获取上下文对象,使用getContext('2d')方法 */
- let ctx = canvas.getContext('2d');
- /* 3.开启一条路径 */
- ctx.beginPath();
- /* 4.确定起点坐标 坐标是相对于 canvas 的左上角 */
- ctx.moveTo(100, 100)
- /* 5.确实终点坐标 */
- ctx.lineTo(400, 400)
-
- /* 设置颜色和线宽,必须要在上色之前设置颜色和线宽属性 */
- ctx.strokeStyle = 'pink'
- ctx.lineWidth = 5
-
- /* 6.上色 */
- ctx.stroke()
- /* 7.关闭路径 */
- ctx.closePath();
- let canvas = document.querySelector('canvas')
- let ctx = canvas.getContext('2d')
-
- drawLine(100, 100, 105, 100, 'pink', 5)
-
- // 画虚线
- for (let i = 0; i < 20; i++) {
- drawLine(100 + 10 * i, 100, 105 + 10 * i, 100, 'pink', 5)
- }
-
- // 斜角度画虚线
- for (let i = 0; i < 20; i++) {
- drawLine(100 + 10 * i, 100 + 10 * i, 105 + 10 * i, 105 + 10 * i, 'pink', 5)
- }
- // 画直线函数
- function drawLine(x1, y1, x2, y2, color, width) {
- ctx.beginPath();
- ctx.moveTo(x1, y1)
- ctx.lineTo(x2, y2)
- ctx.strokeStyle = color
- ctx.lineWidth = width
- ctx.stroke()
- ctx.closePath();
- }
(1)setLineDash([num1,num2]) 方法接受一个数组作为参数,num1为 线条长度,num2 为间隔距离
(2)lineDashOffset = num, 方法设置起始点偏移量;
- function draw() {
- let canvas = document.querySelector('canvas')
- let ctx = canvas.getContext('2d')
-
- ctx.setLineDash([10, 10]); // [实线长度, 间隙长度]
- ctx.lineDashOffset = -5;
- // ctx.strokeRect(50, 50, 210, 210);
- ctx.beginPath()
- ctx.moveTo(0, 0)
- ctx.lineTo(100, 100)
- ctx.stroke()
- ctx.closePath()
- }
- draw();
x,y表示矩形左上角起始坐标;
width,height 表示 矩形的长宽;
- ctx.fillRect(200, 200, 100, 100)
- ctx.fillStyle = 'red'
- ctx.strokeStyle = '#ccc'
- ctx.lineWidth = 3
- ctx.strokeRect(300, 300, 100, 100)
- let canvas = document.querySelector('canvas')
- let ctx = canvas.getContext('2d')
-
- ctx.beginPath()
- // 创建矩形,rect(x,y,width,height)
- ctx.rect(100, 100, 100, 100)
- // 填充色
- ctx.fillStyle = 'pink'
- // 填充
- ctx.fill()
- // 描边
- ctx.strokeStyle = 'green'
- // 描边的宽度
- ctx.lineWidth = 5
- // 着色
- ctx.stroke()
简单实例如下:

清除画布在画图过程中很常用,比如实现动态图,就是不断清除画布和重绘画布;
- /* 画矩形 */
- let canvas = document.querySelector('canvas')
- let ctx = canvas.getContext('2d')
-
- ctx.beginPath()
- // 创建矩形,rect(x,y,width,height)
- ctx.rect(100, 100, 300, 200)
- // 填充色
- ctx.fillStyle = 'pink'
- // 填充
- ctx.fill()
- // 描边
- ctx.strokeStyle = 'green'
- // 描边的宽度
- ctx.lineWidth = 5
- // 着色
- ctx.stroke()
- // 清除画布 clearRect(x,y,width,height) 坐标x,y依然是矩形的左上角;
- ctx.clearRect(120, 120, 150, 100)
方法:arc(x,y,radius,startAngle,endAngle,counterclockwise)
(1)x,y 表示圆心坐标
(2)radius 表示圆弧半径
(3)startAngle 开始角度
(4)endAngle 结束角度
(5)counterclockwise 表示画圆弧的顺逆时针方向,false 表示顺时针,true表示逆时针
- ctx.beginPath()
- ctx.arc(400, 400, 250, 0, Math.PI * 2, false)
- ctx.strokeStyle = 'red'
- ctx.lineWidth = 3
- // 内部填充
- ctx.fillStyle = 'gold'
- ctx.fill()
- // 着色,不可缺,没有着色是不能看到的
- ctx.stroke()
-
- // 图像不是封闭的时候,需要设置开始路径和结束路径的,要不然会连笔
- ctx.beginPath()
- ctx.arc(400, 400, 100, 0, Math.PI, false)
- ctx.strokeStyle = 'red'
- ctx.lineWidth = 3
- // 着色,不可缺,没有着色是不能看到的
- ctx.stroke()

(1).实心字体 方法:fillText('文字内容',x,y,maxWidth)
(2) 空心字体 方法:ctx.strokeText('文字内容', x, y)
- x,y 表示文字的开始位置坐标,maxWidth表示文字内容最大宽度,超出会压缩
(3)线性渐变
方法:let grd = ctx.createLinearGradient(x1, y, x2, y2);
grd.addColorStop('0','颜色')
grd.addColorStop('1','颜色')
- x1,y1,x2,y2表示渐变开始和结束的坐标
- addColorStop() 表示,颜色的添加
- // 字体的样式需要放在 前面
- ctx.font = '50px 微软雅黑'
- ctx.fillStyle = 'gold'
- // 实心字体
- ctx.fillText('hello canvas', 100, 100)
-
- ctx.font = '50px 宋体'
- // 空心字体
- ctx.strokeStyle = 'pink'
- ctx.strokeText('你好', 100, 200)
-
- // 颜色线性渐变
- let grd = ctx.createLinearGradient(0, 0, canvas.width, 0);
- // 增加渐变颜色以及范围
- grd.addColorStop('0', 'yellow')
- grd.addColorStop('0.5', 'red')
- grd.addColorStop('1.0', 'skyBlue')
-
- // 应用渐变,把渐变的变量 赋值给strokeStyle 属性
- ctx.strokeStyle = grd;
- ctx.font = '40px 楷体'
- ctx.strokeText('今天很冷,要多穿衣服哦!!!', 0, 300, 400)

文字位置属性:
文字水平方向:start,end, left,right,center
文字垂直方向:top,bottom,middle
- // 画田字格
- ctx.beginPath();
- ctx.moveTo(250, 0)
- ctx.lineTo(250, 500)
- ctx.stroke()
- ctx.closePath()
-
- ctx.beginPath();
- ctx.moveTo(0, 250)
- ctx.lineTo(500, 250)
- ctx.stroke()
- ctx.closePath()
-
- ctx.font = '30px 宋体'
- ctx.fillStyle = 'red'
- // 水平居中 (参考点都是坐标点)
- ctx.textAlign = 'center'
- // 垂直居中 (参考点都是坐标点)
- ctx.textBaseline = 'middle'
- ctx.fillText('风和日丽', 250, 250)

全图显示方法:ctx.drawImage(img,x,y)
- img 为图片对象,采用new Image()方式
- x,y 为图片左上角的坐标;
裁剪显示方法:ctx.drawImage(img,xs,ys,sWidth,sHeight,x,y,width,heigth)
- xs,ys,表示开始裁剪的位置坐标
- sWidth,sHeight 表示裁剪的宽高
- x,y 表示图片在画布上显示的位置坐标
- width,height 表示要使用的图像的宽高(sheng)
- // 创建图片
- let img = new Image()
- img.src = './imgs/fengjing.jpeg'
- img.onload = function () {
- /**
- * 获取当前图片的属性,宽高
- */
- console.log(img.width, img.height);
- // ctx.drawImage(img, 100, 100)
- ctx.drawImage(img, 0, 0, 100, 100, 100, 100, 50, 50)
- }
- x,y 表获取起始点坐标
- width,height 表示宽高
ctx.getImageData(x,y,w,h)返回一个对象,包含了所获取的像素块的像素内容,包含了 该块图像的每一个像素,每一个像素点信息 = rgba(0-255,0-255,0-255,0-255),前三个数据表示红绿蓝,第四个数据表示 透明度(0-255)
- imgData 表示要放回画布的 ImageData 对象
- x,y 表示 ImageData 对象左上角的x,y坐标,以像素点计算
- dirtyX,dirtyY 可选。表示在画布上放置图像的位置
- dirtyWidth,dirtyHeight 可选。表示在画布上绘制图像所使用的宽高
- // 1.创建图片
- let img = new Image();
- img.src = './imgs/fengjing.jpeg';
- img.onload = function () {
- // 绘制图片
- ctx.drawImage(img, 0, 0);
-
- let copy = ctx.getImageData(0, 0, 100, 100)
- console.log(copy);
- /*
- putImageData(imgData,x,y,dirtyX,dirtyY,dirtyWidth,dirtyHeight)
- - imgData 表示要放回画布的 ImageData 对象
- - x,y 表示 ImageData 对象左上角的x,y坐标,以像素点计算
- - dirtyX,dirtyY 可选。表示在画布上放置图像的位置
- - dirtyWidth,dirtyHeight 可选。表示在画布上绘制图像所使用的宽高
- */
- ctx.putImageData(copy, 0, 650)// 可以在原图片上扣取一部分图片重新绘制到指定地方;
- }

重要点为:小球碰到边缘如何反弹,本质是小球的速度(也就是坐标的变化距离),当小球的坐标+半径和 到了边缘时,设置小球往方向跑
- 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>Documenttitle>
- <style>
- * {
- margin: 0;
- padding: 0;
- }
- canvas {
- margin: 50px auto;
- display: block;
- border: 1px solid #ccc;
- }
- style>
- head>
- <body>
- <canvas width="600" height="600">默认参数canvas>
- <script>
- let c = document.querySelector('canvas')
- let ctx = c.getContext('2d')
- /*
- 小球运动的本质就是定时器重新绘制小球
- */
- let w = h = 600
- let x = 100;
- let y = 100
- let r = 20
- let xSpeed = 3;
- let ySpeed = 4
- setInterval(function () {
- ctx.clearRect(0, 0, w, h)
- // 小球坐标的变化
- drawCircle(x, y, r, 'red')
- if (x + r >= w || x - r <= 0) {
- xSpeed = -xSpeed;
- }
- x += xSpeed
-
- if (y + r >= h || y - r <= 0) {
- ySpeed = -ySpeed;
- }
- y += ySpeed
-
- }, 10)
-
- function drawCircle(x, y, r, color = '#000') {
- ctx.beginPath();
- ctx.arc(x, y, r, 0, Math.PI * 2);
- ctx.fillStyle = color;
- // ctx.fill()方法是实心着色
- ctx.fill()
- // 着色,不可缺,没有着色是不能看到的
- // ctx.stroke() 是空心着色
- // ctx.stroke();
- ctx.closePath();
- }
- script>
- body>
- html>
面向对象的本质是对小球对象的封装,小球移动和绘制方法的封装;
- <body>
- <canvas width="600" height="600">默认参数canvas>
- <script>
- let c = document.querySelector('canvas')
- let ctx = c.getContext('2d')
- /*
- 小球运动的本质就是定时器重新绘制小球
- */
- let w = h = 600
-
- // 创建随机数
- function ranD(num) {
- return Math.random() * num
- }
- // 创建一个小球对象
- class Ball {
- constructor() {
- this.r = ranD(30) + 20;
- this.x = ranD(500) + 60;
- this.y = ranD(500) + 60;
- this.xSpeed = ranD(3) + 2;
- this.ySpeed = ranD(3) + 1;
- this.color = "#" + parseInt(ranD(1) * 0xffffff).toString(16)
- }
- // 小球显示的方法
- show() {
- ctx.beginPath();
- ctx.arc(this.x, this.y, this.r, 0, Math.PI * 2);
- ctx.fillStyle = this.color;
- ctx.fill()
- ctx.closePath();
- }
-
- // 小球运动的方法
- run() {
- if (this.x + this.r >= w || this.x - this.r <= 0) {
- this.xSpeed = -this.xSpeed;
- }
- this.x += this.xSpeed
-
- if (this.y + this.r >= h || this.y - this.r <= 0) {
- this.ySpeed = -this.ySpeed;
- }
- this.y += this.ySpeed
- }
- }
- // 创建小球
- let ballArr = []
- for (let i = 0; i < 20; i++) {
- var ball = new Ball()
- ballArr.push(ball)
- ball.show()
- }
- console.log(ballArr);
-
- // 小球运动
- setInterval(function () {
- ctx.clearRect(0, 0, w, h)
- for (let i = 0; i < ballArr.length; i++) {
- ballArr[i].show()
- ballArr[i].run()
- }
- }, 10)
- script>
- body>
-
- html>
小球之间连线的本质是 选取小球之间的圆心,不断动态重新绘制直线
- <body>
- <canvas width="600" height="600">默认参数canvas>
- <script>
- let c = document.querySelector('canvas')
- let ctx = c.getContext('2d')
- /*
- 小球运动的本质就是定时器重新绘制小球
- */
- let w = h = 600
-
- // 创建随机数
- function ranD(num) {
- return Math.random() * num
- }
- // 创建一个小球对象
- class Ball {
- constructor(text) {
- this.r = ranD(30) + 20;
- this.x = ranD(500) + 50;
- this.y = ranD(500) + 50;
- this.xSpeed = ranD(3) + 2;
- this.ySpeed = ranD(3) + 1;
- this.color = "#" + parseInt(ranD(1) * 0xffffff).toString(16);
- this.text = text;
- }
- // 画圆;小球显示的方法
- show() {
- drawCircle(this.x, this.y, this.r, this.color);// 画圆
- drawText(this.r, this.text, this.x + this.r, this.y, this.color);// 画文字
- }
-
- // 小球运动的方法
- run() {
- if (this.x + this.r >= w - 60 || this.x - this.r <= 0) {
- this.xSpeed = -this.xSpeed;
- }
- this.x += this.xSpeed
-
- if (this.y + this.r >= h || this.y - this.r <= 0) {
- this.ySpeed = -this.ySpeed;
- }
- this.y += this.ySpeed
- }
- }
- // 画直线
- function drawLine(x1, y1, x2, y2, color = "#000") {
- ctx.beginPath();
- ctx.moveTo(x1, y1);
- ctx.lineTo(x2, y2);
- ctx.strokeStyle = color;
- ctx.stroke();
- ctx.closePath();
- }
-
- // 画字体
- function drawText(font, text, x, y, color = '#000') {
- ctx.font = `${font}px 宋体`;
- ctx.textAlign = 'left';
- ctx.textBaseline = 'middle';
- ctx.fillStyle = color;
- ctx.fillText(text, x, y, 60)
- }
-
- // 画圆
- function drawCircle(x, y, r, color) {
- ctx.beginPath();
- ctx.arc(x, y, r, 0, Math.PI * 2);
- ctx.fillStyle = color;
- ctx.fill()
- ctx.closePath();
- }
-
- // 文字数据
- let titleText = 'Java PHP JS GO Vue Angular jQuery CSS HTML Bootstrap webGL ThreeJs ElementUI UI AXIOS ajax'.split(' ')
-
- // 创建小球
- let ballArr = []
- for (let i = 0; i < 6; i++) {
- var ball = new Ball(titleText[i])
- ballArr.push(ball)
- ball.show()
- }
- console.log(ballArr);
- // 小球运动
- setInterval(function () {
- ctx.clearRect(0, 0, w, h)
- for (let i = 0; i < ballArr.length; i++) {
- ballArr[i].show()
- ballArr[i].run()
-
- /*
- 小球连线
- */
- for (let j = 0; j < i; j++) {
- drawLine(ballArr[i].x, ballArr[i].y, ballArr[j].x, ballArr[j].y, ballArr[i].color)
- }
- }
- }, 10)
-
-
- script>
- body>
-
- html>

- <body>
- <canvas>默认参数canvas>
- <script>
- let c = document.querySelector('canvas')
- let ctx = c.getContext('2d')
- /*
- 小球运动的本质就是定时器重新绘制小球
- */
- let w = document.documentElement.clientWidth - 10
- let h = document.documentElement.clientHeight - 10
- c.width = w;
- c.height = h
- // 创建随机数
- function ranD(num) {
- return Math.random() * num
- }
- // 创建一个小球对象
- class Ball {
- constructor(x, y) {
- this.r = 60;
- this.x = x;
- this.y = y;
- this.color = "#" + parseInt(ranD(1) * 0xffffff).toString(16);
- }
- // 画圆;小球显示的方法
- show() {
- this.r--;// 小球直径减小
- if (this.r <= 0) return
- drawCircle(this.x, this.y, this.r, this.color);// 画圆
- }
- }
-
- // 画圆
- function drawCircle(x, y, r, color) {
- ctx.beginPath();
- ctx.arc(x, y, r, 0, Math.PI * 2);
- ctx.fillStyle = color;
- ctx.fill()
- ctx.closePath();
- }
-
- // 创建小球
- let ballArr = []
- // 小球的坐标跟着鼠标的位置而移动
- window.onmousemove = function (event) {
- console.log(event.x, event.y);
- var ball = new Ball(event.x, event.y)
- ballArr.push(ball)
- ball.show()
- }
- // 拿到小球对象集合
- console.log(ballArr);
- // 小球运动
- setInterval(function () {
- ctx.clearRect(0, 0, w, h)
- for (let i = 0; i < ballArr.length; i++) {
- ballArr[i].show()
- }
- }, 8)
-
-
- script>
- body>
-
- html>

最后附上写的比较好的大佬的博客,感谢参考!!