47-dom-overlay-billboard.md 14 KB

执行票:地图标记 DOM overlay 渲染(billboard 发糊与底板生硬的结构性解决)

Label: ready-for-agent Category: frontend-execution

来源

维护者在批次 3(lanhu-cockpit-asset-replacement 票 16)第七轮走查后的裁定:「尝试立票做 DOM」。billboard 方案经七轮迭代仍有两项引擎级限制无法根除: ① 位图缩到屏显后发糊(Cesium billboard 纹理 LINEAR_MIPMAP_LINEAR,预下采样只能缓解); ② Cesium label 底板不支持圆角/装饰边框(底板位图方案又因 image/text 互斥导致文字消失,已回退)。

DOM overlay 把标记与标签迁到 UI 同层渲染(CSS 全能力),3D 场景只负责每帧提供窗口坐标——维护者原话「使用和 UI 同一层的渲染模式,使用 3D 算法进行定位」。

维护者裁定(2026-10-15 两轮走查后,本票方向定调)

  1. 「DOM 还存在很大问题,整体还没有还原 billboard 的功能;但显示效果清晰得多——等功能完全实现后再替换 billboard。」 billboard 链路保留(聚合、特效、Canvas 拾取、强调读数继续依赖它),DOM 与 billboard 同位叠放作两层。
  2. 渲染分工:外层母版自绘 SVG 还原水滴(素材位图喂 DOM 在高 DPR 屏必糊——糊的根因是预下采样合成时机,不是素材本身);中间行业/设备图标继续用素材(去色重染的原生分辨率产物,向下采样永远锐利)。

最终实现(第四轮收口,2026-10-15)

services/markerOverlay.js(重写)+ markerAssets.js(新增 renderInnerIconUrl)+ mapService.js(接入):

  • 外层自绘 SVG:水滴路径按 512px 白母版实测拟合——帽圆 (188.5,189) r189(逐行验证 <1px)+ 下半收尖三次贝塞尔(左缘 57 点最小二乘,最大残差 4.75 源像素 ≈ 0.34 屏显像素);镂空孔 = 实测圆 r75。状态色 fill 直注(token 单源 toneColors());降饱和走 CSS filter(与 billboard 同参数)。拟合探针留档 research/fit-pin-bezier.mjs。
  • 内层行业图标 = 素材:renderInnerIconUrl(icon) 用与 billboard 同一 recolorInner 去色重染规则产出 256px 原生分辨率 data URL(缓存复用),嵌进同一 SVG 的 <image>,按 plan.inner.diameterRatio(80%)× 母版宽、帽心对齐——DOM 里只做向下采样,任何 DPR 都锐利。renderMarker(billboard 路径)共用该缓存,行为不变。
  • 大小对齐 billboard 口径(第四轮浏览器走查修正两处):① 白描边 stroke-width=56 + paint-order="stroke fill"——彩色母版全尺寸保留、白色纯外扩 28 源像素,与 billboard withWhiteOutline(向外膨胀、母版不蚀)同式(此前 stroke 沿中心线,母版被蚀一圈、DOM 比 billboard 小);② 标签限宽取计划层 labelMaxWidth(宽×2.6,content-box),替换硬编码 220px——此前 DOM 标签比 billboard 宽 3 倍,两层并现一长一短。
  • 贴地定位:与 billboard CLAMP_TO_GROUND 同口径——engine.groundHeightAt(地形瓦片实测高程,取不到回椭球 0)+ projectPivot 窗口坐标 − host 窗口原点;尖端/描边余量补偿与 billboard verticalOrigin:BOTTOM + pixelOffset(0,pad) 同式。
  • 点击触发器:overlay 宿主挂显式 click 派发器,命中 data-marker-overlay-* 节点 → 照搬 pickDeviceOrPointAt(与 Canvas 点选链同一功能函数);标记节点 pointerdown/up 停止冒泡防 attachPointPick 双派发;pointermove 不拦(hover/tooltip 照常);标签 pointer-events:none 不遮挡相机。
  • 节点池:计划读数指纹(状态/行业/名称/母版/内层/降饱和/色值)变化才重建(NORMAL→ALARM 换色生效);消失隐藏不销毁;unmountMap 已接 detachOverlay + unmountMarkerOverlay。
  • 降级:内层素材加载失败 = SVG 只剩母版水滴;billboard 双层在底下照常显示(链路未动)。

保持不变(契约面)

  • 合成计划层 domain/markerPlan.js(尺寸/锚点/归属/降饱和逻辑原样复用,overlay 只换渲染媒介);
  • data-* 断言面(markerMaster/markerInner/... 全部挂到 DOM 节点上);
  • 状态词表、拾取身份、面板联动、四模式可见性;billboard 链路(syncPointMarkersForPlan)完整保留。

核验记录(首版声称 vs 实况,均已修)

