WholeProcessPlatform/frontend/docs/地图模块-详细说明.md
2026-07-01 08:48:39 +08:00

17 KiB
Raw Blame History

地图模块-详细说明

1. 文档目的

本文档用于说明当前地图模块的真实运行结构、初始化时序、图层与图例联动、点位渲染规则、筛选与缩放行为,以及近期已经落地的关键约束。

本文档描述的是“当前可运行版本”的现状,不展开抽吸参数细节与专项问题分析。相关补充文档如下:

  • docs/地图模块-抽吸规则与参数说明.md
  • docs/地图模块-OpenLayers抽吸与碰撞分析.md

2. 当前技术栈

  • 前端框架Vue 3 + TypeScript + Ant Design Vue
  • 状态管理Pinia
  • 2D 地图引擎OpenLayers 10.8.0
  • 3D 地图引擎Cesium
  • 地图服务GeoServer / WMTS / XYZ
  • 运行模式:后台配置驱动 + 前台运行时编排

说明:

  • 当前 2D 主链路已经完全围绕 OpenLayers 组织。
  • 项目中仍保留 Leaflet 相关依赖和旧代码,但不是当前主执行路径。

3. 模块分层

当前地图模块可以按 6 层理解:

  1. 页面入口层
  2. 应用编排层
  3. 地图能力门面层
  4. 地图引擎执行层
  5. Store 运行态层
  6. 前台交互组件层

对应核心文件如下:

  • 页面入口层
    • src/components/gis/GisView.vue
  • 应用编排层
    • src/modules/map/application/map-orchestrator.ts
  • 地图能力门面层
    • src/components/gis/map.class.ts
  • 地图引擎执行层
    • src/components/gis/map.ol.ts
    • src/components/gis/map.cesium.ts
    • src/components/gis/ol/point-layer-manager.ts
    • src/components/gis/ol/popup-manager.ts
  • Store 运行态层
    • src/store/modules/map.ts
    • src/modules/map/stores/map-config.store.ts
    • src/modules/map/stores/map-data.store.ts
    • src/modules/map/stores/map-view.store.ts
  • 前台交互组件层
    • src/components/mapLegend/index.vue
    • src/components/mapFilter/index.vue
    • src/components/mapController/index.vue
    • src/components/mapController/LayerController.vue
    • src/components/BaseLayerSwitcher/index.vue

4. 整体原则

当前地图模块遵循以下几个运行原则:

4.1 地图容器全局常驻

地图由 GisView.vue 常驻挂载,不会随着菜单切换被销毁重建。页面切换本质上是:

  • 重新计算 pageKey
  • 重新加载该页图层配置和图例配置
  • 用新的运行态覆盖旧页面显示内容

4.2 配置驱动

前端不把全部图层和图例硬编码死,而是依赖后端返回的:

  • 图层树配置
  • 图例配置
  • 页面级图例配置
  • 各业务点位接口数据

4.3 运行态绝对优先

初始化默认值只在第一次派生时生效;一旦进入运行态,后续图层勾选、图例勾选、筛选器切换,都必须以当前用户操作后的状态为准,不能在加载完成后回退到默认状态。

5. 页面入口层

5.1 GisView.vue

GisView.vue 的职责主要是:

  • 提供地图容器 #mapContainer
  • 提供 popup 挂载容器
  • 挂载图例、筛选器、控制器、底图切换器
  • 根据路由计算 pageKey
  • 在挂载时调用 mapOrchestrator.mountView()
  • 在页面切换时交给编排器重载页面

当前页面层已经不再直接承载复杂业务逻辑,复杂链路都收敛到了编排器和 Store。

6. 应用编排层

6.1 map-orchestrator.ts 的职责

map-orchestrator.ts 是当前地图业务的总调度中心,主要负责:

  • 初始化地图壳与 popup
  • 加载页面图层配置和图例配置
  • 初始化 GIS 基础图层
  • 触发点位图层加载
  • 管理缩放监听和基地切换监听
  • 处理图层树勾选
  • 处理图例勾选
  • 处理时间筛选、容量筛选、搜索定位
  • 处理水电开发菜单下的缩放联动图层

6.2 页面初始化链路

当前初始化顺序如下:

  1. GisView.vue 调用 mapOrchestrator.mountView()
  2. MapClass.init() 初始化地图实例
  3. 页面级 popup 容器挂到地图实例
  4. 绑定缩放监听和基地监听
  5. 并行请求图层树配置与图例配置
  6. 图例接口先返回时,立即生成图例运行态
  7. 图层树接口返回后,生成默认勾选图层并初始化 GIS 基础图层
  8. 再按图层配置批量加载点位数据

