17 KiB
地图模块-详细说明
1. 文档目的
本文档用于说明当前地图模块的真实运行结构、初始化时序、图层与图例联动、点位渲染规则、筛选与缩放行为,以及近期已经落地的关键约束。
本文档描述的是“当前可运行版本”的现状,不展开抽吸参数细节与专项问题分析。相关补充文档如下:
docs/地图模块-抽吸规则与参数说明.mddocs/地图模块-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 层理解:
- 页面入口层
- 应用编排层
- 地图能力门面层
- 地图引擎执行层
- Store 运行态层
- 前台交互组件层
对应核心文件如下:
- 页面入口层
src/components/gis/GisView.vue
- 应用编排层
src/modules/map/application/map-orchestrator.ts
- 地图能力门面层
src/components/gis/map.class.ts
- 地图引擎执行层
src/components/gis/map.ol.tssrc/components/gis/map.cesium.tssrc/components/gis/ol/point-layer-manager.tssrc/components/gis/ol/popup-manager.ts
- Store 运行态层
src/store/modules/map.tssrc/modules/map/stores/map-config.store.tssrc/modules/map/stores/map-data.store.tssrc/modules/map/stores/map-view.store.ts
- 前台交互组件层
src/components/mapLegend/index.vuesrc/components/mapFilter/index.vuesrc/components/mapController/index.vuesrc/components/mapController/LayerController.vuesrc/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 页面初始化链路
当前初始化顺序如下:
GisView.vue调用mapOrchestrator.mountView()MapClass.init()初始化地图实例- 页面级 popup 容器挂到地图实例
- 绑定缩放监听和基地监听
- 并行请求图层树配置与图例配置
- 图例接口先返回时,立即生成图例运行态
- 图层树接口返回后,生成默认勾选图层并初始化 GIS 基础图层
- 再按图层配置批量加载点位数据
这里有两个当前已落地的关键时序调整:
- 图例转圈只跟图例接口绑定,不再等待所有锚点接口完成。
- 筛选器数据会随着已加载图层逐步出现,不再必须等全量点位接口结束。
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
负责配置态数据:
- 图层树配置
- 图层配置索引
- 全量原始图例配置
- 图例索引
- 页面级图例配置
- 配置接口加载状态
当前这里拆分出了两个加载态:
configLoadinglegendLoading
其中 legendLoading 单独控制图例转圈。
9.2 map-data.store.ts
负责数据态:
pointDatapointDataCachelayerLoadState- 地图整体
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() 的主要逻辑是:
- 先收集所有带 URL 的图层
- 把默认勾选图层作为高优先级任务
- 并发加载,默认并发数为 4
- 每个图层完成后立即写入缓存
- 每个图层命中缓存或返回成功后,立即增量更新
pointData - 全部图层结束后,再统一:
- 回填每层原始数据
- 挂载近邻点运行时元数据
- 刷新各图层显示数据
- 用最新运行态收尾
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. 点位显示裁决链
当前点位最终是否显示,至少会经过以下几层判断:
- 图层是否勾选
- 图例是否勾选
- 基地范围是否允许
eng_point缩放过滤是否通过distance密度分档是否通过- 近邻点显示阶段是否通过
- 图标是否已加载完成
- 当前缩放下是否进入碰撞控制
这几层不是互斥关系,而是叠加裁决。
16. 点位渲染与样式
16.1 基础样式
当前点位渲染包括:
- 图标
- 文字标签
- 标签换行与截断
- 缩放相关的图标与文字样式变化
16.2 图标加载约束
当前已经补充图标加载状态缓存:
- 图标未加载完成时,不显示该点
- 图标未加载完成时,文字也不先显示
- 图标未加载完成时,不参与碰撞候选
这样可以避免“文字先出来、图标还是空的”的问题。
17. 抽吸、密度与碰撞
17.1 专项文档
抽吸与密度分档的详细参数请查看:
docs/地图模块-抽吸规则与参数说明.md
17.2 当前裁决顺序
当前点位显示顺序可以理解为:
- 密度分档
- 近邻抽吸
- 图标碰撞
- 文字碰撞
补充约束:
- 只有满足可见性条件的点,才能进入碰撞候选集
- 被图例或缩放过滤掉的点,不能再去占用碰撞资格
- 视图内无近邻的孤立点允许局部放行
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. 基地与区域过滤
基地切换是当前地图模块的关键能力之一,主要影响:
- 地图裁切范围
- 当前基地相关点位的可见性
- 部分专题图层显示
整体过程通常是:
- 外部基地选择源变化
- 编排器接收到基地 ID
- 地图实例切换基地范围
- 点位更新
_regionVisible - 样式函数按区域可见性决定是否显示
20. 典型交互链路
20.1 图层树勾选
LayerController触发勾选变化- 编排器归一化图层 key
map.ts更新运行态图层勾选- 地图实例更新图层显隐
- 图例重新派生
补充:
GISMap勾选时,如果地图里没有该图层,会先补载,再显示
20.2 图例勾选
- 图例组件触发点击
- 编排器转发图例切换
map.ts更新图例运行态- 对应点位立即更新显隐
- 图例树同步更新灰态
20.3 筛选器操作
- 用户切换时间、容量、搜索等条件
- 编排器接收命令
- 视情况更新视图运行态或重载数据
- 地图实例与图例运行态同步刷新
20.4 缩放操作
- OpenLayers 视图触发
change:resolution - 编排器更新当前缩放级别
- 处理
eng_point阈值联动 - 水电开发菜单下处理动态图层联动
map.ol.ts处理高缩放 popup 与点位显示策略
21. 当前重点文件清单
src/components/gis/GisView.vuesrc/components/gis/map.class.tssrc/components/gis/map.ol.tssrc/components/gis/map.cesium.tssrc/components/gis/gisUtils.tssrc/components/gis/mapurlManage.tssrc/components/gis/ol/point-layer-manager.tssrc/components/gis/ol/popup-manager.tssrc/modules/map/application/map-orchestrator.tssrc/modules/map/stores/map-config.store.tssrc/modules/map/stores/map-data.store.tssrc/modules/map/stores/map-view.store.tssrc/store/modules/map.tssrc/components/mapLegend/index.vuesrc/components/mapFilter/index.vuesrc/components/mapController/index.vuesrc/components/mapController/LayerController.vuesrc/components/BaseLayerSwitcher/index.vue
22. 当前结论
当前地图模块已经形成比较清晰的主干结构:
GisView负责挂载与页面入口map-orchestrator负责业务编排MapClass负责能力门面MapOl负责 2D 主执行map.ts + 三个拆分 store共同维护配置、数据与视图运行态- 图层树、图例、筛选器、popup、高缩放规则都已经围绕这条主干收口
相较旧版说明,当前最重要的现状变化有 8 点:
- 图例 loading 已与锚点全量加载解耦
- 筛选器数据已支持渐进展示
- 初始化阶段默认隐藏图例项会立即生效
- 运行态勾选不会在 loading 完成后被默认值覆盖
eng_point有独立的缩放与容量规则- 高缩放下视口内点和文字全部显示,不再做碰撞淘汰
- batch popup 保留拖动跟随,但增加了节流
- 地图拖动惯性已关闭
后续如果继续扩展地图功能,建议仍然优先沿着“编排层 + Store 分层 + OpenLayers 执行层”这条主干扩展,不要再把复杂业务回填到页面组件里。