diff --git a/frontend-sjtb/public/file/过鱼设施数据填报操作手册.docx b/frontend-sjtb/public/file/过鱼设施数据填报操作手册.docx index f3d2e60d..536eb442 100644 Binary files a/frontend-sjtb/public/file/过鱼设施数据填报操作手册.docx and b/frontend-sjtb/public/file/过鱼设施数据填报操作手册.docx differ diff --git a/frontend/docs/地图模块-OpenLayers抽吸与碰撞分析.md b/frontend/docs/地图模块-OpenLayers抽吸与碰撞分析.md index e7bf6d02..3c0e97d0 100644 --- a/frontend/docs/地图模块-OpenLayers抽吸与碰撞分析.md +++ b/frontend/docs/地图模块-OpenLayers抽吸与碰撞分析.md @@ -16,7 +16,10 @@ - 再继续放大后,`1` 和 `2` 都展示,但 `2` 需要“抽吸/拉开”显示,避免与 `1` 重叠; - 如果只是文字发生碰撞,希望点图标保留,仅文字隐藏或延后显示。 -本文件先整理当前代码现状和问题成因,不直接修改实现。 +本文件先整理当前代码现状和问题成因,不直接修改实现。 +如果需要查看**当前已经落地的抽吸规则、默认参数和调参入口**,请同时参考: + +- `docs/地图模块-抽吸规则与参数说明.md` ## 2. 当前代码结构 diff --git a/frontend/docs/地图模块-抽吸规则与参数说明.md b/frontend/docs/地图模块-抽吸规则与参数说明.md new file mode 100644 index 00000000..65c9e71e --- /dev/null +++ b/frontend/docs/地图模块-抽吸规则与参数说明.md @@ -0,0 +1,316 @@ +# 地图模块-抽吸规则与参数说明 + +## 1. 文档目的 + +本文档用于记录当前地图点位“抽吸”功能的现行实现、默认参数、分层级显示规则和后续调参方式。 +本文件描述的是**当前已经落地并验证通过**的规则,适合作为后续维护和继续调参的依据。 + +相关文档: + +- `docs/地图模块-详细说明.md`:地图整体架构说明 +- `docs/地图模块-OpenLayers抽吸与碰撞分析.md`:问题成因与改造分析 + +## 2. 当前实现范围 + +当前抽吸逻辑运行在 OpenLayers 主链路中,核心文件如下: + +1. `src/modules/map/domain/nearby-point-rules.ts` +2. `src/store/modules/map.ts` +3. `src/components/gis/map.ol.ts` +4. `src/components/gis/ol/point-layer-manager.ts` + +各文件职责: + +- `nearby-point-rules.ts` + - 近邻点规则入口 + - 自动识别配置入口 + - 近邻点运行时元数据挂载 +- `map.ts` + - 点位数据加载完成后,统一触发近邻点分组和元数据写回 +- `map.ol.ts` + - 决定某个点在当前缩放级别是否显示 + - 决定文字是否允许显示 + - 承担图标与文字的手工碰撞控制 +- `point-layer-manager.ts` + - 负责展开阶段的几何偏移 + - 负责把同组点位按扇形/环形布局散开 + +## 3. 当前抽吸规则 + +### 3.1 近邻点自动识别 + +当前采用自动识别近邻点,不再靠固定站名手工枚举。 + +识别原则: + +- 只在同一 `layerKey` 内做近邻识别 +- 按点位空间距离自动聚组 +- 满足最小组大小后,才认为是近邻组 +- 组内自动生成显示优先级 `priority` + +这样做的目的: + +- 避免跨图层混组 +- 避免后续新增点位还要手工补名字 +- 让抽吸能力可以覆盖整批业务点 + +### 3.2 分层级显示规则 + +当前显示规则以 `replaceAtZoom` 和 `expandAtZoom` 为核心: + +1. `zoom < replaceAtZoom` + - 只显示组内主点 + - 即 `priority = 1` +2. `replaceAtZoom <= zoom < expandAtZoom` + - 显示组内前两个点 + - 即 `priority <= 2` + - 当前这样设计是为了避免主点在放大过程中突然消失 +3. `zoom >= expandAtZoom` + - 同组点全部显示 + - 同时进入展开布局阶段 + +补充规则: + +- 如果某个点配置了 `showZoomMin` 或 `showZoomMax`,则先受这两个值约束 +- 没有进入近邻组的点,不受抽吸规则影响 + +### 3.3 文字显示规则 + +当前文字显示必须依赖点位显示。 + +也就是说: + +- 点不显示,文字一定不显示 +- 点显示后,文字还要继续通过碰撞判断才会显示 + +当前文字碰撞规则: + +- 文字要避让已保留的图标占位盒 +- 文字要避让已保留的其他文字 +- 图标与文字不再分别交给 OpenLayers 的 `declutter` 自动处理 +- 当前走的是项目内的手工碰撞控制 + +## 4. 当前默认参数 + +当前默认参数集中维护在: + +- `src/modules/map/domain/nearby-point-rules.ts` + +当前采用统一配置对象: + +```ts +type NearbyPointConfig = { + autoRule: NearbyPointAutoRule; + layoutRule: NearbyPointLayoutRule; + densityDisplayRules: NearbyPointDensityDisplayRule[]; +}; +``` + +其中: + +- `autoRule`:控制近邻点自动识别、缩放切换和基础展开半径 +- `layoutRule`:控制展开阶段的单圈容量、扇形角度和外圈间距 +- `densityDisplayRules`:控制 `distance` 密度分档在不同缩放级别的基础显示资格 + +### 4.1 自动识别与缩放阶段参数 + +当前值如下: + +| 参数 | 当前值 | 作用 | +|---|---:|---| +| `distanceThresholdMeters` | `9000` | 近邻点自动识别距离阈值 | +| `replaceAtZoom` | `10.5` | 进入“主点 + 次点”阶段的缩放级别 | +| `expandAtZoom` | `12.2` | 进入“全部显示并展开”阶段的缩放级别 | +| `expandOffsetPx` | `48` | 第一圈展开的基础偏移半径 | +| `angleStepDeg` | `55` | 默认角度步长参考值 | +| `minGroupSize` | `2` | 最小成组数量 | + +### 4.2 展开布局参数 + +当前值如下: + +| 参数 | 当前值 | 作用 | +|---|---:|---| +| `ringSize` | `5` | 单圈最多容纳的次点数量 | +| `fanAngleForTwoDeg` | `110` | 单圈剩余 `2` 个点时的扇形总角度 | +| `fanAngleForFourDeg` | `150` | 单圈剩余 `3` 到 `4` 个点时的扇形总角度 | +| `fanAngleForManyDeg` | `180` | 单圈剩余 `5` 个及以上点时的扇形总角度 | +| `ringGapPx` | `22` | 外圈最小增量半径 | +| `ringGapFactor` | `0.85` | 外圈相对基础半径的增量系数 | + +### 4.3 密度分档显示参数 + +这里的 `distance` 不是物理距离,而是点位密度分档值。 +数值越大表示越稀疏,越早参与显示候选;数值越小表示越密集,需要更高缩放级别才参与显示。 + +当前值如下: + +| `minDensityValue` | `minZoom` | 作用 | +|---:|---:|---| +| `1500000` | `0` | 很稀疏的点,从小缩放级别就可参与显示 | +| `800000` | `6.1` | 稍密集的点,从中低缩放开始参与显示 | +| `400000` | `8.1` | 中密度点,需要进一步放大 | +| `50000` | `10.6` | 高密度点,需要较高缩放级别 | +| `0` | `12.2` | 极密集点,只有更高缩放才进入候选 | + +## 5. 当前展开布局 + +展开阶段由 `point-layer-manager.ts` 控制。 + +### 5.1 布局特点 + +当前布局不是简单把点随机散开,而是按以下方式处理: + +- 主点保留原位置 +- 同组其他点围绕主点展开 +- 展开方向优先偏下方 +- 单圈数量由 `ringSize` 控制 +- 点数较多时进入第二圈 +- 第二圈半径按 `ringGapPx` 和 `ringGapFactor` 继续增大,避免继续叠在一起 + +### 5.2 为什么优先向下展开 + +当前优先向下展开,主要是为了: + +- 尽量给上方文字留空间 +- 降低文字压住上方点的概率 +- 让地图上的抽吸形态更稳定 + +## 6. 当前实现的几个关键约束 + +### 6.1 不使用淡入淡出动画 + +目前已移除点和文字的淡入淡出动画。 + +原因: + +- 抽吸状态切换和动画叠加时,容易让点和文字出现闪烁 +- 会干扰对“当前到底该不该显示”的判断 + +当前阶段优先保证: + +- 显示规则稳定 +- 点和文字状态一致 +- 放大缩小时不出现明显错位 + +### 6.2 不再依赖 OL 的自动 declutter 决定图标命运 + +当前图标和文字都设置为 `declutterMode: 'none'`,由项目内逻辑统一控制。 + +这样做的原因: + +- 避免图标和文字落在两套碰撞体系里 +- 避免出现“文字先出来、点没出来” +- 避免文字压住其他点却仍然显示 + +## 7. 常见现象与调参建议 + +### 7.1 成组太少 + +表现: + +- 相近点仍然容易互相盖住 +- 进入展开前看起来还是压在一起 + +优先调整: + +- 增大 `distanceThresholdMeters` + +### 7.2 成组太多 + +表现: + +- 距离并不算近的点也被当成一组 +- 放大后过早进入抽吸关系 + +优先调整: + +- 减小 `distanceThresholdMeters` + +### 7.3 展开太晚 + +表现: + +- 放大到较深层级前仍然挤在一起 + +优先调整: + +- 减小 `expandAtZoom` + +### 7.4 展开太早 + +表现: + +- 中等缩放时地图上就出现较明显散开效果 + +优先调整: + +- 增大 `expandAtZoom` + +### 7.5 展开后间距不够 + +表现: + +- 虽然已经展开,但图标还是比较挤 + +优先调整: + +- 增大 `expandOffsetPx` +- 或增大 `ringGapPx` +- 或增大 `ringGapFactor` + +### 7.6 单圈散开角度不合适 + +表现: + +- 次点虽然已经展开,但仍然集中在一侧 +- 或者扇形过大,展开形态显得太散 + +优先调整: + +- 调整 `fanAngleForTwoDeg` +- 调整 `fanAngleForFourDeg` +- 调整 `fanAngleForManyDeg` + +### 7.7 主点在放大过程中突然消失 + +当前已经通过 `replaceAtZoom <= zoom < expandAtZoom` 阶段显示 `priority <= 2` 进行修正。 +如果后续又出现类似现象,优先检查: + +- `map.ol.ts` 中 `shouldRenderNearbyFeature()` 的阶段逻辑 +- 是否误改成只显示 `priority = 2` + +### 7.8 明明周围看起来空,文字还是不显示 + +优先检查: + +- 图标碰撞盒是否过大 +- 文字碰撞盒是否过于保守 +- 候选集是否发生重复统计 + +相关代码主要在: + +- `src/components/gis/map.ol.ts` + +## 8. 后续维护建议 + +建议后续继续保持以下约定: + +1. 抽吸参数继续统一放在 `nearby-point-rules.ts` +2. 显示决策继续集中在 `map.ol.ts` +3. 几何偏移继续集中在 `point-layer-manager.ts` +4. 后续调参优先改 `DEFAULT_NEARBY_POINT_CONFIG`,不要直接把数值散落回业务代码 +5. 如果继续加动画,必须放在抽吸状态机完全稳定之后 +6. 如果继续优化 popup,也要同步遵循“点先于文字”的显示原则 + +## 9. 当前结论 + +当前这版抽吸实现已经形成了比较稳定的主线: + +- 自动识别近邻点 +- 统一缩放阶段显示规则 +- 展开阶段几何偏移 +- 文字依赖点显示 +- 文字避让图标与文字 + +后续如果继续调优,建议先从参数层开始,不要先动主逻辑结构。 diff --git a/frontend/docs/地图模块-详细说明.md b/frontend/docs/地图模块-详细说明.md index 0b98ad2e..b957f0bb 100644 --- a/frontend/docs/地图模块-详细说明.md +++ b/frontend/docs/地图模块-详细说明.md @@ -2,590 +2,580 @@ ## 1. 文档目的 -本文档用于梳理当前前端地图模块的整体结构、运行链路、核心文件职责、图层与点位渲染机制、图例与筛选联动方式,以及后台配置与前台运行时之间的关系。 +本文档用于说明当前地图模块的真实运行结构、初始化时序、图层与图例联动、点位渲染规则、筛选与缩放行为,以及近期已经落地的关键约束。 -本文档只描述当前地图模块整体实现,不包含抽吸和碰撞的专项分析。 -抽吸与碰撞问题单独整理在: +本文档描述的是“当前可运行版本”的现状,不展开抽吸参数细节与专项问题分析。相关补充文档如下: +- `docs/地图模块-抽吸规则与参数说明.md` - `docs/地图模块-OpenLayers抽吸与碰撞分析.md` ## 2. 当前技术栈 -当前地图模块涉及的核心技术如下: - - 前端框架:Vue 3 + TypeScript + Ant Design Vue - 状态管理:Pinia -- 2D 地图引擎:OpenLayers +- 2D 地图引擎:OpenLayers 10.8.0 - 3D 地图引擎:Cesium -- 地图服务:GeoServer -- 数据来源: - - 后端接口返回图层树配置 - - 后端接口返回图例配置 - - 后端接口返回各类锚点数据 - -项目依赖中当前地图引擎版本如下: - -- `ol@^10.8.0` -- `cesium@^1.141.0` -- `leaflet@^1.9.4` +- 地图服务:GeoServer / WMTS / XYZ +- 运行模式:后台配置驱动 + 前台运行时编排 说明: -- 当前 2D 主链路已经切换到 OpenLayers; -- Leaflet 依赖仍保留在项目中,但不是当前主运行路径。 +- 当前 2D 主链路已经完全围绕 OpenLayers 组织。 +- 项目中仍保留 Leaflet 相关依赖和旧代码,但不是当前主执行路径。 -## 3. 地图整体架构 +## 3. 模块分层 -当前地图模块可以分成 6 层: +当前地图模块可以按 6 层理解: 1. 页面入口层 2. 应用编排层 3. 地图能力门面层 -4. 地图引擎实现层 -5. 状态存储层 -6. 交互组件层 +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. 整体原则 -### 4.1 全局挂载位置 +当前地图模块遵循以下几个运行原则: -地图视图最终由主布局中的 `GisView` 常驻挂载,入口位置在: +### 4.1 地图容器全局常驻 -- [AppMain.vue](file:///d:/wordpack/WholeProcessPlatform/frontend/src/layout/components/AppMain.vue) +地图由 `GisView.vue` 常驻挂载,不会随着菜单切换被销毁重建。页面切换本质上是: -这意味着地图并不是某一个业务页单独创建,而是作为全局地图容器持续存在,然后随着菜单切换切换图层和页面配置。 +- 重新计算 `pageKey` +- 重新加载该页图层配置和图例配置 +- 用新的运行态覆盖旧页面显示内容 -### 4.2 `GisView.vue` 职责 +### 4.2 配置驱动 -文件: +前端不把全部图层和图例硬编码死,而是依赖后端返回的: -- [GisView.vue](file:///d:/wordpack/WholeProcessPlatform/frontend/src/components/gis/GisView.vue) +- 图层树配置 +- 图例配置 +- 页面级图例配置 +- 各业务点位接口数据 -当前职责主要有: +### 4.3 运行态绝对优先 -- 提供地图 DOM 容器 `#mapContainer` -- 挂载地图 popup 容器 -- 挂载地图图例、筛选器、控制器、底图切换器 -- 根据当前路由计算 `pageKey` -- 在组件挂载时触发地图初始化 -- 在页面切换时触发地图页面配置切换 -- 分发少量地图控制命令,例如 2D/3D 切换、梯级流域显示 +初始化默认值只在第一次派生时生效;一旦进入运行态,后续图层勾选、图例勾选、筛选器切换,都必须以当前用户操作后的状态为准,不能在加载完成后回退到默认状态。 -它已经不再承担大部分地图业务拼装逻辑,更多是地图页面入口和组件装配层。 +## 5. 页面入口层 -## 5. 应用编排层 +### 5.1 `GisView.vue` -文件: +`GisView.vue` 的职责主要是: -- [map-orchestrator.ts](file:///d:/wordpack/WholeProcessPlatform/frontend/src/modules/map/application/map-orchestrator.ts) +- 提供地图容器 `#mapContainer` +- 提供 popup 挂载容器 +- 挂载图例、筛选器、控制器、底图切换器 +- 根据路由计算 `pageKey` +- 在挂载时调用 `mapOrchestrator.mountView()` +- 在页面切换时交给编排器重载页面 -`map-orchestrator` 是当前地图运行时的调度中心,主要负责把页面、Store、地图实例串起来。 +当前页面层已经不再直接承载复杂业务逻辑,复杂链路都收敛到了编排器和 Store。 -核心职责包括: +## 6. 应用编排层 -- 初始化地图壳和 popup 容器 -- 根据 `pageKey` 加载当前页面地图配置 -- 拉取图层树和图例配置 -- 初始化基础底图 -- 触发点位数据加载 +### 6.1 `map-orchestrator.ts` 的职责 + +`map-orchestrator.ts` 是当前地图业务的总调度中心,主要负责: + +- 初始化地图壳与 popup +- 加载页面图层配置和图例配置 +- 初始化 GIS 基础图层 +- 触发点位图层加载 +- 管理缩放监听和基地切换监听 - 处理图层树勾选 -- 处理图例显隐 -- 处理基地切换 -- 处理时间筛选和重新加载 -- 处理搜索定位 -- 处理某些菜单下的缩放联动图层 +- 处理图例勾选 +- 处理时间筛选、容量筛选、搜索定位 +- 处理水电开发菜单下的缩放联动图层 -### 5.1 初始化主链路 +### 6.2 页面初始化链路 -大致流程如下: +当前初始化顺序如下: 1. `GisView.vue` 调用 `mapOrchestrator.mountView()` -2. 编排器初始化地图实例 -3. 挂载 popup 容器 -4. 加载当前页面的图层树、图例和页面图例 -5. 初始化基础底图 -6. 加载点位图层数据 -7. 建立缩放监听、基地监听和图例联动 +2. `MapClass.init()` 初始化地图实例 +3. 页面级 popup 容器挂到地图实例 +4. 绑定缩放监听和基地监听 +5. 并行请求图层树配置与图例配置 +6. 图例接口先返回时,立即生成图例运行态 +7. 图层树接口返回后,生成默认勾选图层并初始化 GIS 基础图层 +8. 再按图层配置批量加载点位数据 -### 5.2 页面切换 +这里有两个当前已落地的关键时序调整: -当路由变化后: +- 图例转圈只跟图例接口绑定,不再等待所有锚点接口完成。 +- 筛选器数据会随着已加载图层逐步出现,不再必须等全量点位接口结束。 -- `GisView.vue` 重新计算 `pageKey` -- 调用 `mapOrchestrator.handlePageChange()` -- 编排器重新加载该页面对应的地图配置和显示状态 +### 6.3 页面切换 -这使得地图容器本身不销毁,只是页面配置和显示内容发生变化。 +页面切换时地图不销毁,只重载当前页面的: -## 6. 地图能力门面层 +- 图层树配置 +- 图例配置 +- 点位数据 +- 当前页面的默认运行态 -文件: +如果仍处于同一个 `pageKey` 且用户之前修改过勾选态,会尽量复用当前运行态,而不是重新回放默认勾选。 -- [map.class.ts](file:///d:/wordpack/WholeProcessPlatform/frontend/src/components/gis/map.class.ts) +### 6.4 缩放联动 -`MapClass` 是地图能力统一门面,对外提供统一方法,屏蔽 2D 和 3D 的差异。 +当前编排层主要有两类缩放联动: -典型能力包括: +- `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()` -- `baseLayerSwitcher()` +- `hasLayer()` +- `hasBaseLayer()` +- `removePointLayer()` - `flyTopanto()` -- `zoomToggle()` -- `lengthCalculate()` -- `areCalculate()` -- `mapOutPut()` -- `destroy()` - `switchView()` -当前 2D 主实现是: +当前业务主执行层仍然是 `MapOl`。 -- `this.service = new MapOl()` +## 8. 地图引擎执行层 -说明当前前台主要还是 OpenLayers 在承担地图业务。 +### 8.1 OpenLayers 主执行层 -## 7. 地图引擎实现层 +`map.ol.ts` 负责 OpenLayers 地图的实际渲染与交互,是当前 2D 地图主执行文件。 -### 7.1 OpenLayers 主实现 +当前承担的核心能力包括: -文件: - -- [map.ol.ts](file:///d:/wordpack/WholeProcessPlatform/frontend/src/components/gis/map.ol.ts) - -这是当前地图模块最核心的执行层文件,承担了大量实际渲染与地图交互逻辑,包括: - -- OpenLayers 地图初始化 -- 视图和底图管理 -- 点图层管理 -- 点位样式生成 +- 地图实例初始化 +- 底图与 GIS 图层管理 +- 点位图层渲染 +- 图标与文字样式生成 - hover popup 与批量 popup -- 区域裁切 -- 基地过滤 -- 梯级流域图层 -- 测量、截图、定位 +- 基地范围裁切 +- 高缩放交互 +- 测量、截图、飞行定位等基础地图能力 -### 7.2 Cesium 实现 +### 8.2 Cesium 执行层 -文件: +`map.cesium.ts` 目前更多是保留 3D 入口和部分基础能力,复杂业务点位与碰撞规则并未与 OpenLayers 完全对齐。 -- [map.cesium.ts](file:///d:/wordpack/WholeProcessPlatform/frontend/src/components/gis/map.cesium.ts) +结论上,当前真实业务规则仍然以 OpenLayers 链路为准。 -当前 3D 能力存在,但相对 2D 来说并没有完全对齐。 -目前更像是保留了切换入口和部分基础能力,例如: +## 9. Store 分层 -- viewer 初始化 -- 底图加载 -- 定位与飞行 -- 部分截图能力 +### 9.1 `map-config.store.ts` -多数业务点位和复杂运行逻辑仍然主要围绕 OpenLayers 设计。 +负责配置态数据: -## 8. 点图层管理 +- 图层树配置 +- 图层配置索引 +- 全量原始图例配置 +- 图例索引 +- 页面级图例配置 +- 配置接口加载状态 -文件: +当前这里拆分出了两个加载态: -- [point-layer-manager.ts](file:///d:/wordpack/WholeProcessPlatform/frontend/src/components/gis/ol/point-layer-manager.ts) +- `configLoading` +- `legendLoading` -这个文件负责 OpenLayers 点图层的生命周期管理。 +其中 `legendLoading` 单独控制图例转圈。 -核心职责包括: +### 9.2 `map-data.store.ts` -- 按图层 key 创建 `VectorLayer` -- 给每个点图层维护独立的 `VectorSource` -- 把后端点位数据转为 `Feature` -- 建立图例字段索引 -- 控制整层显隐 -- 控制图例项对应点位显隐 -- 删除点图层 -- 获取当前可视范围内点位 +负责数据态: -### 8.1 当前图层组织方式 +- `pointData` +- `pointDataCache` +- `layerLoadState` +- 地图整体 `loading` -当前点位图层的组织方式是: +这里的关键设计是: -- 每个业务点图层对应一个 `VectorLayer` -- 每条后端点位数据被转换为一个 `Feature` -- Feature 上会额外挂载运行时字段,例如: - - `_iconUrl` - - `_labelText` - - `_legendVisible` - - `_regionVisible` - - `_layerKey` +- 每个点图层有独立缓存 +- `pointData` 是由缓存合并出来的运行态数据 +- 单个图层命中缓存或接口返回后,就会立即回填 `pointData` -### 8.2 图层显隐 +因此当前搜索筛选下拉已经支持“渐进可用”,不再只能等全部接口结束。 -图层显隐主要分三类: +### 9.3 `map-view.store.ts` -- 图层树控制整层显隐 -- 图例项控制某一类点位显隐 -- 基地裁切控制某些点位在当前基地范围外隐藏 +负责视图运行态: -这些状态最终会体现在 Feature 属性和图层可见性上。 +- 当前勾选图层 `checkedLayerKeys` +- 图例勾选状态 `legendCheckedState` +- 搜索时间范围 +- 当前基地 +- 当前缩放级别 -## 9. 点位样式与渲染 +### 9.4 `src/store/modules/map.ts` -点位样式主逻辑在: +这是当前地图运行逻辑最重的 Store,负责串联配置、缓存和地图实例。 -- [map.ol.ts](file:///d:/wordpack/WholeProcessPlatform/frontend/src/components/gis/map.ol.ts) +主要职责包括: -当前点位样式包含以下内容: +- 生成图例运行态 +- 批量加载点位数据 +- 控制图层显隐 +- 控制图例显隐 +- 管理请求缓存与并发加载 +- 刷新点图层显示数据 +- 处理 `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 基础样式 + +当前点位渲染包括: - 图标 - 文字标签 -- 字号随缩放动态变化 -- 图标大小随缩放动态变化 -- 图例显隐状态 -- 基地区域显隐状态 -- 按 `distance` 字段做缩放级别抽稀 +- 标签换行与截断 +- 缩放相关的图标与文字样式变化 -### 9.1 当前样式生成逻辑 +### 16.2 图标加载约束 -当前渲染时会综合判断: +当前已经补充图标加载状态缓存: -- 是否有图标 URL -- 图例是否可见 -- 区域是否可见 -- 是否满足当前缩放级别下的距离阈值 +- 图标未加载完成时,不显示该点 +- 图标未加载完成时,文字也不先显示 +- 图标未加载完成时,不参与碰撞候选 -满足后才会返回 `Style`。 +这样可以避免“文字先出来、图标还是空的”的问题。 -### 9.2 当前标签处理 +## 17. 抽吸、密度与碰撞 -当前标签会做以下处理: +### 17.1 专项文档 -- 去掉括号 -- 最多显示两行 -- 每行长度受限 -- 超长文本截断并加省略号 -- 根据单行或多行情况设置不同偏移 +抽吸与密度分档的详细参数请查看: -这部分属于当前地图的统一标签显示策略。 +- `docs/地图模块-抽吸规则与参数说明.md` -## 10. Popup 机制 +### 17.2 当前裁决顺序 -文件: +当前点位显示顺序可以理解为: -- [popup-manager.ts](file:///d:/wordpack/WholeProcessPlatform/frontend/src/components/gis/ol/popup-manager.ts) +1. 密度分档 +2. 近邻抽吸 +3. 图标碰撞 +4. 文字碰撞 -Popup 分为两类: +补充约束: -- hover 时显示的单点 popup -- 高缩放下批量显示的 popup +- 只有满足可见性条件的点,才能进入碰撞候选集 +- 被图例或缩放过滤掉的点,不能再去占用碰撞资格 +- 视图内无近邻的孤立点允许局部放行 -### 10.1 Hover Popup +### 17.3 高缩放特例 -基础 hover popup 由地图鼠标移动事件驱动: +当前在高缩放层级 `zoom >= 15` 时,行为与中低缩放不同: -- 检测当前 hover 的要素 -- 更新悬停状态 -- 在对应坐标显示 popup +- 只处理视口内点位 +- 点与文字不再做碰撞淘汰 +- 视口内符合基础显示条件的点和文字全部显示 +- 同时进入批量 popup 模式 -### 10.2 批量 Popup +这条规则的目标是: -在较高缩放级别下,会进入批量 popup 模式: +- 保证深度放大后信息完整可见 +- 避免高缩放下还因为碰撞把点或文字压掉 -- 获取当前视口内所有可见点位 -- 逐个测量 popup 尺寸 -- 做边界框碰撞判断 -- 只渲染不冲突的 popup +## 18. Popup 机制 -这个机制的主要目的是避免高缩放下 popup 过多时完全覆盖地图。 +### 18.1 两类 popup -## 11. 基础底图与 GIS 图层 +当前 popup 分成两类: -基础底图和 GIS 叠加图层相关能力主要集中在: +- hover popup +- batch popup -- `map.ol.ts` -- `mapurlManage.ts` -- `gisUtils.ts` +### 18.2 hover popup -### 11.1 `mapurlManage.ts` +鼠标悬停时由 `pointermove` 驱动,只在非 batch popup 模式下显示。 -文件: +### 18.3 batch popup -- [mapurlManage.ts](file:///d:/wordpack/WholeProcessPlatform/frontend/src/components/gis/mapurlManage.ts) +在 `zoom >= 15` 时进入批量 popup 模式: -主要维护: +- 只基于当前视口内点位 +- 拖动地图时持续刷新 +- 但通过 `requestAnimationFrame` 做节流 +- `moveend` 后立即再做一次强制刷新 -- GeoServer 服务地址 -- WMTS 配置 -- XYZ 配置 -- 矢量图层相关配置 -- 某些专题图层和图例显示参数 +当前这样做是为了兼顾两件事: -### 11.2 `gisUtils.ts` +- 保留“拖动时 popup 跟着更新”的原交互 +- 避免拖动过程中每个事件都重建整批 DOM -文件: +### 18.4 惯性平移已关闭 -- [gisUtils.ts](file:///d:/wordpack/WholeProcessPlatform/frontend/src/components/gis/gisUtils.ts) +当前地图拖动已经关闭 OpenLayers 默认惯性平移: -主要负责: +- 普通拖动仍然保留 +- 松手后不再继续滑动一小段 -- 图层树拍平 -- 地图配置补全 -- 底图配置转换 -- 部分标签/偏移相关工具逻辑 +这样可以减少高缩放 popup 场景下“松手还轻微位移”的观感问题。 -## 12. 图层树与图例 +## 19. 基地与区域过滤 -### 12.1 图层树 UI +基地切换是当前地图模块的关键能力之一,主要影响: -文件: +- 地图裁切范围 +- 当前基地相关点位的可见性 +- 部分专题图层显示 -- [LayerController.vue](file:///d:/wordpack/WholeProcessPlatform/frontend/src/components/mapController/LayerController.vue) +整体过程通常是: -主要职责: +1. 外部基地选择源变化 +2. 编排器接收到基地 ID +3. 地图实例切换基地范围 +4. 点位更新 `_regionVisible` +5. 样式函数按区域可见性决定是否显示 -- 展示右侧图层树 -- 响应勾选变化 -- 把勾选结果转发给编排器和 Store +## 20. 典型交互链路 -当前图层树里还包含若干业务互斥规则,例如: +### 20.1 图层树勾选 -- 视频站和 AI 视频站互斥 -- 环保设施和环保设施在建互斥 -- 珍稀鱼类和沿程鱼类互斥 - -### 12.2 图例 UI - -文件: - -- [mapLegend/index.vue](file:///d:/wordpack/WholeProcessPlatform/frontend/src/components/mapLegend/index.vue) - -主要职责: - -- 展示当前页面和当前已选图层对应的图例 -- 维护图例项勾选状态 -- 把图例点击行为分发给编排器 - -图例不是固定写死的,而是由后端返回配置和当前已选图层共同决定。 - -## 13. 地图筛选与控制器 - -### 13.1 `MapFilter` - -文件: - -- [mapFilter/index.vue](file:///d:/wordpack/WholeProcessPlatform/frontend/src/components/mapFilter/index.vue) - -当前承担的筛选功能包括: - -- 基地筛选 -- 时间筛选 -- 装机容量筛选 -- 关键字搜索 -- 个别专题下的额外筛选 - -### 13.2 `MapController` - -文件: - -- [mapController/index.vue](file:///d:/wordpack/WholeProcessPlatform/frontend/src/components/mapController/index.vue) - -当前承担的地图操作包括: - -- 放大缩小 -- 图层树显隐 -- 2D / 3D 切换 -- 量算 -- 截图 -- 梯级流域专题显示 - -### 13.3 `BaseLayerSwitcher` - -文件: - -- [BaseLayerSwitcher/index.vue](file:///d:/wordpack/WholeProcessPlatform/frontend/src/components/BaseLayerSwitcher/index.vue) - -用于切换: - -- 矢量底图 -- 地形底图 -- 影像底图 - -## 14. Store 分层 - -### 14.1 旧主 Store - -文件: - -- [map.ts](file:///d:/wordpack/WholeProcessPlatform/frontend/src/store/modules/map.ts) - -当前仍然承担大量地图运行态逻辑,例如: - -- 图层选中状态 -- 图例选中状态 -- 图层数据加载 -- 图例联动 -- 点位缓存 -- 图层更新 - -### 14.2 新拆分 Store - -文件: - -- [map-config.store.ts](file:///d:/wordpack/WholeProcessPlatform/frontend/src/modules/map/stores/map-config.store.ts) -- [map-data.store.ts](file:///d:/wordpack/WholeProcessPlatform/frontend/src/modules/map/stores/map-data.store.ts) -- [map-view.store.ts](file:///d:/wordpack/WholeProcessPlatform/frontend/src/modules/map/stores/map-view.store.ts) - -当前已经开始按职责拆分: - -- `map-config.store.ts` - - 维护图层树和图例配置 - -- `map-data.store.ts` - - 维护图层数据缓存和点位数据 - -- `map-view.store.ts` - - 维护视图相关运行态,例如选中图层、图例勾选、缩放级别、基地状态 - -这说明地图模块已经在往“编排层 + Store 分层 + 引擎执行层”方向演进。 - -## 15. 基地裁切与区域过滤 - -基地逻辑是当前地图模块里的关键能力之一。 - -入口主要在: - -- `GisView.vue` -- `map-orchestrator.ts` -- `map.ol.ts` - -整体过程大致如下: - -1. 选择基地 -2. 编排器接收基地变化 -3. 调用地图实例更新基地范围 -4. 请求或读取基地边界 GeoJSON -5. 对点位执行区域内外判断 -6. 更新 Feature 的 `_regionVisible` -7. 地图样式函数据此决定是否显示 - -除了点位控制外,基地切换还会影响底图裁切和专题图层显示。 - -## 16. 后台配置与前台运行时关系 - -地图模块不仅依赖前台代码,也强依赖后台配置。 - -### 16.1 后台管理入口 - -主要页面位于: - -- [views/system/map/index.vue](file:///d:/wordpack/WholeProcessPlatform/frontend/src/views/system/map/index.vue) -- [views/system/map/components/LayerManagement/index.vue](file:///d:/wordpack/WholeProcessPlatform/frontend/src/views/system/map/components/LayerManagement/index.vue) - -### 16.2 后台管理内容 - -后台可维护的内容主要包括: - -- 图层树结构 -- 图层是否启用 -- 图层接口地址 -- 图层基础参数 -- 图例元数据 - -### 16.3 前后台关系 - -运行时不是前端把所有图层写死,而是: - -- 后台维护元数据 -- 前端进入页面后加载配置 -- 再根据配置请求对应图层数据 -- 最后交给地图引擎渲染 - -因此地图模块本质上是“配置驱动 + 运行时渲染”的模式。 - -## 17. 当前调用链总结 - -### 17.1 页面初始化链路 - -整体调用链如下: - -1. `AppMain` 挂载 `GisView` -2. `GisView` 调用 `mapOrchestrator.mountView` -3. `mapOrchestrator` 调用 `MapClass.init` -4. `MapClass` 实际调用 `MapOl.init` -5. 编排器加载图层树和图例配置 -6. 编排器初始化底图 -7. 编排器加载点位数据 -8. `PointLayerManager` 创建点图层并写入 Feature -9. `MapOl` 通过样式函数完成渲染 - -### 17.2 图层勾选链路 - -整体调用链如下: - -1. 用户勾选 `LayerController` -2. 编排器接收图层选择结果 -3. Store 更新图层选中状态 +1. `LayerController` 触发勾选变化 +2. 编排器归一化图层 key +3. `map.ts` 更新运行态图层勾选 4. 地图实例更新图层显隐 5. 图例重新派生 -### 17.3 图例点击链路 +补充: -整体调用链如下: +- `GISMap` 勾选时,如果地图里没有该图层,会先补载,再显示 -1. 用户点击 `MapLegend` -2. 编排器接收图例切换 -3. Store 更新图例选中状态 -4. 地图实例更新图例对应点位显隐 +### 20.2 图例勾选 -### 17.4 筛选链路 +1. 图例组件触发点击 +2. 编排器转发图例切换 +3. `map.ts` 更新图例运行态 +4. 对应点位立即更新显隐 +5. 图例树同步更新灰态 -整体调用链如下: +### 20.3 筛选器操作 -1. 用户操作 `MapFilter` -2. 编排器接收搜索、时间、基地或容量变化 -3. Store 更新运行态 -4. 必要时删图层、清缓存、重新请求数据 -5. 地图引擎重新渲染 +1. 用户切换时间、容量、搜索等条件 +2. 编排器接收命令 +3. 视情况更新视图运行态或重载数据 +4. 地图实例与图例运行态同步刷新 -## 18. 当前模块特点 +### 20.4 缩放操作 -从现有实现看,地图模块有以下几个明显特点: +1. OpenLayers 视图触发 `change:resolution` +2. 编排器更新当前缩放级别 +3. 处理 `eng_point` 阈值联动 +4. 水电开发菜单下处理动态图层联动 +5. `map.ol.ts` 处理高缩放 popup 与点位显示策略 -- 地图容器是全局常驻的 -- 页面切换主要依赖 `pageKey` 重新编排 -- OpenLayers 是当前 2D 主引擎 -- 地图运行态是配置驱动的 -- 点位图层按业务图层分层组织 -- 图层树、图例、筛选、基地切换之间耦合较深 -- 编排层已经出现,但部分旧逻辑仍在 Store 和引擎层混合存在 - -## 19. 相关文件清单 - -地图模块当前重点文件如下: +## 21. 当前重点文件清单 - `src/components/gis/GisView.vue` - `src/components/gis/map.class.ts` @@ -605,18 +595,27 @@ Popup 分为两类: - `src/components/mapController/index.vue` - `src/components/mapController/LayerController.vue` - `src/components/BaseLayerSwitcher/index.vue` -- `src/views/system/map/index.vue` -- `src/views/system/map/components/LayerManagement/index.vue` -## 20. 结论 +## 22. 当前结论 -当前地图模块已经形成了比较清晰的主干结构: +当前地图模块已经形成比较清晰的主干结构: -- `GisView` 作为入口层 -- `map-orchestrator` 作为编排层 -- `MapClass` 作为统一门面 -- `MapOl` 作为 2D 主执行层 -- 多个 Store 共同维护配置、数据和视图状态 -- 图层树、图例、筛选器、底图切换器作为前台交互入口 +- `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 执行层”这条主干扩展,不要再把复杂业务回填到页面组件里。 diff --git a/frontend/src/App.vue b/frontend/src/App.vue index 01f126a5..36f4ab18 100644 --- a/frontend/src/App.vue +++ b/frontend/src/App.vue @@ -7,6 +7,10 @@ const appStore = useAppStore();