首版(迁移自票 20)声称「已实施+走查通过」不成立:SVG 母版路径右半缺失(渲染成月牙碎片);投影原点减法写反(恒偏 host.left/top);内层硬编码 60% 且换算放大 ≈2.2 倍;节点永不刷新;unmount 未接线;「data-* 供点选派发」无消费者。第二/三轮全部修复,第二轮的「renderMarker 位图喂 DOM」经维护者走查证伪(高 DPR 屏放大发糊),第三轮改为自绘 SVG + 原生分辨率内层。

浏览器走查结论(第四轮,2026-10-15 实测,real 数据源)

  • 形状:维护者确认水滴还原 OK;大小按 billboard 口径对齐(描边纯外扩、标签限宽同源)。
  • 标记:实心/镂空双形、状态色、降饱和(未关联设备橙色镂空 + 内层窨井图标)渲染正确;内层素材 256px 原生嵌入清晰。
  • 点选联动:监测点(RQ001 燃气监测点001)与未关联设备(TEST-CNXHS0000001 测试消火栓)均正常——详情卡打开、镜头飞行、引线锚定、面板读数字段正确;data-marker-overlay-key/kind/code 身份断言面在位。
  • 标签:圆角底板 + 青色装饰边 + 截断省略(与 billboard 同宽口径)+ hover title 读全。
  • 控制台:零业务报错(唯一 error 为第三方百度统计 hm.js 的 permissions-policy 提示,与本票无关)。

遗留(不阻塞本票收口)

  • 监测点预警/报警特效:由票 45 承接(范围第 4 条),特效当前仍在 billboard 层;DOM 复刻特效是替换 billboard 的前置之一。
  • 聚合符号(K>1)DOM 化:替换 billboard 的另一前置,未立票(挂地图 Not yet specified 雾区)。
  • billboard 暂不摘除:按维护者裁定,DOM 完整复刻(特效 + 聚合)后才替换;现状 DOM 标记与 billboard 同位叠放,billboard 特效动画期间底图短暂露边属过渡可接受。

进度

Status: resolved Type: task Blocked by: Labels: ready-for-agent, wayfinder:task

Comments

local — 2026-10-15T02:49:19.248Z

维护者第二轮反馈落地:①内层图标直径 60% → 80%(安全边界核验:圆帽区 ≈0.88 倍宽,80% 外沿距帽缘仍有 15 源像素余量);断言同步更新(合成计划 38/38)。overlay 与 billboard 降级路径同受益(同一合成计划)。

local — 2026-10-15(本会话执行记录)

执行票 47:认领后对抗式核验首版「已实施」声称,发现六处确定性缺陷(母版路径残缺/投影原点写反/内层几何错/节点不刷新/unmount 未接线/点击派发无消费者),首版走查结论作废。按维护者走查三条反馈重写 overlay:素材改走 renderMarker 同源合成、贴地定位与 CLAMP_TO_GROUND 同口径、显式 click 触发器照搬 pickDeviceOrPointAt、指纹重建、卸载接线。特效需求确认已有票 45 承接(未重复立票)。浏览器复验按维护者指示推迟到功能完全实现后。票保持 open。按 AGENTS.md 跳过 build/dev 验证,仅做 node --check 与离线断言(38/38 过)。

local — 2026-10-15T07:11:12.351Z

第三轮(同日,维护者反馈「用素材整体变糊」后裁定:外层自绘 SVG 还原水滴 + 内层行业图标继续用素材):

根因先说清——糊不是素材的错,是合成时机:renderMarker 预下采样到 ~39 CSS px 是为绕 Cesium mipmap,但 DOM 无 mipmap、有 DPR 问题(2× 屏上 39px 源图铺 78 物理像素必然糊;内层火焰 302 源像素被压进 ~30px 更甚)。

实施: ① 外层母版改自绘 SVG:水滴路径按 512 母版实测拟合——帽圆 (188.5,189) r189(逐行验证 <1px)+ 下半收尖三次贝塞尔(左缘 57 点最小二乘,最大残差 4.75 源像素 ≈0.34 屏显像素),镂空孔实测圆 r75;描边 stroke 28 = billboard OUTLINE_WIDTH 同值;viewBox 外扩 40 同 OUTLINE_PAD 裁剪窗。拟合探针留档 .scratch/cockpit-real-data-wayfinding/research/fit-pin-bezier.mjs(含 fit-pin-path.mjs 首轮圆弧检验:收尖非圆弧,残差 338px 排除 A 命令)。 ② 内层素材:markerAssets 新增 renderInnerIconUrl——与 billboard 同一 recolorInner 去色重染规则,但不下采样(256px 原生分辨率 data URL,缓存复用),DOM 按帽径 80% 向下采样永远锐利;renderMarker 改为共用该缓存(billboard 路径行为不变,合成计划断言 38/38 复跑过)。 ③ 降级形态更新:内层素材失败 = SVG 只剩母版水滴;billboard 双层在底下照常(链路未动)。

