gis-common 4.2.18 → 4.2.20
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/core/Color.d.ts +1 -0
- package/dist/gis-common.es.js +1032 -1028
- package/dist/gis-common.umd.js +1 -1
- package/dist/utils/StringUtil.d.ts +0 -8
- package/package.json +1 -1
package/dist/gis-common.es.js
CHANGED
|
@@ -150,141 +150,528 @@ 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
|
+
var ColorName = /* @__PURE__ */ ((ColorName2) => {
|
|
196
|
+
ColorName2["white"] = "rgba(255, 255, 255, 1)";
|
|
197
|
+
ColorName2["black"] = "rgba(0, 0, 0, 1)";
|
|
198
|
+
ColorName2["red"] = "rgba(255, 0, 0, 1)";
|
|
199
|
+
ColorName2["green"] = "rgba(0, 255, 0, 1)";
|
|
200
|
+
ColorName2["blue"] = "rgba(0, 0, 255, 1)";
|
|
201
|
+
ColorName2["yellow"] = "rgba(255, 255, 0, 1)";
|
|
202
|
+
ColorName2["cyan"] = "rgba(0, 255, 255, 1)";
|
|
203
|
+
ColorName2["magenta"] = "rgba(255, 0, 255, 1)";
|
|
204
|
+
ColorName2["purple"] = "rgba(128, 0, 128, 1)";
|
|
205
|
+
ColorName2["brown"] = "rgba(165, 42, 42, 1)";
|
|
206
|
+
ColorName2["gray"] = "rgba(128, 128, 128, 1)";
|
|
207
|
+
ColorName2["orange"] = "rgba(255, 165, 0, 1)";
|
|
208
|
+
ColorName2["golden"] = "rgba(255, 215, 0, 1)";
|
|
209
|
+
ColorName2["silvery"] = "rgba(192, 192, 192, 1)";
|
|
210
|
+
ColorName2["transparent"] = "rgba(0, 0, 0, 0)";
|
|
211
|
+
return ColorName2;
|
|
212
|
+
})(ColorName || {});
|
|
213
|
+
class Color {
|
|
214
|
+
constructor(r, g, b, a) {
|
|
215
|
+
__publicField(this, "_r");
|
|
216
|
+
__publicField(this, "_g");
|
|
217
|
+
__publicField(this, "_b");
|
|
218
|
+
__publicField(this, "_alpha");
|
|
219
|
+
this._validateColorChannel(r);
|
|
220
|
+
this._validateColorChannel(g);
|
|
221
|
+
this._validateColorChannel(b);
|
|
222
|
+
this._r = r;
|
|
223
|
+
this._g = g;
|
|
224
|
+
this._b = b;
|
|
225
|
+
this._alpha = MathUtil.clamp(a || 1, 0, 1);
|
|
226
|
+
}
|
|
227
|
+
_validateColorChannel(channel) {
|
|
228
|
+
if (channel < 0 || channel > 255) {
|
|
229
|
+
throw new Error("Color channel must be between 0 and 255.");
|
|
210
230
|
}
|
|
211
|
-
}
|
|
231
|
+
}
|
|
232
|
+
toString() {
|
|
233
|
+
return `rgba(${this._r}, ${this._g}, ${this._b}, ${this._alpha})`;
|
|
234
|
+
}
|
|
235
|
+
toJson() {
|
|
236
|
+
return { r: this._r, g: this._g, b: this._b, a: this._alpha };
|
|
237
|
+
}
|
|
238
|
+
get rgba() {
|
|
239
|
+
return `rgba(${this._r}, ${this._g}, ${this._b}, ${this._alpha})`;
|
|
240
|
+
}
|
|
241
|
+
get hex() {
|
|
242
|
+
return Color.rgb2hex(this._r, this._g, this._b, this._alpha);
|
|
243
|
+
}
|
|
244
|
+
setAlpha(a) {
|
|
245
|
+
this._alpha = MathUtil.clamp(a, 0, 1);
|
|
246
|
+
return this;
|
|
247
|
+
}
|
|
248
|
+
// 设置颜色的RGB值
|
|
249
|
+
setRgb(r, g, b) {
|
|
250
|
+
this._validateColorChannel(r);
|
|
251
|
+
this._validateColorChannel(g);
|
|
252
|
+
this._validateColorChannel(b);
|
|
253
|
+
this._r = r;
|
|
254
|
+
this._g = g;
|
|
255
|
+
this._b = b;
|
|
256
|
+
return this;
|
|
257
|
+
}
|
|
212
258
|
/**
|
|
213
|
-
*
|
|
259
|
+
* 从RGBA字符串创建Color对象
|
|
214
260
|
*
|
|
215
|
-
* @param
|
|
216
|
-
* @returns
|
|
261
|
+
* @param rgbaValue RGBA颜色值字符串,格式为"rgba(r,g,b,a)"或"rgb(r,g,b)"
|
|
262
|
+
* @returns 返回Color对象
|
|
263
|
+
* @throws 如果rgbaValue不是有效的RGBA颜色值,则抛出错误
|
|
217
264
|
*/
|
|
218
|
-
|
|
219
|
-
const
|
|
220
|
-
if (
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
265
|
+
static fromRgba(rgbaValue) {
|
|
266
|
+
const rgbaMatch = rgbaValue.match(/^rgba?\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(,\s*([\d.]+))?\s*\)$/);
|
|
267
|
+
if (!rgbaMatch) throw new Error("Invalid RGBA color value");
|
|
268
|
+
const r = parseInt(rgbaMatch[1], 10);
|
|
269
|
+
const g = parseInt(rgbaMatch[2], 10);
|
|
270
|
+
const b = parseInt(rgbaMatch[3], 10);
|
|
271
|
+
const a = rgbaMatch[5] ? parseFloat(rgbaMatch[5]) : 1;
|
|
272
|
+
return new Color(r, g, b, a);
|
|
273
|
+
}
|
|
226
274
|
/**
|
|
227
|
-
*
|
|
275
|
+
* 将十六进制颜色值转换为颜色对象
|
|
228
276
|
*
|
|
229
|
-
* @
|
|
277
|
+
* @param hexValue 十六进制颜色值,可带或不带#前缀,支持3位和6位表示
|
|
278
|
+
* @returns 返回颜色对象
|
|
230
279
|
*/
|
|
231
|
-
|
|
232
|
-
const
|
|
233
|
-
|
|
234
|
-
};
|
|
235
|
-
|
|
236
|
-
|
|
280
|
+
static fromHex(hexValue, a = 1) {
|
|
281
|
+
const rgxShort = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
|
|
282
|
+
const hex = hexValue.replace(rgxShort, (m, r2, g2, b2) => r2 + r2 + g2 + g2 + b2 + b2);
|
|
283
|
+
const rgx = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i;
|
|
284
|
+
const rgb = rgx.exec(hex);
|
|
285
|
+
if (!rgb) {
|
|
286
|
+
throw new Error("Invalid HEX color value");
|
|
287
|
+
}
|
|
288
|
+
const r = parseInt(rgb[1], 16);
|
|
289
|
+
const g = parseInt(rgb[2], 16);
|
|
290
|
+
const b = parseInt(rgb[3], 16);
|
|
291
|
+
return new Color(r, g, b, a);
|
|
292
|
+
}
|
|
237
293
|
/**
|
|
238
|
-
*
|
|
294
|
+
* 从 HSL 字符串创建颜色对象
|
|
239
295
|
*
|
|
240
|
-
* @param
|
|
241
|
-
* @returns
|
|
296
|
+
* @param hsl HSL 字符串,格式为 hsl(h, s%, l%) 或 hsla(h, s%, l%, a)
|
|
297
|
+
* @returns 返回颜色对象,如果 hsl 字符串无效则返回 null
|
|
242
298
|
*/
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
if (
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
if (
|
|
254
|
-
|
|
255
|
-
|
|
299
|
+
static fromHsl(hslValue) {
|
|
300
|
+
const hsl = /hsl\((\d+),\s*([\d.]+)%,\s*([\d.]+)%\)/g.exec(hslValue) || /hsla\((\d+),\s*([\d.]+)%,\s*([\d.]+)%,\s*([\d.]+)\)/g.exec(hslValue);
|
|
301
|
+
if (!hsl) {
|
|
302
|
+
throw new Error("Invalid HSL color value");
|
|
303
|
+
}
|
|
304
|
+
const h = parseInt(hsl[1], 10) / 360;
|
|
305
|
+
const s = parseInt(hsl[2], 10) / 100;
|
|
306
|
+
const l = parseInt(hsl[3], 10) / 100;
|
|
307
|
+
const a = hsl[4] ? parseFloat(hsl[4]) : 1;
|
|
308
|
+
function hue2rgb(p, q, t) {
|
|
309
|
+
if (t < 0) t += 1;
|
|
310
|
+
if (t > 1) t -= 1;
|
|
311
|
+
if (t < 1 / 6) return p + (q - p) * 6 * t;
|
|
312
|
+
if (t < 1 / 2) return q;
|
|
313
|
+
if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
|
|
314
|
+
return p;
|
|
315
|
+
}
|
|
316
|
+
let r, g, b;
|
|
317
|
+
if (s === 0) {
|
|
318
|
+
r = g = b = l;
|
|
256
319
|
} else {
|
|
257
|
-
|
|
320
|
+
const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
|
|
321
|
+
const p = 2 * l - q;
|
|
322
|
+
r = hue2rgb(p, q, h + 1 / 3);
|
|
323
|
+
g = hue2rgb(p, q, h);
|
|
324
|
+
b = hue2rgb(p, q, h - 1 / 3);
|
|
258
325
|
}
|
|
259
|
-
return
|
|
260
|
-
}
|
|
326
|
+
return new Color(Math.round(r * 255), Math.round(g * 255), Math.round(b * 255), a);
|
|
327
|
+
}
|
|
328
|
+
static fromName(str) {
|
|
329
|
+
const rgba = ColorName[str];
|
|
330
|
+
return this.fromRgba(rgba);
|
|
331
|
+
}
|
|
261
332
|
/**
|
|
262
|
-
*
|
|
333
|
+
* 从字符串中创建颜色对象
|
|
263
334
|
*
|
|
264
|
-
* @param
|
|
265
|
-
* @
|
|
266
|
-
* @
|
|
335
|
+
* @param str 字符串类型的颜色值,支持rgba、hex、hsl格式
|
|
336
|
+
* @returns 返回创建的颜色对象
|
|
337
|
+
* @throws 当颜色值无效时,抛出错误
|
|
267
338
|
*/
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
339
|
+
static from(str) {
|
|
340
|
+
if (this.isRgb(str)) {
|
|
341
|
+
return this.fromRgba(str);
|
|
342
|
+
} else if (this.isHex(str)) {
|
|
343
|
+
return this.fromHex(str);
|
|
344
|
+
} else if (this.isHsl(str)) {
|
|
345
|
+
return this.fromHsl(str);
|
|
346
|
+
} else if (Object.values(ColorName).map((value) => value.toString()).includes(str)) {
|
|
347
|
+
return this.fromName(str);
|
|
348
|
+
} else {
|
|
349
|
+
throw new Error("Invalid color value");
|
|
275
350
|
}
|
|
276
|
-
|
|
277
|
-
},
|
|
351
|
+
}
|
|
278
352
|
/**
|
|
279
|
-
*
|
|
353
|
+
* 将RGB颜色值转换为十六进制颜色值
|
|
280
354
|
*
|
|
281
|
-
* @param
|
|
282
|
-
* @param
|
|
283
|
-
* @param
|
|
284
|
-
* @param
|
|
285
|
-
* @returns
|
|
355
|
+
* @param r 红色分量值,取值范围0-255
|
|
356
|
+
* @param g 绿色分量值,取值范围0-255
|
|
357
|
+
* @param b 蓝色分量值,取值范围0-255
|
|
358
|
+
* @param a 可选参数,透明度分量值,取值范围0-1
|
|
359
|
+
* @returns 十六进制颜色值,格式为#RRGGBB或#RRGGBBAA
|
|
286
360
|
*/
|
|
287
|
-
|
|
361
|
+
static rgb2hex(r, g, b, a) {
|
|
362
|
+
var hex = "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1);
|
|
363
|
+
if (a !== void 0) {
|
|
364
|
+
const alpha = Math.round(a * 255).toString(16).padStart(2, "0");
|
|
365
|
+
return hex + alpha;
|
|
366
|
+
}
|
|
367
|
+
return hex;
|
|
368
|
+
}
|
|
369
|
+
static isHex(a) {
|
|
370
|
+
return /(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)/i.test(a);
|
|
371
|
+
}
|
|
372
|
+
static isRgb(a) {
|
|
373
|
+
return /^rgba?\s*\(\s*\d+\s*,\s*\d+\s*,\s*\d+\s*(,\s*[\d.]+)?\s*\)$/.test(a);
|
|
374
|
+
}
|
|
375
|
+
static isHsl(a) {
|
|
376
|
+
return /^(hsl|hsla)\(\d+,\s*[\d.]+%,\s*[\d.]+%(,\s*[\d.]+)?\)$/.test(a);
|
|
377
|
+
}
|
|
378
|
+
static isColor(a) {
|
|
379
|
+
return this.isHex(a) || this.isRgb(a) || this.isHsl(a);
|
|
380
|
+
}
|
|
381
|
+
static random() {
|
|
382
|
+
let r = Math.floor(Math.random() * 256);
|
|
383
|
+
let g = Math.floor(Math.random() * 256);
|
|
384
|
+
let b = Math.floor(Math.random() * 256);
|
|
385
|
+
let a = Math.random();
|
|
386
|
+
return new Color(r, g, b, a);
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
class CanvasDrawer {
|
|
390
|
+
constructor(el) {
|
|
391
|
+
__publicField(this, "context", null);
|
|
392
|
+
if (typeof el === "string") {
|
|
393
|
+
el = document.querySelector("#" + el);
|
|
394
|
+
if (!el) {
|
|
395
|
+
throw new Error("Element not found");
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
if (el instanceof HTMLElement) {
|
|
399
|
+
const canvas = el;
|
|
400
|
+
if (canvas.getContext) {
|
|
401
|
+
this.context = canvas.getContext("2d");
|
|
402
|
+
} else {
|
|
403
|
+
throw new Error("getContext is not available on this element");
|
|
404
|
+
}
|
|
405
|
+
} else {
|
|
406
|
+
throw new Error("Element is not an HTMLElement");
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
/**
|
|
410
|
+
* 绘制线条
|
|
411
|
+
*
|
|
412
|
+
* @param start 起始坐标点
|
|
413
|
+
* @param end 终止坐标点
|
|
414
|
+
* @param options 绘制选项,包括线条宽度和颜色
|
|
415
|
+
* @throws 当画布上下文不存在时抛出错误
|
|
416
|
+
*/
|
|
417
|
+
drawLine({ x: startX, y: startY }, { x: endX, y: endY }, options = {}) {
|
|
418
|
+
if (!this.context) {
|
|
419
|
+
throw new Error("Canvas context is null or undefined");
|
|
420
|
+
}
|
|
421
|
+
this.context.beginPath();
|
|
422
|
+
const width = options.width || 1;
|
|
423
|
+
const color = options.color || "#000";
|
|
424
|
+
this.context.lineWidth = width;
|
|
425
|
+
this.context.strokeStyle = color;
|
|
426
|
+
this.context.moveTo(startX, startY);
|
|
427
|
+
this.context.lineTo(endX, endY);
|
|
428
|
+
this.context.stroke();
|
|
429
|
+
}
|
|
430
|
+
/**
|
|
431
|
+
* 绘制圆弧
|
|
432
|
+
*
|
|
433
|
+
* @param x 圆心x坐标
|
|
434
|
+
* @param y 圆心y坐标
|
|
435
|
+
* @param radius 半径
|
|
436
|
+
* @param startAngle 起始角度(度)
|
|
437
|
+
* @param endAngle 结束角度(度)
|
|
438
|
+
* @param anticlockwise 是否逆时针绘制
|
|
439
|
+
* @param isFill 是否填充
|
|
440
|
+
* @param bgColor 背景颜色
|
|
441
|
+
* @throws 当Canvas context为null或undefined时抛出错误
|
|
442
|
+
*/
|
|
443
|
+
drawArc({ x, y }, radius, startAngle, endAngle, anticlockwise, isFill, bgColor) {
|
|
444
|
+
if (!this.context) {
|
|
445
|
+
throw new Error("Canvas context is null or undefined");
|
|
446
|
+
}
|
|
447
|
+
if (isFill) {
|
|
448
|
+
this.context.fillStyle = bgColor;
|
|
449
|
+
this.context.beginPath();
|
|
450
|
+
this.context.arc(x, y, radius, MathUtil.deg2Rad(startAngle), MathUtil.deg2Rad(endAngle), anticlockwise);
|
|
451
|
+
this.context.fill();
|
|
452
|
+
} else {
|
|
453
|
+
this.context.strokeStyle = bgColor;
|
|
454
|
+
this.context.beginPath();
|
|
455
|
+
this.context.arc(x, y, radius, MathUtil.deg2Rad(startAngle), MathUtil.deg2Rad(endAngle), anticlockwise);
|
|
456
|
+
this.context.stroke();
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
static createCanvas(width = 1, height = 1) {
|
|
460
|
+
const canvas = document.createElement("canvas");
|
|
461
|
+
if (width) {
|
|
462
|
+
canvas.width = width;
|
|
463
|
+
}
|
|
464
|
+
if (height) {
|
|
465
|
+
canvas.height = height;
|
|
466
|
+
}
|
|
467
|
+
return canvas;
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
class EventDispatcher {
|
|
471
|
+
constructor() {
|
|
472
|
+
__publicField(this, "_listeners");
|
|
473
|
+
__publicField(this, "_mutex", {});
|
|
474
|
+
__publicField(this, "_context");
|
|
475
|
+
}
|
|
476
|
+
addEventListener(type, listener, context, mutexStatus) {
|
|
477
|
+
if (this._listeners === void 0) this._listeners = {};
|
|
478
|
+
this._context = context;
|
|
479
|
+
const mutex = this._mutex;
|
|
480
|
+
const listeners = this._listeners;
|
|
481
|
+
if (listeners[type] === void 0) {
|
|
482
|
+
listeners[type] = [];
|
|
483
|
+
}
|
|
484
|
+
if (listeners[type].indexOf(listener) === -1) {
|
|
485
|
+
if (mutexStatus) {
|
|
486
|
+
mutex[type] = listener;
|
|
487
|
+
}
|
|
488
|
+
listeners[type].push(listener);
|
|
489
|
+
}
|
|
490
|
+
return this;
|
|
491
|
+
}
|
|
492
|
+
hasEventListener(type, listener) {
|
|
493
|
+
if (this._listeners === null || this._listeners === void 0) return false;
|
|
494
|
+
const listeners = this._listeners;
|
|
495
|
+
return listeners[type] !== void 0 && listeners[type].indexOf(listener) !== -1;
|
|
496
|
+
}
|
|
497
|
+
removeEventListener(type, listener) {
|
|
498
|
+
if (this._listeners === void 0) return;
|
|
499
|
+
const listeners = this._listeners;
|
|
500
|
+
const listenerArray = listeners[type];
|
|
501
|
+
if (this._mutex[type] === listener) {
|
|
502
|
+
this._mutex[type] = null;
|
|
503
|
+
}
|
|
504
|
+
if (listenerArray !== void 0) {
|
|
505
|
+
const index = listenerArray.map((d) => d.toString()).indexOf(listener.toString());
|
|
506
|
+
if (index !== -1) {
|
|
507
|
+
listenerArray.splice(index, 1);
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
dispatchEvent(event) {
|
|
512
|
+
if (this._listeners === void 0) return;
|
|
513
|
+
const listeners = this._listeners;
|
|
514
|
+
const listenerArray = listeners[event.type];
|
|
515
|
+
if (listenerArray !== void 0) {
|
|
516
|
+
event.target = this;
|
|
517
|
+
const array = listenerArray.slice(0);
|
|
518
|
+
if (this._mutex[event.type] !== void 0) {
|
|
519
|
+
const find = array.find((item) => item === this._mutex[event.type]);
|
|
520
|
+
if (find) {
|
|
521
|
+
find.call(this._context || this, event);
|
|
522
|
+
return;
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
for (let i = 0, l = array.length; i < l; i++) {
|
|
526
|
+
const item = array[i];
|
|
527
|
+
if (typeof item === "function") {
|
|
528
|
+
item.call(this._context || this, event);
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
removeAllListener() {
|
|
534
|
+
this._mutex = {};
|
|
535
|
+
for (const key in this._listeners) {
|
|
536
|
+
this._listeners[key] = [];
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
const Util = {
|
|
541
|
+
/**
|
|
542
|
+
* 获取数据类型
|
|
543
|
+
*
|
|
544
|
+
* @param data 待判断的数据
|
|
545
|
+
* @returns 返回数据类型字符串
|
|
546
|
+
*/
|
|
547
|
+
getDataType(data) {
|
|
548
|
+
return Object.prototype.toString.call(data).slice(8, -1);
|
|
549
|
+
},
|
|
550
|
+
asArray(obj) {
|
|
551
|
+
return this.isEmpty(obj) ? [] : Array.isArray(obj) ? obj : [obj];
|
|
552
|
+
},
|
|
553
|
+
asNumber(a) {
|
|
554
|
+
return Number.isNaN(Number(a)) ? 0 : Number(a);
|
|
555
|
+
},
|
|
556
|
+
/**
|
|
557
|
+
* 将值转换为字符串
|
|
558
|
+
*
|
|
559
|
+
* @param value 要转换的值
|
|
560
|
+
* @returns 转换后的字符串,如果值为空,则返回空字符串
|
|
561
|
+
*/
|
|
562
|
+
asString(value) {
|
|
563
|
+
if (this.isEmpty(value)) {
|
|
564
|
+
return "";
|
|
565
|
+
} else {
|
|
566
|
+
switch (this.getDataType(value)) {
|
|
567
|
+
case "Object":
|
|
568
|
+
case "Array":
|
|
569
|
+
return JSON.stringify(value);
|
|
570
|
+
default:
|
|
571
|
+
return value;
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
},
|
|
575
|
+
/**
|
|
576
|
+
* 判断传入的值是否为空
|
|
577
|
+
*
|
|
578
|
+
* @param value 待判断的值
|
|
579
|
+
* @returns 返回布尔值,表示是否为空
|
|
580
|
+
*/
|
|
581
|
+
isEmpty(value) {
|
|
582
|
+
if (value == null) {
|
|
583
|
+
return true;
|
|
584
|
+
}
|
|
585
|
+
const type = this.getDataType(value);
|
|
586
|
+
switch (type) {
|
|
587
|
+
case "String":
|
|
588
|
+
return value.trim() === "";
|
|
589
|
+
case "Array":
|
|
590
|
+
return !value.length;
|
|
591
|
+
case "Object":
|
|
592
|
+
return !Object.keys(value).length;
|
|
593
|
+
case "Boolean":
|
|
594
|
+
return !value;
|
|
595
|
+
default:
|
|
596
|
+
return false;
|
|
597
|
+
}
|
|
598
|
+
},
|
|
599
|
+
/**
|
|
600
|
+
* 将JSON对象转换为FormData对象
|
|
601
|
+
*
|
|
602
|
+
* @param json 待转换的JSON对象,其属性值为字符串或Blob类型
|
|
603
|
+
* @returns 转换后的FormData对象
|
|
604
|
+
*/
|
|
605
|
+
json2form(json) {
|
|
606
|
+
const formData = new FormData();
|
|
607
|
+
if (this.isEmpty(json)) return formData;
|
|
608
|
+
Object.keys(json).forEach((key) => {
|
|
609
|
+
formData.append(key, json[key] instanceof Object ? JSON.stringify(json[key]) : json[key]);
|
|
610
|
+
});
|
|
611
|
+
return formData;
|
|
612
|
+
},
|
|
613
|
+
/**
|
|
614
|
+
* 生成GUID
|
|
615
|
+
*
|
|
616
|
+
* @returns 返回一个由8个16进制数组成的GUID字符串
|
|
617
|
+
*/
|
|
618
|
+
guid() {
|
|
619
|
+
const S4 = function() {
|
|
620
|
+
return ((1 + Math.random()) * 65536 | 0).toString(16).substring(1);
|
|
621
|
+
};
|
|
622
|
+
return S4() + S4() + S4() + S4() + S4() + S4() + S4() + S4();
|
|
623
|
+
},
|
|
624
|
+
/**
|
|
625
|
+
* 将参数进行解码并返回解码后的字符串
|
|
626
|
+
*
|
|
627
|
+
* @param args 参数
|
|
628
|
+
* @returns 解码后的字符串
|
|
629
|
+
*/
|
|
630
|
+
decodeDict(...args) {
|
|
631
|
+
let res = "";
|
|
632
|
+
if (args.length > 1) {
|
|
633
|
+
const items = args.slice(1, args.length % 2 === 0 ? args.length - 1 : args.length);
|
|
634
|
+
for (let i = 0; i < items.length; i = i + 2) {
|
|
635
|
+
const item = items[i];
|
|
636
|
+
if (args[0] === item) {
|
|
637
|
+
res = items[i + 1];
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
if (!res && args.length % 2 === 0) {
|
|
641
|
+
res = args[args.length - 1];
|
|
642
|
+
}
|
|
643
|
+
} else {
|
|
644
|
+
res = args[0];
|
|
645
|
+
}
|
|
646
|
+
return res;
|
|
647
|
+
},
|
|
648
|
+
/**
|
|
649
|
+
* 将一个或多个对象的所有可枚举属性复制到目标对象。
|
|
650
|
+
*
|
|
651
|
+
* @param dest 目标对象,用于接收复制的属性。
|
|
652
|
+
* @param args 一个或多个源对象,用于提供要复制的属性。
|
|
653
|
+
* @returns 返回目标对象,包含所有复制的属性。
|
|
654
|
+
*/
|
|
655
|
+
extend(dest, ...args) {
|
|
656
|
+
let i, j, len, src;
|
|
657
|
+
for (j = 0, len = args.length; j < len; j++) {
|
|
658
|
+
src = args[j];
|
|
659
|
+
for (i in src) {
|
|
660
|
+
dest[i] = src[i];
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
return dest;
|
|
664
|
+
},
|
|
665
|
+
/**
|
|
666
|
+
* 将扁平化数组转换为树形结构数组
|
|
667
|
+
*
|
|
668
|
+
* @param data 扁平化数组
|
|
669
|
+
* @param idPropertyName 数据中标识id的字段名,默认为'id'
|
|
670
|
+
* @param parentIdPropertyName 数据中标识父节点id的字段名,默认为'parentId'
|
|
671
|
+
* @param childrenPropertyName 树形结构中标识子节点的字段名,默认为'children'
|
|
672
|
+
* @returns 转换后的树形结构数组
|
|
673
|
+
*/
|
|
674
|
+
convertToTree2(data, idPropertyName = "id", parentIdPropertyName = "parentId", childrenPropertyName = "children") {
|
|
288
675
|
const result = [];
|
|
289
676
|
function buildChildren(item) {
|
|
290
677
|
const children = data.filter((item2) => item2[parentIdPropertyName] === item[idPropertyName]).map((child) => {
|
|
@@ -490,10 +877,143 @@ const ObjectUtil = {
|
|
|
490
877
|
},
|
|
491
878
|
parse(str) {
|
|
492
879
|
if (typeof str === "string" && str.startsWith("{") && str.endsWith("}")) return JSON.parse(str);
|
|
493
|
-
if (
|
|
494
|
-
if (
|
|
880
|
+
if (Util.isEmpty(str)) return {};
|
|
881
|
+
if (Util.isObject(str)) return str;
|
|
882
|
+
}
|
|
883
|
+
};
|
|
884
|
+
class HashMap extends Map {
|
|
885
|
+
isEmpty() {
|
|
886
|
+
return this.size === 0;
|
|
887
|
+
}
|
|
888
|
+
_values() {
|
|
889
|
+
return Array.from(this.values());
|
|
890
|
+
}
|
|
891
|
+
_keys() {
|
|
892
|
+
return Array.from(this.keys());
|
|
893
|
+
}
|
|
894
|
+
_entries() {
|
|
895
|
+
return Array.from(this.entries());
|
|
896
|
+
}
|
|
897
|
+
/**
|
|
898
|
+
* 从键值对数组创建一个HashMap对象
|
|
899
|
+
*
|
|
900
|
+
* @param array 键值对数组,默认为空数组
|
|
901
|
+
* @returns 返回一个新的HashMap对象
|
|
902
|
+
*/
|
|
903
|
+
static fromEntries(array = []) {
|
|
904
|
+
const hashMap = new HashMap();
|
|
905
|
+
array.forEach((element) => {
|
|
906
|
+
if (Array.isArray(element) && element.length === 2) {
|
|
907
|
+
hashMap.set(element[0], element[1]);
|
|
908
|
+
}
|
|
909
|
+
});
|
|
910
|
+
return hashMap;
|
|
911
|
+
}
|
|
912
|
+
/**
|
|
913
|
+
* 从JSON字符串创建HashMap实例
|
|
914
|
+
*
|
|
915
|
+
* @param str JSON字符串
|
|
916
|
+
* @returns HashMap实例
|
|
917
|
+
*/
|
|
918
|
+
static fromJson(str) {
|
|
919
|
+
const json = ObjectUtil.parse(str);
|
|
920
|
+
return new HashMap(Object.entries(json));
|
|
921
|
+
}
|
|
922
|
+
}
|
|
923
|
+
class WebSocketClient extends EventDispatcher {
|
|
924
|
+
constructor(url = "ws://127.0.0.1:10088") {
|
|
925
|
+
super();
|
|
926
|
+
__publicField(this, "maxCheckTimes", 10);
|
|
927
|
+
__publicField(this, "url");
|
|
928
|
+
__publicField(this, "checkTimes", 0);
|
|
929
|
+
__publicField(this, "connectStatus", false);
|
|
930
|
+
__publicField(this, "client", null);
|
|
931
|
+
this.maxCheckTimes = 10;
|
|
932
|
+
this.url = url;
|
|
933
|
+
this.checkTimes = 0;
|
|
934
|
+
this.connect();
|
|
935
|
+
this.connCheckStatus(this.maxCheckTimes);
|
|
936
|
+
}
|
|
937
|
+
connect() {
|
|
938
|
+
this.disconnect();
|
|
939
|
+
if (this.url) {
|
|
940
|
+
try {
|
|
941
|
+
console.info("创建ws连接>>>" + this.url);
|
|
942
|
+
this.client = new WebSocket(this.url);
|
|
943
|
+
if (this.client) {
|
|
944
|
+
const self = this;
|
|
945
|
+
this.client.onopen = function(message) {
|
|
946
|
+
self.dispatchEvent({
|
|
947
|
+
type: EventType.WEB_SOCKET_CONNECT,
|
|
948
|
+
message
|
|
949
|
+
});
|
|
950
|
+
};
|
|
951
|
+
this.client.onmessage = function(message) {
|
|
952
|
+
self.connectStatus = true;
|
|
953
|
+
self.dispatchEvent({
|
|
954
|
+
type: EventType.WEB_SOCKET_MESSAGE,
|
|
955
|
+
message
|
|
956
|
+
});
|
|
957
|
+
};
|
|
958
|
+
this.client.onclose = function(message) {
|
|
959
|
+
self.dispatchEvent({
|
|
960
|
+
type: EventType.WEB_SOCKET_CLOSE,
|
|
961
|
+
message
|
|
962
|
+
});
|
|
963
|
+
};
|
|
964
|
+
if (this.checkTimes === this.maxCheckTimes) {
|
|
965
|
+
this.client.onerror = function(message) {
|
|
966
|
+
self.dispatchEvent({
|
|
967
|
+
type: EventType.WEB_SOCKET_ERROR,
|
|
968
|
+
message
|
|
969
|
+
});
|
|
970
|
+
};
|
|
971
|
+
}
|
|
972
|
+
}
|
|
973
|
+
} catch (ex) {
|
|
974
|
+
console.error("创建ws连接失败" + this.url + ":" + ex);
|
|
975
|
+
}
|
|
976
|
+
}
|
|
977
|
+
}
|
|
978
|
+
disconnect() {
|
|
979
|
+
if (this.client) {
|
|
980
|
+
try {
|
|
981
|
+
console.log("ws断开连接" + this.url);
|
|
982
|
+
this.client.close();
|
|
983
|
+
this.client = null;
|
|
984
|
+
} catch (ex) {
|
|
985
|
+
this.client = null;
|
|
986
|
+
}
|
|
987
|
+
}
|
|
988
|
+
}
|
|
989
|
+
connCheckStatus(times) {
|
|
990
|
+
if (this.checkTimes > times) return;
|
|
991
|
+
setTimeout(() => {
|
|
992
|
+
this.checkTimes++;
|
|
993
|
+
if (this.client && this.client.readyState !== 0 && this.client.readyState !== 1) {
|
|
994
|
+
this.connect();
|
|
995
|
+
}
|
|
996
|
+
this.connCheckStatus(times);
|
|
997
|
+
}, 2e3);
|
|
998
|
+
}
|
|
999
|
+
send(message) {
|
|
1000
|
+
if (this.client && this.client.readyState === 1) {
|
|
1001
|
+
this.client.send(message);
|
|
1002
|
+
return true;
|
|
1003
|
+
}
|
|
1004
|
+
console.error(this.url + "消息发送失败:" + message);
|
|
1005
|
+
return this;
|
|
495
1006
|
}
|
|
496
|
-
|
|
1007
|
+
heartbeat() {
|
|
1008
|
+
setTimeout(() => {
|
|
1009
|
+
if (this.client && this.client.readyState === 1) {
|
|
1010
|
+
this.send("HeartBeat");
|
|
1011
|
+
}
|
|
1012
|
+
console.log("HeartBeat," + this.url);
|
|
1013
|
+
setTimeout(this.heartbeat, 3e4);
|
|
1014
|
+
}, 1e3);
|
|
1015
|
+
}
|
|
1016
|
+
}
|
|
497
1017
|
const ImageUtil = {
|
|
498
1018
|
emptyImageUrl: "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7",
|
|
499
1019
|
/**
|
|
@@ -606,7 +1126,7 @@ const AjaxUtil = {
|
|
|
606
1126
|
* @param callback - callback function when completed
|
|
607
1127
|
*/
|
|
608
1128
|
jsonp(url, callback) {
|
|
609
|
-
const name = "_jsonp_" +
|
|
1129
|
+
const name = "_jsonp_" + Util.guid();
|
|
610
1130
|
const head = document.getElementsByTagName("head")[0];
|
|
611
1131
|
if (url.includes("?")) {
|
|
612
1132
|
url += "&callback=" + name;
|
|
@@ -645,7 +1165,7 @@ const AjaxUtil = {
|
|
|
645
1165
|
* );
|
|
646
1166
|
*/
|
|
647
1167
|
get(url, options = {}, cb) {
|
|
648
|
-
if (
|
|
1168
|
+
if (Util.isFunction(options)) {
|
|
649
1169
|
const t = cb;
|
|
650
1170
|
cb = options;
|
|
651
1171
|
options = t;
|
|
@@ -777,7 +1297,7 @@ const AjaxUtil = {
|
|
|
777
1297
|
* );
|
|
778
1298
|
*/
|
|
779
1299
|
getArrayBuffer(url, options, cb) {
|
|
780
|
-
if (
|
|
1300
|
+
if (Util.isFunction(options)) {
|
|
781
1301
|
const t = cb;
|
|
782
1302
|
cb = options;
|
|
783
1303
|
options = t;
|
|
@@ -830,7 +1350,7 @@ const AjaxUtil = {
|
|
|
830
1350
|
* );
|
|
831
1351
|
*/
|
|
832
1352
|
getJSON(url, options, cb) {
|
|
833
|
-
if (
|
|
1353
|
+
if (Util.isFunction(options)) {
|
|
834
1354
|
const t = cb;
|
|
835
1355
|
cb = options;
|
|
836
1356
|
options = t;
|
|
@@ -847,48 +1367,6 @@ const AjaxUtil = {
|
|
|
847
1367
|
return this.get(url, options, callback);
|
|
848
1368
|
}
|
|
849
1369
|
};
|
|
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
1370
|
class GeoUtil {
|
|
893
1371
|
/**
|
|
894
1372
|
* 判断给定的经纬度是否合法
|
|
@@ -898,7 +1376,7 @@ class GeoUtil {
|
|
|
898
1376
|
* @returns 如果经纬度合法,返回true;否则返回false
|
|
899
1377
|
*/
|
|
900
1378
|
static isLnglat(lng, lat) {
|
|
901
|
-
return
|
|
1379
|
+
return Util.isNumber(lng) && Util.isNumber(lat) && !!(+lat > -90 && +lat < 90 && +lng > -180 && +lng < 180);
|
|
902
1380
|
}
|
|
903
1381
|
/**
|
|
904
1382
|
* 计算两哥平面坐标点间的距离
|
|
@@ -1090,15 +1568,15 @@ class GeoUtil {
|
|
|
1090
1568
|
* @returns 返回计算后的新经纬度点,类型为{lat: number, lng: number}
|
|
1091
1569
|
*/
|
|
1092
1570
|
static calcPointByBearAndDis(latlng, angle, distance) {
|
|
1093
|
-
const sLat =
|
|
1094
|
-
const sLng =
|
|
1571
|
+
const sLat = MathUtil.deg2Rad(latlng.lat * 1);
|
|
1572
|
+
const sLng = MathUtil.deg2Rad(latlng.lng * 1);
|
|
1095
1573
|
const d = distance / this.R;
|
|
1096
|
-
angle =
|
|
1574
|
+
angle = MathUtil.deg2Rad(angle);
|
|
1097
1575
|
const lat = Math.asin(Math.sin(sLat) * Math.cos(d) + Math.cos(sLat) * Math.sin(d) * Math.cos(angle));
|
|
1098
1576
|
const lon = sLng + Math.atan2(Math.sin(angle) * Math.sin(d) * Math.cos(sLat), Math.cos(d) - Math.sin(sLat) * Math.sin(lat));
|
|
1099
1577
|
return {
|
|
1100
|
-
lat:
|
|
1101
|
-
lng:
|
|
1578
|
+
lat: MathUtil.rad2Deg(lat),
|
|
1579
|
+
lng: MathUtil.rad2Deg(lon)
|
|
1102
1580
|
};
|
|
1103
1581
|
}
|
|
1104
1582
|
/**
|
|
@@ -1247,26 +1725,6 @@ const StringUtil = {
|
|
|
1247
1725
|
return str;
|
|
1248
1726
|
}
|
|
1249
1727
|
},
|
|
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
1728
|
/**
|
|
1271
1729
|
* 计算字符串的字节长度
|
|
1272
1730
|
*
|
|
@@ -1589,42 +2047,42 @@ const GeoJsonUtil = {
|
|
|
1589
2047
|
const AssertUtil = {
|
|
1590
2048
|
assertEmpty(...arg) {
|
|
1591
2049
|
arg.forEach((a) => {
|
|
1592
|
-
if (
|
|
2050
|
+
if (Util.isEmpty(a)) {
|
|
1593
2051
|
throw Error(ErrorType.PARAMETER_ERROR_LACK + " -> " + a);
|
|
1594
2052
|
}
|
|
1595
2053
|
});
|
|
1596
2054
|
},
|
|
1597
2055
|
assertInteger(...arg) {
|
|
1598
2056
|
arg.forEach((a) => {
|
|
1599
|
-
if (!
|
|
2057
|
+
if (!Util.isInteger(a)) {
|
|
1600
2058
|
throw Error(ErrorType.PARAMETER_ERROR_INTEGER + " -> " + a);
|
|
1601
2059
|
}
|
|
1602
2060
|
});
|
|
1603
2061
|
},
|
|
1604
2062
|
assertNumber(...arg) {
|
|
1605
2063
|
arg.forEach((a) => {
|
|
1606
|
-
if (!
|
|
2064
|
+
if (!Util.isNumber(a)) {
|
|
1607
2065
|
throw Error(ErrorType.PARAMETER_ERROR_NUMBER + " -> " + a);
|
|
1608
2066
|
}
|
|
1609
2067
|
});
|
|
1610
2068
|
},
|
|
1611
2069
|
assertArray(...arg) {
|
|
1612
2070
|
arg.forEach((a) => {
|
|
1613
|
-
if (!
|
|
2071
|
+
if (!Util.isArray(a)) {
|
|
1614
2072
|
throw Error(ErrorType.PARAMETER_ERROR_ARRAY + " -> " + a);
|
|
1615
2073
|
}
|
|
1616
2074
|
});
|
|
1617
2075
|
},
|
|
1618
2076
|
assertFunction(...arg) {
|
|
1619
2077
|
arg.forEach((a) => {
|
|
1620
|
-
if (!
|
|
2078
|
+
if (!Util.isFunction(a)) {
|
|
1621
2079
|
throw Error(ErrorType.PARAMETER_ERROR_FUNCTION + " -> " + a);
|
|
1622
2080
|
}
|
|
1623
2081
|
});
|
|
1624
2082
|
},
|
|
1625
2083
|
assertObject(...arg) {
|
|
1626
2084
|
arg.forEach((a) => {
|
|
1627
|
-
if (!
|
|
2085
|
+
if (!Util.isObject(a)) {
|
|
1628
2086
|
throw Error(ErrorType.PARAMETER_ERROR_OBJECT + " -> " + a);
|
|
1629
2087
|
}
|
|
1630
2088
|
});
|
|
@@ -2328,7 +2786,7 @@ class CoordsUtil {
|
|
|
2328
2786
|
let p, pp;
|
|
2329
2787
|
for (let i = 0, len = arr.length; i < len; i++) {
|
|
2330
2788
|
p = arr[i];
|
|
2331
|
-
if (
|
|
2789
|
+
if (Util.isNil(p)) {
|
|
2332
2790
|
result.push(null);
|
|
2333
2791
|
continue;
|
|
2334
2792
|
}
|
|
@@ -2518,940 +2976,486 @@ function trim(str) {
|
|
|
2518
2976
|
return str.trim ? str.trim() : str.replace(/^\s+|\s+$/g, "");
|
|
2519
2977
|
}
|
|
2520
2978
|
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 = {
|
|
2684
|
-
/**
|
|
2685
|
-
* 将Base64编码的字符串转换为Blob对象
|
|
2686
|
-
*
|
|
2687
|
-
* @param data Base64编码的字符串
|
|
2688
|
-
* @returns 转换后的Blob对象
|
|
2689
|
-
*/
|
|
2690
|
-
convertBase64ToBlob(data) {
|
|
2691
|
-
const mimeString = data.split(",")[0].split(":")[1].split(";")[0];
|
|
2692
|
-
const byteCharacters = atob(data.split(",")[1]);
|
|
2693
|
-
const byteNumbers = new Array(byteCharacters.length);
|
|
2694
|
-
for (let i = 0; i < byteCharacters.length; i++) {
|
|
2695
|
-
byteNumbers[i] = byteCharacters.charCodeAt(i);
|
|
2696
|
-
}
|
|
2697
|
-
const byteArray = new Uint8Array(byteNumbers);
|
|
2698
|
-
const blob = new Blob([byteArray], { type: mimeString });
|
|
2699
|
-
return blob;
|
|
2700
|
-
},
|
|
2701
|
-
/**
|
|
2702
|
-
* 将图片的URL转换为Base64编码
|
|
2703
|
-
*
|
|
2704
|
-
* @param url 图片的URL地址
|
|
2705
|
-
* @param width 图片的宽度,默认为图片原始宽度
|
|
2706
|
-
* @param height 图片的高度,默认为图片原始高度
|
|
2707
|
-
* @returns 返回Promise对象,解析后得到包含Base64编码数据的对象
|
|
2708
|
-
*/
|
|
2979
|
+
return trim(str).split(/\s+/);
|
|
2980
|
+
}
|
|
2981
|
+
const DomUtil = {
|
|
2709
2982
|
/**
|
|
2710
|
-
*
|
|
2983
|
+
* 获取元素的样式值
|
|
2711
2984
|
*
|
|
2712
|
-
* @param
|
|
2713
|
-
* @param
|
|
2714
|
-
* @returns
|
|
2985
|
+
* @param el 元素对象
|
|
2986
|
+
* @param style 样式属性名称
|
|
2987
|
+
* @returns 元素的样式值,如果获取不到则返回 null
|
|
2715
2988
|
*/
|
|
2716
|
-
|
|
2717
|
-
|
|
2718
|
-
|
|
2719
|
-
|
|
2720
|
-
|
|
2721
|
-
|
|
2722
|
-
|
|
2723
|
-
u8arr[i] = bstr.charCodeAt(i);
|
|
2989
|
+
getStyle(el, style) {
|
|
2990
|
+
var _a2;
|
|
2991
|
+
let value = el.style[style];
|
|
2992
|
+
if (!value || value === "auto") {
|
|
2993
|
+
const css = (_a2 = document.defaultView) == null ? void 0 : _a2.getComputedStyle(el, null);
|
|
2994
|
+
value = css ? css[style] : null;
|
|
2995
|
+
if (value === "auto") value = null;
|
|
2724
2996
|
}
|
|
2725
|
-
|
|
2726
|
-
return file;
|
|
2997
|
+
return value;
|
|
2727
2998
|
},
|
|
2728
2999
|
/**
|
|
2729
|
-
*
|
|
3000
|
+
* 创建一个HTML元素
|
|
2730
3001
|
*
|
|
2731
|
-
* @param
|
|
2732
|
-
* @param
|
|
3002
|
+
* @param tagName 元素标签名
|
|
3003
|
+
* @param className 元素类名
|
|
3004
|
+
* @param container 父容器,若传入,则新创建的元素会被添加到该容器中
|
|
3005
|
+
* @returns 返回新创建的HTML元素
|
|
2733
3006
|
*/
|
|
2734
|
-
|
|
2735
|
-
|
|
2736
|
-
|
|
2737
|
-
|
|
2738
|
-
|
|
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 MessageUtil {
|
|
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
|
-
this.warned[message] = true;
|
|
3007
|
+
create(tagName, className, container) {
|
|
3008
|
+
const el = document.createElement(tagName);
|
|
3009
|
+
el.className = className || "";
|
|
3010
|
+
if (container) {
|
|
3011
|
+
container.appendChild(el);
|
|
2766
3012
|
}
|
|
2767
|
-
|
|
3013
|
+
return el;
|
|
3014
|
+
},
|
|
2768
3015
|
/**
|
|
2769
|
-
*
|
|
3016
|
+
* 从父节点中移除指定元素。
|
|
2770
3017
|
*
|
|
2771
|
-
* @param
|
|
2772
|
-
* @param message 消息内容
|
|
2773
|
-
* @param options 配置选项,可选参数,包括语言、音量、语速和音高
|
|
2774
|
-
* @returns 无返回值
|
|
3018
|
+
* @param el 要移除的元素对象,必须包含parentNode属性。
|
|
2775
3019
|
*/
|
|
2776
|
-
|
|
2777
|
-
|
|
2778
|
-
if (
|
|
2779
|
-
|
|
2780
|
-
this.speechSynthesisUtterance.text = typename + message;
|
|
2781
|
-
this.speechSynthesisUtterance.lang = options.lang || "zh-CN";
|
|
2782
|
-
this.speechSynthesisUtterance.volume = options.volume || 1;
|
|
2783
|
-
this.speechSynthesisUtterance.rate = options.rate || 1;
|
|
2784
|
-
this.speechSynthesisUtterance.pitch = options.pitch || 1;
|
|
2785
|
-
this.speechSynthesis.speak(this.speechSynthesisUtterance);
|
|
2786
|
-
}
|
|
2787
|
-
static stop(e) {
|
|
2788
|
-
this.speechSynthesisUtterance.text = e;
|
|
2789
|
-
this.speechSynthesis.cancel();
|
|
2790
|
-
}
|
|
2791
|
-
static warning(message) {
|
|
2792
|
-
if (process.env.NODE_ENV === "development" && console !== void 0) {
|
|
2793
|
-
console.warn(`Warning: ${message}`);
|
|
2794
|
-
}
|
|
2795
|
-
this.msg("warning", message);
|
|
2796
|
-
}
|
|
2797
|
-
static warningOnce(message) {
|
|
2798
|
-
this._call(this.warning.bind(this), message);
|
|
2799
|
-
}
|
|
2800
|
-
static info(message) {
|
|
2801
|
-
if (process.env.NODE_ENV === "development" && console !== void 0) {
|
|
2802
|
-
console.info(`Info: ${message}`);
|
|
2803
|
-
}
|
|
2804
|
-
this.msg("info", message);
|
|
2805
|
-
}
|
|
2806
|
-
static infoOnce(message) {
|
|
2807
|
-
this._call(this.info.bind(this), message);
|
|
2808
|
-
}
|
|
2809
|
-
static error(message) {
|
|
2810
|
-
if (process.env.NODE_ENV === "development" && console !== void 0) {
|
|
2811
|
-
console.error(`Error: ${message}`);
|
|
2812
|
-
}
|
|
2813
|
-
this.msg("error", message);
|
|
2814
|
-
}
|
|
2815
|
-
static errorOnce(message) {
|
|
2816
|
-
this._call(this.error.bind(this), message);
|
|
2817
|
-
}
|
|
2818
|
-
static success(message) {
|
|
2819
|
-
if (process.env.NODE_ENV === "development" && console !== void 0) {
|
|
2820
|
-
console.log(`Success: ${message}`);
|
|
3020
|
+
remove(el) {
|
|
3021
|
+
const parent = el.parentNode;
|
|
3022
|
+
if (parent) {
|
|
3023
|
+
parent.removeChild(el);
|
|
2821
3024
|
}
|
|
2822
|
-
|
|
2823
|
-
}
|
|
2824
|
-
static successOnce(message) {
|
|
2825
|
-
this._call(this.success.bind(this), message);
|
|
2826
|
-
}
|
|
2827
|
-
}
|
|
2828
|
-
__publicField(MessageUtil, "warned", {});
|
|
2829
|
-
__publicField(MessageUtil, "isMute", !!Number(localStorage.getItem("mute")) || false);
|
|
2830
|
-
__publicField(MessageUtil, "speechSynthesis", window.speechSynthesis);
|
|
2831
|
-
__publicField(MessageUtil, "speechSynthesisUtterance", new SpeechSynthesisUtterance());
|
|
2832
|
-
const OptimizeUtil = {
|
|
3025
|
+
},
|
|
2833
3026
|
/**
|
|
2834
|
-
*
|
|
3027
|
+
* 清空给定元素的子节点
|
|
2835
3028
|
*
|
|
2836
|
-
* @param
|
|
2837
|
-
* @param wait 等待时间,单位毫秒。
|
|
2838
|
-
* @param immediate 是否立即执行函数,默认为true。
|
|
2839
|
-
* @returns 返回防抖后的函数。
|
|
3029
|
+
* @param el 要清空子节点的元素,包含firstChild和removeChild属性
|
|
2840
3030
|
*/
|
|
2841
|
-
|
|
2842
|
-
|
|
2843
|
-
|
|
2844
|
-
|
|
2845
|
-
let result;
|
|
2846
|
-
const later = () => {
|
|
2847
|
-
const last = Date.now() - timestamp;
|
|
2848
|
-
if (last < wait && last > 0) {
|
|
2849
|
-
timeout = setTimeout(later, wait - last);
|
|
2850
|
-
} else {
|
|
2851
|
-
timeout = null;
|
|
2852
|
-
if (!immediate) {
|
|
2853
|
-
result = func.apply(this, args);
|
|
2854
|
-
}
|
|
2855
|
-
}
|
|
2856
|
-
};
|
|
2857
|
-
return (...args2) => {
|
|
2858
|
-
timestamp = Date.now();
|
|
2859
|
-
const callNow = immediate && !timeout;
|
|
2860
|
-
if (!timeout) {
|
|
2861
|
-
timeout = setTimeout(later, wait);
|
|
2862
|
-
}
|
|
2863
|
-
if (callNow) {
|
|
2864
|
-
result = func.apply(this, args2);
|
|
2865
|
-
if (!timeout) {
|
|
2866
|
-
args2 = null;
|
|
2867
|
-
}
|
|
2868
|
-
}
|
|
2869
|
-
return result;
|
|
2870
|
-
};
|
|
3031
|
+
empty(el) {
|
|
3032
|
+
while (el.firstChild) {
|
|
3033
|
+
el.removeChild(el.firstChild);
|
|
3034
|
+
}
|
|
2871
3035
|
},
|
|
2872
3036
|
/**
|
|
2873
|
-
*
|
|
3037
|
+
* 将元素移到父节点的最前面
|
|
2874
3038
|
*
|
|
2875
|
-
* @param
|
|
2876
|
-
* @param wait 节流间隔,单位为毫秒
|
|
2877
|
-
* @param type 节流类型,1表示时间戳方式,2表示定时器方式
|
|
2878
|
-
* @returns 返回一个新的函数,该函数在节流控制下执行传入的函数
|
|
3039
|
+
* @param el 要移动的元素,需要包含 parentNode 属性
|
|
2879
3040
|
*/
|
|
2880
|
-
|
|
2881
|
-
|
|
2882
|
-
|
|
2883
|
-
|
|
2884
|
-
|
|
2885
|
-
const now = Date.now();
|
|
2886
|
-
if (now - previous >= wait) {
|
|
2887
|
-
func.apply(this, args);
|
|
2888
|
-
previous = now;
|
|
2889
|
-
}
|
|
2890
|
-
} else if (type === 2) {
|
|
2891
|
-
if (!timeout) {
|
|
2892
|
-
timeout = setTimeout(() => {
|
|
2893
|
-
timeout = null;
|
|
2894
|
-
func.apply(this, args);
|
|
2895
|
-
}, wait);
|
|
2896
|
-
}
|
|
2897
|
-
}
|
|
2898
|
-
};
|
|
3041
|
+
toFront(el) {
|
|
3042
|
+
const parent = el.parentNode;
|
|
3043
|
+
if (parent && parent.lastChild !== el) {
|
|
3044
|
+
parent.appendChild(el);
|
|
3045
|
+
}
|
|
2899
3046
|
},
|
|
2900
3047
|
/**
|
|
2901
|
-
*
|
|
3048
|
+
* 将元素移动到其父节点的最前面
|
|
2902
3049
|
*
|
|
2903
|
-
* @param
|
|
2904
|
-
* @returns 返回缓存后的函数
|
|
3050
|
+
* @param el 要移动的元素,需要包含parentNode属性
|
|
2905
3051
|
*/
|
|
2906
|
-
|
|
2907
|
-
const
|
|
2908
|
-
|
|
2909
|
-
|
|
2910
|
-
|
|
2911
|
-
return cache.get(argsString);
|
|
2912
|
-
} else {
|
|
2913
|
-
const result = fn.apply(this, args);
|
|
2914
|
-
cache.set(argsString, result);
|
|
2915
|
-
return result;
|
|
2916
|
-
}
|
|
2917
|
-
};
|
|
3052
|
+
toBack(el) {
|
|
3053
|
+
const parent = el.parentNode;
|
|
3054
|
+
if (parent && parent.firstChild !== el) {
|
|
3055
|
+
parent.insertBefore(el, parent.firstChild);
|
|
3056
|
+
}
|
|
2918
3057
|
},
|
|
2919
3058
|
/**
|
|
2920
|
-
*
|
|
3059
|
+
* 获取元素的类名
|
|
2921
3060
|
*
|
|
2922
|
-
* @param
|
|
2923
|
-
* @param
|
|
2924
|
-
* @param
|
|
2925
|
-
|
|
2926
|
-
|
|
2927
|
-
|
|
2928
|
-
|
|
2929
|
-
|
|
2930
|
-
|
|
2931
|
-
fun.call(this);
|
|
2932
|
-
setTimeout(this.recurve.bind(this, fun, frequency, duration), frequency);
|
|
2933
|
-
}
|
|
2934
|
-
}, frequency);
|
|
3061
|
+
* @param el 包含对应元素和类名的对象
|
|
3062
|
+
* @param el.correspondingElement 对应的元素
|
|
3063
|
+
* @param el.className 类名对象
|
|
3064
|
+
* @param el.className.baseVal 类名字符串
|
|
3065
|
+
* @returns 返回元素的类名字符串
|
|
3066
|
+
*/
|
|
3067
|
+
getClass(el) {
|
|
3068
|
+
const shadowElement = (el == null ? void 0 : el.host) || el;
|
|
3069
|
+
return shadowElement.className.toString();
|
|
2935
3070
|
},
|
|
2936
3071
|
/**
|
|
2937
|
-
*
|
|
3072
|
+
* 判断元素是否包含指定类名
|
|
2938
3073
|
*
|
|
2939
|
-
* @param
|
|
2940
|
-
* @
|
|
3074
|
+
* @param el 元素对象,包含classList属性,classList属性包含contains方法
|
|
3075
|
+
* @param name 要判断的类名
|
|
3076
|
+
* @returns 返回一个布尔值,表示元素是否包含指定类名
|
|
2941
3077
|
*/
|
|
2942
|
-
|
|
2943
|
-
|
|
2944
|
-
|
|
2945
|
-
|
|
2946
|
-
|
|
2947
|
-
|
|
2948
|
-
|
|
2949
|
-
|
|
2950
|
-
}
|
|
2951
|
-
};
|
|
2952
|
-
const UrlUtil = {
|
|
3078
|
+
hasClass(el, name) {
|
|
3079
|
+
var _a2;
|
|
3080
|
+
if ((_a2 = el.classList) == null ? void 0 : _a2.contains(name)) {
|
|
3081
|
+
return true;
|
|
3082
|
+
}
|
|
3083
|
+
const className = this.getClass(el);
|
|
3084
|
+
return className.length > 0 && new RegExp(`(^|\\s)${name}(\\s|$)`).test(className);
|
|
3085
|
+
},
|
|
2953
3086
|
/**
|
|
2954
|
-
*
|
|
3087
|
+
* 给指定的 HTML 元素添加类名
|
|
2955
3088
|
*
|
|
2956
|
-
* @param
|
|
2957
|
-
* @
|
|
3089
|
+
* @param el 要添加类名的 HTML 元素
|
|
3090
|
+
* @param name 要添加的类名,多个类名之间用空格分隔
|
|
2958
3091
|
*/
|
|
2959
|
-
|
|
2960
|
-
|
|
2961
|
-
|
|
2962
|
-
|
|
2963
|
-
|
|
2964
|
-
var value = json[i];
|
|
2965
|
-
tempArr.push(encodeURIComponent(key) + "=" + encodeURIComponent(value));
|
|
3092
|
+
addClass(el, name) {
|
|
3093
|
+
if (el.classList !== void 0) {
|
|
3094
|
+
const classes = splitWords(name);
|
|
3095
|
+
for (let i = 0, len = classes.length; i < len; i++) {
|
|
3096
|
+
el.classList.add(classes[i]);
|
|
2966
3097
|
}
|
|
3098
|
+
} else if (!this.hasClass(el, name)) {
|
|
3099
|
+
const className = this.getClass(el);
|
|
3100
|
+
this.setClass(el, (className ? className + " " : "") + name);
|
|
2967
3101
|
}
|
|
2968
|
-
var urlParamsStr = tempArr.join("&");
|
|
2969
|
-
return urlParamsStr;
|
|
2970
3102
|
},
|
|
2971
3103
|
/**
|
|
2972
|
-
*
|
|
3104
|
+
* 从元素中移除指定类名
|
|
2973
3105
|
*
|
|
2974
|
-
* @param
|
|
2975
|
-
* @param
|
|
2976
|
-
* @returns 返回一个包含解析后参数的对象,其中键为参数名,值为参数值
|
|
3106
|
+
* @param el 要移除类名的元素
|
|
3107
|
+
* @param name 要移除的类名,多个类名用空格分隔
|
|
2977
3108
|
*/
|
|
2978
|
-
|
|
2979
|
-
|
|
2980
|
-
|
|
2981
|
-
|
|
2982
|
-
|
|
2983
|
-
|
|
2984
|
-
const str = args[i];
|
|
2985
|
-
if (str) {
|
|
2986
|
-
const s = str.replace(/#|\//g, "");
|
|
2987
|
-
const arr = s.split("?");
|
|
2988
|
-
if (arr.length > 1) {
|
|
2989
|
-
for (let j = 1; j < arr.length; j++) {
|
|
2990
|
-
let res;
|
|
2991
|
-
while (res = reg.exec(arr[j])) {
|
|
2992
|
-
obj[res[1]] = needDecode ? decodeURIComponent(res[2]) : res[2];
|
|
2993
|
-
}
|
|
2994
|
-
}
|
|
2995
|
-
}
|
|
2996
|
-
}
|
|
3109
|
+
removeClass(el, name) {
|
|
3110
|
+
if (el.classList !== void 0) {
|
|
3111
|
+
const classes = splitWords(name);
|
|
3112
|
+
classes.forEach((className) => el.classList.remove(className));
|
|
3113
|
+
} else {
|
|
3114
|
+
this.setClass(el, (" " + this.getClass(el) + " ").replace(" " + name + " ", " ").trim());
|
|
2997
3115
|
}
|
|
2998
|
-
|
|
2999
|
-
|
|
3000
|
-
|
|
3001
|
-
|
|
3002
|
-
|
|
3003
|
-
|
|
3004
|
-
|
|
3005
|
-
|
|
3006
|
-
|
|
3007
|
-
|
|
3008
|
-
|
|
3009
|
-
this._validateColorChannel(b);
|
|
3010
|
-
this._r = r;
|
|
3011
|
-
this._g = g;
|
|
3012
|
-
this._b = b;
|
|
3013
|
-
this._alpha = MathUtils.clamp(a || 1, 0, 1);
|
|
3014
|
-
}
|
|
3015
|
-
_validateColorChannel(channel) {
|
|
3016
|
-
if (channel < 0 || channel > 255) {
|
|
3017
|
-
throw new Error("Color channel must be between 0 and 255.");
|
|
3116
|
+
},
|
|
3117
|
+
/**
|
|
3118
|
+
* 设置元素的 CSS 类名
|
|
3119
|
+
*
|
|
3120
|
+
* @param el HTML 或 SVG 元素
|
|
3121
|
+
* @param name 要设置的类名,多个类名之间用空格分隔
|
|
3122
|
+
*/
|
|
3123
|
+
setClass(el, name) {
|
|
3124
|
+
if ("classList" in el) {
|
|
3125
|
+
el.classList.value = "";
|
|
3126
|
+
name.split(" ").forEach((className) => el.classList.add(className));
|
|
3018
3127
|
}
|
|
3019
|
-
}
|
|
3020
|
-
toString() {
|
|
3021
|
-
return `rgba(${this._r}, ${this._g}, ${this._b}, ${this._alpha})`;
|
|
3022
|
-
}
|
|
3023
|
-
toJson() {
|
|
3024
|
-
return { r: this._r, g: this._g, b: this._b, a: this._alpha };
|
|
3025
|
-
}
|
|
3026
|
-
get rgba() {
|
|
3027
|
-
return `rgba(${this._r}, ${this._g}, ${this._b}, ${this._alpha})`;
|
|
3028
|
-
}
|
|
3029
|
-
get hex() {
|
|
3030
|
-
return Color.rgb2hex(this._r, this._g, this._b, this._alpha);
|
|
3031
|
-
}
|
|
3032
|
-
setAlpha(a) {
|
|
3033
|
-
this._alpha = MathUtils.clamp(a, 0, 1);
|
|
3034
|
-
return this;
|
|
3035
|
-
}
|
|
3036
|
-
// 设置颜色的RGB值
|
|
3037
|
-
setRgb(r, g, b) {
|
|
3038
|
-
this._validateColorChannel(r);
|
|
3039
|
-
this._validateColorChannel(g);
|
|
3040
|
-
this._validateColorChannel(b);
|
|
3041
|
-
this._r = r;
|
|
3042
|
-
this._g = g;
|
|
3043
|
-
this._b = b;
|
|
3044
|
-
return this;
|
|
3045
|
-
}
|
|
3128
|
+
},
|
|
3046
3129
|
/**
|
|
3047
|
-
*
|
|
3130
|
+
* 从字符串中解析XML文档,并返回根节点
|
|
3048
3131
|
*
|
|
3049
|
-
* @param
|
|
3050
|
-
* @returns
|
|
3051
|
-
* @throws 如果rgbaValue不是有效的RGBA颜色值,则抛出错误
|
|
3132
|
+
* @param str 要解析的XML字符串
|
|
3133
|
+
* @returns 解析后的XML文档的根节点
|
|
3052
3134
|
*/
|
|
3053
|
-
|
|
3054
|
-
const
|
|
3055
|
-
|
|
3056
|
-
|
|
3057
|
-
const g = parseInt(rgbaMatch[2], 10);
|
|
3058
|
-
const b = parseInt(rgbaMatch[3], 10);
|
|
3059
|
-
const a = rgbaMatch[5] ? parseFloat(rgbaMatch[5]) : 1;
|
|
3060
|
-
return new Color(r, g, b, a);
|
|
3135
|
+
parseFromString(str) {
|
|
3136
|
+
const parser = new DOMParser();
|
|
3137
|
+
const doc = parser.parseFromString(str, "text/xml");
|
|
3138
|
+
return doc.children[0];
|
|
3061
3139
|
}
|
|
3140
|
+
};
|
|
3141
|
+
const FileUtil = {
|
|
3062
3142
|
/**
|
|
3063
|
-
*
|
|
3143
|
+
* 将Base64编码的字符串转换为Blob对象
|
|
3064
3144
|
*
|
|
3065
|
-
* @param
|
|
3066
|
-
* @returns
|
|
3145
|
+
* @param data Base64编码的字符串
|
|
3146
|
+
* @returns 转换后的Blob对象
|
|
3067
3147
|
*/
|
|
3068
|
-
|
|
3069
|
-
const
|
|
3070
|
-
const
|
|
3071
|
-
const
|
|
3072
|
-
|
|
3073
|
-
|
|
3074
|
-
throw new Error("Invalid HEX color value");
|
|
3148
|
+
convertBase64ToBlob(data) {
|
|
3149
|
+
const mimeString = data.split(",")[0].split(":")[1].split(";")[0];
|
|
3150
|
+
const byteCharacters = atob(data.split(",")[1]);
|
|
3151
|
+
const byteNumbers = new Array(byteCharacters.length);
|
|
3152
|
+
for (let i = 0; i < byteCharacters.length; i++) {
|
|
3153
|
+
byteNumbers[i] = byteCharacters.charCodeAt(i);
|
|
3075
3154
|
}
|
|
3076
|
-
const
|
|
3077
|
-
const
|
|
3078
|
-
|
|
3079
|
-
|
|
3080
|
-
}
|
|
3155
|
+
const byteArray = new Uint8Array(byteNumbers);
|
|
3156
|
+
const blob = new Blob([byteArray], { type: mimeString });
|
|
3157
|
+
return blob;
|
|
3158
|
+
},
|
|
3081
3159
|
/**
|
|
3082
|
-
*
|
|
3160
|
+
* 将图片的URL转换为Base64编码
|
|
3083
3161
|
*
|
|
3084
|
-
* @param
|
|
3085
|
-
* @
|
|
3162
|
+
* @param url 图片的URL地址
|
|
3163
|
+
* @param width 图片的宽度,默认为图片原始宽度
|
|
3164
|
+
* @param height 图片的高度,默认为图片原始高度
|
|
3165
|
+
* @returns 返回Promise对象,解析后得到包含Base64编码数据的对象
|
|
3086
3166
|
*/
|
|
3087
|
-
static fromHsl(hslValue) {
|
|
3088
|
-
const hsl = /hsl\((\d+),\s*([\d.]+)%,\s*([\d.]+)%\)/g.exec(hslValue) || /hsla\((\d+),\s*([\d.]+)%,\s*([\d.]+)%,\s*([\d.]+)\)/g.exec(hslValue);
|
|
3089
|
-
if (!hsl) {
|
|
3090
|
-
throw new Error("Invalid HSL color value");
|
|
3091
|
-
}
|
|
3092
|
-
const h = parseInt(hsl[1], 10) / 360;
|
|
3093
|
-
const s = parseInt(hsl[2], 10) / 100;
|
|
3094
|
-
const l = parseInt(hsl[3], 10) / 100;
|
|
3095
|
-
const a = hsl[4] ? parseFloat(hsl[4]) : 1;
|
|
3096
|
-
function hue2rgb(p, q, t) {
|
|
3097
|
-
if (t < 0) t += 1;
|
|
3098
|
-
if (t > 1) t -= 1;
|
|
3099
|
-
if (t < 1 / 6) return p + (q - p) * 6 * t;
|
|
3100
|
-
if (t < 1 / 2) return q;
|
|
3101
|
-
if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
|
|
3102
|
-
return p;
|
|
3103
|
-
}
|
|
3104
|
-
let r, g, b;
|
|
3105
|
-
if (s === 0) {
|
|
3106
|
-
r = g = b = l;
|
|
3107
|
-
} else {
|
|
3108
|
-
const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
|
|
3109
|
-
const p = 2 * l - q;
|
|
3110
|
-
r = hue2rgb(p, q, h + 1 / 3);
|
|
3111
|
-
g = hue2rgb(p, q, h);
|
|
3112
|
-
b = hue2rgb(p, q, h - 1 / 3);
|
|
3113
|
-
}
|
|
3114
|
-
return new Color(Math.round(r * 255), Math.round(g * 255), Math.round(b * 255), a);
|
|
3115
|
-
}
|
|
3116
3167
|
/**
|
|
3117
|
-
*
|
|
3168
|
+
* 将base64字符串转换为文件对象
|
|
3118
3169
|
*
|
|
3119
|
-
* @param
|
|
3120
|
-
* @
|
|
3121
|
-
* @
|
|
3170
|
+
* @param dataurl 包含base64字符串的数据URL
|
|
3171
|
+
* @param filename 文件的名称
|
|
3172
|
+
* @returns 返回文件对象
|
|
3122
3173
|
*/
|
|
3123
|
-
|
|
3124
|
-
|
|
3125
|
-
|
|
3126
|
-
|
|
3127
|
-
|
|
3128
|
-
|
|
3129
|
-
|
|
3130
|
-
|
|
3131
|
-
throw new Error("Invalid color value");
|
|
3174
|
+
convertBase64ToFile(dataurl, filename) {
|
|
3175
|
+
const arr = dataurl.split(",");
|
|
3176
|
+
const mimeMatch = arr[0].match(/:(.*?);/);
|
|
3177
|
+
const mime = mimeMatch ? mimeMatch[1] : "image/png";
|
|
3178
|
+
const bstr = atob(arr[1]);
|
|
3179
|
+
const u8arr = new Uint8Array(bstr.length);
|
|
3180
|
+
for (let i = 0; i < bstr.length; i++) {
|
|
3181
|
+
u8arr[i] = bstr.charCodeAt(i);
|
|
3132
3182
|
}
|
|
3133
|
-
|
|
3183
|
+
const file = new File([u8arr], filename, { type: mime });
|
|
3184
|
+
return file;
|
|
3185
|
+
},
|
|
3134
3186
|
/**
|
|
3135
|
-
*
|
|
3187
|
+
* 从文件下载数据
|
|
3136
3188
|
*
|
|
3137
|
-
* @param
|
|
3138
|
-
* @param
|
|
3139
|
-
* @param b 蓝色分量值,取值范围0-255
|
|
3140
|
-
* @param a 可选参数,透明度分量值,取值范围0-1
|
|
3141
|
-
* @returns 十六进制颜色值,格式为#RRGGBB或#RRGGBBAA
|
|
3189
|
+
* @param data 要下载的数据,可以是字符串数组、BlobPart 或 MediaSource
|
|
3190
|
+
* @param saveName 下载后文件的保存名称
|
|
3142
3191
|
*/
|
|
3143
|
-
|
|
3144
|
-
|
|
3145
|
-
|
|
3146
|
-
|
|
3147
|
-
|
|
3192
|
+
downloadFromFile(data, saveName) {
|
|
3193
|
+
if (typeof data == "object") {
|
|
3194
|
+
if (data instanceof Blob) {
|
|
3195
|
+
data = URL.createObjectURL(data);
|
|
3196
|
+
} else {
|
|
3197
|
+
const str = JSON.stringify(data);
|
|
3198
|
+
const blob = new Blob([str], { type: "text/json" });
|
|
3199
|
+
data = window.URL.createObjectURL(blob);
|
|
3200
|
+
}
|
|
3201
|
+
} else if (typeof data == "string" && data.indexOf("http") === -1) {
|
|
3202
|
+
const blob = new Blob([data], { type: "text/json" });
|
|
3203
|
+
data = window.URL.createObjectURL(blob);
|
|
3148
3204
|
}
|
|
3149
|
-
|
|
3150
|
-
|
|
3151
|
-
|
|
3152
|
-
|
|
3153
|
-
|
|
3154
|
-
static isRgb(a) {
|
|
3155
|
-
return /^rgba?\s*\(\s*\d+\s*,\s*\d+\s*,\s*\d+\s*(,\s*[\d.]+)?\s*\)$/.test(a);
|
|
3156
|
-
}
|
|
3157
|
-
static isHsl(a) {
|
|
3158
|
-
return /^(hsl|hsla)\(\d+,\s*[\d.]+%,\s*[\d.]+%(,\s*[\d.]+)?\)$/.test(a);
|
|
3205
|
+
var link = document.createElement("a");
|
|
3206
|
+
link.href = data;
|
|
3207
|
+
link.download = saveName || "";
|
|
3208
|
+
link.click();
|
|
3209
|
+
window.URL.revokeObjectURL(link.href);
|
|
3159
3210
|
}
|
|
3160
|
-
|
|
3161
|
-
|
|
3211
|
+
};
|
|
3212
|
+
class MessageUtil {
|
|
3213
|
+
static resetWarned() {
|
|
3214
|
+
this.warned = {};
|
|
3162
3215
|
}
|
|
3163
|
-
static
|
|
3164
|
-
|
|
3165
|
-
|
|
3166
|
-
let b = Math.floor(Math.random() * 256);
|
|
3167
|
-
let a = Math.random();
|
|
3168
|
-
return new Color(r, g, b, a);
|
|
3216
|
+
static changeVoice() {
|
|
3217
|
+
this.isMute = !!Number(!this.isMute);
|
|
3218
|
+
localStorage.setItem("mute", Number(this.isMute).toString());
|
|
3169
3219
|
}
|
|
3170
|
-
|
|
3171
|
-
|
|
3172
|
-
|
|
3173
|
-
|
|
3174
|
-
if (typeof el === "string") {
|
|
3175
|
-
el = document.querySelector("#" + el);
|
|
3176
|
-
if (!el) {
|
|
3177
|
-
throw new Error("Element not found");
|
|
3178
|
-
}
|
|
3179
|
-
}
|
|
3180
|
-
if (el instanceof HTMLElement) {
|
|
3181
|
-
const canvas = el;
|
|
3182
|
-
if (canvas.getContext) {
|
|
3183
|
-
this.context = canvas.getContext("2d");
|
|
3184
|
-
} else {
|
|
3185
|
-
throw new Error("getContext is not available on this element");
|
|
3186
|
-
}
|
|
3187
|
-
} else {
|
|
3188
|
-
throw new Error("Element is not an HTMLElement");
|
|
3220
|
+
static _call(method, message) {
|
|
3221
|
+
if (!this.warned[message]) {
|
|
3222
|
+
method(message);
|
|
3223
|
+
this.warned[message] = true;
|
|
3189
3224
|
}
|
|
3190
3225
|
}
|
|
3191
3226
|
/**
|
|
3192
|
-
*
|
|
3227
|
+
* 播放消息提示音和文字朗读
|
|
3193
3228
|
*
|
|
3194
|
-
* @param
|
|
3195
|
-
* @param
|
|
3196
|
-
* @param options
|
|
3197
|
-
* @
|
|
3229
|
+
* @param type 消息类型
|
|
3230
|
+
* @param message 消息内容
|
|
3231
|
+
* @param options 配置选项,可选参数,包括语言、音量、语速和音高
|
|
3232
|
+
* @returns 无返回值
|
|
3198
3233
|
*/
|
|
3199
|
-
|
|
3200
|
-
|
|
3201
|
-
|
|
3202
|
-
|
|
3203
|
-
this.
|
|
3204
|
-
|
|
3205
|
-
|
|
3206
|
-
this.
|
|
3207
|
-
this.
|
|
3208
|
-
this.
|
|
3209
|
-
this.context.lineTo(endX, endY);
|
|
3210
|
-
this.context.stroke();
|
|
3234
|
+
static msg(type, message, options = {}) {
|
|
3235
|
+
Message({ type, message });
|
|
3236
|
+
if (this.isMute) return;
|
|
3237
|
+
const typename = Util.decodeDict(type, "success", "恭喜:", "error", "发生错误:", "warning", "警告:", "info", "友情提示:") + ":";
|
|
3238
|
+
this.speechSynthesisUtterance.text = typename + message;
|
|
3239
|
+
this.speechSynthesisUtterance.lang = options.lang || "zh-CN";
|
|
3240
|
+
this.speechSynthesisUtterance.volume = options.volume || 1;
|
|
3241
|
+
this.speechSynthesisUtterance.rate = options.rate || 1;
|
|
3242
|
+
this.speechSynthesisUtterance.pitch = options.pitch || 1;
|
|
3243
|
+
this.speechSynthesis.speak(this.speechSynthesisUtterance);
|
|
3211
3244
|
}
|
|
3212
|
-
|
|
3213
|
-
|
|
3214
|
-
|
|
3215
|
-
* @param x 圆心x坐标
|
|
3216
|
-
* @param y 圆心y坐标
|
|
3217
|
-
* @param radius 半径
|
|
3218
|
-
* @param startAngle 起始角度(度)
|
|
3219
|
-
* @param endAngle 结束角度(度)
|
|
3220
|
-
* @param anticlockwise 是否逆时针绘制
|
|
3221
|
-
* @param isFill 是否填充
|
|
3222
|
-
* @param bgColor 背景颜色
|
|
3223
|
-
* @throws 当Canvas context为null或undefined时抛出错误
|
|
3224
|
-
*/
|
|
3225
|
-
drawArc({ x, y }, radius, startAngle, endAngle, anticlockwise, isFill, bgColor) {
|
|
3226
|
-
if (!this.context) {
|
|
3227
|
-
throw new Error("Canvas context is null or undefined");
|
|
3228
|
-
}
|
|
3229
|
-
if (isFill) {
|
|
3230
|
-
this.context.fillStyle = bgColor;
|
|
3231
|
-
this.context.beginPath();
|
|
3232
|
-
this.context.arc(x, y, radius, MathUtils.deg2Rad(startAngle), MathUtils.deg2Rad(endAngle), anticlockwise);
|
|
3233
|
-
this.context.fill();
|
|
3234
|
-
} else {
|
|
3235
|
-
this.context.strokeStyle = bgColor;
|
|
3236
|
-
this.context.beginPath();
|
|
3237
|
-
this.context.arc(x, y, radius, MathUtils.deg2Rad(startAngle), MathUtils.deg2Rad(endAngle), anticlockwise);
|
|
3238
|
-
this.context.stroke();
|
|
3239
|
-
}
|
|
3245
|
+
static stop(e) {
|
|
3246
|
+
this.speechSynthesisUtterance.text = e;
|
|
3247
|
+
this.speechSynthesis.cancel();
|
|
3240
3248
|
}
|
|
3241
|
-
static
|
|
3242
|
-
|
|
3243
|
-
|
|
3244
|
-
canvas.width = width;
|
|
3245
|
-
}
|
|
3246
|
-
if (height) {
|
|
3247
|
-
canvas.height = height;
|
|
3249
|
+
static warning(message) {
|
|
3250
|
+
if (process.env.NODE_ENV === "development" && console !== void 0) {
|
|
3251
|
+
console.warn(`Warning: ${message}`);
|
|
3248
3252
|
}
|
|
3249
|
-
|
|
3253
|
+
this.msg("warning", message);
|
|
3250
3254
|
}
|
|
3251
|
-
|
|
3252
|
-
|
|
3253
|
-
constructor() {
|
|
3254
|
-
__publicField(this, "_listeners");
|
|
3255
|
-
__publicField(this, "_mutex", {});
|
|
3256
|
-
__publicField(this, "_context");
|
|
3255
|
+
static warningOnce(message) {
|
|
3256
|
+
this._call(this.warning.bind(this), message);
|
|
3257
3257
|
}
|
|
3258
|
-
|
|
3259
|
-
if (
|
|
3260
|
-
|
|
3261
|
-
const mutex = this._mutex;
|
|
3262
|
-
const listeners = this._listeners;
|
|
3263
|
-
if (listeners[type] === void 0) {
|
|
3264
|
-
listeners[type] = [];
|
|
3265
|
-
}
|
|
3266
|
-
if (listeners[type].indexOf(listener) === -1) {
|
|
3267
|
-
if (mutexStatus) {
|
|
3268
|
-
mutex[type] = listener;
|
|
3269
|
-
}
|
|
3270
|
-
listeners[type].push(listener);
|
|
3258
|
+
static info(message) {
|
|
3259
|
+
if (process.env.NODE_ENV === "development" && console !== void 0) {
|
|
3260
|
+
console.info(`Info: ${message}`);
|
|
3271
3261
|
}
|
|
3272
|
-
|
|
3262
|
+
this.msg("info", message);
|
|
3273
3263
|
}
|
|
3274
|
-
|
|
3275
|
-
|
|
3276
|
-
const listeners = this._listeners;
|
|
3277
|
-
return listeners[type] !== void 0 && listeners[type].indexOf(listener) !== -1;
|
|
3264
|
+
static infoOnce(message) {
|
|
3265
|
+
this._call(this.info.bind(this), message);
|
|
3278
3266
|
}
|
|
3279
|
-
|
|
3280
|
-
if (
|
|
3281
|
-
|
|
3282
|
-
const listenerArray = listeners[type];
|
|
3283
|
-
if (this._mutex[type] === listener) {
|
|
3284
|
-
this._mutex[type] = null;
|
|
3267
|
+
static error(message) {
|
|
3268
|
+
if (process.env.NODE_ENV === "development" && console !== void 0) {
|
|
3269
|
+
console.error(`Error: ${message}`);
|
|
3285
3270
|
}
|
|
3286
|
-
|
|
3287
|
-
|
|
3288
|
-
|
|
3289
|
-
|
|
3290
|
-
|
|
3271
|
+
this.msg("error", message);
|
|
3272
|
+
}
|
|
3273
|
+
static errorOnce(message) {
|
|
3274
|
+
this._call(this.error.bind(this), message);
|
|
3275
|
+
}
|
|
3276
|
+
static success(message) {
|
|
3277
|
+
if (process.env.NODE_ENV === "development" && console !== void 0) {
|
|
3278
|
+
console.log(`Success: ${message}`);
|
|
3291
3279
|
}
|
|
3280
|
+
this.msg("success", message);
|
|
3292
3281
|
}
|
|
3293
|
-
|
|
3294
|
-
|
|
3295
|
-
|
|
3296
|
-
|
|
3297
|
-
|
|
3298
|
-
|
|
3299
|
-
|
|
3300
|
-
|
|
3301
|
-
|
|
3302
|
-
|
|
3303
|
-
|
|
3304
|
-
|
|
3282
|
+
static successOnce(message) {
|
|
3283
|
+
this._call(this.success.bind(this), message);
|
|
3284
|
+
}
|
|
3285
|
+
}
|
|
3286
|
+
__publicField(MessageUtil, "warned", {});
|
|
3287
|
+
__publicField(MessageUtil, "isMute", !!Number(localStorage.getItem("mute")) || false);
|
|
3288
|
+
__publicField(MessageUtil, "speechSynthesis", window.speechSynthesis);
|
|
3289
|
+
__publicField(MessageUtil, "speechSynthesisUtterance", new SpeechSynthesisUtterance());
|
|
3290
|
+
const OptimizeUtil = {
|
|
3291
|
+
/**
|
|
3292
|
+
* 防抖函数,在指定的等待时间内,如果连续触发事件,则只在最后一次触发后执行函数。适用于像搜索输入框这种需要用户停止输入后才调用的场景
|
|
3293
|
+
*
|
|
3294
|
+
* @param func 需要防抖的函数。
|
|
3295
|
+
* @param wait 等待时间,单位毫秒。
|
|
3296
|
+
* @param immediate 是否立即执行函数,默认为true。
|
|
3297
|
+
* @returns 返回防抖后的函数。
|
|
3298
|
+
*/
|
|
3299
|
+
debounce(func, wait, immediate = true) {
|
|
3300
|
+
let timeout = null;
|
|
3301
|
+
let args;
|
|
3302
|
+
let timestamp;
|
|
3303
|
+
let result;
|
|
3304
|
+
const later = () => {
|
|
3305
|
+
const last = Date.now() - timestamp;
|
|
3306
|
+
if (last < wait && last > 0) {
|
|
3307
|
+
timeout = setTimeout(later, wait - last);
|
|
3308
|
+
} else {
|
|
3309
|
+
timeout = null;
|
|
3310
|
+
if (!immediate) {
|
|
3311
|
+
result = func.apply(this, args);
|
|
3312
|
+
}
|
|
3313
|
+
}
|
|
3314
|
+
};
|
|
3315
|
+
return (...args2) => {
|
|
3316
|
+
timestamp = Date.now();
|
|
3317
|
+
const callNow = immediate && !timeout;
|
|
3318
|
+
if (!timeout) {
|
|
3319
|
+
timeout = setTimeout(later, wait);
|
|
3320
|
+
}
|
|
3321
|
+
if (callNow) {
|
|
3322
|
+
result = func.apply(this, args2);
|
|
3323
|
+
if (!timeout) {
|
|
3324
|
+
args2 = null;
|
|
3305
3325
|
}
|
|
3306
3326
|
}
|
|
3307
|
-
|
|
3308
|
-
|
|
3309
|
-
|
|
3310
|
-
|
|
3327
|
+
return result;
|
|
3328
|
+
};
|
|
3329
|
+
},
|
|
3330
|
+
/**
|
|
3331
|
+
* 节流函数,适用于像滚动事件、窗口resize事件这种需要限制调用频率的场景
|
|
3332
|
+
*
|
|
3333
|
+
* @param func 需要节流的函数
|
|
3334
|
+
* @param wait 节流间隔,单位为毫秒
|
|
3335
|
+
* @param type 节流类型,1表示时间戳方式,2表示定时器方式
|
|
3336
|
+
* @returns 返回一个新的函数,该函数在节流控制下执行传入的函数
|
|
3337
|
+
*/
|
|
3338
|
+
throttle(func, wait, type = 1) {
|
|
3339
|
+
let previous = 0;
|
|
3340
|
+
let timeout = null;
|
|
3341
|
+
return (...args) => {
|
|
3342
|
+
if (type === 1) {
|
|
3343
|
+
const now = Date.now();
|
|
3344
|
+
if (now - previous >= wait) {
|
|
3345
|
+
func.apply(this, args);
|
|
3346
|
+
previous = now;
|
|
3347
|
+
}
|
|
3348
|
+
} else if (type === 2) {
|
|
3349
|
+
if (!timeout) {
|
|
3350
|
+
timeout = setTimeout(() => {
|
|
3351
|
+
timeout = null;
|
|
3352
|
+
func.apply(this, args);
|
|
3353
|
+
}, wait);
|
|
3311
3354
|
}
|
|
3312
3355
|
}
|
|
3313
|
-
}
|
|
3314
|
-
}
|
|
3315
|
-
removeAllListener() {
|
|
3316
|
-
this._mutex = {};
|
|
3317
|
-
for (const key in this._listeners) {
|
|
3318
|
-
this._listeners[key] = [];
|
|
3319
|
-
}
|
|
3320
|
-
}
|
|
3321
|
-
}
|
|
3322
|
-
class HashMap extends Map {
|
|
3323
|
-
isEmpty() {
|
|
3324
|
-
return this.size === 0;
|
|
3325
|
-
}
|
|
3326
|
-
_values() {
|
|
3327
|
-
return Array.from(this.values());
|
|
3328
|
-
}
|
|
3329
|
-
_keys() {
|
|
3330
|
-
return Array.from(this.keys());
|
|
3331
|
-
}
|
|
3332
|
-
_entries() {
|
|
3333
|
-
return Array.from(this.entries());
|
|
3334
|
-
}
|
|
3356
|
+
};
|
|
3357
|
+
},
|
|
3335
3358
|
/**
|
|
3336
|
-
*
|
|
3359
|
+
* 缓存函数,将传入的函数fn的计算结果缓存,提高重复计算的效率
|
|
3337
3360
|
*
|
|
3338
|
-
* @param
|
|
3339
|
-
* @returns
|
|
3361
|
+
* @param fn 传入待缓存的函数
|
|
3362
|
+
* @returns 返回缓存后的函数
|
|
3340
3363
|
*/
|
|
3341
|
-
|
|
3342
|
-
const
|
|
3343
|
-
|
|
3344
|
-
|
|
3345
|
-
|
|
3364
|
+
memoize(fn) {
|
|
3365
|
+
const cache = /* @__PURE__ */ new Map();
|
|
3366
|
+
return (...args) => {
|
|
3367
|
+
const argsString = JSON.stringify(args);
|
|
3368
|
+
if (cache.has(argsString)) {
|
|
3369
|
+
return cache.get(argsString);
|
|
3370
|
+
} else {
|
|
3371
|
+
const result = fn.apply(this, args);
|
|
3372
|
+
cache.set(argsString, result);
|
|
3373
|
+
return result;
|
|
3346
3374
|
}
|
|
3347
|
-
}
|
|
3348
|
-
|
|
3349
|
-
}
|
|
3375
|
+
};
|
|
3376
|
+
},
|
|
3350
3377
|
/**
|
|
3351
|
-
*
|
|
3378
|
+
* 递归调用函数,以一定的频率和持续时间执行。
|
|
3352
3379
|
*
|
|
3353
|
-
* @param
|
|
3354
|
-
* @
|
|
3380
|
+
* @param fun 要递归调用的函数。
|
|
3381
|
+
* @param frequency 每次调用函数之间的时间间隔,单位为毫秒,默认为500毫秒。
|
|
3382
|
+
* @param duration 函数递归调用的总时长,单位为毫秒,默认为5000毫秒。
|
|
3355
3383
|
*/
|
|
3356
|
-
|
|
3357
|
-
|
|
3358
|
-
|
|
3359
|
-
|
|
3360
|
-
|
|
3361
|
-
|
|
3362
|
-
|
|
3363
|
-
super();
|
|
3364
|
-
__publicField(this, "maxCheckTimes", 10);
|
|
3365
|
-
__publicField(this, "url");
|
|
3366
|
-
__publicField(this, "checkTimes", 0);
|
|
3367
|
-
__publicField(this, "connectStatus", false);
|
|
3368
|
-
__publicField(this, "client", null);
|
|
3369
|
-
this.maxCheckTimes = 10;
|
|
3370
|
-
this.url = url;
|
|
3371
|
-
this.checkTimes = 0;
|
|
3372
|
-
this.connect();
|
|
3373
|
-
this.connCheckStatus(this.maxCheckTimes);
|
|
3374
|
-
}
|
|
3375
|
-
connect() {
|
|
3376
|
-
this.disconnect();
|
|
3377
|
-
if (this.url) {
|
|
3378
|
-
try {
|
|
3379
|
-
console.info("创建ws连接>>>" + this.url);
|
|
3380
|
-
this.client = new WebSocket(this.url);
|
|
3381
|
-
if (this.client) {
|
|
3382
|
-
const self = this;
|
|
3383
|
-
this.client.onopen = function(message) {
|
|
3384
|
-
self.dispatchEvent({
|
|
3385
|
-
type: EventType.WEB_SOCKET_CONNECT,
|
|
3386
|
-
message
|
|
3387
|
-
});
|
|
3388
|
-
};
|
|
3389
|
-
this.client.onmessage = function(message) {
|
|
3390
|
-
self.connectStatus = true;
|
|
3391
|
-
self.dispatchEvent({
|
|
3392
|
-
type: EventType.WEB_SOCKET_MESSAGE,
|
|
3393
|
-
message
|
|
3394
|
-
});
|
|
3395
|
-
};
|
|
3396
|
-
this.client.onclose = function(message) {
|
|
3397
|
-
self.dispatchEvent({
|
|
3398
|
-
type: EventType.WEB_SOCKET_CLOSE,
|
|
3399
|
-
message
|
|
3400
|
-
});
|
|
3401
|
-
};
|
|
3402
|
-
if (this.checkTimes === this.maxCheckTimes) {
|
|
3403
|
-
this.client.onerror = function(message) {
|
|
3404
|
-
self.dispatchEvent({
|
|
3405
|
-
type: EventType.WEB_SOCKET_ERROR,
|
|
3406
|
-
message
|
|
3407
|
-
});
|
|
3408
|
-
};
|
|
3409
|
-
}
|
|
3410
|
-
}
|
|
3411
|
-
} catch (ex) {
|
|
3412
|
-
console.error("创建ws连接失败" + this.url + ":" + ex);
|
|
3384
|
+
recurve(fun, frequency = 500, duration = 5e3) {
|
|
3385
|
+
let timer = 0;
|
|
3386
|
+
setTimeout(() => {
|
|
3387
|
+
timer++;
|
|
3388
|
+
if (timer < Math.floor(duration / frequency)) {
|
|
3389
|
+
fun.call(this);
|
|
3390
|
+
setTimeout(this.recurve.bind(this, fun, frequency, duration), frequency);
|
|
3413
3391
|
}
|
|
3414
|
-
}
|
|
3415
|
-
}
|
|
3416
|
-
|
|
3417
|
-
|
|
3418
|
-
|
|
3419
|
-
|
|
3420
|
-
|
|
3421
|
-
|
|
3422
|
-
|
|
3423
|
-
|
|
3392
|
+
}, frequency);
|
|
3393
|
+
},
|
|
3394
|
+
/**
|
|
3395
|
+
* 确保函数只被调用一次
|
|
3396
|
+
*
|
|
3397
|
+
* @param func 要被调用的函数
|
|
3398
|
+
* @returns 返回一个新的函数,该函数在被首次调用时会执行传入的函数,之后再次调用将不再执行
|
|
3399
|
+
*/
|
|
3400
|
+
once(func) {
|
|
3401
|
+
let called = false;
|
|
3402
|
+
return function(...args) {
|
|
3403
|
+
if (!called) {
|
|
3404
|
+
called = true;
|
|
3405
|
+
return func(...args);
|
|
3424
3406
|
}
|
|
3425
|
-
}
|
|
3407
|
+
};
|
|
3426
3408
|
}
|
|
3427
|
-
|
|
3428
|
-
|
|
3429
|
-
|
|
3430
|
-
|
|
3431
|
-
|
|
3432
|
-
|
|
3409
|
+
};
|
|
3410
|
+
const UrlUtil = {
|
|
3411
|
+
/**
|
|
3412
|
+
* 将json对象转换为查询字符串
|
|
3413
|
+
*
|
|
3414
|
+
* @param json 待转换的json对象
|
|
3415
|
+
* @returns 转换后的查询字符串
|
|
3416
|
+
*/
|
|
3417
|
+
json2Query(json) {
|
|
3418
|
+
var tempArr = [];
|
|
3419
|
+
for (var i in json) {
|
|
3420
|
+
if (json.hasOwnProperty(i)) {
|
|
3421
|
+
var key = i;
|
|
3422
|
+
var value = json[i];
|
|
3423
|
+
tempArr.push(encodeURIComponent(key) + "=" + encodeURIComponent(value));
|
|
3433
3424
|
}
|
|
3434
|
-
this.connCheckStatus(times);
|
|
3435
|
-
}, 2e3);
|
|
3436
|
-
}
|
|
3437
|
-
send(message) {
|
|
3438
|
-
if (this.client && this.client.readyState === 1) {
|
|
3439
|
-
this.client.send(message);
|
|
3440
|
-
return true;
|
|
3441
3425
|
}
|
|
3442
|
-
|
|
3443
|
-
return
|
|
3444
|
-
}
|
|
3445
|
-
|
|
3446
|
-
|
|
3447
|
-
|
|
3448
|
-
|
|
3426
|
+
var urlParamsStr = tempArr.join("&");
|
|
3427
|
+
return urlParamsStr;
|
|
3428
|
+
},
|
|
3429
|
+
/**
|
|
3430
|
+
* 从 URL 中解析出查询参数和哈希参数,并以对象的形式返回
|
|
3431
|
+
*
|
|
3432
|
+
* @param href 需要解析的 URL 链接,默认为当前窗口的 URL
|
|
3433
|
+
* @param needDecode 是否需要解码参数值,默认为 true
|
|
3434
|
+
* @returns 返回一个包含解析后参数的对象,其中键为参数名,值为参数值
|
|
3435
|
+
*/
|
|
3436
|
+
query2Json(href = window.location.href, needDecode = true) {
|
|
3437
|
+
const reg = /([^&=]+)=([\w\W]*?)(&|$|#)/g;
|
|
3438
|
+
const { search, hash } = new URL(href);
|
|
3439
|
+
const args = [search, hash];
|
|
3440
|
+
let obj = {};
|
|
3441
|
+
for (let i = 0; i < args.length; i++) {
|
|
3442
|
+
const str = args[i];
|
|
3443
|
+
if (str) {
|
|
3444
|
+
const s = str.replace(/#|\//g, "");
|
|
3445
|
+
const arr = s.split("?");
|
|
3446
|
+
if (arr.length > 1) {
|
|
3447
|
+
for (let j = 1; j < arr.length; j++) {
|
|
3448
|
+
let res;
|
|
3449
|
+
while (res = reg.exec(arr[j])) {
|
|
3450
|
+
obj[res[1]] = needDecode ? decodeURIComponent(res[2]) : res[2];
|
|
3451
|
+
}
|
|
3452
|
+
}
|
|
3453
|
+
}
|
|
3449
3454
|
}
|
|
3450
|
-
|
|
3451
|
-
|
|
3452
|
-
}, 1e3);
|
|
3455
|
+
}
|
|
3456
|
+
return obj;
|
|
3453
3457
|
}
|
|
3454
|
-
}
|
|
3458
|
+
};
|
|
3455
3459
|
const _MqttClient = class _MqttClient extends EventDispatcher {
|
|
3456
3460
|
constructor(url = `ws://${window.document.domain}:20007/mqtt`, config = {}) {
|
|
3457
3461
|
super();
|
|
@@ -3461,10 +3465,10 @@ const _MqttClient = class _MqttClient extends EventDispatcher {
|
|
|
3461
3465
|
__publicField(this, "options");
|
|
3462
3466
|
__publicField(this, "client");
|
|
3463
3467
|
__publicField(this, "topics");
|
|
3464
|
-
this.context =
|
|
3468
|
+
this.context = Util.extend(_MqttClient.defaultContext, config);
|
|
3465
3469
|
this.options = {
|
|
3466
3470
|
connectTimeout: this.context.MQTT_TIMEOUTM,
|
|
3467
|
-
clientId:
|
|
3471
|
+
clientId: Util.guid(),
|
|
3468
3472
|
username: this.context.MQTT_USERNAME,
|
|
3469
3473
|
password: this.context.MQTT_PASSWORD,
|
|
3470
3474
|
clean: true
|
|
@@ -3657,7 +3661,7 @@ const _Storage = class _Storage {
|
|
|
3657
3661
|
}
|
|
3658
3662
|
}
|
|
3659
3663
|
};
|
|
3660
|
-
__publicField(_Storage, "store", window.
|
|
3664
|
+
__publicField(_Storage, "store", window.sessionStorage);
|
|
3661
3665
|
__publicField(_Storage, "prefix", "");
|
|
3662
3666
|
__publicField(_Storage, "_getPrefixedKey", function(key, options) {
|
|
3663
3667
|
options = options || {};
|
|
@@ -3691,7 +3695,7 @@ export {
|
|
|
3691
3695
|
ImageUtil,
|
|
3692
3696
|
LayerType,
|
|
3693
3697
|
LineSymbol,
|
|
3694
|
-
|
|
3698
|
+
MathUtil,
|
|
3695
3699
|
MeasureMode,
|
|
3696
3700
|
MessageUtil,
|
|
3697
3701
|
MqttClient,
|
|
@@ -3701,6 +3705,6 @@ export {
|
|
|
3701
3705
|
Storage,
|
|
3702
3706
|
StringUtil,
|
|
3703
3707
|
UrlUtil,
|
|
3704
|
-
|
|
3708
|
+
Util,
|
|
3705
3709
|
WebSocketClient
|
|
3706
3710
|
};
|