为什么html5 canvas
在绘制 2000 图像时会变得非常慢?
如何优化?
这是我做的一个演示,通过左键单击画布禁用“安全模式”并开始移动鼠标直到你得到〜2000个图像
var img = new Image()
img.src = "http://i.imgur.com/oVOibrL.png";
img.onload = Draw;
var canvas = $("canvas")[0];
var ctx = canvas.getContext("2d")
var cnv = $("canvas");
var draw = [];
$("canvas").mousemove(add)
function add(event) {
draw.push({x: event.clientX, y: event.clientY})
}
canvas.width = cnv.width();
canvas.height = cnv.height();
var safe = true;
cnv.contextmenu(function(e) { e.preventDefault() })
cnv.mousedown(function(event) {
if(event.which == 1) safe = !safe;
if(event.which == 3) draw = []
});
function Draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
requestAnimationFrame(Draw);
for(var i of draw) {
ctx.drawImage(img, i.x, i.y)
}
if(safe && draw.length > 300) draw = []
ctx.fillText("Images count: "+ draw.length,10, 50);
ctx.fillText("Left click to toggle the 300 images limit",10, 70);
ctx.fillText("Right click to clear canvas",10, 90);
}
Draw();
body {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
position: absolute;
}
canvas {
position: absolute;
width: 100%;
height: 100%;
z-index: 99999999999;
cursor: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<canvas></canvas>
Codepen :http://codepen.io/anon/pen/PpeNme
答案 0 :(得分:0)
使用实际代码的简单方法:
由于在您的示例中,图像是静态的,因此您实际上并不需要每帧重绘所有内容:只需绘制最新的图像。
此外,如果您还有其他绘图(例如您的文本),您可能希望仅在图像上使用屏幕外画布,您将在屏幕画布上重绘其他图形。
var img = new Image()
img.src = "http://i.imgur.com/oVOibrL.png";
img.onload = Draw;
var canvas = $("canvas")[0];
var ctx = canvas.getContext("2d")
var cnv = $("canvas");
var draw = [];
$("canvas").mousemove(add)
function add(event) {
draw.push({
x: event.clientX,
y: event.clientY
})
}
canvas.width = cnv.width();
canvas.height = cnv.height();
// create an offscreen clone of our canvas for the images
var imgCan = canvas.cloneNode();
var imgCtx = imgCan.getContext('2d');
var drawn = 0; // a counter to know how much image we've to draw
var safe = true;
cnv.contextmenu(function(e) {
e.preventDefault()
})
cnv.mousedown(function(event) {
if (event.which == 1) safe = !safe;
if (event.which == 3) draw = []
});
function Draw() {
// clear the visible canvas
ctx.clearRect(0, 0, canvas.width, canvas.height);
requestAnimationFrame(Draw);
if (draw.length) { // onmy if we've got some objects to draw
for (drawn; drawn < draw.length; drawn++) { // only the latest ones
let i = draw[drawn];
// draw it on the offscreen canvas
imgCtx.drawImage(img, i.x, i.y)
}
}
// should not be needed anymore but...
if (safe && draw.length > 300) {
draw = [];
drawn = 0; // reset our counter
// clear the offscren canvas
imgCtx.clearRect(0, 0, canvas.width, canvas.height);
}
// draw the offscreen canvas on the visible one
ctx.drawImage(imgCan, 0, 0);
// do the other drawings
ctx.fillText("Images count: " + draw.length, 10, 50);
ctx.fillText("Left click to toggle the 300 images limit", 10, 70);
ctx.fillText("Right click to clear canvas", 10, 90);
}
Draw();
&#13;
body {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
position: absolute;
}
canvas {
position: absolute;
width: 100%;
height: 100%;
z-index: 99999999999;
cursor: none;
}
&#13;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<canvas></canvas>
&#13;
现在,如果您需要这些图像是动态的(即每帧移动),您可以考虑使用 imageDatas 。
你可以通过用户@Loktar看到这个original post,它解释了如何解析你绘制的图像imageData,然后在可见画布上重新绘制每个像素的像素。为imageData。您还可以看到this follow-up Q/A,它提供了Loktar想法的颜色实现。
在小图像上,这实际上大大提高了性能,但是不支持alpha通道乘法非常不方便。您将只有完全透明且完全不透明的像素。另一个缺点是它可能更难实现,但这只是你的问题; - )