Add high-resolution panel guide and hide joint readouts
This commit is contained in:
@@ -825,6 +825,9 @@ machine/operation values remain on the main element as data attributes for
|
||||
browser diagnostics; no control command or gate changes with this layout.
|
||||
Home Joint, the numeric joint selector and Home All are rendered in the Manual
|
||||
tab's action area; the standalone Machine sequence heading is not rendered.
|
||||
The XYZAC position summary and preview HUD display only X/Y/Z/A/C; J0-J4
|
||||
position readouts are omitted. Numeric homing target selection and canonical
|
||||
joint data remain available to the existing control logic.
|
||||
|
||||
```text
|
||||
HOME(all/joint)
|
||||
|
||||
BIN
docs/web-panel-png-guide/00-panel-overview-hd.png
Normal file
BIN
docs/web-panel-png-guide/00-panel-overview-hd.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 542 KiB |
2
docs/web-panel-png-guide/01-toolbar-and-workspace.html
Normal file
2
docs/web-panel-png-guide/01-toolbar-and-workspace.html
Normal file
File diff suppressed because one or more lines are too long
BIN
docs/web-panel-png-guide/01-toolbar-and-workspace.png
Normal file
BIN
docs/web-panel-png-guide/01-toolbar-and-workspace.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.4 MiB |
2
docs/web-panel-png-guide/02-manual-and-homing.html
Normal file
2
docs/web-panel-png-guide/02-manual-and-homing.html
Normal file
File diff suppressed because one or more lines are too long
BIN
docs/web-panel-png-guide/02-manual-and-homing.png
Normal file
BIN
docs/web-panel-png-guide/02-manual-and-homing.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.4 MiB |
2
docs/web-panel-png-guide/03-views-and-overrides.html
Normal file
2
docs/web-panel-png-guide/03-views-and-overrides.html
Normal file
File diff suppressed because one or more lines are too long
BIN
docs/web-panel-png-guide/03-views-and-overrides.png
Normal file
BIN
docs/web-panel-png-guide/03-views-and-overrides.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.8 MiB |
2
docs/web-panel-png-guide/04-mdi-dro-and-menus.html
Normal file
2
docs/web-panel-png-guide/04-mdi-dro-and-menus.html
Normal file
File diff suppressed because one or more lines are too long
BIN
docs/web-panel-png-guide/04-mdi-dro-and-menus.png
Normal file
BIN
docs/web-panel-png-guide/04-mdi-dro-and-menus.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1021 KiB |
42
docs/web-panel-png-guide/README.md
Normal file
42
docs/web-panel-png-guide/README.md
Normal file
@@ -0,0 +1,42 @@
|
||||
# Web 控制台高清 PNG 功能图解
|
||||
|
||||
截图来源:`http://127.0.0.1:5175/`,2026-09-09。
|
||||
图解依据当前 XYZAC TRT Web 面板实现和
|
||||
[`linuxcnc-axis-web-control-panel-source-logic.md`](../linuxcnc-axis-web-control-panel-source-logic.md)。
|
||||
|
||||
## 图片
|
||||
|
||||
| 图片 | 内容 | 分辨率 |
|
||||
| --- | --- | --- |
|
||||
| [高清总览](00-panel-overview-hd.png) | 当前面板原始截图 | 3170 × 3196 |
|
||||
| [01 工具栏与文件操作](01-toolbar-and-workspace.png) | 急停、电源、打开、加载、运行、暂停、停止、视角、菜单入口 | 3600 × 5308 |
|
||||
| [02 手动操作与原生回零](02-manual-and-homing.png) | 回零关节选择、Home、Jog、对刀、主轴、冷却 | 3600 × 6000 |
|
||||
| [03 运动学、视图与倍率](03-views-and-overrides.png) | Switchkins、预览控制、倍率、图层、编辑区 | 3600 × 8134 |
|
||||
| [04 MDI、数显与菜单窗口](04-mdi-dro-and-menus.png) | MDI、历史、DRO、File/Help 菜单、About | 3600 × 7888 |
|
||||
|
||||
红色编号对应每项的中文详细说明。覆盖 83 个控件 ID,含按钮、菜单、页签、
|
||||
复选框、选择框、滑块和输入框;隐藏的文件输入入口作为编号 83 单独说明。
|
||||
禁用且未实现的功能有明确标记。动态 Pause/Resume、Home All/Re-home All
|
||||
使用同一编号解释其状态变化。
|
||||
|
||||
总览中的状态文字为只读监控:Task mode 是 MANUAL/MDI/AUTO;Task state
|
||||
是机床上电/急停状态;Interpreter 为解释器状态;Motion mode 是
|
||||
FREE/COORD/TELEOP,不能与 Motion type 混用。Homing 表示当前回零活动,
|
||||
Machine sequence 的 HOMED 表示各关节已完成参考点建立,二者并不相同。
|
||||
|
||||
当前案例采用原生无搜索回零配置,因此 Jog 后 Home 可以改变关节坐标与
|
||||
电机偏置而不移动电机;不能将其理解为 G53 返回预先固定的物理原点。
|
||||
|
||||
## 再生成
|
||||
|
||||
从仓库根目录运行,需启动面板服务并有可见桌面和 Playwright:
|
||||
|
||||
```bash
|
||||
DISPLAY=:1 PLAYWRIGHT_MODULE=/path/to/playwright/index.js \
|
||||
XYZAC_PANEL_URL=http://127.0.0.1:5175/ \
|
||||
node scripts/generate_panel_png_guide.mjs
|
||||
```
|
||||
|
||||
脚本在独立浏览器会话中操作面板,完成上电/回零并输入无运动的 G21 以展示
|
||||
MDI 历史,然后抓取界面与控件位置。标注仅存在于导出的图片/HTML 中,
|
||||
不修改控制台程序。`controls.json` 保存全部编号、控件 ID 和说明。
|
||||
509
docs/web-panel-png-guide/controls.json
Normal file
509
docs/web-panel-png-guide/controls.json
Normal file
@@ -0,0 +1,509 @@
|
||||
{
|
||||
"url": "http://127.0.0.1:5175/",
|
||||
"controls": [
|
||||
{
|
||||
"id": "menu-file",
|
||||
"name": "File 文件菜单",
|
||||
"detail": "展开文件菜单。当前包含工具表编辑和退出入口,二者受浏览器运行边界限制。",
|
||||
"number": 1
|
||||
},
|
||||
{
|
||||
"id": "menu-help",
|
||||
"name": "Help 帮助菜单",
|
||||
"detail": "展开帮助菜单,可打开 About 信息窗口;不向机床发送运动命令。",
|
||||
"number": 2
|
||||
},
|
||||
{
|
||||
"id": "toolbar-estop",
|
||||
"name": "急停 / 解除急停 · F1",
|
||||
"detail": "按当前状态切换急停。触发急停会中止当前执行和运动;解除后仍需单独上电。F1 在文本输入时也有效。",
|
||||
"number": 3
|
||||
},
|
||||
{
|
||||
"id": "toolbar-power",
|
||||
"name": "机床电源 · F2",
|
||||
"detail": "在解除急停后上电;再次点击断电。断电中止运动和任务。上电不会自动回零,也不会自动执行程序。",
|
||||
"number": 4
|
||||
},
|
||||
{
|
||||
"id": "toolbar-open",
|
||||
"name": "打开 G-code · o",
|
||||
"detail": "从本机选择程序文件并通过 Worker/WASM 加载、解析预览。执行活动或加载未结束时不可替换程序;取消选择不提交。",
|
||||
"number": 5
|
||||
},
|
||||
{
|
||||
"id": "toolbar-load-case",
|
||||
"name": "重新加载 XYZAC 案例",
|
||||
"detail": "重新载入选定 INI、HAL 等配置及其 OPEN_FILE 程序。这是 Web 工作区入口;不会自动上电、回零或运行。",
|
||||
"number": 6
|
||||
},
|
||||
{
|
||||
"id": "toolbar-reload",
|
||||
"name": "重新加载当前程序 · Ctrl+r",
|
||||
"detail": "将编辑区当前文本重新提交给解释器并生成静态预览。要求已有文件且允许加载;保留已有 Live Plot。",
|
||||
"number": 7
|
||||
},
|
||||
{
|
||||
"id": "toolbar-run",
|
||||
"name": "执行程序 · r",
|
||||
"detail": "切换 AUTO 并从第 0 行开始执行当前文件。任务层检查上电、回零等条件;完成或 Stop 后可直接再次 Run。",
|
||||
"number": 8
|
||||
},
|
||||
{
|
||||
"id": "toolbar-step",
|
||||
"name": "单步 · t",
|
||||
"detail": "执行下一处程序/运动边界。首次单步启动后暂停;已有运动队列时按执行边界推进,不等于每次恰好执行一行文本。",
|
||||
"number": 9
|
||||
},
|
||||
{
|
||||
"id": "toolbar-pause-resume",
|
||||
"name": "暂停 / 恢复",
|
||||
"detail": "同一按钮按当前状态切换 Pause 与 Resume,保留程序和运动队列。暂停仍属于活动任务,不能据此进行 Jog 或 Home。",
|
||||
"number": 10
|
||||
},
|
||||
{
|
||||
"id": "toolbar-stop",
|
||||
"name": "停止程序 · Esc",
|
||||
"detail": "中止当前任务及运动,保留所选程序。按钮按任务状态启用;Esc 也可停止手动运动。停止后重新 Run 从头开始。",
|
||||
"number": 11
|
||||
},
|
||||
{
|
||||
"id": "toolbar-block-delete",
|
||||
"name": "跳过 / 程序段 · 未实现",
|
||||
"detail": "原生功能用于跳过带斜杠的程序段。当前 WASM 未暴露完整状态,按钮保持禁用,不是本地开关。",
|
||||
"number": 12
|
||||
},
|
||||
{
|
||||
"id": "toolbar-optional-pause",
|
||||
"name": "可选停止 · 未实现",
|
||||
"detail": "原生功能控制是否在 M1 处停止。当前 ABI 未提供完整命令和状态,按钮保持禁用。",
|
||||
"number": 13
|
||||
},
|
||||
{
|
||||
"id": "toolbar-zoom-in",
|
||||
"name": "放大预览",
|
||||
"detail": "增大当前预览的相机缩放;仅改变显示,不改变进给、机床坐标或程序内容。",
|
||||
"number": 14
|
||||
},
|
||||
{
|
||||
"id": "toolbar-zoom-out",
|
||||
"name": "缩小预览",
|
||||
"detail": "减小预览的相机缩放,用于查看更大范围;不改变实际运动。",
|
||||
"number": 15
|
||||
},
|
||||
{
|
||||
"id": "toolbar-view-z",
|
||||
"name": "Z 顶视图",
|
||||
"detail": "正交投影,屏幕右/上对应 X/Y。 点击后显示 Preview 页;不改变机床状态。",
|
||||
"number": 16
|
||||
},
|
||||
{
|
||||
"id": "toolbar-view-z2",
|
||||
"name": "Z2 旋转顶视图",
|
||||
"detail": "顶视图在屏幕平面旋转,右/上对应 Y/-X。 点击后显示 Preview 页;不改变机床状态。",
|
||||
"number": 17
|
||||
},
|
||||
{
|
||||
"id": "toolbar-view-x",
|
||||
"name": "X 侧视图",
|
||||
"detail": "正交投影,右/上对应 Y/Z。 点击后显示 Preview 页;不改变机床状态。",
|
||||
"number": 18
|
||||
},
|
||||
{
|
||||
"id": "toolbar-view-y",
|
||||
"name": "Y 正视图",
|
||||
"detail": "正交投影,右/上对应 X/Z。 点击后显示 Preview 页;不改变机床状态。",
|
||||
"number": 19
|
||||
},
|
||||
{
|
||||
"id": "toolbar-view-y2",
|
||||
"name": "Y2 反向正视图",
|
||||
"detail": "原生工具栏附加方向,右/上对应 Z/X。 点击后显示 Preview 页;不改变机床状态。",
|
||||
"number": 20
|
||||
},
|
||||
{
|
||||
"id": "toolbar-view-p",
|
||||
"name": "P 透视图",
|
||||
"detail": "三维透视观察刀路;可配合拖动、平移和缩放查看。 点击后显示 Preview 页;不改变机床状态。",
|
||||
"number": 21
|
||||
},
|
||||
{
|
||||
"id": "toolbar-rotate",
|
||||
"name": "拖动 / 旋转模式",
|
||||
"detail": "切换鼠标左键拖动时的平移/旋转行为。按钮按下不代表自动旋转,也不控制旋转轴运动。",
|
||||
"number": 22
|
||||
},
|
||||
{
|
||||
"id": "toolbar-clear-live-plot",
|
||||
"name": "清除加工轨迹 · Ctrl+K",
|
||||
"detail": "仅清除 Live Plot 历史,保留静态程序预览。运行中清除后继续积累新轨迹;不会停止、重载或重启程序。",
|
||||
"number": 23
|
||||
},
|
||||
{
|
||||
"id": "workspace-case-select",
|
||||
"name": "仿真案例选择",
|
||||
"detail": "当前目录限定为支持的 XYZAC TRT 案例。选择本身不执行加载;重新载入使用工具栏的案例加载按钮。",
|
||||
"number": 24
|
||||
},
|
||||
{
|
||||
"id": "workspace-load-3d-chips",
|
||||
"name": "加载 3D_Chips.ngc",
|
||||
"detail": "打开随项目提供的示例程序,走同一 WASM 加载和预览流程。保留 Live Plot,执行前需另按 Run。",
|
||||
"number": 25
|
||||
},
|
||||
{
|
||||
"id": "switchkins-0",
|
||||
"name": "Identity · M429",
|
||||
"detail": "选择本案例 active_type=0 的恒等运动学。要求上电、已回零且无活动队列;M429 不会把模块 KINEMATICS_BOTH 类型改为 IDENTITY。",
|
||||
"number": 26
|
||||
},
|
||||
{
|
||||
"id": "switchkins-1",
|
||||
"name": "TCP: XYZAC · M428",
|
||||
"detail": "选择 active_type=1 的 XYZAC TRT 刀尖运动学,使用当前几何偏置进行变换。切换需任务空闲且运动队列为空。",
|
||||
"number": 27
|
||||
},
|
||||
{
|
||||
"id": "switchkins-2",
|
||||
"name": "User K · M430",
|
||||
"detail": "选择 active_type=2 的已链接用户运动学;当前为 identity 模板,不表示可在浏览器动态加载任意运动学模块。",
|
||||
"number": 28
|
||||
},
|
||||
{
|
||||
"id": "tab-manual",
|
||||
"name": "Manual Control · F3",
|
||||
"detail": "显示手动控制页,并在源门控允许时请求对应模式。AUTO 运行或暂停时,仅切换可见页签不会强制变为 MANUAL。",
|
||||
"number": 29
|
||||
},
|
||||
{
|
||||
"id": "tab-mdi",
|
||||
"name": "MDI · F5",
|
||||
"detail": "显示单条指令输入页,并在允许时请求 MDI 模式。提交指令仍受任务层门控约束。",
|
||||
"number": 30
|
||||
},
|
||||
{
|
||||
"id": "tab-diagnostics",
|
||||
"name": "Diagnostics 诊断",
|
||||
"detail": "查看工作区资源、禁用原因、操作记录和错误信息。浏览此页本身不执行运动或恢复操作。",
|
||||
"number": 31
|
||||
},
|
||||
{
|
||||
"id": "manual-home-joint-select",
|
||||
"name": "回零关节选择",
|
||||
"detail": "选择数字关节 0–4,仅决定 Home Joint 的目标。与下面 X/Y/Z/A/C 世界轴选择相互独立。",
|
||||
"number": 32
|
||||
},
|
||||
{
|
||||
"id": "manual-home-axis",
|
||||
"name": "Home Joint 单关节回零",
|
||||
"detail": "对选定数字关节运行原生 homemod。已回零时先确认;回零完成以 homing/homed 状态为准。不是 G53 返回机床零点。",
|
||||
"number": 33
|
||||
},
|
||||
{
|
||||
"id": "manual-home-all",
|
||||
"name": "HOME ALL / RE-HOME ALL",
|
||||
"detail": "按 INI HOME_SEQUENCE 发起全部关节回零。当前案例搜索/锁存速度为 0,可能在当前位置建立参考点而不产生电机位移。",
|
||||
"number": 34
|
||||
},
|
||||
{
|
||||
"id": "manual-axis-x",
|
||||
"name": "选择 X 轴",
|
||||
"detail": "选择世界坐标 X 作为 Jog、Touch Off 目标。选择本身不移动机床,也不修改回零关节选择。线性轴按 mm/inch 显示单位处理。",
|
||||
"number": 35
|
||||
},
|
||||
{
|
||||
"id": "manual-axis-y",
|
||||
"name": "选择 Y 轴",
|
||||
"detail": "选择世界坐标 Y 作为 Jog、Touch Off 目标。选择本身不移动机床,也不修改回零关节选择。线性轴按 mm/inch 显示单位处理。",
|
||||
"number": 36
|
||||
},
|
||||
{
|
||||
"id": "manual-axis-z",
|
||||
"name": "选择 Z 轴",
|
||||
"detail": "选择世界坐标 Z 作为 Jog、Touch Off 目标。选择本身不移动机床,也不修改回零关节选择。线性轴按 mm/inch 显示单位处理。",
|
||||
"number": 37
|
||||
},
|
||||
{
|
||||
"id": "manual-axis-a",
|
||||
"name": "选择 A 轴",
|
||||
"detail": "选择世界坐标 A 作为 Jog、Touch Off 目标。选择本身不移动机床,也不修改回零关节选择。旋转轴以度为单位。",
|
||||
"number": 38
|
||||
},
|
||||
{
|
||||
"id": "manual-axis-c",
|
||||
"name": "选择 C 轴",
|
||||
"detail": "选择世界坐标 C 作为 Jog、Touch Off 目标。选择本身不移动机床,也不修改回零关节选择。旋转轴以度为单位。",
|
||||
"number": 39
|
||||
},
|
||||
{
|
||||
"id": "manual-jog-negative",
|
||||
"name": "Jog − 负向点动",
|
||||
"detail": "沿所选轴负方向运动。Continuous 按住运动、释放/失焦停止;增量模式提交一次指定距离,松开不截断该增量。",
|
||||
"number": 40
|
||||
},
|
||||
{
|
||||
"id": "manual-jog-positive",
|
||||
"name": "Jog + 正向点动",
|
||||
"detail": "沿所选轴正方向运动,使用当前步长和 Jog Speed。手动页可见且任务允许时生效;运行、暂停或回零期间不可开始点动。",
|
||||
"number": 41
|
||||
},
|
||||
{
|
||||
"id": "manual-jog-increment",
|
||||
"name": "点动步长",
|
||||
"detail": "Continuous 为持续点动;0.1000/0.0100/0.0010/0.0001 为单次增量。线性值遵循 mm/inch,A/C 不做英寸换算。",
|
||||
"number": 42
|
||||
},
|
||||
{
|
||||
"id": "manual-touch-off",
|
||||
"name": "Touch Off 坐标系对刀",
|
||||
"detail": "输入当前点应显示的坐标,再选择 P0 当前或 P1–P9 坐标系。通过 G10 L20 改偏置,不移动机床;取消对话框不执行。",
|
||||
"number": 43
|
||||
},
|
||||
{
|
||||
"id": "manual-tool-touch-off",
|
||||
"name": "Tool Touch Off · 未实现",
|
||||
"detail": "原生为刀具偏置测定,涉及 G10 L10/L11 和 G43。当前 ABI 不完整,禁用;不能用普通 Touch Off 冒充。",
|
||||
"number": 44
|
||||
},
|
||||
{
|
||||
"id": "manual-override-limits",
|
||||
"name": "Override Limits · 未实现",
|
||||
"detail": "原生用于限位触发后的脱离操作。当前面板没有对应完整状态/命令边界,禁用。",
|
||||
"number": 45
|
||||
},
|
||||
{
|
||||
"id": "manual-spindle-ccw",
|
||||
"name": "主轴逆时针",
|
||||
"detail": "发送主轴反转方向命令,选中状态来自 WASM 主轴方向。需上电、任务空闲;不同于 A/C 旋转轴点动。",
|
||||
"number": 46
|
||||
},
|
||||
{
|
||||
"id": "manual-spindle-stop",
|
||||
"name": "Stop Spindle",
|
||||
"detail": "停止主轴旋转。仅控制主轴,不等于停止正在执行的程序;程序停止使用工具栏 Stop。",
|
||||
"number": 47
|
||||
},
|
||||
{
|
||||
"id": "manual-spindle-cw",
|
||||
"name": "主轴顺时针",
|
||||
"detail": "发送主轴正转方向命令,运行方向和速度由规范快照回显;按钮不会设置本地伪运行状态。",
|
||||
"number": 48
|
||||
},
|
||||
{
|
||||
"id": "manual-spindle-decrease",
|
||||
"name": "降低主轴速度",
|
||||
"detail": "主轴方向非零时启用。按下发送减速边沿,释放发送 SPINDLE_CONSTANT;不会减速穿过零后自动变成反转。",
|
||||
"number": 49
|
||||
},
|
||||
{
|
||||
"id": "manual-spindle-increase",
|
||||
"name": "提高主轴速度",
|
||||
"detail": "主轴方向非零时启用。按下发送增速边沿,释放结束调速。主轴倍率与该指令速度分开处理。",
|
||||
"number": 50
|
||||
},
|
||||
{
|
||||
"id": "manual-spindle-brake",
|
||||
"name": "Brake 主轴制动",
|
||||
"detail": "请求接合或释放主轴制动,复选框由 WASM 制动状态回显。受手动操作门控约束。",
|
||||
"number": 51
|
||||
},
|
||||
{
|
||||
"id": "manual-coolant-mist",
|
||||
"name": "Mist 雾化冷却",
|
||||
"detail": "独立开关雾化冷却。手动页需上电且解释器空闲;与 Flood 相互独立,可同时开启。",
|
||||
"number": 52
|
||||
},
|
||||
{
|
||||
"id": "manual-coolant-flood",
|
||||
"name": "Flood 浇注冷却",
|
||||
"detail": "独立开关浇注冷却;状态来自 IO 快照,不因界面勾选而提前认定成功。",
|
||||
"number": 53
|
||||
},
|
||||
{
|
||||
"id": "tab-preview",
|
||||
"name": "Preview 刀路页",
|
||||
"detail": "查看静态程序刀路、加工轨迹和刀具位置。切换显示页不会加载文件、改变模式或发起运动。",
|
||||
"number": 54
|
||||
},
|
||||
{
|
||||
"id": "tab-dro",
|
||||
"name": "DRO 数显页",
|
||||
"detail": "切换至坐标数显与坐标/单位选择;其值来自 Worker 快照。不是另一个轴位置输入入口。",
|
||||
"number": 55
|
||||
},
|
||||
{
|
||||
"id": "preview-panLeft",
|
||||
"name": "L 向左平移",
|
||||
"detail": "向左平移相机观察中心。仅操作画布;“0”不会回零机床。",
|
||||
"number": 56
|
||||
},
|
||||
{
|
||||
"id": "preview-panRight",
|
||||
"name": "R 向右平移",
|
||||
"detail": "向右平移相机观察中心。仅操作画布;“0”不会回零机床。",
|
||||
"number": 57
|
||||
},
|
||||
{
|
||||
"id": "preview-panUp",
|
||||
"name": "U 向上平移",
|
||||
"detail": "向上平移相机观察中心。仅操作画布;“0”不会回零机床。",
|
||||
"number": 58
|
||||
},
|
||||
{
|
||||
"id": "preview-panDown",
|
||||
"name": "D 向下平移",
|
||||
"detail": "向下平移相机观察中心。仅操作画布;“0”不会回零机床。",
|
||||
"number": 59
|
||||
},
|
||||
{
|
||||
"id": "preview-reset",
|
||||
"name": "0 重置视图",
|
||||
"detail": "按当前预置视角和缩放重新取景。仅操作画布;“0”不会回零机床。",
|
||||
"number": 60
|
||||
},
|
||||
{
|
||||
"id": "override-jog-speed",
|
||||
"name": "Jog Speed 点动速度",
|
||||
"detail": "调整之后点动使用的速度比例,当前范围 6%–100%。与程序进给倍率不同;滑块本身不发起运动。",
|
||||
"number": 61
|
||||
},
|
||||
{
|
||||
"id": "override-feed",
|
||||
"name": "Feed Override 进给倍率",
|
||||
"detail": "按当前 INI 调整 0%–200% 程序进给倍率,可在自动运行时修改。不是修改 G-code 中的 F 值;快速倍率独立。",
|
||||
"number": 62
|
||||
},
|
||||
{
|
||||
"id": "override-spindle",
|
||||
"name": "Spindle Override 主轴倍率",
|
||||
"detail": "调整主轴输出速度比例。设为 0% 不会丢失方向和原指令速度,恢复倍率后按原方向输出。",
|
||||
"number": 63
|
||||
},
|
||||
{
|
||||
"id": "override-max-velocity",
|
||||
"name": "Max Velocity 最大速度",
|
||||
"detail": "调整轨迹规划器最大速度比例,当前为 6%–100% 适配。它是速度上限,不能代替 Rapid Override。",
|
||||
"number": 64
|
||||
},
|
||||
{
|
||||
"id": "override-rapid",
|
||||
"name": "Rapid Override · 未实现",
|
||||
"detail": "原生为快速运动倍率。当前选定 WASM TP 没有完整 rapidrate 控制,滑块禁用,不借用 Max Velocity 模拟。",
|
||||
"number": 65
|
||||
},
|
||||
{
|
||||
"id": "preview-layer-path",
|
||||
"name": "path · 静态刀路",
|
||||
"detail": "显示/隐藏当前程序解析得到的静态路径。只改变显示,不改变程序、偏置或运动状态。",
|
||||
"number": 66
|
||||
},
|
||||
{
|
||||
"id": "preview-layer-live",
|
||||
"name": "live · 加工轨迹",
|
||||
"detail": "显示/隐藏已采样 Live Plot,隐藏不会删除轨迹。只改变显示,不改变程序、偏置或运动状态。",
|
||||
"number": 67
|
||||
},
|
||||
{
|
||||
"id": "preview-layer-limits",
|
||||
"name": "limits · 机床限位",
|
||||
"detail": "显示/隐藏 WASM 提供的 XYZ 软限位框。只改变显示,不改变程序、偏置或运动状态。",
|
||||
"number": 68
|
||||
},
|
||||
{
|
||||
"id": "preview-layer-velocity",
|
||||
"name": "velocity · 运动速度",
|
||||
"detail": "显示/隐藏预览中的当前规范速度文字。只改变显示,不改变程序、偏置或运动状态。",
|
||||
"number": 69
|
||||
},
|
||||
{
|
||||
"id": "preview-layer-offsets",
|
||||
"name": "offsets · 坐标偏置",
|
||||
"detail": "显示/隐藏当前已支持的 G5x 平移偏置指示。只改变显示,不改变程序、偏置或运动状态。",
|
||||
"number": 70
|
||||
},
|
||||
{
|
||||
"id": "preview-layer-extents",
|
||||
"name": "extents · 程序范围",
|
||||
"detail": "显示/隐藏规范刀路样本的包围范围。只改变显示,不改变程序、偏置或运动状态。",
|
||||
"number": 71
|
||||
},
|
||||
{
|
||||
"id": "program-editor",
|
||||
"name": "G-code 编辑区",
|
||||
"detail": "修改待提交程序文本。修改后必须通过 Reload 重新提交才影响解释器;编辑文字不等于已经加载或执行。",
|
||||
"number": 72
|
||||
},
|
||||
{
|
||||
"id": "mdi-command",
|
||||
"name": "MDI 指令输入",
|
||||
"detail": "输入单条 G-code/M-code;Enter 与 Go 使用同一提交路径。提交会去除首尾空白,空输入不发送;执行受 manual_ok 与任务门控限制。",
|
||||
"number": 73
|
||||
},
|
||||
{
|
||||
"id": "mdi-submit",
|
||||
"name": "Go 执行 MDI",
|
||||
"detail": "将输入指令提交给 WASM 解释器。可能产生真实仿真运动或 IO 动作;收到 ACK 不代表排队运动已经完成。",
|
||||
"number": 74
|
||||
},
|
||||
{
|
||||
"id": "mdi-history-select",
|
||||
"name": "MDI 历史条目",
|
||||
"detail": "单击将该条指令填回输入框,双击重新提交执行。上下方向键浏览历史,相邻重复记录去重;历史并非执行成功证明。",
|
||||
"number": 75
|
||||
},
|
||||
{
|
||||
"id": "dro-coordinate",
|
||||
"name": "Machine / Relative",
|
||||
"detail": "切换机床坐标与相对工件坐标显示。当前相对投影支持已实现的 G5x 平移偏置,不用显示切换改写运动目标。",
|
||||
"number": 76
|
||||
},
|
||||
{
|
||||
"id": "dro-display",
|
||||
"name": "Actual / Commanded",
|
||||
"detail": "切换实际与指令位置的显示语义。当前理想仿真两者可相同,不能据标签推断已模拟真实跟随误差。",
|
||||
"number": 77
|
||||
},
|
||||
{
|
||||
"id": "dro-units",
|
||||
"name": "mm / inch",
|
||||
"detail": "切换线性坐标显示单位,A/C 仍为角度。该设置也用于界面点动和对刀输入的线性单位换算,不改写原程序。",
|
||||
"number": 78
|
||||
},
|
||||
{
|
||||
"id": "menu-file-edit-tool-data",
|
||||
"name": "Edit tool data… · 未实现",
|
||||
"detail": "桌面原生会启动工具表编辑器,浏览器没有对应宿主编辑流程,因此该菜单项禁用。",
|
||||
"number": 79
|
||||
},
|
||||
{
|
||||
"id": "menu-file-quit",
|
||||
"name": "Quit · 未实现",
|
||||
"detail": "桌面原生用于结束 AXIS 进程。Web 不模拟结束机床进程,此项禁用;可由浏览器关闭页面。",
|
||||
"number": 80
|
||||
},
|
||||
{
|
||||
"id": "menu-help-about",
|
||||
"name": "About AXIS",
|
||||
"detail": "显示本地 About 窗口,查看应用名称与案例信息;不会改变 Worker、任务或 IO 状态。",
|
||||
"number": 81
|
||||
},
|
||||
{
|
||||
"id": "about-close",
|
||||
"name": "About 窗口 OK",
|
||||
"detail": "关闭 About 窗口并返回原界面。属于界面操作,不等于命令确认、复位或启动。",
|
||||
"number": 82
|
||||
},
|
||||
{
|
||||
"id": "program-file-input",
|
||||
"name": "文件选择对话框入口",
|
||||
"detail": "隐藏的浏览器文件输入,由编号 05“打开 G-code”触发。选择 .ngc/.nc/.gcode 等文件后走同一加载事务;没有第二个可见按钮。",
|
||||
"number": 83
|
||||
}
|
||||
],
|
||||
"images": [
|
||||
"01-toolbar-and-workspace.png",
|
||||
"02-manual-and-homing.png",
|
||||
"03-views-and-overrides.png",
|
||||
"04-mdi-dro-and-menus.png"
|
||||
]
|
||||
}
|
||||
183
scripts/generate_panel_png_guide.mjs
Normal file
183
scripts/generate_panel_png_guide.mjs
Normal file
@@ -0,0 +1,183 @@
|
||||
import assert from "node:assert/strict";
|
||||
import { mkdir, writeFile } from "node:fs/promises";
|
||||
import { resolve } from "node:path";
|
||||
|
||||
const modulePath = process.env.PLAYWRIGHT_MODULE ?? "/home/mes006/.npm/_npx/e41f203b7505f1fb/node_modules/playwright/index.js";
|
||||
const imported = await import(modulePath);
|
||||
const { chromium } = imported.default ?? imported;
|
||||
const url = process.env.XYZAC_PANEL_URL ?? "http://127.0.0.1:5175/";
|
||||
const out = resolve("docs/web-panel-png-guide");
|
||||
await mkdir(out, { recursive: true });
|
||||
const entries = [];
|
||||
const add = (id, name, detail) => entries.push({ id, name, detail, number: entries.length + 1 });
|
||||
add("menu-file", "File 文件菜单", "展开文件菜单。当前包含工具表编辑和退出入口,二者受浏览器运行边界限制。");
|
||||
add("menu-help", "Help 帮助菜单", "展开帮助菜单,可打开 About 信息窗口;不向机床发送运动命令。");
|
||||
add("toolbar-estop", "急停 / 解除急停 · F1", "按当前状态切换急停。触发急停会中止当前执行和运动;解除后仍需单独上电。F1 在文本输入时也有效。");
|
||||
add("toolbar-power", "机床电源 · F2", "在解除急停后上电;再次点击断电。断电中止运动和任务。上电不会自动回零,也不会自动执行程序。");
|
||||
add("toolbar-open", "打开 G-code · o", "从本机选择程序文件并通过 Worker/WASM 加载、解析预览。执行活动或加载未结束时不可替换程序;取消选择不提交。");
|
||||
add("toolbar-load-case", "重新加载 XYZAC 案例", "重新载入选定 INI、HAL 等配置及其 OPEN_FILE 程序。这是 Web 工作区入口;不会自动上电、回零或运行。");
|
||||
add("toolbar-reload", "重新加载当前程序 · Ctrl+r", "将编辑区当前文本重新提交给解释器并生成静态预览。要求已有文件且允许加载;保留已有 Live Plot。");
|
||||
add("toolbar-run", "执行程序 · r", "切换 AUTO 并从第 0 行开始执行当前文件。任务层检查上电、回零等条件;完成或 Stop 后可直接再次 Run。");
|
||||
add("toolbar-step", "单步 · t", "执行下一处程序/运动边界。首次单步启动后暂停;已有运动队列时按执行边界推进,不等于每次恰好执行一行文本。");
|
||||
add("toolbar-pause-resume", "暂停 / 恢复", "同一按钮按当前状态切换 Pause 与 Resume,保留程序和运动队列。暂停仍属于活动任务,不能据此进行 Jog 或 Home。");
|
||||
add("toolbar-stop", "停止程序 · Esc", "中止当前任务及运动,保留所选程序。按钮按任务状态启用;Esc 也可停止手动运动。停止后重新 Run 从头开始。");
|
||||
add("toolbar-block-delete", "跳过 / 程序段 · 未实现", "原生功能用于跳过带斜杠的程序段。当前 WASM 未暴露完整状态,按钮保持禁用,不是本地开关。");
|
||||
add("toolbar-optional-pause", "可选停止 · 未实现", "原生功能控制是否在 M1 处停止。当前 ABI 未提供完整命令和状态,按钮保持禁用。");
|
||||
add("toolbar-zoom-in", "放大预览", "增大当前预览的相机缩放;仅改变显示,不改变进给、机床坐标或程序内容。");
|
||||
add("toolbar-zoom-out", "缩小预览", "减小预览的相机缩放,用于查看更大范围;不改变实际运动。");
|
||||
for (const [id, name, detail] of [
|
||||
["z", "Z 顶视图", "正交投影,屏幕右/上对应 X/Y。"], ["z2", "Z2 旋转顶视图", "顶视图在屏幕平面旋转,右/上对应 Y/-X。"],
|
||||
["x", "X 侧视图", "正交投影,右/上对应 Y/Z。"], ["y", "Y 正视图", "正交投影,右/上对应 X/Z。"],
|
||||
["y2", "Y2 反向正视图", "原生工具栏附加方向,右/上对应 Z/X。"], ["p", "P 透视图", "三维透视观察刀路;可配合拖动、平移和缩放查看。"],
|
||||
]) add(`toolbar-view-${id}`, name, `${detail} 点击后显示 Preview 页;不改变机床状态。`);
|
||||
add("toolbar-rotate", "拖动 / 旋转模式", "切换鼠标左键拖动时的平移/旋转行为。按钮按下不代表自动旋转,也不控制旋转轴运动。");
|
||||
add("toolbar-clear-live-plot", "清除加工轨迹 · Ctrl+K", "仅清除 Live Plot 历史,保留静态程序预览。运行中清除后继续积累新轨迹;不会停止、重载或重启程序。");
|
||||
add("workspace-case-select", "仿真案例选择", "当前目录限定为支持的 XYZAC TRT 案例。选择本身不执行加载;重新载入使用工具栏的案例加载按钮。");
|
||||
add("workspace-load-3d-chips", "加载 3D_Chips.ngc", "打开随项目提供的示例程序,走同一 WASM 加载和预览流程。保留 Live Plot,执行前需另按 Run。");
|
||||
add("switchkins-0", "Identity · M429", "选择本案例 active_type=0 的恒等运动学。要求上电、已回零且无活动队列;M429 不会把模块 KINEMATICS_BOTH 类型改为 IDENTITY。");
|
||||
add("switchkins-1", "TCP: XYZAC · M428", "选择 active_type=1 的 XYZAC TRT 刀尖运动学,使用当前几何偏置进行变换。切换需任务空闲且运动队列为空。");
|
||||
add("switchkins-2", "User K · M430", "选择 active_type=2 的已链接用户运动学;当前为 identity 模板,不表示可在浏览器动态加载任意运动学模块。");
|
||||
add("tab-manual", "Manual Control · F3", "显示手动控制页,并在源门控允许时请求对应模式。AUTO 运行或暂停时,仅切换可见页签不会强制变为 MANUAL。");
|
||||
add("tab-mdi", "MDI · F5", "显示单条指令输入页,并在允许时请求 MDI 模式。提交指令仍受任务层门控约束。");
|
||||
add("tab-diagnostics", "Diagnostics 诊断", "查看工作区资源、禁用原因、操作记录和错误信息。浏览此页本身不执行运动或恢复操作。");
|
||||
add("manual-home-joint-select", "回零关节选择", "选择数字关节 0–4,仅决定 Home Joint 的目标。与下面 X/Y/Z/A/C 世界轴选择相互独立。");
|
||||
add("manual-home-axis", "Home Joint 单关节回零", "对选定数字关节运行原生 homemod。已回零时先确认;回零完成以 homing/homed 状态为准。不是 G53 返回机床零点。");
|
||||
add("manual-home-all", "HOME ALL / RE-HOME ALL", "按 INI HOME_SEQUENCE 发起全部关节回零。当前案例搜索/锁存速度为 0,可能在当前位置建立参考点而不产生电机位移。");
|
||||
for (const axis of ["x", "y", "z", "a", "c"]) add(`manual-axis-${axis}`, `选择 ${axis.toUpperCase()} 轴`, `选择世界坐标 ${axis.toUpperCase()} 作为 Jog、Touch Off 目标。选择本身不移动机床,也不修改回零关节选择。${["a", "c"].includes(axis) ? "旋转轴以度为单位。" : "线性轴按 mm/inch 显示单位处理。"}`);
|
||||
add("manual-jog-negative", "Jog − 负向点动", "沿所选轴负方向运动。Continuous 按住运动、释放/失焦停止;增量模式提交一次指定距离,松开不截断该增量。");
|
||||
add("manual-jog-positive", "Jog + 正向点动", "沿所选轴正方向运动,使用当前步长和 Jog Speed。手动页可见且任务允许时生效;运行、暂停或回零期间不可开始点动。");
|
||||
add("manual-jog-increment", "点动步长", "Continuous 为持续点动;0.1000/0.0100/0.0010/0.0001 为单次增量。线性值遵循 mm/inch,A/C 不做英寸换算。");
|
||||
add("manual-touch-off", "Touch Off 坐标系对刀", "输入当前点应显示的坐标,再选择 P0 当前或 P1–P9 坐标系。通过 G10 L20 改偏置,不移动机床;取消对话框不执行。");
|
||||
add("manual-tool-touch-off", "Tool Touch Off · 未实现", "原生为刀具偏置测定,涉及 G10 L10/L11 和 G43。当前 ABI 不完整,禁用;不能用普通 Touch Off 冒充。");
|
||||
add("manual-override-limits", "Override Limits · 未实现", "原生用于限位触发后的脱离操作。当前面板没有对应完整状态/命令边界,禁用。");
|
||||
add("manual-spindle-ccw", "主轴逆时针", "发送主轴反转方向命令,选中状态来自 WASM 主轴方向。需上电、任务空闲;不同于 A/C 旋转轴点动。");
|
||||
add("manual-spindle-stop", "Stop Spindle", "停止主轴旋转。仅控制主轴,不等于停止正在执行的程序;程序停止使用工具栏 Stop。");
|
||||
add("manual-spindle-cw", "主轴顺时针", "发送主轴正转方向命令,运行方向和速度由规范快照回显;按钮不会设置本地伪运行状态。");
|
||||
add("manual-spindle-decrease", "降低主轴速度", "主轴方向非零时启用。按下发送减速边沿,释放发送 SPINDLE_CONSTANT;不会减速穿过零后自动变成反转。");
|
||||
add("manual-spindle-increase", "提高主轴速度", "主轴方向非零时启用。按下发送增速边沿,释放结束调速。主轴倍率与该指令速度分开处理。");
|
||||
add("manual-spindle-brake", "Brake 主轴制动", "请求接合或释放主轴制动,复选框由 WASM 制动状态回显。受手动操作门控约束。");
|
||||
add("manual-coolant-mist", "Mist 雾化冷却", "独立开关雾化冷却。手动页需上电且解释器空闲;与 Flood 相互独立,可同时开启。");
|
||||
add("manual-coolant-flood", "Flood 浇注冷却", "独立开关浇注冷却;状态来自 IO 快照,不因界面勾选而提前认定成功。");
|
||||
add("tab-preview", "Preview 刀路页", "查看静态程序刀路、加工轨迹和刀具位置。切换显示页不会加载文件、改变模式或发起运动。");
|
||||
add("tab-dro", "DRO 数显页", "切换至坐标数显与坐标/单位选择;其值来自 Worker 快照。不是另一个轴位置输入入口。");
|
||||
for (const [id, name, text] of [["panLeft", "L 向左平移", "向左平移相机观察中心"], ["panRight", "R 向右平移", "向右平移相机观察中心"], ["panUp", "U 向上平移", "向上平移相机观察中心"], ["panDown", "D 向下平移", "向下平移相机观察中心"], ["reset", "0 重置视图", "按当前预置视角和缩放重新取景"]]) add(`preview-${id}`, name, `${text}。仅操作画布;“0”不会回零机床。`);
|
||||
add("override-jog-speed", "Jog Speed 点动速度", "调整之后点动使用的速度比例,当前范围 6%–100%。与程序进给倍率不同;滑块本身不发起运动。");
|
||||
add("override-feed", "Feed Override 进给倍率", "按当前 INI 调整 0%–200% 程序进给倍率,可在自动运行时修改。不是修改 G-code 中的 F 值;快速倍率独立。");
|
||||
add("override-spindle", "Spindle Override 主轴倍率", "调整主轴输出速度比例。设为 0% 不会丢失方向和原指令速度,恢复倍率后按原方向输出。");
|
||||
add("override-max-velocity", "Max Velocity 最大速度", "调整轨迹规划器最大速度比例,当前为 6%–100% 适配。它是速度上限,不能代替 Rapid Override。");
|
||||
add("override-rapid", "Rapid Override · 未实现", "原生为快速运动倍率。当前选定 WASM TP 没有完整 rapidrate 控制,滑块禁用,不借用 Max Velocity 模拟。");
|
||||
for (const [id, name, detail] of [["path", "静态刀路", "显示/隐藏当前程序解析得到的静态路径"], ["live", "加工轨迹", "显示/隐藏已采样 Live Plot,隐藏不会删除轨迹"], ["limits", "机床限位", "显示/隐藏 WASM 提供的 XYZ 软限位框"], ["velocity", "运动速度", "显示/隐藏预览中的当前规范速度文字"], ["offsets", "坐标偏置", "显示/隐藏当前已支持的 G5x 平移偏置指示"], ["extents", "程序范围", "显示/隐藏规范刀路样本的包围范围"]]) add(`preview-layer-${id}`, `${id} · ${name}`, `${detail}。只改变显示,不改变程序、偏置或运动状态。`);
|
||||
add("program-editor", "G-code 编辑区", "修改待提交程序文本。修改后必须通过 Reload 重新提交才影响解释器;编辑文字不等于已经加载或执行。");
|
||||
add("mdi-command", "MDI 指令输入", "输入单条 G-code/M-code;Enter 与 Go 使用同一提交路径。提交会去除首尾空白,空输入不发送;执行受 manual_ok 与任务门控限制。");
|
||||
add("mdi-submit", "Go 执行 MDI", "将输入指令提交给 WASM 解释器。可能产生真实仿真运动或 IO 动作;收到 ACK 不代表排队运动已经完成。");
|
||||
add("mdi-history-select", "MDI 历史条目", "单击将该条指令填回输入框,双击重新提交执行。上下方向键浏览历史,相邻重复记录去重;历史并非执行成功证明。");
|
||||
add("dro-coordinate", "Machine / Relative", "切换机床坐标与相对工件坐标显示。当前相对投影支持已实现的 G5x 平移偏置,不用显示切换改写运动目标。");
|
||||
add("dro-display", "Actual / Commanded", "切换实际与指令位置的显示语义。当前理想仿真两者可相同,不能据标签推断已模拟真实跟随误差。");
|
||||
add("dro-units", "mm / inch", "切换线性坐标显示单位,A/C 仍为角度。该设置也用于界面点动和对刀输入的线性单位换算,不改写原程序。");
|
||||
add("menu-file-edit-tool-data", "Edit tool data… · 未实现", "桌面原生会启动工具表编辑器,浏览器没有对应宿主编辑流程,因此该菜单项禁用。");
|
||||
add("menu-file-quit", "Quit · 未实现", "桌面原生用于结束 AXIS 进程。Web 不模拟结束机床进程,此项禁用;可由浏览器关闭页面。");
|
||||
add("menu-help-about", "About AXIS", "显示本地 About 窗口,查看应用名称与案例信息;不会改变 Worker、任务或 IO 状态。");
|
||||
add("about-close", "About 窗口 OK", "关闭 About 窗口并返回原界面。属于界面操作,不等于命令确认、复位或启动。");
|
||||
add("program-file-input", "文件选择对话框入口", "隐藏的浏览器文件输入,由编号 05“打开 G-code”触发。选择 .ngc/.nc/.gcode 等文件后走同一加载事务;没有第二个可见按钮。");
|
||||
assert.equal(entries.length, 83);
|
||||
const byId = new Map(entries.map((entry) => [entry.id, entry]));
|
||||
const covered = new Set();
|
||||
const escape = (s) => String(s).replaceAll("&", "&").replaceAll("<", "<").replaceAll('"', """);
|
||||
const browser = await chromium.launch({ headless: false, executablePath: "/usr/bin/google-chrome", slowMo: 90 });
|
||||
const page = await browser.newPage({ viewport: { width: 1600, height: 1100 }, deviceScaleFactor: 2 });
|
||||
const errors = [];
|
||||
page.on("pageerror", (error) => errors.push(error.message));
|
||||
page.on("dialog", (dialog) => dialog.dismiss());
|
||||
async function capture(selector, title, ids) {
|
||||
const locator = page.locator(selector);
|
||||
await locator.scrollIntoViewIfNeeded();
|
||||
await page.waitForTimeout(180);
|
||||
const bounds = await locator.boundingBox();
|
||||
const marks = [];
|
||||
for (const id of ids) {
|
||||
assert.ok(byId.has(id), `unknown id ${id}`);
|
||||
const control = locator.locator(`[data-axis-control="${id}"]`);
|
||||
if (!await control.count()) continue;
|
||||
if (!await control.first().isVisible()) continue;
|
||||
const box = await control.first().boundingBox();
|
||||
marks.push({ ...byId.get(id), x: box.x - bounds.x, y: box.y - bounds.y, w: box.width, h: box.height });
|
||||
covered.add(id);
|
||||
}
|
||||
const image = await locator.screenshot();
|
||||
return { title, image: image.toString("base64"), width: bounds.width, height: bounds.height, marks };
|
||||
}
|
||||
const ids = (prefix) => entries.filter((e) => e.id.startsWith(prefix)).map((e) => e.id);
|
||||
const docs = [];
|
||||
try {
|
||||
await page.goto(url);
|
||||
await page.waitForFunction(() => document.querySelector("main")?.dataset.axisProgramLoading === "false");
|
||||
await page.locator('[data-axis-control="toolbar-power"]').click();
|
||||
await page.locator('[data-axis-control="manual-home-all"]').click();
|
||||
await page.waitForFunction(() => document.querySelector(".command-status")?.textContent === "HOME complete");
|
||||
await page.evaluate(() => scrollTo(0, 0));
|
||||
await page.screenshot({ path: `${out}/00-panel-overview-hd.png`, fullPage: true });
|
||||
docs.push({ file: "01-toolbar-and-workspace", title: "工具栏与文件操作", note: "截图状态:XYZAC TRT 已上电、已回零、程序空闲。灰色按钮须结合禁用原因判断,不代表点击后可以执行。", captures: [
|
||||
await capture(".axis-menubar", "文件 / 帮助菜单入口", ["menu-file", "menu-help"]),
|
||||
await capture(".axis-toolbar", "机器与程序工具栏 · 图标从左至右", ids("toolbar-")),
|
||||
await capture(".axis-case-strip", "案例与示例程序", ids("workspace-")),
|
||||
], extra: ["program-file-input"] });
|
||||
docs.push({ file: "02-manual-and-homing", title: "手动操作与原生回零", note: "Home Joint 选择数字关节;Jog/Touch Off 选择世界轴。当前案例 Home 可能只重新建立坐标参考点,电机位置不变,这是原生 INI 回零语义。", captures: [
|
||||
await capture(".left-notebook", "Manual Control 手动页", [...ids("tab-").filter((id) => ["tab-manual", "tab-mdi", "tab-diagnostics"].includes(id)), ...ids("manual-")]),
|
||||
] });
|
||||
docs.push({ file: "03-views-and-overrides", title: "运动学、视图与倍率", note: "Switchkins 改变运动学解释;相机与图层仅改变显示。Feed、Spindle、Jog 和 Max Velocity 各有独立含义,不能互相代替。", captures: [
|
||||
await capture(".xyzac-kinematics", "Switchkins 运动学模式", ids("switchkins-")),
|
||||
await capture(".right-notebook", "Preview / DRO 与画布平移", ["tab-preview", "tab-dro", ...ids("preview-pan"), "preview-reset"]),
|
||||
await capture(".axis-metrics", "倍率滑块与预览图层", [...ids("override-"), ...ids("preview-layer-")]),
|
||||
await capture(".axis-program-pane", "程序编辑与执行记录", ["program-editor"]),
|
||||
] });
|
||||
await page.locator('[data-axis-control="tab-mdi"]').click();
|
||||
await page.locator('[data-axis-control="mdi-command"]').fill("G21");
|
||||
await page.locator('[data-axis-control="mdi-submit"]').click();
|
||||
await page.waitForFunction(() => document.querySelector(".command-status")?.textContent === "MDI_EXECUTE acknowledged");
|
||||
const mdi = await capture(".left-notebook", "MDI 单条指令与历史", ids("mdi-"));
|
||||
await page.locator('[data-axis-control="tab-dro"]').click();
|
||||
const dro = await capture(".right-notebook", "DRO 数显设置", ids("dro-"));
|
||||
await page.locator('[data-axis-control="menu-file"]').click();
|
||||
const fileMenu = await capture('.axis-menu-item:has([data-axis-control="menu-file"]) .axis-menu-popup', "File 菜单展开", ["menu-file-edit-tool-data", "menu-file-quit"]);
|
||||
await page.locator('[data-axis-control="menu-file"]').click();
|
||||
await page.locator('[data-axis-control="menu-help"]').click();
|
||||
const helpMenu = await capture('.axis-menu-item:has([data-axis-control="menu-help"]) .axis-menu-popup', "Help 菜单展开", ["menu-help-about"]);
|
||||
await page.locator('[data-axis-control="menu-help-about"]').click();
|
||||
const about = await capture('.axis-about-dialog', "About 弹窗", ["about-close"]);
|
||||
docs.push({ file: "04-mdi-dro-and-menus", title: "MDI、数显与菜单窗口", note: "MDI 示例仅提交 G21(毫米单位),未执行加工运动。错误及禁用原因以当前状态栏与 Diagnostics 为准。", captures: [mdi, dro, fileMenu, helpMenu, about] });
|
||||
covered.add("program-file-input");
|
||||
assert.deepEqual(entries.filter((e) => !covered.has(e.id)).map((e) => e.id), [], "unannotated controls");
|
||||
assert.deepEqual(errors, []);
|
||||
const reportPage = await browser.newPage({ viewport: { width: 1800, height: 1200 }, deviceScaleFactor: 2 });
|
||||
const paths = [];
|
||||
for (const doc of docs) {
|
||||
const blocks = doc.captures.map((cap) => {
|
||||
const scale = Math.min(1.2, 1672 / cap.width);
|
||||
const width = cap.width * scale;
|
||||
const height = cap.height * scale;
|
||||
// Put badges in lanes outside small controls, with a leader to each target.
|
||||
const used = [];
|
||||
const badges = cap.marks.map((mark) => {
|
||||
let x = Math.max(14, Math.min(width - 14, (mark.x + mark.w / 2) * scale));
|
||||
let y = mark.y * scale + 60 - 16;
|
||||
while (used.some((p) => Math.abs(p.x - x) < 34 && Math.abs(p.y - y) < 28)) y -= 30;
|
||||
used.push({ x, y });
|
||||
const tx = (mark.x + mark.w / 2) * scale, ty = (mark.y + mark.h / 2) * scale + 60;
|
||||
return `<line x1="${x}" y1="${y}" x2="${tx}" y2="${ty}" stroke="#b32732" stroke-width="1.5"/><circle cx="${x}" cy="${y}" r="13" fill="#b32732" stroke="white" stroke-width="2"/><text x="${x}" y="${y+4.5}" text-anchor="middle" font-size="12" font-weight="bold" fill="white">${mark.number}</text>`;
|
||||
}).join("");
|
||||
return `<section><h2>${cap.title}</h2><div class="shot" style="width:${width}px;height:${height+76}px"><img style="top:60px;width:${width}px;height:${height}px" src="data:image/png;base64,${cap.image}"/><svg width="${width}" height="${height+76}">${badges}</svg></div><div class="legend">${cap.marks.map((e) => `<article><b class="number">${e.number}</b><div><h3>${escape(e.name)}</h3><p>${escape(e.detail)}</p><code>${e.id}</code></div></article>`).join("")}</div></section>`;
|
||||
}).join("");
|
||||
const extra = (doc.extra ?? []).map((id) => { const e = byId.get(id); return `<article><b class="number">${e.number}</b><div><h3>${escape(e.name)}</h3><p>${escape(e.detail)}</p></div></article>`; }).join("");
|
||||
const html = `<!doctype html><html lang="zh-CN"><meta charset="utf-8"><title>${doc.title}</title><style>
|
||||
*{box-sizing:border-box}body{margin:0;width:1800px;padding:44px 64px;background:#fff;color:#182226;font-family:"Noto Sans CJK SC",sans-serif;letter-spacing:0}header{border-bottom:4px solid #126b67;padding-bottom:22px}h1{font-size:38px;margin:8px 0}header small{color:#126b67;font-size:18px}header p{font-size:20px;line-height:1.65;margin:10px 0 0}h2{font-size:25px;margin:28px 0 6px;border-left:5px solid #126b67;padding-left:14px}.shot{position:relative;margin:0 auto 14px;max-width:100%}.shot img,.shot svg{position:absolute;left:0}.shot svg{top:0;overflow:visible}.legend{display:grid;grid-template-columns:1fr 1fr;gap:0 36px}article{display:flex;gap:13px;padding:12px 0;border-bottom:1px solid #d8e0e2;break-inside:avoid}.number{background:#b32732;color:white;width:32px;height:32px;border-radius:50%;text-align:center;line-height:32px;flex-shrink:0;font-size:17px}h3{font-size:21px;margin:0 0 4px}p{font-size:18px;line-height:1.65;margin:0}code{font-size:12px;color:#687579}footer{margin-top:28px;border-top:2px solid #126b67;padding-top:12px;font-size:15px;color:#58656a}article div{min-width:0}</style><header><small>LinuxCNC AXIS Web/WASM · XYZAC TRT · 控件功能图解 ${doc.file.slice(0,2)}/04</small><h1>${doc.title}</h1><p>${doc.note}</p></header>${blocks}${extra}<footer>红色编号指向实际控件;说明依据当前 Web 实现与源流程契约。灰色“未实现”项不代表已支持。截图来源:${url} · 2026-09-09 · PNG 2× 清晰度</footer></html>`;
|
||||
await writeFile(`${out}/${doc.file}.html`, html);
|
||||
await reportPage.setContent(html);
|
||||
await reportPage.evaluate(() => document.fonts.ready);
|
||||
await reportPage.waitForTimeout(250);
|
||||
assert.equal(await reportPage.evaluate(() => document.documentElement.scrollWidth <= innerWidth), true);
|
||||
await reportPage.screenshot({ path: `${out}/${doc.file}.png`, fullPage: true });
|
||||
paths.push(`${doc.file}.png`);
|
||||
}
|
||||
await writeFile(`${out}/controls.json`, JSON.stringify({ url, controls: entries, images: paths }, null, 2));
|
||||
console.log(JSON.stringify({ status: "verified", controls: entries.length, annotated: covered.size, output: out, images: paths }));
|
||||
} finally { await browser.close(); }
|
||||
@@ -404,7 +404,7 @@ export function XyzacToolPreview({ visual, view = "p", zoom = 1, rotateMode = fa
|
||||
element.dataset.xyzacLimitsVisible = String(limitGrid.visible);
|
||||
element.dataset.xyzacExtentsVisible = String(extents.visible);
|
||||
element.dataset.xyzacOffset = JSON.stringify(offset);
|
||||
if (hudRef.current) hudRef.current.textContent = `TOOL PREVIEW\nX ${Number(renderedPose.x).toFixed(3)} Y ${Number(renderedPose.y).toFixed(3)} Z ${Number(renderedPose.z).toFixed(3)}\nA ${Number(renderedPose.a).toFixed(3)} C ${Number(renderedPose.c).toFixed(3)}\nJ0 ${Number(renderedJoints[0] ?? 0).toFixed(3)} J1 ${Number(renderedJoints[1] ?? 0).toFixed(3)} J2 ${Number(renderedJoints[2] ?? 0).toFixed(3)}\nJ3 ${Number(renderedJoints[3] ?? 0).toFixed(3)} J4 ${Number(renderedJoints[4] ?? 0).toFixed(3)}`;
|
||||
if (hudRef.current) hudRef.current.textContent = `TOOL PREVIEW\nX ${Number(renderedPose.x).toFixed(3)} Y ${Number(renderedPose.y).toFixed(3)} Z ${Number(renderedPose.z).toFixed(3)}\nA ${Number(renderedPose.a).toFixed(3)} C ${Number(renderedPose.c).toFixed(3)}`;
|
||||
if (layer.showVelocity && hudRef.current) hudRef.current.textContent += `\nV ${Number(state.velocityMmMin ?? 0).toFixed(1)} mm/min`;
|
||||
controls.mouseButtons.LEFT = rotateRef.current ? THREE.MOUSE.ROTATE : THREE.MOUSE.PAN;
|
||||
controls.update(); renderer.render(scene, camera); frame = requestAnimationFrame(render);
|
||||
@@ -417,7 +417,7 @@ export function XyzacToolPreview({ visual, view = "p", zoom = 1, rotateMode = fa
|
||||
const helixCount = visual.toolpath.filter((segment) => (segment as { kind?: string }).kind === "helix").length;
|
||||
const sampleCount = visual.toolpath.reduce((count, segment) => count + (Array.isArray((segment as { samples?: unknown[] }).samples) ? (segment as { samples: unknown[] }).samples.length : 0), 0);
|
||||
const controllerButton = (action: string, label: string, glyph: string) => ["zoomIn", "zoomOut"].includes(action) ? null : <button type="button" data-axis-control={`preview-${action}`} data-xyzac-controller={action} title={label} aria-label={label} onClick={() => { const controller = (host.current as (HTMLDivElement & { xyzacController?: Record<string, () => void> }) | null)?.xyzacController; controller?.[action]?.(); }}>{glyph}</button>;
|
||||
return <div className="three-viewer xyzac-tool-preview" ref={host} data-xyzac-authoritative={String(visual.authoritative)} data-xyzac-preview="toolpath" data-xyzac-controller="orbit" data-xyzac-origin="0,0,0" data-xyzac-origin-axes="X,Y,Z" data-xyzac-toolpath-count={visual.toolpath.length} data-xyzac-helix-count={helixCount} data-xyzac-sample-count={sampleCount} data-xyzac-samples-source="linuxcnc-wasm-sim_posemath_segment_point" data-xyzac-live-source="linuxcnc-source-tp" data-xyzac-live-progress={visual.activeProgress} data-xyzac-live-pose={JSON.stringify(visual.livePose)} data-xyzac-tick={visual.tick} data-xyzac-state-hash={visual.stateHash} data-xyzac-active-segment={visual.activeSegmentId ?? ""} aria-label="XYZAC authoritative tool preview"><div className="xyzac-view-controller" role="toolbar" aria-label="3D preview controller">{controllerButton("zoomIn", "Zoom in", "+")}{controllerButton("zoomOut", "Zoom out", "-")}<span className="xyzac-controller-divider" aria-hidden="true" />{controllerButton("panLeft", "Pan left", "L")}{controllerButton("panRight", "Pan right", "R")}{controllerButton("panUp", "Pan up", "U")}{controllerButton("panDown", "Pan down", "D")}<span className="xyzac-controller-divider" aria-hidden="true" />{controllerButton("reset", "Reset 3D view", "0")}</div><pre ref={hudRef} className="axis-preview-hud" aria-label="XYZAC tool preview state">{visual.authoritative ? `TOOL PREVIEW\nX ${Number(pose.x).toFixed(3)} Y ${Number(pose.y).toFixed(3)} Z ${Number(pose.z).toFixed(3)}\nA ${Number(pose.a).toFixed(3)} C ${Number(pose.c).toFixed(3)}\nJ0 ${Number(visual.joints[0]).toFixed(3)} J1 ${Number(visual.joints[1]).toFixed(3)} J2 ${Number(visual.joints[2]).toFixed(3)}\nJ3 ${Number(visual.joints[3]).toFixed(3)} J4 ${Number(visual.joints[4]).toFixed(3)}` : "TOOL PREVIEW\nWASM state pending"}</pre></div>;
|
||||
return <div className="three-viewer xyzac-tool-preview" ref={host} data-xyzac-authoritative={String(visual.authoritative)} data-xyzac-preview="toolpath" data-xyzac-controller="orbit" data-xyzac-origin="0,0,0" data-xyzac-origin-axes="X,Y,Z" data-xyzac-toolpath-count={visual.toolpath.length} data-xyzac-helix-count={helixCount} data-xyzac-sample-count={sampleCount} data-xyzac-samples-source="linuxcnc-wasm-sim_posemath_segment_point" data-xyzac-live-source="linuxcnc-source-tp" data-xyzac-live-progress={visual.activeProgress} data-xyzac-live-pose={JSON.stringify(visual.livePose)} data-xyzac-tick={visual.tick} data-xyzac-state-hash={visual.stateHash} data-xyzac-active-segment={visual.activeSegmentId ?? ""} aria-label="XYZAC authoritative tool preview"><div className="xyzac-view-controller" role="toolbar" aria-label="3D preview controller">{controllerButton("zoomIn", "Zoom in", "+")}{controllerButton("zoomOut", "Zoom out", "-")}<span className="xyzac-controller-divider" aria-hidden="true" />{controllerButton("panLeft", "Pan left", "L")}{controllerButton("panRight", "Pan right", "R")}{controllerButton("panUp", "Pan up", "U")}{controllerButton("panDown", "Pan down", "D")}<span className="xyzac-controller-divider" aria-hidden="true" />{controllerButton("reset", "Reset 3D view", "0")}</div><pre ref={hudRef} className="axis-preview-hud" aria-label="XYZAC tool preview state">{visual.authoritative ? `TOOL PREVIEW\nX ${Number(pose.x).toFixed(3)} Y ${Number(pose.y).toFixed(3)} Z ${Number(pose.z).toFixed(3)}\nA ${Number(pose.a).toFixed(3)} C ${Number(pose.c).toFixed(3)}` : "TOOL PREVIEW\nWASM state pending"}</pre></div>;
|
||||
}
|
||||
|
||||
export function XyzacToolPreviewFromSnapshot({ snapshot, ...props }: Omit<Props, "visual"> & { snapshot: XyzacVisualSource | null | undefined }) {
|
||||
|
||||
@@ -24,7 +24,7 @@ export function XyzacManualPanel({ view }: { view: XyzacPanelView }) {
|
||||
return <section className="xyzac-manual-summary" aria-label="XYZAC authoritative position">
|
||||
<div className="xyzac-section-title"><strong>XYZAC authority</strong><span>{view.kinematics?.linear_units ?? "mm"} / {view.kinematics?.angular_units ?? "deg"}</span></div>
|
||||
<div className="xyzac-position-grid">
|
||||
{axes.map((axis, index) => <div key={axis}><b>{axis.toUpperCase()}</b><output>{pose ? Number(pose[axis] ?? Number.NaN).toFixed(axis === "a" || axis === "c" ? 3 : 4) : "-"}</output><small>J{index} {view.joints.length === 5 ? Number(view.joints[index]).toFixed(4) : "-"}</small></div>)}
|
||||
{axes.map((axis) => <div key={axis}><b>{axis.toUpperCase()}</b><output>{pose ? Number(pose[axis] ?? Number.NaN).toFixed(axis === "a" || axis === "c" ? 3 : 4) : "-"}</output></div>)}
|
||||
</div>
|
||||
<div className="xyzac-offset-row"><span>Tool {view.kinematics ? Number(view.kinematics.offsets.tool_offset).toFixed(3) : "-"}</span><span>Y offset {view.kinematics ? Number(view.kinematics.offsets.y_offset).toFixed(3) : "-"}</span><span>Z offset {view.kinematics ? Number(view.kinematics.offsets.z_offset).toFixed(3) : "-"}</span></div>
|
||||
</section>;
|
||||
|
||||
Reference in New Issue
Block a user