浅谈运用缓存文件来提升HTML5 Canvas程序流程的特

日期:2021-02-25 类型:科技新闻 

关键词:小程序开发者工具,小程序在线生成平台,小程序编辑,免费的小程序,微信小程序在哪里

canvas玩多了后,就会全自动的要刚开始考虑到特性难题了。如何提升canvas的动漫呢?

  【应用缓存文件】

  应用缓存文件也便是用离屏canvas开展预3D渲染了,基本原理很简易,便是先绘图到1个离屏canvas中,随后再根据drawImage把离屏canvas画到主canvas中。将会看到这许多人就会误会,这并不是写手机游戏里边用的许多的双缓存体制么?

  实际上要不然,双缓存体制是手机游戏程序编写中以便避免画面闪动,因而会有1个显示信息在客户眼前的画布和1个后台管理画布,开展绘图时会先将画面內容绘图到后台管理画布中,再将后台管理画布里的数据信息绘图到前台接待画布中。这便是双缓存,可是canvas中是沒有双缓存的,由于当代访问器基础上全是内嵌了双缓存体制。因此,应用离屏canvas其实不是双缓存,而是把离屏canvas当做1个缓存文件区。把必须反复绘图的画面数据信息开展缓存文件起来,降低启用canvas的API的耗费。

  大家都知道,启用canvas的API很耗费特性,因此,当大家要绘图1些反复的画面数据信息时,妥善运用离屏canvas对特性层面有很大的提高,能够看下下面的DEMO

  1 、 没应用缓存文件   

  2、  应用了缓存文件可是沒有设定离屏canvas的宽高  

      3 、 应用了缓存文件可是沒有设定离屏canvas的宽高  

  4 、 应用了缓存文件且设定了离屏canvas的宽高

  能够看到上面的DEMO的特性不1样,下面剖析1下缘故:以便完成每一个圈的款式,因此绘图圈圈时我用了循环系统绘图,假如没用开启缓存文件,当网页页面的圈圈数量做到1定时执行,动漫每帧就要很多启用canvas的API,要开展很多的测算,这样再好的访问器也会被拖垮啦。
XML/HTML Code拷贝內容到剪贴板

  1. ctx.save();   
  2.                         var j=0;   
  3.                         ctx.lineWidth = borderWidth;   
  4.                         for(var i=1;i<this.r;i+=borderWidth){   
  5.                             ctx.beginPath();   
  6.                             ctx.strokeStyle = this.color[j];   
  7.                             ctx.arc(this.x , this.y , i , 0 , 2*Math.PI);   
  8.                             ctx.stroke();   
  9.                             j++;   
  10.                         }   
  11.                         ctx.restore();  

  因此,我的方式很简易,每一个圈圈目标里边给他1个离屏canvas作缓存文件区。

  除建立离屏canvas做为缓存文件以外,下面的编码中有1点很重要,便是要设定离屏canvas的宽度和高宽比,canvas转化成后的默认设置尺寸是300X150;针对我的编码中每一个缓存文件起来圈圈目标半径最大也就不超出80,因此300X150的尺寸显著会导致许多空白地区,会导致資源消耗,因此就要设定1下离屏canvas的宽度和高宽比,让它跟缓存文件起来的元素尺寸1致,这样也是有利于提升动漫特性。上面的4个demo很显著的显示信息出了特性差别,假如沒有设定宽高,当网页页面超出400个圈圈目标时就会卡的不好了,而设定了宽高1000个圈圈目标也不感觉卡。

