canvas的性能优化(缓存问题)

来源:互联网 发布:网络教学系统 编辑:程序博客网 时间:2024/06/08 08:08

文章原创来源于:http://www.cnblogs.com/axes/p/3567364.html?utm_source=tuicool&utm_medium=referral

使用缓存

使用缓存就是用离屏canvas进行预渲染了。原理就是先绘制一个离屏canvas,然后再通过drawImage把离屏canvas画到主canvas中。把离屏canvas当成一个缓存区,需要重复绘制的画面数据进行缓存。减少调用canvas的API消耗。
例如下面的DEMO:

1、使用了缓存
2、没使用缓存
看到上面的DEMO性能明显不一样。分析一下原因:为了实现每个圈的样式,所以绘制圈圈时用了循环绘制,如果没有启用缓存,当页面的圈圈数量达到一定时,动画的每一帧就要大量调用canvas的API,要进行大量的计算,这样再好的浏览器也会被拖垮。

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

除了创建离屏的canvas作为缓存之外,下面的代码中有一点很关键,就是要设置离屏canvas的宽度和高度,canvas生成后的默认大小是300X150,对于代码中每个缓存起来圈圈对象半径最大也就不超过80,所以300X150的大小明显会造成很多空白区域,会造成资源浪费,所以要设置一下离屏canvas的宽度和高度,让他跟缓存起来的元素大小一致,这样有利于提高动画性能。

var ball = function(x , y , vx , vy , useCache){                this.x = x;                this.y = y;                this.vx = vx;                this.vy = vy;                this.r = getZ(getRandom(20,40));                this.color = [];                this.cacheCanvas = document.createElement("canvas");                this.cacheCtx = this.cacheCanvas.getContext("2d");                this.cacheCanvas.width = 2*this.r;                this.cacheCanvas.height = 2*this.r;                var num = getZ(this.r/borderWidth);                for(var j=0;j<num;j++){                    this.color.push("rgba("+getZ(getRandom(0,255))+","+getZ(getRandom(0,255))+","+getZ(getRandom(0,255))+",1)");                }                this.useCache = useCache;                if(useCache){                    this.cache();                }            }

当实例化圈圈对象时,直接调用缓存方法,把复杂的圈圈直接画到圈圈对象的离屏canvas中保存起来。

cache:function(){                    this.cacheCtx.save();                    var j=0;                    this.cacheCtx.lineWidth = borderWidth;                    for(var i=1;i<this.r;i+=borderWidth){                        this.cacheCtx.beginPath();                        this.cacheCtx.strokeStyle = this.color[j];                        this.cacheCtx.arc(this.r , this.r , i , 0 , 2*Math.PI);                        this.cacheCtx.stroke();                        j++;                    }                    this.cacheCtx.restore();                }

然后在接下来的动画中,只需要把圈圈对象的离屏canvas画到主canvas中,这样,每一帧调用的canvasAPI就只有这么一句话:
ctx.drawImage(this.cacheCanvas , this.x-this.r , this.y-this.r);