Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
503 views
in Technique[技术] by (71.8m points)

html - Redrawing HTML5 canvas incredibly slow

I just started playing with the HTML5 canvas and I was hoping to make a couple games with it. However, as soon I started rendering the mouse coordinates to it, it grinded to a near halt:

http://jsfiddle.net/mnpenner/zHpgV/

All I did was render 38 lines and some text, it should be able to handle that, no?

Am I doing something wrong? I'd like to be able to render at lest 30 FPS, but for something like this I would expect it to be able to draw 1000s of times.

Or am I just using the wrong tool for the job? Is WebGL up for the task? Why would one be so much slower than the other?

String.prototype.format = function() {
    var args = arguments;
    return this.replace(/{(d+)}/g, function(m, n) {
        return args[n];
    });
};
var $canvas = $('#canvas');
var c = $canvas[0].getContext('2d');
var scale = 20;
var xMult = $canvas.width() / scale;
var yMult = $canvas.height() / scale;
var mouseX = 0;
var mouseY = 0;
c.scale(xMult, yMult);
c.lineWidth = 1 / scale;
c.font = '1pt Calibri';

function render() {
    c.fillStyle = '#dcb25c';
    c.fillRect(0, 0, scale, scale);
    c.fillStyle = '#544423';
    c.lineCap = 'square';
    for (var i = 0; i <= 19; ++i) {
        var j = 0.5 + i;
        c.moveTo(j, 0.5);
        c.lineTo(j, 19.5);
        c.stroke();
        c.moveTo(0.5, j);
        c.lineTo(19.5, j);
        c.stroke();
    }
    c.fillStyle = '#ffffff';
    c.fillText('{0}, {1}'.format(mouseX, mouseY), 0.5, 1.5);
}
render();
$canvas.mousemove(function(e) {
    mouseX = e.clientX;
    mouseY = e.clientY;
    render();
});
<canvas id="canvas" width="570" height="570"></canvas>
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Here's the code made much better.

http://jsfiddle.net/zHpgV/3/

Here's a breakdown of the things that you should take into consideration that I changed:

  • Continuous adding to a path instead of stopping and creating a new path with beginPath. This is by far the biggest performance killer here. You're ending up with a path with thousands and thousands of line segements that never gets cleared.
  • Continuously making the same path over and over when it only needs to be made once, on initialization. That is, the only thing you need to call inside of render is stroke. You do not need to call lineTo/moveTo ever again, and certainly not continuously. See note 1.
  • Stroking twice for one path
  • Stroking inside a for loop
  • Redrawing a background instead of setting CSS background
  • Setting the line cap over and over

Note 1: If you plan to have more than one path in your application then you should probably cache paths like this one since they never change. I have a a tutorial on how to do that here.

Of course, if you are doing all of this to just make a background, it should be saved as a png and you should be using a CSS background-image.

Like so: http://jsfiddle.net/zHpgV/4/

Then suddenly your render routine is rather small:

function render() {
    c.clearRect(0, 0, scale, scale);
    c.fillText('{0}, {1}'.format(mouseX, mouseY), 0.5, 1.5);
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...