再现:将鼠标聚焦在 Canvas 上,然后将鼠标旋转约 15 秒。一开始你会发现一切都很顺利。一段时间后,它开始失去平滑度并变得非常滞后。
部分js函数来自以下答案
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);
这将中止当前的帧更新请求,并允许您在不累积调用的情况下启动新循环。
因此,您还必须初始化 x
和 y
,因为它们在鼠标移动之前不会初始化(这当然不能保证)。
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/