我用JS编写了一些代码,允许用户单击屏幕创建一个正方形,并在盖章之前按住鼠标以增加正方形的大小。问题是,一旦鼠标从最初单击的位置移动,按住鼠标时正方形大小增加的速度就会减慢。我正在使用间隔在 1 毫秒的时间内更改大小。以下是JS代码(使用Jquery):
更新:如果您运行代码片段,您将不会看到问题。尝试将其另存为文件并运行它,然后可能会出现问题。
<!DOCTYPE html>
<html>
<head>
<title>My Canvas</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.0/jquery.min.js"></script>
<script type="text/javascript">
$(function () {
var mouseDown
var c = document.getElementById('myCanvas');
var ctx = c.getContext("2d");
var objects = []
c.addEventListener("mousedown", onMouseDown);
c.addEventListener("mouseup", onMouseUp);
function createSquare(x, y, size) {
this.x = x;
this.y = y;
this.size = size;
this.draw = draw;
this.drawStylus = drawStylus;
this.clear = clear;
};
function draw() {
ctx.fillRect(this.x, this.y, this.size, this.size);
};
function drawStylus() {
ctx.fillRect(this.x, this.y, this.size, this.size);
};
function clear() {
ctx.clearRect(this.x, this.y, this.size, this.size);
}
// var mySquare = new createSquare(100,100,100);
// mySquare.draw();
function onMouseDown() {
mouseDown = true
x = event.clientX
y = event.clientY
size = 100
console.log('clicked')
interval = setInterval(function () {
size = size + 5
var cursorSquare = new createSquare(x,y,size);
cursorSquare.clear();
cursorSquare.drawStylus();
}, 1);
};
function onMouseUp() {
console.log('up')
if (mouseDown) {
clearInterval(interval);
var newSquare = new createSquare(x,y,size);
newSquare.draw();
mouseDown = false
};
};
});
</script>
</head>
<body>
<canvas id='myCanvas' width="5000" height="5000" style="border:1px solid #000000;">
</canvas>
</body>
</html>
问题是间隔,
首先,1毫秒对于任何渲染来说都太短了,鼠标只更新大约1/60秒,渲染超过1/60(较短的时间)会给浏览器带来过重的负载,并且由于屏幕刷新也是1/60秒,大部分渲染在它有机会进入显示器之前就会丢失。
其次,尽管 1 毫秒对于某些浏览器来说太短了(忘记每个浏览器的最小间隔时间),但问题是,当您呈现的任务比间隔周期长时,浏览器仍然会不断将函数调用添加到调用堆栈中,从而有效地延迟了其他事件和浏览器维护。在这种情况下继续使用 setInterval 将导致调用堆栈溢出,使页面上的所有 javascript 崩溃。
简单的规则是永远不要出于任何原因使用setInterval
。请改用setTimeout
,因为它可以防止调用堆栈溢出并阻止在调用堆栈上放置不受控制的调用。使用setTimeout
实际上可以产生更好的时间间隔。
// simple timeout
var interval = 50
function myTimer(){
setTimeout(myTimer,interval); // set up the next interval
}
// start it
setTimeout(myTimer,interval);
通过new Date().valueOf()
获取时间,您可以调整下一次呼叫的超时,以尽可能接近所需的间隔,这是setInterval很难做到的。要停止调用,如果设置了停止标志,则不要调用 setTimeout。
但是对于图形,您应该使用与setTimeout
非常相似的图形requestAnimationFrame
,但您不提供超时,浏览器将获得最佳时间让您与渲染和布局引擎以及显示硬件保持同步,这样您就不会闪烁和/或剪切。
function update(time){ // requestAnimationFrame calls the function with the time in milliseconds
// do what is needed
requestAnimationFrame(update); // get next frame when browser is ready 1/60th second
}
requestAnimationFrame(update); // start it going
要与鼠标协调,只需让您的鼠标侦听器设置一些变量,如 mouseX
、mouseY
和 buttonState
,然后不做更多的事情。在 update
函数中,使用这些值来处理鼠标。这会产生一个更易于管理的鼠标界面。