WholeProcessPlatform/frontend/docs/地图模块-3D Cesium实施计划.md
2026-07-09 14:58:14 +08:00

16 KiB
Raw Blame History

地图模块 3D Cesium 实施计划

1. 目标

在现有地图体系下补齐 3D(Cesium) 视图能力,使其尽量复用 2D(OpenLayers) 的业务编排结果,满足以下要求:

  • 3D 默认进入中国视角,不再落到美国区域。
  • 3D 初始化时显示过渡动画,再定位到中国。
  • 3D 保留基础底图加载能力,但不提供底图切换面板。
  • 3D 支持锚点展示。
  • 3D 支持与 2D 一致的鼠标悬停 popup样式复用现有 popup。
  • 3D 支持与 2D 一致的锚点点击行为,点击后打开同一套详情弹框逻辑。
  • 菜单切换、图层树勾选、图例勾选后3D 锚点与 2D 一样联动变化。
  • 3D 必须复用 eng_point 的层级显示规则,中型水电站仅在 ENG_POINT_MEDIUM_VISIBLE_ZOOM = 7.5 以上显示。

2. 2D 现状梳理

当前 2D 的能力并不是散落在页面里,而是已经形成了比较清晰的分层:

2.1 页面入口

  • src/components/gis/GisView.vue
  • 负责挂载地图容器、popup 容器、地图控制器、图例、图层树。
  • 页面只调用 mapOrchestrator.mountView()handlePageChange(),不直接拼地图业务。

2.2 地图编排层

  • src/modules/map/application/map-orchestrator.ts
  • 负责页面初始化、菜单切换、图层配置加载、图例配置加载、基地切换、缩放联动。
  • 2D/3D 都应尽量复用这一层,避免在 Cesium 侧另起一套业务流程。

2.3 地图统一门面

  • src/components/gis/map.class.ts
  • 对外暴露统一接口,如:
    • addBaseDataLayer
    • addInitDataLayer
    • mdLayerTreeShowOrHidden
    • setLegendPointVisible
    • controlBaseLayerTreeShowAndHidden
    • initPopupOverlay
    • flyTopanto
  • 业务层只认这套接口,不应感知底层是 OpenLayers 还是 Cesium

2.4 2D 地图能力落点

  • src/components/gis/map.ol.ts
  • 已实现的关键能力:
    • 默认中国视角初始化
    • 基础底图加载与切换
    • 点位图层注册和显隐
    • 图例控制单类锚点显隐
    • 鼠标 hover popup
    • click 打开详情弹窗
    • 基地裁切与底图遮罩
    • 缩放/移动后的批量 popup 和标签刷新

2.5 2D 锚点与 popup 支撑

  • src/components/gis/ol/point-layer-manager.ts
    • 负责将点位数据转成地图要素、分层、索引、图例显隐。
  • src/components/gis/ol/popup-manager.ts
    • 负责 hover 命中、popup DOM 内容复用、批量 popup。

2.6 图层树和图例交互

  • src/components/mapController/LayerController.vue
    • 图层树勾选后走 mapOrchestrator.applyLayerSelection()
  • src/components/mapLegend/index.vue
    • 图例点击后走 mapOrchestrator.toggleLegend() / toggleLegendBatch()
  • src/store/modules/map.ts
    • 真正把缓存数据、图层状态、图例状态应用到地图实例
    • 也就是说,3D 只要把统一接口补齐,就能直接接住现有业务流

2.7 2D 已有特殊业务规则

  • 锚点点击逻辑已在 src/components/gis/map.ol.ts 实现:
    • 命中锚点后,ylfbylfbModalVisible
    • 其他锚点走 modalVisible
    • 标题和参数都直接取当前锚点数据
  • eng_point 的中型水电站显示阈值已在现有链路中实现:
    • 阈值常量位于 src/modules/map/application/map-orchestrator.ts
    • 过滤逻辑位于 src/store/modules/map.tsfilterPointLayerDataForDisplay()
    • 3D 不应重新发明一套规则,而应复用这套现有过滤结果
  • 部分点位会随着缩放级别提升显示得更多,不是简单的“图层开/关”:
    • eng_point 的中型电站要到 ENG_POINT_MEDIUM_VISIBLE_ZOOM = 7.5 以上才显示
    • 水电开发页在缩放跨过 12 级时会自动补开一批动态图层
    • 2D 内部还存在点位密度阈值、近邻点展开、批量 popup 阈值等缩放联动规则
  • 2D 对锚点存在碰撞检测与密度控制,不是所有点始终全量显示:
    • 图标和标签会分别经过碰撞计算
    • 低缩放下会因为密度、碰撞、区域裁切、图例状态而隐藏部分点
    • 高缩放下会逐步放开限制,显示更多锚点和标签

