最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • canvas动画实战与性能优化

    正文概述 掘金(yancy__)   2020-12-13   318

    插播一篇关于 canvas 动画及性能优化的文章,为我们可以更好的进入到 webgl 的世界奠定基础。

    本篇文章的内容可能会稍难理解,还希望大家有问题及时提出。闲话我们就不多说了,开始今天的正题吧。

    1. 动画实战

    首先介绍一下我们要实现的动画内容: 夜空中的流星源码

    今天就来跟大家详细分享一下如何进行编写 canvas 动画以及如何进行优化。

    1.1 搭建页面

    canvas的页面组成是非常简单的。如下所示:

    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <title>canvas动画和性能优化实战</title>
      <!-- 引入页面的样式 -->
      <link rel="stylesheet" href="./style/index.css">
    </head>
    <body>
      <canvas id="shooting-star">您的浏览器不支持canvas标签,请升级版本或选择其他浏览器</canvas>
    </body>
    </html>
    <!-- 引入页面的功能 -->
    <script src="./js/index.js"></script>
    

    创建一个 html 文件,并且引入 css 和 js 文件。

    这里有一个问题,之前我们跟大家分享的时候说,canvas标签的宽和高要在html中进行设置。但是为了适配我们的屏幕,就得用js来设置画布的宽和高。

    1.2 具体实现

    1. 首先创建一个流星的类。并添加一个启动的方法
    class ShootingStar{
      // 构造方法
      constructor() {}
      // 启动的方法
      start() {}
    }
    // 实例化一个对象,并启动
    new ShootingStar().start();
    
    2. 获取到 canvas 对象和绘图上下文,并设置 canvas 的宽和高

    注意:这里设置宽高是因为画布会出现模糊的现象。

    // 构造方法
    constructor() {
    	// 获取canvas对象
      this.ctx = document.getElementById('id名称');
      // 获取绘图上下文
      this.c = this.ctx.getContext('2d');
      // 获取当前页面的宽高
      this.maxW = document.body.offsetWidth;
      this.maxH = document.body.offsetHeight;
      
      // 定义一个数组,用来存放夜空中星,之后的开发中会用到
      this.skyList = [];
    }
    // 初始化画布的宽和高
    initCanvasSize() {
      this.ctx.width = this.maxW;
      this.ctx.height = this.maxH;
    }
    // 在起始方法中调用初始化函数
    start() {
      this.initCanvasSize();
    }
    
    3. 绘制背景

    这里我们没有引入图片,是模拟了一个星空的效果,略微简陋。

    // 绘制背景
    drawBackground() {
      // 夜空中星的数量
      const maxCount = 500;
      // 创建一个黑色的纯色背景
      this.c.fillRect(0, 0, this.ctx.width, this.ctx.height);
    
      // 创建随机坐标。在当前页面内随机
      for (let i = 0; i < maxCount; i++) {
        const r = ~~(Math.random() * 3);
        const x = ~~(Math.random() * this.maxW);
        const y = ~~(Math.random() * this.maxH);
    
        // 将随机坐标推入数组中
        this.skyList.push({
          x,y,r
        })
      }
    }
    
    4. 开启流星模式
    // 初始化背景,并重新开始绘制流星
    initBackground() {
      this.c.beginPath();
      this.c.fillStyle = 'rgba(0,0,0,0.2)';
      // 清空当前画布
      this.c.rect(0,0,this.maxW, this.maxH);
      this.c.fill();
      // 重新绘制背景
      this.drawStarList();
      // 重新开始绘制流星
      this.startShootingStar();
    }
    // 绘制流星
    drawStar(x, y) {
      this.drawStarList()
      this.c.beginPath();
      this.c.fillStyle = 'white';
      this.c.arc(x,y,2,0,Math.PI * 2);
      this.c.fill();
    }
    // 添加拖尾效果
    drawCover() {
      this.c.beginPath();
      this.c.fillStyle = 'rgba(0,0,0,0.06)';
      this.c.rect(0,0,this.ctx.width,this.ctx.height);
      this.c.fill();
    }
    // 开启流星模式
    startShootingStar() {
      // 设置x和y的运动速度
      let x = ~~(Math.random() * this.maxW);
      let y = 4;
      // 设置流星的颜色。
      this.c.fillStyle = 'darkorange';
      // 获取一个流星滑落的最大距离。到这个距离之后消失
      const clearY = Math.random() * this.maxH;
    
      // 绘制函数。
      const draw = () => {
        x -= 1;
        y += 4;
    
        // 如果当前滑落的距离大于最大距离,初始化当前背景。
        if (y >= clearY) {
          this.initBackground();
          return;
        }
    
    		// 绘制流星,传入当前的 x、y 坐标
        this.drawStar(x, y);
        // 此函数用来使流星有拖尾效果。
        this.drawCover();
        // 使用此函数实现动画效果
        requestAnimationFrame(draw);
      }
      draw()
    }
    

    到这里动画实战部分的内容就分享完了,有兴趣的同学可以查看下源码,也可以试着自己实现以下。

    2. 性能优化

    2.1 使用计算代替频繁的渲染

    绘制过程中,通常会使用计算来代替频繁的画布渲染。原理类似于 dom回流。因为 canvas 也是属于 dom 的部分,过多的操作会影响性能。当然,如果你使用一个特别消耗实现的算法的话就另当别论了。

    2.2 使用 requestAnimationFrame

    很多情况下,我们都习惯于使用 setInterval、setTimeout 来实现页面中的动画。也有很多小伙伴发现这种实现会出现丢帧的现象。原因有二:

    • setInterval、setTimeout 依赖于浏览器的异步循环,因而我们设定的动画执行时间可能并不是真正的动画执行时间,可能这个时候的 js引擎 正在执行其他代码,所以就会出现丢帧的情况。
    • 刷新频率收屏幕分辨率和屏幕尺寸影响。不同设备的屏幕刷新率可能不同。

    针对以上两点内容,我们使用 requestAnimationFrame 来优化动画实现。相对于前者,它有两点明显的优势

    • 由系统来决定回调的执行时机,在执行时浏览器会优化方法的调用。
    • 按帧进行重绘,通过 requestAnimationFrame 调用回调函数引起的页面重绘或回流的时间间 隔和显示器的刷新时间间隔相同。所以 requestAnimationFrame 不需要像 setTimeout 那样传递时间间隔,而是浏览器通过系统获取并使用显示器刷新频率

    2.3 离屏渲染

    离屏渲染可以理解为创建一个备用canvas但是不显示到页面上,执行预渲染操作。此项操作用到了drawImage 这个方法,此方法第一个参数可以接受一个图片对象或者是一个**canvas 对象**。

    具体实现:

    将需要操作的内容在离屏的canvas上先处理好,之后再使用drawImage方法放入到显示层。

    2.4 分层画布

    也是使用多个canvas的方式,将静态的内容和需要频繁计算的内容分开渲染,越复杂的场景越适合使用此方法。具体实现如下

    示意图: canvas动画实战与性能优化

    通过这种方式可以将我们的需求拆分为多个模块。将需要频繁绘制的内容拆分出来,从而减少性能的消耗。

    性能优化方式主要是一些日常的注意点和拆分方式,并不是万能的。

    canvas的动画实现中,算法也占据了很大一部分,比如canvas中的粒子操作,动辄就是成千上万的像素点,算法的使用不当可能会带来很大的问题。

    好了,今天的分享就到这里了,临时插播的一条内容。接下来会分享关于 webgl 的内容,版兴趣的同学不要错过哟。Bye~


    起源地下载网 » canvas动画实战与性能优化

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元