如何设置mousemove更新速度?

IT技术 javascript html refresh mousemove
2021-03-08 10:58:13

我生成了一个函数,它需要轻松快速地设置签名。我正在画布字段中写签名。我用的是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个回答

你不能。mousemove 事件由浏览器生成,因此您接收它们的速度与浏览器生成它们的速度一样快。

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

您可以做的是将 mousemove 事件的连续位置与一条直线连接起来 - 这显然不会让您获得更高的精度,但它可能会减轻影响。

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

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

我建议(加强@river 的回答):

  1. 在 mousemove 事件处理程序中,只需将鼠标移动的那些点保存到某个缓冲区(数组)中,以便您的事件处理程序尽可能快
  2. 制作另一个函数,它将从缓冲区读取这些点并将其绘制在画布上作为 lineTo() -> lineTo() -> lineTo() 这样所有点都将被连接,它们之间没有空格。
  3. 将此绘图函数分配给 setInterval() 以便您的签名的绘图不会等到用户完成“绘图”,但它会在用户的手指移动后稍微延迟绘制该签名
我会修改它以在requestAnimationFrame循环中执行绘图功能,但尚未测试以了解它是如何工作的
2021-04-22 10:58:13

您可以根据计时器触发自己的事件,这可能是一个坏主意,但如果您真的需要它,那么最好不要。

其他一些答案表明这是因为处理程序函数缓慢。在我的测试中,无论是count++在处理程序中,还是在更昂贵的画布绘制调用中,都没有任何区别- 在这两种情况下,10 秒内生成的事件数量约为 500。但是,它可能会在较慢的计算机上产生影响。

显然,大多数鼠标/指针每秒仅向操作系统报告其位置不到 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>