一段时间后画布开始滞后

时间:2016-05-02 13:05:46

标签: javascript canvas html5-canvas

复制:将鼠标放在画布上,然后将鼠标旋转约15秒钟。起初你会注意到事情的顺利进行。一段时间后,它开始失去光滑度,变得非常迟钝。

部分js功能来自以下答案

Make moving Rect more smooth



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

1 个答案:

答案 0 :(得分:1)

每个mousemove启动一个新循环就会发生这种情况。这些循环会累积并最终减慢速度。

要解决此问题,您可以执行以下操作cancelAnimationFrame()

...
var timer;

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

然后在主循环中存储定时器引用:

...
timer = requestAnimationFrame(moveObject);

这将中止当前的帧更新请求,并允许您在不累积调用的情况下启动新循环。

出于这个原因,你还必须初始化xy,因为它们没有被初始化,否则直到移动鼠标(这当然不能保证)。

var x = 0;
var y = 0;

注意:此修正的副作用是现在每帧仅计算一次移动。累积时,每帧计算多次运动。为了补偿,将比例调整到较低的值(如下所示)。

修改示例

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>