3. 3D 当前现状与缺口

3.1 已有内容

  • src/components/gis/map.cesium.ts
  • 当前只完成了最小化 Cesium.Viewer 初始化。
  • 已有基础缩放、截图、flyTopanto() 雏形。

3.2 当前主要缺口

  • init() 里虽然定义了 flyToChina(),但没有真正执行,也没有 resolve(viewer),初始化流程不完整。
  • 默认底图仍是 ArcGIS 全球影像,因此启动时容易落到美国默认视角。
  • addBaseDataLayer() 为空,无法接住当前 GISMap/customBaseLayer 逻辑。
  • addInitDataLayer() 为空,无法展示锚点。
  • mdLayerTreeShowOrHidden() 为空,菜单切换时 3D 锚点不会同步显隐。
  • setLegendPointVisible() 为空,图例勾选不会影响 3D 锚点。
  • initPopupOverlay() 为空,无法复用 2D popup 容器。
  • 缺少点击命中与详情弹框联动3D 当前无法做到“点击锚点与 2D 同行为”。
  • controlBaseLayerTreeShowAndHidden() 为空3D 基础底图和叠加层无法受现有图层树控制。
  • 尚未验证 eng_point 的缩放阈值规则在 3D 下是否能完全复用,存在实现时遗漏中型站点显隐的风险。
  • 目前没有承接 2D 中“放大到具体层级显示更多锚点”的缩放联动显示机制。
  • 目前没有承接 2D 中图标/标签的碰撞检测逻辑,后续若直接全量渲染,视觉效果会与 2D 明显不一致。
  • 当前没有建立 Cesium entity / datasource / imageryLayer 的注册表,后续联动无从下手。

4. 实施原则

  • 不重做业务编排,优先复用 map-orchestrator.tssrc/store/modules/map.ts
  • 不额外引入一套 3D 专用图例和图层状态,仍以现有 store 为唯一运行态来源。
  • 不单独复制 eng_point 的中型站显示规则,优先复用现有 mapStore 过滤结果。
  • 不单独新建一套点击弹框协议,优先保持与 map.ol.ts 相同的命中后行为。
  • 对“缩放越大显示越多锚点”这类规则,优先复用现有缩放阈值与显示门闩,不做拍脑袋的新规则。
  • 对碰撞检测,优先与 2D 保持同方向行为:低缩放控量,高缩放放开,而不是 3D 全量堆点。
  • 先做最小闭环,再逐步补能力:
    • 第一步保证 3D 能正确初始化并定位中国。
    • 第二步保证基础底图能显示。
    • 第三步保证锚点能显示。
    • 第四步保证 popup、图层树、图例联动打通。
  • 3D 不做“基础地图切换 UI”但底层仍要支持 customBaseLayer + addBaseDataLayer(..., true) 这一逻辑。

5. 分步骤实施计划

Step 1修正 3D 初始化并默认定位中国

目标:

  • 切到 3D 后稳定初始化 viewer。
  • 首屏出现一个轻量加载动画。
  • 初始化完成后飞到中国默认视角。

计划:

  • 修复 map.cesium.tsinit()
    • 保证初始化后一定 resolve(this.viewer)
    • 执行 flyToChina()
    • 补一个可控的启动过渡动画。
  • 统一中国默认参数:
    • 中心经纬度建议复用 104.5, 36.5
    • 相机高度先按全国视角收口,后续再微调
  • 如果切回 2D 再切到 3D仍然要能正确重建 viewer。

验收:

  • 点击 3D 按钮后,不再出现美国默认视角。
  • 首屏有加载过渡。
  • 进入后稳定落在中国。

Step 2展示 3D 基础底图

目标:

  • 3D 不显示空球。
  • 保留“基础底图 + 3D 专用底图地址”能力。
  • 不提供底图切换面板,但底层能吃现有配置。

计划:

  • MapCesium 内建立基础图层注册表。
  • 实现 addBaseDataLayer(layer, isShow)
    • customBaseLayer 使用 url_3d
    • BASEMAP-imgBASEMAP-white 预留兼容能力
  • 实现 controlBaseLayerTreeShowAndHidden()
    • 让图层树勾选能控制 3D 底图显隐
  • 根据你的要求UI 层先不开放 BaseLayerSwitcher 的 3D 切换行为,只保留默认基础底图加载。

验收:

  • 切到 3D 后可稳定看到基础底图。
  • 图层初始化时 addBaseDataLayer(this.baseLayerConfig, checked, true) 的思路在 3D 可落地。

