map-ol-utils 0.1.28 → 0.1.30

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
@@ -1,109 +1,573 @@
1
1
  # map-ol-utils
2
2
 
3
- OpenLayers 地图工具库,封装常用的图层创建、要素交互与地图管理操作。
3
+ > 目录:`packages/map-utils` | npm 包名:`map-ol-utils`
4
+
5
+ 基于 [OpenLayers](https://openlayers.org/) 的地图工具库,封装了地图实例管理、底图创建、矢量/面/线/聚合/海量点图层、要素交互选择、视野自适应、WMTS 接入等常用能力。
6
+
7
+ ## 特性
8
+
9
+ - **单例地图实例**:模块内维护一个全局 `instance`,多数工具函数直接操作该单例,无需层层传参。
10
+ - **多种底图**:杭州规自瓦片、全国天地图(WMTS)、浙江省天地图(XYZ)。
11
+ - **业务矢量图层**:根据业务数据自动推断几何类型(线/面)并生成 GeoJSON 图层,支持着色映射、点击高亮。
12
+ - **海量点 MassMarks**:基于状态值的多套样式(默认 + 激活),可附带伴生线/面图层。
13
+ - **聚合图层**:基于 `ol/source/Cluster`,半径/颜色随聚合数量动态计算。
14
+ - **坐标系转换**:内部统一通过 [`gcoord`](https://github.com/hujiulong/gcoord) 转换到 `WGS84`(`EPSG:4326`)。
15
+ - **事件总线**:内置 `mitt` 实例 `emitter`,用于派发要素选中等事件。
4
16
 
5
17
  ## 安装
6
18
 
7
19
  ```bash
8
- pnpm add map-ol-utils
20
+ pnpm add map-ol-utils ol gcoord
9
21
  ```
10
22
 
11
- ## 快速上手
23
+ `ol` 是 **peerDependency**(要求 `>=10.5.0`),需由宿主项目安装。
24
+
25
+ ## 快速开始
12
26
 
13
27
  ```ts
14
- import { createMapInstance, createMassMarksLayer, addMassMarksLayer } from 'map-ol-utils'
28
+ import { createMapInstance, createBusinessLayer, emitter } from 'map-ol-utils'
15
29
 
16
- // 创建地图(单例)
17
- const map = createMapInstance({ target: 'map-container' })
30
+ const map = createMapInstance({ center: [120.15, 30.28], zoom: 11 })
31
+ map.setTarget('map') // 容器通过 setTarget 绑定,config 仅透传给 ol/View
18
32
 
19
- // 添加点位图层
20
- const layer = createMassMarksLayer(dataList, styles)
33
+ const layer = createBusinessLayer(dataList, {
34
+ key: 'coordinates',
35
+ isLine: false,
36
+ openClick: true,
37
+ layerName: 'biz-layer',
38
+ fillColor: '#4247DF',
39
+ strokeColor: '#1DEBFF'
40
+ })
21
41
  map.addLayer(layer)
42
+
43
+ emitter.on('selected-feature', (data) => console.log('选中要素:', data))
44
+ ```
45
+
46
+ ---
47
+
48
+ # API 详解
49
+
50
+ > 约定:下文「实例方法默认 `mapInstance = instance`」表示该参数缺省时使用模块单例;调用前请确保已 `createMapInstance` / `createMap`。
51
+
52
+ ## 一、地图实例(`create-map.ts`)
53
+
54
+ ### `createMapInstance(config?)`
55
+
56
+ 创建并缓存地图单例;若已存在则直接返回,不会重建。
57
+
58
+ ```ts
59
+ function createMapInstance(config?: Record<string, any>): CustomMap
60
+ ```
61
+
62
+ | 参数 | 类型 | 默认 | 说明 |
63
+ |---|---|---|---|
64
+ | `config` | `object` | `{}` | 透传给 `createMap` → `ol/View` 的视图配置 |
65
+
66
+ 返回:`CustomMap`(OpenLayers `Map` 的扩展,附带 `getLayerByName` / `removeLayerByName` / `changeLayersByNames` 方法与 `activeBaseLayer` 字段)。
67
+
68
+ ```ts
69
+ const map = createMapInstance({ center: [120.15, 30.28], zoom: 11 })
70
+ map.setTarget('map')
71
+ ```
72
+
73
+ ### `createMap(config?)`
74
+
75
+ 始终新建一个 `CustomMap`。默认挂载杭州规自暗色底图,禁用旋转/双击缩放,并在 `pointermove` 时根据是否命中要素切换鼠标指针。`config` 与以下默认值合并后作为 `ol/View` 选项:
76
+
77
+ ```ts
78
+ function createMap(config?: Record<string, any>): CustomMap
79
+ // 默认 View 配置:
80
+ // { zoom: 9.4, maxZoom: 18, minZoom: 9.4, center, baseLayer: 'vec-layer',
81
+ // projection: 'EPSG:4326', layers: [createBaseLayer()],
82
+ // constrainResolution: false, smoothExtentConstraint: false, tk }
83
+ ```
84
+
85
+ | 参数 | 类型 | 默认 | 说明 |
86
+ |---|---|---|---|
87
+ | `config` | `object` | `{}` | `ol/View` 配置;可额外传 `layers` 覆盖默认底图、`baseLayer` 标记当前底图名 |
88
+
89
+ ```ts
90
+ const map = createMap({ zoom: 12, center: [121.43, 28.66] })
91
+ ```
92
+
93
+ ### `getMapInstance()`
94
+
95
+ ```ts
96
+ function getMapInstance(): CustomMap
97
+ ```
98
+
99
+ 返回当前单例(等价于导出的 `instance` 变量)。
100
+
101
+ ### `disposeMap()`
102
+
103
+ ```ts
104
+ function disposeMap(): void
105
+ ```
106
+
107
+ 销毁单例:移除全部 overlay、清空 interaction、移除并释放(`source.dispose()` + `layer.dispose()`)所有图层,`setTarget('')` 后将 `instance` 置为 `undefined`。
108
+
109
+ ### `resetMap(config?)`
110
+
111
+ ```ts
112
+ function resetMap(config?: { center?: Coordinate; isClearAll?: boolean }): void
113
+ // 默认:{ center: 上次中心, isClearAll: true }
114
+ ```
115
+
116
+ 清除所有非底图图层(内部调用 `removeAllLayers`)并复位缩放与中心。
117
+
118
+ ### `resetZoomAndCenter(center?)`
119
+
120
+ ```ts
121
+ function resetZoomAndCenter(center?: [number, number]): void // 默认上次中心
122
+ ```
123
+
124
+ 动画(1s)复位到默认缩放 `9.4` 与指定中心。
125
+
126
+ ### `instance`
127
+
128
+ ```ts
129
+ let instance: CustomMap // 导出变量;未创建时为 undefined
130
+ ```
131
+
132
+ ---
133
+
134
+ ## 二、底图与图层名管理(`base-layer.ts`)
135
+
136
+ ### `createBaseLayer(layerName?)`
137
+
138
+ 杭州规自瓦片底图(`EPSG:4326`,XYZ,5 路负载)。
139
+
140
+ ```ts
141
+ function createBaseLayer(layerName?: HzsyType): Tile
142
+ // HzsyType = 'hzsyraster' | 'hzsyvector' | 'hzsyvector_dark'(默认 'hzsyvector_dark')
143
+ ```
144
+
145
+ 图层附带属性 `{ _isBaseLayer: true, _layerName: layerName }`,`zIndex: -5`。
146
+
147
+ ```ts
148
+ const base = createBaseLayer('hzsyvector')
149
+ map.addLayer(base)
150
+ ```
151
+
152
+ ### `createMapWorldLayer(layerName, tk?)`
153
+
154
+ 全国天地图 WMTS 图层。
155
+
156
+ ```ts
157
+ function createMapWorldLayer(layerName: WorldLayerType, tk?: string): Tile
158
+ // WorldLayerType = 'vec_c' | 'cva_c' | 'img_c' | 'cia_c' | 'ter_c' | 'cta_c' | 'ibo_c'
159
+ ```
160
+
161
+ | 参数 | 类型 | 默认 | 说明 |
162
+ |---|---|---|---|
163
+ | `layerName` | `WorldLayerType` | — | 形如 `img_c`,内部按 `_` 拆分为图层名与 matrixSet |
164
+ | `tk` | `string` | 内置默认令牌 | 天地图访问令牌,**建议自行传入** |
165
+
166
+ ```ts
167
+ map.addLayer(createMapWorldLayer('img_c', '你的天地图令牌'))
168
+ ```
169
+
170
+ ### `createZheJiangLayer(layerName?, tk?)`
171
+
172
+ 浙江省天地图 XYZ 图层。
173
+
174
+ ```ts
175
+ function createZheJiangLayer(layerName?: ZheJiangType, tk?: string): Tile
176
+ // ZheJiangType = 'emap' | 'emap_lab' | 'imgmap' | 'imgmap_lab'(默认 'emap')
177
+ ```
178
+
179
+ ### `getLayerByName(name)`
180
+
181
+ ```ts
182
+ function getLayerByName(name: string): Layer<Source> | undefined
183
+ ```
184
+
185
+ 按图层 `_layerName` 属性或 `className` 查找首个匹配图层。
186
+
187
+ ### `removeLayerByName(name)`
188
+
189
+ ```ts
190
+ function removeLayerByName(name: string): void
191
+ ```
192
+
193
+ 查找匹配图层并释放其 source、从地图移除并 `dispose`。
194
+
195
+ ### `changeLayersByNames(activeNames, allLayerNames)`
196
+
197
+ ```ts
198
+ function changeLayersByNames(activeNames: string[], allLayerNames: string[]): void
199
+ ```
200
+
201
+ 在 `allLayerNames` 范围内,按 `activeNames` 是否包含来逐一 `setVisible`,实现批量显隐切换。
202
+
203
+ ```ts
204
+ changeLayersByNames(['poi-layer'], ['poi-layer', 'line-layer', 'face-layer'])
205
+ ```
206
+
207
+ ---
208
+
209
+ ## 三、矢量图层(`layer-utils.ts`)
210
+
211
+ ### `createBusinessLayer(dataList, config)`
212
+
213
+ 核心矢量图层构造函数:将业务数据组装为 GeoJSON(自动推断线/面几何类型),生成默认/激活样式并写入要素属性,可选开启点击交互。
214
+
215
+ ```ts
216
+ function createBusinessLayer(dataList: MassData[], config: VectorConfig): VectorLayer
217
+ ```
218
+
219
+ | `config` 关键字段 | 类型 | 说明 |
220
+ |---|---|---|
221
+ | `key` | `string` | 数据中存放坐标数组的字段名 |
222
+ | `isLine` | `boolean` | 是否线图层(影响是否生成填充样式) |
223
+ | `layerName` | `string?` | 图层名(className) |
224
+ | `openClick` | `boolean?` | 是否创建单击选择交互 |
225
+ | `colorKey` / `colorMap` | `string?` / `Map<string,string>?` | 按数据字段值映射颜色 |
226
+ | `fillColor` / `strokeColor` | `string?` | 填充 / 描边色 |
227
+ | `fillOpacity` / `strokeWeight` | `number?` | 填充透明度 / 线宽 |
228
+ | `activeFillColor` / `activeStrokeColor` / `activeStrokeWeight` | … | 激活态样式 |
229
+ | `crsForm` | `CRSTypes?` | 源坐标系(默认 `WGS84`) |
230
+ | `isAutoFit` | `boolean?` | 选中后是否自动居中 |
231
+
232
+ 图层附带属性:`_isCustom`、`_isVectorLayer`、`_isAutoFit`、`_vectorConfig`、`_layerName`、`_dataList`、`_uuidSet`。
233
+
234
+ ```ts
235
+ const layer = createBusinessLayer(dataList, {
236
+ key: 'coordinates', isLine: false, openClick: true,
237
+ layerName: 'area', colorKey: 'level',
238
+ colorMap: new Map([['1', '#f00'], ['2', '#0f0']]),
239
+ fillOpacity: 0.3, strokeWeight: 2
240
+ })
241
+ map.addLayer(layer)
242
+ ```
243
+
244
+ ### `createVectorLineLayer(dataList?, config)` / `createVectorFaceLayer(dataList?, config)`
245
+
246
+ `createBusinessLayer` 的便捷包装,分别固定 `isLine: true` / `isLine: false`。
247
+
248
+ ```ts
249
+ function createVectorLineLayer(dataList?: MassData[], config: VectorConfig): VectorLayer
250
+ function createVectorFaceLayer(dataList?: MassData[], config: VectorConfig): VectorLayer
22
251
  ```
23
252
 
24
- ## 主要 API
253
+ ### `appendFeaturesByLayer(targetLayer, dataList, crsForm?)`
25
254
 
26
- ### 地图管理
255
+ 向已有矢量图层追加要素(同步更新其 `_uuidSet`),复用图层 `_vectorConfig` 生成样式。
27
256
 
28
- | 函数 | 说明 |
29
- |------|------|
30
- | `createMap(config)` | 创建 OL 地图实例 |
31
- | `createMapInstance(config)` | 创建地图单例 |
32
- | `getMapInstance()` | 获取当前单例 |
33
- | `disposeMap()` | 销毁地图,释放资源 |
34
- | `resetMap(config)` | 重置地图(清除图层并还原视图) |
35
- | `resetZoomAndCenter(center)` | 动画还原缩放和中心点 |
257
+ ```ts
258
+ function appendFeaturesByLayer(
259
+ targetLayer: VectorLayer,
260
+ dataList: MassData[],
261
+ crsForm?: CRSTypes
262
+ ): void
263
+ ```
36
264
 
37
- ### 底图图层
265
+ ---
38
266
 
39
- | 函数 | 说明 |
40
- |------|------|
41
- | `createBaseLayer(type?)` | 创建杭州本地切片底图 |
42
- | `createMapWorldLayer(options)` | 创建天地图图层 |
43
- | `createZheJiangLayer(type?)` | 创建浙江省切片图层 |
44
- | `switchBaseLayer(type)` | 切换底图类型 |
267
+ ## 四、海量点 MassMarks(`layer-utils.ts`)
45
268
 
46
- ### 矢量图层
269
+ ### `buildMassMarksStyles(getImgUrlFn)`
47
270
 
48
- | 函数 | 说明 |
49
- |------|------|
50
- | `createBusinessLayer(dataList, config)` | 从业务数据创建矢量图层(自动识别线/面类型) |
51
- | `createVectorLineLayer(dataList, config)` | 创建线状图层 |
52
- | `createVectorFaceLayer(dataList, config)` | 创建面状图层 |
53
- | `appendFeaturesByLayer(layer, dataList)` | 向已有图层追加要素 |
271
+ 高阶函数:先注入「图标地址生成器工厂」,再按 `IconConfig` 生成「默认 + 激活」两段样式数组(长度 `statusNum * 2`)。
54
272
 
55
- ### 点位与聚合
273
+ ```ts
274
+ function buildMassMarksStyles(
275
+ getImgUrlFn: GetImgUrlFn
276
+ ): (iconConfig: IconConfig) => Style[]
56
277
 
57
- | 函数 | 说明 |
58
- |------|------|
59
- | `createMassMarksLayer(dataList, styles)` | 创建大量点位图层 |
60
- | `addMassMarksLayer(getImgUrlFn)` | 高阶函数,返回添加点位图层的方法 |
61
- | `buildMassMarksStyles(getImgUrlFn)` | 构建多状态点位样式数组 |
62
- | `updateMarksLayersByStatus(statusList)` | 按状态控制点位显隐 |
63
- | `createClusterLayer(dataList, config)` | 创建聚合图层 |
278
+ type GetImgUrl = (name: string, ext?: string) => string
279
+ type GetImgUrlFn = (baseUrl: string) => GetImgUrl
280
+ ```
64
281
 
65
- ### 交互与选择
282
+ 图标地址按 `${markerIcon}-${i}` / `${markerIcon}-${i}-active`(后缀 `.webp`)拼接。
66
283
 
67
- | 函数 | 说明 |
68
- |------|------|
69
- | `createSelectByLayer(layer)` | 为图层添加点击选中交互 |
70
- | `activeFeatureByUid(uid)` | 通过 uid 程序化激活要素 |
71
- | `resetActiveFeature()` | 清除选中状态 |
72
- | `resetActiveVector()` | 清除矢量激活状态 |
284
+ ```ts
285
+ const buildStyles = buildMassMarksStyles((baseUrl) => (name, ext) => `${baseUrl}/${name}${ext}`)
286
+ const styles = buildStyles({ baseUrl: '/icons', markerIcon: 'alarm', markerSize: [32, 32], statusNum: 5 })
287
+ ```
73
288
 
74
- ### 视图控制
289
+ ### `createMassMarksLayer(dataList, styleList?)`
75
290
 
76
- | 函数 | 说明 |
77
- |------|------|
78
- | `setFitViewByCoords(coords)` | 缩放至坐标范围 |
79
- | `setFitViewByGeom(geom)` | 缩放至几何范围 |
80
- | `setFitViewByLayer(layer)` | 缩放至图层范围 |
291
+ ```ts
292
+ function createMassMarksLayer(dataList: MassData[], styleList?: StyleLike[]): VectorLayer
293
+ ```
81
294
 
82
- ### OGC
295
+ 按 `item.style` 索引在 `styleList` 中取样式创建要素图层(`zIndex: 2000`)。图层附带 `_isMassMarksLayer`、`_statusNum`、`_dataList`、`_uuidSet` 等属性。
83
296
 
84
- | 函数 | 说明 |
85
- |------|------|
86
- | `createWmtsLayer(url, options)` | 从 GeoServer GetCapabilities 创建 WMTS 图层 |
297
+ ### `addMassMarksLayer(getImgUrlFn)`
87
298
 
88
- ## 依赖
299
+ 高阶函数,返回的方法会生成样式、创建海量点图层、按 `hasLine` / `hasFace` 附加伴生矢量图层,并自动加入地图。
89
300
 
90
- - [ol](https://openlayers.org/) `>=10.5.0`(peer dependency)
91
- - [gcoord](https://github.com/hujiulong/gcoord) — 坐标系转换
92
- - [mitt](https://github.com/developit/mitt) — 事件总线
301
+ ```ts
302
+ function addMassMarksLayer(
303
+ getImgUrlFn: GetImgUrlFn
304
+ ): (dataList?: MassData[], iconConfig: IconConfig, openClick?: boolean) => VectorLayer
305
+ ```
93
306
 
94
- ## 事件
307
+ | `iconConfig` 字段 | 类型 | 说明 |
308
+ |---|---|---|
309
+ | `baseUrl` | `string` | 图标根地址 |
310
+ | `markerIcon` | `string` | 图标名前缀 |
311
+ | `markerSize` | `[number, number]` | 图标尺寸 |
312
+ | `statusNum` | `number?` | 状态数(默认 5) |
313
+ | `activeScale` | `number?` | 激活放大倍数(默认 1.3) |
314
+ | `hasLine` / `hasFace` | `boolean?` | 是否附带线 / 面图层 |
315
+ | `isDynamic` | `boolean?` | 是否动态图层(选中派发 `dynamic-marker`) |
316
+ | `isAutoFit` | `boolean?` | 选中是否自动居中 |
317
+ | `layerName` | `string?` | 图层名 |
318
+ | `offset` | `[number, number]?` | 偏移 |
319
+ | `marksStyles` | `Style[]?` | 直接指定样式(跳过自动生成) |
320
+ | `vectorConfig` | `VectorConfig?` | 伴生线/面图层配置覆盖 |
321
+
322
+ ```ts
323
+ const add = addMassMarksLayer((baseUrl) => (n, e) => `${baseUrl}/${n}${e}`)
324
+ const layer = add(dataList, { baseUrl: '/icons', markerIcon: 'alarm', markerSize: [32, 32], statusNum: 5, hasLine: true })
325
+ ```
95
326
 
96
- 通过导出的 `emitter` 监听图层交互事件:
327
+ ### `addFeaturesByLayer(targetLayer, dataList, config)`
328
+
329
+ 向海量点图层增量添加要素(复用图层 `_massMarksStyles`)。
330
+
331
+ ```ts
332
+ function addFeaturesByLayer(
333
+ targetLayer: VectorLayer,
334
+ dataList: MassData[],
335
+ config: { clear: boolean }
336
+ ): void
337
+ ```
338
+
339
+ `config.clear` 为 `true` 时先清空 source 再添加。
340
+
341
+ ### `updateMarksLayersByStatus(checkedStatusList?)`
342
+
343
+ ```ts
344
+ function updateMarksLayersByStatus(checkedStatusList?: string[]): MassData[]
345
+ ```
346
+
347
+ 遍历所有海量点图层:`status` 不在勾选列表中的要素设为隐藏样式,否则恢复默认样式。返回当前保留显示的数据数组。
348
+
349
+ ---
350
+
351
+ ## 五、聚合图层(`layer-utils.ts`)
352
+
353
+ ### `createClusterLayer(dataList, config)`
97
354
 
98
355
  ```ts
99
- import { emitter } from 'map-ol-utils'
356
+ function createClusterLayer(dataList: ClusterData[], config: ClusterConfig): VectorLayer
100
357
 
101
- emitter.on('selected-feature', (data) => {
102
- console.log('选中要素:', data)
358
+ type ClusterData = {
359
+ _uuid: string
360
+ name: string
361
+ style: number
362
+ lnglat: number[]
363
+ rawData: Record<string, any>
364
+ }
365
+ type ClusterConfig = {
366
+ distance: number
367
+ minDistance: number
368
+ singleStyles: Style[]
369
+ layerName?: string
370
+ openClick?: boolean
371
+ computedRadius?: (size: number) => number
372
+ buildStyle?: (feature: FeatureLike) => Style
373
+ }
374
+ ```
375
+
376
+ 未传 `buildStyle` 时使用内置样式:聚合点半径与色相(`hsla`)随聚合数量变化;`size === 1` 时使用 `singleStyles`。
377
+
378
+ ```ts
379
+ const cluster = createClusterLayer(dataList, {
380
+ distance: 80, minDistance: 20,
381
+ singleStyles: [singlePointStyle], openClick: true
103
382
  })
383
+ map.addLayer(cluster)
384
+ ```
385
+
386
+ ---
387
+
388
+ ## 六、交互与选中(`layer-utils.ts`)
389
+
390
+ ### `createSelectByLayer(vectorLayer)`
391
+
392
+ 为指定图层创建 `ol/interaction/Select`(单击、`multi: false`、`hitTolerance: 10`),命中要素时切换激活样式并派发 `selected-feature` 事件,支持聚合图层单点展开。交互会写入图层属性 `_selectInteraction`。
393
+
394
+ ```ts
395
+ function createSelectByLayer(vectorLayer: VectorLayer): Select
396
+ ```
397
+
398
+ ### `activeFeatureByUid(uid)`
399
+
400
+ ```ts
401
+ function activeFeatureByUid(uid: string): void
104
402
  ```
105
403
 
106
- | 事件名 | 触发时机 | 回调参数 |
107
- |--------|----------|----------|
108
- | `selected-feature` | 点击选中要素 | feature properties |
109
- | `dynamic-marker` | 选中动态标注点 | marker data |
404
+ 在带 `_isVectorLayer` 且其 `_uuidSet` 含该 `uid` 的图层中,程序化触发对应要素的选中(派发 select 事件并加入选中集合)。
405
+
406
+ ### `resetActiveFeature()` / `resetActiveVector()`
407
+
408
+ ```ts
409
+ function resetActiveFeature(): void // 清空 overlay + 触发各矢量图层 deselect
410
+ function resetActiveVector(): void // 清空 overlay + 清空各图层选择交互的要素集合
411
+ ```
412
+
413
+ ---
414
+
415
+ ## 七、覆盖物与视野(`layer-utils.ts`)
416
+
417
+ ### `createOverlay(config?)`
418
+
419
+ ```ts
420
+ function createOverlay(config?: import('ol/Overlay').Options): Overlay
421
+ // 默认:{ id: 'popup-container', positioning: 'top-center' }
422
+ ```
423
+
424
+ 未显式传 `element` 时,按 `config.id` 取 `document.getElementById(id)` 作为容器。
425
+
426
+ ### `removeOverlays(key?)` / `removeAllLayers()`
427
+
428
+ ```ts
429
+ function removeOverlays(key?: string): void // 移除带指定属性键的 overlay(默认按 'position')
430
+ function removeAllLayers(): void // 移除并释放所有非底图(无 _isBaseLayer)图层 + overlay
431
+ ```
432
+
433
+ ### `createAnimationMarker(imgUrl, data)`
434
+
435
+ ```ts
436
+ function createAnimationMarker(imgUrl: string, data: MassData): void
437
+ ```
438
+
439
+ 以 `data.lnglat`(经 `data.crsForm` → `WGS84` 转换)创建动画标注 Overlay,先移除已有动画标注。`data` 中读取 `width` / `height` / `lnglat` / `crsForm`。
440
+
441
+ ### `setFitViewByCoords` / `setFitViewByGeom` / `setFitViewByLayer`
442
+
443
+ ```ts
444
+ function setFitViewByCoords(
445
+ coords: Coordinate[],
446
+ mapInstance?: CustomMap,
447
+ fitOptions?: FitOptions | AnimationOptions
448
+ ): void // 单点时 animate 到 zoom 14,多点时 fit 包围盒
449
+
450
+ function setFitViewByGeom(
451
+ geom: SimpleGeometry,
452
+ mapInstance?: CustomMap,
453
+ fitOptions?: FitOptions
454
+ ): void
455
+
456
+ function setFitViewByLayer(
457
+ layer: VectorLayer,
458
+ mapInstance?: CustomMap,
459
+ fitOptions?: FitOptions
460
+ ): void // 按图层 source 的 extent 自适应
461
+ ```
462
+
463
+ 三者默认 `padding: [50,50,50,50]`、`duration: 1000`,可由 `fitOptions` 覆盖。
464
+
465
+ ```ts
466
+ setFitViewByCoords([[120.1, 30.2], [120.3, 30.4]])
467
+ setFitViewByLayer(layer, undefined, { duration: 500 })
468
+ ```
469
+
470
+ ### `getLayersDataList()`
471
+
472
+ ```ts
473
+ function getLayersDataList(): any[]
474
+ ```
475
+
476
+ 汇总所有图层 `_dataList` 属性并 `flat(2)`,返回当前地图上的全部业务数据。
477
+
478
+ ---
479
+
480
+ ## 八、WMTS(`ogc-utils.ts`)
481
+
482
+ ### `createWmtsLayer(serverUrl)`
483
+
484
+ 柯里化函数:先传 GeoServer 服务地址,返回的方法按 `WmtsSourceOptions` 解析 GetCapabilities 并构建图层(内部缓存 capabilities,重复调用不重复请求)。
485
+
486
+ ```ts
487
+ function createWmtsLayer(
488
+ serverUrl: string
489
+ ): (config: WmtsSourceOptions) => Promise<TileLayer>
490
+
491
+ type WmtsSourceOptions = {
492
+ layerName: string // 形如 'workspace:datastore'
493
+ style?: string
494
+ format?: string // 默认 'image/png'
495
+ version?: string // 默认 '1.1.0'
496
+ matrixSet?: string // 默认 'EPSG:4326'
497
+ }
498
+ ```
499
+
500
+ ```ts
501
+ const build = createWmtsLayer('https://geoserver.example.com/geoserver')
502
+ const layer = await build({ layerName: 'ws:store', matrixSet: 'EPSG:4326' })
503
+ map.addLayer(layer)
504
+ ```
505
+
506
+ ---
507
+
508
+ ## 九、事件总线(`emitter`)
509
+
510
+ ```ts
511
+ import { emitter } from 'map-ol-utils' // mitt 实例
512
+ ```
513
+
514
+ | 事件名 | 载荷 | 触发时机 |
515
+ |---|---|---|
516
+ | `selected-feature` | 要素属性对象 | 要素被选中(`createSelectByLayer` 内触发) |
517
+ | `dynamic-marker` | 动画标注配置 | 选中动态图层(`_isDynamic`)要素 1s 后 |
518
+
519
+ ---
520
+
521
+ ## 十、类型定义(`types.ts`,`export * from './types'`)
522
+
523
+ ```ts
524
+ interface CustomMap extends OlMap {
525
+ activeBaseLayer?: string
526
+ changeBaseLayer?: () => void
527
+ getLayerByName?: (name: string) => Layer<Source> | undefined
528
+ removeLayerByName?: (name: string) => void
529
+ changeLayersByNames?: (activeNames: string[], allLayerNames: string[]) => void
530
+ }
531
+
532
+ type MassData = {
533
+ _uuid?: string
534
+ id: string
535
+ style: number
536
+ name: string
537
+ status: string
538
+ width?: number
539
+ height?: number
540
+ crsForm?: CRSTypes
541
+ rawData: Record<string, any>
542
+ lnglat: [string, string] | [number, number]
543
+ }
544
+
545
+ enum GeometryType {
546
+ LineString = 'LineString',
547
+ MultiLineString = 'MultiLineString',
548
+ Polygon = 'Polygon',
549
+ MultiPolygon = 'MultiPolygon',
550
+ Invalid = 'Invalid'
551
+ }
552
+ ```
553
+
554
+ 完整导出还包括:`VectorConfig`、`ClusterConfig`、`ClusterData`、`IconConfig`、`WmtsSourceOptions`、`GetImgUrl`、`GetImgUrlFn`、`HzsyType`、`ZheJiangType`、`WorldLayerType`、`GeometryCoordinates`。
555
+
556
+ ---
557
+
558
+ ## 图层约定属性
559
+
560
+ 工具库通过图层 properties 标记元信息,维护时请保持一致:`_isBaseLayer`、`_layerName`、`_isCustom`、`_isVectorLayer`、`_isClusterLayer`、`_isMassMarksLayer`、`_selectInteraction`、`_uuidSet`、`_dataList`、`_vectorConfig`、`_isAutoFit`、`_massMarksStyles`、`_statusNum`。
561
+
562
+ ## 构建
563
+
564
+ ```bash
565
+ pnpm --dir packages/map-utils build # tsup 产出 esm + cjs + d.ts
566
+ pnpm --dir packages/map-utils dev # watch 模式
567
+ ```
568
+
569
+ ## 注意事项
570
+
571
+ - **单例副作用**:绝大多数函数依赖模块级 `instance`,请先 `createMapInstance` / `createMap` 再调用其他工具;`disposeMap` 后 `instance` 为 `undefined`。
572
+ - **坐标系**:输入数据可通过 `config.crsForm` / `data.crsForm` 指定源坐标系,内部统一转为 `WGS84`。
573
+ - **天地图令牌**:`createMapWorldLayer` / `createZheJiangLayer` 内置了默认 `tk`,正式项目请传入自有令牌。