这里有两个当前已落地的关键时序调整:

  • 图例转圈只跟图例接口绑定,不再等待所有锚点接口完成。
  • 筛选器数据会随着已加载图层逐步出现,不再必须等全量点位接口结束。

6.3 页面切换

页面切换时地图不销毁,只重载当前页面的:

  • 图层树配置
  • 图例配置
  • 点位数据
  • 当前页面的默认运行态

如果仍处于同一个 pageKey 且用户之前修改过勾选态,会尽量复用当前运行态,而不是重新回放默认勾选。

6.4 缩放联动

当前编排层主要有两类缩放联动:

  • eng_point 缩放联动
    • 大型电站始终允许显示
    • 中型电站仅在 zoom > 7.5 时进入显示候选
  • 水电开发菜单动态图层联动
    • HYDRO_DYNAMIC_LAYER_KEYS 在缩放跨越阈值时参与加载与显隐编排

7. 地图能力门面层

7.1 map.class.ts

MapClass 是地图能力统一门面,屏蔽 2D / 3D 引擎差异,对外暴露统一方法。

当前常用能力包括:

  • init()
  • initPopupOverlay()
  • addBaseDataLayer()
  • addInitDataLayer()
  • mdLayerTreeShowOrHidden()
  • controlBaseLayerTreeShowAndHidden()
  • setLegendPointVisible()
  • hasLayer()
  • hasBaseLayer()
  • removePointLayer()
  • flyTopanto()
  • switchView()

当前业务主执行层仍然是 MapOl

8. 地图引擎执行层

8.1 OpenLayers 主执行层

map.ol.ts 负责 OpenLayers 地图的实际渲染与交互,是当前 2D 地图主执行文件。

当前承担的核心能力包括:

  • 地图实例初始化
  • 底图与 GIS 图层管理
  • 点位图层渲染
  • 图标与文字样式生成
  • hover popup 与批量 popup
  • 基地范围裁切
  • 高缩放交互
  • 测量、截图、飞行定位等基础地图能力

8.2 Cesium 执行层

map.cesium.ts 目前更多是保留 3D 入口和部分基础能力,复杂业务点位与碰撞规则并未与 OpenLayers 完全对齐。

结论上,当前真实业务规则仍然以 OpenLayers 链路为准。

9. Store 分层

9.1 map-config.store.ts

负责配置态数据:

  • 图层树配置
  • 图层配置索引
  • 全量原始图例配置
  • 图例索引
  • 页面级图例配置
  • 配置接口加载状态

当前这里拆分出了两个加载态:

  • configLoading
  • legendLoading

其中 legendLoading 单独控制图例转圈。

9.2 map-data.store.ts

负责数据态:

  • pointData
  • pointDataCache
  • layerLoadState
  • 地图整体 loading

这里的关键设计是:

  • 每个点图层有独立缓存
  • pointData 是由缓存合并出来的运行态数据
  • 单个图层命中缓存或接口返回后,就会立即回填 pointData

因此当前搜索筛选下拉已经支持“渐进可用”,不再只能等全部接口结束。

9.3 map-view.store.ts

负责视图运行态:

  • 当前勾选图层 checkedLayerKeys
  • 图例勾选状态 legendCheckedState
  • 搜索时间范围
  • 当前基地
  • 当前缩放级别

9.4 src/store/modules/map.ts

这是当前地图运行逻辑最重的 Store负责串联配置、缓存和地图实例。

主要职责包括:

  • 生成图例运行态
  • 批量加载点位数据
  • 控制图层显隐
  • 控制图例显隐
  • 管理请求缓存与并发加载
  • 刷新点图层显示数据
  • 处理 eng_point 的显示过滤
  • 在全量点位准备完成后挂载近邻点元数据

10. 图层分类

当前地图里的图层大体可以分成三类:

10.1 GISMap

这类图层对应 GIS 基础图层或专题底图,由 addBaseDataLayer() 加载到 layerRegistry

当前已补充的规则:

  • 勾选 GISMap 时,不能只做显示/隐藏。
  • 如果地图实例中不存在该图层,需要先重新加载,再显示。

10.2 点位图层

这类图层由接口返回锚点数据,最终进入 PointLayerManager 维护的 VectorLayer

10.3 其他专题图层

例如梯级流域、区域裁切辅助层等,这些更多由 map.ol.ts 单独控制。

11. 图层数据加载机制

11.1 配置与数据分离

当前初始化时,配置加载与点位数据加载是两条链:

  • 图层树配置决定有哪些层、哪些默认勾选
  • 图例配置决定图例结构和图例项元数据
  • 点位数据接口决定地图上实际锚点内容

11.2 加载顺序