维护者已授权浏览器复验但指示先完成功能——复验窗口待维护者点名。票保持 open(下一步:浏览器走查同位/同款/点选 + 特效复刻归票 45 + 聚合 DOM 化)。

local — 2026-10-15(第四轮:浏览器走查 + 大小对齐收口)

维护者确认形状 OK、指示走查后收口。浏览器实测(real 数据源,http://127.0.0.1:8000/#/cockpit)发现两处尺寸偏差并修正:① 白描边 stroke 沿路径中心线把彩色母版蚀掉一圈(billboard 的 withWhiteOutline 是纯外膨胀)→ 改 stroke-width=56 + paint-order="stroke fill",母版全尺寸、白环纯外扩 28 源像素同 billboard;② 标签硬编码 max-width:220px 比 billboard 计划层 labelMaxWidth(宽×2.6)宽 3 倍,两层并现一长一短 → 改取 plan.labelMaxWidth + content-box。复验:监测点/未关联设备点选联动(详情卡+镜头+引线)、镂空+降饱和+内层窨井图标、标签截断与 hover title 全通过;控制台零业务报错。票关闭。特效(票 45)与聚合 DOM 化是替换 billboard 的前置,留在遗留。

local — 2026-10-15T09:25:24.605Z

追加(维护者要求同视角 A/B 对照):临时开关已接——① URL 参数 #/cockpit?overlay=0(hash 前后都认)挂载时初始隐藏 DOM 层 = 只露 billboard(之前版本);② DEV 把手 __cockpitMap.toggleMarkerOverlay() / setMarkerOverlay(bool) / getMarkerOverlay() 不重载即时互换(两层同位叠放,切 display 即对照)。浏览器实测两态截图各一张:overlay=0 时标记为位图版(发糊/原生 label),默认态为自绘 SVG 版(锐利/圆角底板标签)。这是临时走查工具:billboard 替换收口后随本票遗留项一并移除(markerOverlay.js 的 overlayVisible 两函数 + mapService.js 的 A/B 块与三个把手键)。改动仍未提交,入库裁剪时连本段一起。

local — 2026-10-16T01:52:05.232Z

追加(收口后维护者走查反馈两缺陷,已修复并浏览器取证):

① 「设备点图标比老版本小一圈」——根因:面板强调(highlightEntities)把 billboard.scale 改到 1.55,而 DOM 镜像层读不到该量,强调时 billboard 放大、DOM 不动,两层一大小看起来「小了一圈」。修复:引擎新增 readPointMarkerScales(viewer)(kind|code → billboard.scale 真值),overlay 每帧镜像该量,transform-origin 设在尖端(与 billboard verticalOrigin:BOTTOM 缩放行为一致)。

② 「有关联监测点的设备点没有正常应用 DOM」——根因:关联设备是独立 billboard 数据源(DEVICE_MARKER_SOURCE,票 42 结构性隔离),DOM overlay 只渲染了摘要标记计划 markerPlan.markers,整个设备图层没进 DOM。修复:引擎新增 projectDeviceMarkers(viewer)(每帧投影当前可见设备实体:窗口坐标真值含 pixelOffset 尖端补偿 + scale/alpha 反应量真值,折叠聚合个体 show=false 不进 DOM——聚合符号按票面 Out of Scope 留在 billboard);mapService 帧状态把设备行与图层计划行并表(name/status/industry/tone)传入 overlay;设备 DOM 节点走与摘要设备同一套合成计划(实心母版 + 内层行业图标),无名字标签(billboard 个体设备本就无 label,两层同口径)。

浏览器取证(real):选中城北排水监测点01(CBWS202610150001 报警)→ 关联设备「测试环网监测设备01(21119740)」出现 data-marker-overlay-kind="associated-device" 节点(key device|CBWS…|21119740,实心 + drainage 内层 + tone #ff3b52 与监测点同状态色),svg 26.72×32.11 = billboard plan.draw 同源同值,与 billboard 设备同位叠放;控制台零业务报错。期间见到的 Vue __vnode null 循环报错是并行会话 HMR 风暴的开发期残留(硬重载后消失),与本修复无关。改动仍未提交,随票 47 存量 hunks 一起裁剪入库。

Answer

DOM overlay 渲染层已交付:外层自绘 SVG 水滴(实测拟合,维护者确认形状)+ 内层素材原生分辨率(去色重染同源)+ 真 DOM 标签(圆角/装饰边/截断/hover 全 CSS 能力);大小按 billboard 口径对齐(描边纯外扩、标签限宽单源);贴地定位同 CLAMP_TO_GROUND;点选走显式触发器照搬 pickDeviceOrPointAt;节点池指纹重建、卸载接线。浏览器走查(real 数据源)四类标记渲染 + 两类点选联动 + 标签截断 + 零业务报错全通过。billboard 链路保留(维护者裁定:特效/聚合 DOM 化后才替换)。票 47 关闭。