demo 地址:
https://lyf521.github.io/docs/blog/animation/meteorshower.html
要点一: canvas平面动画需要不断重复计算x,y的坐标位置
// 设定坐标类
class Crood {
// 创建类的属性、默认值
constructor(x=0,y=0){
this.x = x
this.y = y
}
// 重新设置值
setCrood (x,y){
this.x = x
this.y = y
}
// 复制当前坐标
copy (){
return new Crood(this.x, this.y)
}
}
要点二: 将数组中某个数据移除
remove(star){
this.stars = this.stars.filter((s) => {return s !== star})
}
要点三:requestAnimationFrame
requestAnimationFrame()的原理其实与setTimeout和setInterval类似,通过递归调用同一方法来不断更新画面以达到动画效果,但它优于setTimeout和setInterval的地方在于它是由浏览器专门为动画提供优化实现的API,并且充分利用显示器的刷新机制,比较节省系统资源。显示器有固定的刷新频率(60Hz或75Hz),也就是说,每秒最多只能重绘60次或75次,requestAnimationFrame的基本思想就是与这个刷新频率保持同步,利用这个刷新频率进行页面重绘。此外,使用这个API,一旦页面不处于浏览器的当前标签,就会自动停止刷新。这就节省了CPU、GPU和电力
不过有一点需要注意,requestAnimationFrame是在主线程上完成。这意味着,如果主线程非常繁忙,requestAnimationFrame的动画效果会大打折扣。
// 采用requestAnimationFrame() 帧动画
tick(){
if (this.playing) return
this.playing = true
let now = (new Date()).getTime()
let last = now
let delta // 帧时间
// 兼容性
if (!window.requestAnimationFrame){
window.requestAnimationFrame = (window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.msRequestAnimationFrame || window.pRequestAnimationFrame || function(callback){return setTimeout(callback,Math.floor(1000/60))})
}
// 帧执行 函数
let _tick = () => {
if (this.stop && this.stars.length === 0){
cancelAnimationFrame(this.T)
this,playing = false
return
}
// 获取帧时间,30到16之间
delta = now - last
delta = delta > 500 ? 30 : (delta < 16 ? 16 : delta)
last = now
this.T = window.requestAnimationFrame(_tick)
ctx.save()
ctx.fillStyle = 'rgba(0,0,0,0.2)' // 每一帧用 半透明 覆盖一次画布
ctx.restore()
this.updata(delta)
}
}
要点四: 同时画20个流星
updata(delta){
if (!this.stop && this.stars.length < 20) {
this.stars.push(this.createStar())
}
this.stars.forEach((star) => {
star.draw(this.ctx,delta)
})
}