优化HTML5画布

时间:2017-03-22 19:31:32

标签: javascript html5 canvas

为什么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

1 个答案:

答案 0 :(得分:0)

使用实际代码的简单方法:

不要以此速率重绘所有图像。

由于在您的示例中,图像是静态的,因此您实际上并不需要每帧重绘所有内容:只需绘制最新的图像。
此外,如果您还有其他绘图(例如您的文本),您可能希望仅在图像上使用屏幕外画布,您将在屏幕画布上重绘其他图形。

&#13;
&#13;
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;
&#13;
&#13;

现在,如果您需要这些图像是动态的(即每帧移动),您可以考虑使用 imageDatas

你可以通过用户@Loktar看到这个original post,它解释了如何解析你绘制的图像imageData,然后在可见画布上重新绘制每个像素的像素。为imageData。您还可以看到this follow-up Q/A,它提供了Loktar想法的颜色实现。

在小图像上,这实际上大大提高了性能,但是不支持alpha通道乘法非常不方便。您将只有完全透明且完全不透明的像素。另一个缺点是它可能更难实现,但这只是你的问题; - )