HTMLF Canvas在FireFox 4中闪烁

时间:2011-04-15 13:46:20

标签: javascript html5 canvas flicker

我正在研究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>

2 个答案:

答案 0 :(得分:5)

我已经将你的例子提炼到了这个:

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

它在Firefox和Chrome中的运行速度非常快。

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

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

letterImg中的DrawRain()完全相同。将其创建移至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 :(得分:1)

补充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();
}
(...)
相关问题