Files
road-compiler/.trellis/tasks/archive/2026-08/08-26-direct-edit-map-editor/research/ol-ext-probe-result.md

3.9 KiB
Raw Blame History

ol-ext Transform 探针结论

implement.md 第 1 步的门禁结果。人工验证由 dingkang 在浏览器完成2026-08-27。

门禁结果:三条全过

门禁 结果 证据
OL Map 未重建 通过 实例 #2 / 累计构造 2 次StrictMode 双挂载2438 次 React 渲染下未重建
基线 source 未被写入 通过 60 次拖拽,写入 0 次,几何指纹未变
proxy 拖拽稳定且事件能转成 draft 值 通过 1377 个 translating 事件;跟手连续、不跳数;松手不回弹;反复几十次不失手、不报错

投影链路同时被验证:钳位范围内 raw 3.924 / draft 3.924 完全相等,说明 signedMetersAlongAxis()projectHandleValue() 的换算与钳位都正确。

但不把 ol-ext 用于道路手柄

门禁通过只意味着 ol-ext 可以用(决策表第一行的「可选依赖」),不意味着它是更好的选择。 探针同时暴露了决策表第三行的情况,因此按该行处置。

决定性证据:手柄与约束值脱钩

translateend -> raw -24.146 / draft -5.400

Transform 的 translate 分支按原始 delta 调 geometry.translate(),不知道也不关心我们的钳位。 于是手柄被拖到 -24.1 米处,而约束只到 -5.4 米——手柄停在道路永远不会变成的位置上。

生产要求相反:手柄必须贴着钳位边界停下,位置由约束值反算而来,而不是跟随光标。 这意味着位置更新必须由我们自己拥有。用 ol-ext 就得每帧撤销它刚做的 translate 自己写 PointerInteraction 则直接不移动过界。

其余理由

  • 我们实际用到的只有「Point proxy 上的 translate + start/move/end 生命周期 + hitTolerance 命中」。 这些 ol/interaction/Translate 原生就有,且自带一等 TypeScript 类型。 ol-ext 的增量价值是 bounding box 的 scale / stretch / rotate —— 而道路法线偏移、 区间范围、路口 cutback 都用不上它,canvas-integration.md 早已指出这点。
  • ol-ext 4.0.38 不带类型,也没有 @types/ol-ext。采用它就要长期自己维护一份声明文件。 探针期间已经踩到一次:它的自定义事件名不在 OL 的事件类型联合里, on / un 无法直接声明在类上,只能另设接口做一次转换。
  • 每个 mousemove 都会走 handleMoveEvent_ → getFeatureAtPixel_ → forEachFeatureAtPixel 触发 OL 的 canvas 回读(控制台 Canvas2D getImageData 警告即来自此)。 这不是崩溃原因,但属于固有开销。

探针期间发现的、与 ol-ext 无关的教训

浏览器白屏一度被误当成 ol-ext 的稳定性问题,实际是探针自身的 bug

at projectHandleValue (projection.ts:49)
at ProbeMap.tsx:133
at basicStateReducer → updateReducer → useState

几何计算被写在了 setState 的 updater 函数里。React 会延迟、且在 StrictMode 下重复调用 updater真正执行时闭包里的 start 已被 translateend 置为 null,于是 toLonLat(null) 抛错。 start! 的非空断言正是把运行时问题藏过类型检查的地方。

教训(适用于第 3、4 步):绝不在 setState updater 内做几何计算或读取实时 OL 状态。 先在事件处理器里算出普通值,再传进 updater。

另一条:逐个 translating 事件更新 React state 会产生上千次渲染。探针用 requestAnimationFrame 合并后才可用。生产要更进一步——ghost 直接写自己的 OL source 绝不为每次指针移动重渲染 React 树。

结论

按回退方案 1 推进:原生 OL Snap + 小型 PointerInteraction adapter位置由约束值反算。

HandleManifest → RoadEditOperation → RoadConstraint → preview solver 数据合约不变, 第 2 步已交付的 EditSession / projection / meters 全部保留,探针已验证它们可用。