XML/HTML Code拷贝內容到剪贴板
  1. var ball = function(x , y , vx , vy , useCache){   
  2.                 this.x = x;   
  3.                 this.y = y;   
  4.                 this.vx = vx;   
  5.                 this.vy = vy;   
  6.                 this.r = getZ(getRandom(20,40));   
  7.                 this.color = [];   
  8.                 this.cacheCanvas = document.createElement("canvas");   
  9.                 thisthis.cacheCtx = this.cacheCanvas.getContext("2d");   
  10.                 this.cacheCanvas.width = 2*this.r;   
  11.                 this.cacheCanvas.height = 2*this.r;   
  12.                 var num = getZ(this.r/borderWidth);   
  13.                 for(var j=0;j<num;j++){   
  14.                     this.color.push("rgba("+getZ(getRandom(0,255))+","+getZ(getRandom(0,255))+","+getZ(getRandom(0,255))+",1)");   
  15.                 }   
  16.                 this.useCache = useCache;   
  17.                 if(useCache){   
  18.                     this.cache();   
  19.                 }   
  20.             }  

 

当我案例化圈圈目标时,立即启用缓存文件方式,把繁杂的圈圈立即画到圈圈目标的离屏canvas中储存起来。

XML/HTML Code拷贝內容到剪贴板
  1. cache:function(){   
  2.                     this.cacheCtx.save();   
  3.                     var j=0;   
  4.                     this.cacheCtx.lineWidth = borderWidth;   
  5.                     for(var i=1;i<this.r;i+=borderWidth){   
  6.                         this.cacheCtx.beginPath();   
  7.                         thisthis.cacheCtx.strokeStyle = this.color[j];   
  8.                         this.cacheCtx.arc(this.r , this.r , i , 0 , 2*Math.PI);   
  9.                         this.cacheCtx.stroke();   
  10.                         j++;   
  11.                     }   
  12.                     this.cacheCtx.restore();   
  13.                 }  

随后在接下来的动漫中,我只必须把圈圈目标的离屏canvas画到主canvas中,这样,每帧启用的canvasAPI就仅有这么1句话:

XML/HTML Code拷贝內容到剪贴板
  1. ctx.drawImage(this.cacheCanvas , this.x-this.r , this.y-this.r);  

跟以前的for循环系统绘图比起来,确实是快太多了。因此当必须反复绘图矢量图的情况下或绘图好几个照片的情况下,大家都可以以有效运用离屏canvas来预先把画面数据信息缓存文件起来,在接下来的每帧中就可以降低许多没必要的耗费特性的实际操作。

下面贴出1000个圈圈目标顺畅版编码:
  

