@3clear/basegis 0.1.3 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -5,29 +5,194 @@
5
5
  当前包包含:
6
6
 
7
7
  - `BaseGIS`:地图初始化、引擎切换、视角控制、底图切换、绘制、图层显隐、DEM、点击事件、Cesium / Leaflet 统一粒子风场、GPU 粒子风场、三维体渲染、三维切片/剖面渲染等基础能力。
8
- - `methods`:图片图层、网格图层、海量点、点位抽稀、等值线、等压线、风场、图形组等高级控制器。
8
+ - `methods`:独立线图层、图片图层、网格图层、海量点、点位聚合、点位抽稀、等值线、风场、图形组等高级控制器。
9
9
  - `layers`:天地图、GeoServer 金字塔瓦片、WMS、WMTS 图层配置快捷构造器。
10
10
  - `assets`:GIS 示例资源。
11
11
  - `style.css`:Leaflet、GIS 图层和标注相关基础样式。
12
12
 
13
13
  ## 能力总览
14
14
 
15
- 下表以当前 npm 包的真实出口和本项目源码为准。使用位置列展示原测试路由,点击后会在新标签页打开代码演练场,并通过 `path` 参数自动选中对应路由;没有独立页面的辅助函数与其所属控制器合并展示。
16
-
17
- | <small>导出 / 能力</small> | <small>功能</small> | <small>在本项目中的使用位置或路由</small> |
18
- | --- | --- | --- |
19
- | <small>[`BaseGIS`](#base-gis)</small> | <small>Cesium / Leaflet 统一入口,负责地图初始化、引擎切换、视角控制、场景模式、底图、DEM、绘制、点击事件,以及 GeoJSON、风场、三维体渲染和剖面渲染等能力。</small> | <small>基础能力:<a href="http://61.50.111.214:31166/lgmap/test-page-2" target="_blank" rel="noopener noreferrer">查看示例</a>、<a href="http://61.50.111.214:31166/lgmap/test-page-3" target="_blank" rel="noopener noreferrer">查看示例</a><br>专项能力:<a href="http://61.50.111.214:31166/lgmap/test-page-14" target="_blank" rel="noopener noreferrer">查看示例</a>、<a href="http://61.50.111.214:31166/lgmap/test-page-15" target="_blank" rel="noopener noreferrer">查看示例</a>、<a href="http://61.50.111.214:31166/lgmap/test-page-20" target="_blank" rel="noopener noreferrer">查看示例</a>、<a href="http://61.50.111.214:31166/lgmap/test-page-21" target="_blank" rel="noopener noreferrer">查看示例</a>、<a href="http://61.50.111.214:31166/lgmap/test-page-23" target="_blank" rel="noopener noreferrer">查看示例</a></small> |
20
- | <small>[`GraphicGroupController`](#graphic-group-controller)</small> | <small>统一装载和清理一组点、线、面、文字及 Marker 图形。</small> | <small><a href="http://61.50.111.214:31166/lgmap/test-page-2" target="_blank" rel="noopener noreferrer">查看示例</a>、<a href="http://61.50.111.214:31166/lgmap/test-page-3" target="_blank" rel="noopener noreferrer">查看示例</a></small> |
21
- | <small>[`ImageLayerController` / `toImageLayerArea`](#image-layer-controller)</small> | <small>加载普通图片、GeoTIFF、灰度图着色和多时次栅格,并提供范围参数转换。</small> | <small><a href="http://61.50.111.214:31166/lgmap/test-page-4" target="_blank" rel="noopener noreferrer">查看示例</a>、<a href="http://61.50.111.214:31166/lgmap/test-page-18" target="_blank" rel="noopener noreferrer">查看示例</a></small> |
22
- | <small>[`GridLayerController`](#grid-layer-controller)</small> | <small>加载灰度图或 GeoTIFF 数值网格,支持着色、探针、网格注记和生命周期控制。</small> | <small><a href="http://61.50.111.214:31166/lgmap/test-page-4" target="_blank" rel="noopener noreferrer">查看示例</a></small> |
23
- | <small>[`PointLargeLayerController`](#point-large-layer-controller)</small> | <small>面向海量点位的异步构建、样式规则、点击、高亮、删除和显隐控制。</small> | <small><a href="http://61.50.111.214:31166/lgmap/test-page-5" target="_blank" rel="noopener noreferrer">查看示例</a></small> |
24
- | <small>[`PointDensityController`](#point-density-controller)</small> | <small>点位视野裁剪和屏幕网格抽稀,支持动态图标、点击回调、配置更新和状态统计。</small> | <small><a href="http://61.50.111.214:31166/lgmap/test-page-8" target="_blank" rel="noopener noreferrer">查看示例</a>、<a href="http://61.50.111.214:31166/lgmap/test-page-9" target="_blank" rel="noopener noreferrer">查看示例</a>、<a href="http://61.50.111.214:31166/lgmap/test-page-13" target="_blank" rel="noopener noreferrer">查看示例</a></small> |
25
- | <small>[`PressureContourLayer` / `createPressureDataResolver` / `buildPressureRenderData`](#pressure-contour-layer)</small> | <small>解析气压数据并生成等值线、数值标签及高低压中心标注。</small> | <small><a href="http://61.50.111.214:31166/lgmap/test-page-7" target="_blank" rel="noopener noreferrer">查看示例</a></small> |
26
- | <small>[`ContourLayerController`](#contour-layer-controller)</small> | <small>统一管理等值线图层的加载、更新、显隐、引擎切换和销毁。</small> | <small><a href="http://61.50.111.214:31166/lgmap/test-page-18" target="_blank" rel="noopener noreferrer">查看示例</a></small> |
27
- | <small>[`RasterContourController`](#raster-contour-controller)</small> | <small>从 GeoTIFF、灰度图或数值网格提取并渲染等值线。</small> | <small><a href="http://61.50.111.214:31166/lgmap/test-page-18" target="_blank" rel="noopener noreferrer">查看示例</a></small> |
28
- | <small>[`WindFieldMethods`](#wind-field-methods)</small> | <small>提供 Cesium / Leaflet 风场数据加载、粒子动画、速度底图、交互和生命周期控制。</small> | <small><a href="http://61.50.111.214:31166/lgmap/test-page-2" target="_blank" rel="noopener noreferrer">查看示例</a>、<a href="http://61.50.111.214:31166/lgmap/test-page-3" target="_blank" rel="noopener noreferrer">查看示例</a></small> |
29
- | <small>[`createTiandituLayer` / `createGeoserverPyramidLayer` / `createWmsLayer` / `createWmtsLayer`](#layer-config-builders)</small> | <small>构造天地图、GeoServer 金字塔瓦片、WMS 和 WMTS 图层配置。</small> | <small><a href="http://61.50.111.214:31166/lgmap/test-page-2" target="_blank" rel="noopener noreferrer">查看示例</a>、<a href="http://61.50.111.214:31166/lgmap/test-page-3" target="_blank" rel="noopener noreferrer">查看示例</a></small> |
30
- | <small>[`gisMarkerSample`](#gis-marker-sample)</small> | <small>可直接导入的 GIS Marker 示例资源。</small> | <small><a href="http://61.50.111.214:31166/lgmap/test-page-2" target="_blank" rel="noopener noreferrer">查看示例</a>、<a href="http://61.50.111.214:31166/lgmap/test-page-3" target="_blank" rel="noopener noreferrer">查看示例</a></small> |
15
+ 以下按类型展示 `@3clear/basegis` 的主要业务能力;工具型辅助函数不单独作为能力卡展示。点击名称可跳转到下方详细说明,完整导入方式见[出口](#出口)。
16
+
17
+ ### Core 核心(1)
18
+
19
+ <table>
20
+ <tbody>
21
+ <tr>
22
+ <td>
23
+ <a href="#base-gis"><strong>BaseGIS</strong></a><br>
24
+ <small>Cesium / Leaflet 统一 GIS 主入口 · <a href="http://61.50.111.214:31166/lgmap/test-page-2" target="_blank" rel="noopener noreferrer">查看示例</a></small>
25
+ </td>
26
+ </tr>
27
+ </tbody>
28
+ </table>
29
+
30
+ ### Graphics 图形与点位(4)
31
+
32
+ <table>
33
+ <tbody>
34
+ <tr>
35
+ <td width="50%">
36
+ <a href="#graphic-group-controller"><strong>GraphicGroupController</strong></a><br>
37
+ <small>点、线、面、文字与 Marker 图形组 · <a href="http://61.50.111.214:31166/lgmap/test-page-2" target="_blank" rel="noopener noreferrer">查看示例</a></small>
38
+ </td>
39
+ <td width="50%">
40
+ <a href="#point-large-layer-controller"><strong>PointLargeLayerController</strong></a><br>
41
+ <small>海量点 · <a href="http://61.50.111.214:31166/lgmap/test-page-5" target="_blank" rel="noopener noreferrer">查看示例</a></small>
42
+ </td>
43
+ </tr>
44
+ <tr>
45
+ <td width="50%">
46
+ <a href="#point-cluster-controller"><strong>PointClusterController</strong></a><br>
47
+ <small>点位聚合 · <a href="http://61.50.111.214:31166/lgmap/test-page-29" target="_blank" rel="noopener noreferrer">查看示例</a></small>
48
+ </td>
49
+ <td width="50%">
50
+ <a href="#point-density-controller"><strong>PointDensityController</strong></a><br>
51
+ <small>点位视野裁剪抽稀 · <a href="http://61.50.111.214:31166/lgmap/test-page-8" target="_blank" rel="noopener noreferrer">查看示例</a></small>
52
+ </td>
53
+ </tr>
54
+ </tbody>
55
+ </table>
56
+
57
+ ### Line 线图层(1)
58
+
59
+ <table>
60
+ <tbody>
61
+ <tr>
62
+ <td>
63
+ <a href="#line-layer-controller"><strong>LineLayerController</strong></a><br>
64
+ <small>独立线图层、实线/虚线、固定/流动渐变与沿线动画 · <a href="http://61.50.111.214:31166/lgmap/test-page-34" target="_blank" rel="noopener noreferrer">查看示例</a></small><br>
65
+ <small>支持:一条或多条经纬度折线,可选图标引领的逐步出线</small>
66
+ </td>
67
+ </tr>
68
+ </tbody>
69
+ </table>
70
+
71
+ ### Image 图片图层(1)
72
+
73
+ <table>
74
+ <tbody>
75
+ <tr>
76
+ <td>
77
+ <a href="#image-layer-controller"><strong>ImageLayerController</strong></a><br>
78
+ <small>图片覆盖层与时次切换 · <a href="http://61.50.111.214:31166/lgmap/test-page-4" target="_blank" rel="noopener noreferrer">查看示例</a></small><br>
79
+ <small>支持:PNG / JPG / WebP 等浏览器图片、灰度图;可配套 GeoTIFF 取值</small>
80
+ </td>
81
+ </tr>
82
+ </tbody>
83
+ </table>
84
+
85
+ ### Grid 数值网格(1)
86
+
87
+ <table>
88
+ <tbody>
89
+ <tr>
90
+ <td>
91
+ <a href="#grid-layer-controller"><strong>GridLayerController</strong></a><br>
92
+ <small>栅格数值注记与鼠标探针 · <a href="http://61.50.111.214:31166/lgmap/test-page-4" target="_blank" rel="noopener noreferrer">查看示例</a></small><br>
93
+ <small>支持:GeoTIFF、灰度图、直接数值网格</small>
94
+ </td>
95
+ </tr>
96
+ </tbody>
97
+ </table>
98
+
99
+ ### Contour 通用等值线与中心标注(2)
100
+
101
+ <table>
102
+ <tbody>
103
+ <tr>
104
+ <td width="50%">
105
+ <a href="#contour-layer-controller"><strong>ContourLayerController</strong></a><br>
106
+ <small>已有等值线、线值标签与中心标注 · <a href="http://61.50.111.214:31166/lgmap/test-page-18" target="_blank" rel="noopener noreferrer">查看示例</a></small>
107
+ </td>
108
+ <td width="50%">
109
+ <a href="#raster-contour-controller"><strong>RasterContourController</strong></a><br>
110
+ <small>从栅格追线,可选自动检测 H/L 中心 · <a href="http://61.50.111.214:31166/lgmap/test-page-18" target="_blank" rel="noopener noreferrer">查看示例</a></small>
111
+ </td>
112
+ </tr>
113
+ </tbody>
114
+ </table>
115
+
116
+ ### Volume 三维体渲染(1)
117
+
118
+ <table>
119
+ <tbody>
120
+ <tr>
121
+ <td>
122
+ <a href="#volume-rendering"><strong>BaseGIS.upsertVolumeLayer</strong></a><br>
123
+ <small>Cesium 专有;三维标量场体积采样与裁切 · <a href="http://61.50.111.214:31166/lgmap/test-page-14" target="_blank" rel="noopener noreferrer">查看示例</a></small><br>
124
+ <small>支持:一维体数据 + rows / cols / heights 网格维度</small>
125
+ </td>
126
+ </tr>
127
+ </tbody>
128
+ </table>
129
+
130
+ ### Section 三维切片 / 剖面(1)
131
+
132
+ <table>
133
+ <tbody>
134
+ <tr>
135
+ <td>
136
+ <a href="#section-rendering"><strong>BaseGIS.upsertSectionLayer</strong></a><br>
137
+ <small>Cesium 专有;按经度、纬度、高度/气压层切片 · <a href="http://61.50.111.214:31166/lgmap/test-page-15" target="_blank" rel="noopener noreferrer">查看示例</a></small><br>
138
+ <small>支持:{ Bound, DataAry } 三维格点数据</small>
139
+ </td>
140
+ </tr>
141
+ </tbody>
142
+ </table>
143
+
144
+ ### Wind 风场(1)
145
+
146
+ <table>
147
+ <tbody>
148
+ <tr>
149
+ <td>
150
+ <a href="#wind-field-methods"><strong>WindFieldMethods</strong></a><br>
151
+ <small>Cesium / Leaflet 统一粒子风场 · <a href="http://61.50.111.214:31166/lgmap/test-page-21" target="_blank" rel="noopener noreferrer">查看示例</a></small>
152
+ </td>
153
+ </tr>
154
+ </tbody>
155
+ </table>
156
+
157
+ ### Layers 图层构造器(4)
158
+
159
+ <table>
160
+ <tbody>
161
+ <tr>
162
+ <td width="50%">
163
+ <a href="#layer-config-builders"><strong>createTiandituLayer</strong></a><br>
164
+ <small>天地图图层配置 · <a href="http://61.50.111.214:31166/lgmap/test-page-2" target="_blank" rel="noopener noreferrer">查看示例</a></small>
165
+ </td>
166
+ <td width="50%">
167
+ <a href="#layer-config-builders"><strong>createGeoserverPyramidLayer</strong></a><br>
168
+ <small>GeoServer 金字塔瓦片配置 · <a href="http://61.50.111.214:31166/lgmap/test-page-2" target="_blank" rel="noopener noreferrer">查看示例</a></small>
169
+ </td>
170
+ </tr>
171
+ <tr>
172
+ <td width="50%">
173
+ <a href="#layer-config-builders"><strong>createWmsLayer</strong></a><br>
174
+ <small>WMS 图层配置 · <a href="http://61.50.111.214:31166/lgmap/test-page-2" target="_blank" rel="noopener noreferrer">查看示例</a></small>
175
+ </td>
176
+ <td width="50%">
177
+ <a href="#layer-config-builders"><strong>createWmtsLayer</strong></a><br>
178
+ <small>WMTS 图层配置 · <a href="http://61.50.111.214:31166/lgmap/test-page-2" target="_blank" rel="noopener noreferrer">查看示例</a></small>
179
+ </td>
180
+ </tr>
181
+ </tbody>
182
+ </table>
183
+
184
+ ### Assets 示例资源(1)
185
+
186
+ <table>
187
+ <tbody>
188
+ <tr>
189
+ <td>
190
+ <a href="#gis-marker-sample"><strong>gisMarkerSample</strong></a><br>
191
+ <small>GIS Marker 示例资源 · <a href="http://61.50.111.214:31166/lgmap/test-page-2" target="_blank" rel="noopener noreferrer">查看示例</a></small>
192
+ </td>
193
+ </tr>
194
+ </tbody>
195
+ </table>
31
196
 
32
197
  ## 安装
33
198
 
@@ -55,15 +220,15 @@ import { BaseGIS } from '@3clear/basegis'
55
220
  // 高级能力控制器
56
221
  import {
57
222
  GraphicGroupController,
223
+ LineLayerController,
58
224
  ImageLayerController,
225
+ toImageLayerArea,
59
226
  GridLayerController,
60
227
  PointLargeLayerController,
228
+ PointClusterController,
61
229
  PointDensityController,
62
230
  ContourLayerController,
63
231
  RasterContourController,
64
- PressureContourLayer,
65
- createPressureDataResolver,
66
- buildPressureRenderData,
67
232
  WindFieldMethods,
68
233
  } from '@3clear/basegis/methods'
69
234
 
@@ -352,7 +517,7 @@ const mapCore = new BaseGIS({
352
517
 
353
518
  ## BaseGIS 基础能力
354
519
 
355
- 这一节列的是 `BaseGIS` 主入口直接提供的基础能力。业务页面优先调用这些方法;图片图层、网格图层、海量点、点位抽稀、等值线、风场等更复杂能力,建议使用后文 `methods` 中对应的 Controller。
520
+ 这一节列的是 `BaseGIS` 主入口直接提供的基础能力。业务页面优先调用这些方法;图片图层、网格图层、海量点、点位聚合、点位抽稀、等值线、风场等更复杂能力,建议使用后文 `methods` 中对应的 Controller。
356
521
 
357
522
  ### 1. 生命周期、实例与引擎切换
358
523
 
@@ -453,7 +618,7 @@ if (result.success) {
453
618
 
454
619
  引擎切换不是把 Cesium 图层对象“搬到” Leaflet,也不是把 Leaflet 图层对象“搬到” Cesium。BaseGIS 会保存托管图层的业务参数,并在新 adapter 中重新创建图层。
455
620
 
456
- - 自动恢复范围包括图片、网格、海量点、点位抽稀、等值线和三维体图层,对应 `upsert*Layer` 方法及 Controller。
621
+ - 自动恢复范围包括图片、网格、海量点、点位聚合、点位抽稀、独立线、等值线、统一风场和三维体图层,对应 `upsert*Layer` 方法及 Controller。
457
622
  - 图层最新的数据参数、显隐、清空、删除、海量点删除和高亮状态会同步到 BaseGIS 快照。
458
623
  - 快照只保存业务参数引用,不复制大数组,不保存任何底层引擎对象。
459
624
  - 三维体图层切到 Leaflet 时会返回不支持结果,但快照仍保留,切回 Cesium 后会继续恢复。
@@ -571,7 +736,7 @@ viewListener.data?.off?.()
571
736
 
572
737
  ### 4. 绘制点、线、面、文字和 Marker
573
738
 
574
- 这些方法用于轻量绘制和样例验证。大量点位或复杂业务图层请优先使用后文的 `PointLargeLayerController`、`PointDensityController`、`GraphicGroupController` 等控制器。
739
+ 这些方法用于轻量绘制和样例验证。大量点位或复杂业务图层请优先使用后文的 `PointLargeLayerController`、`PointClusterController`、`PointDensityController`、`GraphicGroupController` 等控制器。
575
740
 
576
741
  点:
577
742
 
@@ -767,7 +932,7 @@ Leaflet 当前返回坐标点击:
767
932
  说明:
768
933
 
769
934
  - 基础 `onClick` 适合地图空白点击、简单 Entity 点击。
770
- - 海量点、点位抽稀等图层自己的点击事件,应使用对应 Controller 的 `onClick` 参数。
935
+ - 海量点、点位聚合、点位抽稀等图层自己的点击事件,应使用对应 Controller 的点击回调参数。
771
936
 
772
937
 
773
938
  <a id="graphic-group-controller"></a>
@@ -809,12 +974,164 @@ graphics.clear()
809
974
  graphics.getState()
810
975
  ```
811
976
 
977
+ <a id="line-layer-controller"></a>
978
+
979
+ ## LineLayerController
980
+
981
+ 独立管理一组折线,支持整体更新、显隐、清空、销毁和引擎切换恢复。每条线必须提供唯一 `id` 和至少两个 `[longitude, latitude, height?]` 坐标点。第一版可以加载多条线,但同一控制器只播放一条线的动画。
982
+
983
+ ### 实线、虚线与纯色
984
+
985
+ ```js
986
+ import { LineLayerController } from '@3clear/basegis/methods'
987
+
988
+ const lineLayer = new LineLayerController({
989
+ mapCore,
990
+ layerId: 'flight-route',
991
+ style: {
992
+ color: '#00d8ff',
993
+ width: 4,
994
+ opacity: 0.9,
995
+ pattern: 'dashed', // solid | dashed
996
+ dashLength: 14,
997
+ gapLength: 8,
998
+ },
999
+ })
1000
+
1001
+ await lineLayer.load({
1002
+ lines: [{
1003
+ id: 'route-1',
1004
+ positions: [
1005
+ [116.4, 39.9],
1006
+ [117.8, 37.5],
1007
+ [121.5, 31.2],
1008
+ ],
1009
+ }],
1010
+ })
1011
+ ```
1012
+
1013
+ 单条线的 `style` 可以覆盖控制器的顶层默认样式。
1014
+
1015
+ ### 固定渐变与流动渐变
1016
+
1017
+ `style.color` 可以是 CSS 颜色字符串,也可以是渐变配置。`stops` 的 `offset` 按 `0~1` 升序排列;配置 `flow` 后渐变会沿线路循环流动。
1018
+
1019
+ ```js
1020
+ const gradientStyle = {
1021
+ width: 5,
1022
+ pattern: 'solid',
1023
+ color: {
1024
+ type: 'gradient',
1025
+ stops: [
1026
+ { offset: 0, color: '#00e5ff' },
1027
+ { offset: 0.5, color: '#2563eb' },
1028
+ { offset: 1, color: '#a855f7' },
1029
+ ],
1030
+ flow: {
1031
+ enabled: true,
1032
+ durationMs: 2400,
1033
+ direction: 'forward', // forward | reverse
1034
+ },
1035
+ },
1036
+ }
1037
+ ```
1038
+
1039
+ 渐变与虚线可以同时配置。Cesium 和 Leaflet 的底层绘制机制不同,虚线端点和颜色交界处可能有轻微视觉差异。
1040
+
1041
+ ### 飞机引领的逐步出线
1042
+
1043
+ 飞机不是单独的类,而是通用 `animation.icon` 配置。省略 `icon` 时只播放线路逐步出现。
1044
+
1045
+ ```js
1046
+ // BaseGIS 不内置飞机图片,替换成业务项目自己的资源地址。
1047
+ const planeIconUrl = '/your-app/plane.svg'
1048
+
1049
+ const flightLine = new LineLayerController({
1050
+ mapCore,
1051
+ layerId: 'flight-route',
1052
+ style: gradientStyle,
1053
+ animation: {
1054
+ enabled: true,
1055
+ lineId: 'route-1',
1056
+ mode: 'reveal',
1057
+ durationMs: 12000,
1058
+ autoplay: true,
1059
+ loop: true,
1060
+ icon: {
1061
+ url: planeIconUrl,
1062
+ size: [36, 36],
1063
+ rotateToPath: true,
1064
+ rotationOffsetDeg: 0,
1065
+ },
1066
+ },
1067
+ })
1068
+
1069
+ await flightLine.load({
1070
+ lines: [{
1071
+ id: 'route-1',
1072
+ positions: [
1073
+ [116.4, 39.9],
1074
+ [117.8, 37.5],
1075
+ [121.5, 31.2],
1076
+ ],
1077
+ }],
1078
+ })
1079
+
1080
+ flightLine.pauseAnimation()
1081
+ flightLine.playAnimation()
1082
+ flightLine.restartAnimation()
1083
+ ```
1084
+
1085
+ 动画按照各段实际地理距离插值。`hide()` 暂停帧更新并记录播放状态,`show()` 恢复隐藏前正在运行的动画;`clear()` 和 `destroy()` 会取消动画。切换引擎会恢复播放/暂停意图,但不会保存逐帧进度,动画从起点重新计算。
1086
+
1087
+ ### 参数
1088
+
1089
+ | 参数 | 默认值 | 说明 |
1090
+ | --- | --- | --- |
1091
+ | `layerId` | `line-default` | 独立线图层 id。 |
1092
+ | `visible` | `true` | 初始是否可见。 |
1093
+ | `style.color` | `#2f80ff` | 纯色字符串或渐变对象。 |
1094
+ | `style.width` / `style.opacity` | `3` / `1` | 线宽和透明度。 |
1095
+ | `style.pattern` | `solid` | `solid` 或 `dashed`。 |
1096
+ | `style.dashLength` / `gapLength` | `12` / `8` | 虚线实段和间隔长度。 |
1097
+ | `animation.enabled` | `false` | 是否启用逐步出线。 |
1098
+ | `animation.lineId` | 单线时自动选择 | 多条线启用动画时必填。 |
1099
+ | `animation.durationMs` | `10000` | 从起点到终点的时长。 |
1100
+ | `animation.autoplay` / `loop` | `true` / `false` | 自动播放与循环。 |
1101
+ | `animation.icon` | - | 可选的飞机、车辆或船舶图标配置。 |
1102
+
1103
+ ### 方法
1104
+
1105
+ | 方法 | 说明 |
1106
+ | --- | --- |
1107
+ | `mount(mapCore)` | 后挂载 BaseGIS。 |
1108
+ | `load(payload, options?)` / `update(payload)` | 加载或更新线、样式和动画。 |
1109
+ | `show()` / `hide()` / `toggle()` | 控制显隐。 |
1110
+ | `playAnimation()` / `pauseAnimation()` / `restartAnimation()` | 控制沿线动画。 |
1111
+ | `clear()` | 清空线和动画,保留控制器。 |
1112
+ | `refreshState()` / `getState()` | 获取线数量、点数和动画状态。 |
1113
+ | `destroy()` | 删除图层、动画和引擎恢复快照。 |
1114
+
1115
+ 页面卸载时先执行 `lineLayer.destroy()`,再执行 `mapCore.destroy()`。
1116
+
1117
+ 在线示例:[查看 LineLayerController 双引擎应用 Demo](http://61.50.111.214:31166/lgmap/test-page-34)。
1118
+
812
1119
  <a id="image-layer-controller"></a>
813
1120
 
814
1121
  ## ImageLayerController
815
1122
 
816
1123
  用于管理一个图片覆盖层。所有更新都走 `update(payload)`;页面有很多时次数据时,自己维护数据列表,然后把当前时次的数据传给 `update`。
817
1124
 
1125
+ ### 支持的数据格式
1126
+
1127
+ | 数据模式 | 核心字段 | 用途 |
1128
+ | --- | --- | --- |
1129
+ | 普通图片 | `imageUrl + area` | 浏览器可解码的图片,常用 PNG、JPG/JPEG、WebP;用作雷达、云图或已填色格点图覆盖层。 |
1130
+ | 灰度图 | `imageUrl + area + imageSourceType: 'grayscale' + colorize` | 把像素灰度映射成业务值,再按色带生成可见图片。 |
1131
+ | 图片 + GeoTIFF | `imageUrl + tifUrl + area` | 图片负责显示,GeoTIFF 为网格注记和鼠标探针提供数值。 |
1132
+
1133
+ `ImageLayerController` 不会把单独的 GeoTIFF 渲染成彩色图片底图。只有 TIF 数值数据时,优先使用 [`GridLayerController`](#grid-layer-controller);需要由栅格生成等值线时使用 [`RasterContourController`](#raster-contour-controller)。
1134
+
818
1135
  `toImageLayerArea()` 可以把经纬度数组、Leaflet Bounds 或常见范围对象统一转换成 `{ startLon, startLat, endLon, endLat }`:
819
1136
 
820
1137
  ```js
@@ -996,57 +1313,26 @@ await imageLayer.update({
996
1313
 
997
1314
  Leaflet 会对经度跨度达到 360° 的全球图片按当前视野自动补充相邻世界副本,全球 TIF / 灰度格点的注记和鼠标探针也会使用同一套经度循环,因此业务页面不需要手动创建 `±360°` 图片层。原始图片按 `0° ~ 360°` 排列时传 `isSplit: true`,适配层会在交换左右半幅的同时把显示范围统一为 `-180° ~ 180°`,确保图片与格点值落在同一经度位置。
998
1315
 
999
- `loadGrayImage` 的灰度值换算规则:
1316
+ ### 4. 仅 TIF 数值层
1000
1317
 
1001
- ```js
1002
- 业务值 = (灰度值 - grayMinValue) / (grayMaxValue - grayMinValue) * (maxValue - minValue) + minValue
1003
- ```
1004
-
1005
- 所以灰度图要表达真实业务值时,建议显式传 `minValue / maxValue`。如果只写 `colorize: true`,会使用默认范围 `minValue: 0`、`maxValue: 1`、`grayMinValue: 1`、`grayMaxValue: 254`,只适合临时预览,不适合正式业务图层。
1006
-
1007
- `loadGrayImage` 支持两种写法:
1008
-
1009
- ```js
1010
- await gridLayer.loadGrayImage({
1011
- imageUrl: '/data/grid/temp-gray.png',
1012
- area,
1013
- colorize: {
1014
- minValue: -20,
1015
- maxValue: 50,
1016
- colors: ['#2639a7', '#2faaf3', '#8ee5b2', '#fd9919', '#fb422d'],
1017
- },
1018
- })
1019
-
1020
- await gridLayer.loadGrayImage({
1021
- imageUrl: '/data/grid/temp-gray.png',
1022
- area,
1023
- minValue: -20,
1024
- maxValue: 50,
1025
- grayMinValue: 1,
1026
- grayMaxValue: 254,
1027
- colors: ['#2639a7', '#2faaf3', '#8ee5b2', '#fd9919', '#fb422d'],
1028
- })
1029
- ```
1030
- ### 4. 纯 TIF
1031
-
1032
- 只传 TIF,不传图片。适合数据本身带地理范围、需要按 TIF 渲染的场景。
1318
+ 只传 TIF 时不会生成彩色图片底图,仅能使用 TIF 数值显示网格注记或鼠标探针。这种场景更推荐直接使用 `GridLayerController`。
1033
1319
 
1034
1320
  ```js
1035
1321
  await imageLayer.update({
1036
1322
  // 选填:当前数据 id。
1037
1323
  id: 'rain-tif',
1038
1324
 
1039
- // 必填建议:纯 TIF 模式下显式清空 imageUrl,避免沿用上一次图片。
1325
+ // 必填建议:仅 TIF 模式下显式清空 imageUrl,避免沿用上一次图片。
1040
1326
  imageUrl: '',
1041
1327
 
1042
1328
  // 必填:TIF 地址。
1043
1329
  tifUrl: '/data/rain.tif',
1044
1330
 
1045
- // 选填:是否按默认色带着色。需要更精细控制时传 colorize 对象。
1046
- colorize: true,
1047
-
1048
1331
  // 选填:是否开启鼠标探针。
1049
1332
  showProbe: true,
1333
+
1334
+ // 选填:是否显示网格数值注记。
1335
+ showLabel: true,
1050
1336
  })
1051
1337
  ```
1052
1338
 
@@ -1138,7 +1424,7 @@ imageLayer.destroy({ layerId: 'radar-image' })
1138
1424
  | 方法 | 参数 | 返回值 | 说明 |
1139
1425
  | --- | --- | --- | --- |
1140
1426
  | `mount(target)` | `BaseGIS` 实例 | `Result` | 绑定 `BaseGIS`。构造时已传 `mapCore/baseGIS` 时通常不需要手动调用。 |
1141
- | `update(payload)` | 图片图层数据 | `Promise<Result>` | 推荐主入口。创建或更新当前图片图层,支持普通图片、图片+TIF、灰度图+色带、纯 TIF |
1427
+ | `update(payload)` | 图片图层数据 | `Promise<Result>` | 推荐主入口。创建或更新普通图片、灰度图或图片 + TIF;仅 TIF 时只有数值注记/探针。 |
1142
1428
  | `show(payload)` | 可选 `layerId` 或 `{ layerId }` | `Result` | 显示图片图层。成功后控制器 `visible` 变为 `true`。 |
1143
1429
  | `hide(payload)` | 可选 `layerId` 或 `{ layerId }` | `Result` | 隐藏图片图层。成功后控制器 `visible` 变为 `false`。 |
1144
1430
  | `destroy(payload)` | 可选 `layerId` 或 `{ layerId }` | `Result` | 移除图片图层,并清空 `items / activeIndex / layerType / currentPayload`。如果地图已销毁,只清本地状态。 |
@@ -1179,19 +1465,19 @@ imageLayer.destroy({ layerId: 'radar-image' })
1179
1465
  | `defaultArea` | 选填 | 默认图片范围,`update` 未传 `area` 时使用。 |
1180
1466
  | `id` | 选填 | 当前数据 id,便于状态记录。 |
1181
1467
  | `name` | 选填 | 当前数据名称,便于页面展示。 |
1182
- | `imageUrl` | 普通图片、灰度图、图片+TIF 必填 | 图片地址。纯 TIF 模式建议传空字符串清掉旧图片。 |
1183
- | `tifUrl` | TIF、图片+TIF 必填 | GeoTIFF 地址,用于渲染、探针或网格注记。 |
1468
+ | `imageUrl` | 普通图片、灰度图、图片+TIF 必填 | 图片地址。仅 TIF 模式建议传空字符串清掉旧图片。 |
1469
+ | `tifUrl` | TIF、图片+TIF 必填 | GeoTIFF 数值地址,用于鼠标探针或网格注记,不会单独生成彩色图片底图。 |
1184
1470
  | `area` | 传 `imageUrl` 时必填 | 图片范围:`startLon / startLat / endLon / endLat`。 |
1185
1471
  | `imageSourceType` | 灰度图必填,其他选填 | `color` 表示已填色图片;`grayscale` 表示灰度图。 |
1186
- | `colorize` | 灰度图必填,TIF 着色选填 | 色带配置,或传 `true` 使用默认着色。 |
1472
+ | `colorize` | 灰度图必填 | 灰度图业务值和色带配置。 |
1187
1473
  | `colorize.minValue` | 灰度图必填 | 色带映射最小值。 |
1188
1474
  | `colorize.maxValue` | 灰度图必填 | 色带映射最大值。 |
1189
1475
  | `colorize.noDataValue` | 选填 | 无效值。 |
1190
1476
  | `colorize.colors` | 灰度图必填 | 色带颜色数组。 |
1191
1477
  | `opacity` | 选填 | 透明度,通常 0 - 1。 |
1192
1478
  | `visible` | 选填 | 是否显示图层。 |
1193
- | `showProbe` | 选填 | 是否开启鼠标探针,通常依赖 `tifUrl`。 |
1194
- | `showLabel` | 选填 | 是否显示网格注记,通常依赖 `tifUrl`。 |
1479
+ | `showProbe` | 选填 | 是否开启鼠标探针,需要 `tifUrl` 或灰度图数值。 |
1480
+ | `showLabel` | 选填 | 是否显示网格注记,需要 `tifUrl` 或灰度图数值。 |
1195
1481
  | `decimalPlaces` | 选填 | 探针或注记数值小数位。 |
1196
1482
  | `isSplit` | 选填 | 是否切片处理大图。 |
1197
1483
  | `gridTotal` | 选填 | 切片网格数量。 |
@@ -1207,7 +1493,15 @@ imageLayer.destroy({ layerId: 'radar-image' })
1207
1493
 
1208
1494
  ## GridLayerController
1209
1495
 
1210
- 用于 TIF 网格、灰度图网格、外部数值网格。
1496
+ 用于 GeoTIFF、灰度图和外部数值网格的采样、数值注记和鼠标探针。它不绘制彩色栅格底图;`showLabel` 和 `showProbe` 都为 `false` 时,数据会被读取,但地图上没有可见内容。
1497
+
1498
+ ### 支持的数据格式
1499
+
1500
+ | 数据模式 | 核心字段 | 数据契约 |
1501
+ | --- | --- | --- |
1502
+ | GeoTIFF | `tifUrl` | `.tif/.tiff` 地址;读取第一个栅格波段及文件地理范围。 |
1503
+ | 灰度图 | `imageUrl/grayImageUrl + area` | 浏览器可解码的灰度图;通过 `grayMinValue/grayMaxValue/minValue/maxValue/noDataValue` 换算业务值。 |
1504
+ | 直接数值网格 | `imageGridData` | `{ values, width, height, area }` 或 `{ values, width, height, bbox }`;`values` 必须是长度不小于 `width * height` 的一维数组或 TypedArray。 |
1211
1505
 
1212
1506
  ```js
1213
1507
  import { GridLayerController } from '@3clear/basegis/methods'
@@ -1222,7 +1516,6 @@ const gridLayer = new GridLayerController({
1222
1516
 
1223
1517
  await gridLayer.loadTif({
1224
1518
  tifUrl: '/data/grid/temp.tif',
1225
- colorize: true,
1226
1519
  })
1227
1520
 
1228
1521
  await gridLayer.loadGrayImage({
@@ -1233,7 +1526,7 @@ await gridLayer.loadGrayImage({
1233
1526
  endLon: 135,
1234
1527
  endLat: 54,
1235
1528
  },
1236
- // 灰度图需要把灰度值映射成业务值,再按业务值找色带。
1529
+ // 灰度图需要把灰度值映射成业务值。
1237
1530
  colorize: {
1238
1531
  // 必填建议:业务值最小值。
1239
1532
  minValue: -20,
@@ -1249,24 +1542,34 @@ await gridLayer.loadGrayImage({
1249
1542
  })
1250
1543
 
1251
1544
  await gridLayer.loadData({
1252
- imageGridData: [
1253
- [12.1, 13.4],
1254
- [14.2, 15.6],
1255
- ],
1256
- area: {
1257
- startLon: 100,
1258
- startLat: 30,
1259
- endLon: 110,
1260
- endLat: 40,
1545
+ imageGridData: {
1546
+ values: [12.1, 13.4, 14.2, 15.6],
1547
+ width: 2,
1548
+ height: 2,
1549
+ area: {
1550
+ startLon: 100,
1551
+ startLat: 30,
1552
+ endLon: 110,
1553
+ endLat: 40,
1554
+ },
1261
1555
  },
1262
1556
  })
1263
1557
 
1264
- gridLayer.update({ opacity: 0.7 })
1558
+ gridLayer.update({ decimalPlaces: 2 })
1265
1559
  gridLayer.hide()
1266
1560
  gridLayer.show()
1267
1561
  gridLayer.destroy()
1268
1562
  ```
1269
1563
 
1564
+ 灰度值换算规则:
1565
+
1566
+ ```text
1567
+ 业务值 = (灰度值 - grayMinValue) / (grayMaxValue - grayMinValue)
1568
+ * (maxValue - minValue) + minValue
1569
+ ```
1570
+
1571
+ 灰度图要表达真实业务值时,应显式传入 `minValue / maxValue`。数值图层不使用色带绘制背景;如果需要同时显示彩色图片,请使用 `ImageLayerController`。
1572
+
1270
1573
  ## 统一粒子风场
1271
1574
 
1272
1575
  同一组 API 会根据当前引擎自动选择渲染器:Cesium 使用 GPU 粒子风场,Leaflet 使用迁自 one-map 的 Canvas 粒子风场。
@@ -1437,6 +1740,8 @@ mapCore.removeGpuWindLayer({ layerId: 'surface-gpu-wind' })
1437
1740
 
1438
1741
  GPU 专用 API 不属于跨引擎自动恢复图层。切换 Cesium/Leaflet 后,业务应重新调用 `upsertGpuWindLayer`;需要自动恢复时改用 `upsertWindLayer`。核心渲染流程改编自 [RaymanNg/3D-Wind-Field](https://github.com/RaymanNg/3D-Wind-Field),遵循源码目录内 `LICENSE-RaymanNg.txt` 的 MIT License。
1439
1742
 
1743
+ <a id="volume-rendering"></a>
1744
+
1440
1745
  ## 三维体渲染
1441
1746
 
1442
1747
  三维体渲染是 Cesium 专有能力,直接通过 `BaseGIS` 调用。Leaflet 调用时会返回不支持结果,不会抛出破坏页面的异常。
@@ -1563,6 +1868,8 @@ console.log(stateResult.data)
1563
1868
  | `geometry` / `dim` | 选填 | 自定义体渲染几何或维度,普通业务通常不需要传。 |
1564
1869
  | `visible` | 选填 | 初始是否显示,默认显示。 |
1565
1870
 
1871
+ <a id="section-rendering"></a>
1872
+
1566
1873
  ## 三维切片 / 剖面渲染
1567
1874
 
1568
1875
  三维切片/剖面渲染也是 Cesium 专有能力,直接通过 `BaseGIS` 调用。它把三维网格数据按 X、Y、Z 三个方向切出剖面,适合气象温度、湿度、风场标量、污染物浓度等三维格点数据查看。
@@ -2109,6 +2416,313 @@ console.log(state)
2109
2416
  ```
2110
2417
 
2111
2418
 
2419
+ <a id="point-cluster-controller"></a>
2420
+
2421
+ ## PointClusterController 点位聚合
2422
+
2423
+ ### 能力介绍
2424
+
2425
+ 用于点位聚合。地图移动、缩放或数据更新后,会把当前视野内落入同一屏幕网格的邻近点合成一个带数量的聚合圆;放大后,聚合圆会继续拆分为更小的聚合组或独立点。
2426
+
2427
+ Cesium / Leaflet 使用相同的点位解析、屏幕网格和状态字段。页面只创建 `BaseGIS` 与 `PointClusterController`,不需要判断当前引擎。
2428
+
2429
+ 一次聚合过程会:
2430
+
2431
+ 1. 根据当前地图视野筛选可见点位。
2432
+ 2. 把经纬度投影到屏幕坐标,并按 `pixelRange` 划分网格。
2433
+ 3. 网格内点数达到 `minimumClusterSize` 时渲染聚合圆,否则渲染独立点。
2434
+ 4. 在地图移动、缩放或数据更新后重新计算,并通过 `onStateChange` 返回最新统计。
2435
+
2436
+ 聚合只改变当前视野的渲染方式,不修改传入的原始点位数据。它适合站点、设备、告警等密集点位;如果需要显示全部点位或只保留代表点,应分别使用 `PointLargeLayerController` 或 `PointDensityController`。
2437
+
2438
+ 它和另外两种点位能力的区别:
2439
+
2440
+ - `PointLargeLayerController`:尽量显示全部有效点位。
2441
+ - `PointClusterController`:邻近点合成一个带数量的聚合圆,可点击继续展开。
2442
+ - `PointDensityController`:邻近点只保留一个代表点,不显示合计数量。
2443
+
2444
+ ### Demo 位置
2445
+
2446
+ - 路由:`/test-page-29`
2447
+ - 页面:`src/views/test-page-29/index.vue`
2448
+ - 数据量:默认生成 10,000 个点位。
2449
+ - 覆盖能力:Cesium / Leaflet 切换、聚合参数更新、数据更新、聚合点击放大、单点点击、显隐、清空、删除和状态读取。
2450
+
2451
+ ### Vue 页面完整用法
2452
+
2453
+ ```vue
2454
+ <template>
2455
+ <div id="station-cluster-map" class="station-cluster-map"></div>
2456
+ </template>
2457
+
2458
+ <script setup>
2459
+ import { onBeforeUnmount, onMounted } from 'vue'
2460
+ import { BaseGIS } from '@3clear/basegis'
2461
+ import { PointClusterController } from '@3clear/basegis/methods'
2462
+ import '@3clear/basegis/style.css'
2463
+
2464
+ let mapCore = null
2465
+ let stationCluster = null
2466
+
2467
+ const points = [
2468
+ { id: 'A001', name: '站点 A', position: [121.4700, 31.2300] },
2469
+ { id: 'A002', name: '站点 B', position: [121.4705, 31.2304] },
2470
+ { id: 'A003', name: '站点 C', position: [121.4710, 31.2308] },
2471
+ ]
2472
+
2473
+ onMounted(async () => {
2474
+ mapCore = new BaseGIS({
2475
+ engineType: 'cesium',
2476
+ containerId: 'station-cluster-map',
2477
+ config: {
2478
+ view: {
2479
+ initialView: {
2480
+ center: [121.4737, 31.2304],
2481
+ height: 420000,
2482
+ zoom: 8,
2483
+ pitch: -90,
2484
+ },
2485
+ },
2486
+ },
2487
+ })
2488
+
2489
+ const initResult = mapCore.init()
2490
+ if (!initResult.success) {
2491
+ console.warn(initResult.message)
2492
+ return
2493
+ }
2494
+
2495
+ stationCluster = new PointClusterController({
2496
+ mapCore,
2497
+ layerId: 'station-cluster',
2498
+
2499
+ // 聚合网格大小,单位屏幕像素。值越大,点越容易聚在一起。
2500
+ pixelRange: 72,
2501
+
2502
+ // 同一网格至少有 3 个点时才显示聚合圆。
2503
+ minimumClusterSize: 3,
2504
+
2505
+ pointColor: '#36cfc9',
2506
+ pointOutlineColor: '#e6fffb',
2507
+ pointSize: 14,
2508
+ clusterColor: '#1677ff',
2509
+ clusterTextColor: '#ffffff',
2510
+ clusterSize: 42,
2511
+
2512
+ // 默认 true。点击聚合圆后,当前引擎会自动向聚合中心放大。
2513
+ zoomOnClusterClick: true,
2514
+
2515
+ onClick(point) {
2516
+ console.log('点击单点:', point)
2517
+ },
2518
+
2519
+ onClusterClick(cluster) {
2520
+ console.log(`点击了包含 ${cluster.count} 个点的聚合圆`)
2521
+ console.log(cluster.center, cluster.ids, cluster.points)
2522
+ },
2523
+
2524
+ onStateChange(state) {
2525
+ console.log('源点、聚合组、渲染对象:', {
2526
+ sourceCount: state.sourceCount,
2527
+ clusterCount: state.clusterCount,
2528
+ renderedCount: state.renderedCount,
2529
+ })
2530
+ },
2531
+ })
2532
+
2533
+ const loadResult = await stationCluster.load({
2534
+ points,
2535
+ visible: true,
2536
+ })
2537
+ if (!loadResult.success) {
2538
+ console.warn(loadResult.message)
2539
+ }
2540
+ })
2541
+
2542
+ onBeforeUnmount(() => {
2543
+ stationCluster?.destroy()
2544
+ stationCluster = null
2545
+ mapCore?.destroy()
2546
+ mapCore = null
2547
+ })
2548
+ </script>
2549
+
2550
+ <style scoped lang="scss">
2551
+ .station-cluster-map {
2552
+ width: 100%;
2553
+ height: 100%;
2554
+ }
2555
+ </style>
2556
+ ```
2557
+
2558
+ `load` 也支持直接传数组或 GeoJSON FeatureCollection:
2559
+
2560
+ ```js
2561
+ await stationCluster.load(points)
2562
+ await stationCluster.load(featureCollection)
2563
+ ```
2564
+
2565
+ 点位既可以使用 `position: [经度, 纬度, 高度]`、`coordinates` 或直接坐标数组,也可以使用以下默认字段:
2566
+
2567
+ - 经度:`longitude / lon / lng / x`
2568
+ - 纬度:`latitude / lat / y`
2569
+ - 高度:`height / altitude / z`
2570
+ - 唯一值:默认 `id`,可通过 `idKey` 指定
2571
+
2572
+ ### 更新聚合参数与数据
2573
+
2574
+ ```js
2575
+ // 让点位更容易形成聚合。
2576
+ await stationCluster.setConfig({
2577
+ pixelRange: 96,
2578
+ minimumClusterSize: 2,
2579
+ })
2580
+
2581
+ // 替换数据,保留图层和其他配置。
2582
+ await stationCluster.update({
2583
+ points: nextPoints,
2584
+ })
2585
+ ```
2586
+
2587
+ `clusterRadius` 是 `pixelRange` 的别名。两者同时传入时,以 `pixelRange` 为准。
2588
+
2589
+ ### 切换 Cesium / Leaflet
2590
+
2591
+ 聚合图层由 `BaseGIS` 托管。切换引擎时直接调用 `setEngine()`,无需在页面里重建 Cesium / Leaflet 分支;切换成功后,现有聚合数据和配置会通过托管快照自动恢复。
2592
+
2593
+ ```js
2594
+ const result = await mapCore.setEngine('leaflet')
2595
+ if (!result.success) {
2596
+ console.warn(result.message)
2597
+ }
2598
+ ```
2599
+
2600
+ ### 点击回调
2601
+
2602
+ 单点点击的第一个参数是原始点位数据:
2603
+
2604
+ ```js
2605
+ onClick(point, engineObject, event) {
2606
+ console.log(point.id)
2607
+ }
2608
+ ```
2609
+
2610
+ 聚合点击的第一个参数结构如下:
2611
+
2612
+ ```js
2613
+ {
2614
+ layerId: 'station-cluster',
2615
+ key: 'cluster:12:8',
2616
+ count: 36,
2617
+ center: [121.48, 31.23, 0],
2618
+ ids: ['A001', 'A002'],
2619
+ points: [/* 原始点位数据 */],
2620
+ }
2621
+ ```
2622
+
2623
+ `engineObject` 和 `event` 是当前引擎的拾取对象与事件,仅在确实需要底层信息时使用。通用业务逻辑应优先只读取第一个参数。
2624
+
2625
+ ### 显隐、清空和销毁
2626
+
2627
+ ```js
2628
+ stationCluster.hide()
2629
+ stationCluster.show()
2630
+ stationCluster.toggle()
2631
+ stationCluster.toggle(true)
2632
+ stationCluster.refreshState()
2633
+
2634
+ // 清空数据但保留图层实例,后续仍可 update/load。
2635
+ stationCluster.clear()
2636
+
2637
+ // 删除图层并释放监听与渲染资源。
2638
+ stationCluster.destroy()
2639
+ ```
2640
+
2641
+ | 方法 | 说明 |
2642
+ | --- | --- |
2643
+ | `mount(mapCore)` | 挂载 `BaseGIS`。构造时已传 `mapCore/baseGIS` 时无需重复调用。 |
2644
+ | `load(payload, options)` | 创建或覆盖聚合点数据,支持数组、FeatureCollection 或 `{ points }`。 |
2645
+ | `upsert(payload, options)` | `load` 的别名。 |
2646
+ | `update(payload)` | 合并现有配置,更新数据、样式或聚合参数。 |
2647
+ | `setConfig(payload)` | `update` 的别名,适合只表达参数更新。 |
2648
+ | `show()` / `hide()` / `toggle()` | 控制图层显隐。 |
2649
+ | `clear()` | 清空点位,保留图层实例。 |
2650
+ | `refreshState()` | 从当前引擎重新读取状态。 |
2651
+ | `destroy()` / `removeLayer()` | 删除图层并释放资源。 |
2652
+ | `getState()` | 获取控制器与引擎侧聚合状态。 |
2653
+
2654
+ ### 参数总表
2655
+
2656
+ | 参数 | 是否必填 | 默认值 | 说明 |
2657
+ | --- | --- | --- | --- |
2658
+ | `mapCore` / `baseGIS` | 构造时建议必填 | - | `BaseGIS` 实例。 |
2659
+ | `layerId` / `pointClusterLayerId` / `clusterLayerId` / `id` | 否 | `point-cluster-default` | 聚合图层 ID。 |
2660
+ | `points` / `data` / `items` | 首次加载必填其一 | - | 点位数组或 GeoJSON FeatureCollection。 |
2661
+ | `idKey` | 否 | `id` | 点位唯一值字段。 |
2662
+ | `longitudeKeys` / `latitudeKeys` / `heightKeys` | 否 | 内置常用字段 | 自定义坐标字段候选名。 |
2663
+ | `visible` | 否 | `true` | 初始是否显示。 |
2664
+ | `pixelRange` / `clusterRadius` | 否 | `64` | 屏幕聚合网格大小,单位像素。 |
2665
+ | `minimumClusterSize` | 否 | `2` | 形成聚合圆所需的最少点数,最小为 2。 |
2666
+ | `pointSize` | 否 | Cesium `16` / Leaflet `14` | 未传图片时的圆点尺寸。 |
2667
+ | `pointWidth` / `pointHeight` | 否 | `pointSize` | 单点图片显示尺寸。 |
2668
+ | `pointColor` | 否 | `#3aa7ff` | 默认单点填充色。 |
2669
+ | `pointOutlineColor` / `pointOutlineWidth` | 否 | 白色 / `2` | 默认单点描边。 |
2670
+ | `image` / `pointImage` / `icon` / `iconUrl` | 否 | - | 自定义单点图片。 |
2671
+ | `imageCallback` | 否 | - | 按点位返回图片地址或图标配置。 |
2672
+ | `clusterSize` | 否 | `42` | 聚合圆基础尺寸;数量增大时会轻微放大。 |
2673
+ | `clusterColor` | 否 | `#1677ff` | 聚合圆背景色。 |
2674
+ | `clusterTextColor` | 否 | `#ffffff` | 聚合数量文字颜色。 |
2675
+ | `clusterOutlineColor` / `clusterOutlineWidth` | 否 | 白色 / `3` | 聚合圆描边。 |
2676
+ | `clusterImageCallback` | 否 | - | 默认图标由双引擎共用 Canvas 生成;可返回自定义图片地址、Canvas 或图标配置。 |
2677
+ | `zoomOnClusterClick` | 否 | `true` | 点击聚合圆后是否自动放大。 |
2678
+ | `throttleTime` | 否 | `100` | 地图变化后重新聚合的节流时间,毫秒。 |
2679
+ | `onClick` | 否 | - | 单点点击回调。 |
2680
+ | `onClusterClick` | 否 | - | 聚合点击回调。 |
2681
+ | `onStateChange` | 否 | - | 聚合状态变化回调。 |
2682
+ | `viewportBuffer` | 否 | `80` | Cesium 专用:屏幕视野缓冲像素。 |
2683
+ | `cullByGlobe` | 否 | `true` | Cesium 专用:剔除地球背面点。 |
2684
+ | `clampToGround` | 否 | `false` | Cesium 专用:单点是否贴地。 |
2685
+ | `clusterZoomFactor` | 否 | `0.45` | Cesium 专用:每次点击后的目标高度比例。 |
2686
+ | `clusterZoomStep` | 否 | `2` | Leaflet 专用:每次点击增加的缩放级别。 |
2687
+ | `maxClusterZoom` | 否 | `Infinity` | Leaflet 专用:聚合点击最大缩放级别。 |
2688
+ | `zIndexOffset` | 否 | `0` | Leaflet 专用:Marker 层级偏移。 |
2689
+
2690
+ ### 状态返回
2691
+
2692
+ ```js
2693
+ const state = stationCluster.getState()
2694
+
2695
+ console.log(state)
2696
+ // {
2697
+ // engineType: 'leaflet',
2698
+ // layerType: 'leaflet-point-cluster-layer',
2699
+ // sourceCount: 10000,
2700
+ // inViewCount: 9800,
2701
+ // outOfViewCount: 200,
2702
+ // clusterCount: 185,
2703
+ // clusteredPointCount: 9600,
2704
+ // visiblePointCount: 200,
2705
+ // renderedCount: 385,
2706
+ // pixelRange: 72,
2707
+ // minimumClusterSize: 3,
2708
+ // visible: true,
2709
+ // destroyed: false,
2710
+ // }
2711
+ ```
2712
+
2713
+ 其中 `renderedCount = clusterCount + visiblePointCount`;被聚合的原始点数量单独记录在 `clusteredPointCount`,不会和聚合圆数量混淆。
2714
+
2715
+ 底层统一方法也可直接通过 `BaseGIS` 调用:
2716
+
2717
+ ```js
2718
+ mapCore.upsertPointClusterLayer(payload)
2719
+ mapCore.showPointClusterLayer({ layerId: 'station-cluster' })
2720
+ mapCore.hidePointClusterLayer({ layerId: 'station-cluster' })
2721
+ mapCore.clearPointClusterLayer({ layerId: 'station-cluster' })
2722
+ mapCore.getPointClusterLayerState({ layerId: 'station-cluster' })
2723
+ mapCore.removePointClusterLayer({ layerId: 'station-cluster' })
2724
+ ```
2725
+
2112
2726
  <a id="point-density-controller"></a>
2113
2727
 
2114
2728
  ## PointDensityController
@@ -2470,11 +3084,35 @@ console.log(state)
2470
3084
  // }
2471
3085
  ```
2472
3086
 
3087
+ <a id="contour-guide"></a>
3088
+
3089
+ ## 等值线与中心标注能力选择
3090
+
3091
+ 对外只保留 2 个控制器:已有线坐标或中心坐标时用 `ContourLayerController`,手里是栅格时用 `RasterContourController`。线值标签与中心标注都属于通用 Contour 渲染配置,不再需要单独的气压组合层。
3092
+
3093
+ | 手里的数据 / 目标 | 使用入口 | 负责内容 |
3094
+ | --- | --- | --- |
3095
+ | 已经计算好的等值线,可选已有中心点 | [`ContourLayerController`](#contour-layer-controller) | 渲染线、线值标签和传入的 `centers`,并管理统一生命周期。 |
3096
+ | GeoTIFF、灰度图或数值网格 | [`RasterContourController`](#raster-contour-controller) | 读取栅格、追踪等值线;显式开启后可从网格检测局部 H/L 中心。 |
3097
+
3098
+ 两条数据链路:
3099
+
3100
+ ```text
3101
+ 已有 isolines + 可选 centers ──> ContourLayerController ──> 线 + 标签 + 中心
3102
+ GeoTIFF / 灰度图 / 数值网格 ──> RasterContourController ──> ContourLayerController ──> 地图
3103
+ ```
3104
+
3105
+ 特别注意:
3106
+
3107
+ - `ContourLayerController` 只渲染传入的 `centers`,不会从已有线坐标反推极值中心。
3108
+ - `RasterContourController.centerDetection` 默认关闭;只有气压等确实需要 H/L 语义的数值网格才应显式开启。
3109
+ - 两个控制器都不转换业务单位或 Windy 原始格式;传入值就是最终计算和展示值。
3110
+
2473
3111
  <a id="contour-layer-controller"></a>
2474
3112
 
2475
- ## ContourLayerController
3113
+ ## ContourLayerController:渲染已有等值线与中心标注
2476
3114
 
2477
- 用于等值线图层,支持加载、更新、显隐、清空和销毁。
3115
+ 负责渲染已经计算好的线和业务传入的中心坐标,不读取栅格,也不执行插值或等值线追踪。Cesium / Leaflet 共用同一套数据、样式和生命周期 API。
2478
3116
 
2479
3117
  ```js
2480
3118
  import { ContourLayerController } from '@3clear/basegis/methods'
@@ -2483,6 +3121,10 @@ const contour = new ContourLayerController({
2483
3121
  mapCore,
2484
3122
  layerId: 'temperature-contour',
2485
3123
  visible: true,
3124
+ color: '#ff4d4f',
3125
+ width: 2,
3126
+ showLabel: true,
3127
+ labelFormatter: (item) => `${item.value}℃`,
2486
3128
  })
2487
3129
 
2488
3130
  await contour.load({
@@ -2490,6 +3132,7 @@ await contour.load({
2490
3132
  {
2491
3133
  value: 20,
2492
3134
  lines: [
3135
+ // 默认坐标顺序是 [纬度, 经度]。
2493
3136
  [
2494
3137
  [30, 104],
2495
3138
  [31, 105],
@@ -2498,18 +3141,11 @@ await contour.load({
2498
3141
  ],
2499
3142
  },
2500
3143
  ],
2501
- style: {
2502
- color: '#ff4d4f',
2503
- width: 2,
2504
- },
2505
- showLabel: true,
2506
- labelFormatter: (item) => String(item.value),
2507
3144
  })
2508
3145
 
2509
3146
  await contour.update({
2510
- style: {
2511
- color: '#1677ff',
2512
- },
3147
+ color: '#1677ff',
3148
+ width: 1.5,
2513
3149
  })
2514
3150
 
2515
3151
  contour.hide()
@@ -2518,13 +3154,63 @@ contour.clear()
2518
3154
  contour.destroy()
2519
3155
  ```
2520
3156
 
2521
- 数据别名支持 `contours / isolines / isoline / lines / data / items`。开启 `showLabel` 后,Cesium Leaflet 都会根据当前屏幕范围重新选择可见线段上的位置。Leaflet 传入经度跨度达到 360° 的 `worldCopyArea` 后,还会按当前视野动态更新等值线路径和标签的世界副本;这个过程只重建可见路径,不重新解析栅格或追踪等值线。`RasterContourController` 会自动把栅格范围作为 `worldCopyArea` 传入。
3157
+ 样式参数必须放在配置顶层,或通过 `styleCallback` 按线返回;`style: { color, width }` 不会生效。
3158
+
3159
+ ### 输入数据
3160
+
3161
+ 推荐使用 `{ value, lines }` 结构:
3162
+
3163
+ ```js
3164
+ const contours = [
3165
+ {
3166
+ value: 20,
3167
+ label: '20℃',
3168
+ lines: [
3169
+ // 一条等值线;默认每个坐标是 [纬度, 经度]。
3170
+ [[30, 104], [31, 105], [32, 106]],
3171
+ ],
3172
+ },
3173
+ ]
3174
+ ```
3175
+
3176
+ 还支持:
3177
+
3178
+ - `{ value, coordinates: [[lat, lon], ...] }`
3179
+ - `{ value, points: [lat, lon, lat, lon, ...] }`
3180
+ - GeoJSON `LineString` / `MultiLineString` Feature;GeoJSON 坐标按标准 `[经度, 纬度]` 解析
3181
+ - 原始线数组,以及顶层字段别名 `contours / isolines / isoline / lines / data / items`
3182
+
3183
+ 传 GeoJSON FeatureCollection 时,请传 `featureCollection.features` 或 `{ contours: featureCollection.features }`。
3184
+
3185
+ <a id="contour-layer-parameters"></a>
3186
+
3187
+ ### 核心参数
3188
+
3189
+ | 参数 | 类型 | 默认值 | 说明 |
3190
+ | --- | --- | --- | --- |
3191
+ | `mapCore/baseGIS` | `BaseGIS` | - | 当前 `BaseGIS` 实例;构造时不传则后续调用 `mount(mapCore)`。 |
3192
+ | `layerId/contourLayerId` | `string` | `contour-default` | 图层唯一 ID。 |
3193
+ | `coordinateOrder` | `latlng/lnglat` | `latlng` | `lines/coordinates` 的嵌套坐标顺序。 |
3194
+ | `flatOrder` | `latlng/lnglat` | `latlng` | `points` 平铺数组的坐标顺序。 |
3195
+ | `color` | `string` | `rgba(255,255,255,0.82)` | 默认线色。 |
3196
+ | `width/weight` | `number` | `1.15` | 线宽;两种写法用于兼容双引擎。 |
3197
+ | `opacity` | `number` | `1` | 线透明度。 |
3198
+ | `styleCallback(rawItem, line, lineIndex, record)` | `Function` | - | 按原始记录和线段返回动态样式。 |
3199
+ | `splitWrappedLine` | `boolean` | `true` | 是否拆分跨日期变更线的异常跳线。 |
3200
+ | `worldCopyOffsets` | `number[]` | Cesium `[0]`;Leaflet `[-360,0,360]` | 世界副本经度偏移。 |
3201
+ | `visible` | `boolean` | `true` | 初始是否显示。 |
3202
+
3203
+ Cesium 专用参数包括 `height / clampToGround / granularity / lineThinStep`;Leaflet 专用参数包括 `smoothFactor / lineCap / lineJoin / interactive / pane`。
3204
+
3205
+ ### 双引擎渲染说明
3206
+
3207
+ 开启 `showLabel` 后,Cesium 和 Leaflet 都会根据当前屏幕范围重新选择可见线段上的标签位置。Leaflet 传入经度跨度达到 360° 的 `worldCopyArea` 后,还会按当前视野动态更新等值线路径和标签的世界副本;这个过程只重建可见路径,不重新解析栅格或追踪等值线。`RasterContourController` 会自动把栅格范围作为 `worldCopyArea` 传入。
2522
3208
 
2523
3209
  Cesium 在默认椭球地表上使用 `PolylineCollection` 批量落图;真正启用 DEM 地形后才使用 `GroundPolylinePrimitive`。新批次就绪后再替换旧批次,不为每条线创建独立 Entity。标签定位可通过 `labelLineThinStep` 抽样投影点,不会改变实际绘制的等值线。
2524
3210
 
2525
3211
  Leaflet 默认复用高精度 SVG renderer,并使用 `smoothFactor: 0.5` 做屏幕空间简化:缩小时清理挤在同一像素内的折点,放大后自动保留曲线细节,避免全局 `preferCanvas` 放大细线锯齿。线位于 `dt-contour-pane`(层级 `450`),稳定显示在图片图层上方,并保持在 `markerPane` 数值标签下方;显式传入 `pane` 时仍以业务配置为准。
2526
3212
 
2527
- 屏幕标注参数:
3213
+ ### 通用线值标签参数
2528
3214
 
2529
3215
  | 参数 | 类型 | 默认值 | 说明 |
2530
3216
  | --- | --- | --- | --- |
@@ -2546,13 +3232,28 @@ Leaflet 默认复用高精度 SVG renderer,并使用 `smoothFactor: 0.5` 做
2546
3232
 
2547
3233
  `getState()` 的 `labelCount` 是当前视野实际显示的标签数量。Cesium 状态额外包含 `lineRenderer/lineBuildElapsed/labelLayoutElapsed/primitiveReadyElapsed`,用于区分线构建、标签排版和异步就绪耗时。`onStateChange(state)` 会在视野重排后回传新状态。页面存在侧栏等遮挡时,可通过 `labelViewportPadding` 排除对应区域。
2548
3234
 
3235
+ ### 生命周期与状态
3236
+
3237
+ | 方法 | 说明 |
3238
+ | --- | --- |
3239
+ | `mount(mapCore)` | 后挂载 `BaseGIS`;构造时已传入则无需调用。 |
3240
+ | `load(payload, options)` / `upsert(...)` | 首次创建或覆盖图层,必须包含等值线数据或 `centers`。 |
3241
+ | `update(payload)` / `setConfig(...)` | 合并数据或渲染参数并更新已经加载的图层。 |
3242
+ | `show()` / `hide()` / `toggle(visible)` | 控制图层显隐。 |
3243
+ | `clear()` | 清空线、线值标签和中心标注,但保留图层实例,可再次加载。 |
3244
+ | `refreshState()` | 从当前引擎重新读取状态。 |
3245
+ | `getState()` | 返回普通状态对象,包括 `levelCount / lineCount / centerCount / lineLabelCount / centerLabelCount / labelCount / visible`。 |
3246
+ | `destroy()` / `removeLayer()` | 删除图层、释放资源,并移除 `BaseGIS` 托管快照。 |
3247
+
3248
+ 推荐顺序:`BaseGIS.init()` 成功后创建控制器并 `load()`;页面卸载时先 `contour.destroy()`,再 `mapCore.destroy()`。
3249
+
2549
3250
  <a id="raster-contour-controller"></a>
2550
3251
 
2551
- ## RasterContourController
3252
+ ## RasterContourController:从栅格生成等值线
2552
3253
 
2553
- 用于从 GeoTIFF、灰度图或数值网格直接计算并绘制等值线。内部统一使用 `d3-contour` 追踪等值线,输出仍交给 `ContourLayerController`,所以页面不需要区分 Cesium 和 Leaflet;调用 `BaseGIS.setEngine()` 时,已经生成的等值线会随托管图层自动恢复。
3254
+ 负责完整的“读取数据源 标准化数值网格 → 追踪等值线 → 双引擎渲染”链路。内部使用 `d3-contour` 生成线,再交给 `ContourLayerController` 渲染;页面不需要区分 Cesium 和 Leaflet。调用 `BaseGIS.setEngine()` 时,已经生成的线会随托管图层自动恢复。
2554
3255
 
2555
- ### 1. GeoTIFF 生成等值线
3256
+ ### GeoTIFF
2556
3257
 
2557
3258
  ```js
2558
3259
  import { RasterContourController } from '@3clear/basegis/methods'
@@ -2598,7 +3299,7 @@ await rasterContour.update({ interval: 2 })
2598
3299
 
2599
3300
  GeoTIFF 依赖宿主页面提供 `window.GeoTIFF`。控制器会读取波段、尺寸、坐标系和范围;当前原生支持 EPSG:4326、EPSG:3857。其他投影可先转换为 WGS84,或传入 WGS84 `area` 覆盖原始范围。
2600
3301
 
2601
- ### 2. 灰度图生成等值线
3302
+ ### 灰度图
2602
3303
 
2603
3304
  ```js
2604
3305
  await rasterContour.loadGrayImage({
@@ -2622,7 +3323,9 @@ await rasterContour.loadGrayImage({
2622
3323
 
2623
3324
  灰度图片本身没有地理范围和业务值含义,因此 `area` 必填;要表达真实数据,还应传正确的灰度范围与业务值范围。已经着色的彩色 PNG 不能反推出原始业务值,应使用对应 TIF 或直接传数值网格。
2624
3325
 
2625
- ### 3. 数值网格生成等值线
3326
+ 上例虽然使用了气压值域,但 `centerDetection` 默认关闭,因此只生成普通等压线和线值标签。需要 H/L 中心时,按下方“自动检测 H/L 中心”配置显式开启。
3327
+
3328
+ ### 数值网格
2626
3329
 
2627
3330
  ```js
2628
3331
  await rasterContour.loadGrid({
@@ -2644,13 +3347,13 @@ await rasterContour.loadGrid({
2644
3347
  })
2645
3348
  ```
2646
3349
 
2647
- ### 4. 参数
3350
+ ### 参数
2648
3351
 
2649
3352
  数据源参数:
2650
3353
 
2651
3354
  | 参数 | 类型 | 必填 | 默认值 | 说明 |
2652
3355
  | --- | --- | --- | --- | --- |
2653
- | `mapCore/baseGIS` | `BaseGIS` | 构造时必填 | `null` | 当前 BaseGIS 实例。 |
3356
+ | `mapCore/baseGIS` | `BaseGIS` | | `null` | 当前 BaseGIS 实例;构造时不传则后续调用 `mount(mapCore)`。 |
2654
3357
  | `layerId/contourLayerId` | `string` | 否 | `raster-contour-default` | 等值线图层 id。 |
2655
3358
  | `sourceType` | `geotiff/grayscale/grid` | 否 | 自动判断 | `loadGeoTiff/loadGrayImage/loadGrid` 会自动补齐。 |
2656
3359
  | `tifUrl/tiffUrl` | `string` | GeoTIFF 必填 | `''` | GeoTIFF 地址。 |
@@ -2681,67 +3384,125 @@ await rasterContour.loadGrid({
2681
3384
  | `minimumLinePoints` | `number` | 否 | `3` | 最短线点数,用于过滤栅格四角的两点补边。 |
2682
3385
  | `coordinatePrecision` | `number` | 否 | `6` | 输出经纬度小数位数。 |
2683
3386
  | `visible` | `boolean` | 否 | `true` | 初始显隐。 |
2684
- | 其他渲染参数 | - | 否 | - | `ContourLayerController` 相同,如 `color/width/weight/styleCallback/showLabel/labelViewportPadding`。 |
3387
+ | 其他渲染参数 | - | 否 | - | 复用 [`ContourLayerController` 核心参数](#contour-layer-parameters),如 `color/width/weight/styleCallback/showLabel/labelViewportPadding`。 |
2685
3388
 
2686
- ### 5. 方法和状态
3389
+ 级别选择优先级为 `thresholds` → `interval` → `thresholdCount`。显式传入 `thresholds` 时,只保留实际值域内的级别。
3390
+
3391
+ ### 自动检测 H/L 中心
3392
+
3393
+ 该能力默认关闭。它使用标准化后的数值网格查找局部极大值(H)和局部极小值(L),而不是根据已经生成的线反推。因此只应用于确实存在 H/L 语义的栅格数据。
3394
+
3395
+ ```js
3396
+ await rasterContour.loadGrid({
3397
+ values: pressureValues,
3398
+ width,
3399
+ height,
3400
+ area: [70, 10, 140, 60],
3401
+ interval: 4,
3402
+ showLabel: true,
3403
+ centerDetection: {
3404
+ enabled: true,
3405
+ radius: 6,
3406
+ minProminence: 2,
3407
+ minGridDistance: 20,
3408
+ maxCount: 12,
3409
+ },
3410
+ centerAnnotation: {
3411
+ visible: true,
3412
+ collision: true,
3413
+ color: '#e3f8ff',
3414
+ valueColor: '#ffffff',
3415
+ },
3416
+ })
3417
+ ```
3418
+
3419
+ | `centerDetection` 参数 | 默认值 | 说明 |
3420
+ | --- | --- | --- |
3421
+ | `enabled` | `false` | 开启 H/L 自动检测。 |
3422
+ | `radius` | `6` | 计算局部显著度的网格半径。 |
3423
+ | `minProminence` | `2` | 中心值与邻域平均值的最小差异,单位与输入网格一致。 |
3424
+ | `minGridDistance` | `20` | 同类中心的最小网格距离,距离过近时合并。 |
3425
+ | `maxCount` | `12` | H/L 合计最大输出数。 |
3426
+ | `includeHigh/includeLow` | `true/true` | 是否输出 H 或 L。 |
3427
+ | `excludeBoundary` | `true` | 排除贴近边界或 NoData 空洞的候选。 |
3428
+ | `smoothingIterations` | `1` | 3×3 有效值平滑次数,范围 0~3。 |
3429
+
3430
+ 检测流程会先进行轻量平滑,再按显著度过滤、合并过近的同类中心并限制数量。超过 100 万格时只对候选搜索做块均值抽样,最终仍回到原网格取精确值和坐标。关闭检测后会清理上一次自动中心。
3431
+
3432
+ `RasterContourController` 也可直接传顶层 `centers`。手工数组(包括 `[]`)优先于自动检测;传 `centers: null` 可恢复使用当前 `centerDetection` 的结果。检测只产生中心数据,仍需 `centerAnnotation.visible: true` 才会显示。
3433
+
3434
+ ### 方法和状态
2687
3435
 
2688
3436
  | 方法 | 说明 |
2689
3437
  | --- | --- |
3438
+ | `mount(mapCore)` | 后挂载 `BaseGIS`;构造时已传入则无需调用。 |
2690
3439
  | `load(payload, options)` | 自动判断数据源并生成等值线。 |
2691
3440
  | `loadGeoTiff(payload, options)` | 从 GeoTIFF 生成。 |
2692
3441
  | `loadGrayImage(payload, options)` | 从灰度图生成。 |
2693
3442
  | `loadGrid(payload, options)` | 从数值网格生成。 |
2694
3443
  | `update(payload)` | 合并配置后重新计算;仅修改等值线或渲染参数时复用已解析网格,修改数据源参数时自动重新加载。 |
2695
- | `show/hide/toggle` | 控制等值线显隐。 |
3444
+ | `show/hide/toggle` | 统一控制等值线、线值标签和中心标注显隐。 |
2696
3445
  | `clear/destroy` | 清空或销毁控制器。 |
2697
- | `getState()` | 返回尺寸、值域、级别、线数、当前标注数、投影、耗时和底层 contour 状态。 |
3446
+ | `getState()` | 返回尺寸、值域、级别、线数、`centerCount`、标注数、投影、耗时和底层 contour 状态。 |
2698
3447
  | `getRasterData()` | 返回当前标准栅格,包含 `values/width/height/area`。 |
2699
3448
 
2700
- <a id="pressure-contour-layer"></a>
2701
-
2702
- ## PressureContourLayer
2703
-
2704
- 用于等压线、线值标签和高低压中心标注。`buildPressureRenderData()` 可把 Windy 风格的气压数据整理成 `{ isolines, centers }`,`createPressureDataResolver()` 在此基础上提供按数据版本缓存的解析函数。
2705
-
2706
3449
  ```js
2707
- import {
2708
- PressureContourLayer,
2709
- buildPressureRenderData,
2710
- createPressureDataResolver,
2711
- } from '@3clear/basegis/methods'
3450
+ // clear 只清空当前渲染结果,控制器仍可继续 update/load。
3451
+ rasterContour.clear()
3452
+
3453
+ // 页面卸载时彻底释放栅格、图层和监听。
3454
+ rasterContour.destroy()
3455
+ ```
3456
+ <a id="contour-center-annotation"></a>
2712
3457
 
2713
- // 单份原始数据可以直接转换。
2714
- const renderData = buildPressureRenderData(pressJson)
3458
+ ## 中心标注配置(两个控制器通用)
2715
3459
 
2716
- // 多个时次或版本可用解析器按 key 缓存转换结果。
2717
- const resolvePressureData = createPressureDataResolver({
2718
- default: pressJson,
2719
- next: pressJson2,
2720
- })
3460
+ `ContourLayerController` 通过顶层 `centers` 接收已经计算好的中心点,通过 `centerAnnotation` 控制显示和样式。该能力是通用标注,不把数据限制为气压;H/L 只是气压业务中的一种标签。
2721
3461
 
2722
- const pressureLayer = new PressureContourLayer({
3462
+ ```js
3463
+ const pressureContour = new ContourLayerController({
2723
3464
  mapCore,
2724
- layerId: 'pressure',
2725
- color: 'rgba(255,255,255,0.82)',
2726
- width: 1.15,
2727
- smoothFactor: 0.2,
2728
- // Cesium 用它判断标签碰撞和屏幕范围,Leaflet 可复用同一容器 id。
2729
- mapContainerId: 'map',
2730
- isAnnotationVisible: () => true,
3465
+ layerId: 'pressure-contour',
3466
+ showLabel: true,
3467
+ labelFormatter: (item) => String(item.value),
3468
+ centerAnnotation: {
3469
+ visible: true,
3470
+ collision: true,
3471
+ color: '#e3f8ff',
3472
+ fontSize: 20,
3473
+ valueColor: '#ffffff',
3474
+ valueFontSize: 12,
3475
+ },
2731
3476
  })
2732
3477
 
2733
- pressureLayer.mount()
2734
- await pressureLayer.load(renderData)
2735
- await pressureLayer.update(resolvePressureData('next'))
2736
- pressureLayer.hide()
2737
- pressureLayer.destroy()
3478
+ await pressureContour.load({
3479
+ isolines: [
3480
+ {
3481
+ value: 1012,
3482
+ lines: [[[31, 116.5], [31.4, 117.2], [31.7, 118]]],
3483
+ },
3484
+ ],
3485
+ centers: [
3486
+ { type: 'H', value: 1020, lat: 32.1, lon: 117.3 },
3487
+ { type: 'L', value: 1004, lat: 30.5, lon: 116.8 },
3488
+ ],
3489
+ })
2738
3490
  ```
2739
3491
 
2740
- 说明:
3492
+ `centers[]` 支持 `{ label, type, value, lat, lon }`,也支持 `position`。对象坐标字段固定按语义读取;`position` 数组遵循 `coordinateOrder`。主标签优先读取 `label`,其次读取 `type`。
3493
+
3494
+ | `centerAnnotation` 参数 | 默认值 | 说明 |
3495
+ | --- | --- | --- |
3496
+ | `visible` | `false` | 是否显示中心标注。数据与显示配置分开,传入 centers 不会自动开启。 |
3497
+ | `collision` | `true` | 是否避让其他中心;中心先占位,线值标签随后避让。 |
3498
+ | `formatter(raw, center)` | - | 返回文本,或返回 `{ label, value }`。 |
3499
+ | `styleCallback(raw, index, center)` | - | 按中心覆盖颜色、字号、字重或返回 `visible:false`。 |
3500
+ | `color/fontSize` | `#34464f / 18` | 主标签颜色与字号。 |
3501
+ | `valueColor/valueFontSize` | 跟随 `color` / `12` | 数值颜色与字号;`color` 也未传时颜色为 `#34464f`。 |
3502
+ | `collisionPadding` | `8` | 碰撞间距,单位 px。 |
3503
+ | `viewportPadding` | `24` | 屏幕安全边距。 |
2741
3504
 
2742
- - 等压线数据会被整理为 `isolines` 和 `centers`。
2743
- - Leaflet 使用 `divIcon` 绘制 H/L 中心和线值标签。
2744
- - Cesium 使用独立标注集合,地图变化时会调度刷新。
3505
+ 状态中的 `centerCount` 是成功解析的有效中心数,`lineLabelCount` 和 `centerLabelCount` 是当前视野实际显示数,`labelCount` 是两者合计。`show/hide/clear/destroy` 以及 `BaseGIS.setEngine()` 会和等值线一起管理这些中心标注。
2745
3506
 
2746
3507
  <a id="wind-field-methods"></a>
2747
3508
 
@@ -2971,7 +3732,7 @@ const result = await setEngine('leaflet')
2971
3732
  console.log(result.data?.restore)
2972
3733
  ```
2973
3734
 
2974
- 只有风场、剖面、一次性绘制对象或页面直接创建的底层引擎对象需要在切换成功后自行恢复。
3735
+ 只有 GPU 专用风场、剖面、一次性绘制对象或页面直接创建的底层引擎对象需要在切换成功后自行恢复。
2975
3736
 
2976
3737
  ## 能力支持说明
2977
3738
 
@@ -2982,9 +3743,11 @@ console.log(result.data?.restore)
2982
3743
  | 放大、缩小、重置 | 支持 | 支持 |
2983
3744
  | 底图切换 | 支持 | 支持 |
2984
3745
  | 点线面文字 | 支持 | 支持 |
3746
+ | 独立线、虚线、渐变与沿线动画 | 支持 | 支持 |
2985
3747
  | 图片覆盖层 | 支持 | 支持 |
2986
3748
  | 网格 / TIF | 支持 | 支持 |
2987
3749
  | 海量点 | 支持 | 支持 |
3750
+ | 点位聚合 | 支持 | 支持 |
2988
3751
  | 点位密度抽稀 | 支持 | 支持 |
2989
3752
  | 等值线 | 支持 | 支持 |
2990
3753
  | 等压线标注 | 支持 | 支持 |
@@ -3131,7 +3894,7 @@ mapCore.init()
3131
3894
 
3132
3895
  ### 切换引擎后图层没了
3133
3896
 
3134
- 直接使用 `setEngine()`。BaseGIS 会保留视野,并自动恢复图片、网格、海量点、点位抽稀、等值线和三维体等托管图层:
3897
+ 直接使用 `setEngine()`。BaseGIS 会保留视野,并自动恢复图片、网格、海量点、点位聚合、点位抽稀、独立线、等值线、统一风场和三维体等托管图层:
3135
3898
 
3136
3899
  ```js
3137
3900
  const result = await mapCore.setEngine('leaflet')
@@ -3140,4 +3903,4 @@ console.log(result.data?.restore?.restored)
3140
3903
  console.log(result.data?.restore?.failed)
3141
3904
  ```
3142
3905
 
3143
- 如果丢失的是 `drawPoint/drawLine/drawPolygon/drawText/addMarker`、点击监听、风场、剖面图层或页面直接创建的 Cesium / Leaflet 对象,它们不属于托管图层,需要业务在切换成功后自行恢复。
3906
+ 如果丢失的是 `drawPoint/drawLine/drawPolygon/drawText/addMarker`、点击监听、GPU 专用风场、剖面图层或页面直接创建的 Cesium / Leaflet 对象,它们不属于托管图层,需要业务在切换成功后自行恢复。