WholeProcessPlatform/frontend/docs/地图模块-抽吸规则与参数说明.md

317 lines
8.6 KiB
Markdown
Raw Normal View History

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