@3clear/basegis 0.1.2 → 0.1.3
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 +368 -58
- package/dist/WindDataGrid-AGJaASUG.js +96 -0
- package/dist/basegis.js +5124 -2890
- package/dist/methods.js +500 -541
- package/package.json +1 -1
- package/dist/result-D03zgqh0.js +0 -39
package/README.md
CHANGED
|
@@ -4,12 +4,31 @@
|
|
|
4
4
|
把leaflet cesium 常用方法做了二次封装统一了api 使同一套代码可以适配2套地图引擎
|
|
5
5
|
当前包包含:
|
|
6
6
|
|
|
7
|
-
- `BaseGIS`:地图初始化、引擎切换、视角控制、底图切换、绘制、图层显隐、DEM
|
|
7
|
+
- `BaseGIS`:地图初始化、引擎切换、视角控制、底图切换、绘制、图层显隐、DEM、点击事件、Cesium / Leaflet 统一粒子风场、GPU 粒子风场、三维体渲染、三维切片/剖面渲染等基础能力。
|
|
8
8
|
- `methods`:图片图层、网格图层、海量点、点位抽稀、等值线、等压线、风场、图形组等高级控制器。
|
|
9
9
|
- `layers`:天地图、GeoServer 金字塔瓦片、WMS、WMTS 图层配置快捷构造器。
|
|
10
10
|
- `assets`:GIS 示例资源。
|
|
11
11
|
- `style.css`:Leaflet、GIS 图层和标注相关基础样式。
|
|
12
12
|
|
|
13
|
+
## 能力总览
|
|
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> |
|
|
31
|
+
|
|
13
32
|
## 安装
|
|
14
33
|
|
|
15
34
|
```bash
|
|
@@ -266,6 +285,70 @@ mapCore.setBasemap({
|
|
|
266
285
|
| `parameters` | 选填 | WMS 附加参数。 |
|
|
267
286
|
| `engineSupport` | 选填 | 支持的引擎列表,如 `['cesium', 'leaflet']`。 |
|
|
268
287
|
|
|
288
|
+
<a id="layer-config-builders"></a>
|
|
289
|
+
|
|
290
|
+
## 图层配置构造器
|
|
291
|
+
|
|
292
|
+
`layers` 出口提供四个快捷构造器,只负责生成标准图层配置,不会直接操作地图。构造结果可以放入 `config.basemap.list`,也可以传给 `setBasemap()`。
|
|
293
|
+
|
|
294
|
+
```js
|
|
295
|
+
import { BaseGIS } from '@3clear/basegis'
|
|
296
|
+
import {
|
|
297
|
+
createGeoserverPyramidLayer,
|
|
298
|
+
createTiandituLayer,
|
|
299
|
+
createWmsLayer,
|
|
300
|
+
createWmtsLayer,
|
|
301
|
+
} from '@3clear/basegis/layers'
|
|
302
|
+
|
|
303
|
+
const basemapList = [
|
|
304
|
+
createTiandituLayer({
|
|
305
|
+
id: 'tianditu-imagery',
|
|
306
|
+
name: '天地图影像',
|
|
307
|
+
category: 'basemap',
|
|
308
|
+
resourceKey: 'imagery',
|
|
309
|
+
annotationResourceKey: 'imageryLabel',
|
|
310
|
+
}),
|
|
311
|
+
createGeoserverPyramidLayer({
|
|
312
|
+
id: 'geoserver-pyramid',
|
|
313
|
+
name: 'GeoServer 金字塔瓦片',
|
|
314
|
+
category: 'basemap',
|
|
315
|
+
url: 'https://example.com/tiles/{z}/{x}/{y}.png',
|
|
316
|
+
}),
|
|
317
|
+
createWmsLayer({
|
|
318
|
+
id: 'weather-wms',
|
|
319
|
+
name: '气象 WMS',
|
|
320
|
+
category: 'basemap',
|
|
321
|
+
serviceUrl: 'https://example.com/geoserver/wms',
|
|
322
|
+
layers: 'workspace:weather',
|
|
323
|
+
parameters: {
|
|
324
|
+
transparent: true,
|
|
325
|
+
format: 'image/png',
|
|
326
|
+
},
|
|
327
|
+
}),
|
|
328
|
+
createWmtsLayer({
|
|
329
|
+
id: 'weather-wmts',
|
|
330
|
+
name: '气象 WMTS',
|
|
331
|
+
category: 'basemap',
|
|
332
|
+
url: 'https://example.com/wmts',
|
|
333
|
+
layer: 'weather',
|
|
334
|
+
tileMatrixSet: 'EPSG:3857',
|
|
335
|
+
}),
|
|
336
|
+
]
|
|
337
|
+
|
|
338
|
+
const mapCore = new BaseGIS({
|
|
339
|
+
containerId: 'map',
|
|
340
|
+
config: {
|
|
341
|
+
basemap: {
|
|
342
|
+
list: basemapList,
|
|
343
|
+
defaultVisibleId: 'tianditu-imagery',
|
|
344
|
+
},
|
|
345
|
+
},
|
|
346
|
+
})
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
四个构造器都会保留额外传入字段,便于继续配置 `engineSupport`、缩放级别、注记资源或服务参数。
|
|
350
|
+
|
|
351
|
+
<a id="base-gis"></a>
|
|
269
352
|
|
|
270
353
|
## BaseGIS 基础能力
|
|
271
354
|
|
|
@@ -579,6 +662,25 @@ mapCore.addMarker({
|
|
|
579
662
|
})
|
|
580
663
|
```
|
|
581
664
|
|
|
665
|
+
<a id="gis-marker-sample"></a>
|
|
666
|
+
|
|
667
|
+
#### 使用 gisMarkerSample 示例资源
|
|
668
|
+
|
|
669
|
+
`gisMarkerSample` 是可直接导入的 Marker 图片资源,适合快速验证 `addMarker()` 或控制器图标配置。
|
|
670
|
+
|
|
671
|
+
```js
|
|
672
|
+
import { gisMarkerSample } from '@3clear/basegis/assets'
|
|
673
|
+
|
|
674
|
+
mapCore.addMarker({
|
|
675
|
+
id: 'marker-sample',
|
|
676
|
+
name: '示例站点',
|
|
677
|
+
position: [104, 35],
|
|
678
|
+
iconUrl: gisMarkerSample,
|
|
679
|
+
iconSize: [42, 50],
|
|
680
|
+
iconAnchor: [21, 50],
|
|
681
|
+
})
|
|
682
|
+
```
|
|
683
|
+
|
|
582
684
|
清理图形:
|
|
583
685
|
|
|
584
686
|
```js
|
|
@@ -668,6 +770,8 @@ Leaflet 当前返回坐标点击:
|
|
|
668
770
|
- 海量点、点位抽稀等图层自己的点击事件,应使用对应 Controller 的 `onClick` 参数。
|
|
669
771
|
|
|
670
772
|
|
|
773
|
+
<a id="graphic-group-controller"></a>
|
|
774
|
+
|
|
671
775
|
## GraphicGroupController
|
|
672
776
|
|
|
673
777
|
用于一次性加载一组点、线、面、文字、marker。它只调用 `BaseGIS.drawPoint / drawLine / drawPolygon / drawText / addMarker`。
|
|
@@ -705,10 +809,28 @@ graphics.clear()
|
|
|
705
809
|
graphics.getState()
|
|
706
810
|
```
|
|
707
811
|
|
|
812
|
+
<a id="image-layer-controller"></a>
|
|
813
|
+
|
|
708
814
|
## ImageLayerController
|
|
709
815
|
|
|
710
816
|
用于管理一个图片覆盖层。所有更新都走 `update(payload)`;页面有很多时次数据时,自己维护数据列表,然后把当前时次的数据传给 `update`。
|
|
711
817
|
|
|
818
|
+
`toImageLayerArea()` 可以把经纬度数组、Leaflet Bounds 或常见范围对象统一转换成 `{ startLon, startLat, endLon, endLat }`:
|
|
819
|
+
|
|
820
|
+
```js
|
|
821
|
+
import {
|
|
822
|
+
ImageLayerController,
|
|
823
|
+
toImageLayerArea,
|
|
824
|
+
} from '@3clear/basegis/methods'
|
|
825
|
+
|
|
826
|
+
const area = toImageLayerArea({
|
|
827
|
+
west: 73,
|
|
828
|
+
south: 18,
|
|
829
|
+
east: 135,
|
|
830
|
+
north: 54,
|
|
831
|
+
})
|
|
832
|
+
```
|
|
833
|
+
|
|
712
834
|
先创建控制器。这里是控制器级默认参数,后续每次 `update(payload)` 都可以覆盖这些默认值:
|
|
713
835
|
|
|
714
836
|
```js
|
|
@@ -872,6 +994,8 @@ await imageLayer.update({
|
|
|
872
994
|
})
|
|
873
995
|
```
|
|
874
996
|
|
|
997
|
+
Leaflet 会对经度跨度达到 360° 的全球图片按当前视野自动补充相邻世界副本,全球 TIF / 灰度格点的注记和鼠标探针也会使用同一套经度循环,因此业务页面不需要手动创建 `±360°` 图片层。原始图片按 `0° ~ 360°` 排列时传 `isSplit: true`,适配层会在交换左右半幅的同时把显示范围统一为 `-180° ~ 180°`,确保图片与格点值落在同一经度位置。
|
|
998
|
+
|
|
875
999
|
`loadGrayImage` 的灰度值换算规则:
|
|
876
1000
|
|
|
877
1001
|
```js
|
|
@@ -1079,6 +1203,8 @@ imageLayer.destroy({ layerId: 'radar-image' })
|
|
|
1079
1203
|
- `switchTo(idOrIndex)`:在已加载的 `items` 内切换到某一项。
|
|
1080
1204
|
- `next() / prev()`:只适合本地小数组演示,不推荐作为业务时次更新主路径。
|
|
1081
1205
|
|
|
1206
|
+
<a id="grid-layer-controller"></a>
|
|
1207
|
+
|
|
1082
1208
|
## GridLayerController
|
|
1083
1209
|
|
|
1084
1210
|
用于 TIF 网格、灰度图网格、外部数值网格。
|
|
@@ -1141,6 +1267,176 @@ gridLayer.show()
|
|
|
1141
1267
|
gridLayer.destroy()
|
|
1142
1268
|
```
|
|
1143
1269
|
|
|
1270
|
+
## 统一粒子风场
|
|
1271
|
+
|
|
1272
|
+
同一组 API 会根据当前引擎自动选择渲染器:Cesium 使用 GPU 粒子风场,Leaflet 使用迁自 one-map 的 Canvas 粒子风场。
|
|
1273
|
+
|
|
1274
|
+
```js
|
|
1275
|
+
const windData = await fetch('/mock/uv.json').then((response) => response.json())
|
|
1276
|
+
|
|
1277
|
+
await mapCore.upsertWindLayer({
|
|
1278
|
+
layerId: 'surface-wind',
|
|
1279
|
+
windData,
|
|
1280
|
+
maxParticles: 6400,
|
|
1281
|
+
speedFactor: 0.15,
|
|
1282
|
+
lineWidth: 2,
|
|
1283
|
+
fadeOpacity: 0.92,
|
|
1284
|
+
color: '#b7d9ff',
|
|
1285
|
+
particleOpacity: 0.72,
|
|
1286
|
+
})
|
|
1287
|
+
|
|
1288
|
+
await mapCore.updateWindLayer({
|
|
1289
|
+
layerId: 'surface-wind',
|
|
1290
|
+
speedFactor: 0.2,
|
|
1291
|
+
})
|
|
1292
|
+
mapCore.hideWindLayer({ layerId: 'surface-wind' })
|
|
1293
|
+
mapCore.showWindLayer({ layerId: 'surface-wind' })
|
|
1294
|
+
mapCore.flyToWindLayer({ layerId: 'surface-wind', duration: 0.8 })
|
|
1295
|
+
const stateResult = mapCore.getWindLayerState({ layerId: 'surface-wind' })
|
|
1296
|
+
mapCore.removeWindLayer({ layerId: 'surface-wind' })
|
|
1297
|
+
```
|
|
1298
|
+
|
|
1299
|
+
| 方法 | 说明 |
|
|
1300
|
+
| --- | --- |
|
|
1301
|
+
| `upsertWindLayer(payload)` | 创建或更新当前引擎的风场 |
|
|
1302
|
+
| `updateWindLayer(payload)` | 更新数据或部分参数 |
|
|
1303
|
+
| `showWindLayer(payload)` / `hideWindLayer(payload)` | 显隐风场 |
|
|
1304
|
+
| `flyToWindLayer(payload)` | 定位到风场数据范围 |
|
|
1305
|
+
| `getWindLayerState(payload)` | 获取渲染器、粒子数量、范围和显隐状态 |
|
|
1306
|
+
| `removeWindLayer(payload)` | 删除风场并释放资源 |
|
|
1307
|
+
|
|
1308
|
+
跨引擎统一使用 `Bound / DataAry` 数据格式。公共参数包括 `maxParticles`、`speedFactor`、`lineWidth`、`fadeOpacity`、`particleOpacity`、`color` 和 `visible`;适配层会统一速度、帧率拖尾、屏幕线宽、设备像素比和粒子视觉密度。`maxParticles` 表示跨引擎视觉预算:Cesium 的实际粒子数会按 GPU 纹理向上取整为整数平方,Leaflet 会按 Canvas 拖尾覆盖率换算实际粒子数,均可通过图层状态查看;算法和投影不同,因此不保证逐像素完全一致。Leaflet 还支持 `particleGap`、`maxAge`、`frameRate`、`minSpeed`。统一风场属于 BaseGIS 托管图层,`setEngine()` 切换引擎时会自动使用原数据和最新参数恢复。
|
|
1309
|
+
|
|
1310
|
+
## GPU 粒子风场
|
|
1311
|
+
|
|
1312
|
+
GPU 粒子风场是 Cesium 专有能力,直接通过 `BaseGIS` 调用。它使用显卡纹理保存和更新粒子,相机平移或缩放期间清空轨迹,操作结束后按新视野重新生成粒子。Leaflet 调用同名方法时会返回 `UNSUPPORTED_CAPABILITY`,不会抛异常。
|
|
1313
|
+
|
|
1314
|
+
Cesium 由宿主通过 `window.Cesium` 提供。启用 `terrainEnabled` 后,图层会采样当前 `viewer.terrainProvider`,让轨迹高度随地形变化;如果当前使用椭球地形,采样高度为 0。
|
|
1315
|
+
|
|
1316
|
+
### 基础用法
|
|
1317
|
+
|
|
1318
|
+
```js
|
|
1319
|
+
const response = await fetch('/mock/uv.json')
|
|
1320
|
+
const windData = await response.json()
|
|
1321
|
+
|
|
1322
|
+
const result = await mapCore.upsertGpuWindLayer({
|
|
1323
|
+
layerId: 'surface-gpu-wind',
|
|
1324
|
+
windData,
|
|
1325
|
+
maxParticles: 10000,
|
|
1326
|
+
particleHeight: 0,
|
|
1327
|
+
terrainEnabled: false,
|
|
1328
|
+
fadeOpacity: 0.901,
|
|
1329
|
+
dropRate: 0.001,
|
|
1330
|
+
dropRateBump: 0.002,
|
|
1331
|
+
speedFactor: 0.15,
|
|
1332
|
+
lineWidth: 4.23,
|
|
1333
|
+
color: '#ffffff',
|
|
1334
|
+
particleOpacity: 1,
|
|
1335
|
+
})
|
|
1336
|
+
|
|
1337
|
+
if (!result.success) {
|
|
1338
|
+
console.warn(result.code, result.message)
|
|
1339
|
+
}
|
|
1340
|
+
```
|
|
1341
|
+
|
|
1342
|
+
创建和更新是异步方法,可能等待地形采样,建议始终使用 `await`。
|
|
1343
|
+
|
|
1344
|
+
### 数据格式
|
|
1345
|
+
|
|
1346
|
+
可直接使用 BaseGIS 现有 Canvas 风场的 `Bound / DataAry` 数据:
|
|
1347
|
+
|
|
1348
|
+
```js
|
|
1349
|
+
const windData = {
|
|
1350
|
+
// 经度最小值、纬度最小值、经向格点数、纬向格点数、
|
|
1351
|
+
// 经度跨度、纬度跨度、数值缩放倍数。
|
|
1352
|
+
Bound: [100, 10, 181, 91, 80, 40, 10],
|
|
1353
|
+
// 每个格点按 U、V 交错;纬度行从南向北排列。
|
|
1354
|
+
DataAry: [u0, v0, u1, v1],
|
|
1355
|
+
}
|
|
1356
|
+
```
|
|
1357
|
+
|
|
1358
|
+
也可以传独立 U/V 分量:
|
|
1359
|
+
|
|
1360
|
+
```js
|
|
1361
|
+
const windData = {
|
|
1362
|
+
width: 181,
|
|
1363
|
+
height: 91,
|
|
1364
|
+
bounds: {
|
|
1365
|
+
west: 100,
|
|
1366
|
+
east: 180,
|
|
1367
|
+
south: 10,
|
|
1368
|
+
north: 50,
|
|
1369
|
+
},
|
|
1370
|
+
u: new Float32Array(181 * 91),
|
|
1371
|
+
v: new Float32Array(181 * 91),
|
|
1372
|
+
// index-gpu.vue 解码结果从北向南排列,因此使用 north-to-south。
|
|
1373
|
+
rowOrder: 'north-to-south',
|
|
1374
|
+
}
|
|
1375
|
+
```
|
|
1376
|
+
|
|
1377
|
+
也可以不改 `windData`,在 `upsertGpuWindLayer` 参数中传 `flipY: true`。这与 `rowOrder: 'north-to-south'` 等价。
|
|
1378
|
+
|
|
1379
|
+
### 更新、显隐和移除
|
|
1380
|
+
|
|
1381
|
+
```js
|
|
1382
|
+
await mapCore.updateGpuWindLayer({
|
|
1383
|
+
layerId: 'surface-gpu-wind',
|
|
1384
|
+
maxParticles: 40000,
|
|
1385
|
+
speedFactor: 0.2,
|
|
1386
|
+
lineWidth: 3,
|
|
1387
|
+
terrainEnabled: true,
|
|
1388
|
+
particleHeight: 20,
|
|
1389
|
+
})
|
|
1390
|
+
|
|
1391
|
+
mapCore.hideGpuWindLayer({ layerId: 'surface-gpu-wind' })
|
|
1392
|
+
mapCore.showGpuWindLayer({ layerId: 'surface-gpu-wind' })
|
|
1393
|
+
mapCore.flyToGpuWindLayer({ layerId: 'surface-gpu-wind', duration: 0.8 })
|
|
1394
|
+
|
|
1395
|
+
const stateResult = mapCore.getGpuWindLayerState({
|
|
1396
|
+
layerId: 'surface-gpu-wind',
|
|
1397
|
+
})
|
|
1398
|
+
console.log(stateResult.data)
|
|
1399
|
+
|
|
1400
|
+
mapCore.removeGpuWindLayer({ layerId: 'surface-gpu-wind' })
|
|
1401
|
+
```
|
|
1402
|
+
|
|
1403
|
+
`updateGpuWindLayer` 只传参数时复用现有数据;传入新的 `windData` 或 `data` 时会重建 GPU 图层。
|
|
1404
|
+
|
|
1405
|
+
### 方法总表
|
|
1406
|
+
|
|
1407
|
+
| 方法 | 参数 | 说明 |
|
|
1408
|
+
| --- | --- | --- |
|
|
1409
|
+
| `upsertGpuWindLayer(payload)` | 数据和完整配置 | 创建或替换同 `layerId` 的 GPU 风场 |
|
|
1410
|
+
| `updateGpuWindLayer(payload)` | `{ layerId, ...partialOptions }` | 更新参数;传新数据时重建 |
|
|
1411
|
+
| `showGpuWindLayer(payload)` | `{ layerId }` | 显示图层 |
|
|
1412
|
+
| `hideGpuWindLayer(payload)` | `{ layerId }` | 隐藏图层 |
|
|
1413
|
+
| `removeGpuWindLayer(payload)` | `{ layerId }` | 删除图层并释放 GPU 资源 |
|
|
1414
|
+
| `flyToGpuWindLayer(payload)` | `{ layerId, duration? }` | 飞到风场数据范围 |
|
|
1415
|
+
| `getGpuWindLayerState(payload)` | `{ layerId }` | 获取粒子、范围、地形采样和显隐状态 |
|
|
1416
|
+
|
|
1417
|
+
### 参数总表
|
|
1418
|
+
|
|
1419
|
+
| 参数 | 是否必填 | 默认值 | 说明 |
|
|
1420
|
+
| --- | --- | --- | --- |
|
|
1421
|
+
| `layerId` / `gpuWindLayerId` / `id` | 建议必填 | `gpu-wind-default` | 图层 id |
|
|
1422
|
+
| `windData` / `data` | 创建时必填 | - | 上述任一种风场数据 |
|
|
1423
|
+
| `maxParticles` | 选填 | `10000` | 请求粒子数;实际值向上取整为整数平方 |
|
|
1424
|
+
| `particleHeight` | 选填 | `0` | 离地高度,单位米 |
|
|
1425
|
+
| `terrainEnabled` | 选填 | `false` | 是否贴合 Cesium 地形 |
|
|
1426
|
+
| `fadeOpacity` | 选填 | `0.901` | 拖尾保留系数,范围 0~1 |
|
|
1427
|
+
| `dropRate` | 选填 | `0.001` | 基础粒子丢弃率 |
|
|
1428
|
+
| `dropRateBump` | 选填 | `0.002` | 随风速增加的附加丢弃率 |
|
|
1429
|
+
| `speedFactor` | 选填 | `0.15` | 移动速度倍率 |
|
|
1430
|
+
| `lineWidth` | 选填 | `4.23` | 轨迹线宽 |
|
|
1431
|
+
| `color` | 选填 | `#ffffff` | 粒子轨迹颜色 |
|
|
1432
|
+
| `particleOpacity` | 选填 | `1` | 粒子轨迹透明度,范围 0~1 |
|
|
1433
|
+
| `visible` | 选填 | `true` | 初始是否显示 |
|
|
1434
|
+
| `terrainMaxSamples` | 选填 | `4096` | 单次地形采样点上限,允许 4~16384 |
|
|
1435
|
+
| `terrainSampleLevel` | 选填 | 自动计算 | 固定地形采样层级,允许 0~15 |
|
|
1436
|
+
| `flipY` | 选填 | `false` | 独立 U/V 数据为北到南行序时传 `true` |
|
|
1437
|
+
|
|
1438
|
+
GPU 专用 API 不属于跨引擎自动恢复图层。切换 Cesium/Leaflet 后,业务应重新调用 `upsertGpuWindLayer`;需要自动恢复时改用 `upsertWindLayer`。核心渲染流程改编自 [RaymanNg/3D-Wind-Field](https://github.com/RaymanNg/3D-Wind-Field),遵循源码目录内 `LICENSE-RaymanNg.txt` 的 MIT License。
|
|
1439
|
+
|
|
1144
1440
|
## 三维体渲染
|
|
1145
1441
|
|
|
1146
1442
|
三维体渲染是 Cesium 专有能力,直接通过 `BaseGIS` 调用。Leaflet 调用时会返回不支持结果,不会抛出破坏页面的异常。
|
|
@@ -1449,6 +1745,8 @@ if (result.success) {
|
|
|
1449
1745
|
| `lon / lat / hpa` | hover 取值必填 | Cesium 拾取得到的经度、纬度、气压高度。 |
|
|
1450
1746
|
| `showZLayer` | hover 取值选填 | Z 切片是否参与 hover 命中,默认参与。 |
|
|
1451
1747
|
|
|
1748
|
+
<a id="point-large-layer-controller"></a>
|
|
1749
|
+
|
|
1452
1750
|
## PointLargeLayerController
|
|
1453
1751
|
|
|
1454
1752
|
用于海量点位渲染。它会尽量把传入的有效点位全部渲染出来,适合站点、设备、告警、监测点等需要保留全部点位并支持点击、高亮、删除、显隐的场景。
|
|
@@ -1811,6 +2109,8 @@ console.log(state)
|
|
|
1811
2109
|
```
|
|
1812
2110
|
|
|
1813
2111
|
|
|
2112
|
+
<a id="point-density-controller"></a>
|
|
2113
|
+
|
|
1814
2114
|
## PointDensityController
|
|
1815
2115
|
|
|
1816
2116
|
用于点位密度抽稀。地图移动、缩放后会按当前视野和屏幕网格重新计算可见点,适合站点、设备、告警、空气质量监测点等高密度点位。
|
|
@@ -2170,6 +2470,8 @@ console.log(state)
|
|
|
2170
2470
|
// }
|
|
2171
2471
|
```
|
|
2172
2472
|
|
|
2473
|
+
<a id="contour-layer-controller"></a>
|
|
2474
|
+
|
|
2173
2475
|
## ContourLayerController
|
|
2174
2476
|
|
|
2175
2477
|
用于等值线图层,支持加载、更新、显隐、清空和销毁。
|
|
@@ -2216,7 +2518,7 @@ contour.clear()
|
|
|
2216
2518
|
contour.destroy()
|
|
2217
2519
|
```
|
|
2218
2520
|
|
|
2219
|
-
数据别名支持 `contours / isolines / isoline / lines / data / items`。开启 `showLabel` 后,Cesium 和 Leaflet
|
|
2521
|
+
数据别名支持 `contours / isolines / isoline / lines / data / items`。开启 `showLabel` 后,Cesium 和 Leaflet 都会根据当前屏幕范围重新选择可见线段上的位置。Leaflet 传入经度跨度达到 360° 的 `worldCopyArea` 后,还会按当前视野动态更新等值线路径和标签的世界副本;这个过程只重建可见路径,不重新解析栅格或追踪等值线。`RasterContourController` 会自动把栅格范围作为 `worldCopyArea` 传入。
|
|
2220
2522
|
|
|
2221
2523
|
Cesium 在默认椭球地表上使用 `PolylineCollection` 批量落图;真正启用 DEM 地形后才使用 `GroundPolylinePrimitive`。新批次就绪后再替换旧批次,不为每条线创建独立 Entity。标签定位可通过 `labelLineThinStep` 抽样投影点,不会改变实际绘制的等值线。
|
|
2222
2524
|
|
|
@@ -2244,6 +2546,8 @@ Leaflet 默认复用高精度 SVG renderer,并使用 `smoothFactor: 0.5` 做
|
|
|
2244
2546
|
|
|
2245
2547
|
`getState()` 的 `labelCount` 是当前视野实际显示的标签数量。Cesium 状态额外包含 `lineRenderer/lineBuildElapsed/labelLayoutElapsed/primitiveReadyElapsed`,用于区分线构建、标签排版和异步就绪耗时。`onStateChange(state)` 会在视野重排后回传新状态。页面存在侧栏等遮挡时,可通过 `labelViewportPadding` 排除对应区域。
|
|
2246
2548
|
|
|
2549
|
+
<a id="raster-contour-controller"></a>
|
|
2550
|
+
|
|
2247
2551
|
## RasterContourController
|
|
2248
2552
|
|
|
2249
2553
|
用于从 GeoTIFF、灰度图或数值网格直接计算并绘制等值线。内部统一使用 `d3-contour` 追踪等值线,输出仍交给 `ContourLayerController`,所以页面不需要区分 Cesium 和 Leaflet;调用 `BaseGIS.setEngine()` 时,已经生成的等值线会随托管图层自动恢复。
|
|
@@ -2393,69 +2697,45 @@ await rasterContour.loadGrid({
|
|
|
2393
2697
|
| `getState()` | 返回尺寸、值域、级别、线数、当前标注数、投影、耗时和底层 contour 状态。 |
|
|
2394
2698
|
| `getRasterData()` | 返回当前标准栅格,包含 `values/width/height/area`。 |
|
|
2395
2699
|
|
|
2396
|
-
|
|
2397
|
-
[//]: # (## PressureContourLayer)
|
|
2700
|
+
<a id="pressure-contour-layer"></a>
|
|
2398
2701
|
|
|
2399
|
-
|
|
2400
|
-
[//]: # (用于等压线和高低压中心标注。`buildPressureRenderData()` 可把 Windy 风格的 `press.json` 数据整理成渲染结构,`createPressureDataResolver()` 提供简单缓存。)
|
|
2702
|
+
## PressureContourLayer
|
|
2401
2703
|
|
|
2402
|
-
|
|
2403
|
-
[//]: # (```js)
|
|
2704
|
+
用于等压线、线值标签和高低压中心标注。`buildPressureRenderData()` 可把 Windy 风格的气压数据整理成 `{ isolines, centers }`,`createPressureDataResolver()` 在此基础上提供按数据版本缓存的解析函数。
|
|
2404
2705
|
|
|
2405
|
-
|
|
2406
|
-
|
|
2407
|
-
|
|
2408
|
-
|
|
2409
|
-
|
|
2410
|
-
|
|
2411
|
-
[//]: # (} from '@3clear/basegis/methods')
|
|
2412
|
-
|
|
2413
|
-
[//]: # ()
|
|
2414
|
-
[//]: # (const resolvePressureData = createPressureDataResolver({)
|
|
2415
|
-
|
|
2416
|
-
[//]: # ( default: pressJson,)
|
|
2417
|
-
|
|
2418
|
-
[//]: # ( next: pressJson2,)
|
|
2419
|
-
|
|
2420
|
-
[//]: # (}))
|
|
2421
|
-
|
|
2422
|
-
[//]: # ()
|
|
2423
|
-
[//]: # (const pressureLayer = new PressureContourLayer({)
|
|
2424
|
-
|
|
2425
|
-
[//]: # ( mapCore,)
|
|
2426
|
-
|
|
2427
|
-
[//]: # ( layerId: 'pressure',)
|
|
2428
|
-
|
|
2429
|
-
[//]: # ( color: 'rgba(255,255,255,0.82)',)
|
|
2430
|
-
|
|
2431
|
-
[//]: # ( width: 1.15,)
|
|
2432
|
-
|
|
2433
|
-
[//]: # ( smoothFactor: 0.2,)
|
|
2434
|
-
|
|
2435
|
-
[//]: # ( // Cesium 场景下用于定位容器尺寸,Leaflet 场景也可以传同一个地图容器 id。)
|
|
2436
|
-
|
|
2437
|
-
[//]: # ( mapContainerId: 'map',)
|
|
2438
|
-
|
|
2439
|
-
[//]: # ( // 标注层通过该函数读取当前数据,便于地图缩放后重建标签。)
|
|
2440
|
-
|
|
2441
|
-
[//]: # ( getData: () => resolvePressureData('default'),)
|
|
2442
|
-
|
|
2443
|
-
[//]: # ( isAnnotationVisible: () => true,)
|
|
2444
|
-
|
|
2445
|
-
[//]: # (}))
|
|
2446
|
-
|
|
2447
|
-
[//]: # ()
|
|
2448
|
-
[//]: # (pressureLayer.mount())
|
|
2449
|
-
|
|
2450
|
-
[//]: # (await pressureLayer.load(resolvePressureData('default')))
|
|
2706
|
+
```js
|
|
2707
|
+
import {
|
|
2708
|
+
PressureContourLayer,
|
|
2709
|
+
buildPressureRenderData,
|
|
2710
|
+
createPressureDataResolver,
|
|
2711
|
+
} from '@3clear/basegis/methods'
|
|
2451
2712
|
|
|
2452
|
-
|
|
2713
|
+
// 单份原始数据可以直接转换。
|
|
2714
|
+
const renderData = buildPressureRenderData(pressJson)
|
|
2453
2715
|
|
|
2454
|
-
|
|
2716
|
+
// 多个时次或版本可用解析器按 key 缓存转换结果。
|
|
2717
|
+
const resolvePressureData = createPressureDataResolver({
|
|
2718
|
+
default: pressJson,
|
|
2719
|
+
next: pressJson2,
|
|
2720
|
+
})
|
|
2455
2721
|
|
|
2456
|
-
|
|
2722
|
+
const pressureLayer = new PressureContourLayer({
|
|
2723
|
+
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,
|
|
2731
|
+
})
|
|
2457
2732
|
|
|
2458
|
-
|
|
2733
|
+
pressureLayer.mount()
|
|
2734
|
+
await pressureLayer.load(renderData)
|
|
2735
|
+
await pressureLayer.update(resolvePressureData('next'))
|
|
2736
|
+
pressureLayer.hide()
|
|
2737
|
+
pressureLayer.destroy()
|
|
2738
|
+
```
|
|
2459
2739
|
|
|
2460
2740
|
说明:
|
|
2461
2741
|
|
|
@@ -2463,6 +2743,8 @@ await rasterContour.loadGrid({
|
|
|
2463
2743
|
- Leaflet 使用 `divIcon` 绘制 H/L 中心和线值标签。
|
|
2464
2744
|
- Cesium 使用独立标注集合,地图变化时会调度刷新。
|
|
2465
2745
|
|
|
2746
|
+
<a id="wind-field-methods"></a>
|
|
2747
|
+
|
|
2466
2748
|
## WindFieldMethods
|
|
2467
2749
|
|
|
2468
2750
|
用于叠加 Canvas 风场粒子动画。它通过 `BaseGIS` 获取容器、投影、视野范围和视图变化事件,不直接依赖某个引擎。
|
|
@@ -2711,6 +2993,34 @@ console.log(result.data?.restore)
|
|
|
2711
2993
|
| 三维切片 / 剖面渲染 | 支持 | 不支持 |
|
|
2712
2994
|
| DEM 地形 | 支持 | 不支持 |
|
|
2713
2995
|
|
|
2996
|
+
## 第三方许可
|
|
2997
|
+
|
|
2998
|
+
GPU 粒子风场核心改编自 RaymanNg/3D-Wind-Field:
|
|
2999
|
+
|
|
3000
|
+
```text
|
|
3001
|
+
MIT License
|
|
3002
|
+
|
|
3003
|
+
Copyright (c) 2019 RaymanNg
|
|
3004
|
+
|
|
3005
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
3006
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
3007
|
+
in the Software without restriction, including without limitation the rights
|
|
3008
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
3009
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
3010
|
+
furnished to do so, subject to the following conditions:
|
|
3011
|
+
|
|
3012
|
+
The above copyright notice and this permission notice shall be included in all
|
|
3013
|
+
copies or substantial portions of the Software.
|
|
3014
|
+
|
|
3015
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
3016
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
3017
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
3018
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
3019
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
3020
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
3021
|
+
SOFTWARE.
|
|
3022
|
+
```
|
|
3023
|
+
|
|
2714
3024
|
## 本地开发与打包
|
|
2715
3025
|
|
|
2716
3026
|
在仓库根目录执行:
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
const u = {
|
|
2
|
+
OK: "OK",
|
|
3
|
+
FAILED: "FAILED",
|
|
4
|
+
NOT_INITIALIZED: "NOT_INITIALIZED",
|
|
5
|
+
INVALID_CONTAINER: "INVALID_CONTAINER",
|
|
6
|
+
ENGINE_NOT_REGISTERED: "ENGINE_NOT_REGISTERED",
|
|
7
|
+
ENGINE_RESOURCE_MISSING: "ENGINE_RESOURCE_MISSING",
|
|
8
|
+
METHOD_NOT_FOUND: "METHOD_NOT_FOUND",
|
|
9
|
+
UNSUPPORTED_CAPABILITY: "UNSUPPORTED_CAPABILITY",
|
|
10
|
+
INVALID_DEM: "INVALID_DEM"
|
|
11
|
+
};
|
|
12
|
+
function _({
|
|
13
|
+
success: i = !0,
|
|
14
|
+
message: t = "",
|
|
15
|
+
data: s = null,
|
|
16
|
+
code: n = u.OK
|
|
17
|
+
} = {}) {
|
|
18
|
+
return { success: i, message: t, data: s, code: n };
|
|
19
|
+
}
|
|
20
|
+
function C(i = null, t = "OK", s = u.OK) {
|
|
21
|
+
return _({ success: !0, message: t, data: i, code: s });
|
|
22
|
+
}
|
|
23
|
+
function g(i = "Operation failed.", t = u.FAILED, s = null) {
|
|
24
|
+
return _({ success: !1, message: i, data: s, code: t });
|
|
25
|
+
}
|
|
26
|
+
function T(i, t, s = "") {
|
|
27
|
+
const n = `${t} adapter does not support "${i}". ${s}`.trim();
|
|
28
|
+
return console.warn(`[3clear-dt-base] ${n}`), g(n, u.UNSUPPORTED_CAPABILITY, {
|
|
29
|
+
methodName: i,
|
|
30
|
+
engineType: t,
|
|
31
|
+
detail: s
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
class x {
|
|
35
|
+
constructor(t = {}) {
|
|
36
|
+
this.rawData = t, this.bound = Array.isArray(t.Bound) ? t.Bound : [], this.data = Array.isArray(t.DataAry) ? t.DataAry : [], this.valid = !1, this.errorMessage = "", this.lonMin = 0, this.latMin = 0, this.lonMax = 0, this.latMax = 0, this.lonCount = 0, this.latCount = 0, this.lonSpan = 0, this.latSpan = 0, this.lonStep = 0, this.latStep = 0, this.valueScale = 1, this.parse();
|
|
37
|
+
}
|
|
38
|
+
parse() {
|
|
39
|
+
if (this.bound.length < 6) {
|
|
40
|
+
this.errorMessage = "Wind field Bound must contain at least 6 values.";
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
const [t, s, n, o, e, a, l = 1] = this.bound, r = Number(n) * Number(o) * 2;
|
|
44
|
+
if (!Number.isFinite(Number(t)) || !Number.isFinite(Number(s)) || Number(n) < 2 || Number(o) < 2 || Number(e) <= 0 || Number(a) <= 0 || this.data.length !== r) {
|
|
45
|
+
this.errorMessage = `Invalid wind field data. Expected DataAry length ${r}, got ${this.data.length}.`;
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
this.lonMin = Number(t), this.latMin = Number(s), this.lonCount = Number(n), this.latCount = Number(o), this.lonSpan = Number(e), this.latSpan = Number(a), this.valueScale = Number(l) || 1, this.lonMax = this.lonMin + this.lonSpan, this.latMax = this.latMin + this.latSpan, this.lonStep = this.lonSpan / (this.lonCount - 1), this.latStep = this.latSpan / (this.latCount - 1), this.valid = !0;
|
|
49
|
+
}
|
|
50
|
+
contains(t, s) {
|
|
51
|
+
return Number.isFinite(t) && Number.isFinite(s) && t >= this.lonMin && t <= this.lonMax && s >= this.latMin && s <= this.latMax;
|
|
52
|
+
}
|
|
53
|
+
getBounds() {
|
|
54
|
+
return {
|
|
55
|
+
west: this.lonMin,
|
|
56
|
+
south: this.latMin,
|
|
57
|
+
east: this.lonMax,
|
|
58
|
+
north: this.latMax
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
getCenter() {
|
|
62
|
+
return {
|
|
63
|
+
lon: this.lonMin + this.lonSpan / 2,
|
|
64
|
+
lat: this.latMin + this.latSpan / 2
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
getVector(t, s) {
|
|
68
|
+
const n = (t * this.lonCount + s) * 2;
|
|
69
|
+
return {
|
|
70
|
+
u: Number(this.data[n]) / this.valueScale,
|
|
71
|
+
v: Number(this.data[n + 1]) / this.valueScale
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* 双线性插值。
|
|
76
|
+
*
|
|
77
|
+
* 数据约定为从左下角开始平铺,因此 row 直接对应从南到北的纬度索引。
|
|
78
|
+
*/
|
|
79
|
+
sample(t, s) {
|
|
80
|
+
if (!this.valid || !this.contains(t, s))
|
|
81
|
+
return null;
|
|
82
|
+
const n = (t - this.lonMin) / this.lonStep, o = (s - this.latMin) / this.latStep, e = Math.max(0, Math.min(Math.floor(n), this.lonCount - 2)), a = Math.max(0, Math.min(Math.floor(o), this.latCount - 2)), l = e + 1, r = a + 1, h = Math.max(0, Math.min(n - e, 1)), c = Math.max(0, Math.min(o - a, 1)), I = this.getVector(a, e), S = this.getVector(a, l), E = this.getVector(r, e), m = this.getVector(r, l), d = 1 - h, p = 1 - c, b = d * p, A = h * p, O = d * c, D = h * c, N = I.u * b + S.u * A + E.u * O + m.u * D, M = I.v * b + S.v * A + E.v * O + m.v * D;
|
|
83
|
+
return !Number.isFinite(N) || !Number.isFinite(M) ? null : {
|
|
84
|
+
u: N,
|
|
85
|
+
v: M,
|
|
86
|
+
speed: Math.hypot(N, M)
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
export {
|
|
91
|
+
u as R,
|
|
92
|
+
x as W,
|
|
93
|
+
g as f,
|
|
94
|
+
C as s,
|
|
95
|
+
T as u
|
|
96
|
+
};
|