如何设置mousemove更新速度?

时间:2011-03-10 10:34:34

标签: javascript html refresh mousemove

即时生成一个需要设置简单快速签名的功能。我正在画布领域写签名。我使用jQuery,但mousemove坐标的刷新率不够快。会发生的是,如果你快速写下你的签名,你会看到一些像素之间的空格。

如何更快地设置mousemove的刷新速度?

$("#xx").mousemove(function(e){

    ctx.fillRect(e.pageX - size, e.pageY - size, size, size);

    $("#pagex").html(e.pageX - size);
    $("#pagey").html(e.pageY - size);

}

6 个答案:

答案 0 :(得分:14)

你做不到。 mousemove事件由浏览器生成,因此您可以像浏览器生成它们一样快地接收它们。

浏览器没有义务以任何给定的速率生成事件(通过移动的像素或经过的时间):如果快速移动鼠标,您将看到坐标中的“跳跃”报告,如浏览器正在报告“鼠标移动了,它现在在这里”,而不是“......并经历了这些像素”。实际上,慢速计算机上的浏览器可能会生成较少的mousemove事件,以免页面速度变慢。

你可以做的是用一条直线连接mousemove事件的连续位置 - 这显然不会让你更精确,但它可以减轻影响。

答案 1 :(得分:7)

你需要让你的处理程序更快。

如果该事件的处理程序仍在运行,浏览器可以删除事件,因此您需要尽快退出mousemove处理程序。你可以尝试在那里优化代码或推迟工作直到鼠标移动完成。绘图可能是您正在做的最慢的事情,因此您可以将鼠标移动存储在内存中并稍后绘制。在绘图完成之前,这不会更新显示,但否则会更好。

答案 2 :(得分:2)

你可以根据计时器发射你自己的事件,这可能是一个坏主意,但如果真的需要,那就更好了。

答案 3 :(得分:1)

我建议(增强@river答案):

  1. 在mousemove事件处理程序中只保存鼠标移动到某个缓冲区(数组)的那些点,以便您的事件处理程序尽可能快
  2. 制作你的另一个函数,它将从缓冲区读取这些点并在画布上绘制为lineTo() - > lineTo() - > lineTo()因此所有点都将被连接,它们之间没有空格。
  3. 将此绘图功能分配到setInterval()中,因此签名的绘图不会等到用户完成"绘制",但它会在用户的手指后稍微延迟绘制该签名运动

答案 4 :(得分:0)

其他一些答案表明这是由于处理程序功能缓慢所致。在我的测试中,无论我是在处理程序中使用count++还是进行更昂贵的画布绘制调用都没有任何区别-两种情况下,在10秒内生成的事件数约为500。但是,这可能在速度较慢的计算机上有所作为。

Apparently大多数鼠标/指针每秒仅向操作系统报告其位置少于100次,因此,这甚至可能不在浏览器的控制范围之内。

您可能需要研究新的PointerEvent.getCoalescedEvents()方法。来自MDN文档:

getCoalescedEvents()接口的PointerEvent方法返回已合并到调度的PointerEvent事件中的所有pointermove实例的序列。

这是一个例子:

window.addEventListener("pointermove", function(event) {
  let events = event.getCoalescedEvents();
  for(let e of events) {
    draw(e.pageX, e.pageY);
  }
});

但是,在对此进行测试之后,似乎很少能够合并我计算机上的事件。同样,它在速度较慢的计算机上可能更有用。因此,目前最好的方法可能是使用ctx.lineTo或类似的方法(也许是arcTo)。这是一个结合getCoalescedEventslineTo的简单的工作画布演示程序:

<canvas id="canvas" style="touch-action:none; width:100vw; height:100vh; position:fixed; top:0; left:0; right:0; bottom:0;"></canvas>

<script>
  let mouseIsDown = false;

  let ctx = canvas.getContext("2d");
  canvas.width = window.innerWidth;
  canvas.height = window.innerHeight;


  window.addEventListener("pointerdown", function(e) {
    ctx.beginPath();
    ctx.moveTo(e.pageX, e.pageY);
    mouseIsDown = true;
  });
  window.addEventListener("pointerup", function(e) {
    mouseIsDown = false;
  });
  window.addEventListener("pointermove", function(event) {
   if(mouseIsDown) {
      let events = event.getCoalescedEvents();
      for(let e of events) {
        ctx.lineTo(e.pageX, e.pageY);
        ctx.stroke();
        ctx.beginPath();
        ctx.moveTo(e.pageX, e.pageY);
      }
   }
  });
</script>

答案 5 :(得分:0)

您是否尝试过使用 passive: truecapture: true 侦听器?通常浏览器会等待 50-200 毫秒来等待 preventDefault() 调用,但使用 passive: true 选项将摆脱这种行为,代价是失去 preventDefault()。这种滞后就是为什么@vageko4924 在 10 秒内总共看到大约 500 个事件,尽管处理程序效率很高。 capture: true 选项只是确保您的回调在所有其他人之前触发 - 这可以保护您免受缓慢回调的间歇性延迟。

我不确定这在 jQuery 中会是什么样子,但在 vanilla JS 中是这样的:

let x = document.querySelector('#xx'); // which would be faster if it were using getElementById()
x.addEventListener('mousemove', e => {
    // Your logic here
}, {passive: true, capture: true});

来源:https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener