BMapGL 视角跟随航向插帧 (BMapGL View-Follow Heading Interpolation)
⚠️ 已废弃(2026-09-02):插帧思路治标不治本——根因是setHeading/setTilt非公开 API 内部默认 500ms 缓动动画,JS 层插帧是在跟 SDK 自带动画打架。最终方案是{noAnimation: true}瞬转。详见 BMapGL 视角跟随 setHeading 内部动画与 noAnimation 瞬转 (BMapGL View-Follow setHeading noAnimation Snap)。本页保留作失败档案。
问题与现象
在 Android WebView 中,指南针二维 UI 可以立即响应设备转向,但 BMapGL Canvas/WebGL 地图的视角跟随会出现延迟、卡帧或旋转动画被打断。常见表现是设备已经转过约 90°,地图仍在追赶旧角度。
条件与根因
- 学校壳的
CampusCompassBridge使用旋转矢量传感器,圆周滤波后约每 80ms 推送一次window.CampusNavigation.receiveNativeHeading(json)。 - 页面若在每次回调中直接调用
map.setHeading(target),BMapGL 可能启动或维护内部旋转动画;下一次传感器回调又改变目标,多个内部动画互相抢占,表现为卡帧和滞后。 - 这不是 JS 桥“注册方法有延迟”的证据,更可能是地图渲染提交与 SDK 内部动画的竞争。
解决方案
在“视角跟随”模式中,将最新目标角度交给一个可抢占的 requestAnimationFrame 插帧器:
- 使用最短圆周角差展开 0/360° 边界,避免反向大旋转。
- 每次转向用 96–144ms 完成,90° 约 120ms,在 60Hz 下产生约 6–8 个离散
setHeading提交。 - 新传感器值到来时,从当前已提交角度重新规划到最新目标,不排队旧目标,降低跟手延迟。
- 切换北向/路线模式、恢复导航视图或停止导航渲染时取消插帧,避免过期 rAF 覆盖新状态。
- 光标和指南针仍在收到桥回调时立即更新;只有地图相机旋转经过插帧。
验证方法
- 自动化:
frontend目录执行npm run test:navi,应通过导航契约、插帧边界和取消逻辑测试。 - 构建:执行
npm run build,确认frontend/dist/navi/app.js同步生成;若 worktree 没有依赖,可临时复用同机已有node_modules,不要提交 junction。 - 真机:快速旋转 90°,观察指南针/光标是否立即改变,地图在约 0.1 秒内以 6–8 个短步完成旋转;连续转动时不应出现明显追赶或旧角度回弹。
仓库内另有独立测试页 frontend/public/test/navi-heading.html,已接入 test/gateway.html。页面右侧嵌入真实 ?dragsim=1 导航画布,左侧可发送瞬时 90°/180° 航向、连续 8 点航向,并读取 getNavigationDebugState() 的相机角度和插帧状态;本地开发地址为 /test/navi-heading.html。
适用边界
该策略只针对视角跟随的地图相机。北向上和路线朝前模式保持即时固定角度;如果设备或地图 SDK 在低端机上仍掉帧,应优先降低地图图层/覆盖物负载,而不是继续延长插帧时长。
关联
campus-navi-rs:frontend/public/navi/app.js- Android 桥:
CampusCompassBridge/CompassController
本文归档于个人知识库 · 领域:CS & AI · 模块:04 Project_CS_AI/Frontend