JavaScript EventListener“ pointerMove”:每秒的点数 [英] JavaScript EventListener "pointerMove": points per second

查看:82
本文介绍了JavaScript EventListener“ pointerMove”:每秒的点数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个添加了 pointerMove EventListener的元素。现在,在移动鼠标时,我可以通过计算自 pointerDown以来绘制的总点数并将其除以自 pointerDown以来经过的时间,来测量每秒 pointerMove传递的数据点数(pps)。
到目前为止,太好了。但是,奇怪的是,当打开开发人员控制台时,我得到了更高的pps速率。



示例:按下鼠标按钮,然后混乱地移动光标,我大约60pps。但是,当打开开发人员控制台然后执行完全相同的操作时,我的pps上升到约235-几乎增加了400%!



此测试是在Windows 10的Chrome 76中完成的使用Firefox可以获得类似的结果。此问题还涉及通过触摸或笔进行的输入,并且同样存在于Chrome操作系统中(尚未检查其他操作系统上的行为)。有趣的是,尽管Microsoft Edge似乎没有受到影响。



所以问题是:为什么会这样?以及如何在不打开开发人员控制台的情况下获得更多的pps?






此处的可执行示例:
https://jsfiddle.net/Galveston01/unxmrchw/



  var指针ID =未定义; var开始,计数; var canvas;函数startup(){canvas =文档。 getElementById( canvas); canvas.addEventListener( pointerdown,pointerdown,false); canvas.addEventListener( pointermove,pointermove,false); canvas.addEventListener( pointerup,pointerup,false); canvas.addEventListener( pointercancel,pointerup,false); canvas.addEventListener( touchstart,touch,false); canvas.addEventListener( touchmove,touch,false); canvas.addEventListener( touchend,touch,false); canvas.addEventListener( touchcancel,touch,false);}函数pointerdown(event){event.preventDefault(); rect = canvas.getBoundingClientRect(); if((event.pointerType == pen || event.pointerType == mouse)&& pointerid ==未定义){pointerid = event.pointerId; var x = event.clientX-rect.left,y = event.clientY-rect.top;开始=新的Date()。getTime();计数= 1; }}函数pointermove(event){event.preventDefault();如果(pointerid == event.pointerId){var x = event.clientX-rect.left,y = event.clientY-rect.top;数++; }}函数pointerup(event){event.preventDefault();如果(pointerid == event.pointerId){var x = event.clientX-rect.left,y = event.clientY-rect.top; pointerid =未定义;数++; console.log((count /(new Date()。getTime()-start)* 1000)+ pps); }}函数touch(event){if(pointerid!= undefined){event.preventDefault(); }} startup();  

 < div id = canvas style = width:2000px; height:2000px;>< / div>  

解决方案

规范现在鼓励浏览器供应商为大多数UI事件设置阈值,以提高性能。



例如,您可以在 mousemove UI事件规范


鼓励实施人员确定


PointerEvents的 pointermove 规格草稿



< blockquote>

这些事件可以根据UA决定合并或对齐到动画帧回调。


实际上,Firefox和Chrome当前都在动画帧回调中进行了 coalesce 这些事件(也就是说,在Chrome中,它实际上与监视器的刷新率保持一致,在FF中,当前是60FPS)。



这也意味着 intermove ,我们可以使用 PointerEvent.getCoalescedEvents 方法。



  const canvas = document.getElementById( canvas); let count = 0,start = 0; const opts = {passive:true}; canvas.addEventListener( pointerdown,pointerdown,opts); canvas .addEventListener( pointermove,pointermove,opts); canvas.addEventListener( pointerup,pointerup,opts); canvas.addEventListener( touchstart,prevent); canvas.addEventListener( touchmove,prevent);函数pointermove( event){if(canvas.hasPointerCapture(event.pointerId)){const coalesced = event.getCoalescedEvents();计数+ = coalesced.length; points.push(...建议);画(); }}函数pointerdown(事件){canvas.setPointerCapture(event.pointerId);计数= 1;开始=新的Date()。getTime(); points.length = 0;}函数pointerup(event){if(canvas.hasPointerCapture(event.pointerId)){canvas.releasePointerCapture(event.pointerId);数++; const PPS =(count /(new Date()。getTime()-start)* 1000); log.textContent = PPS + pps; }} //只是为了说明我们有真实的事件,例如const ctx = canvas.getContext('2d'); const points = []; function draw(){ctx.clearRect(0,0,canvas.width,canvas.height); ctx.beginPath(); points.forEach(evt => {ctx.lineTo(evt.offsetX,evt.offsetY);}); ctx.stroke();} //防止丢弃默认的触摸事件或指针事件function prevent(evt){evt.preventDefault();}  

  #canvas {边框:1px实心;}  

 < pre id = log>< / pre>< canvas id = canvas width = 2000 heigth = 2000> < / canvas>  



