@3clear/basegis 0.1.0
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 +972 -0
- package/dist/assets.js +4 -0
- package/dist/basegis.js +6883 -0
- package/dist/layers.js +94 -0
- package/dist/methods.js +2204 -0
- package/dist/result-D03zgqh0.js +39 -0
- package/dist/style.css +1 -0
- package/package.json +44 -0
package/README.md
ADDED
|
@@ -0,0 +1,972 @@
|
|
|
1
|
+
# @3clear/basegis
|
|
2
|
+
|
|
3
|
+
`@3clear/basegis` 是 3clear 一张图项目抽出的 GIS 能力包。它提供一个统一入口 `BaseGIS`,把 Cesium / Leaflet 的差异收敛到适配层里;业务页面优先只操作 `BaseGIS`,复杂图层能力通过 `methods` 控制器组合 `BaseGIS` 公共方法完成。
|
|
4
|
+
|
|
5
|
+
当前包包含:
|
|
6
|
+
|
|
7
|
+
- `BaseGIS`:地图初始化、引擎切换、视角控制、底图切换、绘制、图层显隐、DEM、点击事件等基础能力。
|
|
8
|
+
- `methods`:图片图层、网格图层、海量点、点位抽稀、等值线、等压线、风场、图形组等高级控制器。
|
|
9
|
+
- `layers`:天地图、GeoServer 金字塔瓦片、WMS、WMTS 图层配置快捷构造器。
|
|
10
|
+
- `assets`:GIS 示例资源。
|
|
11
|
+
- `style.css`:Leaflet、GIS 图层和标注相关基础样式。
|
|
12
|
+
|
|
13
|
+
## 安装
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm install @3clear/basegis leaflet axios pixi.js leaflet-pixi-overlay
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
使用样式:
|
|
20
|
+
|
|
21
|
+
```js
|
|
22
|
+
import '@3clear/basegis/style.css'
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Cesium 当前不随 npm 包发布,宿主项目需要按原项目方式把 Cesium 静态资源放到 `public/lib/Cesium`,并保证初始化前能访问 `window.Cesium`。默认配置会从 `${BASE_URL}lib/Cesium/Cesium.js` 和 `${BASE_URL}lib/Cesium/Widgets/widgets.css` 加载。
|
|
26
|
+
|
|
27
|
+
如果需要加载 GeoTIFF 网格,需要宿主项目提前提供 `window.GeoTIFF`。
|
|
28
|
+
|
|
29
|
+
## 出口
|
|
30
|
+
|
|
31
|
+
```js
|
|
32
|
+
// 主入口
|
|
33
|
+
import { BaseGIS } from '@3clear/basegis'
|
|
34
|
+
|
|
35
|
+
// 高级能力控制器
|
|
36
|
+
import {
|
|
37
|
+
GraphicGroupController,
|
|
38
|
+
ImageLayerController,
|
|
39
|
+
GridLayerController,
|
|
40
|
+
PointLargeLayerController,
|
|
41
|
+
PointDensityController,
|
|
42
|
+
ContourLayerController,
|
|
43
|
+
PressureContourLayer,
|
|
44
|
+
createPressureDataResolver,
|
|
45
|
+
buildPressureRenderData,
|
|
46
|
+
WindFieldMethods,
|
|
47
|
+
} from '@3clear/basegis/methods'
|
|
48
|
+
|
|
49
|
+
// 图层配置构造器
|
|
50
|
+
import {
|
|
51
|
+
createTiandituLayer,
|
|
52
|
+
createGeoserverPyramidLayer,
|
|
53
|
+
createWmsLayer,
|
|
54
|
+
createWmtsLayer,
|
|
55
|
+
} from '@3clear/basegis/layers'
|
|
56
|
+
|
|
57
|
+
// 示例资源
|
|
58
|
+
import { gisMarkerSample } from '@3clear/basegis/assets'
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## 快速开始
|
|
62
|
+
|
|
63
|
+
```vue
|
|
64
|
+
<template>
|
|
65
|
+
<div id="map" class="map"></div>
|
|
66
|
+
</template>
|
|
67
|
+
|
|
68
|
+
<script setup>
|
|
69
|
+
import { onBeforeUnmount, onMounted } from 'vue'
|
|
70
|
+
import { BaseGIS } from '@3clear/basegis'
|
|
71
|
+
import '@3clear/basegis/style.css'
|
|
72
|
+
|
|
73
|
+
let mapCore = null
|
|
74
|
+
|
|
75
|
+
onMounted(() => {
|
|
76
|
+
mapCore = new BaseGIS({
|
|
77
|
+
// 可选 cesium / leaflet。不传时使用默认配置 active: 'cesium'。
|
|
78
|
+
engineType: 'cesium',
|
|
79
|
+
// 也可以传 container: HTMLElement。
|
|
80
|
+
containerId: 'map',
|
|
81
|
+
config: {
|
|
82
|
+
view: {
|
|
83
|
+
// 可选 2d / 2.5d / 3d。
|
|
84
|
+
defaultSceneMode: '3d',
|
|
85
|
+
initialView: {
|
|
86
|
+
center: [104, 35],
|
|
87
|
+
// Cesium 使用 height,Leaflet 使用 zoom。
|
|
88
|
+
height: 5000000,
|
|
89
|
+
zoom: 5,
|
|
90
|
+
// Cesium 默认保持垂直俯视。
|
|
91
|
+
pitch: -90,
|
|
92
|
+
},
|
|
93
|
+
},
|
|
94
|
+
},
|
|
95
|
+
})
|
|
96
|
+
|
|
97
|
+
const result = mapCore.init()
|
|
98
|
+
if (!result.success) {
|
|
99
|
+
console.warn(result.message)
|
|
100
|
+
}
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
onBeforeUnmount(() => {
|
|
104
|
+
mapCore?.destroy()
|
|
105
|
+
})
|
|
106
|
+
</script>
|
|
107
|
+
|
|
108
|
+
<style scoped>
|
|
109
|
+
.map {
|
|
110
|
+
width: 100%;
|
|
111
|
+
height: 100%;
|
|
112
|
+
}
|
|
113
|
+
</style>
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## 返回值约定
|
|
117
|
+
|
|
118
|
+
多数方法返回统一结果对象:
|
|
119
|
+
|
|
120
|
+
```js
|
|
121
|
+
{
|
|
122
|
+
success: true,
|
|
123
|
+
message: 'operation message',
|
|
124
|
+
data: {}
|
|
125
|
+
}
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
失败时:
|
|
129
|
+
|
|
130
|
+
```js
|
|
131
|
+
{
|
|
132
|
+
success: false,
|
|
133
|
+
message: 'error message',
|
|
134
|
+
code: 'NOT_INITIALIZED'
|
|
135
|
+
}
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Leaflet 不支持 3D、DEM 等能力时,会返回失败结果或控制台提示,不应直接打断页面。
|
|
139
|
+
|
|
140
|
+
## BaseGIS 配置
|
|
141
|
+
|
|
142
|
+
```js
|
|
143
|
+
const mapCore = new BaseGIS({
|
|
144
|
+
engineType: 'cesium',
|
|
145
|
+
containerId: 'map',
|
|
146
|
+
config: {
|
|
147
|
+
engine: {
|
|
148
|
+
active: 'cesium',
|
|
149
|
+
cesium: {
|
|
150
|
+
// 本地 Cesium 静态资源地址。
|
|
151
|
+
scriptUrl: '/lib/Cesium/Cesium.js',
|
|
152
|
+
cssUrl: '/lib/Cesium/Widgets/widgets.css',
|
|
153
|
+
},
|
|
154
|
+
leaflet: {
|
|
155
|
+
sourceType: 'npm',
|
|
156
|
+
},
|
|
157
|
+
},
|
|
158
|
+
view: {
|
|
159
|
+
defaultSceneMode: '3d',
|
|
160
|
+
initialView: {
|
|
161
|
+
center: [121.4737, 31.2304],
|
|
162
|
+
height: 1800000,
|
|
163
|
+
zoom: 7,
|
|
164
|
+
heading: 0,
|
|
165
|
+
pitch: -90,
|
|
166
|
+
roll: 0,
|
|
167
|
+
},
|
|
168
|
+
},
|
|
169
|
+
basemap: {
|
|
170
|
+
defaultVisibleId: 'tianditu-imagery',
|
|
171
|
+
defaultAnnotationId: 'tianditu-vector-label',
|
|
172
|
+
list: [],
|
|
173
|
+
},
|
|
174
|
+
dem: {
|
|
175
|
+
defaultEnabled: true,
|
|
176
|
+
defaultVisibleId: 'ellipsoid-flat',
|
|
177
|
+
list: [],
|
|
178
|
+
},
|
|
179
|
+
},
|
|
180
|
+
})
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
说明:
|
|
184
|
+
|
|
185
|
+
- `containerId` 和 `container` 二选一即可;`init()` 时也可以再次传入。
|
|
186
|
+
- 页面传入的 `config` 会覆盖内置默认配置。
|
|
187
|
+
- Cesium 默认视角 `pitch: -90`,表示垂直俯视。
|
|
188
|
+
- `BaseGIS` 只保存运行时配置,调用 `setConfig()` 不会自动重建地图,需要重新 `init()` 才会创建新地图实例。
|
|
189
|
+
|
|
190
|
+
## BaseGIS 基础能力
|
|
191
|
+
|
|
192
|
+
### 生命周期与实例
|
|
193
|
+
|
|
194
|
+
```js
|
|
195
|
+
mapCore.init({ containerId: 'map', engineType: 'leaflet' })
|
|
196
|
+
mapCore.destroy()
|
|
197
|
+
|
|
198
|
+
mapCore.setEngine('cesium')
|
|
199
|
+
mapCore.setConfig({ view: { defaultSceneMode: '2d' } })
|
|
200
|
+
|
|
201
|
+
mapCore.getEngineType()
|
|
202
|
+
mapCore.getConfig()
|
|
203
|
+
mapCore.getMapInstance()
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
### 视角与场景
|
|
207
|
+
|
|
208
|
+
```js
|
|
209
|
+
mapCore.zoomIn()
|
|
210
|
+
mapCore.zoomOut()
|
|
211
|
+
mapCore.resetView()
|
|
212
|
+
|
|
213
|
+
mapCore.setSceneMode('2d')
|
|
214
|
+
mapCore.setSceneMode('2.5d')
|
|
215
|
+
mapCore.setSceneMode('3d')
|
|
216
|
+
mapCore.getSceneMode()
|
|
217
|
+
|
|
218
|
+
mapCore.setInitialView({
|
|
219
|
+
center: [104, 35],
|
|
220
|
+
height: 3000000,
|
|
221
|
+
zoom: 5,
|
|
222
|
+
pitch: -90,
|
|
223
|
+
})
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
### 底图与普通图层
|
|
227
|
+
|
|
228
|
+
```js
|
|
229
|
+
mapCore.setBasemapById('tianditu-imagery')
|
|
230
|
+
|
|
231
|
+
mapCore.setBasemap({
|
|
232
|
+
id: 'custom-wmts',
|
|
233
|
+
name: '自定义 WMTS',
|
|
234
|
+
type: 'wmts',
|
|
235
|
+
provider: 'custom',
|
|
236
|
+
url: 'https://example.com/wmts?...',
|
|
237
|
+
})
|
|
238
|
+
|
|
239
|
+
mapCore.addLayer(layerConfig)
|
|
240
|
+
mapCore.showLayer({ layerId: 'custom-wmts' })
|
|
241
|
+
mapCore.hideLayer({ layerId: 'custom-wmts' })
|
|
242
|
+
mapCore.removeLayer({ layerId: 'custom-wmts' })
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
### 点线面文字
|
|
246
|
+
|
|
247
|
+
```js
|
|
248
|
+
mapCore.drawPoint({
|
|
249
|
+
id: 'point-1',
|
|
250
|
+
longitude: 104,
|
|
251
|
+
latitude: 35,
|
|
252
|
+
style: {
|
|
253
|
+
color: '#ff4d4f',
|
|
254
|
+
pixelSize: 10,
|
|
255
|
+
},
|
|
256
|
+
})
|
|
257
|
+
|
|
258
|
+
mapCore.drawLine({
|
|
259
|
+
id: 'line-1',
|
|
260
|
+
positions: [
|
|
261
|
+
[103, 34],
|
|
262
|
+
[105, 36],
|
|
263
|
+
],
|
|
264
|
+
style: {
|
|
265
|
+
color: '#1677ff',
|
|
266
|
+
width: 3,
|
|
267
|
+
},
|
|
268
|
+
})
|
|
269
|
+
|
|
270
|
+
mapCore.drawPolygon({
|
|
271
|
+
id: 'polygon-1',
|
|
272
|
+
positions: [
|
|
273
|
+
[102, 33],
|
|
274
|
+
[106, 33],
|
|
275
|
+
[106, 36],
|
|
276
|
+
[102, 36],
|
|
277
|
+
],
|
|
278
|
+
style: {
|
|
279
|
+
color: 'rgba(22, 119, 255, 0.25)',
|
|
280
|
+
outlineColor: '#1677ff',
|
|
281
|
+
},
|
|
282
|
+
})
|
|
283
|
+
|
|
284
|
+
mapCore.drawText({
|
|
285
|
+
id: 'text-1',
|
|
286
|
+
longitude: 104,
|
|
287
|
+
latitude: 35,
|
|
288
|
+
text: '示例文字',
|
|
289
|
+
style: {
|
|
290
|
+
color: '#ffffff',
|
|
291
|
+
font: '14px sans-serif',
|
|
292
|
+
},
|
|
293
|
+
})
|
|
294
|
+
|
|
295
|
+
mapCore.addMarker({
|
|
296
|
+
id: 'marker-1',
|
|
297
|
+
longitude: 104,
|
|
298
|
+
latitude: 35,
|
|
299
|
+
image: '/marker.png',
|
|
300
|
+
width: 32,
|
|
301
|
+
height: 32,
|
|
302
|
+
})
|
|
303
|
+
|
|
304
|
+
mapCore.removeGraphic({ id: 'marker-1' })
|
|
305
|
+
mapCore.clearGraphics()
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
### 点击事件与投影
|
|
309
|
+
|
|
310
|
+
```js
|
|
311
|
+
const clickResult = mapCore.onClick({
|
|
312
|
+
id: 'station-click',
|
|
313
|
+
callback(event) {
|
|
314
|
+
// event 中通常包含 longitude / latitude / pickedObject 等信息,具体字段与引擎有关。
|
|
315
|
+
console.log(event)
|
|
316
|
+
},
|
|
317
|
+
})
|
|
318
|
+
|
|
319
|
+
mapCore.offClick({ id: 'station-click' })
|
|
320
|
+
|
|
321
|
+
const point = mapCore.projectToContainerPoint({
|
|
322
|
+
longitude: 104,
|
|
323
|
+
latitude: 35,
|
|
324
|
+
height: 0,
|
|
325
|
+
})
|
|
326
|
+
|
|
327
|
+
const bounds = mapCore.getViewBounds()
|
|
328
|
+
const viewListener = mapCore.onViewChange({
|
|
329
|
+
onStart() {},
|
|
330
|
+
onEnd() {},
|
|
331
|
+
})
|
|
332
|
+
viewListener.data?.off?.()
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
### DEM
|
|
336
|
+
|
|
337
|
+
```js
|
|
338
|
+
mapCore.loadDefaultDEM()
|
|
339
|
+
mapCore.loadDEMById('ellipsoid-flat')
|
|
340
|
+
mapCore.loadDEM({
|
|
341
|
+
id: 'custom-dem',
|
|
342
|
+
sourceType: 'url',
|
|
343
|
+
url: 'https://example.com/terrain',
|
|
344
|
+
options: {},
|
|
345
|
+
})
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
DEM 当前主要面向 Cesium;Leaflet 调用会返回不支持结果。
|
|
349
|
+
|
|
350
|
+
## 图层构造器
|
|
351
|
+
|
|
352
|
+
构造器只返回标准配置对象,通常传给 `config.basemap.list` 或 `mapCore.addLayer()`。
|
|
353
|
+
|
|
354
|
+
```js
|
|
355
|
+
import {
|
|
356
|
+
createTiandituLayer,
|
|
357
|
+
createGeoserverPyramidLayer,
|
|
358
|
+
createWmsLayer,
|
|
359
|
+
createWmtsLayer,
|
|
360
|
+
} from '@3clear/basegis/layers'
|
|
361
|
+
|
|
362
|
+
const tianditu = createTiandituLayer({
|
|
363
|
+
id: 'tdt-img',
|
|
364
|
+
name: '天地图影像',
|
|
365
|
+
resourceKey: 'imagery',
|
|
366
|
+
category: 'basemap',
|
|
367
|
+
engineSupport: ['cesium', 'leaflet'],
|
|
368
|
+
})
|
|
369
|
+
|
|
370
|
+
const geoserverTile = createGeoserverPyramidLayer({
|
|
371
|
+
id: 'geoserver-tile',
|
|
372
|
+
name: 'GeoServer 瓦片',
|
|
373
|
+
url: 'https://example.com/tiles/{z}/{x}/{y}.png',
|
|
374
|
+
})
|
|
375
|
+
|
|
376
|
+
const wms = createWmsLayer({
|
|
377
|
+
id: 'wms-layer',
|
|
378
|
+
serviceUrl: 'https://example.com/geoserver/wms',
|
|
379
|
+
layers: 'workspace:layer',
|
|
380
|
+
parameters: {
|
|
381
|
+
transparent: true,
|
|
382
|
+
format: 'image/png',
|
|
383
|
+
},
|
|
384
|
+
})
|
|
385
|
+
|
|
386
|
+
const wmts = createWmtsLayer({
|
|
387
|
+
id: 'wmts-layer',
|
|
388
|
+
url: 'https://example.com/wmts?...TILEMATRIX={z}&TILEROW={y}&TILECOL={x}',
|
|
389
|
+
layer: 'workspace:layer',
|
|
390
|
+
tileMatrixSet: 'EPSG:3857',
|
|
391
|
+
})
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
## GraphicGroupController
|
|
395
|
+
|
|
396
|
+
用于一次性加载一组点、线、面、文字、marker。它只调用 `BaseGIS.drawPoint / drawLine / drawPolygon / drawText / addMarker`。
|
|
397
|
+
|
|
398
|
+
```js
|
|
399
|
+
import { GraphicGroupController } from '@3clear/basegis/methods'
|
|
400
|
+
|
|
401
|
+
const graphics = new GraphicGroupController({ mapCore })
|
|
402
|
+
|
|
403
|
+
graphics.load([
|
|
404
|
+
{
|
|
405
|
+
type: 'point',
|
|
406
|
+
id: 'p1',
|
|
407
|
+
longitude: 104,
|
|
408
|
+
latitude: 35,
|
|
409
|
+
},
|
|
410
|
+
{
|
|
411
|
+
type: 'line',
|
|
412
|
+
id: 'l1',
|
|
413
|
+
positions: [
|
|
414
|
+
[103, 34],
|
|
415
|
+
[105, 36],
|
|
416
|
+
],
|
|
417
|
+
},
|
|
418
|
+
{
|
|
419
|
+
type: 'text',
|
|
420
|
+
id: 't1',
|
|
421
|
+
longitude: 104,
|
|
422
|
+
latitude: 35,
|
|
423
|
+
text: '站点',
|
|
424
|
+
},
|
|
425
|
+
])
|
|
426
|
+
|
|
427
|
+
graphics.clear()
|
|
428
|
+
graphics.getState()
|
|
429
|
+
```
|
|
430
|
+
|
|
431
|
+
## ImageLayerController
|
|
432
|
+
|
|
433
|
+
用于加载图片覆盖层或 TIF 图片集合,并提供上一张、下一张、显隐和销毁能力。
|
|
434
|
+
|
|
435
|
+
```js
|
|
436
|
+
import { ImageLayerController } from '@3clear/basegis/methods'
|
|
437
|
+
|
|
438
|
+
const imageLayer = new ImageLayerController({
|
|
439
|
+
mapCore,
|
|
440
|
+
layerId: 'radar-image',
|
|
441
|
+
opacity: 0.85,
|
|
442
|
+
defaultArea: {
|
|
443
|
+
startLon: 73,
|
|
444
|
+
startLat: 18,
|
|
445
|
+
endLon: 135,
|
|
446
|
+
endLat: 54,
|
|
447
|
+
},
|
|
448
|
+
})
|
|
449
|
+
|
|
450
|
+
await imageLayer.load([
|
|
451
|
+
{
|
|
452
|
+
id: 'radar-001',
|
|
453
|
+
name: '雷达 001',
|
|
454
|
+
imageUrl: '/data/radar/001.png',
|
|
455
|
+
area: {
|
|
456
|
+
startLon: 73,
|
|
457
|
+
startLat: 18,
|
|
458
|
+
endLon: 135,
|
|
459
|
+
endLat: 54,
|
|
460
|
+
},
|
|
461
|
+
opacity: 0.8,
|
|
462
|
+
},
|
|
463
|
+
{
|
|
464
|
+
id: 'tif-001',
|
|
465
|
+
name: 'TIF 001',
|
|
466
|
+
tifUrl: '/data/grid/001.tif',
|
|
467
|
+
colorize: true,
|
|
468
|
+
},
|
|
469
|
+
])
|
|
470
|
+
|
|
471
|
+
await imageLayer.switchTo('radar-001')
|
|
472
|
+
await imageLayer.next()
|
|
473
|
+
await imageLayer.prev()
|
|
474
|
+
imageLayer.hide()
|
|
475
|
+
imageLayer.show()
|
|
476
|
+
imageLayer.destroy()
|
|
477
|
+
```
|
|
478
|
+
|
|
479
|
+
常用字段:
|
|
480
|
+
|
|
481
|
+
- `imageUrl`:普通图片地址。
|
|
482
|
+
- `tifUrl`:GeoTIFF 地址。
|
|
483
|
+
- `area`:图片四至范围,字段为 `startLon / startLat / endLon / endLat`。
|
|
484
|
+
- `opacity`:透明度。
|
|
485
|
+
- `showLabel / showProbe`:显示网格标注或探针。
|
|
486
|
+
- `colorize / colorStops / colors`:色带渲染配置。
|
|
487
|
+
|
|
488
|
+
## GridLayerController
|
|
489
|
+
|
|
490
|
+
用于 TIF 网格、灰度图网格、外部数值网格。
|
|
491
|
+
|
|
492
|
+
```js
|
|
493
|
+
import { GridLayerController } from '@3clear/basegis/methods'
|
|
494
|
+
|
|
495
|
+
const gridLayer = new GridLayerController({
|
|
496
|
+
mapCore,
|
|
497
|
+
layerId: 'temperature-grid',
|
|
498
|
+
showLabel: true,
|
|
499
|
+
showProbe: true,
|
|
500
|
+
decimalPlaces: 1,
|
|
501
|
+
})
|
|
502
|
+
|
|
503
|
+
await gridLayer.loadTif({
|
|
504
|
+
tifUrl: '/data/grid/temp.tif',
|
|
505
|
+
colorize: true,
|
|
506
|
+
})
|
|
507
|
+
|
|
508
|
+
await gridLayer.loadGrayImage({
|
|
509
|
+
imageUrl: '/data/grid/temp-gray.png',
|
|
510
|
+
area: {
|
|
511
|
+
startLon: 73,
|
|
512
|
+
startLat: 18,
|
|
513
|
+
endLon: 135,
|
|
514
|
+
endLat: 54,
|
|
515
|
+
},
|
|
516
|
+
colorize: true,
|
|
517
|
+
})
|
|
518
|
+
|
|
519
|
+
await gridLayer.loadData({
|
|
520
|
+
imageGridData: [
|
|
521
|
+
[12.1, 13.4],
|
|
522
|
+
[14.2, 15.6],
|
|
523
|
+
],
|
|
524
|
+
area: {
|
|
525
|
+
startLon: 100,
|
|
526
|
+
startLat: 30,
|
|
527
|
+
endLon: 110,
|
|
528
|
+
endLat: 40,
|
|
529
|
+
},
|
|
530
|
+
})
|
|
531
|
+
|
|
532
|
+
gridLayer.update({ opacity: 0.7 })
|
|
533
|
+
gridLayer.hide()
|
|
534
|
+
gridLayer.show()
|
|
535
|
+
gridLayer.destroy()
|
|
536
|
+
```
|
|
537
|
+
|
|
538
|
+
## PointLargeLayerController
|
|
539
|
+
|
|
540
|
+
用于海量点位渲染,支持显隐、高亮、删除单点、批量删除、清空和状态读取。
|
|
541
|
+
|
|
542
|
+
```js
|
|
543
|
+
import { PointLargeLayerController } from '@3clear/basegis/methods'
|
|
544
|
+
|
|
545
|
+
const largePoints = new PointLargeLayerController({
|
|
546
|
+
mapCore,
|
|
547
|
+
layerId: 'station-large',
|
|
548
|
+
idKey: 'staNum',
|
|
549
|
+
image: '/icons/station.png',
|
|
550
|
+
width: 24,
|
|
551
|
+
height: 24,
|
|
552
|
+
onClick(point) {
|
|
553
|
+
console.log('点击站点', point)
|
|
554
|
+
},
|
|
555
|
+
})
|
|
556
|
+
|
|
557
|
+
await largePoints.load({
|
|
558
|
+
points: [
|
|
559
|
+
{ staNum: 'A001', longitude: 104, latitude: 35, name: 'A001' },
|
|
560
|
+
{ staNum: 'A002', longitude: 105, latitude: 36, name: 'A002' },
|
|
561
|
+
],
|
|
562
|
+
})
|
|
563
|
+
|
|
564
|
+
largePoints.setHighlight('A001')
|
|
565
|
+
largePoints.clearHighlight()
|
|
566
|
+
largePoints.removePoint('A002')
|
|
567
|
+
largePoints.removePoints(['A001', 'A003'])
|
|
568
|
+
largePoints.hide()
|
|
569
|
+
largePoints.show()
|
|
570
|
+
largePoints.clear()
|
|
571
|
+
largePoints.destroy()
|
|
572
|
+
largePoints.getState()
|
|
573
|
+
```
|
|
574
|
+
|
|
575
|
+
点位字段默认支持:
|
|
576
|
+
|
|
577
|
+
- 经度:`longitude / lon / lng / x`
|
|
578
|
+
- 纬度:`latitude / lat / y`
|
|
579
|
+
- 高度:`height / altitude / z`
|
|
580
|
+
- 唯一值:默认 `id`,可通过 `idKey` 指定
|
|
581
|
+
|
|
582
|
+
## PointDensityController
|
|
583
|
+
|
|
584
|
+
用于点位密度抽稀。地图移动、缩放后按屏幕网格重新计算可见点,适合站点、设备、告警等高密度点位。
|
|
585
|
+
|
|
586
|
+
```js
|
|
587
|
+
import { PointDensityController } from '@3clear/basegis/methods'
|
|
588
|
+
|
|
589
|
+
const density = new PointDensityController({
|
|
590
|
+
mapCore,
|
|
591
|
+
layerId: 'station-density',
|
|
592
|
+
idKey: 'staNum',
|
|
593
|
+
gridSize: 150,
|
|
594
|
+
maxCount: 500,
|
|
595
|
+
priorityKey: 'level',
|
|
596
|
+
image: '/icons/station.png',
|
|
597
|
+
width: 28,
|
|
598
|
+
height: 28,
|
|
599
|
+
onClick(point) {
|
|
600
|
+
console.log(point)
|
|
601
|
+
},
|
|
602
|
+
onStateChange(state) {
|
|
603
|
+
console.log(state.visibleCount, state.hiddenCount)
|
|
604
|
+
},
|
|
605
|
+
})
|
|
606
|
+
|
|
607
|
+
await density.load({
|
|
608
|
+
points: [
|
|
609
|
+
{ staNum: 'A001', longitude: 104, latitude: 35, level: 5 },
|
|
610
|
+
{ staNum: 'A002', longitude: 104.01, latitude: 35.01, level: 3 },
|
|
611
|
+
],
|
|
612
|
+
})
|
|
613
|
+
|
|
614
|
+
density.update({ gridSize: 120 })
|
|
615
|
+
density.hide()
|
|
616
|
+
density.show()
|
|
617
|
+
density.toggle()
|
|
618
|
+
density.refreshState()
|
|
619
|
+
density.clear()
|
|
620
|
+
density.destroy()
|
|
621
|
+
```
|
|
622
|
+
|
|
623
|
+
常用参数:
|
|
624
|
+
|
|
625
|
+
- `enableThinning`:是否开启抽稀,默认开启。
|
|
626
|
+
- `gridSize / pixelRange`:屏幕网格大小,单位像素。
|
|
627
|
+
- `maxCount`:最多显示点数。
|
|
628
|
+
- `priorityKey / priorityCallback`:同网格内优先显示哪个点。
|
|
629
|
+
- `viewportBuffer`:Cesium 屏幕视野缓冲。
|
|
630
|
+
- `cullByGlobe`:Cesium 3D 下是否剔除地球背面点。
|
|
631
|
+
- `boundsBufferRatio`:Leaflet bounds 扩展比例。
|
|
632
|
+
|
|
633
|
+
## ContourLayerController
|
|
634
|
+
|
|
635
|
+
用于等值线图层,支持加载、更新、显隐、清空和销毁。
|
|
636
|
+
|
|
637
|
+
```js
|
|
638
|
+
import { ContourLayerController } from '@3clear/basegis/methods'
|
|
639
|
+
|
|
640
|
+
const contour = new ContourLayerController({
|
|
641
|
+
mapCore,
|
|
642
|
+
layerId: 'temperature-contour',
|
|
643
|
+
visible: true,
|
|
644
|
+
})
|
|
645
|
+
|
|
646
|
+
await contour.load({
|
|
647
|
+
contours: [
|
|
648
|
+
{
|
|
649
|
+
value: 20,
|
|
650
|
+
lines: [
|
|
651
|
+
[
|
|
652
|
+
[30, 104],
|
|
653
|
+
[31, 105],
|
|
654
|
+
[32, 106],
|
|
655
|
+
],
|
|
656
|
+
],
|
|
657
|
+
},
|
|
658
|
+
],
|
|
659
|
+
style: {
|
|
660
|
+
color: '#ff4d4f',
|
|
661
|
+
width: 2,
|
|
662
|
+
},
|
|
663
|
+
})
|
|
664
|
+
|
|
665
|
+
await contour.update({
|
|
666
|
+
style: {
|
|
667
|
+
color: '#1677ff',
|
|
668
|
+
},
|
|
669
|
+
})
|
|
670
|
+
|
|
671
|
+
contour.hide()
|
|
672
|
+
contour.show()
|
|
673
|
+
contour.clear()
|
|
674
|
+
contour.destroy()
|
|
675
|
+
```
|
|
676
|
+
|
|
677
|
+
数据别名支持 `contours / isolines / isoline / lines / data / items`。
|
|
678
|
+
|
|
679
|
+
## PressureContourLayer
|
|
680
|
+
|
|
681
|
+
用于等压线和高低压中心标注。`buildPressureRenderData()` 可把 Windy 风格的 `press.json` 数据整理成渲染结构,`createPressureDataResolver()` 提供简单缓存。
|
|
682
|
+
|
|
683
|
+
```js
|
|
684
|
+
import {
|
|
685
|
+
PressureContourLayer,
|
|
686
|
+
createPressureDataResolver,
|
|
687
|
+
} from '@3clear/basegis/methods'
|
|
688
|
+
|
|
689
|
+
const resolvePressureData = createPressureDataResolver({
|
|
690
|
+
default: pressJson,
|
|
691
|
+
next: pressJson2,
|
|
692
|
+
})
|
|
693
|
+
|
|
694
|
+
const pressureLayer = new PressureContourLayer({
|
|
695
|
+
mapCore,
|
|
696
|
+
layerId: 'pressure',
|
|
697
|
+
color: 'rgba(255,255,255,0.82)',
|
|
698
|
+
width: 1.15,
|
|
699
|
+
smoothFactor: 0.2,
|
|
700
|
+
// Cesium 场景下用于定位容器尺寸,Leaflet 场景也可以传同一个地图容器 id。
|
|
701
|
+
mapContainerId: 'map',
|
|
702
|
+
// 标注层通过该函数读取当前数据,便于地图缩放后重建标签。
|
|
703
|
+
getData: () => resolvePressureData('default'),
|
|
704
|
+
isAnnotationVisible: () => true,
|
|
705
|
+
})
|
|
706
|
+
|
|
707
|
+
pressureLayer.mount()
|
|
708
|
+
await pressureLayer.load(resolvePressureData('default'))
|
|
709
|
+
await pressureLayer.update(resolvePressureData('next'))
|
|
710
|
+
pressureLayer.hide()
|
|
711
|
+
pressureLayer.destroy()
|
|
712
|
+
```
|
|
713
|
+
|
|
714
|
+
说明:
|
|
715
|
+
|
|
716
|
+
- 等压线数据会被整理为 `isolines` 和 `centers`。
|
|
717
|
+
- Leaflet 使用 `divIcon` 绘制 H/L 中心和线值标签。
|
|
718
|
+
- Cesium 使用独立标注集合,地图变化时会调度刷新。
|
|
719
|
+
|
|
720
|
+
## WindFieldMethods
|
|
721
|
+
|
|
722
|
+
用于叠加 Canvas 风场粒子动画。它通过 `BaseGIS` 获取容器、投影、视野范围和视图变化事件,不直接依赖某个引擎。
|
|
723
|
+
|
|
724
|
+
```js
|
|
725
|
+
import { WindFieldMethods } from '@3clear/basegis/methods'
|
|
726
|
+
|
|
727
|
+
const wind = new WindFieldMethods({ mapCore })
|
|
728
|
+
|
|
729
|
+
wind.addWindField({
|
|
730
|
+
id: 'wind-main',
|
|
731
|
+
data: windData,
|
|
732
|
+
particleCount: 3000,
|
|
733
|
+
velocityScale: 0.01,
|
|
734
|
+
lineWidth: 1,
|
|
735
|
+
color: 'rgba(80, 180, 255, 0.8)',
|
|
736
|
+
})
|
|
737
|
+
|
|
738
|
+
wind.updateWindField({
|
|
739
|
+
id: 'wind-main',
|
|
740
|
+
particleCount: 5000,
|
|
741
|
+
})
|
|
742
|
+
|
|
743
|
+
wind.stopWindField('wind-main')
|
|
744
|
+
wind.startWindField('wind-main')
|
|
745
|
+
wind.hideWindField('wind-main')
|
|
746
|
+
wind.showWindField('wind-main')
|
|
747
|
+
wind.removeWindField('wind-main')
|
|
748
|
+
wind.clearWindFields()
|
|
749
|
+
wind.getState()
|
|
750
|
+
```
|
|
751
|
+
|
|
752
|
+
## 直接使用 BaseGIS 图层方法
|
|
753
|
+
|
|
754
|
+
控制器适合页面长期维护状态。如果只是一次调用,也可以直接用 `BaseGIS` 方法。
|
|
755
|
+
|
|
756
|
+
```js
|
|
757
|
+
await mapCore.upsertImageLayer({
|
|
758
|
+
layerId: 'image-layer',
|
|
759
|
+
imageUrl: '/data/image.png',
|
|
760
|
+
area: {
|
|
761
|
+
startLon: 73,
|
|
762
|
+
startLat: 18,
|
|
763
|
+
endLon: 135,
|
|
764
|
+
endLat: 54,
|
|
765
|
+
},
|
|
766
|
+
})
|
|
767
|
+
mapCore.hideImageLayer({ layerId: 'image-layer' })
|
|
768
|
+
mapCore.showImageLayer({ layerId: 'image-layer' })
|
|
769
|
+
mapCore.removeImageLayer({ layerId: 'image-layer' })
|
|
770
|
+
|
|
771
|
+
await mapCore.upsertGridLayer({
|
|
772
|
+
layerId: 'grid-layer',
|
|
773
|
+
tifUrl: '/data/grid.tif',
|
|
774
|
+
})
|
|
775
|
+
mapCore.removeGridLayer({ layerId: 'grid-layer' })
|
|
776
|
+
|
|
777
|
+
await mapCore.upsertPointLargeLayer({
|
|
778
|
+
layerId: 'large-points',
|
|
779
|
+
points: [{ id: '1', longitude: 104, latitude: 35 }],
|
|
780
|
+
})
|
|
781
|
+
mapCore.setPointLargeHighlight({ layerId: 'large-points', pointId: '1' })
|
|
782
|
+
mapCore.clearPointLargeHighlight({ layerId: 'large-points' })
|
|
783
|
+
mapCore.removePointLargePoint({ layerId: 'large-points', pointId: '1' })
|
|
784
|
+
mapCore.clearPointLargeLayer({ layerId: 'large-points' })
|
|
785
|
+
mapCore.removePointLargeLayer({ layerId: 'large-points' })
|
|
786
|
+
|
|
787
|
+
await mapCore.upsertPointDensityLayer({
|
|
788
|
+
layerId: 'density-points',
|
|
789
|
+
points: [{ id: '1', longitude: 104, latitude: 35 }],
|
|
790
|
+
gridSize: 150,
|
|
791
|
+
})
|
|
792
|
+
mapCore.getPointDensityLayerState({ layerId: 'density-points' })
|
|
793
|
+
mapCore.removePointDensityLayer({ layerId: 'density-points' })
|
|
794
|
+
|
|
795
|
+
await mapCore.upsertContourLayer({
|
|
796
|
+
layerId: 'contour',
|
|
797
|
+
contours: [],
|
|
798
|
+
})
|
|
799
|
+
await mapCore.updateContourLayer({ layerId: 'contour', contours: [] })
|
|
800
|
+
mapCore.getContourLayerState({ layerId: 'contour' })
|
|
801
|
+
mapCore.removeContourLayer({ layerId: 'contour' })
|
|
802
|
+
```
|
|
803
|
+
|
|
804
|
+
## 在 Vue 中封装 Hook
|
|
805
|
+
|
|
806
|
+
推荐页面用 hook 管理生命周期,组件只处理 UI。
|
|
807
|
+
|
|
808
|
+
```js
|
|
809
|
+
import { onBeforeUnmount, onMounted, shallowRef } from 'vue'
|
|
810
|
+
import { BaseGIS } from '@3clear/basegis'
|
|
811
|
+
|
|
812
|
+
export function useBaseGIS(options = {}) {
|
|
813
|
+
const mapCore = shallowRef(null)
|
|
814
|
+
|
|
815
|
+
onMounted(() => {
|
|
816
|
+
mapCore.value = new BaseGIS(options)
|
|
817
|
+
mapCore.value.init()
|
|
818
|
+
})
|
|
819
|
+
|
|
820
|
+
onBeforeUnmount(() => {
|
|
821
|
+
mapCore.value?.destroy()
|
|
822
|
+
mapCore.value = null
|
|
823
|
+
})
|
|
824
|
+
|
|
825
|
+
return {
|
|
826
|
+
mapCore,
|
|
827
|
+
}
|
|
828
|
+
}
|
|
829
|
+
```
|
|
830
|
+
|
|
831
|
+
使用:
|
|
832
|
+
|
|
833
|
+
```vue
|
|
834
|
+
<template>
|
|
835
|
+
<div id="map" class="map"></div>
|
|
836
|
+
</template>
|
|
837
|
+
|
|
838
|
+
<script setup>
|
|
839
|
+
import { useBaseGIS } from './useBaseGIS'
|
|
840
|
+
|
|
841
|
+
const { mapCore } = useBaseGIS({
|
|
842
|
+
engineType: 'cesium',
|
|
843
|
+
containerId: 'map',
|
|
844
|
+
})
|
|
845
|
+
</script>
|
|
846
|
+
```
|
|
847
|
+
|
|
848
|
+
## 能力支持说明
|
|
849
|
+
|
|
850
|
+
| 能力 | Cesium | Leaflet |
|
|
851
|
+
| --- | --- | --- |
|
|
852
|
+
| 2D 地图 | 支持 | 支持 |
|
|
853
|
+
| 2.5D / 3D 场景 | 支持 | 不支持 |
|
|
854
|
+
| 放大、缩小、重置 | 支持 | 支持 |
|
|
855
|
+
| 底图切换 | 支持 | 支持 |
|
|
856
|
+
| 点线面文字 | 支持 | 支持 |
|
|
857
|
+
| 图片覆盖层 | 支持 | 支持 |
|
|
858
|
+
| 网格 / TIF | 支持 | 支持 |
|
|
859
|
+
| 海量点 | 支持 | 支持 |
|
|
860
|
+
| 点位密度抽稀 | 支持 | 支持 |
|
|
861
|
+
| 等值线 | 支持 | 支持 |
|
|
862
|
+
| 等压线标注 | 支持 | 支持 |
|
|
863
|
+
| 风场 Canvas 动画 | 支持 | 支持 |
|
|
864
|
+
| DEM 地形 | 支持 | 不支持 |
|
|
865
|
+
|
|
866
|
+
## 本地开发与打包
|
|
867
|
+
|
|
868
|
+
在仓库根目录执行:
|
|
869
|
+
|
|
870
|
+
```bash
|
|
871
|
+
npm run build:basegis
|
|
872
|
+
npm run pack:basegis
|
|
873
|
+
```
|
|
874
|
+
|
|
875
|
+
`build:basegis` 会生成:
|
|
876
|
+
|
|
877
|
+
```text
|
|
878
|
+
packages/basegis/dist/basegis.js
|
|
879
|
+
packages/basegis/dist/methods.js
|
|
880
|
+
packages/basegis/dist/layers.js
|
|
881
|
+
packages/basegis/dist/assets.js
|
|
882
|
+
packages/basegis/dist/style.css
|
|
883
|
+
```
|
|
884
|
+
|
|
885
|
+
`pack:basegis` 会在仓库根目录生成类似文件:
|
|
886
|
+
|
|
887
|
+
```text
|
|
888
|
+
3clear-basegis-0.1.0.tgz
|
|
889
|
+
```
|
|
890
|
+
|
|
891
|
+
其他项目本地安装:
|
|
892
|
+
|
|
893
|
+
```bash
|
|
894
|
+
npm install ./3clear-basegis-0.1.0.tgz
|
|
895
|
+
```
|
|
896
|
+
|
|
897
|
+
## 发布到 npm
|
|
898
|
+
|
|
899
|
+
只发布 `packages/basegis`,不要在项目根目录执行 `npm publish`,否则会把整个业务项目上传到 npm。
|
|
900
|
+
|
|
901
|
+
发布前检查包内容:
|
|
902
|
+
|
|
903
|
+
```bash
|
|
904
|
+
npm pack --dry-run ./packages/basegis
|
|
905
|
+
```
|
|
906
|
+
|
|
907
|
+
发布 scoped 包:
|
|
908
|
+
|
|
909
|
+
```bash
|
|
910
|
+
npm publish ./packages/basegis --access public
|
|
911
|
+
```
|
|
912
|
+
|
|
913
|
+
如果只希望私有发布,保留 `packages/basegis/package.json` 中的:
|
|
914
|
+
|
|
915
|
+
```json
|
|
916
|
+
{
|
|
917
|
+
"publishConfig": {
|
|
918
|
+
"access": "restricted"
|
|
919
|
+
}
|
|
920
|
+
}
|
|
921
|
+
```
|
|
922
|
+
|
|
923
|
+
如果希望公开发布,需要改为:
|
|
924
|
+
|
|
925
|
+
```json
|
|
926
|
+
{
|
|
927
|
+
"publishConfig": {
|
|
928
|
+
"access": "public"
|
|
929
|
+
}
|
|
930
|
+
}
|
|
931
|
+
```
|
|
932
|
+
|
|
933
|
+
## 常见问题
|
|
934
|
+
|
|
935
|
+
### Cesium 地图不显示
|
|
936
|
+
|
|
937
|
+
检查宿主项目是否存在:
|
|
938
|
+
|
|
939
|
+
```text
|
|
940
|
+
public/lib/Cesium/Cesium.js
|
|
941
|
+
public/lib/Cesium/Widgets/widgets.css
|
|
942
|
+
```
|
|
943
|
+
|
|
944
|
+
并确认页面初始化前能访问 `window.Cesium`。
|
|
945
|
+
|
|
946
|
+
### Leaflet 样式异常
|
|
947
|
+
|
|
948
|
+
确认已引入:
|
|
949
|
+
|
|
950
|
+
```js
|
|
951
|
+
import '@3clear/basegis/style.css'
|
|
952
|
+
```
|
|
953
|
+
|
|
954
|
+
### 调用方法返回 NOT_INITIALIZED
|
|
955
|
+
|
|
956
|
+
说明地图还没有初始化成功。先执行:
|
|
957
|
+
|
|
958
|
+
```js
|
|
959
|
+
const result = mapCore.init()
|
|
960
|
+
console.log(result.success, result.message)
|
|
961
|
+
```
|
|
962
|
+
|
|
963
|
+
### 切换配置后地图没有变化
|
|
964
|
+
|
|
965
|
+
`setConfig()` 只更新 `BaseGIS` 内部配置,不会自动重建地图。需要销毁后重新初始化:
|
|
966
|
+
|
|
967
|
+
```js
|
|
968
|
+
mapCore.setConfig(nextConfig)
|
|
969
|
+
mapCore.init()
|
|
970
|
+
```
|
|
971
|
+
|
|
972
|
+
`init()` 内部会先销毁旧适配器,再创建新实例。
|