demo 地址:

https://lyf521.github.io/docs/blog/animation/meteorshower.html

要点一: canvas平面动画需要不断重复计算x,y的坐标位置

  1. // 设定坐标类
  2. class Crood {
  3. // 创建类的属性、默认值
  4. constructor(x=0,y=0){
  5. this.x = x
  6. this.y = y
  7. }
  8. // 重新设置值
  9. setCrood (x,y){
  10. this.x = x
  11. this.y = y
  12. }
  13. // 复制当前坐标
  14. copy (){
  15. return new Crood(this.x, this.y)
  16. }
  17. }

要点二: 将数组中某个数据移除

  1. remove(star){
  2. this.stars = this.stars.filter((s) => {return s !== star})
  3. }

要点三:requestAnimationFrame

requestAnimationFrame()的原理其实与setTimeout和setInterval类似,通过递归调用同一方法来不断更新画面以达到动画效果,但它优于setTimeout和setInterval的地方在于它是由浏览器专门为动画提供优化实现的API,并且充分利用显示器的刷新机制,比较节省系统资源。显示器有固定的刷新频率(60Hz或75Hz),也就是说,每秒最多只能重绘60次或75次,requestAnimationFrame的基本思想就是与这个刷新频率保持同步,利用这个刷新频率进行页面重绘。此外,使用这个API,一旦页面不处于浏览器的当前标签,就会自动停止刷新。这就节省了CPU、GPU和电力
不过有一点需要注意,requestAnimationFrame是在主线程上完成。这意味着,如果主线程非常繁忙,requestAnimationFrame的动画效果会大打折扣。

  1. // 采用requestAnimationFrame() 帧动画
  2. tick(){
  3. if (this.playing) return
  4. this.playing = true
  5. let now = (new Date()).getTime()
  6. let last = now
  7. let delta // 帧时间
  8. // 兼容性
  9. if (!window.requestAnimationFrame){
  10. window.requestAnimationFrame = (window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.msRequestAnimationFrame || window.pRequestAnimationFrame || function(callback){return setTimeout(callback,Math.floor(1000/60))})
  11. }
  12. // 帧执行 函数
  13. let _tick = () => {
  14. if (this.stop && this.stars.length === 0){
  15. cancelAnimationFrame(this.T)
  16. this,playing = false
  17. return
  18. }
  19. // 获取帧时间,30到16之间
  20. delta = now - last
  21. delta = delta > 500 ? 30 : (delta < 16 ? 16 : delta)
  22. last = now
  23. this.T = window.requestAnimationFrame(_tick)
  24. ctx.save()
  25. ctx.fillStyle = 'rgba(0,0,0,0.2)' // 每一帧用 半透明 覆盖一次画布
  26. ctx.restore()
  27. this.updata(delta)
  28. }
  29. }

要点四: 同时画20个流星

  1. updata(delta){
  2. if (!this.stop && this.stars.length < 20) {
  3. this.stars.push(this.createStar())
  4. }
  5. this.stars.forEach((star) => {
  6. star.draw(this.ctx,delta)
  7. })
  8. }