16 KiB
地图模块-详细说明
1. 文档目的
本文档用于梳理当前前端地图模块的整体结构、运行链路、核心文件职责、图层与点位渲染机制、图例与筛选联动方式,以及后台配置与前台运行时之间的关系。
本文档只描述当前地图模块整体实现,不包含抽吸和碰撞的专项分析。
抽吸与碰撞问题单独整理在:
docs/地图模块-OpenLayers抽吸与碰撞分析.md
2. 当前技术栈
当前地图模块涉及的核心技术如下:
- 前端框架:Vue 3 + TypeScript + Ant Design Vue
- 状态管理:Pinia
- 2D 地图引擎:OpenLayers
- 3D 地图引擎:Cesium
- 地图服务:GeoServer
- 数据来源:
- 后端接口返回图层树配置
- 后端接口返回图例配置
- 后端接口返回各类锚点数据
项目依赖中当前地图引擎版本如下:
ol@^10.8.0cesium@^1.141.0leaflet@^1.9.4
说明:
- 当前 2D 主链路已经切换到 OpenLayers;
- Leaflet 依赖仍保留在项目中,但不是当前主运行路径。
3. 地图整体架构
当前地图模块可以分成 6 层:
- 页面入口层
- 应用编排层
- 地图能力门面层
- 地图引擎实现层
- 状态存储层
- 交互组件层
对应文件如下:
-
页面入口层
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.ts
-
状态存储层
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 常驻挂载,入口位置在:
这意味着地图并不是某一个业务页单独创建,而是作为全局地图容器持续存在,然后随着菜单切换切换图层和页面配置。
4.2 GisView.vue 职责
文件:
当前职责主要有:
- 提供地图 DOM 容器
#mapContainer - 挂载地图 popup 容器
- 挂载地图图例、筛选器、控制器、底图切换器
- 根据当前路由计算
pageKey - 在组件挂载时触发地图初始化
- 在页面切换时触发地图页面配置切换
- 分发少量地图控制命令,例如 2D/3D 切换、梯级流域显示
它已经不再承担大部分地图业务拼装逻辑,更多是地图页面入口和组件装配层。
5. 应用编排层
文件:
map-orchestrator 是当前地图运行时的调度中心,主要负责把页面、Store、地图实例串起来。
核心职责包括:
- 初始化地图壳和 popup 容器
- 根据
pageKey加载当前页面地图配置 - 拉取图层树和图例配置
- 初始化基础底图
- 触发点位数据加载
- 处理图层树勾选
- 处理图例显隐
- 处理基地切换
- 处理时间筛选和重新加载
- 处理搜索定位
- 处理某些菜单下的缩放联动图层
5.1 初始化主链路
大致流程如下:
GisView.vue调用mapOrchestrator.mountView()- 编排器初始化地图实例
- 挂载 popup 容器
- 加载当前页面的图层树、图例和页面图例
- 初始化基础底图
- 加载点位图层数据
- 建立缩放监听、基地监听和图例联动
5.2 页面切换
当路由变化后:
GisView.vue重新计算pageKey- 调用
mapOrchestrator.handlePageChange() - 编排器重新加载该页面对应的地图配置和显示状态
这使得地图容器本身不销毁,只是页面配置和显示内容发生变化。
6. 地图能力门面层
文件:
MapClass 是地图能力统一门面,对外提供统一方法,屏蔽 2D 和 3D 的差异。
典型能力包括:
init()addBaseDataLayer()addInitDataLayer()mdLayerTreeShowOrHidden()setLegendPointVisible()baseLayerSwitcher()flyTopanto()zoomToggle()lengthCalculate()areCalculate()mapOutPut()destroy()switchView()
当前 2D 主实现是:
this.service = new MapOl()
说明当前前台主要还是 OpenLayers 在承担地图业务。
7. 地图引擎实现层
7.1 OpenLayers 主实现
文件:
这是当前地图模块最核心的执行层文件,承担了大量实际渲染与地图交互逻辑,包括:
- OpenLayers 地图初始化
- 视图和底图管理
- 点图层管理
- 点位样式生成
- hover popup 与批量 popup
- 区域裁切
- 基地过滤
- 梯级流域图层
- 测量、截图、定位
7.2 Cesium 实现
文件:
当前 3D 能力存在,但相对 2D 来说并没有完全对齐。
目前更像是保留了切换入口和部分基础能力,例如:
- viewer 初始化
- 底图加载
- 定位与飞行
- 部分截图能力
多数业务点位和复杂运行逻辑仍然主要围绕 OpenLayers 设计。
8. 点图层管理
文件:
这个文件负责 OpenLayers 点图层的生命周期管理。
核心职责包括:
- 按图层 key 创建
VectorLayer - 给每个点图层维护独立的
VectorSource - 把后端点位数据转为
Feature<Point> - 建立图例字段索引
- 控制整层显隐
- 控制图例项对应点位显隐
- 删除点图层
- 获取当前可视范围内点位
8.1 当前图层组织方式
当前点位图层的组织方式是:
- 每个业务点图层对应一个
VectorLayer - 每条后端点位数据被转换为一个
Feature - Feature 上会额外挂载运行时字段,例如:
_iconUrl_labelText_legendVisible_regionVisible_layerKey
8.2 图层显隐
图层显隐主要分三类:
- 图层树控制整层显隐
- 图例项控制某一类点位显隐
- 基地裁切控制某些点位在当前基地范围外隐藏
这些状态最终会体现在 Feature 属性和图层可见性上。
9. 点位样式与渲染
点位样式主逻辑在:
当前点位样式包含以下内容:
- 图标
- 文字标签
- 字号随缩放动态变化
- 图标大小随缩放动态变化
- 图例显隐状态
- 基地区域显隐状态
- 按
distance字段做缩放级别抽稀
9.1 当前样式生成逻辑
当前渲染时会综合判断:
- 是否有图标 URL
- 图例是否可见
- 区域是否可见
- 是否满足当前缩放级别下的距离阈值
满足后才会返回 Style。
9.2 当前标签处理
当前标签会做以下处理:
- 去掉括号
- 最多显示两行
- 每行长度受限
- 超长文本截断并加省略号
- 根据单行或多行情况设置不同偏移
这部分属于当前地图的统一标签显示策略。
10. Popup 机制
文件:
Popup 分为两类:
- hover 时显示的单点 popup
- 高缩放下批量显示的 popup
10.1 Hover Popup
基础 hover popup 由地图鼠标移动事件驱动:
- 检测当前 hover 的要素
- 更新悬停状态
- 在对应坐标显示 popup
10.2 批量 Popup
在较高缩放级别下,会进入批量 popup 模式:
- 获取当前视口内所有可见点位
- 逐个测量 popup 尺寸
- 做边界框碰撞判断
- 只渲染不冲突的 popup
这个机制的主要目的是避免高缩放下 popup 过多时完全覆盖地图。
11. 基础底图与 GIS 图层
基础底图和 GIS 叠加图层相关能力主要集中在:
map.ol.tsmapurlManage.tsgisUtils.ts
11.1 mapurlManage.ts
文件:
主要维护:
- GeoServer 服务地址
- WMTS 配置
- XYZ 配置
- 矢量图层相关配置
- 某些专题图层和图例显示参数
11.2 gisUtils.ts
文件:
主要负责:
- 图层树拍平
- 地图配置补全
- 底图配置转换
- 部分标签/偏移相关工具逻辑
12. 图层树与图例
12.1 图层树 UI
文件:
主要职责:
- 展示右侧图层树
- 响应勾选变化
- 把勾选结果转发给编排器和 Store
当前图层树里还包含若干业务互斥规则,例如:
- 视频站和 AI 视频站互斥
- 环保设施和环保设施在建互斥
- 珍稀鱼类和沿程鱼类互斥
12.2 图例 UI
文件:
主要职责:
- 展示当前页面和当前已选图层对应的图例
- 维护图例项勾选状态
- 把图例点击行为分发给编排器
图例不是固定写死的,而是由后端返回配置和当前已选图层共同决定。
13. 地图筛选与控制器
13.1 MapFilter
文件:
当前承担的筛选功能包括:
- 基地筛选
- 时间筛选
- 装机容量筛选
- 关键字搜索
- 个别专题下的额外筛选
13.2 MapController
文件:
当前承担的地图操作包括:
- 放大缩小
- 图层树显隐
- 2D / 3D 切换
- 量算
- 截图
- 梯级流域专题显示
13.3 BaseLayerSwitcher
文件:
用于切换:
- 矢量底图
- 地形底图
- 影像底图
14. Store 分层
14.1 旧主 Store
文件:
当前仍然承担大量地图运行态逻辑,例如:
- 图层选中状态
- 图例选中状态
- 图层数据加载
- 图例联动
- 点位缓存
- 图层更新
14.2 新拆分 Store
文件:
当前已经开始按职责拆分:
-
map-config.store.ts- 维护图层树和图例配置
-
map-data.store.ts- 维护图层数据缓存和点位数据
-
map-view.store.ts- 维护视图相关运行态,例如选中图层、图例勾选、缩放级别、基地状态
这说明地图模块已经在往“编排层 + Store 分层 + 引擎执行层”方向演进。
15. 基地裁切与区域过滤
基地逻辑是当前地图模块里的关键能力之一。
入口主要在:
GisView.vuemap-orchestrator.tsmap.ol.ts
整体过程大致如下:
- 选择基地
- 编排器接收基地变化
- 调用地图实例更新基地范围
- 请求或读取基地边界 GeoJSON
- 对点位执行区域内外判断
- 更新 Feature 的
_regionVisible - 地图样式函数据此决定是否显示
除了点位控制外,基地切换还会影响底图裁切和专题图层显示。
16. 后台配置与前台运行时关系
地图模块不仅依赖前台代码,也强依赖后台配置。
16.1 后台管理入口
主要页面位于:
16.2 后台管理内容
后台可维护的内容主要包括:
- 图层树结构
- 图层是否启用
- 图层接口地址
- 图层基础参数
- 图例元数据
16.3 前后台关系
运行时不是前端把所有图层写死,而是:
- 后台维护元数据
- 前端进入页面后加载配置
- 再根据配置请求对应图层数据
- 最后交给地图引擎渲染
因此地图模块本质上是“配置驱动 + 运行时渲染”的模式。
17. 当前调用链总结
17.1 页面初始化链路
整体调用链如下:
AppMain挂载GisViewGisView调用mapOrchestrator.mountViewmapOrchestrator调用MapClass.initMapClass实际调用MapOl.init- 编排器加载图层树和图例配置
- 编排器初始化底图
- 编排器加载点位数据
PointLayerManager创建点图层并写入 FeatureMapOl通过样式函数完成渲染
17.2 图层勾选链路
整体调用链如下:
- 用户勾选
LayerController - 编排器接收图层选择结果
- Store 更新图层选中状态
- 地图实例更新图层显隐
- 图例重新派生
17.3 图例点击链路
整体调用链如下:
- 用户点击
MapLegend - 编排器接收图例切换
- Store 更新图例选中状态
- 地图实例更新图例对应点位显隐
17.4 筛选链路
整体调用链如下:
- 用户操作
MapFilter - 编排器接收搜索、时间、基地或容量变化
- Store 更新运行态
- 必要时删图层、清缓存、重新请求数据
- 地图引擎重新渲染
18. 当前模块特点
从现有实现看,地图模块有以下几个明显特点:
- 地图容器是全局常驻的
- 页面切换主要依赖
pageKey重新编排 - OpenLayers 是当前 2D 主引擎
- 地图运行态是配置驱动的
- 点位图层按业务图层分层组织
- 图层树、图例、筛选、基地切换之间耦合较深
- 编排层已经出现,但部分旧逻辑仍在 Store 和引擎层混合存在
19. 相关文件清单
地图模块当前重点文件如下:
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.vuesrc/views/system/map/index.vuesrc/views/system/map/components/LayerManagement/index.vue
20. 结论
当前地图模块已经形成了比较清晰的主干结构:
GisView作为入口层map-orchestrator作为编排层MapClass作为统一门面MapOl作为 2D 主执行层- 多个 Store 共同维护配置、数据和视图状态
- 图层树、图例、筛选器、底图切换器作为前台交互入口
如果后续继续扩展专题图层、复杂筛选、点位布局和高缩放交互,建议都优先沿着这条主干扩展,而不是再回到页面组件里直接堆业务逻辑。