JavaScript EventListener“pointerMove”:每秒点数

2023-12-27

我有一个添加了“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/ 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>

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

例如,您可以在以下位置找到这样的通知:鼠标移动UI 事件规范 https://w3c.github.io/uievents/#event-type-mousemove:

鼓励实施确定最佳频率以平衡响应性与性能。

大致相同的是指针事件'指针移动规格草案 https://w3c.github.io/pointerevents/extension.html#the-pointermove-event

这些事件可能会根据 UA 决策合并或与动画帧回调对齐。

事实上,Firefox 和 Chrome 目前都这样做coalesce这些事件在动画帧回调中,即它实际上与显示器的刷新率对齐。

这也意味着用于指针移动我们可以使用以下方法检索所有这些事件PointerEvent.getCoalescedEvents https://developer.mozilla.org/en-US/docs/Web/API/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>

请注意,在 Chrome 中,这些事件确实有自己的timestamp,这样你就可以知道它们应该何时触发,但在 Firefox 中,此属性设置为0...

然而,一个指针原始更新 event 正在草稿中 https://w3c.github.io/pointerevents/extension.html#the-pointerrawupdate-event并且已经在 Chrome 中可用实验性网络平台功能 flag.
本次活动将not与动画帧对齐,而是“尽快”触发。

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>

但就你而言(绘图应用程序),你最好坚持使用getCoalescedEvents因为无论如何你的绘图应该只发生在动画帧中。


Ps:关于为什么当开发工具打开时阈值被停用,这可能是一个浏览器错误。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

