Files
planet/docs/technical/zh/earth-frontend-context.md
2026-04-29 17:27:44 +08:00

12 KiB
Raw Blame History

Earth 前端结构

本文件描述当前 Earth 大屏前端的真实结构,重点是帮助后续继续改 HUD、图层、媒体面板、真实地形、BGP 可视化时,不再重复踩结构和状态同步上的坑。

相关规则建议一起参考:

当前目标

Earth 前端不是普通管理页,它是独立的大屏展示前端。当前产品目标是:

  • 维持地球视图的空间感和可读性
  • 让 HUD、图层、媒体面板、BGP、卫星、海缆等保持统一交互
  • 把加载中、已启用、已隐藏、锁定中这类状态做清楚

当前入口

React 路由入口:

当前做法很简单:

  • React 页面只负责提供一个全屏 iframe
  • 真正的 Earth 应用运行在:

所以 Earth 前端本质上是 public/earth 下的一套独立静态应用。

当前文件分层

1. 页面入口与结构

职责:

  • HUD 基础 DOM
  • 图层面板
  • 媒体面板
  • 工具栏
  • 设置弹窗
  • 兼容旧元素 id

2. 主运行时

职责:

  • 地球初始化
  • Three.js 场景组装
  • 数据加载与刷新
  • 各图层集成
  • Earth 级别状态同步

3. 地球控制层

职责:

  • 工具栏交互
  • 图层面板交互
  • 旋转/缩放/布局
  • HUD 面板拖拽
  • 图层开关状态机
  • Earth 设置读取、持久化与重置

这份文件是 Earth 前端当前最核心的 UI 控制入口。

4. UI 与状态消息

职责:

  • loading 面板
  • status message
  • tooltip / error / 清理逻辑

当前 status message 有两类短提示:

  • 普通业务提示:通过 showStatusMessage() 入队显示。
  • 手势提示:通过 showGestureStatusMessage() 直接短暂显示,用于缩放视角时的 缩放 N%

手势提示不会抢占 loading 状态。对应样式是 hud.css 中的 .earth-status-message.gesture

5. 地球与地形

职责:

  • 地球球体、云层、大气
  • 真实地形 mesh
  • terrain tile 拉取、解码、位移、着色

6. 图层模块

职责:

  • 各自的数据层
  • 开关行为
  • 面板内容
  • hover/lock/selection 语义

其中 Earth 启动加载链现在也拆成了两层:

  • controls.js
    • 提供图层注册表与启动元信息
  • layer-startup-tasks.js
    • 提供图层启动任务注册表
    • 通过 registerLayerStartupTask(id, taskFactory) 扩展启动任务
  • main.js
    • 只负责读取排序后的启动图层,再按映射执行队列

其中巡航模式现在已经拆成两层:

  • cruise-sequencer.js
    • 负责目标队列顺序、停留时长、切换节奏、打断与恢复
  • callout-connector.js
    • 负责卡片连线 SVG、路径计算与绘制动画
  • bgp-cruise-adapter.js
    • 负责 BGP 巡航展示适配目标排序、卡片落点、连线路径、focus/overlay/info-card 时序

当前 BGP 巡航只是这套能力的一个调用方不应再把“按队列巡航”和“BGP 事件展示”混写在同一个状态机里。

新闻巡航摘要计划见:

当前样式分层

Earth 的 CSS 不是一份大样式表,而是分层管理:

当前建议:

  • 通用 HUD 壳层写进 hud.css
  • 单一面板特性写进各自子文件
  • 不要把业务状态样式再散回 index.html

当前图层开关状态语义

Earth 图层按钮现在不应再只有“开/关”两态,而应支持:

  • inactive
  • active
  • loading

当前入口在:

关键函数:

  • updateLayerButtonState(button, isActive)
  • setLayerButtonState(button, options)

setLayerButtonState 负责:

  • loading 样式
  • aria-busy
  • 按钮禁用
  • tooltip 更新
  • 绑定状态文本更新
  • 可选同步 active

因此后续如果别的图层也需要异步启用,应该直接走这套状态机,而不是再手写一套临时 loading class。

另外Earth 图层控制现在已经收成“注册表驱动”:

  • 图层元数据
    • id
    • icon
    • label
    • meta
    • buttonId
    • persist
    • startupPriority
    • startupMode
    • startupLabel
    • startupMessage
  • 图层行为
    • getVisible()
    • setVisible(next, options)

当前入口仍在 controls.js

这意味着后续新增图层时,优先应补一条图层注册定义,而不是同时去改:

  • 图层面板 HTML
  • 持久化快照
  • 初始化恢复
  • click 绑定

这四处现在都应该由注册表派生。

