用drawImage 带你做一个花瓣散落的动画
之前我们阅读过canvas的基础api。 但是其中包括有很多较为复杂的api我们直接跳过了。
drawImage 就是其中之一。今天我们就一起来看看他。
drawImage 一个方法包括了两种使用方式:渲染 和 裁剪 。 我们重点看看裁剪。
渲染
在我们渲染图片之前我们需要对图片进行预加载。
function loadImg(url) {
return new Promise((resolve, reject) => {
let img = new Image()
img.onload = function () {
resolve(img)
}
img.src = url
})
}
在图片加载结束之后我们将整个img对象返回。在这个img对象中我们可以拿到对img的宽高和img的实例。 而这个img的实例就是 我们drawImage的第一个参数。
我们使用drawImage对img,在参数0,0坐标处进行渲染。 我们可以看到效果是,图形将按照元是的像素进行渲染。
let img = await loadImg(imgUrl);
let sw = img.width
let sh = img.height
ctx.drawImage(img, 0, 0)
我们可以设置一个缩放比例 将img的长宽高都进行缩放然后在进行渲染。
let ZC = 0.2 // 缩放比例我们将缩放比例设置成20%
// 在0,0这个点 按照缩放比例 ZC对图片进行渲染
ctx.drawImage(img, 0, 0, sw * ZC, sh * ZC)
裁剪
drawImage 还有一个形变的公式,那就是裁剪
下面这段代码表示:
在图片宽度的43.6%高度的58%处截取 宽度为宽度的12.7%高度的24%的图形,放在画布的0,shZC高度处 按5050的大小显示出来
ctx.drawImage(img,sw*0.236,sh*0.58,sw*0.127,sh*0.24,0,sh*ZC,50,50)
花瓣飘落动画
动画原理:
-
花瓣裁剪 我们首先定义一个花的类文件
在这个文件中我们顶一个,Flows数组 讲生成花瓣之后的实例都存放在其中。
另外实例的重点就是play方法讲水平移动 垂直移动的数值计算之后,
使用我们的图片裁剪裁剪出一朵花瓣,最后在画布中运动。
好,好这个类就定义完成了。
看代码。
let Flows = [] // 飘动雪花数组
class Flow {
constructor(x, y, w, img, sw, sh) {
this.x = x
this.y = y
this.w = w
this.img = img
this.sw = sw
this.sh = sh
this.g = Math.random() * 3+1 // 重力加速度
this.v = - (Math.random() * 2) // 水平移动速度
Flows.push(this)
}
play() {
let img = this.img
let sw = this.sw
let sh = this.sh
this.x -= this.v
this.y += this.g
// 最初始值绘图
ctx.drawImage(img,sw*0.236,sh*0.58,sw*0.127,sh*0.24,this.x, this.y,100*this.w/10,100*this.w/10)
// 达到零界点清除
if(this.y > canvas.height){
this.clear()
}
}
clear() {
let index = Flows.indexOf(this)
Flows.splice(index,1)
}
}
-
花瓣运动
因为我们封装的图片加载是promise,我想使用异步的方式,
我们顶一个了一个立即执行函数,在图片加载完成之后 ,我们开启生成花瓣的函数。
没什么东西可以说的,理解了就很简单。
看代码。
let canvas = document.getElementById('canvas')
let ctx = canvas.getContext('2d')
canvas.height = window.innerHeight
canvas.width = window.innerWidth
let imgUrl = 'https://bloggers-1304641141.cos.ap-beijing.myqcloud.com/img/1631072101978.png'
function loadImg(url) {
return new Promise((resolve, reject) => {
let img = new Image()
img.onload = function () {
resolve(img)
}
img.src = url
})
}
( async () => {
let img = await loadImg(imgUrl);
let sw = img.width
let sh = img.height
let ZC = 0.2
let index = 0
new Flow(Math.random() * canvas.width/2, 0, Math.random() * 8, img, sw, sh)
new Flow(Math.random() * canvas.width/2, 0, Math.random() * 8, img, sw, sh)
// 60帧每秒渲染
setInterval(() => {
ctx.clearRect(0, 0, canvas.width, canvas.height)
// // 生产花朵
if (index % 50 === 0) {
new Flow(Math.random() * canvas.width, 0, Math.random() * 4+3,img,sw,sh)
}
for (let i = 0; i < Flows.length; i++) {
let element = Flows[i]
element.play()
}
index++
}, 1000 / 60)
})()