JavaScript EventListener“pointerMove”:每秒点数 的相关文章

  • dojo dijit.form.DateTextBox 约束不起作用,datetextbox

    嗨 我是 javascript 和 dojo 的新手 我正在尝试使用两个带有下拉日历的 dijit DateTextBox 来建立数据库查询的日期范围 一旦选择了开始日期或结束日期 我想限制可用的日期 以便不可能选择按时间顺序排列在开始日期
  • 如何在同一页面上使用AJAX处理多个表单

    我有一个表单 当我单击 提交 时 它就被提交了 然后该表单隐藏 操作页面的结果显示在 div 中 classname dig 它工作正常 但是当我添加另一个表单时 它停止正常工作并且所有表单同时提交 我如何更改我的代码 done click
  • 使用 vscode 调试器调试 next.js

    我已经使用安装了一个项目创建下一个应用程序 https github com segmentio create next app 我需要使用我的编辑器 vscode 调试服务器端渲染 所以我访问过vscode recipes 如何调试 ne
  • 关闭选项卡时要求确认[关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 当我在某些浏览器上关闭页面时 我希望出现一个消息框 并询问我是否真的要关闭页面 有两个按钮 如果我单击No那么这个标签就不会被关闭 我怎样
  • 了解设置 JQuery 变量

    了解设置 JQuery 变量 最近 我通过在 StackOverflow 上遇到的另一个问题寻找帮助 了解到如何设置 JQuery 变量 如下所示 您可以通过简单地调用变量来创建输入字段 并且锚变量似乎也定义了样式 var clicked
  • 尝试将布尔 C# 变量传递给 javascript 变量并将其设置为 true

    在我的 aspx 页面中 我将布尔变量 C 传递给需要布尔类型的 javascript 函数 但遇到了问题 但是 C 变量返回 True 而 javascript 不喜欢大写 myjavascript 如果我将 c 变量转换为字符串 那么我
  • 在 Vue.js 中从父组件执行子方法

    目前 我有一个 Vue js 组件 其中包含其他组件的列表 我知道使用 vue 的常见方式是将数据传递给孩子 并从孩子向父母发出事件 但是 在这种情况下 我想在子组件中的按钮出现时执行子组件中的方法 parent被点击 哪种方法最好 一种建
  • 我想检查 $('#td1').text() === "x" 是否?

    我想检查innerHtml是否有X或O 所以我不能再次添加任何其他东西 但它不起作用 添加检查代码后它就停止了 我在这里尝试做一个简单的XO游戏来更熟悉javascript和jquery 我也不确定是否可以用 jQuery 做到这一点
  • 如何抑制窗口鼠标滚轮滚动...?

    我正在开发嵌入页面中的画布应用程序 我有它 因此您可以使用鼠标滚轮放大绘图 但不幸的是 这会滚动页面 因为它是文章的一部分 当我在 dom 元素上滚动鼠标滚轮时 是否可以阻止鼠标滚轮在窗口上滚动 附加鼠标滚轮 不是 Gecko DOMMou
  • Meteor - 从客户端取消服务器方法

    我正在通过服务器方法执行数据库计数 用户可以选择他们希望如何执行计数 然后调用该方法 我的问题是 计数可能需要一些时间 并且用户可能会在方法运行时改变主意并请求不同的计数 有什么方法可以取消调用的方法并运行新的计数吗 我认为 this un
  • 在 webpack 2.x 中使用 autoprefixer 和 postcss

    如何使用autoprefixer使用 webpack 2 x 以前 它曾经是这样的 module loaders test scss loader style css sass postcss postcss gt return autop
  • 通过 CDN 使用 Dojo 时如何加载自定义 AMD 模块?

    我正在使用 google 的 CDN 并尝试使用他们的加载程序加载我自己的 AMD 模块 我知道我做错了什么 但我被困住了 有任何想法吗
  • Babel 7 Jest Core JS“TypeError:wks不是函数”

    将我的项目升级到 Babel 7 后 通过 Jest 运行测试会抛出以下错误 测试在 Babel 6 中运行没有任何问题 但在 Babel 7 中失败并出现以下错误 TypeError wks is not a function at Ob
  • Grails 在 javascript 内的 GSP 站点中使用 grails var

    我有一个在 GSP 文件中的 javascript 代码中使用 grails 变量值的问题 例如 我有一个会话值session getAttribute selectedValue 我想在 javascript 代码部分使用这个值 我现在的
  • HTML 离线应用程序缓存,列出下载的文件

    作为我正在构建的离线 Web 应用程序的加载屏幕的一部分 使用缓存清单 http developer apple com library safari documentation iPhone Conceptual SafariJSData
  • 如何更改此 jquery 插件的时区/时间戳?

    我正在使用这个名为 timeago 的插件 在这里找到 timeago yarp com 它工作得很好 只是它在似乎不同的时区运行 我住在美国东部 费城时区 当我将准确的 EST 时间放入 timeago 插件时 比如 2011 05 28
  • 如何仅在最后一个
  • 处给出透明六边形角度?
  • 我必须制作这样的菜单 替代文本 http shup com Shup 330421 1104422739 My Desktop png http shup com Shup 330421 1104422739 My Desktop png
  • 为什么 jquery 没有检测到单选按钮未被选中的情况? [复制]

    这个问题在这里已经有答案了 可能的重复 JQuery radioButton change 在取消选择期间不会触发 https stackoverflow com questions 5176803 jquery radiobutton c
  • 如何在 pg-promise 中设置模式

    我正在搜索的文档pg 承诺 https github com vitaly t pg promise特别是在创建客户端时 但我无法找到设置连接中使用的默认架构的选项 它始终使用public架构 我该如何设置 通常 为数据库或角色设置默认架构
  • fullCalendar 未显示正确的结束日期

    我正在看调试页面 http jsbin com wukofacaxu edit js outputFullCalendar 官方网站的 我想安排一个活动时间为 22 09 2015 至 30 09 2015 dd mm yyyy 但它只显示

随机推荐

  • sed 删除行中除前 5 个字符之外的剩余字符

    使用 sed 删除行中除前 5 个前导字符之外的所有字符的 sed 命令是什么 我尝试过 向后 处理 恢复删除 但这不是最优雅的解决方案 这可能对你有用 GNU sed echo 1234567890 sed s 6g 12345 Or e
  • 使用映射字典更改字典的键

    我想通过传递映射字典和替换嵌套键的函数来替换字典的键名称 问题是我在嵌套字典中有多个名为 id 的键 我想用特定名称重命名这些 id 初始词典 initial dict id 1 netAmount 10 2 modifiedOn 2017
  • 如何使用 Google Web Toolkit 绘制图表?

    我正在考虑使用 Google Web Toolkit GWT 绘制图表的解决方案 到目前为止我只找到了gwt 图 http code google com p gwt diagrams 项目但似乎被放弃了 对于使用 GWT 绘制图表有什么建
  • 从函数返回后如何在Python中打印原始变量的名称?

    我有枚举并使用类似的变量myEnum SomeNameA myEnum SomeNameB等 当我从函数返回这些变量之一时 我可以打印它们的名称 例如myEnum SomeNameA 而不是他们返回的值 简短的回答 不 长答案 这可以通过使
  • Scipy 标签侵蚀

    如何在 numpy 数组中的标记区域周围保留一圈像素 在一个简单的情况下 我会减去侵蚀 当标签接触时 这种方法就不起作用了 我怎样才能得到B from A A array 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2
  • Jquery ajax 和 php die()

    我的 IE 有问题 我正在使用 jquery ajax 方法来调用 php 脚本 php 脚本只调用 die 在 Firefox 中 会显示错误消息 但在 IE 中 会显示成功消息 但不显示任何数据 我更喜欢调用错误函数 有没有什么办法解决
  • 无法获取本地颁发者证书 vscode

    我正在尝试安装 VSCode 的扩展 但无法获得本地发行人证书 我的设置 json Place your settings in this file to overwrite the default settings Controls th
  • URL 重写 GET 参数

    我希望我的网址如下所示 www website com home foo bar hello world 我只想改变第一个获取参数 然而实际的 幕后 网址是这样的 www website com index php page home fo
  • 高度与线高样式

    当处理永远不会超过一行的文本时 使用这两种方法有什么区别 从我所看到的关于元素顶部或底部的元素来看 它们都可以在屏幕上产生类似的结果 如果是的话为什么还要使用行高呢 使用高度会更有意义 编辑 一个示例是从内部带有文本的 div 创建的风格化
  • 如何在 Django 中使用模式?

    我想在 Django 中使用 PostgreSQL 模式 我该怎么做 也许这会有所帮助 DATABASES default ENGINE django db backends postgresql psycopg2 OPTIONS opti
  • 基于ListView创建XML文件

    我想创建一个基于 ListView 的 XML 文件 现在 我正在创建 ListView 的位图 使其成为可绘制对象 然后将其设置为相对布局的背景 像这样 public Bitmap getWholeListViewItemsToBitma
  • java.sql.SQLException:用户“root”@“localhost”的访问被拒绝(使用密码:YES)Spring boot

    我针对这个问题进行了很多搜索 但没有找到适合我的好的解决方案 我的数据库名称 employee management system 我的应用程序属性 spring datasource url jdbc mysql localhost 33
  • 如何在 ruby​​ 中进行命名捕获

    我想命名从扫描中捕获的字符串 怎么做 555 333 7777 scan d 3 d 3 d 4 flatten gt 555 333 7777 可以改成这样吗 area gt 555 city gt 333 local gt 7777 o
  • SSRS 2008 日期格式化和导出到 Excel 混乱

    假设我在 Reporting Services 模板中有一个带有日期值的字段 例如 CDate 2010 12 03 我将 d 格式应用于此单元格 根据描述 该格式 将反映报告的区域设置 我使用英语生成报告 日期显示为12 03 2010
  • Python 计划未按计划运行

    我使用下面的代码每 5 分钟执行一次 python 脚本 但是当它下次执行时 它不会像以前那样在精确的时间执行 例如 如果我在上午 9 00 00 准确执行它 则下次它在上午 9 05 25 执行 下次在上午 9 10 45 执行 由于我每
  • React Router 中的 match.url 到底是什么?

    我在 React Router 文档中看到您传递到组件中match道具 你可以打电话match url 但您似乎从未真正将任何内容传递给组件 那么 match 到底是什么 你从哪里得到它 希望这可以帮助 https reacttrainin
  • 如何在 vaadin 中设置网格单元格样式

    我创建了一个带有一列的简单网格 public MyGrid addComponentColumn this getIcon setClassNameGenerator i gt icon img setItems some items se
  • Python文件IO“w”与“wb”[重复]

    这个问题在这里已经有答案了 想知道从 Python 编写文件时真正的区别是什么 从我可以看到如果我使用w or wb我用文本得到了相同的结果 我认为保存为二进制文件只会在十六进制编辑器中显示二进制值 但它也会显示文本 然后显示该文本的 AS
  • python:为什么替换不起作用?

    我编写了一个快速脚本 从保存在 Excel 列中的网站地址列表中删除 http 子字符串 但替换功能不起作用 我不明白为什么 from openpyxl import load workbook def rem string print s
  • JavaScript EventListener“pointerMove”:每秒点数

    我有一个添加了 pointerMove EventListener 的元素 现在 当移动鼠标时 我可以通过计算自 pointerDown 以来绘制的点总数并将其除以自 pointerDown 以来经过的时间来测量 pointerMove 每