其中:

  • startupPriority
    • 描述图层参与启动加载时的顺序
  • startupMode
    • visible
      • 仅当前图层处于启用/可见状态时,才加入启动加载队列
    • preload
      • 即使当前图层未显示,也会参与启动预加载

当前 main.js 会通过注册表读取排序后的启动图层列表,再动态拼装启动加载队列,而不是手写一串固定步骤。像 BGP 这类需要尽早准备数据、但不一定默认显示的图层,应该优先走 startupMode: "preload",而不是在启动流程里写隐式特判。

此外,启动阶段给用户看的提示文案也应尽量从注册表派生:

  • startupLabel
    • 用于描述当前启动任务的业务名称
  • startupMessage
    • 用于描述启动中的提示文案
    • 可以是字符串
    • 也可以是对象,用于像海缆这种“准备阶段 / 主加载阶段”两段式文案

这样后续新增会参与启动加载的图层时,顺序、模式和提示文案都在同一处定义,不需要再去 main.js 里补第二套常量。

船只图层与图例

AIS 船只图层入口:

船只图层当前负责:

  • 请求 /api/v1/visualization/geo/vessels
  • 将 BarentsWatch AIS GeoJSON 转为 Three.js sprite
  • 按船型映射颜色
  • 根据航行/停泊状态绘制三角形或圆点纹理
  • 支持 hover、lock、轨迹加载和视觉聚焦

图例系统已经注册 vessels 模式:

getVesselLegendItems() 返回带 shape 的图例项:

  • shape: "vessel":三角形,表示航行船只。
  • shape: "dot":圆点,表示停泊或低速状态。

图例项颜色来自 VESSEL_CONFIG.colors,不要在 legend.css 里重新定义业务颜色。新增船型时,应优先改 vessels.jsconstants.js 的船型映射,再同步图例项。

视角控制反馈

controls.js 统一维护 Earth 缩放状态。滚轮缩放、缩放按钮和触屏双指捏合最终都会更新 zoomLevel,并通过 showZoomStatusCapsule() 显示当前缩放比例:

showGestureStatusMessage(`缩放 ${Math.round(zoomLevel * 100)}%`, "info");

该提示每 90ms 最多更新一次,显示 760ms 后淡出。它是视角反馈,不是数据加载进度,也不应该写进图层 loading 状态。

main.js 只负责在双指捏合缩放时调用 setZoomLevel()showZoomStatusCapsule()。鼠标滚轮与缩放按钮的胶囊提示应继续放在 controls.js,避免同一种缩放反馈散落在多个模块。

拖拽地球的旋转灵敏度会根据当前缩放连续衰减,而不是按某个缩放阈值分段:

const scale = THREE.MathUtils.clamp(
  Math.pow(zoom, -CONFIG.dragRotationZoomExponent),
  CONFIG.dragRotationScaleMin,
  CONFIG.dragRotationScaleMax,
);

调参入口在 constants.jsdragRotationFactorBase 控制基础速度,dragRotationZoomExponent 控制放大后的衰减曲线,dragRotationScaleMin / dragRotationScaleMax 控制上下限。

data-status-target

图层按钮可以通过:

  • data-status-target

指向一个状态文本节点。当前 terrain 已接入:

  • 按钮:#toggle-terrain
  • 状态节点:#terrain-status

以后别的异步图层也可以沿用这套约定。

当前设置持久化

Earth 设置面板当前由 controls.js 统一负责:

  • 捕获默认值
  • localStorage 读取上次设置
  • 初始化应用当前设置
  • 用户变更后即时持久化
  • 一键重置回默认值

当前持久化的范围是:

  • 旋转模式
  • 地球默认大小(作为重置视角、缩放重置和巡航视图的默认 zoom 真源)
  • HUD 面板显示/隐藏
  • 图层控制开关:地形 / 卫星 / 轨迹 / 海缆 / BGP
  • 地形透明度

也就是说Earth 设置不是一次性 UI 状态了,而是本地设备级偏好。后续如果再加入新的设置项,应优先接入同一条持久化链,而不是各自散着写 localStorage

当前地形链路

真实地形首次启用会慢,原因不只是一个:

  1. 需要拉取 Terrarium 瓦片
  2. 需要解码图片
  3. 需要按顶点采样高程
  4. 需要重新写入 geometry 和 color
  5. 需要重新计算法线与包围体

当前入口在:

当前已经做了两层体验优化:

  1. 图层开关 loading 状态持续可见
  2. 页面空闲时会预热 ensureTerrainReady()

当前巡航链路

当前巡航边界:

  • 通用巡航层包含:
    • 当前目标
    • 队列顺序
    • 相机 focus
    • 停留 / 隐藏 / 切换
  • 业务模块提供:
    • 提供目标队列
    • 提供 focus 坐标
    • 提供卡片内容
    • 提供高亮/图层副作用

巡航模块的结构文件: