# 地图模块-详细说明 ## 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 执行层”这条主干扩展,不要再把复杂业务回填到页面组件里。