简体   繁体   English

画布在一段时间后开始滞后

[英]Canvas starts to lag after some time

Reproduction: focus your mouse on canvas , then spin your mouse in circles for ~15 sec. 复制:将鼠标放在画布上,然后将鼠标绕圈旋转约15秒。 At first you'll notice how things are smooth. 首先,您会注意到事情进展顺利。 After some time it starts to lose its smoothness and becomes really laggy. 一段时间后,它开始失去平滑度,变得非常滞后。

Part of the js function came from the following answer js函数的一部分来自以下答案

Make moving Rect more smooth 使移动Rect更平稳

 var canvas = document.getElementById('canvas'); var ctx = document.getElementById('canvas').getContext('2d'); var x; var y; var tx = tx || 0; var ty = ty || 0; var xDir; var yDir; function followMouse(e) { x = e.offsetX; y = e.offsetY; moveObject(); } function moveObject() { ctx.clearRect(0, 0, canvas.width, canvas.height); var scale = 0.2 * Math.max(canvas.width, canvas.height); xDir = 0; yDir = 0; xDir = (x - tx) / scale; yDir = (y - ty) / scale; tx = tx != x ? tx + xDir : tx; ty = ty != y ? ty + yDir : ty; ctx.fillRect(tx - 25, ty + 25, 50, 10); if (tx != x || ty != y) { window.requestAnimationFrame(moveObject); } } function resizeCanvas() { canvas.width = window.innerWidth; canvas.height = window.innerHeight; }; canvas.addEventListener('mousemove', _.throttle(function(e) { followMouse(e); }, 30)); window.addEventListener('resize', resizeCanvas, false); resizeCanvas(); 
 html, body { margin: 0; height: 100%; } canvas { display: block; } 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script> <canvas id="canvas"></canvas> 

This happens as for each mousemove a new loop is started. 对于每次mousemove发生一个新的循环。 These loops will accumulate and eventually slow things down. 这些循环将累积并最终使速度降低。

To solve you can implement cancelAnimationFrame() by doing: 要解决此问题,您可以执行cancelAnimationFrame()来实现cancelAnimationFrame()

...
var timer;

function followMouse(e) {
  x = e.offsetX;
  y = e.offsetY;
  cancelAnimationFrame(timer);
  moveObject();
}

Then store timer reference in the main loop: 然后将计时器参考存储在主循环中:

...
timer = requestAnimationFrame(moveObject);

This will abort the current request for frame update and allow you to start a new loop without accumulating calls. 这将中止当前的帧更新请求,并允许您在不累积调用的情况下开始新的循环。

For this reason you would also have to initialize x and y since they are not initialized otherwise until the mouse has been moved (which is of course no guarantee). 出于这个原因,您还必须初始化xy因为除非移动鼠标,否则它们不会被初始化(当然不能保证)。

var x = 0;
var y = 0;

Note: A side-effect of this correction is that now the movement is only calculated once per frame. 注意:此校正的副作用是现在每帧仅计算一次移动。 When accumulated the movement got calculated many times per frame. 累积运动量后,每帧计算多次。 To compensate adjust the scale to a lower value (shown below). 为了补偿,将比例尺调整为较低的值(如下所示)。

Modified example 修改示例

 var canvas = document.getElementById('canvas'); var ctx = canvas.getContext('2d'); var x = 0; var y = 0; var tx = tx || 0; var ty = ty || 0; var xDir; var yDir; var timer; function followMouse(e) { x = e.clientX; y = e.clientY; cancelAnimationFrame(timer); moveObject(); } function moveObject() { ctx.clearRect(0, 0, canvas.width, canvas.height); var scale = 0.02 * Math.max(canvas.width, canvas.height); xDir = 0; yDir = 0; xDir = (x - tx) / scale; yDir = (y - ty) / scale; tx = tx != x ? tx + xDir : tx; ty = ty != y ? ty + yDir : ty; ctx.fillRect(tx - 25, ty + 25, 50, 10); if (tx != x || ty != y) { timer = requestAnimationFrame(moveObject); } } function resizeCanvas() { canvas.width = window.innerWidth; canvas.height = window.innerHeight; }; canvas.addEventListener('mousemove', _.throttle(function(e) { followMouse(e); }, 30)); window.addEventListener('resize', resizeCanvas, false); resizeCanvas(); 
 html, body { margin: 0; height: 100%; } canvas { display: block; } 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script> <canvas id="canvas"></canvas> 

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

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