HTML Canvas 滞后

HTML Canvas Lag

所以我创建了一个 canvas,当您将鼠标悬停在它上面时,会出现一个绿色的 32x32 框。 canvas 非常大,因此您可以绘制大量肖像,问题是绘制绿色框会使 canvas 和我的整个浏览器变得迟钝。

我添加的部分使其变得迟钝:

function makeTileCover(mousex, mousey) {
    ctx.strokeStyle = "green";
    ctx.strokeRect(mousex, mousey, 32, 32);
    ctx.stroke();
}

我猜想有一些简单的答案可以解决这个问题,似乎它可能绘制了太多次,因为当你将鼠标悬停在它上面的次数越多,正方形就会变得越暗,尽管我不确定这是否会解决无论如何。

var canvas = document.getElementById("MapEditor");
var ctx = canvas.getContext("2d");

function updateCanvas() {
  container = document.getElementById("container");
  if (container.width != window.innerWidth) {
    container.style.width = window.innerWidth - 250;
  }
  if (container.height != window.innerHeight) {
    container.style.height = window.innerHeight;
  }
}

//Destroy mouse on canvas exit.
canvas.addEventListener('mouseout', function() {
  document.body.style.cursor = 'auto';
});

function getMousePos(canvas, evt) {
  var rect = canvas.getBoundingClientRect();
  return {
    x: evt.clientX - rect.left,
    y: evt.clientY - rect.top
  };
}

canvas.addEventListener('mousemove', function(evt) {
  var mousePos = getMousePos(canvas, evt);
  var mousex = Math.round(mousePos.x / 32) * 32;
  var mousey = Math.round(mousePos.y / 32) * 32;
  var cursor = document.createElement('canvas'),
    cursorctx = cursor.getContext('2d');

  cursor.width = 32;
  cursor.height = 32;

  makeTileCover(mousex, mousey);

  document.body.style.cursor = 'url(' + cursor.toDataURL() + '), auto';
  document.getElementById('mousePosLocation').innerHTML = "Mouse location:" + "<b id='mousex'>" + mousex + "</b>" + "," + "<b id='mousey'>" + mousey + "</b>";
}, false);

function makeTileCover(mousex, mousey) {
  ctx.strokeStyle = "green";
  ctx.strokeRect(mousex, mousey, 32, 32);
  ctx.stroke();
}
canvas {
  background-color: black;
}
<div id="container">
  <canvas width="16384" height="16384" id="MapEditor"></canvas>
</div>

您在 MouseMove 上做的太多了,它可能每帧触发很多次,并且可能在帧的任何时间发生。

关于输入事件,您想尽可能少地做。

我认为您只需执行以下操作就可以逃脱惩罚:

 canvas.addEventListener('mousemove', function(evt) {
   //I'm attaching it to Window for now. Ideally, you'd use a private namespace.
   window.mousePos = getMousePos(canvas, evt);
 }, false);

只需设置一个变量并继续。

其他所有内容都应与 requestAnimationFrame() 触发的回调相关联。这样,鼠标位置会随着鼠标的每次移动而更新,但每帧绘制只会发生一次,即采用最近的鼠标位置。

function draw() {
  window.requestAnimationFrame(draw);

  var mousex = Math.round(mousePos.x / 32) * 32;
  var mousey = Math.round(mousePos.y / 32) * 32;
  var cursor = document.createElement('canvas'),
    cursorctx = cursor.getContext('2d');

  cursor.width = 32;
  cursor.height = 32;

  makeTileCover(mousex, mousey);

  document.body.style.cursor = 'url(' + cursor.toDataURL() + '), auto';
  document.getElementById('mousePosLocation').innerHTML = "Mouse location:" + "<b id='mousex'>" + mousex + "</b>" + "," + "<b id='mousey'>" + mousey + "</b>";
}

作为一个额外的好处,好的浏览器也会在浏览器可以管理的框架中尽早出现。这意味着您的长 运行 代码将尽可能远离正在呈现的帧(在监视器需要它之前为这段繁重的代码提供最长的计算时间,这与 mousemove 事件可能发生的一小部分不同)在监视器需要它之前一毫秒)。

问题是您的 canvas 太大了,chrome 无法处理它所需的内存。你真的不希望 canvas 比屏幕上可以容纳的更大。 (通常约为 1080x1920)。结合@ScottMichaud 的回答我们得到

HTML

<div id="container">
   <canvas width="1638" height="900" id="MapEditor"></canvas>
</div>

JS

 var canvas = document.getElementById("MapEditor");
  var ctx = canvas.getContext("2d");
  var MousePos = {x:0, y:0};
  function updateCanvas() {
    container = document.getElementById("container");
    if (container.width != window.innerWidth) {
      container.style.width = window.innerWidth - 250;
    }
    if (container.height != window.innerHeight) {
      container.style.height = window.innerHeight;
    }
  }

  //Destroy mouse on canvas exit.
  canvas.addEventListener('mouseout', function() {
    document.body.style.cursor = 'auto';
  });
  function Update(){
    window.requestAnimationFrame(Update);
    var mousex = Math.round(MousePos.x / 32) * 32;
    var mousey = Math.round(MousePos.y / 32) * 32;
    ctx.fillRect(0,0,canvas.width,canvas.height);
    makeTileCover(ctx, mousex, mousey);
  }
  function getMousePos(canvas, evt) {
    var rect = canvas.getBoundingClientRect();
    return {
      x: evt.clientX - rect.left,
      y: evt.clientY - rect.top
    };
  }

  canvas.addEventListener('mousemove', function(evt) {
    MousePos = getMousePos(canvas, evt);

    // var cursor = document.createElement('canvas'),
    //   cursorctx = cursor.getContext('2d');

    // cursor.width = 32;
    // cursor.height = 32;

    // makeTileCover(mousex, mousey);

    // document.body.style.cursor = 'url(' + cursor.toDataURL() + '), auto';
    // document.getElementById('mousePosLocation').innerHTML = "Mouse location:" + "<b id='mousex'>" + mousex + "</b>" + "," + "<b id='mousey'>" + mousey + "</b>";
  }, false);

  function makeTileCover(ctx, mousex, mousey) {
    ctx.strokeStyle = "green";
    ctx.strokeRect(mousex, mousey, 32, 32);
    ctx.stroke();
  }
  Update();

我还更改了 canvas,因此每一帧都会将 canvas 重新填充为黑色,这样您就不会在视图中看到一堆方块,而只有光标所在的方块.