hn-map 1.1.15 → 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/dist/index.js +1 -6003
- package/package.json +1 -1
- package/src/base/gaode_entity.ts +52 -30
- package/src/base/mars3d_entity.ts +50 -13
- package/src/base/siji_entity.ts +81 -44
- package/src/graphic/circle.ts +6 -6
- package/src/graphic/divPoint.ts +5 -5
- package/src/graphic/imagePoint.ts +6 -6
- package/src/graphic/label.ts +6 -6
- package/src/graphic/line.ts +6 -6
- package/src/graphic/numPoint.ts +6 -6
- package/src/graphic/point.ts +12 -7
- package/src/graphic/polygon.ts +6 -6
- package/src/graphic/rectangle.ts +6 -6
- package/src/index.ts +184 -86
- package/src/layer/cluster.ts +86 -0
- package/src/layer/layer.ts +177 -3
- package/src/map.ts +401 -0
- package/src/other/route.ts +2 -2
- package/src/util.ts +420 -220
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,177 +18,257 @@
|
|
|
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
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
}
|
|
34
|
+
for (let key of Object.keys(source)) {
|
|
35
|
+
if (source[key] instanceof Object && !Array.isArray(source[key])) {
|
|
36
|
+
if (!target[key]) Object.assign(target, { [key]: {} });
|
|
37
|
+
deepMerge(target[key], source[key]);
|
|
38
|
+
} else {
|
|
39
|
+
Object.assign(target, { [key]: source[key] });
|
|
25
40
|
}
|
|
26
|
-
|
|
41
|
+
}
|
|
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
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
63
|
+
// 判断是否是二维数组(线或面坐标)
|
|
64
|
+
if (position.every((item: any) => Array.isArray(item))) {
|
|
65
|
+
return position.map((item: any) => {
|
|
66
|
+
return wgs84ToGcj02Format(item);
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
// 判断是否是对象数组
|
|
70
|
+
else if (position.every((item: any) => typeof item === "object")) {
|
|
71
|
+
return position.map((item: any) => {
|
|
72
|
+
let data = wgs84ToGcj02Format([item.lng, item.lat]);
|
|
73
|
+
return {
|
|
74
|
+
...item,
|
|
75
|
+
lng: data[0],
|
|
76
|
+
lat: data[1],
|
|
77
|
+
};
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
// 单点坐标
|
|
81
|
+
else {
|
|
82
|
+
return wgs84ToGcj02(position[0], position[1]);
|
|
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
|
-
* @
|
|
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
|
-
|
|
58
|
-
|
|
59
|
-
|
|
97
|
+
if (!isCorrectPosition(wgsLng, wgsLat)) {
|
|
98
|
+
return [wgsLng, wgsLat];
|
|
99
|
+
}
|
|
60
100
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
function transformLat(x: any, y: any): any {
|
|
65
|
-
let ret =
|
|
66
|
-
-100.0 +
|
|
67
|
-
2.0 * x +
|
|
68
|
-
3.0 * y +
|
|
69
|
-
0.2 * y * y +
|
|
70
|
-
0.1 * x * y +
|
|
71
|
-
0.2 * Math.sqrt(Math.abs(x));
|
|
72
|
-
ret +=
|
|
73
|
-
((20.0 * Math.sin(6.0 * x * Math.PI) +
|
|
74
|
-
20.0 * Math.sin(2.0 * x * Math.PI)) *
|
|
75
|
-
2.0) /
|
|
76
|
-
3.0;
|
|
77
|
-
ret +=
|
|
78
|
-
((160.0 * Math.sin((y * Math.PI) / 3.0) +
|
|
79
|
-
320 * Math.sin((y * Math.PI) / 30.0)) *
|
|
80
|
-
2.0) /
|
|
81
|
-
3.0;
|
|
82
|
-
return ret;
|
|
83
|
-
}
|
|
101
|
+
const a = 6378245.0; // 长半轴
|
|
102
|
+
const ee = 0.00669342162296594323; // 扁率
|
|
84
103
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
+
/**
|
|
105
|
+
* 纬度转换函数
|
|
106
|
+
* @param x 经度偏移
|
|
107
|
+
* @param y 纬度偏移
|
|
108
|
+
* @returns {number} 纬度转换值
|
|
109
|
+
*/
|
|
110
|
+
function transformLat(x: any, y: any): any {
|
|
111
|
+
let ret =
|
|
112
|
+
-100.0 +
|
|
113
|
+
2.0 * x +
|
|
114
|
+
3.0 * y +
|
|
115
|
+
0.2 * y * y +
|
|
116
|
+
0.1 * x * y +
|
|
117
|
+
0.2 * Math.sqrt(Math.abs(x));
|
|
118
|
+
ret +=
|
|
119
|
+
((20.0 * Math.sin(6.0 * x * Math.PI) +
|
|
120
|
+
20.0 * Math.sin(2.0 * x * Math.PI)) *
|
|
121
|
+
2.0) /
|
|
122
|
+
3.0;
|
|
123
|
+
ret +=
|
|
124
|
+
((160.0 * Math.sin((y * Math.PI) / 3.0) +
|
|
125
|
+
320 * Math.sin((y * Math.PI) / 30.0)) *
|
|
126
|
+
2.0) /
|
|
127
|
+
3.0;
|
|
128
|
+
return ret;
|
|
129
|
+
}
|
|
104
130
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
131
|
+
/**
|
|
132
|
+
* 经度转换函数
|
|
133
|
+
* @param x 经度偏移
|
|
134
|
+
* @param y 纬度偏移
|
|
135
|
+
* @returns {number} 经度转换值
|
|
136
|
+
*/
|
|
137
|
+
function transformLng(x: any, y: any): any {
|
|
138
|
+
let ret =
|
|
139
|
+
300.0 +
|
|
140
|
+
x +
|
|
141
|
+
2.0 * y +
|
|
142
|
+
0.1 * x * x +
|
|
143
|
+
0.1 * x * y +
|
|
144
|
+
0.1 * Math.sqrt(Math.abs(x));
|
|
145
|
+
ret +=
|
|
146
|
+
((20.0 * Math.sin(6.0 * x * Math.PI) + 20.0 * Math.sin(x * Math.PI)) *
|
|
147
|
+
2.0) /
|
|
148
|
+
3.0;
|
|
149
|
+
ret +=
|
|
150
|
+
((150.0 * Math.sin((x * Math.PI) / 3.0) +
|
|
151
|
+
300.0 * Math.sin((x * Math.PI) / 15.0)) *
|
|
152
|
+
2.0) /
|
|
153
|
+
3.0;
|
|
154
|
+
return ret;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
let dLat = transformLat(wgsLng - 105.0, wgsLat - 35.0);
|
|
158
|
+
let dLng = transformLng(wgsLng - 105.0, wgsLat - 35.0);
|
|
159
|
+
const radLat = (wgsLat / 180.0) * Math.PI;
|
|
160
|
+
let magic = Math.sin(radLat);
|
|
161
|
+
magic = 1 - ee * magic * magic;
|
|
162
|
+
const sqrtMagic = Math.sqrt(magic);
|
|
163
|
+
dLat = (dLat * 180.0) / (((a * (1 - ee)) / (magic * sqrtMagic)) * Math.PI);
|
|
164
|
+
dLng = (dLng * 180.0) / ((a / sqrtMagic) * Math.cos(radLat) * Math.PI);
|
|
165
|
+
const gcjLat = wgsLat + dLat;
|
|
166
|
+
const gcjLng = wgsLng + dLng;
|
|
167
|
+
|
|
168
|
+
return [gcjLng, gcjLat];
|
|
117
169
|
}
|
|
118
170
|
|
|
119
171
|
/**
|
|
120
|
-
*
|
|
121
|
-
* @param {number} lat - 纬度
|
|
172
|
+
* 判断是否为正确的坐标范围
|
|
122
173
|
* @param {number} lng - 经度
|
|
123
|
-
* @
|
|
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
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
204
|
+
const [leftTopLng, leftTopLat] = leftTop;
|
|
205
|
+
const [rightBottomLng, rightBottomLat] = rightBottom;
|
|
206
|
+
|
|
207
|
+
// 计算四个角点
|
|
208
|
+
const leftTopPoint = [Number(leftTopLng), Number(leftTopLat)];
|
|
209
|
+
const rightTopPoint = [Number(rightBottomLng), Number(leftTopLat)];
|
|
210
|
+
const rightBottomPoint = [Number(rightBottomLng), Number(rightBottomLat)];
|
|
211
|
+
const leftBottomPoint = [Number(leftTopLng), Number(rightBottomLat)];
|
|
212
|
+
|
|
213
|
+
// 返回五个点的坐标对(首尾相同,形成闭合矩形)
|
|
214
|
+
return [
|
|
215
|
+
leftTopPoint,
|
|
216
|
+
rightTopPoint,
|
|
217
|
+
rightBottomPoint,
|
|
218
|
+
leftBottomPoint,
|
|
219
|
+
leftTopPoint, // 闭合矩形
|
|
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
|
-
|
|
152
|
-
|
|
233
|
+
// 输入校验:限制在 1~18
|
|
234
|
+
level = Math.max(1, Math.min(18, Math.floor(level)));
|
|
153
235
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
}
|
|
236
|
+
// 计算指定 level 对应的高度(level >= 2 时使用指数衰减)
|
|
237
|
+
function getHeight(lvl: number) {
|
|
238
|
+
if (lvl === 1) {
|
|
239
|
+
return Infinity; // level=1 表示“最大高度”,逻辑上为无穷大
|
|
240
|
+
} else {
|
|
241
|
+
return 32000000 / Math.pow(2, lvl - 2);
|
|
161
242
|
}
|
|
243
|
+
}
|
|
162
244
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
245
|
+
const endHeight = getHeight(level); // 当前 level 的“粗略”高度
|
|
246
|
+
const startHeight = level < 18 ? getHeight(level + 1) : 0; // 下一级更细
|
|
247
|
+
return { startHeight, endHeight };
|
|
166
248
|
}
|
|
167
249
|
|
|
168
250
|
/**
|
|
169
|
-
*
|
|
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
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
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;
|
|
187
272
|
}
|
|
188
273
|
|
|
189
274
|
/**
|
|
@@ -194,109 +279,224 @@ export function getLevelMiddleHeight(level: number): number {
|
|
|
194
279
|
*
|
|
195
280
|
* @param {number} level - 缩放级别 [1, 18]
|
|
196
281
|
* @returns {[number, number]} [开始高度, 结束高度](单位:米)
|
|
282
|
+
* @example
|
|
283
|
+
* ```javascript
|
|
284
|
+
* getLevelHeightRange(11); // 返回level=11对应的高度范围
|
|
285
|
+
* ```
|
|
197
286
|
*/
|
|
198
287
|
export function getLevelHeightRange(level: number): [number, number] {
|
|
199
|
-
|
|
200
|
-
|
|
288
|
+
const { startHeight, endHeight } = getMapRangeHeightByLevel(level);
|
|
289
|
+
return [startHeight, endHeight];
|
|
201
290
|
}
|
|
202
291
|
|
|
203
292
|
/**
|
|
204
|
-
*
|
|
293
|
+
* 根据高度反推地图缩放级别(1~18)
|
|
205
294
|
* @param {number} height - 当前视野高度(米)
|
|
206
|
-
* @returns {number}
|
|
295
|
+
* @returns {number} 对应的地图缩放级别
|
|
296
|
+
* @example
|
|
297
|
+
* ```javascript
|
|
298
|
+
* getHeightToLevel(100000); // 根据高度返回对应的缩放级别
|
|
299
|
+
* ```
|
|
207
300
|
*/
|
|
208
301
|
export function getHeightToLevel(height: number): number {
|
|
209
|
-
|
|
210
|
-
|
|
302
|
+
if (height > 32000000) return 1;
|
|
303
|
+
if (height <= 0) return 18;
|
|
211
304
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
305
|
+
// 解公式:height = 32e6 / 2^(level-2)
|
|
306
|
+
let level = 2 + Math.log(32000000 / height) / Math.log(2);
|
|
307
|
+
level = Math.floor(level);
|
|
215
308
|
|
|
216
|
-
|
|
217
|
-
|
|
309
|
+
// 限制在 1~18
|
|
310
|
+
return Math.max(1, Math.min(18, level));
|
|
218
311
|
}
|
|
219
312
|
|
|
220
|
-
|
|
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
|
+
*/
|
|
221
324
|
export function convertPosition(
|
|
222
|
-
|
|
325
|
+
position: string[] | string[][] | string[][][]
|
|
223
326
|
): number[] | number[][] | number[][][] {
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
} else {
|
|
231
|
-
return Number(innerItem);
|
|
232
|
-
}
|
|
233
|
-
});
|
|
327
|
+
return position.map((item) => {
|
|
328
|
+
if (Array.isArray(item)) {
|
|
329
|
+
return item.map((innerItem) => {
|
|
330
|
+
if (Array.isArray(innerItem)) {
|
|
331
|
+
// 第三层,将每个字符串转数字
|
|
332
|
+
return innerItem.map((str) => Number(str));
|
|
234
333
|
} else {
|
|
235
|
-
|
|
334
|
+
return Number(innerItem);
|
|
236
335
|
}
|
|
237
|
-
|
|
336
|
+
});
|
|
337
|
+
} else {
|
|
338
|
+
return Number(item);
|
|
339
|
+
}
|
|
340
|
+
}) as number[] | number[][] | number[][][];
|
|
238
341
|
}
|
|
239
342
|
|
|
240
|
-
|
|
343
|
+
/**
|
|
344
|
+
* mars3d 地图重写瓦片加载失败的回调函数
|
|
345
|
+
* 用于过滤掉控制台中瓦片加载失败的报错,提高开发体验
|
|
346
|
+
* @example
|
|
347
|
+
* ```javascript
|
|
348
|
+
* // 在地图初始化后调用
|
|
349
|
+
* mars3dTileErrorHandler();
|
|
350
|
+
* ```
|
|
351
|
+
*/
|
|
241
352
|
export function mars3dTileErrorHandler() {
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
353
|
+
// 确保 Cesium 已加载
|
|
354
|
+
if (typeof Cesium !== "undefined" && Cesium.TileProviderError) {
|
|
355
|
+
const originalReportError = Cesium.TileProviderError.reportError;
|
|
356
|
+
|
|
357
|
+
Cesium.TileProviderError.reportError = function (
|
|
358
|
+
existingError: any,
|
|
359
|
+
provider: any,
|
|
360
|
+
errorEvent: any,
|
|
361
|
+
message: any,
|
|
362
|
+
x: any,
|
|
363
|
+
y: any,
|
|
364
|
+
level: any,
|
|
365
|
+
error: any
|
|
366
|
+
) {
|
|
367
|
+
// 判断是否为“瓦片不存在”类错误(如 404、fetch 失败等)
|
|
368
|
+
const shouldIgnore =
|
|
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");
|
|
375
|
+
|
|
376
|
+
if (shouldIgnore) {
|
|
377
|
+
// 静默处理:不打印日志,但仍可触发 errorEvent(供自定义监听)
|
|
378
|
+
if (Cesium.defined(errorEvent) && errorEvent.numberOfListeners > 0) {
|
|
379
|
+
let tileError = existingError;
|
|
380
|
+
if (Cesium.defined(existingError)) {
|
|
381
|
+
tileError.provider = provider;
|
|
382
|
+
tileError.message = message;
|
|
383
|
+
tileError.x = x;
|
|
384
|
+
tileError.y = y;
|
|
385
|
+
tileError.level = level;
|
|
386
|
+
tileError.retry = false;
|
|
387
|
+
tileError.error = error;
|
|
388
|
+
tileError.timesRetried =
|
|
389
|
+
Cesium.defaultValue(tileError.timesRetried, 0) + 1;
|
|
390
|
+
} else {
|
|
391
|
+
tileError = new Cesium.TileProviderError(
|
|
392
|
+
provider,
|
|
393
|
+
message,
|
|
394
|
+
x,
|
|
395
|
+
y,
|
|
396
|
+
level,
|
|
397
|
+
0,
|
|
398
|
+
error
|
|
399
|
+
);
|
|
400
|
+
}
|
|
401
|
+
errorEvent.raiseEvent(tileError);
|
|
402
|
+
return tileError;
|
|
403
|
+
} else {
|
|
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
|
+
);
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
// 非忽略错误:走原始逻辑
|
|
421
|
+
return originalReportError.apply(this, arguments);
|
|
422
|
+
};
|
|
423
|
+
}
|
|
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);
|
|
302
502
|
}
|