2D 缩放到 webgl 中的点

2024-03-05

我正在尝试使用 WebGL (更具体地说,是 regl)创建 2D 图形可视化。通过我当前的实现,我已经可以看到力布局应用于每个节点,这很好。当我尝试相对于当前鼠标位置进行缩放时,问题就出现了。根据我的研究,要实现这种行为,需要按以下顺序应用矩阵变换:

translate(nodePosition, mousePosition)
scale(scaleFactor)
translate(nodePosition, -mousePosition)

所以,每次wheel触发事件,重新计算鼠标位置,并使用新的鼠标位置信息更新变换矩阵。 目前的行为很奇怪,我似乎不明白出了什么问题。这是一个活生生的例子 https://codesandbox.io/s/922pkr64jw?module=%2Fsrc%2Findex.js.

显然,如果我将鼠标固定在初始位置进行放大和缩小,一切都会正常工作。但是,如果我移动鼠标并尝试将焦点放在另一个节点上,则会失败。

检索鼠标位置的函数是:

const getMousePosition = (event) => {
    var canvas = event.currentTarget
    var rect = canvas.getBoundingClientRect()
    var x = event.clientX - rect.left
    var y = event.clientY - rect.top
    var projection = mat3.create()
    var pos = vec2.fromValues(x,y)
    // this converts the mouse coordinates from 
    // pixel space to WebGL clipspace
    mat3.projection(projection, canvas.clientWidth, canvas.clientHeight)
    vec2.transformMat3(pos, pos, projection)
    return(pos)
}

The wheel事件监听器回调:

var zoomFactor = 1.0
var mouse = vec2.fromValues(0.0, 0.0)
options.canvas.addEventListener("wheel", (event) => {
    event.preventDefault()
    mouse = getMousePosition(event)
    var direction = event.deltaY < 0 ? 1 : -1
    zoomFactor = 1 + direction * 0.1
    updateTransform()
})

以及更新变换的函数:

var transform = mat3.create()
function updateTransform() {
    var negativeMouse = vec2.create()
    vec2.negate(negativeMouse, mouse)
    mat3.translate(transform, transform, mouse)
    mat3.scale(transform, transform, [zoomFactor, zoomFactor])
    mat3.translate(transform, transform, negativeMouse)
}

This transform矩阵在顶点着色器中作为统一变量提供:

  precision highp float;
  attribute vec2 position;

  uniform mat3 transform;

  uniform float stageWidth;
  uniform float stageHeight;

  vec2 normalizeCoords(vec2 position) {
    float x = (position[0]+ (stageWidth  / 2.0));
    float y = (position[1]+ (stageHeight / 2.0));

    return vec2(
        2.0 * ((x / stageWidth ) - 0.5),
      -(2.0 * ((y / stageHeight) - 0.5))
    );
  }

  void main () {
    gl_PointSize = 7.0;
    vec3 final = transform * vec3(normalizeCoords(position), 1);
    gl_Position = vec4(final.xy, 0, 1);
  }

where, position是保存节点位置的属性。

到目前为止我已经尝试过:

  • 我已经尝试更改转换的顺序。结果更奇怪。
  • 当我独立应用平移或缩放时,一切看起来都很好。

这是我第一次与不常见的 SVG/canvas 东西进行交互。解决方案可能很明显,但我真的不知道该去哪里寻找。我究竟做错了什么?

更新 06/11/2018

我遵循@Johan的建议并在现场演示 https://codesandbox.io/s/922pkr64jw?module=%2Fsrc%2Findex.js。虽然解释颇有说服力,但结果却不太符合我的预期。反转变换以获取模型空间中的鼠标位置的想法对我来说很有意义,但我的直觉(可能是错误的)表明直接在屏幕空间上应用变换也应该可行。为什么我不能将节点和鼠标都投影到屏幕空间中并直接在那里应用变换?

更新 07/11/2018

经过一番挣扎后,我决定采取不同的方法并调整解决方案这个答案 https://stackoverflow.com/a/42437153/5288378对于我的用例。尽管缩放功能按预期工作(还添加了平移),但我仍然相信有些解决方案根本不依赖于 d3-zoom。也许隔离视图矩阵并独立控制它以实现预期的行为,如评论中所建议的。要查看我当前的解决方案,请检查下面我的答案。


好吧,在原始方法失败后,我设法使这个解决方案 https://stackoverflow.com/a/42437153/5288378适合我的用例。

The updateTransform现在的功能是:

