21

我正在生成一个需要设置简单快速签名的函数。我正在画布字段中写签名。我用的是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);

}
4

6 回答 6

18

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

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

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

于 2011-03-10T11:29:46.707 回答
9

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

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

于 2011-03-10T11:44:17.647 回答
5

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

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

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

于 2014-06-23T12:27:01.517 回答
1

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

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

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

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

这是一个例子:

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>

于 2020-07-13T16:30:19.403 回答
0

您是否尝试过使用passive: trueandcapture: 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

于 2021-06-03T14:00:09.870 回答