绘制大量图像时的画布性能

时间:2017-05-18 08:15:12

标签: javascript html5 canvas

我即将画出许多明星,比如10000画布,不断创造新的,淡出旧的。

这是我的想法:

  1. 每帧制作一些星星
  2. 每帧绘制所有星星
  3. 当星数达到阈值时,创建一个新画布并保留旧画布,空星列表。从现在开始,在新画布中绘制星星。这将使浏览器仅绘制最大星数,看起来有更多的星星。
  4. 当画布计数达到阈值时,只淡出并删除第一个。
  5. 所以总会有新的明星被创造出来,而旧的明星也会逐渐消失,同时表现也很高。

    但是在跑了大约1分钟之后,fps突然变得非常低,那里的问题是什么?

    以下是我的代码示例(仅在整页模式下运行会导致问题,我不知道原因。在Chrome 58中测试):

    
    
    var container, star, starCtx,
        starList = [],
        starShapeList = [],
        canvasList = [],
        starSize = 22,
        maxCanvasCount = 10,
        starCountPerCanvas = 500;
    var width = window.innerWidth, height = window.innerHeight;
    
    init();
    
    function init() {
        container = document.createElement('div');
    
        // for drawing stars
        starCtx = createCanvas();
    
        star = document.createElement('img');
        star.src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAMAAADzapwJAAAAM1BMVEX/hAD/hQD1kA3+hQHykxH7iQbXsDDVsTHqnBnrmxjPtzjGwkTKvT7WsDC7zE++yUzNuTrg0dc+AAAAEXRSTlMBBhELFg0mMCAaOVNGH3psPn/xpHgAAACMSURBVBjTndBLDsMgDEXR5vFsbCCf/a+2CahYidRJ7vAIYcznXUvvadFdU294KCAAKN0nC1eCvuLyqUmo6q4KST+/FNRiuRhPDwZoR2vFnAgWrprbvrec1TEZpx5122q5cQLdSq3zkhhpJT9HLgJoNtPM8fA4rk5S2Q/HPiB6Y5vwJGep67+PjQJf9AUF8wQVfnj+ngAAAABJRU5ErkJggg==';
    
        star.onload = function () {
            var size = starSize;
            // init 60 stars in each rotate (for star is a regular hexagon)
            for (var i = 0; i < 60; i++) {
                var canvas = document.createElement('canvas');
                var ctx = canvas.getContext('2d');
                canvas.width = size;
                canvas.height = size;
                ctx.translate(size / 2, size / 2);
                ctx.rotate(i * Math.PI / 180);
                ctx.translate(-size / 2, -size / 2);
                ctx.drawImage(star, 0, 0);
                starShapeList.push(canvas);
            }
    
            // start animation
            animate();
        }
    
    }
    
    function createCanvas() {
        var canvas = document.createElement('canvas');
        canvas.style.width = width + 'px';
        canvas.style.height = height + 'px';
        canvas.width = width * window.devicePixelRatio;
        canvas.height = height * window.devicePixelRatio;
    
        container.appendChild(canvas);
        canvasList.push(canvas);
        // return the ctx of created canvas
        return canvas.getContext('2d');
    }
    
    function Star() {
        // pick a random shape
        this.canvas = starShapeList[_.random(starShapeList.length - 1)];
    
        this.size = starSize;
        this.scale = 0.01;
        // set a random max scale
        this.maxScale = _.random(60, 120) / 100;
        // set a random position
        this.position = {
            x: _.random(width),
            y: _.random(height)
        };
    
        // start a scale animation
        new TWEEN.Tween(this)
            .to({
                scale: this.maxScale
            }, 1000)
            .start()
    }
    
    function animate() {
        // log time per frame
        console.timeEnd('per frame');
        console.time('per frame');
        requestAnimationFrame(animate);
        render();
    }
    
    function render() {
        // update tween
        TWEEN.update();
    
        // clear
        starCtx.clearRect(0, 0, width, height);
        // draw each star in star list
        starList.forEach(function (item) {
            // get current size
            var size = item.size * item.scale;
            starCtx.drawImage(item.canvas, 0, 0, item.size, item.size, item.position.x - size / 2, item.position.y - size / 2, size, size);
        });
    
        // create 10 stars per frame
        for (var i = 0; i < 10; i++) {
            starList.push(new Star());
        }
    
        // when star count reached max star count per canvas
        if (starList.length > starCountPerCanvas) {
            // create a new canvas
            starCtx = createCanvas();
            // clear star list
            starList.length = 0;
            // when canvas count reached max canvas count, fade out and remove the very first one
            if (canvasList.length > maxCanvasCount) {
                var c = canvasList.shift();
                $(c).fadeOut(1000, function () {
                    this.remove();
                });
            }
        }
    }
    
    window.onload = function () {
        document.body.appendChild(container);
    }
    &#13;
    * {
        margin: 0;
        padding: 0;
        box-sizing: border-box;
    }
    
    body {
        background-color: black;
    }
    
    canvas {
        position: absolute;
        top: 0;
        left: 0;
    }
    &#13;
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Test</title>
    </head>
    <body>
      <script src="http://cdn.bootcss.com/underscore.js/1.8.3/underscore-min.js"></script>
      <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
      <script src="https://cdnjs.cloudflare.com/ajax/libs/tween.js/16.3.5/Tween.min.js"></script>
    </body>
    </html>
    &#13;
    &#13;
    &#13;

    确认这是Chrome Bug,在IE 11和FireFox中工作正常

0 个答案:

没有答案