javascript - 一段时间后 Canvas 开始滞后

标签 javascript canvas html5-canvas

再现:将鼠标聚焦在 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>

最佳答案

每次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>

关于javascript - 一段时间后 Canvas 开始滞后,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36983189/

相关文章:

javascript - 从流式音频 Node js 中删除高频声音

javascript - 赋值后需要分号,然后是 js 字符串插值

javascript - 发射器跟随 Canvas 中的粒子

javascript - 是否可以在 HTML5 canvas 中的路径上绘制图像?

javascript - 如何围绕组内的某个点旋转 Three.js 组?

css - 为什么 box-sizing 不适用于 canvas 元素上的宽度/高度属性?

javascript - Extjs 3.2。 GridView -商店关联

javascript - 使用 D3.js 和 GeoJson 在 map 上的州显示一些文本

javascript - 如何在 HTML Canvas 上找到文本的高度?

javascript - 创建一个蒙版覆盖层,其下方可拖动/可调整大小