我相信有很多小伙伴和我一样,在面试的时候面试官总喜欢问一个问题就是:让你讲讲HTML5新增的标签,而<canvas>就是其中一个非常重要的标签,但是部分小伙伴可能一开始和我一样回答得不太完整或者回答不出来,接下来让我花10分钟带你从入门到实践讲讲一些常用的知识点。
首先一句话先总结,什么是canvas?canvas顾名思义是画布、画板的意思,所以它是一个画画的载体,也可以理解成是一个画画的容器,那要如何实现在画板上进行画画的操作呢?答案就是通过我们的JS来实现,所以一句话总结:<canvas> 标签只是图形容器,必须使用脚本来绘制图形。
我们先通过一个简单的例子来看一下canvas在实际开发中是怎么运用的:
<!DOCTYPE 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>Document</title>
</head>
<body>
<canvas id="mycanvas" width="200" height="200" style="border:1px solid black"></canvas>
<script>
//获取Canvas元素对应的DOM对象
var canvas = document.getElementById('mycanvas');
//获取Canvas上的绘图的CanvasRenderingContext2D对象
var ctx = canvas.getContext('2d');
//设置笔触线条的宽度
ctx.lineWidth=3;
//将画布的中间点(100,100)设置为原点
ctx.translate(100,100);
//保存当前画布的状态,该状态包含了lineWidth=3,translate(100,100),然后其他那些属性为默认值.
ctx.save();
//设置线条颜色为红色
ctx.strokeStyle='red';
//坐标系统旋转90°
ctx.rotate(Math.PI/2);
//画第一条直线
//因为画笔是默认连续的,我们必须将我们每次画完的图形写在beginPath和closePath里面
ctx.beginPath();
ctx.moveTo(-100,0);
ctx.lineTo(100,0);
ctx.closePath();
//勾勒线条
ctx.stroke();
//恢复之前保存的绘图状态,也就是旋转90°之前的坐标系统
ctx.restore();
//再画第二条直线
ctx.beginPath();
ctx.moveTo(-100,0);
ctx.lineTo(100,0);
ctx.closePath();
//勾勒线条
ctx.stroke();
</script>
</body>
</html>
相信在这个例子中大部分小伙伴都是一看就能够理解的,有点疑问的可能是对于Canvas的save()和restore()这两个方法,save()就是保存当前画布坐标系的一切配置的方法,我们可以理解成新复制一份画布然后对它进行旋转等操作,画完后restore()就是把刚才画好的图和保存前的状态图合并,就以上面的作为例子,请看下图:
然后在旋转后的画布上画出从 (-100,0)到(100,0)的一条红色直线,效果就是:
接着restore(),就是将保存前画布的状态和这个画完后的状态进行合并,注意此时画布又回到一开始保存前的坐标系,所以合并后的效果就是:
接着在此时的这个坐标系再画一条从(-100,0)到(100,0)的黑色直线也就是:
接着po上前端大全公众号给的俩个实战例子,大家学会了之后再拿这俩个小项目练练手估计对canvas的掌握就掌握得7788了。
案例1:用canvas画出一个时钟(它原本的代码思路有点绕不便理解,所以这里我对它加以改变了一下方便大家理解,实现出来的效果都是一样的)
<!DOCTYPE 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>Document</title>
</head>
<body>
<canvas id="mycanvas" width="600px" height="600px"></canvas>
<script>
const canvas = document.getElementById('mycanvas')
const ctx = canvas.getContext('2d')
setInterval(() => {
ctx.save()
ctx.clearRect(0, 0, 600, 600)
// 设置中心点,此时300,300变成了坐标的0,0,坐标x右边为正,坐标y下边为正
ctx.translate(300, 300)
ctx.save()
// 画大圆
ctx.beginPath()
// 画圆线使用arc(中心点X,中心点Y,半径,起始角度,结束角度)
ctx.arc(0, 0, 100, 0, 2 * Math.PI)
// 执行画线段的操作
ctx.stroke()
ctx.closePath()
// 画小圆
ctx.beginPath()
ctx.arc(0, 0, 5, 0, 2 * Math.PI)
ctx.stroke()
ctx.closePath()
// 获取当前时,分,秒
let time = new Date()
let hour = time.getHours() % 12
let min = time.getMinutes()
let sec = time.getSeconds()
// 时针
ctx.rotate(2 * Math.PI / 12 * hour + 2 * Math.PI / 12 * (min / 60))
ctx.beginPath()
// moveTo设置画线起点
ctx.moveTo(0, 0)
// lineTo设置画线经过点
ctx.lineTo(0, -40)
// 设置线宽
ctx.lineWidth = 10
ctx.stroke()
ctx.closePath()
ctx.restore()
ctx.save()
// 分针
ctx.rotate(2 * Math.PI / 60 * min + 2 * Math.PI / 60 * (sec / 60))
ctx.beginPath()
ctx.moveTo(0, 0)
ctx.lineTo(0, -60)
ctx.lineWidth = 5
ctx.strokeStyle = 'blue'
ctx.stroke()
ctx.closePath()
ctx.restore()
ctx.save()
//秒针
ctx.rotate(2 * Math.PI / 60 * sec )
ctx.beginPath()
ctx.moveTo(0, 0)
ctx.lineTo(0, -80)
ctx.strokeStyle = 'red'
ctx.stroke()
ctx.closePath()
ctx.restore()
ctx.save()
// 绘制刻度,也是跟绘制时分秒针一样,只不过刻度是死的
ctx.lineWidth = 1
for (let i = 0; i < 60; i++) {
ctx.rotate(2 * Math.PI / 60)
ctx.beginPath()
ctx.moveTo(90, 0)
ctx.lineTo(100, 0)
// ctx.strokeStyle = 'red'
ctx.stroke()
ctx.closePath()
}
ctx.restore()
ctx.save()
ctx.lineWidth = 5
for (let i = 0; i < 12; i++) {
ctx.rotate(2 * Math.PI / 12)
ctx.beginPath()
ctx.moveTo(85, 0)
ctx.lineTo(100, 0)
// ctx.strokeStyle = 'red'
ctx.stroke()
ctx.closePath()
}
ctx.restore()
ctx.restore()
}, 1000)
</script>
</body>
</html>
运行效果:
案例2:用canvas实现刮刮乐
<!DOCTYPE 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>Document</title>
<style>
.text {
position: absolute;
left: 130px;
top: 35px;
z-index: -1;
}
</style>
</head>
<body>
<canvas id="canvas" width="400" height="100"></canvas>
<div class="text">恭喜您获得100w</div>
<script>
const canvas = document.getElementById('canvas')
const ctx = canvas.getContext('2d')
// 填充矩形的颜色
ctx.fillStyle = 'darkgray'
// 填充矩形 fillRect(起始X,起始Y,终点X,终点Y)
ctx.fillRect(0, 0, 400, 100)
// 绘制填充文字及颜色
ctx.fillStyle = '#fff'
ctx.fillText('刮刮卡', 180, 50)
//设置isDraw的目的就是确保鼠标是真的按下去了,然后才开始刮
let isDraw = false
canvas.onmousedown = function () {
isDraw = true
}
canvas.onmousemove = function (e) {
if (!isDraw) return
// 计算鼠标在canvas里的位置
//e.pageX和e.pageY是鼠标相对于左上角浏览器的位置
//canvas.offsetLeft和canvas.offsetTop是画布canvas相对于左上角原点的位置
//所以获取鼠标在画布里的位置就是e.pageX-canvas.offsetLeft
const x = e.pageX - canvas.offsetLeft
const y = e.pageY - canvas.offsetTop
// 设置globalCompositeOperation
ctx.globalCompositeOperation = 'destination-out'
// 画圆
ctx.arc(x, y, 10, 0, 2 * Math.PI)
// 填充圆形
ctx.fill()
}
canvas.onmouseup = function () {
isDraw = false
}
</script>
</body>
</html>
运行效果:
好了,相信看到这里的小伙伴们都应该大概掌握了canvas这个标签的运用,码字不易,喜欢的并且看完觉得有帮助的麻烦点个收藏加关注,这将是对我莫大的鼓励~