XML/HTML Code拷贝內容到剪贴板
  1. <!doctype html>  
  2. <html lang="en">  
  3. <head>  
  4.     <meta charset="UTF⑻">  
  5.     <style>  
  6.         body{   
  7.             padding:0;   
  8.             margin:0;   
  9.             overflow: hidden;   
  10.         }   
  11.         #cas{   
  12.             display: block;   
  13.             background-color:rgba(0,0,0,0);   
  14.             margin:auto;   
  15.             border:1px solid;   
  16.         }   
  17.     </style>  
  18.     <title>检测</title>  
  19. </head>  
  20. <body>  
  21.     <div >  
  22.         <canvas id='cas' width="800" height="600">访问器不适用canvas</canvas>  
  23.         <div style="text-align:center">1000个圈圈目标也不卡</div>  
  24.     </div>  
  25.   
  26.     <script>  
  27.         var testBox = function(){   
  28.             var canvas = document.getElementById("cas"),   
  29.                 ctx = canvas.getContext('2d'),   
  30.                 borderWidth = 2,   
  31.                 Balls = [];   
  32.             var ball = function(x , y , vx , vy , useCache){   
  33.                 this.x = x;   
  34.                 this.y = y;   
  35.                 this.vx = vx;   
  36.                 this.vy = vy;   
  37.                 this.r = getZ(getRandom(20,40));   
  38.                 this.color = [];   
  39.                 this.cacheCanvas = document.createElement("canvas");   
  40.                 thisthis.cacheCtx = this.cacheCanvas.getContext("2d");   
  41.                 this.cacheCanvas.width = 2*this.r;   
  42.                 this.cacheCanvas.height = 2*this.r;   
  43.                 var num = getZ(this.r/borderWidth);   
  44.                 for(var j=0;j<num;j++){   
  45.                     this.color.push("rgba("+getZ(getRandom(0,255))+","+getZ(getRandom(0,255))+","+getZ(getRandom(0,255))+",1)");   
  46.                 }   
  47.                 this.useCache = useCache;   
  48.                 if(useCache){   
  49.                     this.cache();   
  50.                 }   
  51.             }   
  52.   
  53.             function getZ(num){   
  54.                 var rounded;   
  55.                 rounded = (0.5 + num) | 0;   
  56.                 // A double bitwise not.   
  57.                 rounded = ~~ (0.5 + num);   
  58.                 // Finally, a left bitwise shift.   
  59.                 rounded = (0.5 + num) << 0;   
  60.   
  61.                 return rounded;   
  62.             }   
  63.   
  64.             ball.prototype = {   
  65.                 paint:function(ctx){   
  66.                     if(!this.useCache){   
  67.                         ctx.save();   
  68.                         var j=0;   
  69.                         ctx.lineWidth = borderWidth;   
  70.                         for(var i=1;i<this.r;i+=borderWidth){   
  71.                             ctx.beginPath();   
  72.                             ctx.strokeStyle = this.color[j];   
  73.                             ctx.arc(this.x , this.y , i , 0 , 2*Math.PI);   
  74.                             ctx.stroke();   
  75.                             j++;   
  76.                         }   
  77.                         ctx.restore();   
  78.                     } else{   
  79.                         ctx.drawImage(this.cacheCanvas , this.x-this.r , this.y-this.r);   
  80.                     }   
  81.                 },   
  82.   
  83.                 cache:function(){   
  84.                     this.cacheCtx.save();   
  85.                     var j=0;   
  86.                     this.cacheCtx.lineWidth = borderWidth;   
  87.                     for(var i=1;i<this.r;i+=borderWidth){   
  88.                         this.cacheCtx.beginPath();   
  89.                         thisthis.cacheCtx.strokeStyle = this.color[j];   
  90.                         this.cacheCtx.arc(this.r , this.r , i , 0 , 2*Math.PI);   
  91.                         this.cacheCtx.stroke();   
  92.                         j++;   
  93.                     }   
  94.                     this.cacheCtx.restore();   
  95.                 },   
  96.   
  97.                 move:function(){   
  98.                     this.x += this.vx;   
  99.                     this.y += this.vy;   
  100.                     if(this.x>(canvas.width-this.r)||this.x<this.r){   
  101.                         thisthis.x=this.x<this.r?this.r:(canvas.width-this.r);   
  102.                         this.vx = -this.vx;   
  103.                     }   
  104.                     if(this.y>(canvas.height-this.r)||this.y<this.r){   
  105.                         thisthis.y=this.y<this.r?this.r:(canvas.height-this.r);   
  106.                         this.vy = -this.vy;   
  107.                     }   
  108.   
  109.                     this.paint(ctx);   
  110.                 }   
  111.             }   
  112.   
  113.             var Game = {   
  114.                 init:function(){   
  115.                     for(var i=0;i<1000;i++){   
  116.                         var b = new ball(getRandom(0,canvas.width) , getRandom(0,canvas.height) , getRandom(⑴0 , 10) ,  getRandom(⑴0 , 10) , true)   
  117.                         Balls.push(b);   
  118.                     }   
  119.                 },   
  120.   
  121.                 update:function(){   
  122.                     ctx.clearRect(0,0,canvas.width,canvas.height);   
  123.                     for(var i=0;i<Balls.length;i++){   
  124.                         Balls[i].move();   
  125.                     }   
  126.                 },   
  127.   
  128.                 loop:function(){   
  129.                     var _this = this;   
  130.                     this.update();   
  131.                     RAF(function(){   
  132.                         _this.loop();   
  133.                     })   
  134.                 },   
  135.   
  136.                 start:function(){   
  137.                     this.init();   
  138.                     this.loop();   
  139.                 }   
  140.             }   
  141.   
  142.             window.RAF = (function(){   
  143.                 return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function (callback) {window.setTimeout(callback, 1000 / 60); };   
  144.             })();   
  145.   
  146.             return Game;   
  147.         }();   
  148.   
  149.         function getRandom(a , b){   
  150.             return Math.random()*(b-a)+a;   
  151.         }   
  152.   
  153.         window.onload = function(){   
  154.             testBox.start();   
  155.         }   
  156.     </script>  
  157. </body>  
  158. </html>  

  离屏canvas也有1个留意事项,假如你做的实际效果是会将目标不断地建立和消毁,请谨慎应用离屏canvas,最少不必像我上面写的那样给每一个目标的特性关联离屏canvas。

  由于假如这样关联,当目标被消毁时,离屏canvas也会被消毁,而很多的离屏canvas不断地被建立和消毁,会致使canvas buffer消耗很多GPU資源,非常容易导致访问器奔溃或比较严重卡帧状况。处理方法便是弄1个离屏canvas数字能量数组,预先装进充足数量的离屏canvas,仅将依然生存的目标缓存文件起来,当目标被消毁时,再消除缓存文件。这样就不容易致使离屏canvas被消毁了。

 

 【应用requestAnimationFrame】

  这个就不实际解释了,估算许多人都了解,这个才是做动漫的最好循环系统,而并不是setTimeout或setInterval。立即贴出适配性写法:

