# 库位渲染与状态集成说明 本文档说明当前项目中“库位网格”在 Meta2D 渲染链路中的实现方式、扩展点与接入 WebSocket 实时状态的建议方案,并给出从旧的 DOM 覆盖层组件迁移到画布内绘制的步骤与注意事项。 - 相关文件 - 画布渲染入口:`src/services/editor.service.ts` 中 `drawPoint()` 自定义绘制 - 库位网格绘制模块:`src/services/draw/storage-location-drawer.ts`(导出 `drawStorageGrid`) - 场景编辑页:`src/pages/scene-editor.vue` - WS 服务(示例/参考):`src/services/storage-location.service.ts` ## 一、渲染概览 - 使用 Meta2D 的自定义绘制回调,在 `drawPoint()` 内针对 `MapPointType.动作点` 调用 `drawStorageGrid()`,在“世界坐标”中直接绘制 2x3 栅格。 - 这样,库位网格与点位同步缩放和平移,无需计算 DOM 偏移与容器滚动,也无需在模板中叠加覆盖层组件。 ## 二、数据来源与字段约定 - 点位对象:`MapPen`(`@api/map` 导出的类型)。 - 动作点扩展字段: - `pen.point.associatedStorageLocations: string[]` - 用于静态展示与数量溢出提示(+N)。 - 后续若接入 WS 实时状态,建议增加: - `pen.point.storageStates?: Record` - key 为库位层名(例如 `layer_name`),value 为状态对象。 ## 三、绘制模块 `drawStorageGrid` 路径:`src/services/draw/storage-location-drawer.ts` 签名: ```ts export function drawStorageGrid( ctx: CanvasRenderingContext2D, pen: MapPen, opts?: { fontFamily?: string }, ): void ``` 职责: - 基于 `pen.calculative.worldRect` 决定栅格的尺寸、间距与摆放位置(点位右上角)。 - 前 5 格按默认样式绘制;若数量超出 6,则在最后一格显示 `+N`。 - 采用“世界坐标”绘制,随 Meta2D 画布的缩放/平移自然同步。 可调参数(在代码内集中计算): - 单格尺寸 `cell`:约为点位较短边的 35%,限制在 `[6, 14]`(世界坐标单位)。 - 间距 `gap`:约为点位较短边的 8%,限制在 `[2, 6]`。 - 圆角统一通过 `roundedRectPath` 构造路径,避免 `roundRect` 类型兼容问题。 ## 四、在 `drawPoint()` 中的接入 路径:`src/services/editor.service.ts` 核心片段: ```ts // …计算文本等 ctx.fillText(label, x + w / 2, y - fontSize * lineHeight); // 库位2x3栅格:动作点在画布上直接绘制(静态数据) if (type === MapPointType.动作点) { drawStorageGrid(ctx, pen, { fontFamily }); } ``` 注意:需确保 `EditorService.#register()` 已注册 point 的自定义绘制函数(项目中已完成)。 ## 五、接入 WS 实时状态(建议) 有两种模式可选: - 模式 A:在 `drawStorageGrid()` 增加状态解析回调 - 签名扩展:`opts.stateResolver?: (penId: string, layerName: string) => { occupied?: boolean; locked?: boolean; }` - `drawPoint()` 调用时传入解析函数(从全局 Map 或服务读取),按状态填充不同的底色/边框/角标。 - 优点:不污染 `pen` 数据,职责清晰;适合不同页面传入不同策略。 - 模式 B:将状态写回 `pen` 上 - WS 收到后更新 `pen.point.storageStates[layer_name] = { … }`,然后 `editor.render()` 触发重绘。 - `drawStorageGrid()` 读取 `pen.point.storageStates` 决定样式。 - 优点:渲染模块无额外依赖;缺点:需管理好数据生命周期与清理。 建议优先使用模式 A,便于解耦与测试。 ### 与 `StorageLocationService` 的对接 `StorageLocationService.handleStorageLocationUpdate()` 已按 `operate_point_id` 与站点名映射聚合库位数据: - 可在服务层维护 `Map>` 的结构。 - `drawPoint()` 中调用 `drawStorageGrid(ctx, pen, { stateResolver })`,`stateResolver` 从该 Map 中读取。 - 状态变化后调用 `editor.render()` 重绘即可生效。 ## 六、样式与语义(可自定义) - 默认颜色: - 底板:`#00000022`(半透明) - 单格:`#f5f5f5` + `#999` 边框 - 溢出格:底 `#e6f4ff`,边框 `#1677ff`,文字 `#1677ff` - 状态上色(建议): - occupied=true:填充偏黄/橙(例:`#ffe58f`) - locked=true:边框高亮(例:`#fa541c`)或角标图标 - 冲突(同时 occupied & locked):设置优先级或组合样式 ## 七、性能考量 - 绘制在同一 Canvas 渲染管线完成,没有额外 DOM 或布局成本。 - 仅当 WS 推送或交互(缩放/平移/选择)触发重绘,保持流畅。 - 如果点位非常密集,可在 `drawStorageGrid` 内做最小尺寸阈值,过小则不绘制或绘制为简化标记。 ## 八、迁移步骤(从 DOM 覆盖层组件) 1. 将组件 `storage-location-grid-overlay.vue` 从页面删除(如 `scene-editor.vue`)。 2. 确认 `drawPoint()` 已导入并调用 `drawStorageGrid()`。 3. 按需对接 WS:在服务层聚合状态,传入解析回调或写入 `pen`。 4. 验证缩放/平移/窗口尺寸变化场景,确保网格对齐与可读性。 ## 九、测试清单 - 缩放到 0.5x、1x、2x 时,栅格位置与尺寸是否稳定且可读。 - 拖动画布及窗口 resize 后,栅格仍紧邻动作点右上角。 - 当 `associatedStorageLocations.length` <= 6 与 > 6 时展示正确(含 `+N`)。 - 接入 WS 后: - occupied/locked 状态能正确上色/标注。 - 状态切换时无残影,性能稳定。 ## 十、常见问题 FAQ - Q:为何不再使用 DOM 覆盖层组件? - A:避免坐标换算/偏移/滚动同步等复杂问题,统一交由 Meta2D 世界坐标与渲染管线处理。 - Q:如果需要支持点击库位打开菜单? - A:可在 Meta2D 的事件系统中命中该区域(保留格子范围),或保留一个轻量的浮层仅用于复杂交互(与绘制相互独立)。 - Q:如何快速调整大小与颜色? - A:修改 `storage-location-drawer.ts` 内的 `cell/gap` 与颜色常量;如需主题化,可迁移到 `sTheme`。