canvas
canvas是HTML5中才引入的元素。canvas元素为网页提供了可以通过JavaScript完成绘画的画布。可通过编写canvas元素脚本在网页上生成动态图形和复杂的视觉效果。你甚至可以通过对canvas元素编写脚本,在页面上生成蒙娜丽莎。
通过完成环形进度条和随机验证码这两个小案例掌握canvas。
使用步骤
创建画布
canvas是HTML标签。在HTML中,通过<canvas></canvas>
创建一个画布,也可以指定特定的高度和宽度。eg:
<canvas id="canvas" width="500" height="500"></canvas>
效果如图:
获取canvas元素
要使JavaScript和html进行交互,就需要通过JavaScript获取html中的元素:
let canvas = document.getElementById('canvas')
通过getContext('2d')
获取canvas元素的二维绘图上下文对象:
var ctx = canvas.getContext('2d');
有了这个对象就可以通过使用这个对象的方法和属性进行绘制操作。
绘制
- 常用绘制属性:
-
width
和height
:控制画布的高度和宽度。 -
fillStyle
:控制填充颜色。 -
strokeStyle
:控制描边颜色。 -
lineWidth
:控制线条的宽度。
-
- 常用绘制方法:
-
fillRect(x, y, width, height)
:填充矩形。 -
strokeRect(x, y, width, height)
:绘制矩形的边框。 -
beginPath()
和closePath()
:开始和结束一个路径。 -
moveTo(x, y)
:将当前绘制点移动到指定的坐标 。 -
lineTo(x, y)
:在当前路径上添加一条从当前点到指定坐标点的直线段。 -
fill()
:填充路径。 -
stroke()
:描边路径。 -
arc(x, y, radius, startAngle, endAngle, counterclockwise)
:绘制圆形,其中(x,y)是圆心,radius是半径,startAngle和endAngle是开始和结束的弧度,counterclockwise是是否逆时针。 -
clearRect(x, y, width, height)
: 清除指定区域。 -
save()
和restore()
:保存和恢复绘图状态栈。
-
实现动画效果
结合JavaScript的事件监听和定时器实现动画效果。
圆形进度条
html部分
创建一个宽高皆为500px,背景颜色为黑色的canvas画布。
<canvas id="canvas" width="500" height="500" style="background-color: black;"></canvas>
JavaScript部分
初始化变量
let canvas = document.getElementById('canvas'),
ctx = canvas.getContext('2d'),
centerX = canvas.width / 2,
centerY = canvas.height / 2,
rad = Math.PI * 2 / 100,
speed = 0.1
- 获取页面的canvas元素和其2D绘图上下文。
- 计算画布的中心点。
- 将360度分成100份作为每次增加的度数。
- 初始化动画的速度为0.1。
绘制圆环
function drawCircle(n) {
ctx.save()
ctx.strokeStyle = '#fff'//设置线条颜色
ctx.lineWidth = 5//设置线条宽度
ctx.beginPath()
ctx.arc(centerX, centerY, 100, -Math.PI / 2, -Math.PI / 2 + n * rad)
ctx.stroke()
ctx.closePath()
ctx.restore()
}
- 通过
ctx.save()
保存当前的Canvas绘图上下文的状态,然后继续绘制操作,再通过ctx.restore()
恢复到这个保存的状态。 - 通过
ctx.beginPath()
开始一个新的路径,防止与之前的图形相连。 - 通过
ctx.arc(centerX, centerY, 100, -Math.PI / 2, -Math.PI / 2 + n * rad)
绘制一个圆心为画布中心点,半径为100,起始角度为-Math.PI / 2
,结束角度为-Math.PI / 2 + n * rad
的圆弧。 - 调用
stroke()
来绘制线条。 - 使用
closePath()
结束路径。 - 使用
restore()
恢复之前保存的绘图状态。
绘制百分比
function drawNumber(n) {
ctx.save()
ctx.strokeStyle = '#fff'//设置描边颜色
ctx.font = '40px Arial'//设置字体和字体大小
ctx.strokeText(n.toFixed(0) + '%', centerX - 40, centerY + 10)
ctx.restore()
}
一样的操作,先保存绘图状态,然后继续绘制操作,再恢复绘图状态。
其中的绘制操作是ctx.strokeText(n.toFixed(0) + '%', centerX - 40, centerY + 10)
,效果是在圆环中心添加当前的speed
值四舍五入到整数,然后加上百分号。
动画循环
(function draw() {
requestAnimationFrame(draw)
ctx.clearRect(0, 0, canvas.width, canvas.height)
drawNumber(speed)
drawCircle(speed)
if (speed >= 100) {
return speed = 100
}
speed += 0.1
})()
通过一个立即执行函数开始进行递归操作。
requestAnimationFrame是个用于在页面重绘之前执行特定代码的方法。每次调用requestAnimationFrame 会在下次浏览器重绘之前执行传入的回调函数,从而实现连续、流畅的动画效果。
通过执行 ctx.clearRect(0, 0, canvas.width, canvas.height)
在每一帧开始的时候就清除整个画布,进行重新绘制。
调用drawNumber(speed)
和drawCircle(speed)
绘制环形进度条和进度百分比。
当speed
达到100时停止增加,并且让其重置为100。
在每一帧结束的时候,speed
值增加0.1,模拟进度增加的效果。
最终效果
随机验证码
html部分
创建一个宽为120,高为40,并且具有点击事件的画布。在点击画布区域时就会重新生成一个验证码。
<canvas id="canvas" width="120" height="40" onclick="draw()"></canvas>
JavaScript部分
初始化变量
let pool = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890'
定义了一个字符串,其中包含了所有可能用于生成验证码的大写字母和数字。
随机数生成函数
function randomNum(min, max) {
return Math.floor(Math.random() * (max - min) + min)
}
通过Math.random() * (max - min) + min
生成一个在min
和max
之间的随机数,并且通过Math.floor()
对该随机数进行向下取整。
随机颜色生成函数
function randomColor(min, max) {
const r = randomNum(min, max)
const g = randomNum(min, max)
const b = randomNum(min, max)
return `rgb(${r},${g},${b})`
}
通过调用三次随机数生成函数生成三个随机数作为rgb的三个参数,最后通过生成的三个随机数生成一个随机的颜色并返回。
主函数
function draw() {
let canvas = document.getElementById("canvas");
let ctx = canvas.getContext("2d");
ctx.fillStyle = randomColor(100, 230)
ctx.fillRect(0, 0, canvas.width, canvas.height)
let imgCode = ''
//随机生成验证码
for (let i = 0; i < 4; i++) {
const text = pool[randomNum(0, pool.length)]
imgCode += text
const fontSize = randomNum(18, 40)
const deg = randomNum(-30, 30)
ctx.font = `${fontSize}px Simhei`
ctx.textBaseline = 'top'
ctx.fillStyle = randomColor(80, 150)
ctx.save()
ctx.translate(30 * i + 15, 15)
ctx.rotate((deg * Math.PI) / 180)
ctx.fillText(text, -10, -15)
ctx.restore()
}
//随机生成干扰线段
for (let i = 0; i < 5; i++) {
ctx.beginPath()
ctx.moveTo(randomNum(0, canvas.width), randomNum(0, canvas.height))
ctx.lineTo(randomNum(0, canvas.width), randomNum(0, canvas.height))
ctx.strokeStyle = randomColor(100, 230)
ctx.closePath()
ctx.stroke()
}
//随机生成干扰点
for (let i = 0; i < 40; i++) {
ctx.beginPath()
ctx.arc(randomNum(0, canvas.width), randomNum(0, canvas.height), 1, 0, 2 * Math.PI)
ctx.fillStyle = randomColor(150, 200)
ctx.closePath()
ctx.fill()
}
}
- 首先获取canvas元素,并且获取其2D渲染上下文。
- 在100到230的区间内随机生成一个填充颜色作为画布的颜色。
- 定义一个
imgCode
变量并且赋值为空字符串,为了通过用imgCode
拼接验证码字符形成新的字符串。 - 通过第一个for循环,循环4遍在画布上生成4个随机的验证码字符,具体的操作如下:
- 通过生成一个字符串的随机下标实现随机产生一个随机字符,再通过
imgCode
进行拼接。 - 为验证码字符设置随机字体大小、随机旋转角度和随机颜色。
- 通过
ctx.translate(30 * i + 15, 15)
使每个字符的位置都不同,防止重复重叠;通过ctx.rotate((deg * Math.PI) / 180)
使字符具有倾斜角度;最后绘制字符形状。
- 通过生成一个字符串的随机下标实现随机产生一个随机字符,再通过
- 通过第二个for循环,循环5遍在画布上生成5个随机的干扰线段。对线段的起点和终点进行随机生成,并且随机生成线段的颜色。
- 通过第三个for循环,循环40遍在画布上生成40个随机的干扰点。通过
ctx.arc(randomNum(0, canvas.width), randomNum(0, canvas.height), 1, 0, 2 * Math.PI)
生成随机位置的半径为1的小圆点,再对小圆点设置随机颜色。