XML/HTML Code拷贝內容到剪贴板
  1. window.RAF = (function(){   
  2.        return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function (callback) {window.setTimeout(callback, 1000 / 60); };   
  3.             })();   

  

  【防止浮点运算】

  尽管javascript出示了很便捷的1些取整方式,像Math.floor,Math.ceil,parseInt,可是,海外友人做过检测,parseInt这个方式做了1些附加的工作中(例如检验数据信息是否合理的标值,parseInt 乃至先将主要参数变换变成标识符串!),因此,立即用parseInt的话相对性来讲较为耗费特性,那如何取整呢,能够立即用老外写的凑巧妙的方式了:

    JavaScript Code拷贝內容到剪贴板

    1.rounded = (0.5 + somenum) | 0;      

    2.rounded = ~~ (0.5 + somenum);   3.rounded = (0.5 + somenum) << 0;      

    运算符不懂的能够立即戳:http://www.w3school.com.cn/js/pro_js_operators_bitwise.asp  里边有详尽解释

  

  【尽可能降低canvasAPI的启用】

  作颗粒实际效果时,尽可能少应用圆,最好是应用方形,由于颗粒很小,因此方形看上去也跟圆类似。至于缘故,很非常容易了解,大家画1个圆必须3个流程:先beginPath,随后用arc画弧,再用fill开展填充才可以造成1个圆。可是画方形,只必须1个fillRect便可以了。尽管只是差了两个启用,当颗粒目标数量做到1定时执行,这特性差别就会显示信息出来了。

  也有1些别的留意事项,我就不11例举了,由于谷歌上1搜也挺多的。我这也算是1个给自身做下纪录,关键是纪录缓存文件的用法。要想提高canvas的特性最关键的還是得留意编码的构造,降低无须要的API启用,在每帧中降低繁杂的运算或把繁杂运算由每帧算1次改为数帧算1次。另外,上面所述的缓存文件用法,我由于贪图便捷,因此是每一个目标1个离屏canvas,实际上离屏canvas也不可以用的太泛滥成灾,假如用太多离屏canvas也会性爱能难题,请尽可能有效运用离屏canvas。

   源代码详细地址:https://github.com/whxaxes/canvas-test/tree/gh-pages/src/Other-demo/cache