Step 3打通 3D 锚点展示

目标:

  • 3D 能展示和 2D 同源的锚点数据。
  • 菜单切换后3D 能跟随页面数据切换。

计划:

  • MapCesium 内建立点位图层注册结构,建议按 layerKey -> entity[]CustomDataSource 管理。
  • 实现 addInitDataLayer(pointData, layerType)
    • 复用当前点位数据结构
    • 解析 lgtd/lttd/iconCode/titleName/stnm/anchoPointState/popupHtml
    • 复用现有图标资源路径
    • 确保 eng_point 仍按现有 mapStore 过滤后的数据展示,中型站点只在 7.5 以上层级出现
    • 为后续缩放驱动的增量显示预留运行态字段,不把所有点简单一次性硬渲染
  • 实现 mdLayerTreeShowOrHidden(layerType, checked)
    • 图层树控制整个点图层显隐
  • 实现 removePointLayer() / hasLayer()
    • 便于后续页面切换和重载

验收:

  • 切到 3D 后当前页默认勾选图层的锚点能显示。
  • 切换菜单后3D 锚点跟随变化。
  • 取消勾选图层后,对应锚点消失。
  • eng_point 在低于 7.5 时不显示中型水电站,高于 7.5 时正常显示。

Step 4打通 3D popup 与 hover

目标:

  • 3D 鼠标悬停时显示与 2D 一样的 popup。
  • popup 样式复用现有 DOM 和样式,不再单独做一版。

计划:

  • 实现 initPopupOverlay(popupContainer)
    • 继续复用 GisView.vue 中现有 popup 容器
  • 在 Cesium 中增加鼠标移动命中:
    • 基于 ScreenSpaceEventHandler
    • hover 到锚点时读取 entity 附带属性
  • popup 内容生成逻辑复用 2D 现有字段:
    • 优先使用 popupHtml
    • 否则走通用字段渲染
  • 处理离开锚点时隐藏 popup。

验收:

  • 鼠标移入锚点出现 popup。
  • 样式和 2D 保持一致。
  • 移出后 popup 正常消失。

Step 5补齐缩放驱动显示与碰撞检测

目标:

  • 3D 在低缩放下控制锚点数量,避免全量堆叠。
  • 3D 在放大到具体层级后,逐步显示更多锚点。
  • 3D 的图标/标签显示效果尽量接近 2D不出现严重遮挡。

计划:

  • 先承接现有明确可复用的缩放规则:
    • eng_point7.5 阈值
    • 水电开发页的 12 级动态图层联动
  • 再补 3D 侧的显示门闩:
    • 低缩放下根据缩放级别、图层状态、图例状态控制 entity 显隐
    • 高缩放下逐步放开限制,显示更多锚点
  • 为 3D 补一版轻量碰撞控制:
    • 至少先控制标签碰撞,避免名称完全叠在一起
    • 如有必要,再补图标级碰撞或屏幕网格抽稀
  • 明确与 2D 对齐的目标不是“算法完全一样”,而是“视觉行为一致”:
    • 低缩放控量
    • 高缩放增量显示
    • 关键锚点不被完全淹没

验收:

  • 3D 在全国视角下不会一次性挤满所有锚点。
  • 放大到具体层级后会看到更多锚点逐步出现。
  • 标签和锚点不会大面积重叠到不可读。

Step 6打通 3D 锚点点击详情

目标:

  • 3D 点击锚点后,行为与 2D 一致。
  • 继续复用现有详情弹框状态和参数结构。

计划:

  • 在 Cesium 中增加点击命中:
    • 基于 ScreenSpaceEventHandler
    • 命中锚点后读取 entity 绑定的原始业务数据
  • 复用 2D 当前点击行为:
    • sttpMap === 'ylfb' 时打开 ylfbModalVisible
    • 其他锚点打开 modalVisible
    • paramstitle 赋值逻辑与 map.ol.ts 保持一致
  • 避免 hover popup 与 click 弹框互相干扰。

验收:

  • 点击 3D 锚点后可打开与 2D 一致的详情弹框。
  • ylfb 和普通锚点分支行为一致。
  • 点击空白区域不会误触发弹框。

Step 7打通图例联动

目标:

  • 图例勾选后3D 只显示对应状态的锚点。

计划:

  • 实现 setLegendPointVisible(layerKey, anchoPointState, checked)
    • 复用 anchoPointState 作为图例匹配字段
    • entity 级别维护显示状态
  • 如果后续需要,也可补一个 3D 版本的图例索引表,避免每次全量遍历。

验收:

  • 图例单项勾选/取消时3D 对应类别锚点同步显隐。
  • 图例分组勾选/取消时3D 行为与 2D 保持一致。

Step 8补足收口与稳定性

目标:

  • 让 3D 能稳定参与现有地图生命周期。

计划:

  • 清理 Cesium 事件监听、viewer、entity、datasource避免重复切换内存泄漏。
  • 检查 switchView('2D' | '3D') 前后 popup、底图、图层注册是否被正确重置。
  • 检查 hover、click、图例、图层树、缩放阈值这几条联动链路在 3D 是否完全闭环。
  • 视情况补最小诊断日志,确认菜单切换与图层联动没有漏项。

验收:

  • 2D/3D 多次来回切换不报错。
  • 菜单切换、图层切换、图例切换行为稳定。

6. 推荐落地顺序

按你的要求,建议严格按下面顺序推进:

  1. 默认定位到中国 + 启动动画
  2. 展示基础底图
  3. 展示锚点
  4. 补 hover popup
  5. 补缩放驱动显示与碰撞检测
  6. 补锚点点击详情
  7. 补图层树联动
  8. 补图例联动
  9. 做切换稳定性收口

9. 必须补齐的隐藏逻辑清单

下面这些逻辑不是表面接口能直接看出来的,但如果 3D 不补,最终效果就会和 2D 明显不一致。

9.1 图层与菜单切换

  • 菜单切换时,只隐藏旧页点图层,不隐藏底图。
  • 图层树勾选前要先经过互斥规则归一化:
    • rare_fish_pointfish_along_point 互斥
    • stinfo/stinfo_video_pointstinfo_ai_video_point 互斥
    • facilitiesfacilities_built 两个分支互斥
  • 点图层取消勾选时只隐藏,不删除缓存;重新勾选时优先从缓存恢复。

9.2 图例与点内显隐

  • 图例控制的是图层内部锚点是否可见,不是图层本身是否可见。
  • 图层恢复显示时,图例要先整层全关,再按当前 checked 状态逐项恢复。
  • 环保设施图例组当前是只展示不交互。

9.3 缩放驱动显示

  • eng_point 的中型水电站只在 ENG_POINT_MEDIUM_VISIBLE_ZOOM = 7.5 以上显示。
  • 水电开发页缩放跨过 12 级时,会自动补开一批动态图层;缩回去时再自动收口。
  • 2D 存在“缩放越大显示越多”的行为,不是所有锚点在所有层级都等量显示。
  • 2D 还存在 hover、批量 popup、密度控制等缩放阈值
    • hover 低于一定缩放不触发
    • 高缩放会进入批量 popup 模式
    • 点位会随着缩放提升逐步放开显示限制

9.4 锚点碰撞与控量

  • 2D 中锚点是否可见,不只受图层开关控制,还受以下门闩共同影响:
    • 图例可见性
    • 区域裁切可见性
    • 密度阈值
    • 图标碰撞结果
    • 标签碰撞结果
  • 低缩放下,为避免堆叠,部分锚点或标签会被主动隐藏。
  • 高缩放下,会逐步放开图标/标签限制,显示更多内容。
  • 因此 3D 不能简单把所有 entity 永久全开,否则视觉密度会明显失控。

9.5 Popup 与点击

  • hover popup 不是全时开启的,有缩放门槛。
  • 点击和 hover 的命中对象是图标本体,不是任意文字区域。
  • ylfb 与普通锚点的点击详情弹框走不同业务分支。

9.6 基地与区域裁切

  • 基地切换不仅影响搜索候选,还会影响地图上的点位可见范围。
  • 区域裁切会直接把区域外点位隐藏,不是只改底图遮罩。

9.7 筛选器特殊逻辑

  • 装机容量筛选本质是批量切 eng_point 图例状态,不是简单切图层。
  • 鱼类分布模式会接管 ylfb_point 的数据、缓存、图例与显隐。
  • 时间筛选当前只重载指定时间相关图层,不是全量重载。

7. 预计修改文件

  • src/components/gis/map.cesium.ts
    • 3D 地图主体实现,主改动文件
  • src/components/gis/map.class.ts
    • 视情况补齐 2D/3D 切换后 popup 初始化和服务切换细节
  • src/components/gis/GisView.vue
    • 视情况控制 3D 下的底图切换器显示策略、加载态挂载位置
  • src/components/mapController/index.vue
    • 若需要补 3D 初始化后的交互控制

8. 当前建议

建议先只做 Step 1,也就是:

  • 修正 Cesium 初始化完成逻辑
  • 增加 3D 启动加载动画
  • 默认飞到中国

这一步最小、最容易验证,也能先把“打开 3D 看起来不对”的核心问题解决掉。