loadAllLayerData() 的主要逻辑是:

  1. 先收集所有带 URL 的图层
  2. 把默认勾选图层作为高优先级任务
  3. 并发加载,默认并发数为 4
  4. 每个图层完成后立即写入缓存
  5. 每个图层命中缓存或返回成功后,立即增量更新 pointData
  6. 全部图层结束后,再统一:
    • 回填每层原始数据
    • 挂载近邻点运行时元数据
    • 刷新各图层显示数据
    • 用最新运行态收尾

11.3 初始化阶段的图例绝对性

当前已修复一个关键问题:

  • 图例虽然可能在界面上还在 loading
  • 但只要图例配置已经返回,默认隐藏的图例项在点位首批入图时就必须生效

也就是说,现在不会再出现:

  • loading 过程中先显示默认隐藏点
  • loading 结束后才消失

12. 图例机制

12.1 图例来源

图例运行态由以下数据共同决定:

  • 原始全量图例配置
  • 当前页面图例配置
  • 当前已勾选图层
  • 当前图例勾选状态

12.2 图例派生

图例最终显示的是 legendDataSelected,而不是全量图例。

派生逻辑核心原则如下:

  • 只有当前勾选图层对应的图例项才进入页面图例
  • 图例勾选状态是运行态绝对值
  • 环保设施分组有单独规则

12.3 图例加载时机

当前图例面板的 loading 只跟图例接口绑定:

  • 图例接口返回后立即停转
  • 图例内容在图层默认勾选同步后立即派生
  • 不再等待所有锚点接口完成

13. 筛选器机制

13.1 MapFilter 的职责

筛选器当前包含以下能力:

  • 时间范围筛选
  • 装机容量筛选
  • 搜索定位
  • 个别页面的专题筛选项

13.2 搜索下拉来源

搜索下拉使用 mapDataStore.pointData 作为数据源。

当前行为已经调整为:

  • 某个图层一旦命中缓存,筛选器即可出现该图层点位
  • 某个图层接口一旦返回成功,筛选器也会立即出现该图层点位

因此筛选器当前是“渐进展示”,而不是“全量完成后一次性展示”。

13.3 装机容量筛选

装机容量筛选针对 eng_point 图层,当前规则如下:

  • all
    • 恢复大型与中型图例
  • large_eng_built
    • 只保留 large_eng_ 前缀相关图例
    • 地图上只显示大型电站点位
  • mid_eng_built
    • 只保留 mid_eng_ 前缀相关图例
    • 地图上只显示中型电站点位

当前容量切换不再只是影响筛选器本地下拉,而是会同步驱动:

  • 图例运行态
  • eng_point 点位显示

14. eng_point 专项规则

eng_point 是当前地图模块中的特殊图层,存在独立显示规则。

14.1 缩放规则

在数据入图阶段就生效:

  • 大型电站始终允许显示
  • 中型电站仅在 zoom > 7.5 时允许进入显示候选

这不是单纯的图例控制,而是点位入图时的过滤逻辑。

14.2 图例规则

点位入图之后,仍然必须再经过图例运行态控制:

  • 允许入图,不等于最终可见
  • 只要图例勾选为隐藏,该类点位就必须隐藏

14.3 容量筛选规则

装机容量下拉会进一步批量控制 eng_point 的图例项,使图例与点位同步切换。

15. 点位显示裁决链

当前点位最终是否显示,至少会经过以下几层判断:

  1. 图层是否勾选
  2. 图例是否勾选
  3. 基地范围是否允许
  4. eng_point 缩放过滤是否通过
  5. distance 密度分档是否通过
  6. 近邻点显示阶段是否通过
  7. 图标是否已加载完成
  8. 当前缩放下是否进入碰撞控制

这几层不是互斥关系,而是叠加裁决。

16. 点位渲染与样式

16.1 基础样式

当前点位渲染包括:

  • 图标
  • 文字标签
  • 标签换行与截断
  • 缩放相关的图标与文字样式变化

16.2 图标加载约束

当前已经补充图标加载状态缓存:

  • 图标未加载完成时,不显示该点
  • 图标未加载完成时,文字也不先显示
  • 图标未加载完成时,不参与碰撞候选

这样可以避免“文字先出来、图标还是空的”的问题。

17. 抽吸、密度与碰撞

17.1 专项文档

抽吸与密度分档的详细参数请查看:

  • docs/地图模块-抽吸规则与参数说明.md

17.2 当前裁决顺序

当前点位显示顺序可以理解为:

  1. 密度分档
  2. 近邻抽吸
  3. 图标碰撞
  4. 文字碰撞

补充约束:

  • 只有满足可见性条件的点,才能进入碰撞候选集
  • 被图例或缩放过滤掉的点,不能再去占用碰撞资格
  • 视图内无近邻的孤立点允许局部放行

17.3 高缩放特例