请注意,在Chrome中,这些事件确实具有自己的时间戳,因此您可以知道何时触发它们,但是在Firefox中,此属性设置为 0 。 ..



但是, pointerrawupdate 事件 ,并且已在Chrome中的 Experimental Web Platform功能标志下提供。

此事件将与动画对齐

  if(!(窗口中的'onpointerrawupdate')){console.error(您的浏览器不支持'pointerrawupdate'事件。您可能需要切换一些配置标志);}其他{const canvas = document.getElementById( canvas); let count = 0,start = 0; const opts = {passive:true}; canvas.addEventListener( pointerdown ,pointerdown,opts); canvas.addEventListener( pointerrawupdate,pointermove,opts); canvas.addEventListener( pointerup,pointerup,opts);函数pointermove(event){if(canvas.hasPointerCapture(event.pointerId)) {const coalesced = event.getCoalescedEvents(); count + = coalesced.length;}}函数pointerdown(event){canvas.setPointerCapture(event.pointerId); count = 1; start = new Date()。getTime();}函数pointerup(event){if(canvas.hasPointerCapture(event.pointerId)){canvas.releasePointerCapture(event.pointerId); count ++; const PPS =(count /(new Date()。getTime()-start)* 1000) ; log.textContent = PPS + pps;}} //删除了绘图部分,因为绘图应在动画帧中进行}  

  #canvas {边框:1px实线;}  

 < pre id = log>< / pre>< canvas id = canvas width = 2000 heigth = 2000>< / canvas>  



但是在您的情况下(绘图应用程序),您最好坚持使用 getCoalescedEvents ,因为您的绘图无论如何都应该只在动画帧中发生。






Ps :关于为何在打开开发工具时停用阈值的原因,这可能是浏览器错误。


I have an element with a "pointerMove" EventListener added to it. Now when moving my mouse around, I can measure the number of data points "pointerMove" delivers per second (pps) by counting the total number of points drawn since "pointerDown" and dividing this by the time that passed since "pointerDown". So far, so good. What is strange though is the fact that I get a higher pps rate when the developer console is opened.

Example: Pressing my mouse button and then moving the cursor around chaotically gives me about 60pps. But when opening the developer console and then doing exactly the same, my pps rises to about 235 - almost 400% increase!

This test was done in Chrome 76 on Windows 10. Similar results may be obtained using Firefox. This issue also concerns input via touch or pen and is present in Chrome OS as well (behaviour on other operating systems has not yet been examined). Interestingly though Microsoft Edge seems not to be affected.

So the question is: Why does this happen? And how may I get the higher number of pps without having to open the developer console?


Executable example here: https://jsfiddle.net/Galveston01/unxmrchw/

var pointerid = undefined;
var start, count;
var canvas;

function startup() {
  canvas = document.getElementById("canvas");
  canvas.addEventListener("pointerdown", pointerdown, false);
  canvas.addEventListener("pointermove", pointermove, false);
  canvas.addEventListener("pointerup", pointerup, false);
  canvas.addEventListener("pointercancel", pointerup, false);
  canvas.addEventListener("touchstart", touch, false);
  canvas.addEventListener("touchmove", touch, false);
  canvas.addEventListener("touchend", touch, false);
  canvas.addEventListener("touchcancel", touch, false);
}

function pointerdown(event) {
  event.preventDefault();
  rect = canvas.getBoundingClientRect();
  if ((event.pointerType == "pen" || event.pointerType == "mouse") && pointerid == undefined) {
    pointerid = event.pointerId;
    var x = event.clientX - rect.left,
      y = event.clientY - rect.top;
    start = new Date().getTime();
    count = 1;
  }
}

function pointermove(event) {
  event.preventDefault();
  if (pointerid == event.pointerId) {
    var x = event.clientX - rect.left,
      y = event.clientY - rect.top;
    count++;
  }
}

function pointerup(event) {
  event.preventDefault();
  if (pointerid == event.pointerId) {
    var x = event.clientX - rect.left,
      y = event.clientY - rect.top;
    pointerid = undefined;
    count++;
    console.log((count / (new Date().getTime() - start) * 1000) + "pps");
  }
}

function touch(event) {
  if (pointerid != undefined) {
    event.preventDefault();
  }
}
startup();

<div id="canvas" style="width:2000px; height:2000px; ">
</div>

解决方案

Specs now encourage browser vendors to threshold most UI Events in order to improve performances.

For instance you can find such a notice in mousemove UI-Event specs:

Implementations are encouraged to determine the optimal frequency rate to balance responsiveness with performance.

And about the same in PointerEvents' pointermove specs drafts

These events may be coalesced or aligned to animation frame callbacks based on UA decision.

In the facts, both Firefox and Chrome do currently coalesce these events in animation frame callback (that is in Chrome it's actually aligned on your monitor's refresh rate, in FF it's currently 60FPS).

This also means that for pointermove we can retrieve all these events using the PointerEvent.getCoalescedEvents method.

const canvas = document.getElementById("canvas");
let
  count = 0,
  start = 0;
const opts = {passive: true};
canvas.addEventListener("pointerdown", pointerdown, opts);
canvas.addEventListener("pointermove", pointermove, opts);
canvas.addEventListener("pointerup", pointerup, opts);
canvas.addEventListener("touchstart", prevent);
canvas.addEventListener("touchmove", prevent);


function pointermove(event) {
  if(canvas.hasPointerCapture(event.pointerId)) {
    const coalesced = event.getCoalescedEvents();
    count += coalesced.length;
    points.push(...coalesced);
    draw();
  }
}
function pointerdown(event) {
  canvas.setPointerCapture(event.pointerId);
  count = 1;
  start = new Date().getTime();
  points.length = 0;
}
function pointerup(event) {
  if(canvas.hasPointerCapture(event.pointerId)) {
    canvas.releasePointerCapture(event.pointerId);
    count++;
    const PPS = (count / (new Date().getTime() - start) * 1000);
    log.textContent = PPS + "pps";
  }
}

// just to show we have real Events
const ctx = canvas.getContext('2d');
const points = [];
function draw() {
  ctx.clearRect(0,0,canvas.width,canvas.height);
  ctx.beginPath();
  points.forEach(evt => {
    ctx.lineTo(evt.offsetX, evt.offsetY);
  });
  ctx.stroke();
}
// prevent default touch events or pointer ones are discarded
function prevent(evt) {
  evt.preventDefault();
}

#canvas {
  border: 1px solid;
}

<pre id="log"></pre>
<canvas id="canvas" width="2000" heigth="2000"></canvas>

Note that in Chrome these Events do have their own timestamp, so you can know when they should have fired, but in Firefox this property is set to 0...

However, a pointerrawupdate event is coming in the drafts and is already available in Chrome under the Experimental Web Platform features flag.
This event will not be aligned to animation frames and instead will fire "as soon as possible".

if(!('onpointerrawupdate' in window)) {
  console.error("Your browser doesn't support 'pointerrawupdate' event. You may need to toggle some config flags");
}
else {
const canvas = document.getElementById("canvas");
let
  count = 0,
  start = 0;
const opts = {passive: true};
canvas.addEventListener("pointerdown", pointerdown, opts);
canvas.addEventListener("pointerrawupdate", pointermove, opts);
canvas.addEventListener("pointerup", pointerup, opts);


function pointermove(event) {
  if(canvas.hasPointerCapture(event.pointerId)) {
    const coalesced = event.getCoalescedEvents();
    count += coalesced.length;
  }
}
function pointerdown(event) {
  canvas.setPointerCapture(event.pointerId);
  count = 1;
  start = new Date().getTime();
}
function pointerup(event) {
  if(canvas.hasPointerCapture(event.pointerId)) {
    canvas.releasePointerCapture(event.pointerId);
    count++;
    const PPS = (count / (new Date().getTime() - start) * 1000);
    log.textContent = PPS + "pps";
  }
}

// Removed the drawing part because drawing should be made in animation frames
}

#canvas {
  border: 1px solid;
}

<pre id="log"></pre>
<canvas id="canvas" width="2000" heigth="2000"></canvas>

But in your case (a drawing app) you'd be better to stick with getCoalescedEvents since your drawings should anyway happen only in animation frames.


Ps: about why the threshold is deactivated when dev-tools are open, that's probably a browser bug.

这篇关于JavaScript EventListener“ pointerMove”:每秒的点数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