hn-map 1.1.14 → 1.1.16

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/src/util.ts CHANGED
@@ -1,3 +1,8 @@
1
+ /**
2
+ * 地图工具函数库
3
+ * 包含坐标转换、地图计算、数据处理等工具函数
4
+ */
5
+
1
6
  // import Vue from 'vue'
2
7
  //
3
8
  // // 渲染vue组件并获取dom结构
@@ -13,7 +18,18 @@
13
18
  // return app.$el
14
19
  // }
15
20
 
16
- // 对象深度合并
21
+ /**
22
+ * 对象深度合并函数
23
+ * @param target 目标对象,合并结果会存储在此对象中
24
+ * @param source 源对象,提供要合并的属性
25
+ * @returns {any} 合并后的目标对象
26
+ * @example
27
+ * ```javascript
28
+ * const target = { a: 1, b: { c: 2 } };
29
+ * const source = { b: { d: 3 }, e: 4 };
30
+ * deepMerge(target, source); // { a: 1, b: { c: 2, d: 3 }, e: 4 }
31
+ * ```
32
+ */
17
33
  export function deepMerge(target: any, source: any): any {
18
34
  for (let key of Object.keys(source)) {
19
35
  if (source[key] instanceof Object && !Array.isArray(source[key])) {
@@ -26,14 +42,32 @@ export function deepMerge(target: any, source: any): any {
26
42
  return target;
27
43
  }
28
44
 
29
- // 递归格式化高德坐标系
45
+ /**
46
+ * 递归格式化坐标数组,将WGS-84坐标转换为GCJ-02(高德坐标)
47
+ * 支持多种坐标格式:点坐标、线坐标、面坐标和对象数组
48
+ * @param position 坐标数组或对象数组
49
+ * @returns {any} 转换后的坐标数组或对象数组
50
+ * @example
51
+ * ```javascript
52
+ * // 点坐标
53
+ * wgs84ToGcj02Format([116.404, 39.915]);
54
+ *
55
+ * // 线坐标
56
+ * wgs84ToGcj02Format([[116.404, 39.915], [116.405, 39.916]]);
57
+ *
58
+ * // 对象数组
59
+ * wgs84ToGcj02Format([{lng: 116.404, lat: 39.915}, {lng: 116.405, lat: 39.916}]);
60
+ * ```
61
+ */
30
62
  export function wgs84ToGcj02Format(position: any): any {
31
- // 判断是否是数组
63
+ // 判断是否是二维数组(线或面坐标)
32
64
  if (position.every((item: any) => Array.isArray(item))) {
33
65
  return position.map((item: any) => {
34
66
  return wgs84ToGcj02Format(item);
35
67
  });
36
- } else if (position.every((item: any) => typeof item === "object")) {
68
+ }
69
+ // 判断是否是对象数组
70
+ else if (position.every((item: any) => typeof item === "object")) {
37
71
  return position.map((item: any) => {
38
72
  let data = wgs84ToGcj02Format([item.lng, item.lat]);
39
73
  return {
@@ -42,16 +76,22 @@ export function wgs84ToGcj02Format(position: any): any {
42
76
  lat: data[1],
43
77
  };
44
78
  });
45
- } else {
79
+ }
80
+ // 单点坐标
81
+ else {
46
82
  return wgs84ToGcj02(position[0], position[1]);
47
83
  }
48
84
  }
49
85
 
50
86
  /**
51
87
  * WGS-84 转 GCJ-02(高德坐标)
52
- * @param {number} wgsLat - WGS-84纬度
53
88
  * @param {number} wgsLng - WGS-84经度
54
- * @returns {[number, number]} GCJ-02经纬度数组
89
+ * @param {number} wgsLat - WGS-84纬度
90
+ * @returns {[number, number]} GCJ-02经纬度数组 [经度, 纬度]
91
+ * @example
92
+ * ```javascript
93
+ * wgs84ToGcj02(116.404, 39.915); // 返回转换后的高德坐标
94
+ * ```
55
95
  */
56
96
  export function wgs84ToGcj02(wgsLng: any, wgsLat: any): any {
57
97
  if (!isCorrectPosition(wgsLng, wgsLat)) {
@@ -61,6 +101,12 @@ export function wgs84ToGcj02(wgsLng: any, wgsLat: any): any {
61
101
  const a = 6378245.0; // 长半轴
62
102
  const ee = 0.00669342162296594323; // 扁率
63
103
 
104
+ /**
105
+ * 纬度转换函数
106
+ * @param x 经度偏移
107
+ * @param y 纬度偏移
108
+ * @returns {number} 纬度转换值
109
+ */
64
110
  function transformLat(x: any, y: any): any {
65
111
  let ret =
66
112
  -100.0 +
@@ -82,6 +128,12 @@ export function wgs84ToGcj02(wgsLng: any, wgsLat: any): any {
82
128
  return ret;
83
129
  }
84
130
 
131
+ /**
132
+ * 经度转换函数
133
+ * @param x 经度偏移
134
+ * @param y 纬度偏移
135
+ * @returns {number} 经度转换值
136
+ */
85
137
  function transformLng(x: any, y: any): any {
86
138
  let ret =
87
139
  300.0 +
@@ -117,16 +169,37 @@ export function wgs84ToGcj02(wgsLng: any, wgsLat: any): any {
117
169
  }
118
170
 
119
171
  /**
120
- * 判断是否为正确的坐标
121
- * @param {number} lat - 纬度
172
+ * 判断是否为正确的坐标范围
122
173
  * @param {number} lng - 经度
123
- * @returns {boolean}
174
+ * @param {number} lat - 纬度
175
+ * @returns {boolean} 坐标是否在有效范围内
176
+ * @example
177
+ * ```javascript
178
+ * isCorrectPosition(116.404, 39.915); // true
179
+ * isCorrectPosition(200, 100); // false
180
+ * ```
124
181
  */
125
182
  export function isCorrectPosition(lng: any, lat: any): boolean {
126
183
  return lng <= 180 && lng >= -180 && lat <= 90 && lat >= -90;
127
184
  }
128
185
 
129
- // 根据矩形左上角和右上角坐标计算矩形坐标对
186
+ /**
187
+ * 根据矩形左上角和右下角坐标计算矩形的完整坐标数组
188
+ * @param leftTop 左上角坐标 [经度, 纬度]
189
+ * @param rightBottom 右下角坐标 [经度, 纬度]
190
+ * @returns {Array<Array<number>>} 矩形的完整坐标数组,包含5个点(首尾相同以闭合矩形)
191
+ * @example
192
+ * ```javascript
193
+ * createRectangleCoordinates([116.404, 39.915], [116.405, 39.914]);
194
+ * // 返回:[
195
+ * // [116.404, 39.915], // 左上角
196
+ * // [116.405, 39.915], // 右上角
197
+ * // [116.405, 39.914], // 右下角
198
+ * // [116.404, 39.914], // 左下角
199
+ * // [116.404, 39.915] // 回到左上角,闭合矩形
200
+ * // ]
201
+ * ```
202
+ */
130
203
  export function createRectangleCoordinates(leftTop: any, rightBottom: any) {
131
204
  const [leftTopLng, leftTopLat] = leftTop;
132
205
  const [rightBottomLng, rightBottomLat] = rightBottom;
@@ -137,7 +210,7 @@ export function createRectangleCoordinates(leftTop: any, rightBottom: any) {
137
210
  const rightBottomPoint = [Number(rightBottomLng), Number(rightBottomLat)];
138
211
  const leftBottomPoint = [Number(leftTopLng), Number(rightBottomLat)];
139
212
 
140
- // 返回五个点的坐标对(首尾相同)
213
+ // 返回五个点的坐标对(首尾相同,形成闭合矩形)
141
214
  return [
142
215
  leftTopPoint,
143
216
  rightTopPoint,
@@ -147,6 +220,15 @@ export function createRectangleCoordinates(leftTop: any, rightBottom: any) {
147
220
  ];
148
221
  }
149
222
 
223
+ /**
224
+ * 根据地图缩放级别获取对应的高度范围
225
+ * @param level 地图缩放级别(1-18)
226
+ * @returns {Object} 包含startHeight和endHeight的对象,表示该级别的高度范围
227
+ * @example
228
+ * ```javascript
229
+ * getMapRangeHeightByLevel(11); // 返回level=11对应的高度范围
230
+ * ```
231
+ */
150
232
  export function getMapRangeHeightByLevel(level: number) {
151
233
  // 输入校验:限制在 1~18
152
234
  level = Math.max(1, Math.min(18, Math.floor(level)));
@@ -166,21 +248,27 @@ export function getMapRangeHeightByLevel(level: number) {
166
248
  }
167
249
 
168
250
  /**
169
- * 根据 level 返回该层级的“中间高度”(几何平均值)
170
- *
251
+ * 根据缩放级别返回该层级的“中间高度”
171
252
  * @param {number} level - 缩放级别 [1, 18]
172
253
  * @returns {number} 中间高度(米)
254
+ * @example
255
+ * ```javascript
256
+ * getLevelMiddleHeight(11); // 返回level=11对应的中间高度
257
+ * ```
173
258
  */
174
259
  export function getLevelMiddleHeight(level: number): number {
175
- const { startHeight, endHeight } = getMapRangeHeightByLevel(level);
176
- // 如果 startHeight 为 0(如 level=18),几何平均会为 0,不合理
177
- // 所以 level=18 特殊处理:返回 (0 + end)/2 或直接返回 end * 0.7 左右
178
- if (startHeight === 0) {
179
- return endHeight * 0.7; // 经验值,贴近“中间感知”
180
- }
181
-
182
- // 几何平均:√(start × end)
183
- return Math.sqrt(startHeight * endHeight);
260
+ // const { startHeight, endHeight } = getMapRangeHeightByLevel(level);
261
+ // // 如果 startHeight 为 0(如 level=18),几何平均会为 0,不合理
262
+ // // 所以 level=18 特殊处理:返回 (0 + end)/2 或直接返回 end * 0.7 左右
263
+ // if (startHeight === 0) {
264
+ // return endHeight * 0.7; // 经验值,贴近“中间感知”
265
+ // }
266
+ //
267
+ // // 几何平均:√(start × end)
268
+ // return Math.sqrt(startHeight * endHeight);
269
+ const EARTH_RADIUS = 6378137; // 赤道半径
270
+ const height = (2 * Math.PI * EARTH_RADIUS) / (256 * Math.pow(2, level));
271
+ return height;
184
272
  }
185
273
 
186
274
  /**
@@ -191,6 +279,10 @@ export function getLevelMiddleHeight(level: number): number {
191
279
  *
192
280
  * @param {number} level - 缩放级别 [1, 18]
193
281
  * @returns {[number, number]} [开始高度, 结束高度](单位:米)
282
+ * @example
283
+ * ```javascript
284
+ * getLevelHeightRange(11); // 返回level=11对应的高度范围
285
+ * ```
194
286
  */
195
287
  export function getLevelHeightRange(level: number): [number, number] {
196
288
  const { startHeight, endHeight } = getMapRangeHeightByLevel(level);
@@ -198,9 +290,13 @@ export function getLevelHeightRange(level: number): [number, number] {
198
290
  }
199
291
 
200
292
  /**
201
- * 根据高度反推 level(1~18)
293
+ * 根据高度反推地图缩放级别(1~18)
202
294
  * @param {number} height - 当前视野高度(米)
203
- * @returns {number} level
295
+ * @returns {number} 对应的地图缩放级别
296
+ * @example
297
+ * ```javascript
298
+ * getHeightToLevel(100000); // 根据高度返回对应的缩放级别
299
+ * ```
204
300
  */
205
301
  export function getHeightToLevel(height: number): number {
206
302
  if (height > 32000000) return 1;
@@ -213,7 +309,18 @@ export function getHeightToLevel(height: number): number {
213
309
  // 限制在 1~18
214
310
  return Math.max(1, Math.min(18, level));
215
311
  }
216
- // 將坐标数组中的元素字符串类型统一处理为number类型
312
+
313
+ /**
314
+ * 将坐标数组中的字符串类型元素统一转换为数字类型
315
+ * 支持一维、二维、三维坐标数组
316
+ * @param position 字符串坐标数组
317
+ * @returns {number[] | number[][] | number[][][]} 转换后的数字坐标数组
318
+ * @example
319
+ * ```javascript
320
+ * convertPosition(["116.404", "39.915"]); // [116.404, 39.915]
321
+ * convertPosition([["116.404", "39.915"], ["116.405", "39.916"]]); // 二维数组转换
322
+ * ```
323
+ */
217
324
  export function convertPosition(
218
325
  position: string[] | string[][] | string[][][]
219
326
  ): number[] | number[][] | number[][][] {
@@ -233,34 +340,41 @@ export function convertPosition(
233
340
  }) as number[] | number[][] | number[][][];
234
341
  }
235
342
 
236
- // mars3d 地图重写瓦片加载失败的回调,使控制台过滤掉瓦片加载失败的报错
343
+ /**
344
+ * mars3d 地图重写瓦片加载失败的回调函数
345
+ * 用于过滤掉控制台中瓦片加载失败的报错,提高开发体验
346
+ * @example
347
+ * ```javascript
348
+ * // 在地图初始化后调用
349
+ * mars3dTileErrorHandler();
350
+ * ```
351
+ */
237
352
  export function mars3dTileErrorHandler() {
238
353
  // 确保 Cesium 已加载
239
- if (typeof Cesium !== 'undefined' && Cesium.TileProviderError) {
354
+ if (typeof Cesium !== "undefined" && Cesium.TileProviderError) {
240
355
  const originalReportError = Cesium.TileProviderError.reportError;
241
356
 
242
357
  Cesium.TileProviderError.reportError = function (
243
- existingError:any,
244
- provider:any,
245
- errorEvent:any,
246
- message:any,
247
- x:any,
248
- y:any,
249
- level:any,
250
- error:any
358
+ existingError: any,
359
+ provider: any,
360
+ errorEvent: any,
361
+ message: any,
362
+ x: any,
363
+ y: any,
364
+ level: any,
365
+ error: any
251
366
  ) {
252
- // 可选:判断是否为“瓦片不存在”类错误(如 404、fetch 失败等)
367
+ // 判断是否为“瓦片不存在”类错误(如 404、fetch 失败等)
253
368
  const shouldIgnore =
254
- message?.includes('Failed to obtain image') ||
255
- message?.includes('无法获得图块') ||
256
- message?.includes('404') ||
257
- (error && error.status === 404) ||
258
- message?.includes('NetworkError') ||
259
- message?.includes('not found');
369
+ message?.includes("Failed to obtain image") ||
370
+ message?.includes("无法获得图块") ||
371
+ message?.includes("404") ||
372
+ (error && error.status === 404) ||
373
+ message?.includes("NetworkError") ||
374
+ message?.includes("not found");
260
375
 
261
376
  if (shouldIgnore) {
262
377
  // 静默处理:不打印日志,但仍可触发 errorEvent(供自定义监听)
263
- // 注意:仍需调用 raiseEvent(如果有人监听),但跳过 console.log
264
378
  if (Cesium.defined(errorEvent) && errorEvent.numberOfListeners > 0) {
265
379
  let tileError = existingError;
266
380
  if (Cesium.defined(existingError)) {
@@ -271,23 +385,35 @@ export function mars3dTileErrorHandler() {
271
385
  tileError.level = level;
272
386
  tileError.retry = false;
273
387
  tileError.error = error;
274
- tileError.timesRetried = Cesium.defaultValue(tileError.timesRetried, 0) + 1;
388
+ tileError.timesRetried =
389
+ Cesium.defaultValue(tileError.timesRetried, 0) + 1;
275
390
  } else {
276
391
  tileError = new Cesium.TileProviderError(
277
- provider,
278
- message,
279
- x,
280
- y,
281
- level,
282
- 0,
283
- error
392
+ provider,
393
+ message,
394
+ x,
395
+ y,
396
+ level,
397
+ 0,
398
+ error
284
399
  );
285
400
  }
286
401
  errorEvent.raiseEvent(tileError);
287
402
  return tileError;
288
403
  } else {
289
- // 没人监听,且我们不想打印 → 直接返回一个空错误对象(或 null)
290
- return existingError || new Cesium.TileProviderError(provider, message, x, y, level, 0, error);
404
+ // 没人监听,直接返回错误对象
405
+ return (
406
+ existingError ||
407
+ new Cesium.TileProviderError(
408
+ provider,
409
+ message,
410
+ x,
411
+ y,
412
+ level,
413
+ 0,
414
+ error
415
+ )
416
+ );
291
417
  }
292
418
  }
293
419
 
@@ -296,3 +422,81 @@ export function mars3dTileErrorHandler() {
296
422
  };
297
423
  }
298
424
  }
425
+
426
+ /**
427
+ * Cesium专用工具函数
428
+ */
429
+
430
+ /**
431
+ * 将WGS84坐标转换为Cesium笛卡尔坐标
432
+ */
433
+ export function wgs84ToCartesian(
434
+ lng: number,
435
+ lat: number,
436
+ alt: number = 0
437
+ ): any {
438
+ return Cesium.Cartesian3.fromDegrees(lng, lat, alt);
439
+ }
440
+
441
+ /**
442
+ * 将Cesium笛卡尔坐标转换为WGS84坐标
443
+ */
444
+ export function cartesianToWgs84(cartesian: any): {
445
+ lng: number;
446
+ lat: number;
447
+ alt: number;
448
+ } {
449
+ const cartographic = Cesium.Cartographic.fromCartesian(cartesian);
450
+ return {
451
+ lng: Cesium.Math.toDegrees(cartographic.longitude),
452
+ lat: Cesium.Math.toDegrees(cartographic.latitude),
453
+ alt: cartographic.height,
454
+ };
455
+ }
456
+
457
+ /**
458
+ * 计算两点间的距离(米)
459
+ */
460
+ export function calculateDistance(pos1: any, pos2: any): number {
461
+ const cartesian1 = wgs84ToCartesian(pos1.lng, pos1.lat, pos1.alt || 0);
462
+ const cartesian2 = wgs84ToCartesian(pos2.lng, pos2.lat, pos2.alt || 0);
463
+ return Cesium.Cartesian3.distance(cartesian1, cartesian2);
464
+ }
465
+
466
+ /**
467
+ * 创建颜色材质
468
+ */
469
+ export function createColorMaterial(color: string, opacity: number = 1.0): any {
470
+ return new Cesium.ColorMaterialProperty(
471
+ Cesium.Color.fromCssColorString(color).withAlpha(opacity)
472
+ );
473
+ }
474
+
475
+ /**
476
+ * 创建图片材质
477
+ */
478
+ export function createImageMaterial(imageUrl: string): any {
479
+ return new Cesium.ImageMaterialProperty({
480
+ image: imageUrl,
481
+ transparent: true,
482
+ });
483
+ }
484
+
485
+ /**
486
+ * 计算包围球
487
+ */
488
+ export function calculateBoundingSphere(
489
+ positions: Array<[number, number, number?]>
490
+ ): any {
491
+ const cartesians = positions.map((pos) =>
492
+ wgs84ToCartesian(pos[0], pos[1], pos[2] || 0)
493
+ );
494
+ return Cesium.BoundingSphere.fromPoints(cartesians);
495
+ }
496
+
497
+ /**
498
+ * 创建实体集合
499
+ */
500
+ export function createEntityCollection(id: string): any {
501
+ return new Cesium.CustomDataSource(id);
502
+ }