var transform = mat3.create();
function updateTransform(x, y, scale) {
    mat3.projection(transform, options.canvas.width, options.canvas.height);
    mat3.translate(transform, transform, [x,y]);
    mat3.scale(transform, transform, [scale,scale]);
    mat3.translate(transform, transform, [
      options.canvas.width / 2,
      options.canvas.height / 2
    ]);
    mat3.scale(transform, transform, [
      options.canvas.width / 2,
      options.canvas.height / 2
    ]);
    mat3.scale(transform, transform, [1, -1]);
}

并由 d3-zoom 调用:

import { zoom as d3Zoom } from "d3-zoom";
import { select } from "d3-selection";

var zoom = d3Zoom();

d3Event = () => require("d3-selection").event;

select(options.canvas)
      .call(zoom.on("zoom", () => {
          var t = d3Event().transform
          updateTransform(t.x, t.y, t.k)
       }));

Here https://codesandbox.io/s/x2wzn3v1yz是该解决方案的现场演示。

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

2D 缩放到 webgl 中的点 的相关文章

  • 使用 PHP 和 MySQL 的服务器端事件

    我正在使用 PHP 和 MySQL 构建一个 非常基本的 应用程序 该应用程序的目的是在网页上显示 实时 数据交易 这些交易来自于transactionsMySQL 数据库中的表 到目前为止 我可以在网页上检索并显示数据 不过我期待看到数据
  • Kendo UI 网格过滤器日期格式

    在我的剑道网格中 我想更改过滤器中的日期格式 例如 2015年1月30日至2015年1月30日 我已经更改了开始日期的日期格式 field StartDate title Start Date width 30 format 0 MMM d
  • 这段代码有什么问题。如果用户选择或不选择复选框,为什么它仍然显示 MsgBox? [关闭]

    很难说出这里问的是什么 这个问题是含糊的 模糊的 不完整的 过于宽泛的或修辞性的 无法以目前的形式得到合理的回答 如需帮助澄清此问题以便重新打开 访问帮助中心 help reopen questions 无论我是否选择复选框 它仍然会给出
  • Jquery文件上传插件进度条

    这个插件 https github com blueimp jQuery File Upload wiki管理网页中的文件上传 并且可以在上传过程中添加很多 UI 元素 您创建一个输入文件类型元素 然后绑定 js 文件 使用实例化代码和 w
  • mocha.opts 已弃用,如何迁移到 package.json?

    我正在开发一个大型项目 自从上周我更新了摩卡以来 现在我们收到警告 DeprecationWarning 通过 mocha opts 进行的配置已被弃用并且 将从 Mocha 的未来版本中删除 使用 RC 文件或 改为 package js
  • 弃用警告:时刻构造回退到 js Date

    我正在尝试转换这个日期时间 150423160509 这是 utc 日期时间 改为以下格式 2015 04 24 00 05 09 本地时区 通过使用 moment js var moment require moment timezone
  • “move(-1)”作为 AngularJS 表达式有什么问题吗?

    我收到此错误 parse ueoe Unexpected end of expression move 从这段代码来看
  • 使用淘汰赛动态显示/隐藏元素

    我有一个表 有四列 即代码 名称 数量和价格 其中 我想动态更改数量列的内容 元素 通常 它应该显示其中显示数量的元素 当用户单击元素时 我想显示该元素 以便用户可以编辑数量 我正在尝试按照 示例2 来实现淘汰赛文档链接 http knoc
  • UpdatePanel 启动脚本未执行

    我正在编写一个在 SharePoint 网站中使用的 ASP NET Web 部件 并尝试使用 UpdatePanel 来呈现查询结果 我想使用 JQuery 插件来修改从异步回发返回的表 但我无法让启动脚本在异步更新上执行 我发现这个帖子
  • jQuery 模板插件:如何创建双向绑定?

    我开始使用 jQuery 模板插件 微软创建的 但现在我面临这个问题 模板用于绑定到对象数组的一堆表单 当我更改其中一个表单上的某些内容时 我希望更新绑定的对象 但我不知道如何自动执行该操作 这是一个简单的例子 现实生活中的模板和对象要复杂
  • Kendo 刷新 (DropDownList.refresh()) 不起作用错误未定义

    我试图在另一个 DropDownList 更改后刷新下拉列表 但 Refresh 方法未定义错误正在升级 我尝试再次读取数据源 它显示它正在加载 但数据仍然相同 帮助解决这个问题请 Code DropDownList1 change fun
  • 如何获取从 Express (Node.js) 中的表单传递的数据

    我想获取使用表单从页面传递的数据 并在重定向的页面中使用该数据 我的客户端有这个表格
  • 为什么我从 c# 到 js 得到不同的 MD5 哈希值?

    我有一个用于加密密码的 C 函数 System Security Cryptography MD5CryptoServiceProvider md5Provider new System Security Cryptography MD5C
  • 如何使用 API 中的数据填充选择的下拉元素 - ReactJS

    我对 React 还很陌生 我正在从 API 获取数据 当我检查控制台日志时可以看到数据 但是我不知道如何使用 map 创建一个新数组 然后选项元素可以使用该数组来显示货币代码 目前它填充下拉列表 但选项元素全部为空 结果显示为 NaN 下
  • Dojo“正在加载”消息

    我是 Dojo 新手 所以我需要一些帮助 我的一些链接需要一段时间 当用户单击时 页面开始加载需要几秒钟 我想添加一条 正在加载 消息 我可以用 旧时尚方式 来做 但我想学习新的 更简单 更智能的 Dojo 方式 具体如何工作现在并不重要
  • redux - 如何存储和更新键/值对

    我正在使用 redux 和 React js 我想存储简单的键 值对 但无法获得正确的减速器语法 在这种情况下 每个键 值对将保持与外部系统的连接 这是正确的做法吗 我刚开始使用 redux 所以这有点神秘 export default s
  • 除非打开开发人员工具,否则 IE8 Javascript 无法运行?

    由于某种原因 在 IE8 中 除非我在打开开发工具的情况下重新加载页面 否则 javascript 不会运行 我关闭开发人员工具并重新加载页面 然后 javascript 停止工作 我没有收到任何错误报告 无论如何它们也没有任何用处 还有其
  • 检测 html 选择框上的编程更改

    有没有办法让 HTML 选择元素在每次以编程方式更改其选择时调用函数 当使用 JavaScript 修改选择框中的当前选择时 IE 和 FF 都不会触发 onchange 此外 更改选择的 js 函数是框架的一部分 因此我无法更改它以在结束
  • 尽管 getBoundingClientRect() 是假的,但如何将事件坐标转换为 SVG 坐标?

    我正在尝试根据鼠标的位置在 SVG 元素上动态绘制内容 不幸的是 我很难将 mousemove 事件中的鼠标坐标转换为 SVG 元素的坐标空间 这是我一直在测试的一个有缺陷的函数 CylinderDemo prototype handleM
  • 加载谷歌地图控件时是否有事件?

    我知道tilesloaded 但控件似乎在该事件之后加载 我基本上希望能够通过 jQuery 获取控件 但甚至找不到正确的监听 我也刚刚处理了 没有类似的事件 在控件可见之前空闲和tilesloaded触发 因此 基本上将 特殊控制 类添加

随机推荐

  • 启用自定义键盘 iOS8 的应用内购买

    我正在为 iOS 构建自定义键盘 我想知道如何启用应用内购买 该文档指出我可以通过包含的应用程序启用应用程序内购买 但我不确定这意味着什么 技术上 有没有人通过应用内购买构建了 iPhone 扩展 可以给我一些指导 扩展程序与应用程序捆绑在
  • 您认识 16 位时间戳吗?

    我正在使用 Google 书签 它返回 16 位时间戳 我似乎无法在 C 中识别该时间戳以将其转换为真实日期 有什么想法吗 如何转动这个时间戳 1278276905502403在 C 中有意义的东西 这看起来就像以微秒为单位的 UNIX 时
  • 为什么 getQueryString() 在带有 h:commandButton 的 jsf 支持 bean 中不起作用

    我已经在菜单栏顶部构建了一个登录代码片段 如果用户通过导航进入任何页面并突然按下登录按钮 我希望看到该人经过身份验证 同时停留在他最初来自的页面上 所以我在支持 bean 上使用了这个 HttpServletRequest request
  • 等待 Kubernetes 或 Google Container Engine 中的作业/Pod 完成

    在 Kubernetes 或 Google Container Engine 中 脚本中等待作业或 Pod 完成的最佳方式是什么 特别是 最好得到通知而不是轮询状态kubectl 但我会很高兴有一个相当有效的循环 并且裂缝之间没有任何滑动
  • 了解 matplotlib 事件处理:什么是 event 和 mpl_connect?

    我希望能够在按下散点图中的点时显示值 解决方案在这里找到 当鼠标悬停在 matplotlib 中的某个点上时可以显示标签吗 https stackoverflow com questions 7908636 possible to make
  • .NET Core 2.2 迁移生成器无法删除索引

    我正在尝试从 IdentityUserRole 表中名为 UserRole 的列中删除索引 外键 UserRole 有 2 列 用户 ID 和角色 ID 两者都是主键 protected override void OnModelCreat
  • 在*某些* WebAPI 控制器上禁用 SSL 客户端证书?

    为未来的读者编辑 不幸的是 赏金奖励答案 不起作用 我现在对此无能为力 但请阅读我自己的答案 下面 通过测试 确认可以使用最少的代码更改 我们有一个完全采用 ASP NET WebAPI 2 2 的 Azure 云服务 WebRole 无
  • Maven Jetty 插件中的 Jetty JNDI 错误

    我正在尝试配置一个可通过调用 Maven Jetty 插件使用的 JNDI 数据源 我试图在 WAR 文件外部执行此操作 以便以后使用 Jetty 部署我们的 web 应用程序的任何人都不必编辑 WAR 的 WEB INF 目录内的配置文件
  • Android:ViewPager - PagerSlidingTabStrip,state_selected 上的自定义选项卡背景

    当每个选项卡都在时 我需要为每个选项卡使用自定义背景状态选择模式 但当我选择一个选项卡时仍然没有任何反应 我使用这样的选择器 tab selector xml
  • PHP 中的超链接自动生成图像

    我正在为我的第一个客户建立一个网站 使用WordPress 的 Simplicity Lite 主题 http wordpress org themes simplicity lite 我想以某种方式改变主题 以便在特色框位置 幻灯片放映的
  • 在 CSS Bootstrap jquery modal 中将元素暴露在 modal-backdrop 之外

    我正在使用 CSS Bootstrap 的 Modal 功能 它运行得很好 但是 我想添加一项功能 当模式对话框打开并且网页的其余部分被 modal backdrop 覆盖时 来自页面结构范围内不同位置的外部元素之一可以是暴露在背景之上 d
  • 使用中继现代 graphql 添加突变

    我正在尝试使用中继添加用户 下面是我的架构文件 schema graphql createUser input CreateUserInput UserPayload input CreateUserInput clientMutation
  • 如何判断点击了表格中的哪一行号?

    我有一个如下表 table tr td 1 td td 1 td td 1 td tr tr td 2 td td 2 td td 2 td tr tr td 3 td td 3 td td 3 td tr table 当用户单击表时 如何
  • 核心数据问题 - 选择分组依据/具有最大值

    假设我有两个实体 每个消息都属于一个消息线程 如何获取所有消息线程以及该线程上相应的最后一条消息 通常 在 SQL 中 我会这样做 按时间戳 max timeStamp 的线程从消息组中选择 其一 我认为 Core Data 不允许在其谓词
  • C++ Builder vs Delphi vs MFC

    我正在学习MFC 发现它不太好用 我听说过很多关于 Delphi 的事 对 Delphi 的研究让我接触到了 C Builder C Builder 是否提供了 C MFC 的严肃且良好的替代方案 C Builder 比 MFC 更好吗 C
  • Chrome扩展:从popup.js访问background.js的变量

    如果我正在使用chrome extension getBackgroundPage https developer chrome com extensions extension html method getBackgroundPage
  • 如何关闭窗口.打开

    我知道你可以用 window close 关闭 window open 但还有其他方法吗 我有一个打开 facebook 连接的弹出窗口 我想在用户连接到 facebook 时关闭弹出窗口 然后刷新父窗口 我认为过去我使用过 TARGET
  • 一元 & 运算符并在 Ruby 中将过程作为参数传递

    我无法理解下面的这段代码 我了解一元与运算符并将过程作为参数传递给方法的想法 但我实在无法接受过去的事self to the language call 我是这样理解的 我们正在过去self作为 proc block 语言的参数 这对我来说
  • GNU Smalltalk 80 调试器。如何调试smallcode代码?启动调试器?

    在 GNU Smalltalk 80 中 可以用您自己的普通代码编写 Smalltalk 代码 个人选择的文本编辑器 因此 调试代码非常重要 首先 将文件另存为 txt 文件 然后 您可以使用 工具 从程序员文本编辑器中打开该文件 这里的工
  • 2D 缩放到 webgl 中的点

    我正在尝试使用 WebGL 更具体地说 是 regl 创建 2D 图形可视化 通过我当前的实现 我已经可以看到力布局应用于每个节点 这很好 当我尝试相对于当前鼠标位置进行缩放时 问题就出现了 根据我的研究 要实现这种行为 需要按以下顺序应用