gis-common 4.2.17 → 4.2.19
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/gis-common.es.js +1023 -1052
- package/dist/gis-common.umd.js +1 -1
- package/dist/utils/MessageUtil.d.ts +1 -1
- package/dist/utils/StringUtil.d.ts +0 -8
- package/package.json +1 -1
package/dist/gis-common.es.js
CHANGED
|
@@ -150,142 +150,505 @@ class Cookie {
|
|
|
150
150
|
}
|
|
151
151
|
}
|
|
152
152
|
}
|
|
153
|
-
const
|
|
153
|
+
const MathUtil = {
|
|
154
|
+
DEG2RAD: Math.PI / 180,
|
|
155
|
+
RAD2DEG: 180 / Math.PI,
|
|
156
|
+
randInt(low, high) {
|
|
157
|
+
return low + Math.floor(Math.random() * (high - low + 1));
|
|
158
|
+
},
|
|
159
|
+
randFloat(low, high) {
|
|
160
|
+
return low + Math.random() * (high - low);
|
|
161
|
+
},
|
|
154
162
|
/**
|
|
155
|
-
*
|
|
163
|
+
* 角度转弧度
|
|
156
164
|
*
|
|
157
|
-
* @param
|
|
158
|
-
* @returns
|
|
165
|
+
* @param {*} degrees
|
|
166
|
+
* @returns {*}
|
|
159
167
|
*/
|
|
160
|
-
|
|
161
|
-
return
|
|
162
|
-
},
|
|
163
|
-
asArray(obj) {
|
|
164
|
-
return this.isEmpty(obj) ? [] : Array.isArray(obj) ? obj : [obj];
|
|
165
|
-
},
|
|
166
|
-
asNumber(a) {
|
|
167
|
-
return Number.isNaN(Number(a)) ? 0 : Number(a);
|
|
168
|
+
deg2Rad(degrees) {
|
|
169
|
+
return degrees * this.DEG2RAD;
|
|
168
170
|
},
|
|
169
171
|
/**
|
|
170
|
-
*
|
|
172
|
+
* 弧度转角度
|
|
171
173
|
*
|
|
172
|
-
* @param
|
|
173
|
-
* @returns
|
|
174
|
+
* @param {*} radians
|
|
175
|
+
* @returns {*}
|
|
174
176
|
*/
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
case "Object":
|
|
181
|
-
case "Array":
|
|
182
|
-
return JSON.stringify(value);
|
|
183
|
-
default:
|
|
184
|
-
return value;
|
|
185
|
-
}
|
|
186
|
-
}
|
|
177
|
+
rad2Deg(radians) {
|
|
178
|
+
return radians * this.RAD2DEG;
|
|
179
|
+
},
|
|
180
|
+
round(value, n = 2) {
|
|
181
|
+
return Math.round(value * Math.pow(10, n)) / Math.pow(10, n);
|
|
187
182
|
},
|
|
188
183
|
/**
|
|
189
|
-
*
|
|
184
|
+
* 将数值限制在指定范围内
|
|
190
185
|
*
|
|
191
|
-
* @param
|
|
192
|
-
* @
|
|
186
|
+
* @param val 需要限制的数值
|
|
187
|
+
* @param min 最小值
|
|
188
|
+
* @param max 最大值
|
|
189
|
+
* @returns 返回限制后的数值
|
|
193
190
|
*/
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
191
|
+
clamp(val, min, max) {
|
|
192
|
+
return Math.max(min, Math.min(max, val));
|
|
193
|
+
}
|
|
194
|
+
};
|
|
195
|
+
class Color {
|
|
196
|
+
constructor(r, g, b, a) {
|
|
197
|
+
__publicField(this, "_r");
|
|
198
|
+
__publicField(this, "_g");
|
|
199
|
+
__publicField(this, "_b");
|
|
200
|
+
__publicField(this, "_alpha");
|
|
201
|
+
this._validateColorChannel(r);
|
|
202
|
+
this._validateColorChannel(g);
|
|
203
|
+
this._validateColorChannel(b);
|
|
204
|
+
this._r = r;
|
|
205
|
+
this._g = g;
|
|
206
|
+
this._b = b;
|
|
207
|
+
this._alpha = MathUtil.clamp(a || 1, 0, 1);
|
|
208
|
+
}
|
|
209
|
+
_validateColorChannel(channel) {
|
|
210
|
+
if (channel < 0 || channel > 255) {
|
|
211
|
+
throw new Error("Color channel must be between 0 and 255.");
|
|
210
212
|
}
|
|
211
|
-
}
|
|
213
|
+
}
|
|
214
|
+
toString() {
|
|
215
|
+
return `rgba(${this._r}, ${this._g}, ${this._b}, ${this._alpha})`;
|
|
216
|
+
}
|
|
217
|
+
toJson() {
|
|
218
|
+
return { r: this._r, g: this._g, b: this._b, a: this._alpha };
|
|
219
|
+
}
|
|
220
|
+
get rgba() {
|
|
221
|
+
return `rgba(${this._r}, ${this._g}, ${this._b}, ${this._alpha})`;
|
|
222
|
+
}
|
|
223
|
+
get hex() {
|
|
224
|
+
return Color.rgb2hex(this._r, this._g, this._b, this._alpha);
|
|
225
|
+
}
|
|
226
|
+
setAlpha(a) {
|
|
227
|
+
this._alpha = MathUtil.clamp(a, 0, 1);
|
|
228
|
+
return this;
|
|
229
|
+
}
|
|
230
|
+
// 设置颜色的RGB值
|
|
231
|
+
setRgb(r, g, b) {
|
|
232
|
+
this._validateColorChannel(r);
|
|
233
|
+
this._validateColorChannel(g);
|
|
234
|
+
this._validateColorChannel(b);
|
|
235
|
+
this._r = r;
|
|
236
|
+
this._g = g;
|
|
237
|
+
this._b = b;
|
|
238
|
+
return this;
|
|
239
|
+
}
|
|
212
240
|
/**
|
|
213
|
-
*
|
|
241
|
+
* 从RGBA字符串创建Color对象
|
|
214
242
|
*
|
|
215
|
-
* @param
|
|
216
|
-
* @returns
|
|
243
|
+
* @param rgbaValue RGBA颜色值字符串,格式为"rgba(r,g,b,a)"或"rgb(r,g,b)"
|
|
244
|
+
* @returns 返回Color对象
|
|
245
|
+
* @throws 如果rgbaValue不是有效的RGBA颜色值,则抛出错误
|
|
217
246
|
*/
|
|
218
|
-
|
|
219
|
-
const
|
|
220
|
-
if (
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
247
|
+
static fromRgba(rgbaValue) {
|
|
248
|
+
const rgbaMatch = rgbaValue.match(/^rgba?\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(,\s*([\d.]+))?\s*\)$/);
|
|
249
|
+
if (!rgbaMatch) throw new Error("Invalid RGBA color value");
|
|
250
|
+
const r = parseInt(rgbaMatch[1], 10);
|
|
251
|
+
const g = parseInt(rgbaMatch[2], 10);
|
|
252
|
+
const b = parseInt(rgbaMatch[3], 10);
|
|
253
|
+
const a = rgbaMatch[5] ? parseFloat(rgbaMatch[5]) : 1;
|
|
254
|
+
return new Color(r, g, b, a);
|
|
255
|
+
}
|
|
226
256
|
/**
|
|
227
|
-
*
|
|
257
|
+
* 将十六进制颜色值转换为颜色对象
|
|
228
258
|
*
|
|
229
|
-
* @
|
|
259
|
+
* @param hexValue 十六进制颜色值,可带或不带#前缀,支持3位和6位表示
|
|
260
|
+
* @returns 返回颜色对象
|
|
230
261
|
*/
|
|
231
|
-
|
|
232
|
-
const
|
|
233
|
-
|
|
234
|
-
};
|
|
235
|
-
|
|
236
|
-
|
|
262
|
+
static fromHex(hexValue, a = 1) {
|
|
263
|
+
const rgxShort = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
|
|
264
|
+
const hex = hexValue.replace(rgxShort, (m, r2, g2, b2) => r2 + r2 + g2 + g2 + b2 + b2);
|
|
265
|
+
const rgx = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i;
|
|
266
|
+
const rgb = rgx.exec(hex);
|
|
267
|
+
if (!rgb) {
|
|
268
|
+
throw new Error("Invalid HEX color value");
|
|
269
|
+
}
|
|
270
|
+
const r = parseInt(rgb[1], 16);
|
|
271
|
+
const g = parseInt(rgb[2], 16);
|
|
272
|
+
const b = parseInt(rgb[3], 16);
|
|
273
|
+
return new Color(r, g, b, a);
|
|
274
|
+
}
|
|
237
275
|
/**
|
|
238
|
-
*
|
|
276
|
+
* 从 HSL 字符串创建颜色对象
|
|
239
277
|
*
|
|
240
|
-
* @param
|
|
241
|
-
* @returns
|
|
278
|
+
* @param hsl HSL 字符串,格式为 hsl(h, s%, l%) 或 hsla(h, s%, l%, a)
|
|
279
|
+
* @returns 返回颜色对象,如果 hsl 字符串无效则返回 null
|
|
242
280
|
*/
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
if (
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
if (
|
|
254
|
-
|
|
255
|
-
|
|
281
|
+
static fromHsl(hslValue) {
|
|
282
|
+
const hsl = /hsl\((\d+),\s*([\d.]+)%,\s*([\d.]+)%\)/g.exec(hslValue) || /hsla\((\d+),\s*([\d.]+)%,\s*([\d.]+)%,\s*([\d.]+)\)/g.exec(hslValue);
|
|
283
|
+
if (!hsl) {
|
|
284
|
+
throw new Error("Invalid HSL color value");
|
|
285
|
+
}
|
|
286
|
+
const h = parseInt(hsl[1], 10) / 360;
|
|
287
|
+
const s = parseInt(hsl[2], 10) / 100;
|
|
288
|
+
const l = parseInt(hsl[3], 10) / 100;
|
|
289
|
+
const a = hsl[4] ? parseFloat(hsl[4]) : 1;
|
|
290
|
+
function hue2rgb(p, q, t) {
|
|
291
|
+
if (t < 0) t += 1;
|
|
292
|
+
if (t > 1) t -= 1;
|
|
293
|
+
if (t < 1 / 6) return p + (q - p) * 6 * t;
|
|
294
|
+
if (t < 1 / 2) return q;
|
|
295
|
+
if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
|
|
296
|
+
return p;
|
|
297
|
+
}
|
|
298
|
+
let r, g, b;
|
|
299
|
+
if (s === 0) {
|
|
300
|
+
r = g = b = l;
|
|
256
301
|
} else {
|
|
257
|
-
|
|
302
|
+
const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
|
|
303
|
+
const p = 2 * l - q;
|
|
304
|
+
r = hue2rgb(p, q, h + 1 / 3);
|
|
305
|
+
g = hue2rgb(p, q, h);
|
|
306
|
+
b = hue2rgb(p, q, h - 1 / 3);
|
|
258
307
|
}
|
|
259
|
-
return
|
|
260
|
-
}
|
|
308
|
+
return new Color(Math.round(r * 255), Math.round(g * 255), Math.round(b * 255), a);
|
|
309
|
+
}
|
|
261
310
|
/**
|
|
262
|
-
*
|
|
311
|
+
* 从字符串中创建颜色对象
|
|
263
312
|
*
|
|
264
|
-
* @param
|
|
265
|
-
* @
|
|
266
|
-
* @
|
|
313
|
+
* @param str 字符串类型的颜色值,支持rgba、hex、hsl格式
|
|
314
|
+
* @returns 返回创建的颜色对象
|
|
315
|
+
* @throws 当颜色值无效时,抛出错误
|
|
267
316
|
*/
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
317
|
+
static from(str) {
|
|
318
|
+
if (this.isRgb(str)) {
|
|
319
|
+
return this.fromRgba(str);
|
|
320
|
+
} else if (this.isHex(str)) {
|
|
321
|
+
return this.fromHex(str);
|
|
322
|
+
} else if (this.isHsl(str)) {
|
|
323
|
+
return this.fromHsl(str);
|
|
324
|
+
} else {
|
|
325
|
+
throw new Error("Invalid color value");
|
|
275
326
|
}
|
|
276
|
-
|
|
277
|
-
},
|
|
327
|
+
}
|
|
278
328
|
/**
|
|
279
|
-
*
|
|
329
|
+
* 将RGB颜色值转换为十六进制颜色值
|
|
280
330
|
*
|
|
281
|
-
* @param
|
|
282
|
-
* @param
|
|
283
|
-
* @param
|
|
284
|
-
* @param
|
|
285
|
-
* @returns
|
|
331
|
+
* @param r 红色分量值,取值范围0-255
|
|
332
|
+
* @param g 绿色分量值,取值范围0-255
|
|
333
|
+
* @param b 蓝色分量值,取值范围0-255
|
|
334
|
+
* @param a 可选参数,透明度分量值,取值范围0-1
|
|
335
|
+
* @returns 十六进制颜色值,格式为#RRGGBB或#RRGGBBAA
|
|
286
336
|
*/
|
|
287
|
-
|
|
288
|
-
|
|
337
|
+
static rgb2hex(r, g, b, a) {
|
|
338
|
+
var hex = "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1);
|
|
339
|
+
if (a !== void 0) {
|
|
340
|
+
const alpha = Math.round(a * 255).toString(16).padStart(2, "0");
|
|
341
|
+
return hex + alpha;
|
|
342
|
+
}
|
|
343
|
+
return hex;
|
|
344
|
+
}
|
|
345
|
+
static isHex(a) {
|
|
346
|
+
return /(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)/i.test(a);
|
|
347
|
+
}
|
|
348
|
+
static isRgb(a) {
|
|
349
|
+
return /^rgba?\s*\(\s*\d+\s*,\s*\d+\s*,\s*\d+\s*(,\s*[\d.]+)?\s*\)$/.test(a);
|
|
350
|
+
}
|
|
351
|
+
static isHsl(a) {
|
|
352
|
+
return /^(hsl|hsla)\(\d+,\s*[\d.]+%,\s*[\d.]+%(,\s*[\d.]+)?\)$/.test(a);
|
|
353
|
+
}
|
|
354
|
+
static isColor(a) {
|
|
355
|
+
return this.isHex(a) || this.isRgb(a) || this.isHsl(a);
|
|
356
|
+
}
|
|
357
|
+
static random() {
|
|
358
|
+
let r = Math.floor(Math.random() * 256);
|
|
359
|
+
let g = Math.floor(Math.random() * 256);
|
|
360
|
+
let b = Math.floor(Math.random() * 256);
|
|
361
|
+
let a = Math.random();
|
|
362
|
+
return new Color(r, g, b, a);
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
class CanvasDrawer {
|
|
366
|
+
constructor(el) {
|
|
367
|
+
__publicField(this, "context", null);
|
|
368
|
+
if (typeof el === "string") {
|
|
369
|
+
el = document.querySelector("#" + el);
|
|
370
|
+
if (!el) {
|
|
371
|
+
throw new Error("Element not found");
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
if (el instanceof HTMLElement) {
|
|
375
|
+
const canvas = el;
|
|
376
|
+
if (canvas.getContext) {
|
|
377
|
+
this.context = canvas.getContext("2d");
|
|
378
|
+
} else {
|
|
379
|
+
throw new Error("getContext is not available on this element");
|
|
380
|
+
}
|
|
381
|
+
} else {
|
|
382
|
+
throw new Error("Element is not an HTMLElement");
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
/**
|
|
386
|
+
* 绘制线条
|
|
387
|
+
*
|
|
388
|
+
* @param start 起始坐标点
|
|
389
|
+
* @param end 终止坐标点
|
|
390
|
+
* @param options 绘制选项,包括线条宽度和颜色
|
|
391
|
+
* @throws 当画布上下文不存在时抛出错误
|
|
392
|
+
*/
|
|
393
|
+
drawLine({ x: startX, y: startY }, { x: endX, y: endY }, options = {}) {
|
|
394
|
+
if (!this.context) {
|
|
395
|
+
throw new Error("Canvas context is null or undefined");
|
|
396
|
+
}
|
|
397
|
+
this.context.beginPath();
|
|
398
|
+
const width = options.width || 1;
|
|
399
|
+
const color = options.color || "#000";
|
|
400
|
+
this.context.lineWidth = width;
|
|
401
|
+
this.context.strokeStyle = color;
|
|
402
|
+
this.context.moveTo(startX, startY);
|
|
403
|
+
this.context.lineTo(endX, endY);
|
|
404
|
+
this.context.stroke();
|
|
405
|
+
}
|
|
406
|
+
/**
|
|
407
|
+
* 绘制圆弧
|
|
408
|
+
*
|
|
409
|
+
* @param x 圆心x坐标
|
|
410
|
+
* @param y 圆心y坐标
|
|
411
|
+
* @param radius 半径
|
|
412
|
+
* @param startAngle 起始角度(度)
|
|
413
|
+
* @param endAngle 结束角度(度)
|
|
414
|
+
* @param anticlockwise 是否逆时针绘制
|
|
415
|
+
* @param isFill 是否填充
|
|
416
|
+
* @param bgColor 背景颜色
|
|
417
|
+
* @throws 当Canvas context为null或undefined时抛出错误
|
|
418
|
+
*/
|
|
419
|
+
drawArc({ x, y }, radius, startAngle, endAngle, anticlockwise, isFill, bgColor) {
|
|
420
|
+
if (!this.context) {
|
|
421
|
+
throw new Error("Canvas context is null or undefined");
|
|
422
|
+
}
|
|
423
|
+
if (isFill) {
|
|
424
|
+
this.context.fillStyle = bgColor;
|
|
425
|
+
this.context.beginPath();
|
|
426
|
+
this.context.arc(x, y, radius, MathUtil.deg2Rad(startAngle), MathUtil.deg2Rad(endAngle), anticlockwise);
|
|
427
|
+
this.context.fill();
|
|
428
|
+
} else {
|
|
429
|
+
this.context.strokeStyle = bgColor;
|
|
430
|
+
this.context.beginPath();
|
|
431
|
+
this.context.arc(x, y, radius, MathUtil.deg2Rad(startAngle), MathUtil.deg2Rad(endAngle), anticlockwise);
|
|
432
|
+
this.context.stroke();
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
static createCanvas(width = 1, height = 1) {
|
|
436
|
+
const canvas = document.createElement("canvas");
|
|
437
|
+
if (width) {
|
|
438
|
+
canvas.width = width;
|
|
439
|
+
}
|
|
440
|
+
if (height) {
|
|
441
|
+
canvas.height = height;
|
|
442
|
+
}
|
|
443
|
+
return canvas;
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
class EventDispatcher {
|
|
447
|
+
constructor() {
|
|
448
|
+
__publicField(this, "_listeners");
|
|
449
|
+
__publicField(this, "_mutex", {});
|
|
450
|
+
__publicField(this, "_context");
|
|
451
|
+
}
|
|
452
|
+
addEventListener(type, listener, context, mutexStatus) {
|
|
453
|
+
if (this._listeners === void 0) this._listeners = {};
|
|
454
|
+
this._context = context;
|
|
455
|
+
const mutex = this._mutex;
|
|
456
|
+
const listeners = this._listeners;
|
|
457
|
+
if (listeners[type] === void 0) {
|
|
458
|
+
listeners[type] = [];
|
|
459
|
+
}
|
|
460
|
+
if (listeners[type].indexOf(listener) === -1) {
|
|
461
|
+
if (mutexStatus) {
|
|
462
|
+
mutex[type] = listener;
|
|
463
|
+
}
|
|
464
|
+
listeners[type].push(listener);
|
|
465
|
+
}
|
|
466
|
+
return this;
|
|
467
|
+
}
|
|
468
|
+
hasEventListener(type, listener) {
|
|
469
|
+
if (this._listeners === null || this._listeners === void 0) return false;
|
|
470
|
+
const listeners = this._listeners;
|
|
471
|
+
return listeners[type] !== void 0 && listeners[type].indexOf(listener) !== -1;
|
|
472
|
+
}
|
|
473
|
+
removeEventListener(type, listener) {
|
|
474
|
+
if (this._listeners === void 0) return;
|
|
475
|
+
const listeners = this._listeners;
|
|
476
|
+
const listenerArray = listeners[type];
|
|
477
|
+
if (this._mutex[type] === listener) {
|
|
478
|
+
this._mutex[type] = null;
|
|
479
|
+
}
|
|
480
|
+
if (listenerArray !== void 0) {
|
|
481
|
+
const index = listenerArray.map((d) => d.toString()).indexOf(listener.toString());
|
|
482
|
+
if (index !== -1) {
|
|
483
|
+
listenerArray.splice(index, 1);
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
dispatchEvent(event) {
|
|
488
|
+
if (this._listeners === void 0) return;
|
|
489
|
+
const listeners = this._listeners;
|
|
490
|
+
const listenerArray = listeners[event.type];
|
|
491
|
+
if (listenerArray !== void 0) {
|
|
492
|
+
event.target = this;
|
|
493
|
+
const array = listenerArray.slice(0);
|
|
494
|
+
if (this._mutex[event.type] !== void 0) {
|
|
495
|
+
const find = array.find((item) => item === this._mutex[event.type]);
|
|
496
|
+
if (find) {
|
|
497
|
+
find.call(this._context || this, event);
|
|
498
|
+
return;
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
for (let i = 0, l = array.length; i < l; i++) {
|
|
502
|
+
const item = array[i];
|
|
503
|
+
if (typeof item === "function") {
|
|
504
|
+
item.call(this._context || this, event);
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
removeAllListener() {
|
|
510
|
+
this._mutex = {};
|
|
511
|
+
for (const key in this._listeners) {
|
|
512
|
+
this._listeners[key] = [];
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
const Util = {
|
|
517
|
+
/**
|
|
518
|
+
* 获取数据类型
|
|
519
|
+
*
|
|
520
|
+
* @param data 待判断的数据
|
|
521
|
+
* @returns 返回数据类型字符串
|
|
522
|
+
*/
|
|
523
|
+
getDataType(data) {
|
|
524
|
+
return Object.prototype.toString.call(data).slice(8, -1);
|
|
525
|
+
},
|
|
526
|
+
asArray(obj) {
|
|
527
|
+
return this.isEmpty(obj) ? [] : Array.isArray(obj) ? obj : [obj];
|
|
528
|
+
},
|
|
529
|
+
asNumber(a) {
|
|
530
|
+
return Number.isNaN(Number(a)) ? 0 : Number(a);
|
|
531
|
+
},
|
|
532
|
+
/**
|
|
533
|
+
* 将值转换为字符串
|
|
534
|
+
*
|
|
535
|
+
* @param value 要转换的值
|
|
536
|
+
* @returns 转换后的字符串,如果值为空,则返回空字符串
|
|
537
|
+
*/
|
|
538
|
+
asString(value) {
|
|
539
|
+
if (this.isEmpty(value)) {
|
|
540
|
+
return "";
|
|
541
|
+
} else {
|
|
542
|
+
switch (this.getDataType(value)) {
|
|
543
|
+
case "Object":
|
|
544
|
+
case "Array":
|
|
545
|
+
return JSON.stringify(value);
|
|
546
|
+
default:
|
|
547
|
+
return value;
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
},
|
|
551
|
+
/**
|
|
552
|
+
* 判断传入的值是否为空
|
|
553
|
+
*
|
|
554
|
+
* @param value 待判断的值
|
|
555
|
+
* @returns 返回布尔值,表示是否为空
|
|
556
|
+
*/
|
|
557
|
+
isEmpty(value) {
|
|
558
|
+
if (value == null) {
|
|
559
|
+
return true;
|
|
560
|
+
}
|
|
561
|
+
const type = this.getDataType(value);
|
|
562
|
+
switch (type) {
|
|
563
|
+
case "String":
|
|
564
|
+
return value.trim() === "";
|
|
565
|
+
case "Array":
|
|
566
|
+
return !value.length;
|
|
567
|
+
case "Object":
|
|
568
|
+
return !Object.keys(value).length;
|
|
569
|
+
case "Boolean":
|
|
570
|
+
return !value;
|
|
571
|
+
default:
|
|
572
|
+
return false;
|
|
573
|
+
}
|
|
574
|
+
},
|
|
575
|
+
/**
|
|
576
|
+
* 将JSON对象转换为FormData对象
|
|
577
|
+
*
|
|
578
|
+
* @param json 待转换的JSON对象,其属性值为字符串或Blob类型
|
|
579
|
+
* @returns 转换后的FormData对象
|
|
580
|
+
*/
|
|
581
|
+
json2form(json) {
|
|
582
|
+
const formData = new FormData();
|
|
583
|
+
if (this.isEmpty(json)) return formData;
|
|
584
|
+
Object.keys(json).forEach((key) => {
|
|
585
|
+
formData.append(key, json[key] instanceof Object ? JSON.stringify(json[key]) : json[key]);
|
|
586
|
+
});
|
|
587
|
+
return formData;
|
|
588
|
+
},
|
|
589
|
+
/**
|
|
590
|
+
* 生成GUID
|
|
591
|
+
*
|
|
592
|
+
* @returns 返回一个由8个16进制数组成的GUID字符串
|
|
593
|
+
*/
|
|
594
|
+
guid() {
|
|
595
|
+
const S4 = function() {
|
|
596
|
+
return ((1 + Math.random()) * 65536 | 0).toString(16).substring(1);
|
|
597
|
+
};
|
|
598
|
+
return S4() + S4() + S4() + S4() + S4() + S4() + S4() + S4();
|
|
599
|
+
},
|
|
600
|
+
/**
|
|
601
|
+
* 将参数进行解码并返回解码后的字符串
|
|
602
|
+
*
|
|
603
|
+
* @param args 参数
|
|
604
|
+
* @returns 解码后的字符串
|
|
605
|
+
*/
|
|
606
|
+
decodeDict(...args) {
|
|
607
|
+
let res = "";
|
|
608
|
+
if (args.length > 1) {
|
|
609
|
+
const items = args.slice(1, args.length % 2 === 0 ? args.length - 1 : args.length);
|
|
610
|
+
for (let i = 0; i < items.length; i = i + 2) {
|
|
611
|
+
const item = items[i];
|
|
612
|
+
if (args[0] === item) {
|
|
613
|
+
res = items[i + 1];
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
if (!res && args.length % 2 === 0) {
|
|
617
|
+
res = args[args.length - 1];
|
|
618
|
+
}
|
|
619
|
+
} else {
|
|
620
|
+
res = args[0];
|
|
621
|
+
}
|
|
622
|
+
return res;
|
|
623
|
+
},
|
|
624
|
+
/**
|
|
625
|
+
* 将一个或多个对象的所有可枚举属性复制到目标对象。
|
|
626
|
+
*
|
|
627
|
+
* @param dest 目标对象,用于接收复制的属性。
|
|
628
|
+
* @param args 一个或多个源对象,用于提供要复制的属性。
|
|
629
|
+
* @returns 返回目标对象,包含所有复制的属性。
|
|
630
|
+
*/
|
|
631
|
+
extend(dest, ...args) {
|
|
632
|
+
let i, j, len, src;
|
|
633
|
+
for (j = 0, len = args.length; j < len; j++) {
|
|
634
|
+
src = args[j];
|
|
635
|
+
for (i in src) {
|
|
636
|
+
dest[i] = src[i];
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
return dest;
|
|
640
|
+
},
|
|
641
|
+
/**
|
|
642
|
+
* 将扁平化数组转换为树形结构数组
|
|
643
|
+
*
|
|
644
|
+
* @param data 扁平化数组
|
|
645
|
+
* @param idPropertyName 数据中标识id的字段名,默认为'id'
|
|
646
|
+
* @param parentIdPropertyName 数据中标识父节点id的字段名,默认为'parentId'
|
|
647
|
+
* @param childrenPropertyName 树形结构中标识子节点的字段名,默认为'children'
|
|
648
|
+
* @returns 转换后的树形结构数组
|
|
649
|
+
*/
|
|
650
|
+
convertToTree2(data, idPropertyName = "id", parentIdPropertyName = "parentId", childrenPropertyName = "children") {
|
|
651
|
+
const result = [];
|
|
289
652
|
function buildChildren(item) {
|
|
290
653
|
const children = data.filter((item2) => item2[parentIdPropertyName] === item[idPropertyName]).map((child) => {
|
|
291
654
|
if (!result.some((r) => r[idPropertyName] === child[idPropertyName])) {
|
|
@@ -480,20 +843,153 @@ const CommUtils = {
|
|
|
480
843
|
var numT = targetV.replace(/[^0-9]/gi, "");
|
|
481
844
|
return numC < numT;
|
|
482
845
|
}
|
|
483
|
-
};
|
|
484
|
-
const ObjectUtil = {
|
|
485
|
-
deepClone(a) {
|
|
486
|
-
return structuredClone(a);
|
|
487
|
-
},
|
|
488
|
-
isEqual(a, b) {
|
|
489
|
-
return JSON.stringify(a) === JSON.stringify(b);
|
|
490
|
-
},
|
|
491
|
-
parse(str) {
|
|
492
|
-
if (typeof str === "string" && str.startsWith("{") && str.endsWith("}")) return JSON.parse(str);
|
|
493
|
-
if (
|
|
494
|
-
if (
|
|
846
|
+
};
|
|
847
|
+
const ObjectUtil = {
|
|
848
|
+
deepClone(a) {
|
|
849
|
+
return structuredClone(a);
|
|
850
|
+
},
|
|
851
|
+
isEqual(a, b) {
|
|
852
|
+
return JSON.stringify(a) === JSON.stringify(b);
|
|
853
|
+
},
|
|
854
|
+
parse(str) {
|
|
855
|
+
if (typeof str === "string" && str.startsWith("{") && str.endsWith("}")) return JSON.parse(str);
|
|
856
|
+
if (Util.isEmpty(str)) return {};
|
|
857
|
+
if (Util.isObject(str)) return str;
|
|
858
|
+
}
|
|
859
|
+
};
|
|
860
|
+
class HashMap extends Map {
|
|
861
|
+
isEmpty() {
|
|
862
|
+
return this.size === 0;
|
|
863
|
+
}
|
|
864
|
+
_values() {
|
|
865
|
+
return Array.from(this.values());
|
|
866
|
+
}
|
|
867
|
+
_keys() {
|
|
868
|
+
return Array.from(this.keys());
|
|
869
|
+
}
|
|
870
|
+
_entries() {
|
|
871
|
+
return Array.from(this.entries());
|
|
872
|
+
}
|
|
873
|
+
/**
|
|
874
|
+
* 从键值对数组创建一个HashMap对象
|
|
875
|
+
*
|
|
876
|
+
* @param array 键值对数组,默认为空数组
|
|
877
|
+
* @returns 返回一个新的HashMap对象
|
|
878
|
+
*/
|
|
879
|
+
static fromEntries(array = []) {
|
|
880
|
+
const hashMap = new HashMap();
|
|
881
|
+
array.forEach((element) => {
|
|
882
|
+
if (Array.isArray(element) && element.length === 2) {
|
|
883
|
+
hashMap.set(element[0], element[1]);
|
|
884
|
+
}
|
|
885
|
+
});
|
|
886
|
+
return hashMap;
|
|
887
|
+
}
|
|
888
|
+
/**
|
|
889
|
+
* 从JSON字符串创建HashMap实例
|
|
890
|
+
*
|
|
891
|
+
* @param str JSON字符串
|
|
892
|
+
* @returns HashMap实例
|
|
893
|
+
*/
|
|
894
|
+
static fromJson(str) {
|
|
895
|
+
const json = ObjectUtil.parse(str);
|
|
896
|
+
return new HashMap(Object.entries(json));
|
|
897
|
+
}
|
|
898
|
+
}
|
|
899
|
+
class WebSocketClient extends EventDispatcher {
|
|
900
|
+
constructor(url = "ws://127.0.0.1:10088") {
|
|
901
|
+
super();
|
|
902
|
+
__publicField(this, "maxCheckTimes", 10);
|
|
903
|
+
__publicField(this, "url");
|
|
904
|
+
__publicField(this, "checkTimes", 0);
|
|
905
|
+
__publicField(this, "connectStatus", false);
|
|
906
|
+
__publicField(this, "client", null);
|
|
907
|
+
this.maxCheckTimes = 10;
|
|
908
|
+
this.url = url;
|
|
909
|
+
this.checkTimes = 0;
|
|
910
|
+
this.connect();
|
|
911
|
+
this.connCheckStatus(this.maxCheckTimes);
|
|
912
|
+
}
|
|
913
|
+
connect() {
|
|
914
|
+
this.disconnect();
|
|
915
|
+
if (this.url) {
|
|
916
|
+
try {
|
|
917
|
+
console.info("创建ws连接>>>" + this.url);
|
|
918
|
+
this.client = new WebSocket(this.url);
|
|
919
|
+
if (this.client) {
|
|
920
|
+
const self = this;
|
|
921
|
+
this.client.onopen = function(message) {
|
|
922
|
+
self.dispatchEvent({
|
|
923
|
+
type: EventType.WEB_SOCKET_CONNECT,
|
|
924
|
+
message
|
|
925
|
+
});
|
|
926
|
+
};
|
|
927
|
+
this.client.onmessage = function(message) {
|
|
928
|
+
self.connectStatus = true;
|
|
929
|
+
self.dispatchEvent({
|
|
930
|
+
type: EventType.WEB_SOCKET_MESSAGE,
|
|
931
|
+
message
|
|
932
|
+
});
|
|
933
|
+
};
|
|
934
|
+
this.client.onclose = function(message) {
|
|
935
|
+
self.dispatchEvent({
|
|
936
|
+
type: EventType.WEB_SOCKET_CLOSE,
|
|
937
|
+
message
|
|
938
|
+
});
|
|
939
|
+
};
|
|
940
|
+
if (this.checkTimes === this.maxCheckTimes) {
|
|
941
|
+
this.client.onerror = function(message) {
|
|
942
|
+
self.dispatchEvent({
|
|
943
|
+
type: EventType.WEB_SOCKET_ERROR,
|
|
944
|
+
message
|
|
945
|
+
});
|
|
946
|
+
};
|
|
947
|
+
}
|
|
948
|
+
}
|
|
949
|
+
} catch (ex) {
|
|
950
|
+
console.error("创建ws连接失败" + this.url + ":" + ex);
|
|
951
|
+
}
|
|
952
|
+
}
|
|
953
|
+
}
|
|
954
|
+
disconnect() {
|
|
955
|
+
if (this.client) {
|
|
956
|
+
try {
|
|
957
|
+
console.log("ws断开连接" + this.url);
|
|
958
|
+
this.client.close();
|
|
959
|
+
this.client = null;
|
|
960
|
+
} catch (ex) {
|
|
961
|
+
this.client = null;
|
|
962
|
+
}
|
|
963
|
+
}
|
|
964
|
+
}
|
|
965
|
+
connCheckStatus(times) {
|
|
966
|
+
if (this.checkTimes > times) return;
|
|
967
|
+
setTimeout(() => {
|
|
968
|
+
this.checkTimes++;
|
|
969
|
+
if (this.client && this.client.readyState !== 0 && this.client.readyState !== 1) {
|
|
970
|
+
this.connect();
|
|
971
|
+
}
|
|
972
|
+
this.connCheckStatus(times);
|
|
973
|
+
}, 2e3);
|
|
974
|
+
}
|
|
975
|
+
send(message) {
|
|
976
|
+
if (this.client && this.client.readyState === 1) {
|
|
977
|
+
this.client.send(message);
|
|
978
|
+
return true;
|
|
979
|
+
}
|
|
980
|
+
console.error(this.url + "消息发送失败:" + message);
|
|
981
|
+
return this;
|
|
495
982
|
}
|
|
496
|
-
|
|
983
|
+
heartbeat() {
|
|
984
|
+
setTimeout(() => {
|
|
985
|
+
if (this.client && this.client.readyState === 1) {
|
|
986
|
+
this.send("HeartBeat");
|
|
987
|
+
}
|
|
988
|
+
console.log("HeartBeat," + this.url);
|
|
989
|
+
setTimeout(this.heartbeat, 3e4);
|
|
990
|
+
}, 1e3);
|
|
991
|
+
}
|
|
992
|
+
}
|
|
497
993
|
const ImageUtil = {
|
|
498
994
|
emptyImageUrl: "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7",
|
|
499
995
|
/**
|
|
@@ -606,7 +1102,7 @@ const AjaxUtil = {
|
|
|
606
1102
|
* @param callback - callback function when completed
|
|
607
1103
|
*/
|
|
608
1104
|
jsonp(url, callback) {
|
|
609
|
-
const name = "_jsonp_" +
|
|
1105
|
+
const name = "_jsonp_" + Util.guid();
|
|
610
1106
|
const head = document.getElementsByTagName("head")[0];
|
|
611
1107
|
if (url.includes("?")) {
|
|
612
1108
|
url += "&callback=" + name;
|
|
@@ -645,7 +1141,7 @@ const AjaxUtil = {
|
|
|
645
1141
|
* );
|
|
646
1142
|
*/
|
|
647
1143
|
get(url, options = {}, cb) {
|
|
648
|
-
if (
|
|
1144
|
+
if (Util.isFunction(options)) {
|
|
649
1145
|
const t = cb;
|
|
650
1146
|
cb = options;
|
|
651
1147
|
options = t;
|
|
@@ -777,7 +1273,7 @@ const AjaxUtil = {
|
|
|
777
1273
|
* );
|
|
778
1274
|
*/
|
|
779
1275
|
getArrayBuffer(url, options, cb) {
|
|
780
|
-
if (
|
|
1276
|
+
if (Util.isFunction(options)) {
|
|
781
1277
|
const t = cb;
|
|
782
1278
|
cb = options;
|
|
783
1279
|
options = t;
|
|
@@ -830,7 +1326,7 @@ const AjaxUtil = {
|
|
|
830
1326
|
* );
|
|
831
1327
|
*/
|
|
832
1328
|
getJSON(url, options, cb) {
|
|
833
|
-
if (
|
|
1329
|
+
if (Util.isFunction(options)) {
|
|
834
1330
|
const t = cb;
|
|
835
1331
|
cb = options;
|
|
836
1332
|
options = t;
|
|
@@ -847,48 +1343,6 @@ const AjaxUtil = {
|
|
|
847
1343
|
return this.get(url, options, callback);
|
|
848
1344
|
}
|
|
849
1345
|
};
|
|
850
|
-
const MathUtils = {
|
|
851
|
-
DEG2RAD: Math.PI / 180,
|
|
852
|
-
RAD2DEG: 180 / Math.PI,
|
|
853
|
-
randInt(low, high) {
|
|
854
|
-
return low + Math.floor(Math.random() * (high - low + 1));
|
|
855
|
-
},
|
|
856
|
-
randFloat(low, high) {
|
|
857
|
-
return low + Math.random() * (high - low);
|
|
858
|
-
},
|
|
859
|
-
/**
|
|
860
|
-
* 角度转弧度
|
|
861
|
-
*
|
|
862
|
-
* @param {*} degrees
|
|
863
|
-
* @returns {*}
|
|
864
|
-
*/
|
|
865
|
-
deg2Rad(degrees) {
|
|
866
|
-
return degrees * this.DEG2RAD;
|
|
867
|
-
},
|
|
868
|
-
/**
|
|
869
|
-
* 弧度转角度
|
|
870
|
-
*
|
|
871
|
-
* @param {*} radians
|
|
872
|
-
* @returns {*}
|
|
873
|
-
*/
|
|
874
|
-
rad2Deg(radians) {
|
|
875
|
-
return radians * this.RAD2DEG;
|
|
876
|
-
},
|
|
877
|
-
round(value, n = 2) {
|
|
878
|
-
return Math.round(value * Math.pow(10, n)) / Math.pow(10, n);
|
|
879
|
-
},
|
|
880
|
-
/**
|
|
881
|
-
* 将数值限制在指定范围内
|
|
882
|
-
*
|
|
883
|
-
* @param val 需要限制的数值
|
|
884
|
-
* @param min 最小值
|
|
885
|
-
* @param max 最大值
|
|
886
|
-
* @returns 返回限制后的数值
|
|
887
|
-
*/
|
|
888
|
-
clamp(val, min, max) {
|
|
889
|
-
return Math.max(min, Math.min(max, val));
|
|
890
|
-
}
|
|
891
|
-
};
|
|
892
1346
|
class GeoUtil {
|
|
893
1347
|
/**
|
|
894
1348
|
* 判断给定的经纬度是否合法
|
|
@@ -898,7 +1352,7 @@ class GeoUtil {
|
|
|
898
1352
|
* @returns 如果经纬度合法,返回true;否则返回false
|
|
899
1353
|
*/
|
|
900
1354
|
static isLnglat(lng, lat) {
|
|
901
|
-
return
|
|
1355
|
+
return Util.isNumber(lng) && Util.isNumber(lat) && !!(+lat > -90 && +lat < 90 && +lng > -180 && +lng < 180);
|
|
902
1356
|
}
|
|
903
1357
|
/**
|
|
904
1358
|
* 计算两哥平面坐标点间的距离
|
|
@@ -1090,15 +1544,15 @@ class GeoUtil {
|
|
|
1090
1544
|
* @returns 返回计算后的新经纬度点,类型为{lat: number, lng: number}
|
|
1091
1545
|
*/
|
|
1092
1546
|
static calcPointByBearAndDis(latlng, angle, distance) {
|
|
1093
|
-
const sLat =
|
|
1094
|
-
const sLng =
|
|
1547
|
+
const sLat = MathUtil.deg2Rad(latlng.lat * 1);
|
|
1548
|
+
const sLng = MathUtil.deg2Rad(latlng.lng * 1);
|
|
1095
1549
|
const d = distance / this.R;
|
|
1096
|
-
angle =
|
|
1550
|
+
angle = MathUtil.deg2Rad(angle);
|
|
1097
1551
|
const lat = Math.asin(Math.sin(sLat) * Math.cos(d) + Math.cos(sLat) * Math.sin(d) * Math.cos(angle));
|
|
1098
1552
|
const lon = sLng + Math.atan2(Math.sin(angle) * Math.sin(d) * Math.cos(sLat), Math.cos(d) - Math.sin(sLat) * Math.sin(lat));
|
|
1099
1553
|
return {
|
|
1100
|
-
lat:
|
|
1101
|
-
lng:
|
|
1554
|
+
lat: MathUtil.rad2Deg(lat),
|
|
1555
|
+
lng: MathUtil.rad2Deg(lon)
|
|
1102
1556
|
};
|
|
1103
1557
|
}
|
|
1104
1558
|
/**
|
|
@@ -1247,26 +1701,6 @@ const StringUtil = {
|
|
|
1247
1701
|
return str;
|
|
1248
1702
|
}
|
|
1249
1703
|
},
|
|
1250
|
-
/**
|
|
1251
|
-
* 根据字符串数组和参数生成新的字符串
|
|
1252
|
-
*
|
|
1253
|
-
* @param strArray 字符串数组
|
|
1254
|
-
* @param args 可变参数列表,支持 Object、Array 类型和任意其他类型,若为 null 或 undefined,则按类型默认转换为 '{}'、'[]' 或 ''
|
|
1255
|
-
* @returns 返回生成的新字符串
|
|
1256
|
-
*/
|
|
1257
|
-
tag(strArray, ...args) {
|
|
1258
|
-
args = args.map((val) => {
|
|
1259
|
-
switch (CommUtils.getDataType(val)) {
|
|
1260
|
-
case "Object":
|
|
1261
|
-
return val || "{}";
|
|
1262
|
-
case "Array":
|
|
1263
|
-
return val || "[]";
|
|
1264
|
-
default:
|
|
1265
|
-
return val || "";
|
|
1266
|
-
}
|
|
1267
|
-
});
|
|
1268
|
-
return strArray.reduce((prev, next, index) => `${prev}${args[index - 1]}${next}`);
|
|
1269
|
-
},
|
|
1270
1704
|
/**
|
|
1271
1705
|
* 计算字符串的字节长度
|
|
1272
1706
|
*
|
|
@@ -1589,42 +2023,42 @@ const GeoJsonUtil = {
|
|
|
1589
2023
|
const AssertUtil = {
|
|
1590
2024
|
assertEmpty(...arg) {
|
|
1591
2025
|
arg.forEach((a) => {
|
|
1592
|
-
if (
|
|
2026
|
+
if (Util.isEmpty(a)) {
|
|
1593
2027
|
throw Error(ErrorType.PARAMETER_ERROR_LACK + " -> " + a);
|
|
1594
2028
|
}
|
|
1595
2029
|
});
|
|
1596
2030
|
},
|
|
1597
2031
|
assertInteger(...arg) {
|
|
1598
2032
|
arg.forEach((a) => {
|
|
1599
|
-
if (!
|
|
2033
|
+
if (!Util.isInteger(a)) {
|
|
1600
2034
|
throw Error(ErrorType.PARAMETER_ERROR_INTEGER + " -> " + a);
|
|
1601
2035
|
}
|
|
1602
2036
|
});
|
|
1603
2037
|
},
|
|
1604
2038
|
assertNumber(...arg) {
|
|
1605
2039
|
arg.forEach((a) => {
|
|
1606
|
-
if (!
|
|
2040
|
+
if (!Util.isNumber(a)) {
|
|
1607
2041
|
throw Error(ErrorType.PARAMETER_ERROR_NUMBER + " -> " + a);
|
|
1608
2042
|
}
|
|
1609
2043
|
});
|
|
1610
2044
|
},
|
|
1611
2045
|
assertArray(...arg) {
|
|
1612
2046
|
arg.forEach((a) => {
|
|
1613
|
-
if (!
|
|
2047
|
+
if (!Util.isArray(a)) {
|
|
1614
2048
|
throw Error(ErrorType.PARAMETER_ERROR_ARRAY + " -> " + a);
|
|
1615
2049
|
}
|
|
1616
2050
|
});
|
|
1617
2051
|
},
|
|
1618
2052
|
assertFunction(...arg) {
|
|
1619
2053
|
arg.forEach((a) => {
|
|
1620
|
-
if (!
|
|
2054
|
+
if (!Util.isFunction(a)) {
|
|
1621
2055
|
throw Error(ErrorType.PARAMETER_ERROR_FUNCTION + " -> " + a);
|
|
1622
2056
|
}
|
|
1623
2057
|
});
|
|
1624
2058
|
},
|
|
1625
2059
|
assertObject(...arg) {
|
|
1626
2060
|
arg.forEach((a) => {
|
|
1627
|
-
if (!
|
|
2061
|
+
if (!Util.isObject(a)) {
|
|
1628
2062
|
throw Error(ErrorType.PARAMETER_ERROR_OBJECT + " -> " + a);
|
|
1629
2063
|
}
|
|
1630
2064
|
});
|
|
@@ -2328,7 +2762,7 @@ class CoordsUtil {
|
|
|
2328
2762
|
let p, pp;
|
|
2329
2763
|
for (let i = 0, len = arr.length; i < len; i++) {
|
|
2330
2764
|
p = arr[i];
|
|
2331
|
-
if (
|
|
2765
|
+
if (Util.isNil(p)) {
|
|
2332
2766
|
result.push(null);
|
|
2333
2767
|
continue;
|
|
2334
2768
|
}
|
|
@@ -2512,955 +2946,492 @@ __publicField(DateUtil, "lastWeekDate", new Date((/* @__PURE__ */ new Date()).ge
|
|
|
2512
2946
|
__publicField(DateUtil, "thisWeekDate", new Date((/* @__PURE__ */ new Date()).getFullYear(), (/* @__PURE__ */ new Date()).getMonth(), (/* @__PURE__ */ new Date()).getDate() + 1 - (/* @__PURE__ */ new Date()).getDay()));
|
|
2513
2947
|
__publicField(DateUtil, "nextWeekDate", new Date((/* @__PURE__ */ new Date()).getFullYear(), (/* @__PURE__ */ new Date()).getMonth(), (/* @__PURE__ */ new Date()).getDate() + 1 + 7 - (/* @__PURE__ */ new Date()).getDay()));
|
|
2514
2948
|
__publicField(DateUtil, "lastDayDate", new Date((/* @__PURE__ */ new Date()).getFullYear(), (/* @__PURE__ */ new Date()).getMonth(), (/* @__PURE__ */ new Date()).getDate() - 1));
|
|
2515
|
-
__publicField(DateUtil, "thisDayDate", new Date((/* @__PURE__ */ new Date()).setHours(0, 0, 0, 0)));
|
|
2516
|
-
__publicField(DateUtil, "nextDayDate", new Date((/* @__PURE__ */ new Date()).getFullYear(), (/* @__PURE__ */ new Date()).getMonth(), (/* @__PURE__ */ new Date()).getDate() + 1));
|
|
2517
|
-
function trim(str) {
|
|
2518
|
-
return str.trim ? str.trim() : str.replace(/^\s+|\s+$/g, "");
|
|
2519
|
-
}
|
|
2520
|
-
function splitWords(str) {
|
|
2521
|
-
return trim(str).split(/\s+/);
|
|
2522
|
-
}
|
|
2523
|
-
const DomUtil = {
|
|
2524
|
-
/**
|
|
2525
|
-
* 获取元素的样式值
|
|
2526
|
-
*
|
|
2527
|
-
* @param el 元素对象
|
|
2528
|
-
* @param style 样式属性名称
|
|
2529
|
-
* @returns 元素的样式值,如果获取不到则返回 null
|
|
2530
|
-
*/
|
|
2531
|
-
getStyle(el, style) {
|
|
2532
|
-
var _a2;
|
|
2533
|
-
let value = el.style[style];
|
|
2534
|
-
if (!value || value === "auto") {
|
|
2535
|
-
const css = (_a2 = document.defaultView) == null ? void 0 : _a2.getComputedStyle(el, null);
|
|
2536
|
-
value = css ? css[style] : null;
|
|
2537
|
-
if (value === "auto") value = null;
|
|
2538
|
-
}
|
|
2539
|
-
return value;
|
|
2540
|
-
},
|
|
2541
|
-
/**
|
|
2542
|
-
* 创建一个HTML元素
|
|
2543
|
-
*
|
|
2544
|
-
* @param tagName 元素标签名
|
|
2545
|
-
* @param className 元素类名
|
|
2546
|
-
* @param container 父容器,若传入,则新创建的元素会被添加到该容器中
|
|
2547
|
-
* @returns 返回新创建的HTML元素
|
|
2548
|
-
*/
|
|
2549
|
-
create(tagName, className, container) {
|
|
2550
|
-
const el = document.createElement(tagName);
|
|
2551
|
-
el.className = className || "";
|
|
2552
|
-
if (container) {
|
|
2553
|
-
container.appendChild(el);
|
|
2554
|
-
}
|
|
2555
|
-
return el;
|
|
2556
|
-
},
|
|
2557
|
-
/**
|
|
2558
|
-
* 从父节点中移除指定元素。
|
|
2559
|
-
*
|
|
2560
|
-
* @param el 要移除的元素对象,必须包含parentNode属性。
|
|
2561
|
-
*/
|
|
2562
|
-
remove(el) {
|
|
2563
|
-
const parent = el.parentNode;
|
|
2564
|
-
if (parent) {
|
|
2565
|
-
parent.removeChild(el);
|
|
2566
|
-
}
|
|
2567
|
-
},
|
|
2568
|
-
/**
|
|
2569
|
-
* 清空给定元素的子节点
|
|
2570
|
-
*
|
|
2571
|
-
* @param el 要清空子节点的元素,包含firstChild和removeChild属性
|
|
2572
|
-
*/
|
|
2573
|
-
empty(el) {
|
|
2574
|
-
while (el.firstChild) {
|
|
2575
|
-
el.removeChild(el.firstChild);
|
|
2576
|
-
}
|
|
2577
|
-
},
|
|
2578
|
-
/**
|
|
2579
|
-
* 将元素移到父节点的最前面
|
|
2580
|
-
*
|
|
2581
|
-
* @param el 要移动的元素,需要包含 parentNode 属性
|
|
2582
|
-
*/
|
|
2583
|
-
toFront(el) {
|
|
2584
|
-
const parent = el.parentNode;
|
|
2585
|
-
if (parent && parent.lastChild !== el) {
|
|
2586
|
-
parent.appendChild(el);
|
|
2587
|
-
}
|
|
2588
|
-
},
|
|
2589
|
-
/**
|
|
2590
|
-
* 将元素移动到其父节点的最前面
|
|
2591
|
-
*
|
|
2592
|
-
* @param el 要移动的元素,需要包含parentNode属性
|
|
2593
|
-
*/
|
|
2594
|
-
toBack(el) {
|
|
2595
|
-
const parent = el.parentNode;
|
|
2596
|
-
if (parent && parent.firstChild !== el) {
|
|
2597
|
-
parent.insertBefore(el, parent.firstChild);
|
|
2598
|
-
}
|
|
2599
|
-
},
|
|
2600
|
-
/**
|
|
2601
|
-
* 获取元素的类名
|
|
2602
|
-
*
|
|
2603
|
-
* @param el 包含对应元素和类名的对象
|
|
2604
|
-
* @param el.correspondingElement 对应的元素
|
|
2605
|
-
* @param el.className 类名对象
|
|
2606
|
-
* @param el.className.baseVal 类名字符串
|
|
2607
|
-
* @returns 返回元素的类名字符串
|
|
2608
|
-
*/
|
|
2609
|
-
getClass(el) {
|
|
2610
|
-
const shadowElement = (el == null ? void 0 : el.host) || el;
|
|
2611
|
-
return shadowElement.className.toString();
|
|
2612
|
-
},
|
|
2613
|
-
/**
|
|
2614
|
-
* 判断元素是否包含指定类名
|
|
2615
|
-
*
|
|
2616
|
-
* @param el 元素对象,包含classList属性,classList属性包含contains方法
|
|
2617
|
-
* @param name 要判断的类名
|
|
2618
|
-
* @returns 返回一个布尔值,表示元素是否包含指定类名
|
|
2619
|
-
*/
|
|
2620
|
-
hasClass(el, name) {
|
|
2621
|
-
var _a2;
|
|
2622
|
-
if ((_a2 = el.classList) == null ? void 0 : _a2.contains(name)) {
|
|
2623
|
-
return true;
|
|
2624
|
-
}
|
|
2625
|
-
const className = this.getClass(el);
|
|
2626
|
-
return className.length > 0 && new RegExp(`(^|\\s)${name}(\\s|$)`).test(className);
|
|
2627
|
-
},
|
|
2628
|
-
/**
|
|
2629
|
-
* 给指定的 HTML 元素添加类名
|
|
2630
|
-
*
|
|
2631
|
-
* @param el 要添加类名的 HTML 元素
|
|
2632
|
-
* @param name 要添加的类名,多个类名之间用空格分隔
|
|
2633
|
-
*/
|
|
2634
|
-
addClass(el, name) {
|
|
2635
|
-
if (el.classList !== void 0) {
|
|
2636
|
-
const classes = splitWords(name);
|
|
2637
|
-
for (let i = 0, len = classes.length; i < len; i++) {
|
|
2638
|
-
el.classList.add(classes[i]);
|
|
2639
|
-
}
|
|
2640
|
-
} else if (!this.hasClass(el, name)) {
|
|
2641
|
-
const className = this.getClass(el);
|
|
2642
|
-
this.setClass(el, (className ? className + " " : "") + name);
|
|
2643
|
-
}
|
|
2644
|
-
},
|
|
2645
|
-
/**
|
|
2646
|
-
* 从元素中移除指定类名
|
|
2647
|
-
*
|
|
2648
|
-
* @param el 要移除类名的元素
|
|
2649
|
-
* @param name 要移除的类名,多个类名用空格分隔
|
|
2650
|
-
*/
|
|
2651
|
-
removeClass(el, name) {
|
|
2652
|
-
if (el.classList !== void 0) {
|
|
2653
|
-
const classes = splitWords(name);
|
|
2654
|
-
classes.forEach((className) => el.classList.remove(className));
|
|
2655
|
-
} else {
|
|
2656
|
-
this.setClass(el, (" " + this.getClass(el) + " ").replace(" " + name + " ", " ").trim());
|
|
2657
|
-
}
|
|
2658
|
-
},
|
|
2659
|
-
/**
|
|
2660
|
-
* 设置元素的 CSS 类名
|
|
2661
|
-
*
|
|
2662
|
-
* @param el HTML 或 SVG 元素
|
|
2663
|
-
* @param name 要设置的类名,多个类名之间用空格分隔
|
|
2664
|
-
*/
|
|
2665
|
-
setClass(el, name) {
|
|
2666
|
-
if ("classList" in el) {
|
|
2667
|
-
el.classList.value = "";
|
|
2668
|
-
name.split(" ").forEach((className) => el.classList.add(className));
|
|
2669
|
-
}
|
|
2670
|
-
},
|
|
2671
|
-
/**
|
|
2672
|
-
* 从字符串中解析XML文档,并返回根节点
|
|
2673
|
-
*
|
|
2674
|
-
* @param str 要解析的XML字符串
|
|
2675
|
-
* @returns 解析后的XML文档的根节点
|
|
2676
|
-
*/
|
|
2677
|
-
parseFromString(str) {
|
|
2678
|
-
const parser = new DOMParser();
|
|
2679
|
-
const doc = parser.parseFromString(str, "text/xml");
|
|
2680
|
-
return doc.children[0];
|
|
2681
|
-
}
|
|
2682
|
-
};
|
|
2683
|
-
const FileUtil = {
|
|
2949
|
+
__publicField(DateUtil, "thisDayDate", new Date((/* @__PURE__ */ new Date()).setHours(0, 0, 0, 0)));
|
|
2950
|
+
__publicField(DateUtil, "nextDayDate", new Date((/* @__PURE__ */ new Date()).getFullYear(), (/* @__PURE__ */ new Date()).getMonth(), (/* @__PURE__ */ new Date()).getDate() + 1));
|
|
2951
|
+
function trim(str) {
|
|
2952
|
+
return str.trim ? str.trim() : str.replace(/^\s+|\s+$/g, "");
|
|
2953
|
+
}
|
|
2954
|
+
function splitWords(str) {
|
|
2955
|
+
return trim(str).split(/\s+/);
|
|
2956
|
+
}
|
|
2957
|
+
const DomUtil = {
|
|
2684
2958
|
/**
|
|
2685
|
-
*
|
|
2959
|
+
* 获取元素的样式值
|
|
2686
2960
|
*
|
|
2687
|
-
* @param
|
|
2688
|
-
* @
|
|
2961
|
+
* @param el 元素对象
|
|
2962
|
+
* @param style 样式属性名称
|
|
2963
|
+
* @returns 元素的样式值,如果获取不到则返回 null
|
|
2689
2964
|
*/
|
|
2690
|
-
|
|
2691
|
-
|
|
2692
|
-
|
|
2693
|
-
|
|
2694
|
-
|
|
2695
|
-
|
|
2965
|
+
getStyle(el, style) {
|
|
2966
|
+
var _a2;
|
|
2967
|
+
let value = el.style[style];
|
|
2968
|
+
if (!value || value === "auto") {
|
|
2969
|
+
const css = (_a2 = document.defaultView) == null ? void 0 : _a2.getComputedStyle(el, null);
|
|
2970
|
+
value = css ? css[style] : null;
|
|
2971
|
+
if (value === "auto") value = null;
|
|
2696
2972
|
}
|
|
2697
|
-
|
|
2698
|
-
const blob = new Blob([byteArray], { type: mimeString });
|
|
2699
|
-
return blob;
|
|
2973
|
+
return value;
|
|
2700
2974
|
},
|
|
2701
2975
|
/**
|
|
2702
|
-
*
|
|
2703
|
-
*
|
|
2704
|
-
* @param url 图片的URL地址
|
|
2705
|
-
* @param width 图片的宽度,默认为图片原始宽度
|
|
2706
|
-
* @param height 图片的高度,默认为图片原始高度
|
|
2707
|
-
* @returns 返回Promise对象,解析后得到包含Base64编码数据的对象
|
|
2708
|
-
*/
|
|
2709
|
-
/**
|
|
2710
|
-
* 将base64字符串转换为文件对象
|
|
2976
|
+
* 创建一个HTML元素
|
|
2711
2977
|
*
|
|
2712
|
-
* @param
|
|
2713
|
-
* @param
|
|
2714
|
-
* @
|
|
2978
|
+
* @param tagName 元素标签名
|
|
2979
|
+
* @param className 元素类名
|
|
2980
|
+
* @param container 父容器,若传入,则新创建的元素会被添加到该容器中
|
|
2981
|
+
* @returns 返回新创建的HTML元素
|
|
2715
2982
|
*/
|
|
2716
|
-
|
|
2717
|
-
const
|
|
2718
|
-
|
|
2719
|
-
|
|
2720
|
-
|
|
2721
|
-
const u8arr = new Uint8Array(bstr.length);
|
|
2722
|
-
for (let i = 0; i < bstr.length; i++) {
|
|
2723
|
-
u8arr[i] = bstr.charCodeAt(i);
|
|
2983
|
+
create(tagName, className, container) {
|
|
2984
|
+
const el = document.createElement(tagName);
|
|
2985
|
+
el.className = className || "";
|
|
2986
|
+
if (container) {
|
|
2987
|
+
container.appendChild(el);
|
|
2724
2988
|
}
|
|
2725
|
-
|
|
2726
|
-
return file;
|
|
2989
|
+
return el;
|
|
2727
2990
|
},
|
|
2728
2991
|
/**
|
|
2729
|
-
*
|
|
2992
|
+
* 从父节点中移除指定元素。
|
|
2730
2993
|
*
|
|
2731
|
-
* @param
|
|
2732
|
-
* @param saveName 下载后文件的保存名称
|
|
2994
|
+
* @param el 要移除的元素对象,必须包含parentNode属性。
|
|
2733
2995
|
*/
|
|
2734
|
-
|
|
2735
|
-
|
|
2736
|
-
|
|
2737
|
-
|
|
2738
|
-
} else {
|
|
2739
|
-
const str = JSON.stringify(data);
|
|
2740
|
-
const blob = new Blob([str], { type: "text/json" });
|
|
2741
|
-
data = window.URL.createObjectURL(blob);
|
|
2742
|
-
}
|
|
2743
|
-
} else if (typeof data == "string" && data.indexOf("http") === -1) {
|
|
2744
|
-
const blob = new Blob([data], { type: "text/json" });
|
|
2745
|
-
data = window.URL.createObjectURL(blob);
|
|
2746
|
-
}
|
|
2747
|
-
var link = document.createElement("a");
|
|
2748
|
-
link.href = data;
|
|
2749
|
-
link.download = saveName || "";
|
|
2750
|
-
link.click();
|
|
2751
|
-
window.URL.revokeObjectURL(link.href);
|
|
2752
|
-
}
|
|
2753
|
-
};
|
|
2754
|
-
class GlobalMsg {
|
|
2755
|
-
static resetWarned() {
|
|
2756
|
-
this.warned = {};
|
|
2757
|
-
}
|
|
2758
|
-
static changeVoice() {
|
|
2759
|
-
this.isMute = !!Number(!this.isMute);
|
|
2760
|
-
localStorage.setItem("mute", Number(this.isMute).toString());
|
|
2761
|
-
}
|
|
2762
|
-
static _call(method, message) {
|
|
2763
|
-
if (!this.warned[message]) {
|
|
2764
|
-
method(message);
|
|
2765
|
-
if (method instanceof this.warning) {
|
|
2766
|
-
this.msg("warning", message);
|
|
2767
|
-
} else if (method instanceof this.info) {
|
|
2768
|
-
this.msg("info", message);
|
|
2769
|
-
} else if (method instanceof this.error) {
|
|
2770
|
-
this.msg("error", message);
|
|
2771
|
-
} else if (method instanceof this.success) {
|
|
2772
|
-
this.msg("success", message);
|
|
2773
|
-
}
|
|
2774
|
-
this.warned[message] = true;
|
|
2996
|
+
remove(el) {
|
|
2997
|
+
const parent = el.parentNode;
|
|
2998
|
+
if (parent) {
|
|
2999
|
+
parent.removeChild(el);
|
|
2775
3000
|
}
|
|
2776
|
-
}
|
|
3001
|
+
},
|
|
2777
3002
|
/**
|
|
2778
|
-
*
|
|
3003
|
+
* 清空给定元素的子节点
|
|
2779
3004
|
*
|
|
2780
|
-
* @param
|
|
2781
|
-
* @param message 消息内容
|
|
2782
|
-
* @param options 配置选项,可选参数,包括语言、音量、语速和音高
|
|
2783
|
-
* @returns 无返回值
|
|
3005
|
+
* @param el 要清空子节点的元素,包含firstChild和removeChild属性
|
|
2784
3006
|
*/
|
|
2785
|
-
|
|
2786
|
-
|
|
2787
|
-
|
|
2788
|
-
const typename = CommUtils.decodeDict(type, "success", "恭喜:", "error", "发生错误:", "warning", "警告:", "info", "友情提示:") + ":";
|
|
2789
|
-
this.speechSynthesisUtterance.text = typename + message;
|
|
2790
|
-
this.speechSynthesisUtterance.lang = options.lang || "zh-CN";
|
|
2791
|
-
this.speechSynthesisUtterance.volume = options.volume || 1;
|
|
2792
|
-
this.speechSynthesisUtterance.rate = options.rate || 1;
|
|
2793
|
-
this.speechSynthesisUtterance.pitch = options.pitch || 1;
|
|
2794
|
-
this.speechSynthesis.speak(this.speechSynthesisUtterance);
|
|
2795
|
-
}
|
|
2796
|
-
static stop(e) {
|
|
2797
|
-
this.speechSynthesisUtterance.text = e;
|
|
2798
|
-
this.speechSynthesis.cancel();
|
|
2799
|
-
}
|
|
2800
|
-
static warning(message) {
|
|
2801
|
-
if (process.env.NODE_ENV !== "development" && console !== void 0) {
|
|
2802
|
-
console.warn(`Warning: ${message}`);
|
|
2803
|
-
}
|
|
2804
|
-
this.msg("warning", message);
|
|
2805
|
-
}
|
|
2806
|
-
static warningOnce(message) {
|
|
2807
|
-
this._call(this.warning, message);
|
|
2808
|
-
}
|
|
2809
|
-
static info(message) {
|
|
2810
|
-
if (process.env.NODE_ENV !== "development" && console !== void 0) {
|
|
2811
|
-
console.info(`Info: ${message}`);
|
|
2812
|
-
}
|
|
2813
|
-
this.msg("info", message);
|
|
2814
|
-
}
|
|
2815
|
-
static infoOnce(message) {
|
|
2816
|
-
this._call(this.info, message);
|
|
2817
|
-
}
|
|
2818
|
-
static error(message) {
|
|
2819
|
-
if (process.env.NODE_ENV !== "development" && console !== void 0) {
|
|
2820
|
-
console.error(`Error: ${message}`);
|
|
2821
|
-
}
|
|
2822
|
-
this.msg("error", message);
|
|
2823
|
-
}
|
|
2824
|
-
static errorOnce(message) {
|
|
2825
|
-
this._call(this.error, message);
|
|
2826
|
-
}
|
|
2827
|
-
static success(message) {
|
|
2828
|
-
if (process.env.NODE_ENV !== "development" && console !== void 0) {
|
|
2829
|
-
console.log(`Success: ${message}`);
|
|
3007
|
+
empty(el) {
|
|
3008
|
+
while (el.firstChild) {
|
|
3009
|
+
el.removeChild(el.firstChild);
|
|
2830
3010
|
}
|
|
2831
|
-
|
|
2832
|
-
}
|
|
2833
|
-
static successOnce(message) {
|
|
2834
|
-
this._call(this.success, message);
|
|
2835
|
-
}
|
|
2836
|
-
}
|
|
2837
|
-
__publicField(GlobalMsg, "warned", {});
|
|
2838
|
-
__publicField(GlobalMsg, "isMute", !!Number(localStorage.getItem("mute")) || false);
|
|
2839
|
-
__publicField(GlobalMsg, "speechSynthesis", window.speechSynthesis);
|
|
2840
|
-
__publicField(GlobalMsg, "speechSynthesisUtterance", new SpeechSynthesisUtterance());
|
|
2841
|
-
const OptimizeUtil = {
|
|
3011
|
+
},
|
|
2842
3012
|
/**
|
|
2843
|
-
*
|
|
3013
|
+
* 将元素移到父节点的最前面
|
|
2844
3014
|
*
|
|
2845
|
-
* @param
|
|
2846
|
-
* @param wait 等待时间,单位毫秒。
|
|
2847
|
-
* @param immediate 是否立即执行函数,默认为true。
|
|
2848
|
-
* @returns 返回防抖后的函数。
|
|
3015
|
+
* @param el 要移动的元素,需要包含 parentNode 属性
|
|
2849
3016
|
*/
|
|
2850
|
-
|
|
2851
|
-
|
|
2852
|
-
|
|
2853
|
-
|
|
2854
|
-
|
|
2855
|
-
const later = () => {
|
|
2856
|
-
const last = Date.now() - timestamp;
|
|
2857
|
-
if (last < wait && last > 0) {
|
|
2858
|
-
timeout = setTimeout(later, wait - last);
|
|
2859
|
-
} else {
|
|
2860
|
-
timeout = null;
|
|
2861
|
-
if (!immediate) {
|
|
2862
|
-
result = func.apply(this, args);
|
|
2863
|
-
}
|
|
2864
|
-
}
|
|
2865
|
-
};
|
|
2866
|
-
return (...args2) => {
|
|
2867
|
-
timestamp = Date.now();
|
|
2868
|
-
const callNow = immediate && !timeout;
|
|
2869
|
-
if (!timeout) {
|
|
2870
|
-
timeout = setTimeout(later, wait);
|
|
2871
|
-
}
|
|
2872
|
-
if (callNow) {
|
|
2873
|
-
result = func.apply(this, args2);
|
|
2874
|
-
if (!timeout) {
|
|
2875
|
-
args2 = null;
|
|
2876
|
-
}
|
|
2877
|
-
}
|
|
2878
|
-
return result;
|
|
2879
|
-
};
|
|
3017
|
+
toFront(el) {
|
|
3018
|
+
const parent = el.parentNode;
|
|
3019
|
+
if (parent && parent.lastChild !== el) {
|
|
3020
|
+
parent.appendChild(el);
|
|
3021
|
+
}
|
|
2880
3022
|
},
|
|
2881
3023
|
/**
|
|
2882
|
-
*
|
|
3024
|
+
* 将元素移动到其父节点的最前面
|
|
2883
3025
|
*
|
|
2884
|
-
* @param
|
|
2885
|
-
* @param wait 节流间隔,单位为毫秒
|
|
2886
|
-
* @param type 节流类型,1表示时间戳方式,2表示定时器方式
|
|
2887
|
-
* @returns 返回一个新的函数,该函数在节流控制下执行传入的函数
|
|
3026
|
+
* @param el 要移动的元素,需要包含parentNode属性
|
|
2888
3027
|
*/
|
|
2889
|
-
|
|
2890
|
-
|
|
2891
|
-
|
|
2892
|
-
|
|
2893
|
-
|
|
2894
|
-
const now = Date.now();
|
|
2895
|
-
if (now - previous >= wait) {
|
|
2896
|
-
func.apply(this, args);
|
|
2897
|
-
previous = now;
|
|
2898
|
-
}
|
|
2899
|
-
} else if (type === 2) {
|
|
2900
|
-
if (!timeout) {
|
|
2901
|
-
timeout = setTimeout(() => {
|
|
2902
|
-
timeout = null;
|
|
2903
|
-
func.apply(this, args);
|
|
2904
|
-
}, wait);
|
|
2905
|
-
}
|
|
2906
|
-
}
|
|
2907
|
-
};
|
|
3028
|
+
toBack(el) {
|
|
3029
|
+
const parent = el.parentNode;
|
|
3030
|
+
if (parent && parent.firstChild !== el) {
|
|
3031
|
+
parent.insertBefore(el, parent.firstChild);
|
|
3032
|
+
}
|
|
2908
3033
|
},
|
|
2909
3034
|
/**
|
|
2910
|
-
*
|
|
3035
|
+
* 获取元素的类名
|
|
2911
3036
|
*
|
|
2912
|
-
* @param
|
|
2913
|
-
* @
|
|
2914
|
-
|
|
2915
|
-
|
|
2916
|
-
|
|
2917
|
-
|
|
2918
|
-
|
|
2919
|
-
|
|
2920
|
-
|
|
2921
|
-
} else {
|
|
2922
|
-
const result = fn.apply(this, args);
|
|
2923
|
-
cache.set(argsString, result);
|
|
2924
|
-
return result;
|
|
2925
|
-
}
|
|
2926
|
-
};
|
|
3037
|
+
* @param el 包含对应元素和类名的对象
|
|
3038
|
+
* @param el.correspondingElement 对应的元素
|
|
3039
|
+
* @param el.className 类名对象
|
|
3040
|
+
* @param el.className.baseVal 类名字符串
|
|
3041
|
+
* @returns 返回元素的类名字符串
|
|
3042
|
+
*/
|
|
3043
|
+
getClass(el) {
|
|
3044
|
+
const shadowElement = (el == null ? void 0 : el.host) || el;
|
|
3045
|
+
return shadowElement.className.toString();
|
|
2927
3046
|
},
|
|
2928
3047
|
/**
|
|
2929
|
-
*
|
|
3048
|
+
* 判断元素是否包含指定类名
|
|
2930
3049
|
*
|
|
2931
|
-
* @param
|
|
2932
|
-
* @param
|
|
2933
|
-
* @
|
|
3050
|
+
* @param el 元素对象,包含classList属性,classList属性包含contains方法
|
|
3051
|
+
* @param name 要判断的类名
|
|
3052
|
+
* @returns 返回一个布尔值,表示元素是否包含指定类名
|
|
2934
3053
|
*/
|
|
2935
|
-
|
|
2936
|
-
|
|
2937
|
-
|
|
2938
|
-
|
|
2939
|
-
|
|
2940
|
-
|
|
2941
|
-
|
|
2942
|
-
}
|
|
2943
|
-
}, frequency);
|
|
3054
|
+
hasClass(el, name) {
|
|
3055
|
+
var _a2;
|
|
3056
|
+
if ((_a2 = el.classList) == null ? void 0 : _a2.contains(name)) {
|
|
3057
|
+
return true;
|
|
3058
|
+
}
|
|
3059
|
+
const className = this.getClass(el);
|
|
3060
|
+
return className.length > 0 && new RegExp(`(^|\\s)${name}(\\s|$)`).test(className);
|
|
2944
3061
|
},
|
|
2945
3062
|
/**
|
|
2946
|
-
*
|
|
3063
|
+
* 给指定的 HTML 元素添加类名
|
|
2947
3064
|
*
|
|
2948
|
-
* @param
|
|
2949
|
-
* @
|
|
3065
|
+
* @param el 要添加类名的 HTML 元素
|
|
3066
|
+
* @param name 要添加的类名,多个类名之间用空格分隔
|
|
2950
3067
|
*/
|
|
2951
|
-
|
|
2952
|
-
|
|
2953
|
-
|
|
2954
|
-
|
|
2955
|
-
|
|
2956
|
-
return func(...args);
|
|
3068
|
+
addClass(el, name) {
|
|
3069
|
+
if (el.classList !== void 0) {
|
|
3070
|
+
const classes = splitWords(name);
|
|
3071
|
+
for (let i = 0, len = classes.length; i < len; i++) {
|
|
3072
|
+
el.classList.add(classes[i]);
|
|
2957
3073
|
}
|
|
2958
|
-
}
|
|
2959
|
-
|
|
2960
|
-
|
|
2961
|
-
|
|
3074
|
+
} else if (!this.hasClass(el, name)) {
|
|
3075
|
+
const className = this.getClass(el);
|
|
3076
|
+
this.setClass(el, (className ? className + " " : "") + name);
|
|
3077
|
+
}
|
|
3078
|
+
},
|
|
2962
3079
|
/**
|
|
2963
|
-
*
|
|
3080
|
+
* 从元素中移除指定类名
|
|
2964
3081
|
*
|
|
2965
|
-
* @param
|
|
2966
|
-
* @
|
|
3082
|
+
* @param el 要移除类名的元素
|
|
3083
|
+
* @param name 要移除的类名,多个类名用空格分隔
|
|
2967
3084
|
*/
|
|
2968
|
-
|
|
2969
|
-
|
|
2970
|
-
|
|
2971
|
-
|
|
2972
|
-
|
|
2973
|
-
|
|
2974
|
-
tempArr.push(encodeURIComponent(key) + "=" + encodeURIComponent(value));
|
|
2975
|
-
}
|
|
3085
|
+
removeClass(el, name) {
|
|
3086
|
+
if (el.classList !== void 0) {
|
|
3087
|
+
const classes = splitWords(name);
|
|
3088
|
+
classes.forEach((className) => el.classList.remove(className));
|
|
3089
|
+
} else {
|
|
3090
|
+
this.setClass(el, (" " + this.getClass(el) + " ").replace(" " + name + " ", " ").trim());
|
|
2976
3091
|
}
|
|
2977
|
-
var urlParamsStr = tempArr.join("&");
|
|
2978
|
-
return urlParamsStr;
|
|
2979
3092
|
},
|
|
2980
3093
|
/**
|
|
2981
|
-
*
|
|
3094
|
+
* 设置元素的 CSS 类名
|
|
2982
3095
|
*
|
|
2983
|
-
* @param
|
|
2984
|
-
* @param
|
|
2985
|
-
* @returns 返回一个包含解析后参数的对象,其中键为参数名,值为参数值
|
|
3096
|
+
* @param el HTML 或 SVG 元素
|
|
3097
|
+
* @param name 要设置的类名,多个类名之间用空格分隔
|
|
2986
3098
|
*/
|
|
2987
|
-
|
|
2988
|
-
|
|
2989
|
-
|
|
2990
|
-
|
|
2991
|
-
let obj = {};
|
|
2992
|
-
for (let i = 0; i < args.length; i++) {
|
|
2993
|
-
const str = args[i];
|
|
2994
|
-
if (str) {
|
|
2995
|
-
const s = str.replace(/#|\//g, "");
|
|
2996
|
-
const arr = s.split("?");
|
|
2997
|
-
if (arr.length > 1) {
|
|
2998
|
-
for (let j = 1; j < arr.length; j++) {
|
|
2999
|
-
let res;
|
|
3000
|
-
while (res = reg.exec(arr[j])) {
|
|
3001
|
-
obj[res[1]] = needDecode ? decodeURIComponent(res[2]) : res[2];
|
|
3002
|
-
}
|
|
3003
|
-
}
|
|
3004
|
-
}
|
|
3005
|
-
}
|
|
3006
|
-
}
|
|
3007
|
-
return obj;
|
|
3008
|
-
}
|
|
3009
|
-
};
|
|
3010
|
-
class Color {
|
|
3011
|
-
constructor(r, g, b, a) {
|
|
3012
|
-
__publicField(this, "_r");
|
|
3013
|
-
__publicField(this, "_g");
|
|
3014
|
-
__publicField(this, "_b");
|
|
3015
|
-
__publicField(this, "_alpha");
|
|
3016
|
-
this._validateColorChannel(r);
|
|
3017
|
-
this._validateColorChannel(g);
|
|
3018
|
-
this._validateColorChannel(b);
|
|
3019
|
-
this._r = r;
|
|
3020
|
-
this._g = g;
|
|
3021
|
-
this._b = b;
|
|
3022
|
-
this._alpha = MathUtils.clamp(a || 1, 0, 1);
|
|
3023
|
-
}
|
|
3024
|
-
_validateColorChannel(channel) {
|
|
3025
|
-
if (channel < 0 || channel > 255) {
|
|
3026
|
-
throw new Error("Color channel must be between 0 and 255.");
|
|
3099
|
+
setClass(el, name) {
|
|
3100
|
+
if ("classList" in el) {
|
|
3101
|
+
el.classList.value = "";
|
|
3102
|
+
name.split(" ").forEach((className) => el.classList.add(className));
|
|
3027
3103
|
}
|
|
3028
|
-
}
|
|
3029
|
-
toString() {
|
|
3030
|
-
return `rgba(${this._r}, ${this._g}, ${this._b}, ${this._alpha})`;
|
|
3031
|
-
}
|
|
3032
|
-
toJson() {
|
|
3033
|
-
return { r: this._r, g: this._g, b: this._b, a: this._alpha };
|
|
3034
|
-
}
|
|
3035
|
-
get rgba() {
|
|
3036
|
-
return `rgba(${this._r}, ${this._g}, ${this._b}, ${this._alpha})`;
|
|
3037
|
-
}
|
|
3038
|
-
get hex() {
|
|
3039
|
-
return Color.rgb2hex(this._r, this._g, this._b, this._alpha);
|
|
3040
|
-
}
|
|
3041
|
-
setAlpha(a) {
|
|
3042
|
-
this._alpha = MathUtils.clamp(a, 0, 1);
|
|
3043
|
-
return this;
|
|
3044
|
-
}
|
|
3045
|
-
// 设置颜色的RGB值
|
|
3046
|
-
setRgb(r, g, b) {
|
|
3047
|
-
this._validateColorChannel(r);
|
|
3048
|
-
this._validateColorChannel(g);
|
|
3049
|
-
this._validateColorChannel(b);
|
|
3050
|
-
this._r = r;
|
|
3051
|
-
this._g = g;
|
|
3052
|
-
this._b = b;
|
|
3053
|
-
return this;
|
|
3054
|
-
}
|
|
3104
|
+
},
|
|
3055
3105
|
/**
|
|
3056
|
-
*
|
|
3106
|
+
* 从字符串中解析XML文档,并返回根节点
|
|
3057
3107
|
*
|
|
3058
|
-
* @param
|
|
3059
|
-
* @returns
|
|
3060
|
-
* @throws 如果rgbaValue不是有效的RGBA颜色值,则抛出错误
|
|
3108
|
+
* @param str 要解析的XML字符串
|
|
3109
|
+
* @returns 解析后的XML文档的根节点
|
|
3061
3110
|
*/
|
|
3062
|
-
|
|
3063
|
-
const
|
|
3064
|
-
|
|
3065
|
-
|
|
3066
|
-
const g = parseInt(rgbaMatch[2], 10);
|
|
3067
|
-
const b = parseInt(rgbaMatch[3], 10);
|
|
3068
|
-
const a = rgbaMatch[5] ? parseFloat(rgbaMatch[5]) : 1;
|
|
3069
|
-
return new Color(r, g, b, a);
|
|
3111
|
+
parseFromString(str) {
|
|
3112
|
+
const parser = new DOMParser();
|
|
3113
|
+
const doc = parser.parseFromString(str, "text/xml");
|
|
3114
|
+
return doc.children[0];
|
|
3070
3115
|
}
|
|
3116
|
+
};
|
|
3117
|
+
const FileUtil = {
|
|
3071
3118
|
/**
|
|
3072
|
-
*
|
|
3119
|
+
* 将Base64编码的字符串转换为Blob对象
|
|
3073
3120
|
*
|
|
3074
|
-
* @param
|
|
3075
|
-
* @returns
|
|
3121
|
+
* @param data Base64编码的字符串
|
|
3122
|
+
* @returns 转换后的Blob对象
|
|
3076
3123
|
*/
|
|
3077
|
-
|
|
3078
|
-
const
|
|
3079
|
-
const
|
|
3080
|
-
const
|
|
3081
|
-
|
|
3082
|
-
|
|
3083
|
-
throw new Error("Invalid HEX color value");
|
|
3124
|
+
convertBase64ToBlob(data) {
|
|
3125
|
+
const mimeString = data.split(",")[0].split(":")[1].split(";")[0];
|
|
3126
|
+
const byteCharacters = atob(data.split(",")[1]);
|
|
3127
|
+
const byteNumbers = new Array(byteCharacters.length);
|
|
3128
|
+
for (let i = 0; i < byteCharacters.length; i++) {
|
|
3129
|
+
byteNumbers[i] = byteCharacters.charCodeAt(i);
|
|
3084
3130
|
}
|
|
3085
|
-
const
|
|
3086
|
-
const
|
|
3087
|
-
|
|
3088
|
-
|
|
3089
|
-
}
|
|
3131
|
+
const byteArray = new Uint8Array(byteNumbers);
|
|
3132
|
+
const blob = new Blob([byteArray], { type: mimeString });
|
|
3133
|
+
return blob;
|
|
3134
|
+
},
|
|
3090
3135
|
/**
|
|
3091
|
-
*
|
|
3136
|
+
* 将图片的URL转换为Base64编码
|
|
3092
3137
|
*
|
|
3093
|
-
* @param
|
|
3094
|
-
* @
|
|
3138
|
+
* @param url 图片的URL地址
|
|
3139
|
+
* @param width 图片的宽度,默认为图片原始宽度
|
|
3140
|
+
* @param height 图片的高度,默认为图片原始高度
|
|
3141
|
+
* @returns 返回Promise对象,解析后得到包含Base64编码数据的对象
|
|
3095
3142
|
*/
|
|
3096
|
-
static fromHsl(hslValue) {
|
|
3097
|
-
const hsl = /hsl\((\d+),\s*([\d.]+)%,\s*([\d.]+)%\)/g.exec(hslValue) || /hsla\((\d+),\s*([\d.]+)%,\s*([\d.]+)%,\s*([\d.]+)\)/g.exec(hslValue);
|
|
3098
|
-
if (!hsl) {
|
|
3099
|
-
throw new Error("Invalid HSL color value");
|
|
3100
|
-
}
|
|
3101
|
-
const h = parseInt(hsl[1], 10) / 360;
|
|
3102
|
-
const s = parseInt(hsl[2], 10) / 100;
|
|
3103
|
-
const l = parseInt(hsl[3], 10) / 100;
|
|
3104
|
-
const a = hsl[4] ? parseFloat(hsl[4]) : 1;
|
|
3105
|
-
function hue2rgb(p, q, t) {
|
|
3106
|
-
if (t < 0) t += 1;
|
|
3107
|
-
if (t > 1) t -= 1;
|
|
3108
|
-
if (t < 1 / 6) return p + (q - p) * 6 * t;
|
|
3109
|
-
if (t < 1 / 2) return q;
|
|
3110
|
-
if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
|
|
3111
|
-
return p;
|
|
3112
|
-
}
|
|
3113
|
-
let r, g, b;
|
|
3114
|
-
if (s === 0) {
|
|
3115
|
-
r = g = b = l;
|
|
3116
|
-
} else {
|
|
3117
|
-
const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
|
|
3118
|
-
const p = 2 * l - q;
|
|
3119
|
-
r = hue2rgb(p, q, h + 1 / 3);
|
|
3120
|
-
g = hue2rgb(p, q, h);
|
|
3121
|
-
b = hue2rgb(p, q, h - 1 / 3);
|
|
3122
|
-
}
|
|
3123
|
-
return new Color(Math.round(r * 255), Math.round(g * 255), Math.round(b * 255), a);
|
|
3124
|
-
}
|
|
3125
3143
|
/**
|
|
3126
|
-
*
|
|
3144
|
+
* 将base64字符串转换为文件对象
|
|
3127
3145
|
*
|
|
3128
|
-
* @param
|
|
3129
|
-
* @
|
|
3130
|
-
* @
|
|
3131
|
-
*/
|
|
3132
|
-
|
|
3133
|
-
|
|
3134
|
-
|
|
3135
|
-
|
|
3136
|
-
|
|
3137
|
-
|
|
3138
|
-
|
|
3139
|
-
|
|
3140
|
-
throw new Error("Invalid color value");
|
|
3146
|
+
* @param dataurl 包含base64字符串的数据URL
|
|
3147
|
+
* @param filename 文件的名称
|
|
3148
|
+
* @returns 返回文件对象
|
|
3149
|
+
*/
|
|
3150
|
+
convertBase64ToFile(dataurl, filename) {
|
|
3151
|
+
const arr = dataurl.split(",");
|
|
3152
|
+
const mimeMatch = arr[0].match(/:(.*?);/);
|
|
3153
|
+
const mime = mimeMatch ? mimeMatch[1] : "image/png";
|
|
3154
|
+
const bstr = atob(arr[1]);
|
|
3155
|
+
const u8arr = new Uint8Array(bstr.length);
|
|
3156
|
+
for (let i = 0; i < bstr.length; i++) {
|
|
3157
|
+
u8arr[i] = bstr.charCodeAt(i);
|
|
3141
3158
|
}
|
|
3142
|
-
|
|
3159
|
+
const file = new File([u8arr], filename, { type: mime });
|
|
3160
|
+
return file;
|
|
3161
|
+
},
|
|
3143
3162
|
/**
|
|
3144
|
-
*
|
|
3163
|
+
* 从文件下载数据
|
|
3145
3164
|
*
|
|
3146
|
-
* @param
|
|
3147
|
-
* @param
|
|
3148
|
-
* @param b 蓝色分量值,取值范围0-255
|
|
3149
|
-
* @param a 可选参数,透明度分量值,取值范围0-1
|
|
3150
|
-
* @returns 十六进制颜色值,格式为#RRGGBB或#RRGGBBAA
|
|
3165
|
+
* @param data 要下载的数据,可以是字符串数组、BlobPart 或 MediaSource
|
|
3166
|
+
* @param saveName 下载后文件的保存名称
|
|
3151
3167
|
*/
|
|
3152
|
-
|
|
3153
|
-
|
|
3154
|
-
|
|
3155
|
-
|
|
3156
|
-
|
|
3168
|
+
downloadFromFile(data, saveName) {
|
|
3169
|
+
if (typeof data == "object") {
|
|
3170
|
+
if (data instanceof Blob) {
|
|
3171
|
+
data = URL.createObjectURL(data);
|
|
3172
|
+
} else {
|
|
3173
|
+
const str = JSON.stringify(data);
|
|
3174
|
+
const blob = new Blob([str], { type: "text/json" });
|
|
3175
|
+
data = window.URL.createObjectURL(blob);
|
|
3176
|
+
}
|
|
3177
|
+
} else if (typeof data == "string" && data.indexOf("http") === -1) {
|
|
3178
|
+
const blob = new Blob([data], { type: "text/json" });
|
|
3179
|
+
data = window.URL.createObjectURL(blob);
|
|
3157
3180
|
}
|
|
3158
|
-
|
|
3159
|
-
|
|
3160
|
-
|
|
3161
|
-
|
|
3162
|
-
|
|
3163
|
-
static isRgb(a) {
|
|
3164
|
-
return /^rgba?\s*\(\s*\d+\s*,\s*\d+\s*,\s*\d+\s*(,\s*[\d.]+)?\s*\)$/.test(a);
|
|
3165
|
-
}
|
|
3166
|
-
static isHsl(a) {
|
|
3167
|
-
return /^(hsl|hsla)\(\d+,\s*[\d.]+%,\s*[\d.]+%(,\s*[\d.]+)?\)$/.test(a);
|
|
3181
|
+
var link = document.createElement("a");
|
|
3182
|
+
link.href = data;
|
|
3183
|
+
link.download = saveName || "";
|
|
3184
|
+
link.click();
|
|
3185
|
+
window.URL.revokeObjectURL(link.href);
|
|
3168
3186
|
}
|
|
3169
|
-
|
|
3170
|
-
|
|
3187
|
+
};
|
|
3188
|
+
class MessageUtil {
|
|
3189
|
+
static resetWarned() {
|
|
3190
|
+
this.warned = {};
|
|
3171
3191
|
}
|
|
3172
|
-
static
|
|
3173
|
-
|
|
3174
|
-
|
|
3175
|
-
let b = Math.floor(Math.random() * 256);
|
|
3176
|
-
let a = Math.random();
|
|
3177
|
-
return new Color(r, g, b, a);
|
|
3192
|
+
static changeVoice() {
|
|
3193
|
+
this.isMute = !!Number(!this.isMute);
|
|
3194
|
+
localStorage.setItem("mute", Number(this.isMute).toString());
|
|
3178
3195
|
}
|
|
3179
|
-
|
|
3180
|
-
|
|
3181
|
-
|
|
3182
|
-
|
|
3183
|
-
if (typeof el === "string") {
|
|
3184
|
-
el = document.querySelector("#" + el);
|
|
3185
|
-
if (!el) {
|
|
3186
|
-
throw new Error("Element not found");
|
|
3187
|
-
}
|
|
3188
|
-
}
|
|
3189
|
-
if (el instanceof HTMLElement) {
|
|
3190
|
-
const canvas = el;
|
|
3191
|
-
if (canvas.getContext) {
|
|
3192
|
-
this.context = canvas.getContext("2d");
|
|
3193
|
-
} else {
|
|
3194
|
-
throw new Error("getContext is not available on this element");
|
|
3195
|
-
}
|
|
3196
|
-
} else {
|
|
3197
|
-
throw new Error("Element is not an HTMLElement");
|
|
3196
|
+
static _call(method, message) {
|
|
3197
|
+
if (!this.warned[message]) {
|
|
3198
|
+
method(message);
|
|
3199
|
+
this.warned[message] = true;
|
|
3198
3200
|
}
|
|
3199
3201
|
}
|
|
3200
3202
|
/**
|
|
3201
|
-
*
|
|
3203
|
+
* 播放消息提示音和文字朗读
|
|
3202
3204
|
*
|
|
3203
|
-
* @param
|
|
3204
|
-
* @param
|
|
3205
|
-
* @param options
|
|
3206
|
-
* @
|
|
3205
|
+
* @param type 消息类型
|
|
3206
|
+
* @param message 消息内容
|
|
3207
|
+
* @param options 配置选项,可选参数,包括语言、音量、语速和音高
|
|
3208
|
+
* @returns 无返回值
|
|
3207
3209
|
*/
|
|
3208
|
-
|
|
3209
|
-
|
|
3210
|
-
|
|
3211
|
-
|
|
3212
|
-
this.
|
|
3213
|
-
|
|
3214
|
-
|
|
3215
|
-
this.
|
|
3216
|
-
this.
|
|
3217
|
-
this.
|
|
3218
|
-
this.context.lineTo(endX, endY);
|
|
3219
|
-
this.context.stroke();
|
|
3210
|
+
static msg(type, message, options = {}) {
|
|
3211
|
+
Message({ type, message });
|
|
3212
|
+
if (this.isMute) return;
|
|
3213
|
+
const typename = Util.decodeDict(type, "success", "恭喜:", "error", "发生错误:", "warning", "警告:", "info", "友情提示:") + ":";
|
|
3214
|
+
this.speechSynthesisUtterance.text = typename + message;
|
|
3215
|
+
this.speechSynthesisUtterance.lang = options.lang || "zh-CN";
|
|
3216
|
+
this.speechSynthesisUtterance.volume = options.volume || 1;
|
|
3217
|
+
this.speechSynthesisUtterance.rate = options.rate || 1;
|
|
3218
|
+
this.speechSynthesisUtterance.pitch = options.pitch || 1;
|
|
3219
|
+
this.speechSynthesis.speak(this.speechSynthesisUtterance);
|
|
3220
3220
|
}
|
|
3221
|
-
|
|
3222
|
-
|
|
3223
|
-
|
|
3224
|
-
* @param x 圆心x坐标
|
|
3225
|
-
* @param y 圆心y坐标
|
|
3226
|
-
* @param radius 半径
|
|
3227
|
-
* @param startAngle 起始角度(度)
|
|
3228
|
-
* @param endAngle 结束角度(度)
|
|
3229
|
-
* @param anticlockwise 是否逆时针绘制
|
|
3230
|
-
* @param isFill 是否填充
|
|
3231
|
-
* @param bgColor 背景颜色
|
|
3232
|
-
* @throws 当Canvas context为null或undefined时抛出错误
|
|
3233
|
-
*/
|
|
3234
|
-
drawArc({ x, y }, radius, startAngle, endAngle, anticlockwise, isFill, bgColor) {
|
|
3235
|
-
if (!this.context) {
|
|
3236
|
-
throw new Error("Canvas context is null or undefined");
|
|
3237
|
-
}
|
|
3238
|
-
if (isFill) {
|
|
3239
|
-
this.context.fillStyle = bgColor;
|
|
3240
|
-
this.context.beginPath();
|
|
3241
|
-
this.context.arc(x, y, radius, MathUtils.deg2Rad(startAngle), MathUtils.deg2Rad(endAngle), anticlockwise);
|
|
3242
|
-
this.context.fill();
|
|
3243
|
-
} else {
|
|
3244
|
-
this.context.strokeStyle = bgColor;
|
|
3245
|
-
this.context.beginPath();
|
|
3246
|
-
this.context.arc(x, y, radius, MathUtils.deg2Rad(startAngle), MathUtils.deg2Rad(endAngle), anticlockwise);
|
|
3247
|
-
this.context.stroke();
|
|
3248
|
-
}
|
|
3221
|
+
static stop(e) {
|
|
3222
|
+
this.speechSynthesisUtterance.text = e;
|
|
3223
|
+
this.speechSynthesis.cancel();
|
|
3249
3224
|
}
|
|
3250
|
-
static
|
|
3251
|
-
|
|
3252
|
-
|
|
3253
|
-
canvas.width = width;
|
|
3254
|
-
}
|
|
3255
|
-
if (height) {
|
|
3256
|
-
canvas.height = height;
|
|
3225
|
+
static warning(message) {
|
|
3226
|
+
if (process.env.NODE_ENV === "development" && console !== void 0) {
|
|
3227
|
+
console.warn(`Warning: ${message}`);
|
|
3257
3228
|
}
|
|
3258
|
-
|
|
3229
|
+
this.msg("warning", message);
|
|
3259
3230
|
}
|
|
3260
|
-
|
|
3261
|
-
|
|
3262
|
-
constructor() {
|
|
3263
|
-
__publicField(this, "_listeners");
|
|
3264
|
-
__publicField(this, "_mutex", {});
|
|
3265
|
-
__publicField(this, "_context");
|
|
3231
|
+
static warningOnce(message) {
|
|
3232
|
+
this._call(this.warning.bind(this), message);
|
|
3266
3233
|
}
|
|
3267
|
-
|
|
3268
|
-
if (
|
|
3269
|
-
|
|
3270
|
-
const mutex = this._mutex;
|
|
3271
|
-
const listeners = this._listeners;
|
|
3272
|
-
if (listeners[type] === void 0) {
|
|
3273
|
-
listeners[type] = [];
|
|
3274
|
-
}
|
|
3275
|
-
if (listeners[type].indexOf(listener) === -1) {
|
|
3276
|
-
if (mutexStatus) {
|
|
3277
|
-
mutex[type] = listener;
|
|
3278
|
-
}
|
|
3279
|
-
listeners[type].push(listener);
|
|
3234
|
+
static info(message) {
|
|
3235
|
+
if (process.env.NODE_ENV === "development" && console !== void 0) {
|
|
3236
|
+
console.info(`Info: ${message}`);
|
|
3280
3237
|
}
|
|
3281
|
-
|
|
3238
|
+
this.msg("info", message);
|
|
3282
3239
|
}
|
|
3283
|
-
|
|
3284
|
-
|
|
3285
|
-
const listeners = this._listeners;
|
|
3286
|
-
return listeners[type] !== void 0 && listeners[type].indexOf(listener) !== -1;
|
|
3240
|
+
static infoOnce(message) {
|
|
3241
|
+
this._call(this.info.bind(this), message);
|
|
3287
3242
|
}
|
|
3288
|
-
|
|
3289
|
-
if (
|
|
3290
|
-
|
|
3291
|
-
const listenerArray = listeners[type];
|
|
3292
|
-
if (this._mutex[type] === listener) {
|
|
3293
|
-
this._mutex[type] = null;
|
|
3243
|
+
static error(message) {
|
|
3244
|
+
if (process.env.NODE_ENV === "development" && console !== void 0) {
|
|
3245
|
+
console.error(`Error: ${message}`);
|
|
3294
3246
|
}
|
|
3295
|
-
|
|
3296
|
-
|
|
3297
|
-
|
|
3298
|
-
|
|
3299
|
-
|
|
3247
|
+
this.msg("error", message);
|
|
3248
|
+
}
|
|
3249
|
+
static errorOnce(message) {
|
|
3250
|
+
this._call(this.error.bind(this), message);
|
|
3251
|
+
}
|
|
3252
|
+
static success(message) {
|
|
3253
|
+
if (process.env.NODE_ENV === "development" && console !== void 0) {
|
|
3254
|
+
console.log(`Success: ${message}`);
|
|
3300
3255
|
}
|
|
3256
|
+
this.msg("success", message);
|
|
3301
3257
|
}
|
|
3302
|
-
|
|
3303
|
-
|
|
3304
|
-
|
|
3305
|
-
|
|
3306
|
-
|
|
3307
|
-
|
|
3308
|
-
|
|
3309
|
-
|
|
3310
|
-
|
|
3311
|
-
|
|
3312
|
-
|
|
3313
|
-
|
|
3258
|
+
static successOnce(message) {
|
|
3259
|
+
this._call(this.success.bind(this), message);
|
|
3260
|
+
}
|
|
3261
|
+
}
|
|
3262
|
+
__publicField(MessageUtil, "warned", {});
|
|
3263
|
+
__publicField(MessageUtil, "isMute", !!Number(localStorage.getItem("mute")) || false);
|
|
3264
|
+
__publicField(MessageUtil, "speechSynthesis", window.speechSynthesis);
|
|
3265
|
+
__publicField(MessageUtil, "speechSynthesisUtterance", new SpeechSynthesisUtterance());
|
|
3266
|
+
const OptimizeUtil = {
|
|
3267
|
+
/**
|
|
3268
|
+
* 防抖函数,在指定的等待时间内,如果连续触发事件,则只在最后一次触发后执行函数。适用于像搜索输入框这种需要用户停止输入后才调用的场景
|
|
3269
|
+
*
|
|
3270
|
+
* @param func 需要防抖的函数。
|
|
3271
|
+
* @param wait 等待时间,单位毫秒。
|
|
3272
|
+
* @param immediate 是否立即执行函数,默认为true。
|
|
3273
|
+
* @returns 返回防抖后的函数。
|
|
3274
|
+
*/
|
|
3275
|
+
debounce(func, wait, immediate = true) {
|
|
3276
|
+
let timeout = null;
|
|
3277
|
+
let args;
|
|
3278
|
+
let timestamp;
|
|
3279
|
+
let result;
|
|
3280
|
+
const later = () => {
|
|
3281
|
+
const last = Date.now() - timestamp;
|
|
3282
|
+
if (last < wait && last > 0) {
|
|
3283
|
+
timeout = setTimeout(later, wait - last);
|
|
3284
|
+
} else {
|
|
3285
|
+
timeout = null;
|
|
3286
|
+
if (!immediate) {
|
|
3287
|
+
result = func.apply(this, args);
|
|
3288
|
+
}
|
|
3289
|
+
}
|
|
3290
|
+
};
|
|
3291
|
+
return (...args2) => {
|
|
3292
|
+
timestamp = Date.now();
|
|
3293
|
+
const callNow = immediate && !timeout;
|
|
3294
|
+
if (!timeout) {
|
|
3295
|
+
timeout = setTimeout(later, wait);
|
|
3296
|
+
}
|
|
3297
|
+
if (callNow) {
|
|
3298
|
+
result = func.apply(this, args2);
|
|
3299
|
+
if (!timeout) {
|
|
3300
|
+
args2 = null;
|
|
3314
3301
|
}
|
|
3315
3302
|
}
|
|
3316
|
-
|
|
3317
|
-
|
|
3318
|
-
|
|
3319
|
-
|
|
3303
|
+
return result;
|
|
3304
|
+
};
|
|
3305
|
+
},
|
|
3306
|
+
/**
|
|
3307
|
+
* 节流函数,适用于像滚动事件、窗口resize事件这种需要限制调用频率的场景
|
|
3308
|
+
*
|
|
3309
|
+
* @param func 需要节流的函数
|
|
3310
|
+
* @param wait 节流间隔,单位为毫秒
|
|
3311
|
+
* @param type 节流类型,1表示时间戳方式,2表示定时器方式
|
|
3312
|
+
* @returns 返回一个新的函数,该函数在节流控制下执行传入的函数
|
|
3313
|
+
*/
|
|
3314
|
+
throttle(func, wait, type = 1) {
|
|
3315
|
+
let previous = 0;
|
|
3316
|
+
let timeout = null;
|
|
3317
|
+
return (...args) => {
|
|
3318
|
+
if (type === 1) {
|
|
3319
|
+
const now = Date.now();
|
|
3320
|
+
if (now - previous >= wait) {
|
|
3321
|
+
func.apply(this, args);
|
|
3322
|
+
previous = now;
|
|
3323
|
+
}
|
|
3324
|
+
} else if (type === 2) {
|
|
3325
|
+
if (!timeout) {
|
|
3326
|
+
timeout = setTimeout(() => {
|
|
3327
|
+
timeout = null;
|
|
3328
|
+
func.apply(this, args);
|
|
3329
|
+
}, wait);
|
|
3320
3330
|
}
|
|
3321
3331
|
}
|
|
3322
|
-
}
|
|
3323
|
-
}
|
|
3324
|
-
removeAllListener() {
|
|
3325
|
-
this._mutex = {};
|
|
3326
|
-
for (const key in this._listeners) {
|
|
3327
|
-
this._listeners[key] = [];
|
|
3328
|
-
}
|
|
3329
|
-
}
|
|
3330
|
-
}
|
|
3331
|
-
class HashMap extends Map {
|
|
3332
|
-
isEmpty() {
|
|
3333
|
-
return this.size === 0;
|
|
3334
|
-
}
|
|
3335
|
-
_values() {
|
|
3336
|
-
return Array.from(this.values());
|
|
3337
|
-
}
|
|
3338
|
-
_keys() {
|
|
3339
|
-
return Array.from(this.keys());
|
|
3340
|
-
}
|
|
3341
|
-
_entries() {
|
|
3342
|
-
return Array.from(this.entries());
|
|
3343
|
-
}
|
|
3332
|
+
};
|
|
3333
|
+
},
|
|
3344
3334
|
/**
|
|
3345
|
-
*
|
|
3335
|
+
* 缓存函数,将传入的函数fn的计算结果缓存,提高重复计算的效率
|
|
3346
3336
|
*
|
|
3347
|
-
* @param
|
|
3348
|
-
* @returns
|
|
3337
|
+
* @param fn 传入待缓存的函数
|
|
3338
|
+
* @returns 返回缓存后的函数
|
|
3349
3339
|
*/
|
|
3350
|
-
|
|
3351
|
-
const
|
|
3352
|
-
|
|
3353
|
-
|
|
3354
|
-
|
|
3340
|
+
memoize(fn) {
|
|
3341
|
+
const cache = /* @__PURE__ */ new Map();
|
|
3342
|
+
return (...args) => {
|
|
3343
|
+
const argsString = JSON.stringify(args);
|
|
3344
|
+
if (cache.has(argsString)) {
|
|
3345
|
+
return cache.get(argsString);
|
|
3346
|
+
} else {
|
|
3347
|
+
const result = fn.apply(this, args);
|
|
3348
|
+
cache.set(argsString, result);
|
|
3349
|
+
return result;
|
|
3355
3350
|
}
|
|
3356
|
-
}
|
|
3357
|
-
|
|
3358
|
-
}
|
|
3351
|
+
};
|
|
3352
|
+
},
|
|
3359
3353
|
/**
|
|
3360
|
-
*
|
|
3354
|
+
* 递归调用函数,以一定的频率和持续时间执行。
|
|
3361
3355
|
*
|
|
3362
|
-
* @param
|
|
3363
|
-
* @
|
|
3356
|
+
* @param fun 要递归调用的函数。
|
|
3357
|
+
* @param frequency 每次调用函数之间的时间间隔,单位为毫秒,默认为500毫秒。
|
|
3358
|
+
* @param duration 函数递归调用的总时长,单位为毫秒,默认为5000毫秒。
|
|
3364
3359
|
*/
|
|
3365
|
-
|
|
3366
|
-
|
|
3367
|
-
|
|
3368
|
-
|
|
3369
|
-
|
|
3370
|
-
|
|
3371
|
-
|
|
3372
|
-
super();
|
|
3373
|
-
__publicField(this, "maxCheckTimes", 10);
|
|
3374
|
-
__publicField(this, "url");
|
|
3375
|
-
__publicField(this, "checkTimes", 0);
|
|
3376
|
-
__publicField(this, "connectStatus", false);
|
|
3377
|
-
__publicField(this, "client", null);
|
|
3378
|
-
this.maxCheckTimes = 10;
|
|
3379
|
-
this.url = url;
|
|
3380
|
-
this.checkTimes = 0;
|
|
3381
|
-
this.connect();
|
|
3382
|
-
this.connCheckStatus(this.maxCheckTimes);
|
|
3383
|
-
}
|
|
3384
|
-
connect() {
|
|
3385
|
-
this.disconnect();
|
|
3386
|
-
if (this.url) {
|
|
3387
|
-
try {
|
|
3388
|
-
console.info("创建ws连接>>>" + this.url);
|
|
3389
|
-
this.client = new WebSocket(this.url);
|
|
3390
|
-
if (this.client) {
|
|
3391
|
-
const self = this;
|
|
3392
|
-
this.client.onopen = function(message) {
|
|
3393
|
-
self.dispatchEvent({
|
|
3394
|
-
type: EventType.WEB_SOCKET_CONNECT,
|
|
3395
|
-
message
|
|
3396
|
-
});
|
|
3397
|
-
};
|
|
3398
|
-
this.client.onmessage = function(message) {
|
|
3399
|
-
self.connectStatus = true;
|
|
3400
|
-
self.dispatchEvent({
|
|
3401
|
-
type: EventType.WEB_SOCKET_MESSAGE,
|
|
3402
|
-
message
|
|
3403
|
-
});
|
|
3404
|
-
};
|
|
3405
|
-
this.client.onclose = function(message) {
|
|
3406
|
-
self.dispatchEvent({
|
|
3407
|
-
type: EventType.WEB_SOCKET_CLOSE,
|
|
3408
|
-
message
|
|
3409
|
-
});
|
|
3410
|
-
};
|
|
3411
|
-
if (this.checkTimes === this.maxCheckTimes) {
|
|
3412
|
-
this.client.onerror = function(message) {
|
|
3413
|
-
self.dispatchEvent({
|
|
3414
|
-
type: EventType.WEB_SOCKET_ERROR,
|
|
3415
|
-
message
|
|
3416
|
-
});
|
|
3417
|
-
};
|
|
3418
|
-
}
|
|
3419
|
-
}
|
|
3420
|
-
} catch (ex) {
|
|
3421
|
-
console.error("创建ws连接失败" + this.url + ":" + ex);
|
|
3360
|
+
recurve(fun, frequency = 500, duration = 5e3) {
|
|
3361
|
+
let timer = 0;
|
|
3362
|
+
setTimeout(() => {
|
|
3363
|
+
timer++;
|
|
3364
|
+
if (timer < Math.floor(duration / frequency)) {
|
|
3365
|
+
fun.call(this);
|
|
3366
|
+
setTimeout(this.recurve.bind(this, fun, frequency, duration), frequency);
|
|
3422
3367
|
}
|
|
3423
|
-
}
|
|
3424
|
-
}
|
|
3425
|
-
|
|
3426
|
-
|
|
3427
|
-
|
|
3428
|
-
|
|
3429
|
-
|
|
3430
|
-
|
|
3431
|
-
|
|
3432
|
-
|
|
3368
|
+
}, frequency);
|
|
3369
|
+
},
|
|
3370
|
+
/**
|
|
3371
|
+
* 确保函数只被调用一次
|
|
3372
|
+
*
|
|
3373
|
+
* @param func 要被调用的函数
|
|
3374
|
+
* @returns 返回一个新的函数,该函数在被首次调用时会执行传入的函数,之后再次调用将不再执行
|
|
3375
|
+
*/
|
|
3376
|
+
once(func) {
|
|
3377
|
+
let called = false;
|
|
3378
|
+
return function(...args) {
|
|
3379
|
+
if (!called) {
|
|
3380
|
+
called = true;
|
|
3381
|
+
return func(...args);
|
|
3433
3382
|
}
|
|
3434
|
-
}
|
|
3383
|
+
};
|
|
3435
3384
|
}
|
|
3436
|
-
|
|
3437
|
-
|
|
3438
|
-
|
|
3439
|
-
|
|
3440
|
-
|
|
3441
|
-
|
|
3385
|
+
};
|
|
3386
|
+
const UrlUtil = {
|
|
3387
|
+
/**
|
|
3388
|
+
* 将json对象转换为查询字符串
|
|
3389
|
+
*
|
|
3390
|
+
* @param json 待转换的json对象
|
|
3391
|
+
* @returns 转换后的查询字符串
|
|
3392
|
+
*/
|
|
3393
|
+
json2Query(json) {
|
|
3394
|
+
var tempArr = [];
|
|
3395
|
+
for (var i in json) {
|
|
3396
|
+
if (json.hasOwnProperty(i)) {
|
|
3397
|
+
var key = i;
|
|
3398
|
+
var value = json[i];
|
|
3399
|
+
tempArr.push(encodeURIComponent(key) + "=" + encodeURIComponent(value));
|
|
3442
3400
|
}
|
|
3443
|
-
this.connCheckStatus(times);
|
|
3444
|
-
}, 2e3);
|
|
3445
|
-
}
|
|
3446
|
-
send(message) {
|
|
3447
|
-
if (this.client && this.client.readyState === 1) {
|
|
3448
|
-
this.client.send(message);
|
|
3449
|
-
return true;
|
|
3450
3401
|
}
|
|
3451
|
-
|
|
3452
|
-
return
|
|
3453
|
-
}
|
|
3454
|
-
|
|
3455
|
-
|
|
3456
|
-
|
|
3457
|
-
|
|
3402
|
+
var urlParamsStr = tempArr.join("&");
|
|
3403
|
+
return urlParamsStr;
|
|
3404
|
+
},
|
|
3405
|
+
/**
|
|
3406
|
+
* 从 URL 中解析出查询参数和哈希参数,并以对象的形式返回
|
|
3407
|
+
*
|
|
3408
|
+
* @param href 需要解析的 URL 链接,默认为当前窗口的 URL
|
|
3409
|
+
* @param needDecode 是否需要解码参数值,默认为 true
|
|
3410
|
+
* @returns 返回一个包含解析后参数的对象,其中键为参数名,值为参数值
|
|
3411
|
+
*/
|
|
3412
|
+
query2Json(href = window.location.href, needDecode = true) {
|
|
3413
|
+
const reg = /([^&=]+)=([\w\W]*?)(&|$|#)/g;
|
|
3414
|
+
const { search, hash } = new URL(href);
|
|
3415
|
+
const args = [search, hash];
|
|
3416
|
+
let obj = {};
|
|
3417
|
+
for (let i = 0; i < args.length; i++) {
|
|
3418
|
+
const str = args[i];
|
|
3419
|
+
if (str) {
|
|
3420
|
+
const s = str.replace(/#|\//g, "");
|
|
3421
|
+
const arr = s.split("?");
|
|
3422
|
+
if (arr.length > 1) {
|
|
3423
|
+
for (let j = 1; j < arr.length; j++) {
|
|
3424
|
+
let res;
|
|
3425
|
+
while (res = reg.exec(arr[j])) {
|
|
3426
|
+
obj[res[1]] = needDecode ? decodeURIComponent(res[2]) : res[2];
|
|
3427
|
+
}
|
|
3428
|
+
}
|
|
3429
|
+
}
|
|
3458
3430
|
}
|
|
3459
|
-
|
|
3460
|
-
|
|
3461
|
-
}, 1e3);
|
|
3431
|
+
}
|
|
3432
|
+
return obj;
|
|
3462
3433
|
}
|
|
3463
|
-
}
|
|
3434
|
+
};
|
|
3464
3435
|
const _MqttClient = class _MqttClient extends EventDispatcher {
|
|
3465
3436
|
constructor(url = `ws://${window.document.domain}:20007/mqtt`, config = {}) {
|
|
3466
3437
|
super();
|
|
@@ -3470,10 +3441,10 @@ const _MqttClient = class _MqttClient extends EventDispatcher {
|
|
|
3470
3441
|
__publicField(this, "options");
|
|
3471
3442
|
__publicField(this, "client");
|
|
3472
3443
|
__publicField(this, "topics");
|
|
3473
|
-
this.context =
|
|
3444
|
+
this.context = Util.extend(_MqttClient.defaultContext, config);
|
|
3474
3445
|
this.options = {
|
|
3475
3446
|
connectTimeout: this.context.MQTT_TIMEOUTM,
|
|
3476
|
-
clientId:
|
|
3447
|
+
clientId: Util.guid(),
|
|
3477
3448
|
username: this.context.MQTT_USERNAME,
|
|
3478
3449
|
password: this.context.MQTT_PASSWORD,
|
|
3479
3450
|
clean: true
|
|
@@ -3666,7 +3637,7 @@ const _Storage = class _Storage {
|
|
|
3666
3637
|
}
|
|
3667
3638
|
}
|
|
3668
3639
|
};
|
|
3669
|
-
__publicField(_Storage, "store", window.
|
|
3640
|
+
__publicField(_Storage, "store", window.sessionStorage);
|
|
3670
3641
|
__publicField(_Storage, "prefix", "");
|
|
3671
3642
|
__publicField(_Storage, "_getPrefixedKey", function(key, options) {
|
|
3672
3643
|
options = options || {};
|
|
@@ -3700,9 +3671,9 @@ export {
|
|
|
3700
3671
|
ImageUtil,
|
|
3701
3672
|
LayerType,
|
|
3702
3673
|
LineSymbol,
|
|
3703
|
-
|
|
3674
|
+
MathUtil,
|
|
3704
3675
|
MeasureMode,
|
|
3705
|
-
|
|
3676
|
+
MessageUtil,
|
|
3706
3677
|
MqttClient,
|
|
3707
3678
|
ObjectState,
|
|
3708
3679
|
ObjectUtil,
|
|
@@ -3710,6 +3681,6 @@ export {
|
|
|
3710
3681
|
Storage,
|
|
3711
3682
|
StringUtil,
|
|
3712
3683
|
UrlUtil,
|
|
3713
|
-
|
|
3684
|
+
Util,
|
|
3714
3685
|
WebSocketClient
|
|
3715
3686
|
};
|