简体   繁体   English

HTML画布延迟

[英]HTML Canvas Lag

So I've created a canvas that when you hover your mouse over top of it a green 32x32 box appears. 因此,我创建了一个画布,当您将鼠标悬停在其上方时,会出现一个绿色的32x32框。 The canvas is very large so you could draw massive portraits, the problem is that drawing the green box has made the canvas and my whole browser laggy. 画布非常大,因此您可以绘制大量的肖像,问题是绘制绿色框使画布和整个浏览器变得迟钝。

The part that I added that made it laggy: 我添加的那部分使它变得迟钝:

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

I'm guessing that there's some simple answer to fix this, it seems like it might be drawing too many times because the square gets darker the more you hover over it all though I'm not sure that that would fix it anyway. 我猜想有一个简单的答案可以解决此问题,看来它绘制的次数太多了,因为当您将鼠标悬停在上方时,正方形会变得更暗,尽管我不确定这是否会解决。

 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> 

You're doing way too much on MouseMove, which could fire MANY times per frame, and can occur at ANY time of the frame. 您在MouseMove上做的太多了,每帧可能触发很多次,并且可能在帧的任何时间发生。

On input events, you want to do as LITTLE as possible. 在输入事件时,您希望尽可能地少。

I think you'd be able to get away with just doing: 我认为您只要这样做就能摆脱困境:

 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);

Just set one variable and move on. 只需设置一个变量然后继续。

Everything else should be associated with the callback triggered by requestAnimationFrame() . 其他所有内容都应与requestAnimationFrame()触发的回调关联。 That way, the mouse position will update with every mouse move, but the draw will only happen once per frame, taking the most recent mouse position. 这样,鼠标位置将随着每次鼠标移动而更新,但是绘制只会以最新的鼠标位置每帧发生一次。

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>";
}

As an added benefit, good browsers will will also happen as early in the frame as the browser can manage. 另外一个好处是,优秀的浏览器也将在浏览器可以管理的范围内尽早出现。 This means that your long running code will happen as FAR AWAY from the frame being presented as possible (giving this heavy code the longest time possible to calculate before the monitor needs it, unlike the mousemove event which could happen a fraction of a millisecond before the monitor needs it). 这意味着您的长时间运行的代码将尽可能远离显示的帧发生(给此沉重的代码以尽可能长的时间在监视器需要它之前进行计算,这与mousemove事件不同,后者可能在发生之前几分之一毫秒内发生)显示器需要它)。

The problem is your canvas is way too big and chrome can't handle the memory required for it. 问题是您的画布太大,而chrome无法处理它所需的内存。 You really never want the canvas to be bigger than what can fit on the screen. 您真的不希望画布大于屏幕上的尺寸。 (Typically going to be around 1080x1920). (通常为1080x1920左右)。 Combining that with @ScottMichaud 's answer we get 结合@ScottMichaud的答案,我们得到

HTML 的HTML

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

JS 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();

I also changed the canvas so every frame it refills the canvas to black so you don't get a bunch of squares populating the view and only have the one for where the cursor is. 我还更改了画布,以便将画布重新填充为黑色的每一帧,这样您就不会在视图中堆满一堆正方形,而只在光标所在的位置显示一个正方形。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM