【问题标题】:HTML5 Canvas flicker in FireFox 4Firefox 4 中的 HTML5 画布闪烁
【发布时间】:2011-08-06 08:52:04
【问题描述】:

我正在 HTML5 画布上进行概念验证。我能够在 Chrome 和 IE9 中像魅力一样工作,但在 Firefox 4 中,当它重新绘制画布时,我会不断闪烁。我已经尝试了这个网站上提到的一些技术,比如双缓冲,但我仍然得到了大量的闪烁。对此的任何见解将不胜感激!

<!DOCTYPE HTML>
<html>
<head>
<style type="text/css">  
body
{  
    margin:0px;  
    padding:0px;  
    text-align:center;  
} 
canvas
{  
    outline:0;  
    border:1px solid #000;  
    margin-top: 10px;
    margin-left: auto;  
    margin-right: auto;  
}  
</style>
<script type="text/javascript">
var canvasWidth = 640;
var thisXPos = 0;
var canvasHeight = 820;
var thisYPos = 0;
var canvas = null;
var context = null;
var gLoop = null;
var rain = [];
var rainImg = "images/raindrop.gif";
var bgImg = null;
var i;

for (i = 0; i < howManyLetters; i++)
{
    rain.push([Math.floor(Math.random() * canvasWidth), Math.floor(Math.random() * canvasHeight),rainImg]);
}

var DrawRain = function()
{
    for (i = 0; i < 10; i++)
    {
        thisXPos = rain[i][0];
        thisYPos = rain[i][1];
        imgSrc = rain[i][2];
        letterImg = new Image();
        letterImg.setAtX = thisXPos;
        letterImg.setAtY = thisYPos;
        letterImg.onload = function()
        {
            context.drawImage(this, this.setAtX, this.setAtY);
        }
        letterImg.src = imgSrc;
    }
};

var MoveRain = function(e)
{
    for (i = 0; i < 10; i++)
    {
        if ((rain[i][1] - 5) > canvasHeight)
        {
            randomnumber = Math.floor(Math.random()*26);

            rain[i][0] = Math.random() * canvasWidth;
            rain[i][1] = 0;
            rain[i][2] = rainImg;
        }
        else
        {
            rain[i][1] += e;
        }
    }
};

var clear = function()
{
    context.beginPath();
    context.rect(0, 0, canvasWidth, canvasHeight);
    context.closePath();

    bgImg = new Image();
    bgImg.src = "images/bg.png";
    bgImg.onload = function()
    {
        context.drawImage(bgImg,0,0);
    }
} 

var GameLoop = function()
{
    context.save();
    clear();
    MoveRain(1);
    DrawRain();
    context.restore();

    gLoop = setTimeout(GameLoop, 10);
}

function loadGame()
{
    canvas = document.getElementById("gameCanvas");
    context = canvas.getContext("2d");
    canvas.width = canvasWidth;
    canvas.height = canvasHeight;

    GameLoop();
}

</script>
</head>
<body onload="loadGame();">
    <canvas id="gameCanvas"></canvas>
</body>
</html>

【问题讨论】:

    标签: javascript html canvas flicker


    【解决方案1】:

    我把你的例子提炼成这样:

    http://jsfiddle.net/sPm3b/6/

    它在 Firefox 和 Chrome 中运行得非常快。

    所以我们知道问题出在图像上。

    您需要优化它们的创建和加载方式。现在,每个clear() 都会创建一个新图像并等待它加载!该图像应该只在您的loadGame() 中创建一次,然后一遍又一遍地重复使用。

    DrawRain() 中与letterImg 完全相同。将其创建移至loadGame()

    这可能会解决问题。

    编辑:

    像这样:

    在顶部添加:

    var letterImg = new Image();
    var bgImg = new Image();
    

    然后

    function loadGame()
    {
        canvas = document.getElementById("gameCanvas");
        context = canvas.getContext("2d");
        canvas.width = canvasWidth;
        canvas.height = canvasHeight;
    
        bgImg.src = "images/bg.png";
        letterImg.src = "images/raindrop.gif";
    
        // optional: wait for them to load here
    
        GameLoop();
    }
    

    例如,drawRain 将如下所示:

    var DrawRain = function()
    {
        for (i = 0; i < 10; i++)
        {
            thisXPos = rain[i][0];
            thisYPos = rain[i][1];
            context.drawImage(letterImg, thisXPosX, thisYPos); // letterImg was already constructed, no need to make it again
        }
    };
    

    【讨论】:

    • 我正在消除原始图像并“重新绘制”它低于先前位置 1 个像素,因此显示下降。也许我误解了你的例子是如何工作的。如果我在 loadGame() 中创建图像对象,如何在画布下方重新绘制它们的位置?
    • 我进行了编辑以使其更加清晰。如果愿意,您可以清除画布并一遍又一遍地重绘已加载的图像,这没有问题。
    • 很高兴为您提供帮助。将来,请始终注意此类事情。问问自己:“我是否加载了超出我必须加载的内容?”还要问自己:“我是在为屏幕外的对象绘制东西或进行计算吗?我怎样才能跳过(为它们做工作)?” Canvas 有一个优化的世界。玩得开心编码!
    【解决方案2】:

    作为对 Simon Sarris 回应的补充。我使用了“双帆布”技术来避免屏幕因厚重的帆布而变形。

    它的工作方式总是有两个版本的画布,一个在 DOM 中,一个在外部,并且总是在不在 DOM 中的一个上绘制。我将它与重绘队列一起使用。

    这是工作代码的一部分

    (...)
    clear: function() {
        //rotating on 2 canvas, one for draw (outside DOM) one for show
        var self = this;
        if (null == self.canvasbackup) {
            var tmpcanvas = self.canvas.clone(true);
            self.canvasbackup = self.canvas;
            self.canvas=tmpcanvas;
        } else {
            var tmpcanvas = self.canvasbackup;
            self.canvasbackup = self.canvas;
            self.canvas=tmpcanvas;
        }
        self.ctx = self.canvas[0].getContext('2d');
        self.ctx.clearRect( 0, 0, self.options.width, self.options.height );
        jQuery.each(self.elements,function(idx,elt){
            // custom function: my elements need to know which canvas they depends on
            elt.reconnectCanvas(self.canvas,self.ctx);
        });
    },
    inDOM: function() {
        var self = this;
        if(null==self.canvasbackup) {
            //1st time need to get all things in DOM
            self.canvas.appendTo(self.div);
            self.div.appendTo(self.container);
        } else {
            // remove current shown canvas
            self.connectHuman();
            self.canvasbackup.remove();
            // loosing some events here...
            self.canvas.appendTo(self.div);
            // div is already in DOM, we are in redraw
        }
    },
    redraw: function() {
        var self = this;
        self.clear();
        jQuery.each(self.elements,function(idx,elt){
            elt.draw();
            elt.enddraw();
        });
        self.inDOM();
    }
    (...)
    

    【讨论】:

      猜你喜欢
      • 2015-09-11
      • 2021-01-10
      • 2013-08-27
      • 2012-10-16
      • 2014-07-22
      • 1970-01-01
      • 2013-03-25
      • 2015-01-05
      • 1970-01-01
      相关资源
      最近更新 更多