WholeProcessPlatform/frontend/docs/地图模块-抽吸规则与参数说明.md
2026-07-01 08:48:39 +08:00

317 lines
8.6 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 地图模块-抽吸规则与参数说明
## 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. 当前结论
当前这版抽吸实现已经形成了比较稳定的主线:
- 自动识别近邻点
- 统一缩放阶段显示规则
- 展开阶段几何偏移
- 文字依赖点显示
- 文字避让图标与文字
后续如果继续调优,建议先从参数层开始,不要先动主逻辑结构。