当前在高缩放层级 zoom >= 15 时,行为与中低缩放不同:

  • 只处理视口内点位
  • 点与文字不再做碰撞淘汰
  • 视口内符合基础显示条件的点和文字全部显示
  • 同时进入批量 popup 模式

这条规则的目标是:

  • 保证深度放大后信息完整可见
  • 避免高缩放下还因为碰撞把点或文字压掉

18. Popup 机制

18.1 两类 popup

当前 popup 分成两类:

  • hover popup
  • batch popup

18.2 hover popup

鼠标悬停时由 pointermove 驱动,只在非 batch popup 模式下显示。

18.3 batch popup

zoom >= 15 时进入批量 popup 模式:

  • 只基于当前视口内点位
  • 拖动地图时持续刷新
  • 但通过 requestAnimationFrame 做节流
  • moveend 后立即再做一次强制刷新

当前这样做是为了兼顾两件事:

  • 保留“拖动时 popup 跟着更新”的原交互
  • 避免拖动过程中每个事件都重建整批 DOM

18.4 惯性平移已关闭

当前地图拖动已经关闭 OpenLayers 默认惯性平移:

  • 普通拖动仍然保留
  • 松手后不再继续滑动一小段

这样可以减少高缩放 popup 场景下“松手还轻微位移”的观感问题。

19. 基地与区域过滤

基地切换是当前地图模块的关键能力之一,主要影响:

  • 地图裁切范围
  • 当前基地相关点位的可见性
  • 部分专题图层显示

整体过程通常是:

  1. 外部基地选择源变化
  2. 编排器接收到基地 ID
  3. 地图实例切换基地范围
  4. 点位更新 _regionVisible
  5. 样式函数按区域可见性决定是否显示

20. 典型交互链路

20.1 图层树勾选

  1. LayerController 触发勾选变化
  2. 编排器归一化图层 key
  3. map.ts 更新运行态图层勾选
  4. 地图实例更新图层显隐
  5. 图例重新派生

补充:

  • GISMap 勾选时,如果地图里没有该图层,会先补载,再显示

20.2 图例勾选

  1. 图例组件触发点击
  2. 编排器转发图例切换
  3. map.ts 更新图例运行态
  4. 对应点位立即更新显隐
  5. 图例树同步更新灰态

20.3 筛选器操作

  1. 用户切换时间、容量、搜索等条件
  2. 编排器接收命令
  3. 视情况更新视图运行态或重载数据
  4. 地图实例与图例运行态同步刷新

20.4 缩放操作

  1. OpenLayers 视图触发 change:resolution
  2. 编排器更新当前缩放级别
  3. 处理 eng_point 阈值联动
  4. 水电开发菜单下处理动态图层联动
  5. map.ol.ts 处理高缩放 popup 与点位显示策略

21. 当前重点文件清单

  • src/components/gis/GisView.vue
  • src/components/gis/map.class.ts
  • src/components/gis/map.ol.ts
  • src/components/gis/map.cesium.ts
  • src/components/gis/gisUtils.ts
  • src/components/gis/mapurlManage.ts
  • src/components/gis/ol/point-layer-manager.ts
  • src/components/gis/ol/popup-manager.ts
  • src/modules/map/application/map-orchestrator.ts
  • src/modules/map/stores/map-config.store.ts
  • src/modules/map/stores/map-data.store.ts
  • src/modules/map/stores/map-view.store.ts
  • src/store/modules/map.ts
  • src/components/mapLegend/index.vue
  • src/components/mapFilter/index.vue
  • src/components/mapController/index.vue
  • src/components/mapController/LayerController.vue
  • src/components/BaseLayerSwitcher/index.vue

22. 当前结论

当前地图模块已经形成比较清晰的主干结构:

  • GisView 负责挂载与页面入口
  • map-orchestrator 负责业务编排
  • MapClass 负责能力门面
  • MapOl 负责 2D 主执行
  • map.ts + 三个拆分 store 共同维护配置、数据与视图运行态
  • 图层树、图例、筛选器、popup、高缩放规则都已经围绕这条主干收口

相较旧版说明,当前最重要的现状变化有 8 点:

  1. 图例 loading 已与锚点全量加载解耦
  2. 筛选器数据已支持渐进展示
  3. 初始化阶段默认隐藏图例项会立即生效
  4. 运行态勾选不会在 loading 完成后被默认值覆盖
  5. eng_point 有独立的缩放与容量规则
  6. 高缩放下视口内点和文字全部显示,不再做碰撞淘汰
  7. batch popup 保留拖动跟随,但增加了节流
  8. 地图拖动惯性已关闭

后续如果继续扩展地图功能,建议仍然优先沿着“编排层 + Store 分层 + OpenLayers 执行层”这条主干扩展,不要再把复杂业务回填到页面组件里。