news 2026/10/30 2:27:42

Web 加载 DWG 实战(五):缩放、平移与图纸坐标怎么对应

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Web 加载 DWG 实战(五):缩放、平移与图纸坐标怎么对应

在浏览器里查看 DWG,滚轮放大和拖动平移是最常用的两个操作。真正接入业务页面时,细节问题很快就会出现:鼠标指着一个节点,放大后节点为什么跑了?图纸明明没有修改,状态栏坐标为什么一直变化?换到高分屏后,点击位置为什么偏了?

这些问题都与同一件事有关:图纸坐标怎样变成屏幕上的位置,又怎样从鼠标位置换算回图纸坐标。

上一期讲了字体资源和文字显示。本期继续使用 UDE(UTUM Data Engine)公开 Web 示例,拆开缩放、平移和坐标换算。理解这套关系后,状态栏坐标、对象点选和后续业务标记就有了共同的定位依据。

本文以UDE DWG SDK v0.4.0 FREE 的有序查看入口为例。下面的worldPoint()、renderer.setView()等属于随包提供的 JavaScript 查看器代码;接入其他渲染器时,需要按对应的视图变换实现。

一、先分清三种坐标

鼠标在屏幕上移动时,网页事件提供的是位置,图纸中的实体也有自己的位置。两者需要换算。

坐标或尺寸本文中的含义用在哪里
图纸坐标(x, y)查看器显示数据使用的二维坐标定位图形、查询对象
画布内位置(sx, sy)相对画布左上角的 CSS 像素位置鼠标交互和视图变换
画布像素尺寸Canvas 实际分配的像素宽高WebGL 绘制,适配高分屏

浏览器的event.clientX、event.clientY相对当前浏览器视口。画布旁边如果有导航栏、图层面板或页面留白,就需要先减去画布自身的位置:

constrect=elements.drawing.getBoundingClientRect();constsx=event.clientX-rect.left;constsy=event.clientY-rect.top;

这里得到的sx、sy仍然是CSS 像素。例如,鼠标在画布右侧 500 像素、下方 100 像素处,对应的就是(500, 100)。

图 1:坐标关系示意,用于解释公式;不是 DWG 运行截图。本文讨论的是示例的二维视图变换。

二、图纸坐标怎样映射到画布

这个查看器用三个值描述当前视图:

  • scale:每一个图纸单位对应多少个 CSS 像素。
  • offsetX:图纸原点在画布上的水平位置。
  • offsetY:图纸原点在画布上的垂直位置。

先记住这一组对应关系:

sx = x × scale + offsetX sy = -y × scale + offsetY

这里的负号很关键。示例中的图纸 Y 轴向上,网页画布的 Y 轴向下,所以绘制时需要反转 Y 的方向。

反过来,从鼠标位置计算图纸坐标:

x = (sx - offsetX) / scale y = -(sy - offsetY) / scale

公开示例中的worldPoint()正是这个过程:

functionworldPoint(event){constrect=elements.drawing.getBoundingClientRect();constx=event.clientX-rect.left;consty=event.clientY-rect.top;return{screenX:x,screenY:y,x:(x-renderer.offsetX)/renderer.scale,y:-(y-renderer.offsetY)/renderer.scale,};}

这段函数同时返回画布位置和图纸坐标。前者用来确定缩放的中心,后者可以用于状态栏显示和对象查询。

用一组便于手算的数值检查:图纸点为(100, 50),scale = 2,偏移为(300, 200)。它在画布中的位置就是:

sx = 100 × 2 + 300 = 500 sy = -50 × 2 + 200 = 100

将(500, 100)代回反向公式,得到的仍是(100, 50)。这组数值是教学示例,不代表某张 DWG 的实际坐标。

三、拖动平移:改变偏移量

鼠标向右拖动 60 个 CSS 像素,图形也应该向右移动 60 个 CSS 像素。最直接的做法是把鼠标位移加到视图偏移上。

下面摘自示例拖动处理的核心部分,drag保存上一次事件的位置:

renderer.setView(renderer.scale,renderer.offsetX+event.clientX-drag.x,renderer.offsetY+event.clientY-drag.y,);drag.x=event.clientX;drag.y=event.clientY;

scale保持原值,offsetX、offsetY随拖动变化。图纸中的端点、圆心和文字插入点仍使用原来的坐标。

有序查看器支持鼠标左键或中键按下后拖动,并通过setPointerCapture()接收后续指针事件。松开时,如果从按下位置起的位移小于 3 个 CSS 像素,示例会进入对象点选处理。

因此,鼠标停在相同屏幕位置时,平移后状态栏可能显示另一个图纸坐标:这个位置下面已经换成了图纸的另一处。若要观察同一个节点,应让鼠标跟随那个节点移动。

四、滚轮缩放:让鼠标下面的点保持原位

仅修改scale,图形会围绕当前图纸原点的屏幕位置放大。原点如果在画布之外,鼠标指着的局部就可能迅速移出视野。

更符合查看习惯的行为是:缩放前后,鼠标下面的同一个图纸点保持在同一个画布位置。

要做到这一点,需要一起更新比例和偏移量。设新旧比例之比为factor:

factor = newScale / oldScale newOffsetX = sx - (sx - oldOffsetX) × factor newOffsetY = sy - (sy - oldOffsetY) × factor

公开示例的滚轮事件采用这组公式:

elements.drawing.addEventListener('wheel',(event)=>{if(!renderer)return;event.preventDefault();constpoint=worldPoint(event);constnext=Math.max(0.000001,Math.min(1000000,renderer.scale*(event.deltaY>0?0.9:1.1)));constfactor=next/renderer.scale;autoFit=false;renderer.setView(next,point.screenX-(point.screenX-renderer.offsetX)*factor,point.screenY-(point.screenY-renderer.offsetY)*factor,);redrawHighlight();updateZoom();},{passive:false});

worldPoint(event)在修改视图之前执行,以取得旧视图下的鼠标位置。passive: false让事件能够调用preventDefault(),避免操作画布时同时触发页面滚动。

继续用前面的图纸点(100, 50)。把scale从 2 改成 4,鼠标保持在(500, 100),就能算出:

factor = 4 / 2 = 2 newOffsetX = 500 - (500 - 300) × 2 = 100 newOffsetY = 100 - (100 - 200) × 2 = 300 缩放后再计算这个图纸点: sx = 100 × 4 + 100 = 500 sy = -50 × 4 + 300 = 100

周围的图形放大了,但这个点的位置保持不变。

图 2:为了方便计算,示意图使用 2 倍放大。公开示例每次滚轮事件按方向乘以 1.1 或 0.9;这里的 2 倍不是它的默认滚轮步长。

五、适合窗口、窗口变化和高分屏

初次打开图纸时,查看器会根据图形包围盒和画布可用尺寸,计算可以容纳整张图纸的比例,再将图形居中:

scale = min( (画布宽度 - 左右留白) / 图形宽度, (画布高度 - 上下留白) / 图形高度 )

对应的示例方法是renderer.fit(),默认每边预留 50 个 CSS 像素。这个计算针对有效、宽高均大于零的图形包围盒,运行时还会限制最小比例。

当图层或属性面板展开、浏览器窗口改变大小时,可用画布尺寸也会变化。示例通过ResizeObserver处理:自动适配状态下重新执行fit();用户已经拖动或缩放后,则在保持比例的同时,让原来的视图中心继续位于新画布中心。点击“适合窗口”可以重新回到自动适配状态。

高分屏还多了一层换算。假设画布的 CSS 尺寸为1000 × 600,devicePixelRatio = 2,实际绘图缓冲区就可能是2000 × 1200。

在本示例中,鼠标事件和视图参数统一使用 CSS 像素,渲染器在提交给 WebGL 时,再把比例和偏移乘以像素比。因此,前面的worldPoint()不需要再把鼠标位置乘以devicePixelRatio。重复乘一次,就会让点选与画面错位。

如果换用其他渲染器,应先确认它的相机、偏移和鼠标输入使用哪一种坐标约定,再接入换算。

六、坐标、单位和“100%”分别表示什么

缩放比例决定怎样看图,图纸单位决定怎样解释数据。两者需要分别处理。

例如,一段线的坐标差是1000,图纸约定以毫米绘制时可以解释为 1000 mm;图纸约定以米绘制时,它代表另一种实际长度。仅凭画面上的线段长度,或者状态栏的一个坐标值,无法确定工程单位。

这个有序查看器把renderer.scale × 100显示为缩放百分比。因此,100%表示每一个显示数据单位对应一个 CSS 像素,不能直接解释为工程图的 1:1 打印比例。

还有两个接入细节:

  • 状态栏用toFixed(2)显示坐标,表示保留两位小数供阅读;不要拿这段显示文本代替后续计算使用的数值。
  • 前文的反向公式得到查看器显示数据中的二维坐标。如果业务需要转换到块的局部坐标、UCS 或其他业务坐标,还要继续处理对应的变换关系。

对象点选也依赖同一套坐标。第三期使用的候选对象查询中,5 / renderer.scale把约 5 个 CSS 像素的选取容差换算成图纸单位,使不同缩放下的点击范围更接近一致;这仍需要结合候选对象和命中逻辑判断最终选择。

七、在公开 Web 示例里操作一次

以下命令从 Windows PowerShell 执行,使用公开包中的 Python 后端:

cd./UDE-SDK./examples/web/run.ps1-Language python-Port 8082-OrderedPreview

需要 64 位 Python 3.11+ 和 Microsoft Visual C++ x64 Runtime。打开http://127.0.0.1:8082/?ordered=1,上传自己有权使用的 DWG。免费版单个原始 DWG 上限为3,000,000 字节。

使用有序查看入口,是为了让页面行为与本文讲解的ordered_viewer.mjs保持一致。Python、Java、C# 后端生成显示结果后,本文这些缩放和平移操作由同一套前端处理。

可以按下面顺序观察:

  1. 把鼠标移到一个容易辨认的节点,查看底部 X、Y 坐标。
  2. 保持鼠标位置,滚轮放大,观察同一个节点是否保持在鼠标附近。
  3. 拖动平移,观察图形随指针移动,缩放比例保持原值。
  4. 展开图层或属性面板,观察可用画布变化后的视图位置。
  5. 点击“适合窗口”,重新显示整张图纸。

缩放和平移更新的是当前查看器的视图。已加载的图纸可以直接在浏览器重绘,无须为每次交互重新上传 DWG。

八、接入时常见的几个问题

现象优先检查
放大后鼠标指着的节点移走了是否在修改比例的同时,按鼠标位置更新了偏移
点选位置整体偏向一侧是否减去了画布的rect.left、rect.top
Y 坐标或上下移动方向相反正向和反向变换是否使用了相同的 Y 轴约定
高分屏上点击位置偏了是否混用了 CSS 像素和实际画布像素,或重复乘了像素比
面板一展开,图纸就重新跳回全景用户操作后是否仍在无条件执行fit()
“100%”时的尺寸和打印纸张不一致是否把查看器比例误当成了物理尺寸或出图比例

示例源码与下一期

本文对应的公开源码:

  • examples/web/README.md:环境、启动参数和有序查看入口。
  • ordered_viewer.mjs:鼠标坐标换算、拖动、滚轮、点选和窗口变化。
  • ordered_compact_webgl.mjs:视图参数、适合窗口和高分屏绘制。

下一期继续沿着这套示例讲:从上传 DWG 到浏览器显示,后端和前端之间传递了什么?把render.bin、entities.bin和可选的render.ord放回完整的数据流程中。

本文由 UDE 团队结合公开示例整理。示例版本为 UDE DWG SDK v0.4.0 FREE、Windows x64。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/30 2:26:04

python中的静态方法和类方法

在版本号为.2的情况之下, 静态方法与类方法是被进行引用的, 不管是经典类还是新式类, 都是可以直接被使用的。与此同时, 存在一对内建函数, 是分别被称为和被的这两个内建函数被引入到了进来, 它们的作用是用于把一个类之中的某种方法进行转化, 从而把其转化为上述这两种方法当…

作者头像 李华
网站建设 2026/10/30 2:24:17

ltx-2.5-mlx提示词工程:文生视频Prompt写法完全指南(新手友好)

ltx-2.5-mlx提示词工程:文生视频Prompt写法完全指南(新手友好) ltx-2.5-mlx 是 Lightricks LTX-2.5 视频生成模型在 Apple Silicon(MLX 格式)上的转换版,支持文生视频、图生视频与音视频联合生成。本文面向…

作者头像 李华
网站建设 2026/10/30 2:23:31

显存优化不是万能药:4 步加速版在 8G 卡上翻车的那些瞬间

显存优化不是万能药:4 步加速版在 8G 卡上翻车的那些瞬间 "4 步出图""提速 8 到 10 倍""显存峰值降到 8GB,3090 就能跑"——过去几个月,围绕 Qwen-Image 加速版的社区文章几乎都用同一套话术:步数…

作者头像 李华