gis-common 4.2.1 → 4.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/constant/GraphicConstant.d.ts +6 -0
- package/dist/core/AudioPlayer.d.ts +16 -0
- package/dist/core/CanvasDrawer.d.ts +2 -2
- package/dist/core/Cookie.d.ts +5 -0
- package/dist/core/MqttClient.d.ts +3 -3
- package/dist/core/Storage.d.ts +28 -0
- package/dist/core/index.d.ts +2 -0
- package/dist/gis-common.es.js +2385 -1419
- package/dist/gis-common.umd.js +1 -1
- package/dist/utils/AjaxUtil.d.ts +7 -7
- package/dist/utils/ArrayUtil.d.ts +2 -2
- package/dist/utils/AssertUtil.d.ts +21 -0
- package/dist/utils/CommUtil.d.ts +22 -1
- package/dist/utils/MathUtil.d.ts +6 -29
- package/dist/utils/OptimizeUtil.d.ts +7 -0
- package/dist/utils/StringUtil.d.ts +0 -8
- package/dist/utils/index.d.ts +1 -2
- package/package.json +2 -1
- package/dist/utils/Cookie.d.ts +0 -6
- package/dist/utils/StoreUtil.d.ts +0 -10
package/dist/gis-common.es.js
CHANGED
|
@@ -1,16 +1,123 @@
|
|
|
1
|
-
var
|
|
2
|
-
var
|
|
3
|
-
var
|
|
4
|
-
import { connect
|
|
5
|
-
var
|
|
6
|
-
|
|
7
|
-
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
3
|
+
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
4
|
+
import { connect } from "mqtt-browser";
|
|
5
|
+
var EventType = /* @__PURE__ */ ((EventType2) => {
|
|
6
|
+
EventType2["MAP_RENDER"] = "mapRender";
|
|
7
|
+
EventType2["MAP_READY"] = "mapReady";
|
|
8
|
+
EventType2["MOUSE_CLICK"] = "click";
|
|
9
|
+
EventType2["MOUSE_DOUBLE_CLICK"] = "dblclick";
|
|
10
|
+
EventType2["MOUSE_MOVE"] = "mousemove";
|
|
11
|
+
EventType2["MOUSE_IN"] = "mousein";
|
|
12
|
+
EventType2["MOUSE_OUT"] = "mouseout";
|
|
13
|
+
EventType2["MOUSE_RIGHT_CLICK"] = "mouseRightClick";
|
|
14
|
+
EventType2["KEY_DOWN"] = "keyDown";
|
|
15
|
+
EventType2["KEY_UP"] = "keyUp";
|
|
16
|
+
EventType2["DRAW_ACTIVE"] = "drawActive";
|
|
17
|
+
EventType2["DRAW_MOVE"] = "drawMove";
|
|
18
|
+
EventType2["DRAW_COMPLETE"] = "drawComplete";
|
|
19
|
+
EventType2["MQTT_CONNECT"] = "mqttConnect";
|
|
20
|
+
EventType2["MQTT_ERROR"] = "mqttError";
|
|
21
|
+
EventType2["MQTT_MESSAGE"] = "mqttMessage";
|
|
22
|
+
EventType2["MQTT_CLOSE"] = "mqttClose";
|
|
23
|
+
EventType2["WEB_SOCKET_CONNECT"] = "webSocketConnect";
|
|
24
|
+
EventType2["WEB_SOCKET_ERROR"] = "webSocketError";
|
|
25
|
+
EventType2["WEB_SOCKET_MESSAGE"] = "webSocketMessage";
|
|
26
|
+
EventType2["WEB_SOCKET_CLOSE"] = "webSocketClose";
|
|
27
|
+
return EventType2;
|
|
28
|
+
})(EventType || {});
|
|
29
|
+
var ErrorType = /* @__PURE__ */ ((ErrorType2) => {
|
|
30
|
+
ErrorType2["LOGIN_EXPIRED"] = "登录信息过期,请重新登录";
|
|
31
|
+
ErrorType2["CROSS_ERROR"] = "跨域访问";
|
|
32
|
+
ErrorType2["UNEXIST_RESOURCE"] = "资源不存在";
|
|
33
|
+
ErrorType2["TIMEOUT"] = "请求超时";
|
|
34
|
+
ErrorType2["INTERNAL_ERROR"] = "内部错误";
|
|
35
|
+
ErrorType2["NETWORK_ERROR"] = "请求失败,请检查网络是否已连接";
|
|
36
|
+
ErrorType2["PROCESS_FAIL"] = "处理失败";
|
|
37
|
+
ErrorType2["AUTH_VERIFY_ERROR"] = "权限验证失败";
|
|
38
|
+
ErrorType2["NO_DATA_FOUND"] = "未找到数据";
|
|
39
|
+
ErrorType2["DUPLICATE_INSTANCE"] = "实例为单例模式,不允许重复构建";
|
|
40
|
+
ErrorType2["COORDINATE_ERROR"] = "坐标验证失败";
|
|
41
|
+
ErrorType2["JSON_PARSE_ERROR"] = "JSON解析失败,格式有误";
|
|
42
|
+
ErrorType2["JSON_VALUE_ERROR"] = "JSON无此键";
|
|
43
|
+
ErrorType2["PARAMETER_ERROR"] = "验证数据类型失败";
|
|
44
|
+
ErrorType2["PARAMETER_ERROR_ARRAY"] = "格式类型验证失败:必须是数组";
|
|
45
|
+
ErrorType2["PARAMETER_ERROR_STRING"] = "格式类型验证失败:必须是字符";
|
|
46
|
+
ErrorType2["PARAMETER_ERROR_FUNCTION"] = "格式类型验证失败:必须是函数";
|
|
47
|
+
ErrorType2["PARAMETER_ERROR_OBJECT"] = "格式类型验证失败:必须是对象";
|
|
48
|
+
ErrorType2["PARAMETER_ERROR_LACK"] = "参数缺失";
|
|
49
|
+
ErrorType2["STRING_CHECK_LOSS"] = "字符缺少关键字";
|
|
50
|
+
return ErrorType2;
|
|
51
|
+
})(ErrorType || {});
|
|
52
|
+
var LayerType = /* @__PURE__ */ ((LayerType2) => {
|
|
53
|
+
LayerType2["SUPER_MAP_IMAGES"] = "SuperMapImages";
|
|
54
|
+
LayerType2["SUPER_MAP_DATA"] = "SuperMapData";
|
|
55
|
+
LayerType2["ARC_GIS_MAP_IMAGES"] = "ArcGisMapImages";
|
|
56
|
+
LayerType2["ARC_GIS_MAP_DATA"] = "ArcGisMapData";
|
|
57
|
+
LayerType2["OSGB_LAYER"] = "OSGBLayer";
|
|
58
|
+
LayerType2["S3M_GROUP"] = "S3MGroup";
|
|
59
|
+
LayerType2["TERRAIN_LAYER"] = "TerrainFileLayer";
|
|
60
|
+
return LayerType2;
|
|
61
|
+
})(LayerType || {});
|
|
62
|
+
var GraphicType = /* @__PURE__ */ ((GraphicType2) => {
|
|
63
|
+
GraphicType2["POINT"] = "point";
|
|
64
|
+
GraphicType2["POLYLINE"] = "polyline";
|
|
65
|
+
GraphicType2["POLYGON"] = "polygon";
|
|
66
|
+
GraphicType2["BILLBOARD"] = "billboard";
|
|
67
|
+
GraphicType2["CYLINDER"] = "cylinder";
|
|
68
|
+
GraphicType2["ELLIPSOID"] = "ellipsoid";
|
|
69
|
+
GraphicType2["LABEL"] = "label";
|
|
70
|
+
GraphicType2["MODEL"] = "model";
|
|
71
|
+
GraphicType2["WALL"] = "wall";
|
|
72
|
+
return GraphicType2;
|
|
73
|
+
})(GraphicType || {});
|
|
74
|
+
var LineSymbol = /* @__PURE__ */ ((LineSymbol2) => {
|
|
75
|
+
LineSymbol2["DASH"] = "10,5";
|
|
76
|
+
LineSymbol2["DOT"] = "3";
|
|
77
|
+
LineSymbol2["DASHDOT"] = "10,3,3,3";
|
|
78
|
+
LineSymbol2["DASHDOTDOT"] = "10,3,3,3,3,3";
|
|
79
|
+
return LineSymbol2;
|
|
80
|
+
})(LineSymbol || {});
|
|
81
|
+
var MeasureMode = /* @__PURE__ */ ((MeasureMode2) => {
|
|
82
|
+
MeasureMode2["DISTANCE"] = "distance";
|
|
83
|
+
MeasureMode2["AREA"] = "area";
|
|
84
|
+
MeasureMode2["HEIGHT"] = "height";
|
|
85
|
+
return MeasureMode2;
|
|
86
|
+
})(MeasureMode || {});
|
|
87
|
+
var ObjectState = /* @__PURE__ */ ((ObjectState2) => {
|
|
88
|
+
ObjectState2["ADD"] = "add";
|
|
89
|
+
ObjectState2["REMOVE"] = "remove";
|
|
90
|
+
ObjectState2["INIT"] = "init";
|
|
91
|
+
return ObjectState2;
|
|
92
|
+
})(ObjectState || {});
|
|
93
|
+
class AudioPlayer {
|
|
94
|
+
constructor(url) {
|
|
8
95
|
/**
|
|
9
96
|
* Creates an instance of AudioPlayer.
|
|
10
97
|
* @param {*} url
|
|
11
98
|
*/
|
|
12
|
-
|
|
13
|
-
this.audio = new Audio()
|
|
99
|
+
__publicField(this, "audio");
|
|
100
|
+
this.audio = new Audio();
|
|
101
|
+
this.audio.src = url;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* 朗读文本
|
|
105
|
+
*
|
|
106
|
+
* @param message 要朗读的文本内容
|
|
107
|
+
* @param options 朗读选项,可选参数包括:
|
|
108
|
+
* - lang: 使用的语言,默认为中文
|
|
109
|
+
* - volume: 声音音量,默认为1
|
|
110
|
+
* - rate: 语速,默认为1
|
|
111
|
+
* - pitch: 音高,默认为1
|
|
112
|
+
*/
|
|
113
|
+
static speak(message, options = {}) {
|
|
114
|
+
const msg = new SpeechSynthesisUtterance();
|
|
115
|
+
msg.text = message;
|
|
116
|
+
msg.lang = options.lang || "zh-CN";
|
|
117
|
+
msg.volume = options.volume || 1;
|
|
118
|
+
msg.rate = options.rate || 1;
|
|
119
|
+
msg.pitch = options.pitch || 1;
|
|
120
|
+
window.speechSynthesis.speak(msg);
|
|
14
121
|
}
|
|
15
122
|
play() {
|
|
16
123
|
!this.muted && this.audio.play();
|
|
@@ -24,27 +131,44 @@ class H {
|
|
|
24
131
|
/**
|
|
25
132
|
* @description 设置静音状态,如果静音,autoplay属性将失效
|
|
26
133
|
*/
|
|
27
|
-
set muted(
|
|
28
|
-
this.audio.muted =
|
|
134
|
+
set muted(val) {
|
|
135
|
+
this.audio.muted = val;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
class Cookie {
|
|
139
|
+
static set(name, value, days = 30) {
|
|
140
|
+
if (typeof name !== "string" || typeof value !== "string" || typeof days !== "number") {
|
|
141
|
+
throw new Error("Invalid arguments");
|
|
142
|
+
}
|
|
143
|
+
const exp = /* @__PURE__ */ new Date();
|
|
144
|
+
exp.setTime(exp.getTime() + days * 24 * 60 * 60 * 1e3);
|
|
145
|
+
document.cookie = `${name}=${encodeURIComponent(value)};expires=${exp.toUTCString()}`;
|
|
146
|
+
}
|
|
147
|
+
static remove(name) {
|
|
148
|
+
var exp = /* @__PURE__ */ new Date();
|
|
149
|
+
exp.setTime(exp.getTime() - 1);
|
|
150
|
+
var cval = this.get(name);
|
|
151
|
+
if (cval != null) {
|
|
152
|
+
document.cookie = name + "=" + cval + ";expires=" + exp.toUTCString();
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
static get(name) {
|
|
156
|
+
var arr = document.cookie.match(new RegExp("(^| )" + name + "=([^;]*)(;|$)"));
|
|
157
|
+
if (arr != null) {
|
|
158
|
+
return arr[2];
|
|
159
|
+
} else {
|
|
160
|
+
return "";
|
|
161
|
+
}
|
|
29
162
|
}
|
|
30
163
|
}
|
|
31
|
-
const
|
|
164
|
+
const MathUtils = {
|
|
32
165
|
DEG2RAD: Math.PI / 180,
|
|
33
166
|
RAD2DEG: 180 / Math.PI,
|
|
34
|
-
randInt(
|
|
35
|
-
return
|
|
167
|
+
randInt(low, high) {
|
|
168
|
+
return low + Math.floor(Math.random() * (high - low + 1));
|
|
36
169
|
},
|
|
37
|
-
randFloat(
|
|
38
|
-
return
|
|
39
|
-
},
|
|
40
|
-
/**
|
|
41
|
-
* 角度转弧度
|
|
42
|
-
*
|
|
43
|
-
* @param {*} degrees
|
|
44
|
-
* @returns {*}
|
|
45
|
-
*/
|
|
46
|
-
degreesToRadians(t) {
|
|
47
|
-
return t * this.DEG2RAD;
|
|
170
|
+
randFloat(low, high) {
|
|
171
|
+
return low + Math.random() * (high - low);
|
|
48
172
|
},
|
|
49
173
|
/**
|
|
50
174
|
* 角度转弧度
|
|
@@ -52,17 +176,8 @@ const R = {
|
|
|
52
176
|
* @param {*} degrees
|
|
53
177
|
* @returns {*}
|
|
54
178
|
*/
|
|
55
|
-
|
|
56
|
-
return
|
|
57
|
-
},
|
|
58
|
-
/**
|
|
59
|
-
* 弧度转角度
|
|
60
|
-
*
|
|
61
|
-
* @param {*} radians
|
|
62
|
-
* @returns {*}
|
|
63
|
-
*/
|
|
64
|
-
radiansToDegrees(t) {
|
|
65
|
-
return t * this.RAD2DEG;
|
|
179
|
+
deg2Rad(degrees) {
|
|
180
|
+
return degrees * this.DEG2RAD;
|
|
66
181
|
},
|
|
67
182
|
/**
|
|
68
183
|
* 弧度转角度
|
|
@@ -70,48 +185,43 @@ const R = {
|
|
|
70
185
|
* @param {*} radians
|
|
71
186
|
* @returns {*}
|
|
72
187
|
*/
|
|
73
|
-
|
|
74
|
-
return
|
|
188
|
+
rad2Deg(radians) {
|
|
189
|
+
return radians * this.RAD2DEG;
|
|
75
190
|
},
|
|
76
|
-
|
|
77
|
-
return Math.round(
|
|
191
|
+
round(value, n = 2) {
|
|
192
|
+
return Math.round(value * Math.pow(10, n)) / Math.pow(10, n);
|
|
78
193
|
},
|
|
79
194
|
/**
|
|
80
|
-
*
|
|
195
|
+
* 将数值限制在指定范围内
|
|
81
196
|
*
|
|
82
|
-
* @param val
|
|
197
|
+
* @param val 需要限制的数值
|
|
83
198
|
* @param min 最小值
|
|
84
199
|
* @param max 最大值
|
|
85
200
|
* @returns 返回限制后的数值
|
|
86
201
|
*/
|
|
87
|
-
|
|
88
|
-
return Math.min(Math.max(
|
|
89
|
-
},
|
|
90
|
-
/**
|
|
91
|
-
* 根据给定值返回指定的最小值和最大值之间的最大值
|
|
92
|
-
*
|
|
93
|
-
* @param val 给定的数值
|
|
94
|
-
* @param min 最小值
|
|
95
|
-
* @param max 最大值
|
|
96
|
-
* @returns 返回限制后的数值
|
|
97
|
-
*/
|
|
98
|
-
maxMin(t, e, n) {
|
|
99
|
-
return Math.max(Math.min(t, n), e);
|
|
202
|
+
clamp(val, min, max) {
|
|
203
|
+
return Math.min(Math.max(val, min), max);
|
|
100
204
|
}
|
|
101
205
|
};
|
|
102
|
-
class
|
|
103
|
-
constructor(
|
|
104
|
-
|
|
105
|
-
if (typeof
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
206
|
+
class CanvasDrawer {
|
|
207
|
+
constructor(el) {
|
|
208
|
+
__publicField(this, "context", null);
|
|
209
|
+
if (typeof el === "string") {
|
|
210
|
+
el = document.querySelector("#" + el);
|
|
211
|
+
if (!el) {
|
|
212
|
+
throw new Error("Element not found");
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
if (el instanceof HTMLElement) {
|
|
216
|
+
const canvas = el;
|
|
217
|
+
if (canvas.getContext) {
|
|
218
|
+
this.context = canvas.getContext("2d");
|
|
219
|
+
} else {
|
|
112
220
|
throw new Error("getContext is not available on this element");
|
|
113
|
-
|
|
221
|
+
}
|
|
222
|
+
} else {
|
|
114
223
|
throw new Error("Element is not an HTMLElement");
|
|
224
|
+
}
|
|
115
225
|
}
|
|
116
226
|
/**
|
|
117
227
|
* 绘制线条
|
|
@@ -121,12 +231,18 @@ class j {
|
|
|
121
231
|
* @param options 绘制选项,包括线条宽度和颜色
|
|
122
232
|
* @throws 当画布上下文不存在时抛出错误
|
|
123
233
|
*/
|
|
124
|
-
drawLine({ x:
|
|
125
|
-
if (!this.context)
|
|
234
|
+
drawLine({ x: startX, y: startY }, { x: endX, y: endY }, options = {}) {
|
|
235
|
+
if (!this.context) {
|
|
126
236
|
throw new Error("Canvas context is null or undefined");
|
|
237
|
+
}
|
|
127
238
|
this.context.beginPath();
|
|
128
|
-
const
|
|
129
|
-
|
|
239
|
+
const width = options.width || 1;
|
|
240
|
+
const color = options.color || "#000";
|
|
241
|
+
this.context.lineWidth = width;
|
|
242
|
+
this.context.strokeStyle = color;
|
|
243
|
+
this.context.moveTo(startX, startY);
|
|
244
|
+
this.context.lineTo(endX, endY);
|
|
245
|
+
this.context.stroke();
|
|
130
246
|
}
|
|
131
247
|
/**
|
|
132
248
|
* 绘制圆弧
|
|
@@ -141,67 +257,104 @@ class j {
|
|
|
141
257
|
* @param bgColor 背景颜色
|
|
142
258
|
* @throws 当Canvas context为null或undefined时抛出错误
|
|
143
259
|
*/
|
|
144
|
-
drawArc({ x
|
|
145
|
-
if (!this.context)
|
|
260
|
+
drawArc({ x, y }, radius, startAngle, endAngle, anticlockwise, isFill, bgColor) {
|
|
261
|
+
if (!this.context) {
|
|
146
262
|
throw new Error("Canvas context is null or undefined");
|
|
147
|
-
|
|
263
|
+
}
|
|
264
|
+
if (isFill) {
|
|
265
|
+
this.context.fillStyle = bgColor;
|
|
266
|
+
this.context.beginPath();
|
|
267
|
+
this.context.arc(x, y, radius, MathUtils.deg2Rad(startAngle), MathUtils.deg2Rad(endAngle), anticlockwise);
|
|
268
|
+
this.context.fill();
|
|
269
|
+
} else {
|
|
270
|
+
this.context.strokeStyle = bgColor;
|
|
271
|
+
this.context.beginPath();
|
|
272
|
+
this.context.arc(x, y, radius, MathUtils.deg2Rad(startAngle), MathUtils.deg2Rad(endAngle), anticlockwise);
|
|
273
|
+
this.context.stroke();
|
|
274
|
+
}
|
|
148
275
|
}
|
|
149
|
-
static createCanvas(
|
|
150
|
-
|
|
151
|
-
if (
|
|
152
|
-
|
|
276
|
+
static createCanvas(width = 1, height = 1) {
|
|
277
|
+
const canvas = document.createElement("canvas");
|
|
278
|
+
if (width) {
|
|
279
|
+
canvas.width = width;
|
|
280
|
+
}
|
|
281
|
+
if (height) {
|
|
282
|
+
canvas.height = height;
|
|
283
|
+
}
|
|
284
|
+
return canvas;
|
|
153
285
|
}
|
|
154
286
|
}
|
|
155
|
-
class
|
|
287
|
+
class EventDispatcher {
|
|
156
288
|
constructor() {
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
289
|
+
__publicField(this, "_listeners");
|
|
290
|
+
__publicField(this, "_mutex", {});
|
|
291
|
+
__publicField(this, "_context");
|
|
160
292
|
}
|
|
161
|
-
addEventListener(
|
|
162
|
-
this._listeners === void 0
|
|
163
|
-
|
|
164
|
-
|
|
293
|
+
addEventListener(type, listener, context, mutexStatus) {
|
|
294
|
+
if (this._listeners === void 0) this._listeners = {};
|
|
295
|
+
this._context = context;
|
|
296
|
+
const mutex = this._mutex;
|
|
297
|
+
const listeners = this._listeners;
|
|
298
|
+
if (listeners[type] === void 0) {
|
|
299
|
+
listeners[type] = [];
|
|
300
|
+
}
|
|
301
|
+
if (listeners[type].indexOf(listener) === -1) {
|
|
302
|
+
if (mutexStatus) {
|
|
303
|
+
mutex[type] = listener;
|
|
304
|
+
}
|
|
305
|
+
listeners[type].push(listener);
|
|
306
|
+
}
|
|
307
|
+
return this;
|
|
165
308
|
}
|
|
166
|
-
hasEventListener(
|
|
167
|
-
if (this._listeners === null || this._listeners === void 0) return
|
|
168
|
-
const
|
|
169
|
-
return
|
|
309
|
+
hasEventListener(type, listener) {
|
|
310
|
+
if (this._listeners === null || this._listeners === void 0) return false;
|
|
311
|
+
const listeners = this._listeners;
|
|
312
|
+
return listeners[type] !== void 0 && listeners[type].indexOf(listener) !== -1;
|
|
170
313
|
}
|
|
171
|
-
removeEventListener(
|
|
314
|
+
removeEventListener(type, listener) {
|
|
172
315
|
if (this._listeners === void 0) return;
|
|
173
|
-
const
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
316
|
+
const listeners = this._listeners;
|
|
317
|
+
const listenerArray = listeners[type];
|
|
318
|
+
if (this._mutex[type] === listener) {
|
|
319
|
+
this._mutex[type] = null;
|
|
320
|
+
}
|
|
321
|
+
if (listenerArray !== void 0) {
|
|
322
|
+
const index = listenerArray.map((d) => d.toString()).indexOf(listener.toString());
|
|
323
|
+
if (index !== -1) {
|
|
324
|
+
listenerArray.splice(index, 1);
|
|
325
|
+
}
|
|
177
326
|
}
|
|
178
327
|
}
|
|
179
|
-
dispatchEvent(
|
|
328
|
+
dispatchEvent(event) {
|
|
180
329
|
if (this._listeners === void 0) return;
|
|
181
|
-
const
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
330
|
+
const listeners = this._listeners;
|
|
331
|
+
const listenerArray = listeners[event.type];
|
|
332
|
+
if (listenerArray !== void 0) {
|
|
333
|
+
event.target = this;
|
|
334
|
+
const array = listenerArray.slice(0);
|
|
335
|
+
if (this._mutex[event.type] !== void 0) {
|
|
336
|
+
const find = array.find((item) => item === this._mutex[event.type]);
|
|
337
|
+
if (find) {
|
|
338
|
+
find.call(this._context || this, event);
|
|
189
339
|
return;
|
|
190
340
|
}
|
|
191
341
|
}
|
|
192
|
-
for (let
|
|
193
|
-
const
|
|
194
|
-
typeof
|
|
342
|
+
for (let i = 0, l = array.length; i < l; i++) {
|
|
343
|
+
const item = array[i];
|
|
344
|
+
if (typeof item === "function") {
|
|
345
|
+
item.call(this._context || this, event);
|
|
346
|
+
}
|
|
195
347
|
}
|
|
196
348
|
}
|
|
197
349
|
}
|
|
198
350
|
removeAllListener() {
|
|
199
351
|
this._mutex = {};
|
|
200
|
-
for (const
|
|
201
|
-
this._listeners[
|
|
352
|
+
for (const key in this._listeners) {
|
|
353
|
+
this._listeners[key] = [];
|
|
354
|
+
}
|
|
202
355
|
}
|
|
203
356
|
}
|
|
204
|
-
class
|
|
357
|
+
class HashMap extends Map {
|
|
205
358
|
isEmpty() {
|
|
206
359
|
return this.size === 0;
|
|
207
360
|
}
|
|
@@ -217,90 +370,143 @@ class C extends Map {
|
|
|
217
370
|
fromEntries() {
|
|
218
371
|
}
|
|
219
372
|
}
|
|
220
|
-
|
|
221
|
-
const
|
|
222
|
-
|
|
223
|
-
Array.isArray(
|
|
224
|
-
|
|
373
|
+
HashMap.prototype.fromEntries = function(array = []) {
|
|
374
|
+
const hashMap = new HashMap();
|
|
375
|
+
array.forEach((element) => {
|
|
376
|
+
if (Array.isArray(element) && element.length === 2) {
|
|
377
|
+
hashMap.set(element[0], element[1]);
|
|
378
|
+
}
|
|
379
|
+
});
|
|
380
|
+
return hashMap;
|
|
225
381
|
};
|
|
226
|
-
class
|
|
227
|
-
constructor(
|
|
382
|
+
class WebSocketClient extends EventDispatcher {
|
|
383
|
+
constructor(url = "ws://127.0.0.1:10088") {
|
|
228
384
|
super();
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
this.maxCheckTimes = 10
|
|
385
|
+
__publicField(this, "maxCheckTimes", 10);
|
|
386
|
+
__publicField(this, "url");
|
|
387
|
+
__publicField(this, "checkTimes", 0);
|
|
388
|
+
__publicField(this, "connectStatus", false);
|
|
389
|
+
__publicField(this, "client", null);
|
|
390
|
+
this.maxCheckTimes = 10;
|
|
391
|
+
this.url = url;
|
|
392
|
+
this.checkTimes = 0;
|
|
393
|
+
this.connect();
|
|
394
|
+
this.connCheckStatus(this.maxCheckTimes);
|
|
235
395
|
}
|
|
236
396
|
connect() {
|
|
237
|
-
|
|
397
|
+
this.disconnect();
|
|
398
|
+
if (this.url) {
|
|
238
399
|
try {
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
400
|
+
console.info("创建ws连接>>>" + this.url);
|
|
401
|
+
this.client = new WebSocket(this.url);
|
|
402
|
+
if (this.client) {
|
|
403
|
+
const self = this;
|
|
404
|
+
this.client.onopen = function(message) {
|
|
405
|
+
self.dispatchEvent({
|
|
406
|
+
type: EventType.WEB_SOCKET_CONNECT,
|
|
407
|
+
message
|
|
245
408
|
});
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
409
|
+
};
|
|
410
|
+
this.client.onmessage = function(message) {
|
|
411
|
+
self.connectStatus = true;
|
|
412
|
+
self.dispatchEvent({
|
|
413
|
+
type: EventType.WEB_SOCKET_MESSAGE,
|
|
414
|
+
message
|
|
250
415
|
});
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
416
|
+
};
|
|
417
|
+
this.client.onclose = function(message) {
|
|
418
|
+
self.dispatchEvent({
|
|
419
|
+
type: EventType.WEB_SOCKET_CLOSE,
|
|
420
|
+
message
|
|
255
421
|
});
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
422
|
+
};
|
|
423
|
+
if (this.checkTimes === this.maxCheckTimes) {
|
|
424
|
+
this.client.onerror = function(message) {
|
|
425
|
+
self.dispatchEvent({
|
|
426
|
+
type: EventType.WEB_SOCKET_ERROR,
|
|
427
|
+
message
|
|
428
|
+
});
|
|
429
|
+
};
|
|
430
|
+
}
|
|
262
431
|
}
|
|
263
|
-
} catch (
|
|
264
|
-
console.error("创建ws连接失败" + this.url + ":" +
|
|
432
|
+
} catch (ex) {
|
|
433
|
+
console.error("创建ws连接失败" + this.url + ":" + ex);
|
|
265
434
|
}
|
|
435
|
+
}
|
|
266
436
|
}
|
|
267
437
|
disconnect() {
|
|
268
|
-
if (this.client)
|
|
438
|
+
if (this.client) {
|
|
269
439
|
try {
|
|
270
|
-
console.log("ws断开连接" + this.url)
|
|
271
|
-
|
|
440
|
+
console.log("ws断开连接" + this.url);
|
|
441
|
+
this.client.close();
|
|
442
|
+
this.client = null;
|
|
443
|
+
} catch (ex) {
|
|
272
444
|
this.client = null;
|
|
273
445
|
}
|
|
446
|
+
}
|
|
274
447
|
}
|
|
275
|
-
connCheckStatus(
|
|
276
|
-
this.checkTimes >
|
|
277
|
-
|
|
448
|
+
connCheckStatus(times) {
|
|
449
|
+
if (this.checkTimes > times) return;
|
|
450
|
+
setTimeout(() => {
|
|
451
|
+
this.checkTimes++;
|
|
452
|
+
if (this.client && this.client.readyState !== 0 && this.client.readyState !== 1) {
|
|
453
|
+
this.connect();
|
|
454
|
+
}
|
|
455
|
+
this.connCheckStatus(times);
|
|
278
456
|
}, 2e3);
|
|
279
457
|
}
|
|
280
|
-
send(
|
|
281
|
-
|
|
458
|
+
send(message) {
|
|
459
|
+
if (this.client && this.client.readyState === 1) {
|
|
460
|
+
this.client.send(message);
|
|
461
|
+
return true;
|
|
462
|
+
}
|
|
463
|
+
console.error(this.url + "消息发送失败:" + message);
|
|
464
|
+
return false;
|
|
282
465
|
}
|
|
283
466
|
heartbeat() {
|
|
284
467
|
setTimeout(() => {
|
|
285
|
-
this.client && this.client.readyState === 1
|
|
468
|
+
if (this.client && this.client.readyState === 1) {
|
|
469
|
+
this.send("HeartBeat");
|
|
470
|
+
}
|
|
471
|
+
console.log("HeartBeat," + this.url);
|
|
472
|
+
setTimeout(this.heartbeat, 3e4);
|
|
286
473
|
}, 1e3);
|
|
287
474
|
}
|
|
288
475
|
}
|
|
289
|
-
const
|
|
476
|
+
const CommUtil = {
|
|
290
477
|
/**
|
|
291
478
|
* 获取数据类型
|
|
292
479
|
*
|
|
293
480
|
* @param data 待判断的数据
|
|
294
481
|
* @returns 返回数据类型字符串
|
|
295
482
|
*/
|
|
296
|
-
getDataType(
|
|
297
|
-
return Object.prototype.toString.call(
|
|
483
|
+
getDataType(data) {
|
|
484
|
+
return Object.prototype.toString.call(data).slice(8, -1);
|
|
485
|
+
},
|
|
486
|
+
asArray(obj) {
|
|
487
|
+
return this.isEmpty(obj) ? [] : Array.isArray(obj) ? obj : [obj];
|
|
298
488
|
},
|
|
299
|
-
|
|
300
|
-
return
|
|
489
|
+
asNumber(a) {
|
|
490
|
+
return Number.isNaN(Number(a)) ? 0 : Number(a);
|
|
301
491
|
},
|
|
302
|
-
|
|
303
|
-
|
|
492
|
+
/**
|
|
493
|
+
* 将值转换为字符串
|
|
494
|
+
*
|
|
495
|
+
* @param value 要转换的值
|
|
496
|
+
* @returns 转换后的字符串,如果值为空,则返回空字符串
|
|
497
|
+
*/
|
|
498
|
+
asString(value) {
|
|
499
|
+
if (this.isEmpty(value)) {
|
|
500
|
+
return "";
|
|
501
|
+
} else {
|
|
502
|
+
switch (this.getDataType(value)) {
|
|
503
|
+
case "Object":
|
|
504
|
+
case "Array":
|
|
505
|
+
return JSON.stringify(value);
|
|
506
|
+
default:
|
|
507
|
+
return value;
|
|
508
|
+
}
|
|
509
|
+
}
|
|
304
510
|
},
|
|
305
511
|
/**
|
|
306
512
|
* 判断传入的值是否为空
|
|
@@ -308,36 +514,36 @@ const M = {
|
|
|
308
514
|
* @param value 待判断的值
|
|
309
515
|
* @returns 返回布尔值,表示是否为空
|
|
310
516
|
*/
|
|
311
|
-
isEmpty(
|
|
312
|
-
if (
|
|
313
|
-
return
|
|
314
|
-
|
|
517
|
+
isEmpty(value) {
|
|
518
|
+
if (value == null) {
|
|
519
|
+
return true;
|
|
520
|
+
}
|
|
521
|
+
const type = this.getDataType(value);
|
|
522
|
+
switch (type) {
|
|
315
523
|
case "String":
|
|
316
|
-
return
|
|
524
|
+
return value.trim() === "";
|
|
317
525
|
case "Array":
|
|
318
|
-
return !
|
|
526
|
+
return !value.length;
|
|
319
527
|
case "Object":
|
|
320
|
-
return !Object.keys(
|
|
528
|
+
return !Object.keys(value).length;
|
|
321
529
|
case "Boolean":
|
|
322
|
-
return !
|
|
530
|
+
return !value;
|
|
323
531
|
default:
|
|
324
|
-
return
|
|
532
|
+
return false;
|
|
325
533
|
}
|
|
326
534
|
},
|
|
327
|
-
isNotEmpty(t) {
|
|
328
|
-
return !this.isEmpty(t);
|
|
329
|
-
},
|
|
330
535
|
/**
|
|
331
536
|
* 将JSON对象转换为FormData对象
|
|
332
537
|
*
|
|
333
538
|
* @param json 待转换的JSON对象,其属性值为字符串或Blob类型
|
|
334
539
|
* @returns 转换后的FormData对象
|
|
335
540
|
*/
|
|
336
|
-
json2form(
|
|
337
|
-
const
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
})
|
|
541
|
+
json2form(json) {
|
|
542
|
+
const formData = new FormData();
|
|
543
|
+
Object.keys(json).forEach((key) => {
|
|
544
|
+
formData.append(key, json[key] instanceof Object ? JSON.stringify(json[key]) : json[key]);
|
|
545
|
+
});
|
|
546
|
+
return formData;
|
|
341
547
|
},
|
|
342
548
|
/**
|
|
343
549
|
* 生成GUID
|
|
@@ -345,10 +551,10 @@ const M = {
|
|
|
345
551
|
* @returns 返回一个由8个16进制数组成的GUID字符串
|
|
346
552
|
*/
|
|
347
553
|
guid() {
|
|
348
|
-
const
|
|
554
|
+
const S4 = function() {
|
|
349
555
|
return ((1 + Math.random()) * 65536 | 0).toString(16).substring(1);
|
|
350
556
|
};
|
|
351
|
-
return
|
|
557
|
+
return S4() + S4() + S4() + S4() + S4() + S4() + S4() + S4();
|
|
352
558
|
},
|
|
353
559
|
/**
|
|
354
560
|
* 将参数进行解码并返回解码后的字符串
|
|
@@ -356,18 +562,23 @@ const M = {
|
|
|
356
562
|
* @param args 参数
|
|
357
563
|
* @returns 解码后的字符串
|
|
358
564
|
*/
|
|
359
|
-
decodeDict(...
|
|
360
|
-
let
|
|
361
|
-
if (
|
|
362
|
-
const
|
|
363
|
-
for (let
|
|
364
|
-
const
|
|
365
|
-
|
|
565
|
+
decodeDict(...args) {
|
|
566
|
+
let res = "";
|
|
567
|
+
if (args.length > 1) {
|
|
568
|
+
const items = args.slice(1, args.length % 2 === 0 ? args.length - 1 : args.length);
|
|
569
|
+
for (let i = 0; i < items.length; i = i + 2) {
|
|
570
|
+
const item = items[i];
|
|
571
|
+
if (args[0] === item) {
|
|
572
|
+
res = items[i + 1];
|
|
573
|
+
}
|
|
366
574
|
}
|
|
367
|
-
!
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
575
|
+
if (!res && args.length % 2 === 0) {
|
|
576
|
+
res = args[args.length - 1];
|
|
577
|
+
}
|
|
578
|
+
} else {
|
|
579
|
+
res = args[0];
|
|
580
|
+
}
|
|
581
|
+
return res;
|
|
371
582
|
},
|
|
372
583
|
/**
|
|
373
584
|
* 将一个或多个对象的所有可枚举属性复制到目标对象。
|
|
@@ -376,14 +587,15 @@ const M = {
|
|
|
376
587
|
* @param args 一个或多个源对象,用于提供要复制的属性。
|
|
377
588
|
* @returns 返回目标对象,包含所有复制的属性。
|
|
378
589
|
*/
|
|
379
|
-
extend(
|
|
380
|
-
let
|
|
381
|
-
for (
|
|
382
|
-
|
|
383
|
-
for (
|
|
384
|
-
|
|
590
|
+
extend(dest, ...args) {
|
|
591
|
+
let i, j, len, src;
|
|
592
|
+
for (j = 0, len = args.length; j < len; j++) {
|
|
593
|
+
src = args[j];
|
|
594
|
+
for (i in src) {
|
|
595
|
+
dest[i] = src[i];
|
|
596
|
+
}
|
|
385
597
|
}
|
|
386
|
-
return
|
|
598
|
+
return dest;
|
|
387
599
|
},
|
|
388
600
|
/**
|
|
389
601
|
* 将扁平化数组转换为树形结构数组
|
|
@@ -394,34 +606,55 @@ const M = {
|
|
|
394
606
|
* @param childrenPropertyName 树形结构中标识子节点的字段名,默认为'children'
|
|
395
607
|
* @returns 转换后的树形结构数组
|
|
396
608
|
*/
|
|
397
|
-
convertToTree2(
|
|
398
|
-
const
|
|
399
|
-
function
|
|
400
|
-
const
|
|
401
|
-
|
|
609
|
+
convertToTree2(data, idPropertyName = "id", parentIdPropertyName = "parentId", childrenPropertyName = "children") {
|
|
610
|
+
const result = [];
|
|
611
|
+
function buildChildren(item) {
|
|
612
|
+
const children = data.filter((item2) => item2[parentIdPropertyName] === item[idPropertyName]).map((child) => {
|
|
613
|
+
if (!result.some((r) => r[idPropertyName] === child[idPropertyName])) {
|
|
614
|
+
buildChildren(child);
|
|
615
|
+
}
|
|
616
|
+
return child;
|
|
617
|
+
});
|
|
618
|
+
if (children.length > 0) {
|
|
619
|
+
item[childrenPropertyName] = children;
|
|
620
|
+
}
|
|
402
621
|
}
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
622
|
+
data.forEach((item) => {
|
|
623
|
+
if (!data.some((other) => other[parentIdPropertyName] === item[idPropertyName])) {
|
|
624
|
+
buildChildren(item);
|
|
625
|
+
result.push(item);
|
|
626
|
+
}
|
|
627
|
+
});
|
|
628
|
+
return result;
|
|
406
629
|
},
|
|
407
630
|
/**
|
|
408
631
|
* 异步加载script
|
|
409
632
|
*
|
|
410
633
|
* @param {*} url
|
|
411
634
|
*/
|
|
412
|
-
asyncLoadScript(
|
|
413
|
-
return new Promise((
|
|
635
|
+
asyncLoadScript(url) {
|
|
636
|
+
return new Promise((resolve, reject) => {
|
|
414
637
|
try {
|
|
415
|
-
const
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
638
|
+
const oscript = document.createElement("script");
|
|
639
|
+
oscript.type = "text/javascript";
|
|
640
|
+
oscript.src = url;
|
|
641
|
+
if ("readyState" in oscript) {
|
|
642
|
+
oscript.onreadystatechange = function() {
|
|
643
|
+
if (oscript.readyState === "complete" || oscript.readyState === "loaded") {
|
|
644
|
+
resolve(oscript);
|
|
645
|
+
}
|
|
646
|
+
};
|
|
647
|
+
} else {
|
|
648
|
+
oscript.onload = function() {
|
|
649
|
+
resolve(oscript);
|
|
650
|
+
};
|
|
651
|
+
oscript.onerror = function() {
|
|
652
|
+
reject(new Error("Script failed to load for URL: " + url));
|
|
653
|
+
};
|
|
654
|
+
}
|
|
655
|
+
document.body.appendChild(oscript);
|
|
656
|
+
} catch (error) {
|
|
657
|
+
reject(error);
|
|
425
658
|
}
|
|
426
659
|
});
|
|
427
660
|
},
|
|
@@ -431,12 +664,16 @@ const M = {
|
|
|
431
664
|
* @param urls 样式文件URL数组
|
|
432
665
|
* @returns 无返回值
|
|
433
666
|
*/
|
|
434
|
-
loadStyle(
|
|
435
|
-
|
|
436
|
-
const
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
667
|
+
loadStyle(urls) {
|
|
668
|
+
urls.forEach((url) => {
|
|
669
|
+
const css = document.createElement("link");
|
|
670
|
+
css.href = url;
|
|
671
|
+
css.rel = "stylesheet";
|
|
672
|
+
css.type = "text/css";
|
|
673
|
+
css.onerror = function() {
|
|
674
|
+
console.error(`Style loading failed for URL: ${url}`);
|
|
675
|
+
};
|
|
676
|
+
document.head.appendChild(css);
|
|
440
677
|
});
|
|
441
678
|
},
|
|
442
679
|
/**
|
|
@@ -447,13 +684,17 @@ const M = {
|
|
|
447
684
|
* @returns 替换后的字符串
|
|
448
685
|
* @throws 当对象中没有找到与占位符对应的值时,抛出错误
|
|
449
686
|
*/
|
|
450
|
-
template(
|
|
451
|
-
const
|
|
452
|
-
return
|
|
453
|
-
const
|
|
454
|
-
if (
|
|
455
|
-
throw new Error(`${
|
|
456
|
-
|
|
687
|
+
template(str, data) {
|
|
688
|
+
const templateRe = /\{ *([\w_-]+) *\}/g;
|
|
689
|
+
return str.replace(templateRe, (match, key) => {
|
|
690
|
+
const value = data[key];
|
|
691
|
+
if (value === void 0) {
|
|
692
|
+
throw new Error(`${ErrorType.JSON_VALUE_ERROR}: ${match}`);
|
|
693
|
+
} else if (typeof value === "function") {
|
|
694
|
+
return value(data);
|
|
695
|
+
} else {
|
|
696
|
+
return value;
|
|
697
|
+
}
|
|
457
698
|
});
|
|
458
699
|
},
|
|
459
700
|
/**
|
|
@@ -462,18 +703,32 @@ const M = {
|
|
|
462
703
|
* @param data 待处理的对象
|
|
463
704
|
* @returns 返回处理后的对象
|
|
464
705
|
*/
|
|
465
|
-
deleteEmptyProperty(
|
|
706
|
+
deleteEmptyProperty(data) {
|
|
466
707
|
return Object.fromEntries(
|
|
467
|
-
Object.keys(
|
|
708
|
+
Object.keys(data).filter((d) => !this.isEmpty(data[d])).map((i) => [i, data[i]])
|
|
468
709
|
);
|
|
469
710
|
},
|
|
470
|
-
deepAssign(
|
|
471
|
-
(typeof
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
711
|
+
deepAssign(target, ...sources) {
|
|
712
|
+
if (typeof target !== "object" || target === null) {
|
|
713
|
+
target = {};
|
|
714
|
+
}
|
|
715
|
+
for (const source of sources) {
|
|
716
|
+
if (typeof source === "object" && source !== null) {
|
|
717
|
+
for (const key in source) {
|
|
718
|
+
if (Object.prototype.hasOwnProperty.call(source, key)) {
|
|
719
|
+
if (typeof source[key] === "object" && source[key] !== null) {
|
|
720
|
+
if (!target[key]) {
|
|
721
|
+
target[key] = Array.isArray(source[key]) ? [] : {};
|
|
722
|
+
}
|
|
723
|
+
this.deepAssign(target[key], source[key]);
|
|
724
|
+
} else {
|
|
725
|
+
target[key] = source[key];
|
|
726
|
+
}
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
}
|
|
730
|
+
}
|
|
731
|
+
return target;
|
|
477
732
|
},
|
|
478
733
|
/**
|
|
479
734
|
* 复制文本到剪贴板
|
|
@@ -481,96 +736,141 @@ const M = {
|
|
|
481
736
|
* @param text 要复制的文本
|
|
482
737
|
* @returns 返回一个Promise,表示复制操作的结果
|
|
483
738
|
*/
|
|
484
|
-
handleCopyValue(
|
|
485
|
-
if (navigator.clipboard && window.isSecureContext)
|
|
486
|
-
return navigator.clipboard.writeText(
|
|
487
|
-
{
|
|
488
|
-
const
|
|
489
|
-
|
|
739
|
+
handleCopyValue(text) {
|
|
740
|
+
if (navigator.clipboard && window.isSecureContext) {
|
|
741
|
+
return navigator.clipboard.writeText(text);
|
|
742
|
+
} else {
|
|
743
|
+
const textArea = document.createElement("textarea");
|
|
744
|
+
textArea.style.position = "fixed";
|
|
745
|
+
textArea.style.top = textArea.style.left = "-100vh";
|
|
746
|
+
textArea.style.opacity = "0";
|
|
747
|
+
textArea.value = text;
|
|
748
|
+
document.body.appendChild(textArea);
|
|
749
|
+
textArea.focus();
|
|
750
|
+
textArea.select();
|
|
751
|
+
return new Promise((resolve, reject) => {
|
|
490
752
|
try {
|
|
491
|
-
document.execCommand("copy")
|
|
492
|
-
|
|
493
|
-
|
|
753
|
+
document.execCommand("copy");
|
|
754
|
+
resolve();
|
|
755
|
+
} catch (error) {
|
|
756
|
+
reject(new Error("copy failed"));
|
|
494
757
|
} finally {
|
|
495
|
-
|
|
758
|
+
textArea.remove();
|
|
496
759
|
}
|
|
497
760
|
});
|
|
498
761
|
}
|
|
499
762
|
},
|
|
500
|
-
isArray(
|
|
501
|
-
return Array.isArray(
|
|
763
|
+
isArray(a) {
|
|
764
|
+
return Array.isArray(a);
|
|
765
|
+
},
|
|
766
|
+
isObject(a) {
|
|
767
|
+
return Object.prototype.toString.call(a).indexOf("Object") > -1;
|
|
768
|
+
},
|
|
769
|
+
isNil(a) {
|
|
770
|
+
return a === void 0 || a === "undefined" || a === null || a === "null";
|
|
502
771
|
},
|
|
503
|
-
|
|
504
|
-
return
|
|
772
|
+
isNumber(a) {
|
|
773
|
+
return typeof a === "number" && !isNaN(a) || typeof a === "string" && Number.isFinite(+a);
|
|
505
774
|
},
|
|
506
|
-
|
|
507
|
-
|
|
775
|
+
isFunction(obj) {
|
|
776
|
+
if (this.isNil(obj)) {
|
|
777
|
+
return false;
|
|
778
|
+
}
|
|
779
|
+
return typeof obj === "function" || obj.constructor !== null && obj.constructor === Function;
|
|
508
780
|
},
|
|
509
|
-
|
|
510
|
-
|
|
781
|
+
/**
|
|
782
|
+
* 判断传入参数是否为DOM元素
|
|
783
|
+
*
|
|
784
|
+
* @param a 待判断的参数
|
|
785
|
+
* @returns 返回布尔值,表示是否为DOM元素
|
|
786
|
+
*/
|
|
787
|
+
isElement(a) {
|
|
788
|
+
return typeof a === "object" && a.nodeType === 1;
|
|
511
789
|
},
|
|
512
|
-
|
|
513
|
-
|
|
790
|
+
/**
|
|
791
|
+
* 检查版本
|
|
792
|
+
*
|
|
793
|
+
* @param currentV 当前版本号
|
|
794
|
+
* @param targetV 要求版本号
|
|
795
|
+
* @returns 返回布尔值,表示当前版本是否需要升级到目标版本
|
|
796
|
+
*/
|
|
797
|
+
checheVersion(currentV, targetV) {
|
|
798
|
+
var numC = currentV.replace(/[^0-9]/gi, "");
|
|
799
|
+
var numT = targetV.replace(/[^0-9]/gi, "");
|
|
800
|
+
return numC < numT;
|
|
514
801
|
}
|
|
515
|
-
}
|
|
516
|
-
|
|
517
|
-
|
|
802
|
+
};
|
|
803
|
+
const ObjectUtil = {
|
|
804
|
+
deepClone(a) {
|
|
805
|
+
return structuredClone(a);
|
|
518
806
|
},
|
|
519
|
-
isEqual(
|
|
520
|
-
return JSON.stringify(
|
|
807
|
+
isEqual(a, b) {
|
|
808
|
+
return JSON.stringify(a) === JSON.stringify(b);
|
|
521
809
|
},
|
|
522
|
-
parse(
|
|
523
|
-
|
|
810
|
+
parse(str) {
|
|
811
|
+
if (!str || !(typeof str === "string")) {
|
|
812
|
+
return str;
|
|
813
|
+
}
|
|
814
|
+
return JSON.parse(str);
|
|
524
815
|
}
|
|
525
816
|
};
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
817
|
+
const myArray = Object.create(Array);
|
|
818
|
+
myArray.groupBy = function(f) {
|
|
819
|
+
var groups = {};
|
|
820
|
+
this.forEach(function(o) {
|
|
821
|
+
var group = JSON.stringify(f(o));
|
|
822
|
+
groups[group] = groups[group] || [];
|
|
823
|
+
groups[group].push(o);
|
|
824
|
+
});
|
|
825
|
+
return Object.keys(groups).map((group) => groups[group]);
|
|
532
826
|
};
|
|
533
|
-
|
|
534
|
-
const
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
827
|
+
myArray.distinct = function(f = (d) => d) {
|
|
828
|
+
const arr = [];
|
|
829
|
+
const obj = {};
|
|
830
|
+
this.forEach((item) => {
|
|
831
|
+
const val = f(item);
|
|
832
|
+
const key = String(val);
|
|
833
|
+
if (!obj[key]) {
|
|
834
|
+
obj[key] = true;
|
|
835
|
+
arr.push(item);
|
|
836
|
+
}
|
|
837
|
+
});
|
|
838
|
+
return arr;
|
|
539
839
|
};
|
|
540
|
-
|
|
840
|
+
myArray.prototype.max = function() {
|
|
541
841
|
return Math.max.apply({}, this);
|
|
542
842
|
};
|
|
543
|
-
|
|
843
|
+
myArray.prototype.min = function() {
|
|
544
844
|
return Math.min.apply({}, this);
|
|
545
845
|
};
|
|
546
|
-
|
|
547
|
-
return this.length > 0 ? this.reduce((
|
|
846
|
+
myArray.sum = function() {
|
|
847
|
+
return this.length > 0 ? this.reduce((prev = 0, curr = 0) => prev + curr) : 0;
|
|
548
848
|
};
|
|
549
|
-
|
|
849
|
+
myArray.avg = function() {
|
|
550
850
|
return this.length ? this.sum() / this.length : 0;
|
|
551
851
|
};
|
|
552
|
-
|
|
553
|
-
return this.sort((
|
|
852
|
+
myArray.desc = function(f = (d) => d) {
|
|
853
|
+
return this.sort((n1, n2) => f(n2) - f(n1));
|
|
554
854
|
};
|
|
555
|
-
|
|
556
|
-
return this.sort((
|
|
855
|
+
myArray.asc = function(f = (d) => d) {
|
|
856
|
+
return this.sort((n1, n2) => f(n1) - f(n2));
|
|
557
857
|
};
|
|
558
|
-
|
|
559
|
-
const
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
return this
|
|
858
|
+
myArray.remove = function(obj) {
|
|
859
|
+
const i = this.indexOf(obj);
|
|
860
|
+
if (i > -1) {
|
|
861
|
+
this.splice(i, 1);
|
|
862
|
+
}
|
|
863
|
+
return this;
|
|
564
864
|
};
|
|
565
|
-
const
|
|
865
|
+
const ArrayUtil = {
|
|
566
866
|
/**
|
|
567
867
|
* 创建指定长度的数组,并返回其索引数组
|
|
568
868
|
*
|
|
569
869
|
* @param length 数组长度
|
|
570
870
|
* @returns 索引数组
|
|
571
871
|
*/
|
|
572
|
-
create(
|
|
573
|
-
return [...new Array(
|
|
872
|
+
create(length) {
|
|
873
|
+
return [...new Array(length).keys()];
|
|
574
874
|
},
|
|
575
875
|
/**
|
|
576
876
|
* 合并多个数组,并去重
|
|
@@ -578,11 +878,14 @@ const S = {
|
|
|
578
878
|
* @param args 需要合并的数组
|
|
579
879
|
* @returns 合并后的去重数组
|
|
580
880
|
*/
|
|
581
|
-
union(...
|
|
582
|
-
let
|
|
583
|
-
|
|
584
|
-
Array.isArray(
|
|
585
|
-
|
|
881
|
+
union(...args) {
|
|
882
|
+
let res = [];
|
|
883
|
+
args.forEach((arg) => {
|
|
884
|
+
if (Array.isArray(arg)) {
|
|
885
|
+
res = res.concat(arg.filter((v) => !res.includes(v)));
|
|
886
|
+
}
|
|
887
|
+
});
|
|
888
|
+
return res;
|
|
586
889
|
},
|
|
587
890
|
/**
|
|
588
891
|
* 求多个数组的交集
|
|
@@ -590,11 +893,14 @@ const S = {
|
|
|
590
893
|
* @param args 多个需要求交集的数组
|
|
591
894
|
* @returns 返回多个数组的交集数组
|
|
592
895
|
*/
|
|
593
|
-
intersection(...
|
|
594
|
-
let
|
|
595
|
-
|
|
596
|
-
Array.isArray(
|
|
597
|
-
|
|
896
|
+
intersection(...args) {
|
|
897
|
+
let res = args[0] || [];
|
|
898
|
+
args.forEach((arg) => {
|
|
899
|
+
if (Array.isArray(arg)) {
|
|
900
|
+
res = res.filter((v) => arg.includes(v));
|
|
901
|
+
}
|
|
902
|
+
});
|
|
903
|
+
return res;
|
|
598
904
|
},
|
|
599
905
|
/**
|
|
600
906
|
* 将多个数组拼接为一个数组,并去除其中的空值。
|
|
@@ -602,8 +908,8 @@ const S = {
|
|
|
602
908
|
* @param args 需要拼接的数组列表。
|
|
603
909
|
* @returns 拼接并去空后的数组。
|
|
604
910
|
*/
|
|
605
|
-
unionAll(...
|
|
606
|
-
return [...
|
|
911
|
+
unionAll(...args) {
|
|
912
|
+
return [...args].flat().filter((d) => !!d);
|
|
607
913
|
},
|
|
608
914
|
/**
|
|
609
915
|
* 求差集
|
|
@@ -611,106 +917,256 @@ const S = {
|
|
|
611
917
|
* @param args 任意个集合
|
|
612
918
|
* @returns 返回差集结果
|
|
613
919
|
*/
|
|
614
|
-
difference(...
|
|
615
|
-
|
|
920
|
+
difference(...args) {
|
|
921
|
+
if (args.length === 0) return [];
|
|
922
|
+
return this.union(...args).filter((d) => !this.intersection(...args).includes(d));
|
|
616
923
|
}
|
|
617
|
-
}
|
|
618
|
-
|
|
924
|
+
};
|
|
925
|
+
const _MqttClient = class _MqttClient extends EventDispatcher {
|
|
926
|
+
constructor(url = `ws://${window.document.domain}:20007/mqtt`, config = {}) {
|
|
619
927
|
super();
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
this
|
|
928
|
+
__publicField(this, "state");
|
|
929
|
+
__publicField(this, "url");
|
|
930
|
+
__publicField(this, "context");
|
|
931
|
+
__publicField(this, "options");
|
|
932
|
+
__publicField(this, "client");
|
|
933
|
+
__publicField(this, "topics");
|
|
934
|
+
this.context = CommUtil.extend(_MqttClient.defaultContext, config);
|
|
935
|
+
this.options = {
|
|
626
936
|
connectTimeout: this.context.MQTT_TIMEOUTM,
|
|
627
|
-
clientId:
|
|
937
|
+
clientId: CommUtil.guid(),
|
|
628
938
|
username: this.context.MQTT_USERNAME,
|
|
629
939
|
password: this.context.MQTT_PASSWORD,
|
|
630
|
-
clean:
|
|
631
|
-
}
|
|
940
|
+
clean: true
|
|
941
|
+
};
|
|
942
|
+
this.url = url;
|
|
943
|
+
this.client = connect(this.url, this.options);
|
|
944
|
+
this._onConnect();
|
|
945
|
+
this._onMessage();
|
|
946
|
+
this.state = 0;
|
|
947
|
+
this.topics = [];
|
|
632
948
|
}
|
|
633
949
|
_onConnect() {
|
|
634
950
|
this.client.on("connect", () => {
|
|
635
|
-
this.state = 1
|
|
636
|
-
|
|
637
|
-
|
|
951
|
+
this.state = 1;
|
|
952
|
+
console.log("链接mqtt成功==>" + this.url);
|
|
953
|
+
this.dispatchEvent({ type: EventType.MQTT_CONNECT, message: this });
|
|
954
|
+
});
|
|
955
|
+
this.client.on("error", (err) => {
|
|
956
|
+
console.log("链接mqtt报错", err);
|
|
957
|
+
this.state = -1;
|
|
958
|
+
this.dispatchEvent({ type: EventType.MQTT_ERROR, message: this });
|
|
959
|
+
this.client.end();
|
|
960
|
+
this.client.reconnect();
|
|
638
961
|
});
|
|
639
962
|
}
|
|
640
963
|
_onMessage() {
|
|
641
|
-
this.client.on("message", (
|
|
642
|
-
let
|
|
643
|
-
|
|
964
|
+
this.client.on("message", (topic, message) => {
|
|
965
|
+
let dataString = message;
|
|
966
|
+
let data = "";
|
|
967
|
+
if (message instanceof Uint8Array) {
|
|
968
|
+
dataString = message.toString();
|
|
969
|
+
}
|
|
644
970
|
try {
|
|
645
|
-
|
|
646
|
-
} catch {
|
|
647
|
-
throw new Error(
|
|
971
|
+
data = ObjectUtil.parse(dataString);
|
|
972
|
+
} catch (error) {
|
|
973
|
+
throw new Error(ErrorType.JSON_PARSE_ERROR);
|
|
648
974
|
}
|
|
649
975
|
this.dispatchEvent({
|
|
650
|
-
type:
|
|
651
|
-
message: { topic
|
|
976
|
+
type: EventType.MQTT_MESSAGE,
|
|
977
|
+
message: { topic, data }
|
|
652
978
|
});
|
|
653
979
|
});
|
|
654
980
|
}
|
|
655
|
-
sendMsg(
|
|
981
|
+
sendMsg(topic, msg) {
|
|
656
982
|
if (!this.client.connected) {
|
|
657
983
|
console.error("客户端未连接");
|
|
658
984
|
return;
|
|
659
985
|
}
|
|
660
|
-
this.client.publish(
|
|
986
|
+
this.client.publish(topic, msg, { qos: 1, retain: true });
|
|
661
987
|
}
|
|
662
|
-
subscribe(
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
}) : this.addEventListener(
|
|
666
|
-
this.client.subscribe(
|
|
667
|
-
|
|
988
|
+
subscribe(topic) {
|
|
989
|
+
this.state === 1 ? this.client.subscribe(topic, { qos: 1 }, (error, e) => {
|
|
990
|
+
error instanceof Error ? console.error("订阅失败==>" + topic, error) : (this.topics = ArrayUtil.union(this.topics, topic), console.log("订阅成功==>" + topic));
|
|
991
|
+
}) : this.addEventListener(EventType.MQTT_CONNECT, (res) => {
|
|
992
|
+
this.client.subscribe(topic, { qos: 1 }, (error, e) => {
|
|
993
|
+
error instanceof Error ? console.error("订阅失败==>" + topic, error) : (this.topics = ArrayUtil.union(this.topics, topic), console.log("订阅成功==>" + topic));
|
|
668
994
|
});
|
|
669
|
-
})
|
|
995
|
+
});
|
|
996
|
+
return this;
|
|
670
997
|
}
|
|
671
|
-
unsubscribe(
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
998
|
+
unsubscribe(topic) {
|
|
999
|
+
this.client.unsubscribe(topic, { qos: 1 }, (error, res) => {
|
|
1000
|
+
if (error instanceof Error) {
|
|
1001
|
+
console.error(`取消订阅失败==>${topic}`, error);
|
|
1002
|
+
} else {
|
|
1003
|
+
this.topics = ArrayUtil.difference(this.topics, topic);
|
|
1004
|
+
console.log(`取消订阅成功==>${topic}`);
|
|
1005
|
+
}
|
|
1006
|
+
});
|
|
1007
|
+
return this;
|
|
675
1008
|
}
|
|
676
1009
|
unsubscribeAll() {
|
|
677
1010
|
this.unsubscribe(this.topics);
|
|
678
1011
|
}
|
|
679
1012
|
unconnect() {
|
|
680
|
-
this.client.end()
|
|
1013
|
+
this.client.end();
|
|
1014
|
+
this.client = null;
|
|
1015
|
+
this.dispatchEvent({ type: EventType.MQTT_CLOSE, message: null });
|
|
1016
|
+
console.log("断开mqtt成功==>" + this.url);
|
|
681
1017
|
}
|
|
682
1018
|
};
|
|
683
1019
|
/**
|
|
684
1020
|
* Creates an instance of MqttClient.
|
|
685
1021
|
* @param {*} config mqtt实例参数
|
|
686
1022
|
*/
|
|
687
|
-
|
|
1023
|
+
__publicField(_MqttClient, "defaultContext", {
|
|
688
1024
|
MQTT_USERNAME: "iRVMS-WEB",
|
|
689
1025
|
MQTT_PASSWORD: "novasky888",
|
|
690
|
-
MQTT_SERVICE: `ws://${window.document.domain}:20007/mqtt`,
|
|
691
1026
|
MQTT_TIMEOUTM: 2e4
|
|
692
1027
|
});
|
|
693
|
-
let
|
|
694
|
-
const
|
|
1028
|
+
let MqttClient = _MqttClient;
|
|
1029
|
+
const _Storage = class _Storage {
|
|
1030
|
+
/**
|
|
1031
|
+
* 将键值对存储到localStorage中
|
|
1032
|
+
*
|
|
1033
|
+
* @param key 键名
|
|
1034
|
+
* @param value 值,默认为null
|
|
1035
|
+
* @param options 存储选项,可选参数
|
|
1036
|
+
* @param options.expires 过期时间,单位为毫秒,默认为null
|
|
1037
|
+
*/
|
|
1038
|
+
static set(key, value = null, options = {}) {
|
|
1039
|
+
var query_key = this._getPrefixedKey(key, options);
|
|
1040
|
+
try {
|
|
1041
|
+
const { expires } = options;
|
|
1042
|
+
const data = { data: value };
|
|
1043
|
+
if (expires) {
|
|
1044
|
+
data.expires = expires;
|
|
1045
|
+
}
|
|
1046
|
+
localStorage.setItem(query_key, JSON.stringify(data));
|
|
1047
|
+
} catch (e) {
|
|
1048
|
+
if (console) console.warn(`Storage didn't successfully save the '{"${key}": "${value}"}' pair, because the localStorage is full.`);
|
|
1049
|
+
}
|
|
1050
|
+
}
|
|
1051
|
+
/**
|
|
1052
|
+
* 从localStorage中获取指定key的存储值
|
|
1053
|
+
*
|
|
1054
|
+
* @param key 存储键名
|
|
1055
|
+
* @param missing 当获取不到指定key的存储值时返回的默认值
|
|
1056
|
+
* @param options 其他配置选项
|
|
1057
|
+
* @returns 返回指定key的存储值,若获取不到则返回missing参数指定的默认值
|
|
1058
|
+
*/
|
|
1059
|
+
static get(key, missing, options) {
|
|
1060
|
+
var query_key = this._getPrefixedKey(key, options), value;
|
|
1061
|
+
try {
|
|
1062
|
+
value = JSON.parse(localStorage.getItem(query_key) || "");
|
|
1063
|
+
} catch (e) {
|
|
1064
|
+
if (localStorage[query_key]) {
|
|
1065
|
+
value = { data: localStorage.getItem(query_key) };
|
|
1066
|
+
} else {
|
|
1067
|
+
value = null;
|
|
1068
|
+
}
|
|
1069
|
+
}
|
|
1070
|
+
if (!value) {
|
|
1071
|
+
return missing;
|
|
1072
|
+
} else if (typeof value === "object" && typeof value.data !== "undefined") {
|
|
1073
|
+
const expires = value.expires;
|
|
1074
|
+
if (expires && Date.now() > expires) {
|
|
1075
|
+
return missing;
|
|
1076
|
+
}
|
|
1077
|
+
return value.data;
|
|
1078
|
+
}
|
|
1079
|
+
}
|
|
1080
|
+
static keys() {
|
|
1081
|
+
const keys = [];
|
|
1082
|
+
var allKeys = Object.keys(localStorage);
|
|
1083
|
+
if (_Storage.prefix.length === 0) {
|
|
1084
|
+
return allKeys;
|
|
1085
|
+
}
|
|
1086
|
+
allKeys.forEach(function(key) {
|
|
1087
|
+
if (key.indexOf(_Storage.prefix) !== -1) {
|
|
1088
|
+
keys.push(key.replace(_Storage.prefix, ""));
|
|
1089
|
+
}
|
|
1090
|
+
});
|
|
1091
|
+
return keys;
|
|
1092
|
+
}
|
|
1093
|
+
static getAll(includeKeys) {
|
|
1094
|
+
var keys = _Storage.keys();
|
|
1095
|
+
if (includeKeys) {
|
|
1096
|
+
const result = [];
|
|
1097
|
+
keys.forEach((key) => {
|
|
1098
|
+
if (includeKeys.includes(key)) {
|
|
1099
|
+
const tempObj = {};
|
|
1100
|
+
tempObj[key] = _Storage.get(key, null, null);
|
|
1101
|
+
result.push(tempObj);
|
|
1102
|
+
}
|
|
1103
|
+
});
|
|
1104
|
+
return result;
|
|
1105
|
+
}
|
|
1106
|
+
return keys.map((key) => _Storage.get(key, null, null));
|
|
1107
|
+
}
|
|
1108
|
+
static remove(key, options) {
|
|
1109
|
+
var queryKey = this._getPrefixedKey(key, options);
|
|
1110
|
+
localStorage.removeItem(queryKey);
|
|
1111
|
+
}
|
|
1112
|
+
static clear(options) {
|
|
1113
|
+
if (_Storage.prefix.length) {
|
|
1114
|
+
this.keys().forEach((key) => {
|
|
1115
|
+
localStorage.removeItem(this._getPrefixedKey(key, options));
|
|
1116
|
+
});
|
|
1117
|
+
} else {
|
|
1118
|
+
localStorage.clear();
|
|
1119
|
+
}
|
|
1120
|
+
}
|
|
1121
|
+
};
|
|
1122
|
+
__publicField(_Storage, "prefix", "");
|
|
1123
|
+
__publicField(_Storage, "_getPrefixedKey", function(key, options) {
|
|
1124
|
+
options = options || {};
|
|
1125
|
+
if (options.noPrefix) {
|
|
1126
|
+
return key;
|
|
1127
|
+
} else {
|
|
1128
|
+
return _Storage.prefix + key;
|
|
1129
|
+
}
|
|
1130
|
+
});
|
|
1131
|
+
let Storage = _Storage;
|
|
1132
|
+
const ImageUtil = {
|
|
695
1133
|
emptyImageUrl: "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7",
|
|
696
1134
|
/**
|
|
697
1135
|
*
|
|
698
1136
|
* @param image image,类型可以是HTMLCanvasElement、ImageData
|
|
699
1137
|
* @returns
|
|
700
1138
|
*/
|
|
701
|
-
getURL(
|
|
702
|
-
let
|
|
703
|
-
if (/^data:/i.test(
|
|
704
|
-
return
|
|
705
|
-
|
|
706
|
-
if (
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
1139
|
+
getURL(image) {
|
|
1140
|
+
let _canvas;
|
|
1141
|
+
if (/^data:/i.test(image.src)) {
|
|
1142
|
+
return image.src;
|
|
1143
|
+
}
|
|
1144
|
+
if (typeof HTMLCanvasElement === "undefined") {
|
|
1145
|
+
return image.src;
|
|
1146
|
+
}
|
|
1147
|
+
let canvas;
|
|
1148
|
+
if (image instanceof HTMLCanvasElement) {
|
|
1149
|
+
canvas = image;
|
|
1150
|
+
} else {
|
|
1151
|
+
if (_canvas === void 0) _canvas = document.createElementNS("http://www.w3.org/1999/xhtml", "canvas");
|
|
1152
|
+
_canvas.width = image.width;
|
|
1153
|
+
_canvas.height = image.height;
|
|
1154
|
+
const context = _canvas.getContext("2d");
|
|
1155
|
+
if (context) {
|
|
1156
|
+
if (image instanceof ImageData) {
|
|
1157
|
+
context.putImageData(image, 0, 0);
|
|
1158
|
+
} else {
|
|
1159
|
+
context.drawImage(image, 0, 0, image.width, image.height);
|
|
1160
|
+
}
|
|
1161
|
+
}
|
|
1162
|
+
canvas = _canvas;
|
|
1163
|
+
}
|
|
1164
|
+
if (canvas.width > 2048 || canvas.height > 2048) {
|
|
1165
|
+
console.warn("ImageUtil.getDataURL: Image converted to jpg for performance reasons", image);
|
|
1166
|
+
return canvas.toDataURL("image/jpeg", 0.6);
|
|
1167
|
+
} else {
|
|
1168
|
+
return canvas.toDataURL("image/png");
|
|
712
1169
|
}
|
|
713
|
-
return n.width > 2048 || n.height > 2048 ? (console.warn("ImageUtil.getDataURL: Image converted to jpg for performance reasons", t), n.toDataURL("image/jpeg", 0.6)) : n.toDataURL("image/png");
|
|
714
1170
|
},
|
|
715
1171
|
/**
|
|
716
1172
|
* 将图片的URL转换为Base64编码
|
|
@@ -720,13 +1176,16 @@ const $ = {
|
|
|
720
1176
|
* @param height 图片的高度,默认为图片原始高度
|
|
721
1177
|
* @returns 返回Promise对象,解析后得到包含Base64编码数据的对象
|
|
722
1178
|
*/
|
|
723
|
-
getBase64(
|
|
724
|
-
return new Promise((
|
|
725
|
-
let
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
1179
|
+
getBase64(url) {
|
|
1180
|
+
return new Promise((resolve, reject) => {
|
|
1181
|
+
let image = new Image();
|
|
1182
|
+
image.setAttribute("crossOrigin", "Anonymous");
|
|
1183
|
+
image.src = url;
|
|
1184
|
+
image.onload = () => {
|
|
1185
|
+
let dataURL = this.getURL(image);
|
|
1186
|
+
resolve(dataURL);
|
|
1187
|
+
};
|
|
1188
|
+
image.onerror = reject;
|
|
730
1189
|
});
|
|
731
1190
|
},
|
|
732
1191
|
/**
|
|
@@ -735,13 +1194,17 @@ const $ = {
|
|
|
735
1194
|
* @param base64 base64编码字符串
|
|
736
1195
|
* @returns 返回一个对象,包含type(类型)、ext(扩展名)和data(数据)字段,如果解析失败则返回null
|
|
737
1196
|
*/
|
|
738
|
-
parseBase64(
|
|
739
|
-
let
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
1197
|
+
parseBase64(base64) {
|
|
1198
|
+
let re = new RegExp("data:(?<type>.*?);base64,(?<data>.*)");
|
|
1199
|
+
let res = re.exec(base64);
|
|
1200
|
+
if (res && res.groups) {
|
|
1201
|
+
return {
|
|
1202
|
+
type: res.groups.type,
|
|
1203
|
+
ext: res.groups.type.split("/").slice(-1)[0],
|
|
1204
|
+
data: res.groups.data
|
|
1205
|
+
};
|
|
1206
|
+
}
|
|
1207
|
+
return null;
|
|
745
1208
|
},
|
|
746
1209
|
/**
|
|
747
1210
|
* 复制图片到剪贴板
|
|
@@ -750,33 +1213,51 @@ const $ = {
|
|
|
750
1213
|
* @returns 无返回值
|
|
751
1214
|
* @throws 如果解析base64数据失败,则抛出异常
|
|
752
1215
|
*/
|
|
753
|
-
async copyImage(
|
|
1216
|
+
async copyImage(url) {
|
|
754
1217
|
try {
|
|
755
|
-
const
|
|
756
|
-
|
|
1218
|
+
const base64Result = await this.getBase64(url);
|
|
1219
|
+
const parsedBase64 = this.parseBase64(base64Result.dataURL);
|
|
1220
|
+
if (!parsedBase64) {
|
|
757
1221
|
throw new Error("Failed to parse base64 data.");
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
let
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
1222
|
+
}
|
|
1223
|
+
let type = parsedBase64.type;
|
|
1224
|
+
let bytes = atob(parsedBase64.data);
|
|
1225
|
+
let ab = new ArrayBuffer(bytes.length);
|
|
1226
|
+
let ua = new Uint8Array(ab);
|
|
1227
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
1228
|
+
ua[i] = bytes.charCodeAt(i);
|
|
1229
|
+
}
|
|
1230
|
+
let blob = new Blob([ab], { type });
|
|
1231
|
+
await navigator.clipboard.write([new ClipboardItem({ [type]: blob })]);
|
|
1232
|
+
} catch (error) {
|
|
1233
|
+
console.error("Failed to copy image to clipboard:", error);
|
|
765
1234
|
}
|
|
766
1235
|
}
|
|
767
|
-
}
|
|
1236
|
+
};
|
|
1237
|
+
const AjaxUtil = {
|
|
768
1238
|
/**
|
|
769
1239
|
* Get JSON data by jsonp
|
|
770
1240
|
* @param url - resource url
|
|
771
1241
|
* @param callback - callback function when completed
|
|
772
1242
|
*/
|
|
773
|
-
jsonp(
|
|
774
|
-
const
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
1243
|
+
jsonp(url, callback) {
|
|
1244
|
+
const name = "_jsonp_" + CommUtil.guid();
|
|
1245
|
+
const head = document.getElementsByTagName("head")[0];
|
|
1246
|
+
if (url.includes("?")) {
|
|
1247
|
+
url += "&callback=" + name;
|
|
1248
|
+
} else {
|
|
1249
|
+
url += "?callback=" + name;
|
|
1250
|
+
}
|
|
1251
|
+
let script = document.createElement("script");
|
|
1252
|
+
script.type = "text/javascript";
|
|
1253
|
+
script.src = url;
|
|
1254
|
+
window[name] = function(data) {
|
|
1255
|
+
callback(null, data);
|
|
1256
|
+
head.removeChild(script);
|
|
1257
|
+
script = null;
|
|
1258
|
+
delete window[name];
|
|
1259
|
+
};
|
|
1260
|
+
head.appendChild(script);
|
|
780
1261
|
},
|
|
781
1262
|
/**
|
|
782
1263
|
* Fetch remote resource by HTTP "GET" method
|
|
@@ -798,18 +1279,25 @@ const $ = {
|
|
|
798
1279
|
* }
|
|
799
1280
|
* );
|
|
800
1281
|
*/
|
|
801
|
-
get(
|
|
802
|
-
if (
|
|
803
|
-
const
|
|
804
|
-
|
|
1282
|
+
get(url, options, cb) {
|
|
1283
|
+
if (CommUtil.isFunction(options)) {
|
|
1284
|
+
const t = cb;
|
|
1285
|
+
cb = options;
|
|
1286
|
+
options = t;
|
|
805
1287
|
}
|
|
806
|
-
const
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
1288
|
+
const client = this._getClient(cb);
|
|
1289
|
+
client.open("GET", url, true);
|
|
1290
|
+
if (options) {
|
|
1291
|
+
for (const k in options.headers) {
|
|
1292
|
+
client.setRequestHeader(k, options.headers[k]);
|
|
1293
|
+
}
|
|
1294
|
+
client.withCredentials = options.credentials === "include";
|
|
1295
|
+
if (options["responseType"]) {
|
|
1296
|
+
client.responseType = options["responseType"];
|
|
1297
|
+
}
|
|
811
1298
|
}
|
|
812
|
-
|
|
1299
|
+
client.send(null);
|
|
1300
|
+
return client;
|
|
813
1301
|
},
|
|
814
1302
|
/**
|
|
815
1303
|
* Fetch remote resource by HTTP "POST" method
|
|
@@ -836,38 +1324,81 @@ const $ = {
|
|
|
836
1324
|
* }
|
|
837
1325
|
* );
|
|
838
1326
|
*/
|
|
839
|
-
post(
|
|
840
|
-
let
|
|
841
|
-
if (typeof
|
|
1327
|
+
post(url, options = {}, cb) {
|
|
1328
|
+
let postData;
|
|
1329
|
+
if (typeof url !== "string") {
|
|
1330
|
+
cb = options.cb;
|
|
1331
|
+
postData = options.postData;
|
|
1332
|
+
options = { ...options };
|
|
1333
|
+
delete options.cb;
|
|
1334
|
+
delete options.postData;
|
|
1335
|
+
url = options.url;
|
|
1336
|
+
} else {
|
|
1337
|
+
if (typeof options === "function") {
|
|
1338
|
+
cb = options;
|
|
1339
|
+
options = {};
|
|
1340
|
+
}
|
|
1341
|
+
postData = options.postData;
|
|
1342
|
+
}
|
|
1343
|
+
if (!cb) {
|
|
842
1344
|
throw new Error("Callback function is required");
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
1345
|
+
}
|
|
1346
|
+
const client = this._getClient(cb);
|
|
1347
|
+
client.open("POST", url, true);
|
|
1348
|
+
options.headers = options.headers || {};
|
|
1349
|
+
if (!options.headers["Content-Type"]) {
|
|
1350
|
+
options.headers["Content-Type"] = "application/x-www-form-urlencoded";
|
|
1351
|
+
}
|
|
1352
|
+
Object.keys(options.headers).forEach((key) => {
|
|
1353
|
+
client.setRequestHeader(key, options.headers[key]);
|
|
1354
|
+
});
|
|
1355
|
+
if (typeof postData !== "string") {
|
|
1356
|
+
postData = JSON.stringify(postData);
|
|
1357
|
+
}
|
|
1358
|
+
client.send(postData);
|
|
1359
|
+
return client;
|
|
847
1360
|
},
|
|
848
|
-
_wrapCallback(
|
|
1361
|
+
_wrapCallback(client, cb) {
|
|
849
1362
|
return function() {
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
1363
|
+
if (client.readyState === 4) {
|
|
1364
|
+
if (client.status === 200) {
|
|
1365
|
+
if (client.responseType === "arraybuffer") {
|
|
1366
|
+
const response = client.response;
|
|
1367
|
+
if (response.byteLength === 0) {
|
|
1368
|
+
cb(new Error("http status 200 returned without content."));
|
|
1369
|
+
} else {
|
|
1370
|
+
cb(null, {
|
|
1371
|
+
data: client.response,
|
|
1372
|
+
cacheControl: client.getResponseHeader("Cache-Control"),
|
|
1373
|
+
expires: client.getResponseHeader("Expires"),
|
|
1374
|
+
contentType: client.getResponseHeader("Content-Type")
|
|
1375
|
+
});
|
|
1376
|
+
}
|
|
1377
|
+
} else {
|
|
1378
|
+
cb(null, client.responseText);
|
|
1379
|
+
}
|
|
1380
|
+
} else {
|
|
1381
|
+
cb(new Error(client.statusText + "," + client.status));
|
|
1382
|
+
}
|
|
1383
|
+
}
|
|
856
1384
|
};
|
|
857
1385
|
},
|
|
858
|
-
_getClient(
|
|
859
|
-
let
|
|
1386
|
+
_getClient(cb) {
|
|
1387
|
+
let client = null;
|
|
860
1388
|
try {
|
|
861
|
-
|
|
862
|
-
} catch {
|
|
1389
|
+
client = new XMLHttpRequest();
|
|
1390
|
+
} catch (e) {
|
|
863
1391
|
throw new Error("XMLHttpRequest not supported.");
|
|
864
1392
|
}
|
|
865
|
-
|
|
1393
|
+
if (client) {
|
|
1394
|
+
client.onreadystatechange = this._wrapCallback(client, cb);
|
|
1395
|
+
}
|
|
1396
|
+
return client;
|
|
866
1397
|
},
|
|
867
1398
|
/**
|
|
868
1399
|
* Fetch resource as arraybuffer.
|
|
869
1400
|
* @param {String} url - url
|
|
870
|
-
* @param {Object} [options=null] - options, same as
|
|
1401
|
+
* @param {Object} [options=null] - options, same as AjaxUtil.get
|
|
871
1402
|
* @param {Function} cb - callback function when completed.
|
|
872
1403
|
* @example
|
|
873
1404
|
* AjaxUtil.getArrayBuffer(
|
|
@@ -880,24 +1411,37 @@ const $ = {
|
|
|
880
1411
|
* }
|
|
881
1412
|
* );
|
|
882
1413
|
*/
|
|
883
|
-
getArrayBuffer(
|
|
884
|
-
if (
|
|
885
|
-
const
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
1414
|
+
getArrayBuffer(url, options, cb) {
|
|
1415
|
+
if (CommUtil.isFunction(options)) {
|
|
1416
|
+
const t = cb;
|
|
1417
|
+
cb = options;
|
|
1418
|
+
options = t;
|
|
1419
|
+
}
|
|
1420
|
+
if (!options) {
|
|
1421
|
+
options = {};
|
|
1422
|
+
}
|
|
1423
|
+
options["responseType"] = "arraybuffer";
|
|
1424
|
+
return this.get(url, options, cb);
|
|
1425
|
+
},
|
|
1426
|
+
getImage(img, url, options) {
|
|
1427
|
+
return this.getArrayBuffer(url, options, (err, imgData) => {
|
|
1428
|
+
if (err) {
|
|
1429
|
+
if (img.onerror) {
|
|
1430
|
+
img.onerror(err);
|
|
1431
|
+
}
|
|
1432
|
+
} else if (imgData) {
|
|
1433
|
+
const URL2 = window.URL || window.webkitURL;
|
|
1434
|
+
const onload = img.onload;
|
|
1435
|
+
img.onload = () => {
|
|
1436
|
+
if (onload) {
|
|
1437
|
+
onload();
|
|
1438
|
+
}
|
|
1439
|
+
URL2.revokeObjectURL(img.src);
|
|
898
1440
|
};
|
|
899
|
-
const
|
|
900
|
-
|
|
1441
|
+
const blob = new Blob([new Uint8Array(imgData.data)], { type: imgData.contentType });
|
|
1442
|
+
img.cacheControl = imgData.cacheControl;
|
|
1443
|
+
img.expires = imgData.expires;
|
|
1444
|
+
img.src = imgData.data.byteLength ? URL2.createObjectURL(blob) : ImageUtil.emptyImageUrl;
|
|
901
1445
|
}
|
|
902
1446
|
});
|
|
903
1447
|
},
|
|
@@ -920,537 +1464,549 @@ const $ = {
|
|
|
920
1464
|
* }
|
|
921
1465
|
* );
|
|
922
1466
|
*/
|
|
923
|
-
getJSON(
|
|
924
|
-
if (
|
|
925
|
-
const
|
|
926
|
-
|
|
1467
|
+
getJSON(url, options, cb) {
|
|
1468
|
+
if (CommUtil.isFunction(options)) {
|
|
1469
|
+
const t = cb;
|
|
1470
|
+
cb = options;
|
|
1471
|
+
options = t;
|
|
927
1472
|
}
|
|
928
|
-
const
|
|
929
|
-
const
|
|
930
|
-
|
|
1473
|
+
const callback = function(err, resp) {
|
|
1474
|
+
const data = resp ? ObjectUtil.parse(resp) : null;
|
|
1475
|
+
if (cb) {
|
|
1476
|
+
cb(err, data);
|
|
1477
|
+
}
|
|
931
1478
|
};
|
|
932
|
-
|
|
1479
|
+
if (options && options["jsonp"]) {
|
|
1480
|
+
return this.jsonp(url, callback);
|
|
1481
|
+
}
|
|
1482
|
+
return this.get(url, options, callback);
|
|
933
1483
|
}
|
|
934
|
-
}
|
|
1484
|
+
};
|
|
1485
|
+
const GeoUtil = {
|
|
1486
|
+
toRadian: Math.PI / 180,
|
|
1487
|
+
R: 6371393,
|
|
935
1488
|
/**
|
|
936
|
-
*
|
|
1489
|
+
* 判断给定的经纬度是否合法
|
|
937
1490
|
*
|
|
938
|
-
* @
|
|
1491
|
+
* @param lng 经度值
|
|
1492
|
+
* @param lat 纬度值
|
|
1493
|
+
* @returns 如果经纬度合法,返回true;否则返回false
|
|
939
1494
|
*/
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
return t.indexOf("MSIE") >= 0 || /Trident\//.test(t) ? "IE" : t.indexOf("Firefox") >= 0 ? "Firefox" : t.indexOf("Chrome") >= 0 ? "Chrome" : t.indexOf("Opera") >= 0 ? "Opera" : t.indexOf("Safari") >= 0 && t.indexOf("Chrome") === -1 ? "Safari" : "Unknown";
|
|
1495
|
+
isLnglat(lng, lat) {
|
|
1496
|
+
return !isNaN(lng) && !isNaN(lat) && !!(+lat > -90 && +lat < 90 && +lng > -180 && +lng < 180);
|
|
943
1497
|
},
|
|
944
1498
|
/**
|
|
945
|
-
*
|
|
1499
|
+
* 计算两哥平面坐标点间的距离
|
|
946
1500
|
*
|
|
947
|
-
* @
|
|
1501
|
+
* @param p1 坐标点1,包含x和y属性
|
|
1502
|
+
* @param p2 坐标点2,包含x和y属性
|
|
1503
|
+
* @returns 返回两点间的欧几里得距离
|
|
948
1504
|
*/
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
const e = navigator.userAgent.indexOf("Windows", 0) != -1 ? 1 : 0, n = navigator.userAgent.indexOf("mac", 0) != -1 ? 1 : 0, r = navigator.userAgent.indexOf("Linux", 0) != -1 ? 1 : 0, i = navigator.userAgent.indexOf("X11", 0) != -1 ? 1 : 0;
|
|
952
|
-
return e ? t = "MS Windows" : n ? t = "Apple mac" : r ? t = "Linux" : i && (t = "Unix"), t;
|
|
1505
|
+
distance(p1, p2) {
|
|
1506
|
+
return Math.sqrt(Math.pow(p2.x - p1.x, 2) + Math.pow(p2.y - p1.y, 2));
|
|
953
1507
|
},
|
|
954
1508
|
/**
|
|
955
|
-
*
|
|
1509
|
+
* 计算两个经纬度点之间的距离
|
|
956
1510
|
*
|
|
957
|
-
* @param
|
|
1511
|
+
* @param A 经纬度点A,包含lng(经度)和lat(纬度)两个属性
|
|
1512
|
+
* @param B 经纬度点B,包含lng(经度)和lat(纬度)两个属性
|
|
1513
|
+
* @returns 返回两点之间的距离,单位为米
|
|
958
1514
|
*/
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
1515
|
+
distanceByPoints(A, B) {
|
|
1516
|
+
const { lng: lngA, lat: latA } = A;
|
|
1517
|
+
const { lng: lngB, lat: latB } = B;
|
|
1518
|
+
const earthR = 6371e3;
|
|
1519
|
+
const x = Math.cos(latA * Math.PI / 180) * Math.cos(latB * Math.PI / 180) * Math.cos((lngA - lngB) * Math.PI / 180);
|
|
1520
|
+
const y = Math.sin(latA * Math.PI / 180) * Math.sin(latB * Math.PI / 180);
|
|
1521
|
+
let s = x + y;
|
|
1522
|
+
if (s > 1) s = 1;
|
|
1523
|
+
if (s < -1) s = -1;
|
|
1524
|
+
const alpha = Math.acos(s);
|
|
1525
|
+
const distance = alpha * earthR;
|
|
1526
|
+
return distance;
|
|
965
1527
|
},
|
|
966
1528
|
/**
|
|
967
|
-
*
|
|
1529
|
+
* 格式化经纬度为度分秒格式
|
|
968
1530
|
*
|
|
969
|
-
* @
|
|
1531
|
+
* @param lng 经度
|
|
1532
|
+
* @param lat 纬度
|
|
1533
|
+
* @returns 返回格式化后的经纬度字符串,格式为:经度度分秒,纬度度分秒
|
|
970
1534
|
*/
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
1535
|
+
formatLnglat(lng, lat) {
|
|
1536
|
+
let res = "";
|
|
1537
|
+
function formatDegreeToDMS(valueInDegrees) {
|
|
1538
|
+
const degree = Math.floor(valueInDegrees);
|
|
1539
|
+
const minutes = Math.floor((valueInDegrees - degree) * 60);
|
|
1540
|
+
const seconds = (valueInDegrees - degree) * 3600 - minutes * 60;
|
|
1541
|
+
return `${degree}°${minutes}′${seconds.toFixed(2)}″`;
|
|
1542
|
+
}
|
|
1543
|
+
if (this.isLnglat(lng, lat)) {
|
|
1544
|
+
res = formatDegreeToDMS(lng) + "," + formatDegreeToDMS(lat);
|
|
1545
|
+
} else if (!isNaN(lng)) {
|
|
1546
|
+
res = formatDegreeToDMS(lng);
|
|
1547
|
+
} else if (!isNaN(lat)) {
|
|
1548
|
+
res = formatDegreeToDMS(lat);
|
|
1549
|
+
}
|
|
1550
|
+
return res;
|
|
977
1551
|
},
|
|
978
1552
|
/**
|
|
979
|
-
*
|
|
1553
|
+
* 将经纬度字符串转换为度
|
|
980
1554
|
*
|
|
981
|
-
* @
|
|
1555
|
+
* @param lng 经度字符串
|
|
1556
|
+
* @param lat 纬度字符串
|
|
1557
|
+
* @returns 转换后的经纬度对象
|
|
982
1558
|
*/
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
}
|
|
1002
|
-
}, Y = {
|
|
1003
|
-
PI: 3.141592653589793,
|
|
1004
|
-
XPI: 3.141592653589793 * 3e3 / 180,
|
|
1005
|
-
delta(t, e) {
|
|
1006
|
-
const r = 0.006693421622965943;
|
|
1007
|
-
let i = this.transformLat(e - 105, t - 35), o = this.transformLon(e - 105, t - 35);
|
|
1008
|
-
const a = t / 180 * this.PI;
|
|
1009
|
-
let c = Math.sin(a);
|
|
1010
|
-
c = 1 - r * c * c;
|
|
1011
|
-
const l = Math.sqrt(c);
|
|
1012
|
-
return i = i * 180 / (6378245 * (1 - r) / (c * l) * this.PI), o = o * 180 / (6378245 / l * Math.cos(a) * this.PI), { lat: i, lng: o };
|
|
1559
|
+
transformLnglat(lng, lat) {
|
|
1560
|
+
function dms2deg(dmsString) {
|
|
1561
|
+
const isNegative = /[sw]/i.test(dmsString);
|
|
1562
|
+
let factor = isNegative ? -1 : 1;
|
|
1563
|
+
const numericParts = dmsString.match(/[\d.]+/g) || [];
|
|
1564
|
+
let degrees = 0;
|
|
1565
|
+
for (let i = 0; i < numericParts.length; i++) {
|
|
1566
|
+
degrees += parseFloat(numericParts[i]) / factor;
|
|
1567
|
+
factor *= 60;
|
|
1568
|
+
}
|
|
1569
|
+
return degrees;
|
|
1570
|
+
}
|
|
1571
|
+
if (lng && lat) {
|
|
1572
|
+
return {
|
|
1573
|
+
lng: dms2deg(lng),
|
|
1574
|
+
lat: dms2deg(lat)
|
|
1575
|
+
};
|
|
1576
|
+
}
|
|
1013
1577
|
},
|
|
1014
1578
|
/**
|
|
1015
|
-
*
|
|
1579
|
+
* 射线法判断点是否在多边形内
|
|
1016
1580
|
*
|
|
1017
|
-
* @param
|
|
1018
|
-
* @param
|
|
1019
|
-
* @returns
|
|
1581
|
+
* @param p 点对象,包含x和y属性
|
|
1582
|
+
* @param poly 多边形顶点数组,可以是字符串数组或对象数组
|
|
1583
|
+
* @returns 返回字符串,表示点相对于多边形的位置:'in'表示在多边形内,'out'表示在多边形外,'on'表示在多边形上
|
|
1020
1584
|
*/
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
},
|
|
1038
|
-
// GCJ-02 to WGS-84 exactly
|
|
1039
|
-
gcjDecryptExact(t, e) {
|
|
1040
|
-
let i = 0.01, o = 0.01, a = t - i, c = e - o, l = t + i, u = e + o, h = 0, d = 0, f = 0;
|
|
1041
|
-
for (; ; ) {
|
|
1042
|
-
h = (a + l) / 2, d = (c + u) / 2;
|
|
1043
|
-
const m = this.gcjEncrypt(h, d);
|
|
1044
|
-
if (i = m.lat - t, o = m.lng - e, Math.abs(i) < 1e-9 && Math.abs(o) < 1e-9 || (i > 0 ? l = h : a = h, o > 0 ? u = d : c = d, ++f > 1e4)) break;
|
|
1585
|
+
rayCasting(p, poly) {
|
|
1586
|
+
var px = p.x, py = p.y, flag = false;
|
|
1587
|
+
for (var i = 0, l = poly.length, j = l - 1; i < l; j = i, i++) {
|
|
1588
|
+
var sx = poly[i].x, sy = poly[i].y, tx = poly[j].x, ty = poly[j].y;
|
|
1589
|
+
if (sx === px && sy === py || tx === px && ty === py) {
|
|
1590
|
+
return "on";
|
|
1591
|
+
}
|
|
1592
|
+
if (sy < py && ty >= py || sy >= py && ty < py) {
|
|
1593
|
+
var x = sx + (py - sy) * (tx - sx) / (ty - sy);
|
|
1594
|
+
if (x === px) {
|
|
1595
|
+
return "on";
|
|
1596
|
+
}
|
|
1597
|
+
if (x > px) {
|
|
1598
|
+
flag = !flag;
|
|
1599
|
+
}
|
|
1600
|
+
}
|
|
1045
1601
|
}
|
|
1046
|
-
return
|
|
1047
|
-
},
|
|
1048
|
-
// GCJ-02 to BD-09
|
|
1049
|
-
bdEncrypt(t, e) {
|
|
1050
|
-
const n = e, r = t, i = Math.sqrt(n * n + r * r) + 2e-5 * Math.sin(r * this.XPI), o = Math.atan2(r, n) + 3e-6 * Math.cos(n * this.XPI), a = i * Math.cos(o) + 65e-4;
|
|
1051
|
-
return { lat: i * Math.sin(o) + 6e-3, lng: a };
|
|
1602
|
+
return flag ? "in" : "out";
|
|
1052
1603
|
},
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
// Web mercator to WGS-84
|
|
1066
|
-
// mercatorLat -> y mercatorLon -> x
|
|
1067
|
-
mercatorDecrypt(t, e) {
|
|
1068
|
-
const n = e / 2003750834e-2 * 180;
|
|
1069
|
-
let r = t / 2003750834e-2 * 180;
|
|
1070
|
-
return r = 180 / this.PI * (2 * Math.atan(Math.exp(r * this.PI / 180)) - this.PI / 2), { lat: r, lng: n };
|
|
1071
|
-
},
|
|
1072
|
-
transformLat(t, e) {
|
|
1073
|
-
let n = -100 + 2 * t + 3 * e + 0.2 * e * e + 0.1 * t * e + 0.2 * Math.sqrt(Math.abs(t));
|
|
1074
|
-
return n += (20 * Math.sin(6 * t * this.PI) + 20 * Math.sin(2 * t * this.PI)) * 2 / 3, n += (20 * Math.sin(e * this.PI) + 40 * Math.sin(e / 3 * this.PI)) * 2 / 3, n += (160 * Math.sin(e / 12 * this.PI) + 320 * Math.sin(e * this.PI / 30)) * 2 / 3, n;
|
|
1604
|
+
/**
|
|
1605
|
+
* 旋转点
|
|
1606
|
+
*
|
|
1607
|
+
* @param p1 旋转前点坐标
|
|
1608
|
+
* @param p2 旋转中心坐标
|
|
1609
|
+
* @param θ 旋转角度(顺时针旋转为正)
|
|
1610
|
+
* @returns 旋转后点坐标
|
|
1611
|
+
*/
|
|
1612
|
+
rotatePoint(p1, p2, θ) {
|
|
1613
|
+
const x = (p1.x - p2.x) * Math.cos(Math.PI / 180 * -θ) - (p1.y - p2.y) * Math.sin(Math.PI / 180 * -θ) + p2.x;
|
|
1614
|
+
const y = (p1.x - p2.x) * Math.sin(Math.PI / 180 * -θ) + (p1.y - p2.y) * Math.cos(Math.PI / 180 * -θ) + p2.y;
|
|
1615
|
+
return { x, y };
|
|
1075
1616
|
},
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1617
|
+
/**
|
|
1618
|
+
* 根据两个平面坐标点计算方位角和距离
|
|
1619
|
+
*
|
|
1620
|
+
* @param p1 第一个点的坐标对象
|
|
1621
|
+
* @param p2 第二个点的坐标对象
|
|
1622
|
+
* @returns 返回一个对象,包含angle和distance属性,分别表示两点之间的角度(以度为单位,取值范围为0~359)和距离
|
|
1623
|
+
*/
|
|
1624
|
+
calcBearAndDis(p1, p2) {
|
|
1625
|
+
const { x: x1, y: y1 } = p1;
|
|
1626
|
+
const { x: x2, y: y2 } = p2;
|
|
1627
|
+
const dx = x2 - x1;
|
|
1628
|
+
const dy = y2 - y1;
|
|
1629
|
+
const distance = Math.sqrt(dx * dx + dy * dy);
|
|
1630
|
+
const angleInRadians = Math.atan2(dy, dx);
|
|
1631
|
+
const angle = (angleInRadians * (180 / Math.PI) + 360 + 90) % 360;
|
|
1632
|
+
return { angle, distance };
|
|
1079
1633
|
},
|
|
1080
1634
|
/**
|
|
1081
|
-
*
|
|
1635
|
+
* 根据两个经纬度点计算方位角和距离
|
|
1082
1636
|
*
|
|
1083
|
-
* @param
|
|
1084
|
-
* @param
|
|
1085
|
-
* @returns
|
|
1637
|
+
* @param latlng1 第一个经纬度点
|
|
1638
|
+
* @param latlng2 第二个经纬度点
|
|
1639
|
+
* @returns 包含方位角和距离的对象
|
|
1086
1640
|
*/
|
|
1087
|
-
|
|
1641
|
+
calcBearAndDisByPoints(latlng1, latlng2) {
|
|
1642
|
+
var f1 = latlng1.lat * 1, l1 = latlng1.lng * 1, f2 = latlng2.lat * 1, l2 = latlng2.lng * 1;
|
|
1643
|
+
var y = Math.sin((l2 - l1) * this.toRadian) * Math.cos(f2 * this.toRadian);
|
|
1644
|
+
var x = Math.cos(f1 * this.toRadian) * Math.sin(f2 * this.toRadian) - Math.sin(f1 * this.toRadian) * Math.cos(f2 * this.toRadian) * Math.cos((l2 - l1) * this.toRadian);
|
|
1645
|
+
var angle = Math.atan2(y, x) * (180 / Math.PI);
|
|
1646
|
+
var deltaF = (f2 - f1) * this.toRadian;
|
|
1647
|
+
var deltaL = (l2 - l1) * this.toRadian;
|
|
1648
|
+
var a = Math.sin(deltaF / 2) * Math.sin(deltaF / 2) + Math.cos(f1 * this.toRadian) * Math.cos(f2 * this.toRadian) * Math.sin(deltaL / 2) * Math.sin(deltaL / 2);
|
|
1649
|
+
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
|
|
1650
|
+
var distance = this.R * c;
|
|
1088
1651
|
return {
|
|
1089
|
-
|
|
1090
|
-
|
|
1652
|
+
angle,
|
|
1653
|
+
distance
|
|
1091
1654
|
};
|
|
1092
1655
|
},
|
|
1093
|
-
deCompose(t, e, n) {
|
|
1094
|
-
if (!Array.isArray(t))
|
|
1095
|
-
return n ? e.call(n, t) : e(t);
|
|
1096
|
-
const r = [];
|
|
1097
|
-
let i, o;
|
|
1098
|
-
for (let a = 0, c = t.length; a < c; a++) {
|
|
1099
|
-
if (i = t[a], M.isNil(i)) {
|
|
1100
|
-
r.push(null);
|
|
1101
|
-
continue;
|
|
1102
|
-
}
|
|
1103
|
-
Array.isArray(i) ? r.push(this.deCompose(i, e, n)) : (o = n ? e.call(n, i) : e(i), r.push(o));
|
|
1104
|
-
}
|
|
1105
|
-
return r;
|
|
1106
|
-
}
|
|
1107
|
-
}, z = {
|
|
1108
|
-
random() {
|
|
1109
|
-
let t = Math.floor(Math.random() * 256).toString(16), e = Math.floor(Math.random() * 256).toString(16), n = Math.floor(Math.random() * 256).toString(16);
|
|
1110
|
-
return t = t.length === 1 ? "0" + t : t, e = e.length === 1 ? "0" + e : e, n = n.length === 1 ? "0" + n : n, "#" + t + e + n;
|
|
1111
|
-
},
|
|
1112
1656
|
/**
|
|
1113
|
-
*
|
|
1657
|
+
* 计算点P到线段P1P2的最短距离
|
|
1114
1658
|
*
|
|
1115
|
-
* @param
|
|
1116
|
-
* @
|
|
1659
|
+
* @param p 点P的坐标
|
|
1660
|
+
* @param p1 线段起点P1的坐标
|
|
1661
|
+
* @param p2 线段终点P2的坐标
|
|
1662
|
+
* @returns 点P到线段P1P2的最短距离
|
|
1117
1663
|
*/
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1664
|
+
distanceToSegment(p, p1, p2) {
|
|
1665
|
+
const x = p.x, y = p.y, x1 = p1.x, y1 = p1.y, x2 = p2.x, y2 = p2.y;
|
|
1666
|
+
const cross = (x2 - x1) * (x - x1) + (y2 - y1) * (y - y1);
|
|
1667
|
+
if (cross <= 0) {
|
|
1668
|
+
return Math.sqrt((x - x1) * (x - x1) + (y - y1) * (y - y1));
|
|
1669
|
+
}
|
|
1670
|
+
const d2 = (x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1);
|
|
1671
|
+
if (cross >= d2) {
|
|
1672
|
+
return Math.sqrt((x - x2) * (x - x2) + (y - y2) * (y - y2));
|
|
1673
|
+
}
|
|
1674
|
+
const r = cross / d2;
|
|
1675
|
+
const px = x1 + (x2 - x1) * r;
|
|
1676
|
+
const py = y1 + (y2 - y1) * r;
|
|
1677
|
+
return Math.sqrt((x - px) * (x - px) + (y - py) * (y - py));
|
|
1121
1678
|
},
|
|
1122
1679
|
/**
|
|
1123
|
-
*
|
|
1680
|
+
* 根据给定的经纬度、角度和距离计算新的经纬度点
|
|
1124
1681
|
*
|
|
1125
|
-
* @param
|
|
1126
|
-
* @
|
|
1682
|
+
* @param latlng 给定的经纬度点,类型为LngLat
|
|
1683
|
+
* @param angle 角度值,单位为度,表示从当前点出发的方向
|
|
1684
|
+
* @param distance 距离值,单位为米,表示从当前点出发的距离
|
|
1685
|
+
* @returns 返回计算后的新经纬度点,类型为{lat: number, lng: number}
|
|
1127
1686
|
*/
|
|
1128
|
-
|
|
1129
|
-
const
|
|
1130
|
-
|
|
1687
|
+
calcPointByBearAndDis(latlng, angle, distance) {
|
|
1688
|
+
const sLat = MathUtils.deg2Rad(latlng.lat * 1);
|
|
1689
|
+
const sLng = MathUtils.deg2Rad(latlng.lng * 1);
|
|
1690
|
+
const d = distance / this.R;
|
|
1691
|
+
angle = MathUtils.deg2Rad(angle);
|
|
1692
|
+
const lat = Math.asin(Math.sin(sLat) * Math.cos(d) + Math.cos(sLat) * Math.sin(d) * Math.cos(angle));
|
|
1693
|
+
const lon = sLng + Math.atan2(Math.sin(angle) * Math.sin(d) * Math.cos(sLat), Math.cos(d) - Math.sin(sLat) * Math.sin(lat));
|
|
1694
|
+
return {
|
|
1695
|
+
lat: MathUtils.rad2Deg(lat),
|
|
1696
|
+
lng: MathUtils.rad2Deg(lon)
|
|
1697
|
+
};
|
|
1131
1698
|
},
|
|
1132
1699
|
/**
|
|
1133
|
-
*
|
|
1700
|
+
* 将墨卡托坐标转换为经纬度坐标
|
|
1134
1701
|
*
|
|
1135
|
-
* @param
|
|
1136
|
-
* @
|
|
1702
|
+
* @param x 墨卡托坐标的x值
|
|
1703
|
+
* @param y 墨卡托坐标的y值
|
|
1704
|
+
* @returns 返回包含转换后的经度lng和纬度lat的对象
|
|
1137
1705
|
*/
|
|
1138
|
-
|
|
1139
|
-
const
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
return `rgba(${o},${a},${c},1)`;
|
|
1706
|
+
mercatorTolonlat(x, y) {
|
|
1707
|
+
const lng = x / 2003750834e-2 * 180;
|
|
1708
|
+
var mmy = y / 2003750834e-2 * 180;
|
|
1709
|
+
const lat = 180 / Math.PI * (2 * Math.atan(Math.exp(mmy * Math.PI / 180)) - Math.PI / 2);
|
|
1710
|
+
return { lng, lat };
|
|
1144
1711
|
},
|
|
1145
1712
|
/**
|
|
1146
|
-
*
|
|
1713
|
+
* 将经纬度坐标转换为墨卡托坐标
|
|
1147
1714
|
*
|
|
1148
|
-
* @param
|
|
1149
|
-
* @
|
|
1715
|
+
* @param lng 经度值
|
|
1716
|
+
* @param lat 纬度值
|
|
1717
|
+
* @returns 墨卡托坐标对象,包含x和y属性
|
|
1150
1718
|
*/
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
const n = parseInt(e[1], 10) / 360, r = parseInt(e[2], 10) / 100, i = parseInt(e[3], 10) / 100, o = e[4] ? parseFloat(e[4]) : 1;
|
|
1158
|
-
function a(h, d, f) {
|
|
1159
|
-
return f < 0 && (f += 1), f > 1 && (f -= 1), f < 1 / 6 ? h + (d - h) * 6 * f : f < 1 / 2 ? d : f < 2 / 3 ? h + (d - h) * (2 / 3 - f) * 6 : h;
|
|
1160
|
-
}
|
|
1161
|
-
let c, l, u;
|
|
1162
|
-
if (r === 0)
|
|
1163
|
-
c = l = u = i;
|
|
1164
|
-
else {
|
|
1165
|
-
const h = i < 0.5 ? i * (1 + r) : i + r - i * r, d = 2 * i - h;
|
|
1166
|
-
c = a(d, h, n + 1 / 3), l = a(d, h, n), u = a(d, h, n - 1 / 3);
|
|
1167
|
-
}
|
|
1168
|
-
return `rgba(${Math.round(c * 255)},${Math.round(l * 255)},${Math.round(u * 255)},${o})`;
|
|
1169
|
-
},
|
|
1170
|
-
isHex(t) {
|
|
1171
|
-
return /(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)/i.test(t);
|
|
1172
|
-
},
|
|
1173
|
-
isRgb(t) {
|
|
1174
|
-
return /^rgb/.test(t);
|
|
1175
|
-
},
|
|
1176
|
-
isHsl(t) {
|
|
1177
|
-
return /^hsl/.test(t);
|
|
1178
|
-
},
|
|
1179
|
-
isColor(t) {
|
|
1180
|
-
return this.isHex(t) || this.isRgb(t) || this.isHsl(t);
|
|
1181
|
-
},
|
|
1182
|
-
colorToRgb(t) {
|
|
1183
|
-
if (this.isRgb(t)) return this.rgbToRgba(t);
|
|
1184
|
-
if (this.isHex(t)) return this.hexToRgba(t);
|
|
1185
|
-
if (this.isHsl(t)) return this.hslToRgba(t);
|
|
1186
|
-
}
|
|
1187
|
-
};
|
|
1188
|
-
Date.prototype.format = function(t) {
|
|
1189
|
-
const e = {
|
|
1190
|
-
"M+": this.getMonth() + 1,
|
|
1191
|
-
// 月份
|
|
1192
|
-
"d+": this.getDate(),
|
|
1193
|
-
// 日
|
|
1194
|
-
"h+": this.getHours() % 12,
|
|
1195
|
-
// 小时
|
|
1196
|
-
"H+": this.getHours(),
|
|
1197
|
-
// 小时 (24小时制)
|
|
1198
|
-
"m+": this.getMinutes(),
|
|
1199
|
-
// 分
|
|
1200
|
-
"s+": this.getSeconds(),
|
|
1201
|
-
// 秒
|
|
1202
|
-
"q+": Math.floor((this.getMonth() + 3) / 3),
|
|
1203
|
-
// 季度
|
|
1204
|
-
S: this.getMilliseconds()
|
|
1205
|
-
// 毫秒
|
|
1206
|
-
};
|
|
1207
|
-
/(y+)/.test(t) && (t = t.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length)));
|
|
1208
|
-
for (const n in e)
|
|
1209
|
-
if (new RegExp("(" + n + ")").test(t)) {
|
|
1210
|
-
const r = n.length === 1 ? 1 : Number(n.slice(1));
|
|
1211
|
-
t = t.replace(RegExp.$1, ("00" + e[n]).substr(("" + e[n]).length + r - (e[n] + "").length));
|
|
1212
|
-
}
|
|
1213
|
-
return t;
|
|
1214
|
-
};
|
|
1215
|
-
Date.prototype.addDate = function(t, e) {
|
|
1216
|
-
const n = new Date(this);
|
|
1217
|
-
switch (t) {
|
|
1218
|
-
case "y":
|
|
1219
|
-
n.setFullYear(this.getFullYear() + e);
|
|
1220
|
-
break;
|
|
1221
|
-
case "q":
|
|
1222
|
-
n.setMonth(this.getMonth() + e * 3);
|
|
1223
|
-
break;
|
|
1224
|
-
case "M":
|
|
1225
|
-
n.setMonth(this.getMonth() + e);
|
|
1226
|
-
break;
|
|
1227
|
-
case "w":
|
|
1228
|
-
n.setDate(this.getDate() + e * 7);
|
|
1229
|
-
break;
|
|
1230
|
-
case "d":
|
|
1231
|
-
n.setDate(this.getDate() + e);
|
|
1232
|
-
break;
|
|
1233
|
-
case "h":
|
|
1234
|
-
n.setHours(this.getHours() + e);
|
|
1235
|
-
break;
|
|
1236
|
-
case "m":
|
|
1237
|
-
n.setMinutes(this.getMinutes() + e);
|
|
1238
|
-
break;
|
|
1239
|
-
case "s":
|
|
1240
|
-
n.setSeconds(this.getSeconds() + e);
|
|
1241
|
-
break;
|
|
1242
|
-
default:
|
|
1243
|
-
n.setDate(this.getDate() + e);
|
|
1244
|
-
break;
|
|
1245
|
-
}
|
|
1246
|
-
return n;
|
|
1247
|
-
};
|
|
1248
|
-
const X = {
|
|
1249
|
-
lastMonthDate: new Date((/* @__PURE__ */ new Date()).getFullYear(), (/* @__PURE__ */ new Date()).getMonth() - 1, 1),
|
|
1250
|
-
thisMonthDate: new Date((/* @__PURE__ */ new Date()).getFullYear(), (/* @__PURE__ */ new Date()).getMonth(), 1),
|
|
1251
|
-
nextMonthDate: new Date((/* @__PURE__ */ new Date()).getFullYear(), (/* @__PURE__ */ new Date()).getMonth() + 1, 1),
|
|
1252
|
-
lastWeekDate: new Date((/* @__PURE__ */ new Date()).getFullYear(), (/* @__PURE__ */ new Date()).getMonth(), (/* @__PURE__ */ new Date()).getDate() + 1 - 7 - (/* @__PURE__ */ new Date()).getDay()),
|
|
1253
|
-
thisWeekDate: new Date((/* @__PURE__ */ new Date()).getFullYear(), (/* @__PURE__ */ new Date()).getMonth(), (/* @__PURE__ */ new Date()).getDate() + 1 - (/* @__PURE__ */ new Date()).getDay()),
|
|
1254
|
-
nextWeekDate: new Date((/* @__PURE__ */ new Date()).getFullYear(), (/* @__PURE__ */ new Date()).getMonth(), (/* @__PURE__ */ new Date()).getDate() + 1 + 7 - (/* @__PURE__ */ new Date()).getDay()),
|
|
1255
|
-
lastDayDate: new Date((/* @__PURE__ */ new Date()).getFullYear(), (/* @__PURE__ */ new Date()).getMonth(), (/* @__PURE__ */ new Date()).getDate() - 1),
|
|
1256
|
-
thisDayDate: new Date((/* @__PURE__ */ new Date()).setHours(0, 0, 0, 0)),
|
|
1257
|
-
nextDayDate: new Date((/* @__PURE__ */ new Date()).getFullYear(), (/* @__PURE__ */ new Date()).getMonth(), (/* @__PURE__ */ new Date()).getDate() + 1),
|
|
1258
|
-
parseDate(t) {
|
|
1259
|
-
if (typeof t == "string") {
|
|
1260
|
-
var e = t.match(/^ *(\d{4})-(\d{1,2})-(\d{1,2}) *$/);
|
|
1261
|
-
if (e && e.length > 3) return new Date(parseInt(e[1]), parseInt(e[2]) - 1, parseInt(e[3]));
|
|
1262
|
-
if (e = t.match(/^ *(\d{4})-(\d{1,2})-(\d{1,2}) +(\d{1,2}):(\d{1,2}):(\d{1,2}) *$/), e && e.length > 6)
|
|
1263
|
-
return new Date(
|
|
1264
|
-
parseInt(e[1]),
|
|
1265
|
-
parseInt(e[2]) - 1,
|
|
1266
|
-
parseInt(e[3]),
|
|
1267
|
-
parseInt(e[4]),
|
|
1268
|
-
parseInt(e[5]),
|
|
1269
|
-
parseInt(e[6])
|
|
1270
|
-
);
|
|
1271
|
-
if (e = t.match(/^ *(\d{4})-(\d{1,2})-(\d{1,2}) +(\d{1,2}):(\d{1,2}):(\d{1,2})\.(\d{1,9}) *$/), e && e.length > 7)
|
|
1272
|
-
return new Date(
|
|
1273
|
-
parseInt(e[1]),
|
|
1274
|
-
parseInt(e[2]) - 1,
|
|
1275
|
-
parseInt(e[3]),
|
|
1276
|
-
parseInt(e[4]),
|
|
1277
|
-
parseInt(e[5]),
|
|
1278
|
-
parseInt(e[6]),
|
|
1279
|
-
parseInt(e[7])
|
|
1280
|
-
);
|
|
1281
|
-
}
|
|
1282
|
-
return null;
|
|
1719
|
+
lonlatToMercator(lng, lat) {
|
|
1720
|
+
var earthRad = 6378137;
|
|
1721
|
+
const x = lng * Math.PI / 180 * earthRad;
|
|
1722
|
+
var a = lat * Math.PI / 180;
|
|
1723
|
+
const y = earthRad / 2 * Math.log((1 + Math.sin(a)) / (1 - Math.sin(a)));
|
|
1724
|
+
return { x, y };
|
|
1283
1725
|
},
|
|
1284
1726
|
/**
|
|
1285
|
-
*
|
|
1727
|
+
* 根据百分比获取坐标
|
|
1286
1728
|
*
|
|
1287
|
-
* @param
|
|
1288
|
-
* @param
|
|
1289
|
-
* @
|
|
1729
|
+
* @param start 起点坐标
|
|
1730
|
+
* @param end 终点坐标
|
|
1731
|
+
* @param percent 百分比,取值范围0-1
|
|
1732
|
+
* @returns 返回插值后的坐标
|
|
1290
1733
|
*/
|
|
1291
|
-
|
|
1292
|
-
const
|
|
1293
|
-
|
|
1294
|
-
return o > 0 && (f += o + "天"), c > 0 && (f += c + "时"), u > 0 && (f += u + "分"), d > 0 && (f += d + "秒"), o === 0 && c === 0 && u === 0 && d === 0 && (f = "少于1秒"), f;
|
|
1295
|
-
},
|
|
1296
|
-
formatterCounter(t) {
|
|
1297
|
-
const e = function(c) {
|
|
1298
|
-
return (c > 10 ? "" : "0") + (c || 0);
|
|
1299
|
-
}, n = e(Math.floor(t / 3600)), r = t % 3600, i = e(Math.floor(r / 60)), o = r % 60, a = e(Math.round(o));
|
|
1300
|
-
return `${n}:${i}:${a}`;
|
|
1301
|
-
},
|
|
1302
|
-
sleep(t) {
|
|
1734
|
+
interpolate({ x: x1, y: y1, z: z1 = 0 }, { x: x2, y: y2, z: z2 = 0 }, percent) {
|
|
1735
|
+
const dx = x2 - x1, dy = y2 - y1, dz = z2 - z1;
|
|
1736
|
+
return { x: x1 + dx * percent, y: y1 + dy * percent, z: z1 + dz * percent };
|
|
1303
1737
|
}
|
|
1304
1738
|
};
|
|
1305
|
-
|
|
1306
|
-
return t.trim ? t.trim() : t.replace(/^\s+|\s+$/g, "");
|
|
1307
|
-
}
|
|
1308
|
-
function D(t) {
|
|
1309
|
-
return q(t).split(/\s+/);
|
|
1310
|
-
}
|
|
1311
|
-
const V = {
|
|
1739
|
+
const StringUtil = {
|
|
1312
1740
|
/**
|
|
1313
|
-
*
|
|
1741
|
+
* 校验字符串是否符合指定类型
|
|
1314
1742
|
*
|
|
1315
|
-
* @param
|
|
1316
|
-
* @param
|
|
1317
|
-
*
|
|
1743
|
+
* @param str 待校验字符串
|
|
1744
|
+
* @param type 校验类型,可选值包括:
|
|
1745
|
+
* - 'phone': 手机号码
|
|
1746
|
+
* - 'tel': 座机
|
|
1747
|
+
* - 'card': 身份证
|
|
1748
|
+
* - 'pwd': 密码(以字母开头,长度在6~18之间,只能包含字母、数字和下划线)
|
|
1749
|
+
* - 'postal': 邮政编码
|
|
1750
|
+
* - 'QQ': QQ号
|
|
1751
|
+
* - 'email': 邮箱
|
|
1752
|
+
* - 'money': 金额(小数点2位)
|
|
1753
|
+
* - 'URL': 网址
|
|
1754
|
+
* - 'IP': IP地址
|
|
1755
|
+
* - 'date': 日期时间
|
|
1756
|
+
* - 'number': 数字
|
|
1757
|
+
* - 'english': 英文
|
|
1758
|
+
* - 'chinese': 中文
|
|
1759
|
+
* - 'lower': 小写字母
|
|
1760
|
+
* - 'upper': 大写字母
|
|
1761
|
+
* - 'HTML': HTML标记
|
|
1762
|
+
* @returns 校验结果,符合返回true,否则返回false
|
|
1318
1763
|
*/
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1764
|
+
checkStr(str, type) {
|
|
1765
|
+
switch (type) {
|
|
1766
|
+
case "phone":
|
|
1767
|
+
return /^1[3|4|5|6|7|8|9][0-9]{9}$/.test(str);
|
|
1768
|
+
case "tel":
|
|
1769
|
+
return /^(0\d{2,3}-\d{7,8})(-\d{1,4})?$/.test(str);
|
|
1770
|
+
case "card":
|
|
1771
|
+
return /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/.test(str);
|
|
1772
|
+
case "pwd":
|
|
1773
|
+
return /^[a-zA-Z]\w{5,17}$/.test(str);
|
|
1774
|
+
case "postal":
|
|
1775
|
+
return /[1-9]\d{5}(?!\d)/.test(str);
|
|
1776
|
+
case "QQ":
|
|
1777
|
+
return /^[1-9][0-9]{4,9}$/.test(str);
|
|
1778
|
+
case "email":
|
|
1779
|
+
return /^[\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)+$/.test(str);
|
|
1780
|
+
case "money":
|
|
1781
|
+
return /^\d*(?:\.\d{0,2})?$/.test(str);
|
|
1782
|
+
case "URL":
|
|
1783
|
+
return /(http|ftp|https):\/\/[\w\-_]+(\.[\w\-_]+)+([\w\-\.,@?^=%&:/~\+#]*[\w\-\@?^=%&/~\+#])?/.test(str);
|
|
1784
|
+
case "IP":
|
|
1785
|
+
return /((?:(?:25[0-5]|2[0-4]\\d|[01]?\\d?\\d)\\.){3}(?:25[0-5]|2[0-4]\\d|[01]?\\d?\\d))/.test(str);
|
|
1786
|
+
case "date":
|
|
1787
|
+
return /^(\d{4})\-(\d{2})\-(\d{2}) (\d{2})(?:\:\d{2}|:(\d{2}):(\d{2}))$/.test(str) || /^(\d{4})\-(\d{2})\-(\d{2})$/.test(str);
|
|
1788
|
+
case "number":
|
|
1789
|
+
return /^[0-9]$/.test(str);
|
|
1790
|
+
case "english":
|
|
1791
|
+
return /^[a-zA-Z]+$/.test(str);
|
|
1792
|
+
case "chinese":
|
|
1793
|
+
return /^[\u4E00-\u9FA5]+$/.test(str);
|
|
1794
|
+
case "lower":
|
|
1795
|
+
return /^[a-z]+$/.test(str);
|
|
1796
|
+
case "upper":
|
|
1797
|
+
return /^[A-Z]+$/.test(str);
|
|
1798
|
+
case "HTML":
|
|
1799
|
+
return /<("[^"]*"|'[^']*'|[^'">])*>/.test(str);
|
|
1800
|
+
default:
|
|
1801
|
+
return true;
|
|
1325
1802
|
}
|
|
1326
|
-
return n;
|
|
1327
|
-
},
|
|
1328
|
-
/**
|
|
1329
|
-
* 创建一个HTML元素
|
|
1330
|
-
*
|
|
1331
|
-
* @param tagName 元素标签名
|
|
1332
|
-
* @param className 元素类名
|
|
1333
|
-
* @param container 父容器,若传入,则新创建的元素会被添加到该容器中
|
|
1334
|
-
* @returns 返回新创建的HTML元素
|
|
1335
|
-
*/
|
|
1336
|
-
create(t, e, n) {
|
|
1337
|
-
const r = document.createElement(t);
|
|
1338
|
-
return r.className = e || "", n && n.appendChild(r), r;
|
|
1339
1803
|
},
|
|
1340
1804
|
/**
|
|
1341
|
-
*
|
|
1805
|
+
* 转换字符串大小写
|
|
1342
1806
|
*
|
|
1343
|
-
* @param
|
|
1807
|
+
* @param str 待转换的字符串
|
|
1808
|
+
* @param type 转换类型,可选值为 1-5,默认为 4
|
|
1809
|
+
* 1:首字母大写,其余小写
|
|
1810
|
+
* 2:首字母小写,其余大写
|
|
1811
|
+
* 3:字母大小写反转
|
|
1812
|
+
* 4:全部大写
|
|
1813
|
+
* 5:全部小写
|
|
1814
|
+
* @returns 转换后的字符串
|
|
1344
1815
|
*/
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1816
|
+
changeCase(str, type) {
|
|
1817
|
+
type = type || 4;
|
|
1818
|
+
switch (type) {
|
|
1819
|
+
case 1:
|
|
1820
|
+
return str.replace(/\b\w+\b/g, function(word) {
|
|
1821
|
+
return word.substring(0, 1).toUpperCase() + word.substring(1).toLowerCase();
|
|
1822
|
+
});
|
|
1823
|
+
case 2:
|
|
1824
|
+
return str.replace(/\b\w+\b/g, function(word) {
|
|
1825
|
+
return word.substring(0, 1).toLowerCase() + word.substring(1).toUpperCase();
|
|
1826
|
+
});
|
|
1827
|
+
case 3:
|
|
1828
|
+
return str.split("").map(function(word) {
|
|
1829
|
+
if (/[a-z]/.test(word)) {
|
|
1830
|
+
return word.toUpperCase();
|
|
1831
|
+
} else {
|
|
1832
|
+
return word.toLowerCase();
|
|
1833
|
+
}
|
|
1834
|
+
}).join("");
|
|
1835
|
+
case 4:
|
|
1836
|
+
return str.toUpperCase();
|
|
1837
|
+
case 5:
|
|
1838
|
+
return str.toLowerCase();
|
|
1839
|
+
default:
|
|
1840
|
+
return str;
|
|
1841
|
+
}
|
|
1348
1842
|
},
|
|
1349
1843
|
/**
|
|
1350
|
-
*
|
|
1844
|
+
* 根据字符串数组和参数生成新的字符串
|
|
1351
1845
|
*
|
|
1352
|
-
* @param
|
|
1846
|
+
* @param strArray 字符串数组
|
|
1847
|
+
* @param args 可变参数列表,支持 Object、Array 类型和任意其他类型,若为 null 或 undefined,则按类型默认转换为 '{}'、'[]' 或 ''
|
|
1848
|
+
* @returns 返回生成的新字符串
|
|
1353
1849
|
*/
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1850
|
+
tag(strArray, ...args) {
|
|
1851
|
+
args = args.map((val) => {
|
|
1852
|
+
switch (CommUtil.getDataType(val)) {
|
|
1853
|
+
case "Object":
|
|
1854
|
+
return val || "{}";
|
|
1855
|
+
case "Array":
|
|
1856
|
+
return val || "[]";
|
|
1857
|
+
default:
|
|
1858
|
+
return val || "";
|
|
1859
|
+
}
|
|
1860
|
+
});
|
|
1861
|
+
return strArray.reduce((prev, next, index) => `${prev}${args[index - 1]}${next}`);
|
|
1357
1862
|
},
|
|
1358
1863
|
/**
|
|
1359
|
-
*
|
|
1864
|
+
* 计算字符串的字节长度
|
|
1360
1865
|
*
|
|
1361
|
-
* @param
|
|
1866
|
+
* @param str 需要计算字节长度的字符串
|
|
1867
|
+
* @returns 返回字符串的字节长度
|
|
1362
1868
|
*/
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
e && e.lastChild !== t && e.appendChild(t);
|
|
1869
|
+
getByteLength(str) {
|
|
1870
|
+
return str.replace(/[\u0391-\uFFE5]/g, "aa").length;
|
|
1366
1871
|
},
|
|
1367
1872
|
/**
|
|
1368
|
-
*
|
|
1873
|
+
* 截取字符串中指定字节长度的子串
|
|
1369
1874
|
*
|
|
1370
|
-
* @param
|
|
1875
|
+
* @param str 字符串对象,包含replace、length和substring方法
|
|
1876
|
+
* @param start 截取起始位置
|
|
1877
|
+
* @param n 截取字节长度
|
|
1878
|
+
* @returns 返回截取后的子串
|
|
1371
1879
|
*/
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1880
|
+
subStringByte(str, start, n) {
|
|
1881
|
+
var r = /[^\x00-\xff]/g;
|
|
1882
|
+
if (str.replace(r, "mm").length <= n) {
|
|
1883
|
+
return str;
|
|
1884
|
+
}
|
|
1885
|
+
var m = Math.floor(n / 2);
|
|
1886
|
+
for (var i = m; i < str.length; i++) {
|
|
1887
|
+
let sub = str.substring(start, i);
|
|
1888
|
+
if (sub.replace(r, "mm").length >= n) {
|
|
1889
|
+
return sub;
|
|
1890
|
+
}
|
|
1891
|
+
}
|
|
1892
|
+
return str;
|
|
1893
|
+
}
|
|
1894
|
+
};
|
|
1895
|
+
const ColorUtil = {
|
|
1896
|
+
random() {
|
|
1897
|
+
let r = Math.floor(Math.random() * 256).toString(16);
|
|
1898
|
+
let g = Math.floor(Math.random() * 256).toString(16);
|
|
1899
|
+
let b = Math.floor(Math.random() * 256).toString(16);
|
|
1900
|
+
r = r.length === 1 ? "0" + r : r;
|
|
1901
|
+
g = g.length === 1 ? "0" + g : g;
|
|
1902
|
+
b = b.length === 1 ? "0" + b : b;
|
|
1903
|
+
return "#" + r + g + b;
|
|
1375
1904
|
},
|
|
1376
1905
|
/**
|
|
1377
|
-
*
|
|
1906
|
+
* 将RGB颜色值转换为十六进制颜色值
|
|
1378
1907
|
*
|
|
1379
|
-
* @param
|
|
1380
|
-
* @
|
|
1381
|
-
* @param el.className 类名对象
|
|
1382
|
-
* @param el.className.baseVal 类名字符串
|
|
1383
|
-
* @returns 返回元素的类名字符串
|
|
1908
|
+
* @param rgb RGB颜色值数组,包含三个0-255之间的整数
|
|
1909
|
+
* @returns 转换后的十六进制颜色值,以#开头
|
|
1384
1910
|
*/
|
|
1385
|
-
|
|
1386
|
-
|
|
1911
|
+
rgb2hex(rgb) {
|
|
1912
|
+
var hex = "#" + ((1 << 24) + (rgb[0] << 16) + (rgb[1] << 8) + rgb[2]).toString(16).slice(1);
|
|
1913
|
+
return hex;
|
|
1387
1914
|
},
|
|
1388
1915
|
/**
|
|
1389
|
-
*
|
|
1916
|
+
* 将RGB颜色值转换为RGBA颜色值,并返回转换后的颜色值。
|
|
1390
1917
|
*
|
|
1391
|
-
* @param
|
|
1392
|
-
* @
|
|
1393
|
-
* @returns 返回一个布尔值,表示元素是否包含指定类名
|
|
1918
|
+
* @param rgbValue RGB颜色值,格式为"rgb(r, g, b)"。
|
|
1919
|
+
* @returns 转换后的RGBA颜色值,格式为"rgba(r, g, b, 1)"。如果输入值不符合RGB格式,则返回原值。
|
|
1394
1920
|
*/
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
return !0;
|
|
1399
|
-
const n = this.getClass(t);
|
|
1400
|
-
return n.length > 0 && new RegExp(`(^|\\s)${e}(\\s|$)`).test(n);
|
|
1921
|
+
rgbToRgba(rgbValue) {
|
|
1922
|
+
const rgb = /rgb\((\d+,\s*[\d]+,\s*[\d]+)\)/g.exec(rgbValue);
|
|
1923
|
+
return rgb ? `rgba(${rgb[1]}, 1)` : rgbValue;
|
|
1401
1924
|
},
|
|
1402
1925
|
/**
|
|
1403
|
-
*
|
|
1926
|
+
* 将十六进制颜色值转换为rgba格式的颜色值
|
|
1404
1927
|
*
|
|
1405
|
-
* @param
|
|
1406
|
-
* @
|
|
1928
|
+
* @param hexValue 十六进制颜色值,可带或不带#前缀,支持3位和6位表示
|
|
1929
|
+
* @returns 返回rgba格式的颜色值,格式为rgba(r,g,b,1)
|
|
1407
1930
|
*/
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
this.setClass(t, (n ? n + " " : "") + e);
|
|
1931
|
+
hexToRgba(hexValue) {
|
|
1932
|
+
const rgxShort = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
|
|
1933
|
+
const hex = hexValue.replace(rgxShort, (m, r2, g2, b2) => r2 + r2 + g2 + g2 + b2 + b2);
|
|
1934
|
+
const rgx = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i;
|
|
1935
|
+
const rgb = rgx.exec(hex);
|
|
1936
|
+
if (!rgb) {
|
|
1937
|
+
return hexValue;
|
|
1416
1938
|
}
|
|
1939
|
+
const r = parseInt(rgb[1], 16);
|
|
1940
|
+
const g = parseInt(rgb[2], 16);
|
|
1941
|
+
const b = parseInt(rgb[3], 16);
|
|
1942
|
+
return `rgba(${r},${g},${b},1)`;
|
|
1417
1943
|
},
|
|
1418
1944
|
/**
|
|
1419
|
-
*
|
|
1945
|
+
* 将 HSL 颜色值转换为 RGBA 颜色值
|
|
1420
1946
|
*
|
|
1421
|
-
* @param
|
|
1422
|
-
* @
|
|
1947
|
+
* @param hslValue HSL 颜色值字符串,格式为 "hsl(h, s%, l%)" 或 "hsla(h, s%, l%, a)",其中 h 为色相,s 为饱和度,l 为亮度,a 为透明度(可选)。
|
|
1948
|
+
* @returns 转换后的 RGBA 颜色值字符串,格式为 "rgba(r, g, b, a)",其中 r、g、b 为红绿蓝分量,a 为透明度。若输入为空或无效,则返回 null。
|
|
1423
1949
|
*/
|
|
1424
|
-
|
|
1425
|
-
|
|
1950
|
+
hslToRgba(hslValue) {
|
|
1951
|
+
if (!hslValue) {
|
|
1952
|
+
return null;
|
|
1953
|
+
}
|
|
1954
|
+
const hsl = /hsl\((\d+),\s*([\d.]+)%,\s*([\d.]+)%\)/g.exec(hslValue) || /hsla\((\d+),\s*([\d.]+)%,\s*([\d.]+)%,\s*([\d.]+)\)/g.exec(hslValue);
|
|
1955
|
+
if (!hsl) {
|
|
1956
|
+
return null;
|
|
1957
|
+
}
|
|
1958
|
+
const h = parseInt(hsl[1], 10) / 360;
|
|
1959
|
+
const s = parseInt(hsl[2], 10) / 100;
|
|
1960
|
+
const l = parseInt(hsl[3], 10) / 100;
|
|
1961
|
+
const a = hsl[4] ? parseFloat(hsl[4]) : 1;
|
|
1962
|
+
function hue2rgb(p, q, t) {
|
|
1963
|
+
if (t < 0) t += 1;
|
|
1964
|
+
if (t > 1) t -= 1;
|
|
1965
|
+
if (t < 1 / 6) return p + (q - p) * 6 * t;
|
|
1966
|
+
if (t < 1 / 2) return q;
|
|
1967
|
+
if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
|
|
1968
|
+
return p;
|
|
1969
|
+
}
|
|
1970
|
+
let r, g, b;
|
|
1971
|
+
if (s === 0) {
|
|
1972
|
+
r = g = b = l;
|
|
1973
|
+
} else {
|
|
1974
|
+
const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
|
|
1975
|
+
const p = 2 * l - q;
|
|
1976
|
+
r = hue2rgb(p, q, h + 1 / 3);
|
|
1977
|
+
g = hue2rgb(p, q, h);
|
|
1978
|
+
b = hue2rgb(p, q, h - 1 / 3);
|
|
1979
|
+
}
|
|
1980
|
+
return `rgba(${Math.round(r * 255)},${Math.round(g * 255)},${Math.round(b * 255)},${a})`;
|
|
1426
1981
|
},
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
*
|
|
1430
|
-
* @param el HTML 或 SVG 元素
|
|
1431
|
-
* @param name 要设置的类名,多个类名之间用空格分隔
|
|
1432
|
-
*/
|
|
1433
|
-
setClass(t, e) {
|
|
1434
|
-
"classList" in t && (t.classList.value = "", e.split(" ").forEach((n) => t.classList.add(n)));
|
|
1982
|
+
isHex(a) {
|
|
1983
|
+
return /(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)/i.test(a);
|
|
1435
1984
|
},
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
return
|
|
1985
|
+
isRgb(a) {
|
|
1986
|
+
return /^rgb/.test(a);
|
|
1987
|
+
},
|
|
1988
|
+
isHsl(a) {
|
|
1989
|
+
return /^hsl/.test(a);
|
|
1990
|
+
},
|
|
1991
|
+
isColor(a) {
|
|
1992
|
+
return this.isHex(a) || this.isRgb(a) || this.isHsl(a);
|
|
1993
|
+
},
|
|
1994
|
+
colorToRgb(val) {
|
|
1995
|
+
if (this.isRgb(val)) return this.rgbToRgba(val);
|
|
1996
|
+
if (this.isHex(val)) return this.hexToRgba(val);
|
|
1997
|
+
if (this.isHsl(val)) return this.hslToRgba(val);
|
|
1444
1998
|
}
|
|
1445
|
-
}
|
|
1999
|
+
};
|
|
2000
|
+
const TYPES = ["Point", "MultiPoint", "LineString", "MultiLineString", "Polygon", "MultiPolygon"];
|
|
2001
|
+
const GeoJsonUtil = {
|
|
1446
2002
|
/**
|
|
1447
2003
|
* 获取GeoJSON要素的几何类型
|
|
1448
2004
|
*
|
|
1449
2005
|
* @param feature GeoJSONFeature 类型的要素
|
|
1450
2006
|
* @returns 返回要素的几何类型,如果要素没有几何属性则返回 null
|
|
1451
2007
|
*/
|
|
1452
|
-
getGeoJsonType(
|
|
1453
|
-
return
|
|
2008
|
+
getGeoJsonType(feature) {
|
|
2009
|
+
return feature.geometry ? feature.geometry.type : null;
|
|
1454
2010
|
},
|
|
1455
2011
|
/**
|
|
1456
2012
|
* 判断给定的GeoJSON要素是否为有效的GeoJSON格式
|
|
@@ -1458,14 +2014,16 @@ const V = {
|
|
|
1458
2014
|
* @param feature 要判断的GeoJSON要素
|
|
1459
2015
|
* @returns 如果为有效的GeoJSON格式则返回true,否则返回false
|
|
1460
2016
|
*/
|
|
1461
|
-
isGeoJson(
|
|
1462
|
-
const
|
|
1463
|
-
if (
|
|
1464
|
-
for (let
|
|
1465
|
-
if (
|
|
1466
|
-
return
|
|
2017
|
+
isGeoJson(feature) {
|
|
2018
|
+
const type = this.getGeoJsonType(feature);
|
|
2019
|
+
if (type) {
|
|
2020
|
+
for (let i = 0, len = TYPES.length; i < len; i++) {
|
|
2021
|
+
if (TYPES[i] === type) {
|
|
2022
|
+
return true;
|
|
2023
|
+
}
|
|
2024
|
+
}
|
|
1467
2025
|
}
|
|
1468
|
-
return
|
|
2026
|
+
return false;
|
|
1469
2027
|
},
|
|
1470
2028
|
/**
|
|
1471
2029
|
* 判断是否为 GeoJSON 多边形
|
|
@@ -1473,9 +2031,12 @@ const V = {
|
|
|
1473
2031
|
* @param feature GeoJSONFeature 对象
|
|
1474
2032
|
* @returns 返回布尔值,表示是否为 GeoJSON 多边形
|
|
1475
2033
|
*/
|
|
1476
|
-
isGeoJsonPolygon(
|
|
1477
|
-
const
|
|
1478
|
-
|
|
2034
|
+
isGeoJsonPolygon(feature) {
|
|
2035
|
+
const type = this.getGeoJsonType(feature);
|
|
2036
|
+
if (type && (type === TYPES[4] || type === TYPES[5])) {
|
|
2037
|
+
return true;
|
|
2038
|
+
}
|
|
2039
|
+
return false;
|
|
1479
2040
|
},
|
|
1480
2041
|
/**
|
|
1481
2042
|
* 判断给定的 GeoJSONFeature 是否为 GeoJSON 线
|
|
@@ -1483,9 +2044,12 @@ const V = {
|
|
|
1483
2044
|
* @param feature GeoJSONFeature 对象
|
|
1484
2045
|
* @returns 是 GeoJSON 线返回 true,否则返回 false
|
|
1485
2046
|
*/
|
|
1486
|
-
isGeoJsonLine(
|
|
1487
|
-
const
|
|
1488
|
-
|
|
2047
|
+
isGeoJsonLine(feature) {
|
|
2048
|
+
const type = this.getGeoJsonType(feature);
|
|
2049
|
+
if (type && (type === TYPES[2] || type === TYPES[3])) {
|
|
2050
|
+
return true;
|
|
2051
|
+
}
|
|
2052
|
+
return false;
|
|
1489
2053
|
},
|
|
1490
2054
|
/**
|
|
1491
2055
|
* 判断是否为 GeoJSON 点类型
|
|
@@ -1493,9 +2057,12 @@ const V = {
|
|
|
1493
2057
|
* @param feature GeoJSONFeature 对象
|
|
1494
2058
|
* @returns 是点类型返回 true,否则返回 false
|
|
1495
2059
|
*/
|
|
1496
|
-
isGeoJsonPoint(
|
|
1497
|
-
const
|
|
1498
|
-
|
|
2060
|
+
isGeoJsonPoint(feature) {
|
|
2061
|
+
const type = this.getGeoJsonType(feature);
|
|
2062
|
+
if (type && (type === TYPES[0] || type === TYPES[1])) {
|
|
2063
|
+
return true;
|
|
2064
|
+
}
|
|
2065
|
+
return false;
|
|
1499
2066
|
},
|
|
1500
2067
|
/**
|
|
1501
2068
|
* 判断传入的 GeoJSONFeature 是否为 Multi 类型的 GeoJSON。
|
|
@@ -1503,9 +2070,14 @@ const V = {
|
|
|
1503
2070
|
* @param feature GeoJSONFeature 类型的参数,待判断是否为 Multi 类型的 GeoJSON。
|
|
1504
2071
|
* @returns 返回一个布尔值,如果传入的 GeoJSONFeature 是 Multi 类型的 GeoJSON,则返回 true,否则返回 false。
|
|
1505
2072
|
*/
|
|
1506
|
-
isGeoJsonMulti(
|
|
1507
|
-
const
|
|
1508
|
-
|
|
2073
|
+
isGeoJsonMulti(feature) {
|
|
2074
|
+
const type = this.getGeoJsonType(feature);
|
|
2075
|
+
if (type) {
|
|
2076
|
+
if (type.indexOf("Multi") > -1) {
|
|
2077
|
+
return true;
|
|
2078
|
+
}
|
|
2079
|
+
}
|
|
2080
|
+
return false;
|
|
1509
2081
|
},
|
|
1510
2082
|
/**
|
|
1511
2083
|
* 获取GeoJSON要素的坐标数组
|
|
@@ -1513,8 +2085,8 @@ const V = {
|
|
|
1513
2085
|
* @param feature GeoJSONFeature对象
|
|
1514
2086
|
* @returns 返回一个包含坐标数组的数组,可以是二维、三维或四维数组
|
|
1515
2087
|
*/
|
|
1516
|
-
getGeoJsonCoordinates(
|
|
1517
|
-
return
|
|
2088
|
+
getGeoJsonCoordinates(feature) {
|
|
2089
|
+
return feature.geometry ? feature.geometry.coordinates : [];
|
|
1518
2090
|
},
|
|
1519
2091
|
/**
|
|
1520
2092
|
* 获取GeoJSON要素的中心点坐标
|
|
@@ -1523,42 +2095,64 @@ const V = {
|
|
|
1523
2095
|
* @param out 输出坐标对象,默认为null
|
|
1524
2096
|
* @returns 返回中心点坐标,如果无法获取则返回null
|
|
1525
2097
|
*/
|
|
1526
|
-
getGeoJsonCenter(
|
|
1527
|
-
const
|
|
1528
|
-
if (!
|
|
2098
|
+
getGeoJsonCenter(feature, out) {
|
|
2099
|
+
const type = this.getGeoJsonType(feature);
|
|
2100
|
+
if (!type || !feature.geometry) {
|
|
1529
2101
|
return null;
|
|
1530
|
-
|
|
1531
|
-
|
|
2102
|
+
}
|
|
2103
|
+
const geometry = feature.geometry;
|
|
2104
|
+
const coordinates = geometry.coordinates;
|
|
2105
|
+
if (!coordinates) {
|
|
1532
2106
|
return null;
|
|
1533
|
-
|
|
1534
|
-
|
|
2107
|
+
}
|
|
2108
|
+
let sumX = 0, sumY = 0, coordLen = 0;
|
|
2109
|
+
switch (type) {
|
|
1535
2110
|
case "Point": {
|
|
1536
|
-
|
|
2111
|
+
sumX = coordinates[0];
|
|
2112
|
+
sumY = coordinates[1];
|
|
2113
|
+
coordLen++;
|
|
1537
2114
|
break;
|
|
1538
2115
|
}
|
|
1539
2116
|
case "MultiPoint":
|
|
1540
2117
|
case "LineString": {
|
|
1541
|
-
for (let
|
|
1542
|
-
|
|
2118
|
+
for (let i = 0, len = coordinates.length; i < len; i++) {
|
|
2119
|
+
sumX += coordinates[i][0];
|
|
2120
|
+
sumY += coordinates[i][1];
|
|
2121
|
+
coordLen++;
|
|
2122
|
+
}
|
|
1543
2123
|
break;
|
|
1544
2124
|
}
|
|
1545
2125
|
case "MultiLineString":
|
|
1546
2126
|
case "Polygon": {
|
|
1547
|
-
for (let
|
|
1548
|
-
for (let
|
|
1549
|
-
|
|
2127
|
+
for (let i = 0, len = coordinates.length; i < len; i++) {
|
|
2128
|
+
for (let j = 0, len1 = coordinates[i].length; j < len1; j++) {
|
|
2129
|
+
sumX += coordinates[i][j][0];
|
|
2130
|
+
sumY += coordinates[i][j][1];
|
|
2131
|
+
coordLen++;
|
|
2132
|
+
}
|
|
2133
|
+
}
|
|
1550
2134
|
break;
|
|
1551
2135
|
}
|
|
1552
2136
|
case "MultiPolygon": {
|
|
1553
|
-
for (let
|
|
1554
|
-
for (let
|
|
1555
|
-
for (let
|
|
1556
|
-
|
|
2137
|
+
for (let i = 0, len = coordinates.length; i < len; i++) {
|
|
2138
|
+
for (let j = 0, len1 = coordinates[i].length; j < len1; j++) {
|
|
2139
|
+
for (let m = 0, len2 = coordinates[i][j].length; m < len2; m++) {
|
|
2140
|
+
sumX += coordinates[i][j][m][0];
|
|
2141
|
+
sumY += coordinates[i][j][m][1];
|
|
2142
|
+
coordLen++;
|
|
2143
|
+
}
|
|
2144
|
+
}
|
|
2145
|
+
}
|
|
1557
2146
|
break;
|
|
1558
2147
|
}
|
|
1559
2148
|
}
|
|
1560
|
-
const
|
|
1561
|
-
|
|
2149
|
+
const x = sumX / coordLen, y = sumY / coordLen;
|
|
2150
|
+
if (out) {
|
|
2151
|
+
out.x = x;
|
|
2152
|
+
out.y = y;
|
|
2153
|
+
return out;
|
|
2154
|
+
}
|
|
2155
|
+
return { x, y };
|
|
1562
2156
|
},
|
|
1563
2157
|
/**
|
|
1564
2158
|
* 将一个包含多个点、线或面的 GeoJSON 特征对象拆分成多个独立的 GeoJSON 特征对象数组。
|
|
@@ -1566,42 +2160,48 @@ const V = {
|
|
|
1566
2160
|
* @param feature 包含多个点、线或面的 GeoJSON 特征对象
|
|
1567
2161
|
* @returns 返回一个 GeoJSON 特征对象数组,如果拆分失败则返回 null
|
|
1568
2162
|
*/
|
|
1569
|
-
spliteGeoJsonMulti(
|
|
1570
|
-
const
|
|
1571
|
-
if (!
|
|
2163
|
+
spliteGeoJsonMulti(feature) {
|
|
2164
|
+
const type = this.getGeoJsonType(feature);
|
|
2165
|
+
if (!type || !feature.geometry) {
|
|
1572
2166
|
return null;
|
|
1573
|
-
|
|
1574
|
-
|
|
2167
|
+
}
|
|
2168
|
+
const geometry = feature.geometry;
|
|
2169
|
+
const properties = feature.properties || {};
|
|
2170
|
+
const coordinates = geometry.coordinates;
|
|
2171
|
+
if (!coordinates) {
|
|
1575
2172
|
return null;
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
2173
|
+
}
|
|
2174
|
+
const features = [];
|
|
2175
|
+
let fType;
|
|
2176
|
+
switch (type) {
|
|
1579
2177
|
case "MultiPoint": {
|
|
1580
|
-
|
|
2178
|
+
fType = "Point";
|
|
1581
2179
|
break;
|
|
1582
2180
|
}
|
|
1583
2181
|
case "MultiLineString": {
|
|
1584
|
-
|
|
2182
|
+
fType = "LineString";
|
|
1585
2183
|
break;
|
|
1586
2184
|
}
|
|
1587
2185
|
case "MultiPolygon": {
|
|
1588
|
-
|
|
2186
|
+
fType = "Polygon";
|
|
1589
2187
|
break;
|
|
1590
2188
|
}
|
|
1591
2189
|
}
|
|
1592
|
-
if (
|
|
1593
|
-
for (let
|
|
1594
|
-
|
|
2190
|
+
if (fType) {
|
|
2191
|
+
for (let i = 0, len = coordinates.length; i < len; i++) {
|
|
2192
|
+
features.push({
|
|
1595
2193
|
type: "Feature",
|
|
1596
2194
|
geometry: {
|
|
1597
|
-
type:
|
|
1598
|
-
coordinates: i
|
|
2195
|
+
type: fType,
|
|
2196
|
+
coordinates: coordinates[i]
|
|
1599
2197
|
},
|
|
1600
|
-
properties
|
|
2198
|
+
properties
|
|
1601
2199
|
});
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
2200
|
+
}
|
|
2201
|
+
} else {
|
|
2202
|
+
features.push(feature);
|
|
2203
|
+
}
|
|
2204
|
+
return features;
|
|
1605
2205
|
},
|
|
1606
2206
|
/**
|
|
1607
2207
|
* 根据坐标数组生成GeoJSON要素
|
|
@@ -1610,246 +2210,768 @@ const V = {
|
|
|
1610
2210
|
* @returns GeoJSONFeature 生成的GeoJSON要素
|
|
1611
2211
|
* @throws Error 如果coordinates参数格式错误
|
|
1612
2212
|
*/
|
|
1613
|
-
getGeoJsonByCoordinates(
|
|
1614
|
-
if (!Array.isArray(
|
|
2213
|
+
getGeoJsonByCoordinates(coordinates) {
|
|
2214
|
+
if (!Array.isArray(coordinates)) {
|
|
1615
2215
|
throw Error("coordinates 参数格式错误");
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
else
|
|
2216
|
+
}
|
|
2217
|
+
let type;
|
|
2218
|
+
if (coordinates.length === 2 && typeof coordinates[0] === "number" && typeof coordinates[1] === "number") {
|
|
2219
|
+
type = "Point";
|
|
2220
|
+
} else if (Array.isArray(coordinates[0]) && coordinates[0].length === 2) {
|
|
2221
|
+
type = "LineString";
|
|
2222
|
+
} else if (Array.isArray(coordinates[0]) && Array.isArray(coordinates[0][0])) {
|
|
2223
|
+
const outerRing = coordinates[0];
|
|
2224
|
+
const isClosed = outerRing[0].join(",") === outerRing[outerRing.length - 1].join(",");
|
|
2225
|
+
if (isClosed) {
|
|
2226
|
+
type = "Polygon";
|
|
2227
|
+
} else if (coordinates.length > 1) {
|
|
2228
|
+
type = "MultiPolygon";
|
|
2229
|
+
} else {
|
|
1628
2230
|
throw Error("coordinates 参数格式错误");
|
|
1629
|
-
|
|
2231
|
+
}
|
|
2232
|
+
} else {
|
|
1630
2233
|
throw Error("coordinates 参数格式错误");
|
|
2234
|
+
}
|
|
1631
2235
|
return {
|
|
1632
2236
|
type: "Feature",
|
|
1633
|
-
geometry: { type
|
|
2237
|
+
geometry: { type, coordinates }
|
|
1634
2238
|
};
|
|
1635
2239
|
}
|
|
1636
|
-
}
|
|
1637
|
-
|
|
1638
|
-
|
|
2240
|
+
};
|
|
2241
|
+
const AssertUtil = {
|
|
2242
|
+
assertEmpty(...arg) {
|
|
2243
|
+
arg.forEach((a) => {
|
|
2244
|
+
if (CommUtil.isEmpty(a)) {
|
|
2245
|
+
throw Error("变量为空:>>>" + a);
|
|
2246
|
+
}
|
|
2247
|
+
});
|
|
2248
|
+
},
|
|
2249
|
+
assertNumber(...arg) {
|
|
2250
|
+
arg.forEach((a) => {
|
|
2251
|
+
if (!CommUtil.isNumber(a)) {
|
|
2252
|
+
throw Error("不是数字:>>>" + a);
|
|
2253
|
+
}
|
|
2254
|
+
});
|
|
2255
|
+
},
|
|
2256
|
+
assertArray(...arg) {
|
|
2257
|
+
arg.forEach((a) => {
|
|
2258
|
+
if (!CommUtil.isArray(a)) {
|
|
2259
|
+
throw Error(ErrorType.PARAMETER_ERROR_ARRAY + ":>>>" + a);
|
|
2260
|
+
}
|
|
2261
|
+
});
|
|
2262
|
+
},
|
|
2263
|
+
assertFunction(...arg) {
|
|
2264
|
+
arg.forEach((a) => {
|
|
2265
|
+
if (!CommUtil.isFunction(a)) {
|
|
2266
|
+
throw Error(ErrorType.PARAMETER_ERROR_FUNCTION + ":>>>" + a);
|
|
2267
|
+
}
|
|
2268
|
+
});
|
|
2269
|
+
},
|
|
2270
|
+
assertObject(...arg) {
|
|
2271
|
+
arg.forEach((a) => {
|
|
2272
|
+
if (!CommUtil.isObject(a)) {
|
|
2273
|
+
throw Error(ErrorType.PARAMETER_ERROR_OBJECT + ":>>>" + a);
|
|
2274
|
+
}
|
|
2275
|
+
});
|
|
2276
|
+
},
|
|
2277
|
+
assertColor(...arg) {
|
|
2278
|
+
arg.forEach((a) => {
|
|
2279
|
+
if (!ColorUtil.isColor(a)) {
|
|
2280
|
+
throw Error("颜色代码不正确:>>>" + a);
|
|
2281
|
+
}
|
|
2282
|
+
});
|
|
2283
|
+
},
|
|
2284
|
+
assertLnglat(...arg) {
|
|
2285
|
+
arg.forEach((a) => {
|
|
2286
|
+
if (!GeoUtil.isLnglat(a.lng, a.lat)) {
|
|
2287
|
+
throw Error(ErrorType.COORDINATE_ERROR + ":>>>" + a);
|
|
2288
|
+
}
|
|
2289
|
+
});
|
|
2290
|
+
},
|
|
2291
|
+
assertGeoJson(...arg) {
|
|
2292
|
+
arg.forEach((a) => {
|
|
2293
|
+
if (!GeoJsonUtil.isGeoJson(a)) {
|
|
2294
|
+
throw Error("不是GeoJSON:>>>" + a);
|
|
2295
|
+
}
|
|
2296
|
+
});
|
|
2297
|
+
},
|
|
2298
|
+
assertContain(str, ...args) {
|
|
2299
|
+
let res = false;
|
|
2300
|
+
const len = args.length || 0;
|
|
2301
|
+
for (let i = 0, l = len; i < l; i++) {
|
|
2302
|
+
res = str.indexOf(args[i]) >= 0;
|
|
2303
|
+
}
|
|
2304
|
+
if (res) {
|
|
2305
|
+
throw Error(ErrorType.STRING_CHECK_LOSS + ":>>>" + str);
|
|
2306
|
+
}
|
|
2307
|
+
},
|
|
1639
2308
|
/**
|
|
1640
|
-
*
|
|
2309
|
+
* 判断字符串是否合法
|
|
1641
2310
|
*
|
|
1642
|
-
* @param
|
|
1643
|
-
* @param
|
|
1644
|
-
* @
|
|
2311
|
+
* @param value 待判断的字符串
|
|
2312
|
+
* @param type 字符串类型
|
|
2313
|
+
* @throws 当字符串不合法时,抛出错误,错误信息为“参数错误:>>>不是{typename}”
|
|
2314
|
+
*/
|
|
2315
|
+
assertLegal(value, type) {
|
|
2316
|
+
const bool = StringUtil.checkStr(value, type);
|
|
2317
|
+
let typename = "";
|
|
2318
|
+
switch (type) {
|
|
2319
|
+
case "phone":
|
|
2320
|
+
typename = "电话";
|
|
2321
|
+
break;
|
|
2322
|
+
case "tel":
|
|
2323
|
+
typename = "座机";
|
|
2324
|
+
break;
|
|
2325
|
+
case "card":
|
|
2326
|
+
typename = "身份证";
|
|
2327
|
+
break;
|
|
2328
|
+
case "pwd":
|
|
2329
|
+
typename = "密码";
|
|
2330
|
+
break;
|
|
2331
|
+
case "postal":
|
|
2332
|
+
typename = "邮政编码";
|
|
2333
|
+
break;
|
|
2334
|
+
case "QQ":
|
|
2335
|
+
typename = "QQ";
|
|
2336
|
+
break;
|
|
2337
|
+
case "email":
|
|
2338
|
+
typename = "邮箱";
|
|
2339
|
+
break;
|
|
2340
|
+
case "money":
|
|
2341
|
+
typename = "金额";
|
|
2342
|
+
break;
|
|
2343
|
+
case "URL":
|
|
2344
|
+
typename = "网址";
|
|
2345
|
+
break;
|
|
2346
|
+
case "IP":
|
|
2347
|
+
typename = "IP";
|
|
2348
|
+
break;
|
|
2349
|
+
case "date":
|
|
2350
|
+
typename = "日期时间";
|
|
2351
|
+
break;
|
|
2352
|
+
case "number":
|
|
2353
|
+
typename = "数字";
|
|
2354
|
+
break;
|
|
2355
|
+
case "english":
|
|
2356
|
+
typename = "英文";
|
|
2357
|
+
break;
|
|
2358
|
+
case "chinese":
|
|
2359
|
+
typename = "中文";
|
|
2360
|
+
break;
|
|
2361
|
+
case "lower":
|
|
2362
|
+
typename = "小写";
|
|
2363
|
+
break;
|
|
2364
|
+
case "upper":
|
|
2365
|
+
typename = "大写";
|
|
2366
|
+
break;
|
|
2367
|
+
case "HTML":
|
|
2368
|
+
typename = "HTML标记";
|
|
2369
|
+
break;
|
|
2370
|
+
}
|
|
2371
|
+
if (!bool) {
|
|
2372
|
+
throw Error(ErrorType.PARAMETER_ERROR + ":>>>不是" + typename);
|
|
2373
|
+
}
|
|
2374
|
+
}
|
|
2375
|
+
};
|
|
2376
|
+
const BrowserUtil = {
|
|
2377
|
+
/**
|
|
2378
|
+
* 获取浏览器类型
|
|
2379
|
+
*
|
|
2380
|
+
* @returns 返回浏览器类型字符串,可能的值为 'IE'、'Firefox'、'Chrome'、'Opera'、'Safari' 或 'Unknown'
|
|
1645
2381
|
*/
|
|
1646
|
-
|
|
1647
|
-
|
|
2382
|
+
getExplorer() {
|
|
2383
|
+
var explorer = window.navigator.userAgent;
|
|
2384
|
+
if (explorer.indexOf("MSIE") >= 0 || /Trident\//.test(explorer)) {
|
|
2385
|
+
return "IE";
|
|
2386
|
+
} else if (explorer.indexOf("Firefox") >= 0) {
|
|
2387
|
+
return "Firefox";
|
|
2388
|
+
} else if (explorer.indexOf("Chrome") >= 0) {
|
|
2389
|
+
return "Chrome";
|
|
2390
|
+
} else if (explorer.indexOf("Opera") >= 0) {
|
|
2391
|
+
return "Opera";
|
|
2392
|
+
} else if (explorer.indexOf("Safari") >= 0 && explorer.indexOf("Chrome") === -1) {
|
|
2393
|
+
return "Safari";
|
|
2394
|
+
}
|
|
2395
|
+
return "Unknown";
|
|
1648
2396
|
},
|
|
1649
2397
|
/**
|
|
1650
|
-
*
|
|
2398
|
+
* 检测操作系统类型
|
|
1651
2399
|
*
|
|
1652
|
-
* @
|
|
1653
|
-
|
|
1654
|
-
|
|
2400
|
+
* @returns 返回操作系统类型字符串,可能的值有:'MS Windows'、'Apple mac'、'Linux'、'Unix'
|
|
2401
|
+
*/
|
|
2402
|
+
detectOS() {
|
|
2403
|
+
let os_type = "";
|
|
2404
|
+
const windows = navigator.userAgent.indexOf("Windows", 0) != -1 ? 1 : 0;
|
|
2405
|
+
const mac = navigator.userAgent.indexOf("mac", 0) != -1 ? 1 : 0;
|
|
2406
|
+
const linux = navigator.userAgent.indexOf("Linux", 0) != -1 ? 1 : 0;
|
|
2407
|
+
const unix = navigator.userAgent.indexOf("X11", 0) != -1 ? 1 : 0;
|
|
2408
|
+
if (windows) os_type = "MS Windows";
|
|
2409
|
+
else if (mac) os_type = "Apple mac";
|
|
2410
|
+
else if (linux) os_type = "Linux";
|
|
2411
|
+
else if (unix) os_type = "Unix";
|
|
2412
|
+
return os_type;
|
|
2413
|
+
},
|
|
2414
|
+
/**
|
|
2415
|
+
* 切换全屏状态
|
|
2416
|
+
*
|
|
2417
|
+
* @param status 是否全屏
|
|
2418
|
+
*/
|
|
2419
|
+
switchFullScreen(status) {
|
|
2420
|
+
if (status) {
|
|
2421
|
+
const element = document.documentElement;
|
|
2422
|
+
if (element.requestFullscreen) {
|
|
2423
|
+
element.requestFullscreen();
|
|
2424
|
+
} else if ("msRequestFullscreen" in element) {
|
|
2425
|
+
element.msRequestFullscreen();
|
|
2426
|
+
} else if ("mozRequestFullScreen" in element) {
|
|
2427
|
+
element.mozRequestFullScreen();
|
|
2428
|
+
} else if ("webkitRequestFullscreen" in element) {
|
|
2429
|
+
element.webkitRequestFullscreen();
|
|
2430
|
+
}
|
|
2431
|
+
} else {
|
|
2432
|
+
if (document.exitFullscreen) {
|
|
2433
|
+
document.exitFullscreen();
|
|
2434
|
+
} else if ("msExitFullscreen" in document) {
|
|
2435
|
+
document.msExitFullscreen();
|
|
2436
|
+
} else if ("mozCancelFullScreen" in document) {
|
|
2437
|
+
document.mozCancelFullScreen();
|
|
2438
|
+
} else if ("webkitExitFullscreen" in document) {
|
|
2439
|
+
document.webkitExitFullscreen();
|
|
2440
|
+
}
|
|
2441
|
+
}
|
|
2442
|
+
},
|
|
2443
|
+
/**
|
|
2444
|
+
* 刷新缩放比例
|
|
2445
|
+
*
|
|
2446
|
+
* @returns 无返回值
|
|
2447
|
+
*/
|
|
2448
|
+
refreshScale() {
|
|
2449
|
+
const baseWidth = document.documentElement.clientWidth || 0;
|
|
2450
|
+
const baseHeight = document.documentElement.clientHeight || 0;
|
|
2451
|
+
const appElement = document.getElementById("app");
|
|
2452
|
+
if (!appElement) return;
|
|
2453
|
+
const appStyle = appElement.style;
|
|
2454
|
+
const realRatio = baseWidth / baseHeight;
|
|
2455
|
+
const designRatio = 16 / 9;
|
|
2456
|
+
let scaleRate = baseWidth / 1920;
|
|
2457
|
+
if (realRatio > designRatio) {
|
|
2458
|
+
scaleRate = baseHeight / 1080;
|
|
2459
|
+
}
|
|
2460
|
+
appStyle.transformOrigin = "left top";
|
|
2461
|
+
appStyle.transform = `scale(${scaleRate}) translateX(-49.99%)`;
|
|
2462
|
+
appStyle.width = `${baseWidth / scaleRate}px`;
|
|
2463
|
+
},
|
|
2464
|
+
/**
|
|
2465
|
+
* 获取HTML字体大小
|
|
2466
|
+
*
|
|
2467
|
+
* @returns 无返回值,该函数会直接修改HTML元素的字体大小
|
|
2468
|
+
*/
|
|
2469
|
+
getHtmlFontSize() {
|
|
2470
|
+
const htmlwidth = document.documentElement.clientWidth || document.body.clientWidth;
|
|
2471
|
+
const htmlDom = document.querySelector("html");
|
|
2472
|
+
if (htmlDom) {
|
|
2473
|
+
htmlDom.style.fontSize = htmlwidth / 192 + "px";
|
|
2474
|
+
}
|
|
2475
|
+
}
|
|
2476
|
+
};
|
|
2477
|
+
const CoordsUtil = {
|
|
2478
|
+
PI: 3.141592653589793,
|
|
2479
|
+
XPI: 3.141592653589793 * 3e3 / 180,
|
|
2480
|
+
delta(lat, lng) {
|
|
2481
|
+
const a = 6378245;
|
|
2482
|
+
const ee = 0.006693421622965943;
|
|
2483
|
+
let dLat = this.transformLat(lng - 105, lat - 35);
|
|
2484
|
+
let dLon = this.transformLon(lng - 105, lat - 35);
|
|
2485
|
+
const radLat = lat / 180 * this.PI;
|
|
2486
|
+
let magic = Math.sin(radLat);
|
|
2487
|
+
magic = 1 - ee * magic * magic;
|
|
2488
|
+
const sqrtMagic = Math.sqrt(magic);
|
|
2489
|
+
dLat = dLat * 180 / (a * (1 - ee) / (magic * sqrtMagic) * this.PI);
|
|
2490
|
+
dLon = dLon * 180 / (a / sqrtMagic * Math.cos(radLat) * this.PI);
|
|
2491
|
+
return { lat: dLat, lng: dLon };
|
|
2492
|
+
},
|
|
2493
|
+
/**
|
|
2494
|
+
* 判断经纬度是否不在中国境内
|
|
2495
|
+
*
|
|
2496
|
+
* @param lng 经度
|
|
2497
|
+
* @param lat 纬度
|
|
2498
|
+
* @returns 如果经纬度不在中国境内则返回true,否则返回false
|
|
2499
|
+
*/
|
|
2500
|
+
outOfChina(lng, lat) {
|
|
2501
|
+
if (lng < 72.004 || lng > 137.8347) {
|
|
2502
|
+
return true;
|
|
2503
|
+
}
|
|
2504
|
+
if (lat < 0.8293 || lat > 55.8271) {
|
|
2505
|
+
return true;
|
|
2506
|
+
}
|
|
2507
|
+
return false;
|
|
2508
|
+
},
|
|
2509
|
+
// WGS-84 to GCJ-02
|
|
2510
|
+
gcjEncrypt(wgsLat, wgsLon) {
|
|
2511
|
+
if (this.outOfChina(wgsLat, wgsLon)) {
|
|
2512
|
+
return { lat: wgsLat, lng: wgsLon };
|
|
2513
|
+
}
|
|
2514
|
+
const d = this.delta(wgsLat, wgsLon);
|
|
2515
|
+
return { lat: wgsLat + d.lat, lng: wgsLon + d.lng };
|
|
2516
|
+
},
|
|
2517
|
+
// GCJ-02 to WGS-84
|
|
2518
|
+
gcjDecrypt(gcjLat, gcjLon) {
|
|
2519
|
+
if (this.outOfChina(gcjLat, gcjLon)) {
|
|
2520
|
+
return { lat: gcjLat, lng: gcjLon };
|
|
2521
|
+
}
|
|
2522
|
+
const d = this.delta(gcjLat, gcjLon);
|
|
2523
|
+
return { lat: gcjLat - d.lat, lng: gcjLon - d.lng };
|
|
2524
|
+
},
|
|
2525
|
+
// GCJ-02 to WGS-84 exactly
|
|
2526
|
+
gcjDecryptExact(gcjLat, gcjLon) {
|
|
2527
|
+
const initDelta = 0.01;
|
|
2528
|
+
const threshold = 1e-9;
|
|
2529
|
+
let dLat = initDelta;
|
|
2530
|
+
let dLon = initDelta;
|
|
2531
|
+
let mLat = gcjLat - dLat;
|
|
2532
|
+
let mLon = gcjLon - dLon;
|
|
2533
|
+
let pLat = gcjLat + dLat;
|
|
2534
|
+
let pLon = gcjLon + dLon;
|
|
2535
|
+
let wgsLat = 0;
|
|
2536
|
+
let wgsLon = 0;
|
|
2537
|
+
let i = 0;
|
|
2538
|
+
while (1) {
|
|
2539
|
+
wgsLat = (mLat + pLat) / 2;
|
|
2540
|
+
wgsLon = (mLon + pLon) / 2;
|
|
2541
|
+
const tmp = this.gcjEncrypt(wgsLat, wgsLon);
|
|
2542
|
+
dLat = tmp.lat - gcjLat;
|
|
2543
|
+
dLon = tmp.lng - gcjLon;
|
|
2544
|
+
if (Math.abs(dLat) < threshold && Math.abs(dLon) < threshold) {
|
|
2545
|
+
break;
|
|
2546
|
+
}
|
|
2547
|
+
if (dLat > 0) pLat = wgsLat;
|
|
2548
|
+
else mLat = wgsLat;
|
|
2549
|
+
if (dLon > 0) pLon = wgsLon;
|
|
2550
|
+
else mLon = wgsLon;
|
|
2551
|
+
if (++i > 1e4) break;
|
|
2552
|
+
}
|
|
2553
|
+
return { lat: wgsLat, lng: wgsLon };
|
|
2554
|
+
},
|
|
2555
|
+
// GCJ-02 to BD-09
|
|
2556
|
+
bdEncrypt(gcjLat, gcjLon) {
|
|
2557
|
+
const x = gcjLon;
|
|
2558
|
+
const y = gcjLat;
|
|
2559
|
+
const z = Math.sqrt(x * x + y * y) + 2e-5 * Math.sin(y * this.XPI);
|
|
2560
|
+
const theta = Math.atan2(y, x) + 3e-6 * Math.cos(x * this.XPI);
|
|
2561
|
+
const bdLon = z * Math.cos(theta) + 65e-4;
|
|
2562
|
+
const bdLat = z * Math.sin(theta) + 6e-3;
|
|
2563
|
+
return { lat: bdLat, lng: bdLon };
|
|
2564
|
+
},
|
|
2565
|
+
// BD-09 to GCJ-02
|
|
2566
|
+
bdDecrypt(bdLat, bdLon) {
|
|
2567
|
+
const x = bdLon - 65e-4;
|
|
2568
|
+
const y = bdLat - 6e-3;
|
|
2569
|
+
const z = Math.sqrt(x * x + y * y) - 2e-5 * Math.sin(y * this.XPI);
|
|
2570
|
+
const theta = Math.atan2(y, x) - 3e-6 * Math.cos(x * this.XPI);
|
|
2571
|
+
const gcjLon = z * Math.cos(theta);
|
|
2572
|
+
const gcjLat = z * Math.sin(theta);
|
|
2573
|
+
return { lat: gcjLat, lng: gcjLon };
|
|
2574
|
+
},
|
|
2575
|
+
// WGS-84 to Web mercator
|
|
2576
|
+
// mercatorLat -> y mercatorLon -> x
|
|
2577
|
+
mercatorEncrypt(wgsLat, wgsLon) {
|
|
2578
|
+
const x = wgsLon * 2003750834e-2 / 180;
|
|
2579
|
+
let y = Math.log(Math.tan((90 + wgsLat) * this.PI / 360)) / (this.PI / 180);
|
|
2580
|
+
y = y * 2003750834e-2 / 180;
|
|
2581
|
+
return { lat: y, lng: x };
|
|
2582
|
+
},
|
|
2583
|
+
// Web mercator to WGS-84
|
|
2584
|
+
// mercatorLat -> y mercatorLon -> x
|
|
2585
|
+
mercatorDecrypt(mercatorLat, mercatorLon) {
|
|
2586
|
+
const x = mercatorLon / 2003750834e-2 * 180;
|
|
2587
|
+
let y = mercatorLat / 2003750834e-2 * 180;
|
|
2588
|
+
y = 180 / this.PI * (2 * Math.atan(Math.exp(y * this.PI / 180)) - this.PI / 2);
|
|
2589
|
+
return { lat: y, lng: x };
|
|
2590
|
+
},
|
|
2591
|
+
transformLat(x, y) {
|
|
2592
|
+
let ret = -100 + 2 * x + 3 * y + 0.2 * y * y + 0.1 * x * y + 0.2 * Math.sqrt(Math.abs(x));
|
|
2593
|
+
ret += (20 * Math.sin(6 * x * this.PI) + 20 * Math.sin(2 * x * this.PI)) * 2 / 3;
|
|
2594
|
+
ret += (20 * Math.sin(y * this.PI) + 40 * Math.sin(y / 3 * this.PI)) * 2 / 3;
|
|
2595
|
+
ret += (160 * Math.sin(y / 12 * this.PI) + 320 * Math.sin(y * this.PI / 30)) * 2 / 3;
|
|
2596
|
+
return ret;
|
|
2597
|
+
},
|
|
2598
|
+
transformLon(x, y) {
|
|
2599
|
+
let ret = 300 + x + 2 * y + 0.1 * x * x + 0.1 * x * y + 0.1 * Math.sqrt(Math.abs(x));
|
|
2600
|
+
ret += (20 * Math.sin(6 * x * this.PI) + 20 * Math.sin(2 * x * this.PI)) * 2 / 3;
|
|
2601
|
+
ret += (20 * Math.sin(x * this.PI) + 40 * Math.sin(x / 3 * this.PI)) * 2 / 3;
|
|
2602
|
+
ret += (150 * Math.sin(x / 12 * this.PI) + 300 * Math.sin(x / 30 * this.PI)) * 2 / 3;
|
|
2603
|
+
return ret;
|
|
2604
|
+
},
|
|
2605
|
+
/**
|
|
2606
|
+
* 生成指定范围内的随机经纬度坐标
|
|
2607
|
+
*
|
|
2608
|
+
* @param min 最小坐标,包含属性 x 和 y,分别表示最小经度和最小纬度
|
|
2609
|
+
* @param max 最大坐标,包含属性 x 和 y,分别表示最大经度和最大纬度
|
|
2610
|
+
* @returns 返回生成的随机经纬度坐标,包含属性 lat 和 lng,分别表示纬度和经度
|
|
2611
|
+
*/
|
|
2612
|
+
random({ x: minX, y: minY }, { x: maxX, y: maxY }) {
|
|
2613
|
+
return {
|
|
2614
|
+
lat: Math.random() * (maxY - minY) + minY,
|
|
2615
|
+
lng: Math.random() * (maxX - minX) + minX
|
|
2616
|
+
};
|
|
2617
|
+
},
|
|
2618
|
+
deCompose(arr, fn, context) {
|
|
2619
|
+
if (!Array.isArray(arr)) {
|
|
2620
|
+
return context ? fn.call(context, arr) : fn(arr);
|
|
2621
|
+
}
|
|
2622
|
+
const result = [];
|
|
2623
|
+
let p, pp;
|
|
2624
|
+
for (let i = 0, len = arr.length; i < len; i++) {
|
|
2625
|
+
p = arr[i];
|
|
2626
|
+
if (CommUtil.isNil(p)) {
|
|
2627
|
+
result.push(null);
|
|
2628
|
+
continue;
|
|
2629
|
+
}
|
|
2630
|
+
if (Array.isArray(p)) {
|
|
2631
|
+
result.push(this.deCompose(p, fn, context));
|
|
2632
|
+
} else {
|
|
2633
|
+
pp = context ? fn.call(context, p) : fn(p);
|
|
2634
|
+
result.push(pp);
|
|
2635
|
+
}
|
|
2636
|
+
}
|
|
2637
|
+
return result;
|
|
2638
|
+
}
|
|
2639
|
+
};
|
|
2640
|
+
const myDate = Object.create(Date);
|
|
2641
|
+
myDate.prototype.format = function(fmt = "yyyy-MM-dd hh:mm:ss") {
|
|
2642
|
+
const o = {
|
|
2643
|
+
"M+": this.getMonth() + 1,
|
|
2644
|
+
// 月份
|
|
2645
|
+
"d+": this.getDate(),
|
|
2646
|
+
// 日
|
|
2647
|
+
"h+": this.getHours() % 12,
|
|
2648
|
+
// 小时
|
|
2649
|
+
"H+": this.getHours(),
|
|
2650
|
+
// 小时 (24小时制)
|
|
2651
|
+
"m+": this.getMinutes(),
|
|
2652
|
+
// 分
|
|
2653
|
+
"s+": this.getSeconds(),
|
|
2654
|
+
// 秒
|
|
2655
|
+
"q+": Math.floor((this.getMonth() + 3) / 3),
|
|
2656
|
+
// 季度
|
|
2657
|
+
S: this.getMilliseconds()
|
|
2658
|
+
// 毫秒
|
|
2659
|
+
};
|
|
2660
|
+
if (/(y+)/.test(fmt)) {
|
|
2661
|
+
fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));
|
|
2662
|
+
}
|
|
2663
|
+
for (const k in o) {
|
|
2664
|
+
if (new RegExp("(" + k + ")").test(fmt)) {
|
|
2665
|
+
const len = k.length === 1 ? 1 : Number(k.slice(1));
|
|
2666
|
+
fmt = fmt.replace(RegExp.$1, ("00" + o[k]).substr(("" + o[k]).length + len - (o[k] + "").length));
|
|
2667
|
+
}
|
|
2668
|
+
}
|
|
2669
|
+
return fmt;
|
|
2670
|
+
};
|
|
2671
|
+
myDate.prototype.addDate = function(interval, number) {
|
|
2672
|
+
const date = new Date(this);
|
|
2673
|
+
switch (interval) {
|
|
2674
|
+
case "y":
|
|
2675
|
+
date.setFullYear(this.getFullYear() + number);
|
|
2676
|
+
break;
|
|
2677
|
+
case "q":
|
|
2678
|
+
date.setMonth(this.getMonth() + number * 3);
|
|
2679
|
+
break;
|
|
2680
|
+
case "M":
|
|
2681
|
+
date.setMonth(this.getMonth() + number);
|
|
2682
|
+
break;
|
|
2683
|
+
case "w":
|
|
2684
|
+
date.setDate(this.getDate() + number * 7);
|
|
2685
|
+
break;
|
|
2686
|
+
case "d":
|
|
2687
|
+
date.setDate(this.getDate() + number);
|
|
2688
|
+
break;
|
|
2689
|
+
case "h":
|
|
2690
|
+
date.setHours(this.getHours() + number);
|
|
2691
|
+
break;
|
|
2692
|
+
case "m":
|
|
2693
|
+
date.setMinutes(this.getMinutes() + number);
|
|
2694
|
+
break;
|
|
2695
|
+
case "s":
|
|
2696
|
+
date.setSeconds(this.getSeconds() + number);
|
|
2697
|
+
break;
|
|
2698
|
+
default:
|
|
2699
|
+
date.setDate(this.getDate() + number);
|
|
2700
|
+
break;
|
|
2701
|
+
}
|
|
2702
|
+
return date;
|
|
2703
|
+
};
|
|
2704
|
+
const DateUtil = {
|
|
2705
|
+
lastMonthDate: new Date((/* @__PURE__ */ new Date()).getFullYear(), (/* @__PURE__ */ new Date()).getMonth() - 1, 1),
|
|
2706
|
+
thisMonthDate: new Date((/* @__PURE__ */ new Date()).getFullYear(), (/* @__PURE__ */ new Date()).getMonth(), 1),
|
|
2707
|
+
nextMonthDate: new Date((/* @__PURE__ */ new Date()).getFullYear(), (/* @__PURE__ */ new Date()).getMonth() + 1, 1),
|
|
2708
|
+
lastWeekDate: new Date((/* @__PURE__ */ new Date()).getFullYear(), (/* @__PURE__ */ new Date()).getMonth(), (/* @__PURE__ */ new Date()).getDate() + 1 - 7 - (/* @__PURE__ */ new Date()).getDay()),
|
|
2709
|
+
thisWeekDate: new Date((/* @__PURE__ */ new Date()).getFullYear(), (/* @__PURE__ */ new Date()).getMonth(), (/* @__PURE__ */ new Date()).getDate() + 1 - (/* @__PURE__ */ new Date()).getDay()),
|
|
2710
|
+
nextWeekDate: new Date((/* @__PURE__ */ new Date()).getFullYear(), (/* @__PURE__ */ new Date()).getMonth(), (/* @__PURE__ */ new Date()).getDate() + 1 + 7 - (/* @__PURE__ */ new Date()).getDay()),
|
|
2711
|
+
lastDayDate: new Date((/* @__PURE__ */ new Date()).getFullYear(), (/* @__PURE__ */ new Date()).getMonth(), (/* @__PURE__ */ new Date()).getDate() - 1),
|
|
2712
|
+
thisDayDate: new Date((/* @__PURE__ */ new Date()).setHours(0, 0, 0, 0)),
|
|
2713
|
+
nextDayDate: new Date((/* @__PURE__ */ new Date()).getFullYear(), (/* @__PURE__ */ new Date()).getMonth(), (/* @__PURE__ */ new Date()).getDate() + 1),
|
|
2714
|
+
parseDate(str) {
|
|
2715
|
+
if (typeof str == "string") {
|
|
2716
|
+
var results = str.match(/^ *(\d{4})-(\d{1,2})-(\d{1,2}) *$/);
|
|
2717
|
+
if (results && results.length > 3) return new Date(parseInt(results[1]), parseInt(results[2]) - 1, parseInt(results[3]));
|
|
2718
|
+
results = str.match(/^ *(\d{4})-(\d{1,2})-(\d{1,2}) +(\d{1,2}):(\d{1,2}):(\d{1,2}) *$/);
|
|
2719
|
+
if (results && results.length > 6)
|
|
2720
|
+
return new Date(
|
|
2721
|
+
parseInt(results[1]),
|
|
2722
|
+
parseInt(results[2]) - 1,
|
|
2723
|
+
parseInt(results[3]),
|
|
2724
|
+
parseInt(results[4]),
|
|
2725
|
+
parseInt(results[5]),
|
|
2726
|
+
parseInt(results[6])
|
|
2727
|
+
);
|
|
2728
|
+
results = str.match(/^ *(\d{4})-(\d{1,2})-(\d{1,2}) +(\d{1,2}):(\d{1,2}):(\d{1,2})\.(\d{1,9}) *$/);
|
|
2729
|
+
if (results && results.length > 7)
|
|
2730
|
+
return new Date(
|
|
2731
|
+
parseInt(results[1]),
|
|
2732
|
+
parseInt(results[2]) - 1,
|
|
2733
|
+
parseInt(results[3]),
|
|
2734
|
+
parseInt(results[4]),
|
|
2735
|
+
parseInt(results[5]),
|
|
2736
|
+
parseInt(results[6]),
|
|
2737
|
+
parseInt(results[7])
|
|
2738
|
+
);
|
|
2739
|
+
}
|
|
2740
|
+
return null;
|
|
2741
|
+
},
|
|
2742
|
+
/**
|
|
2743
|
+
* 格式化时间间隔
|
|
2744
|
+
*
|
|
2745
|
+
* @param startTime 开始时间,可以是字符串、数字或日期类型
|
|
2746
|
+
* @param endTime 结束时间,可以是字符串、数字或日期类型
|
|
2747
|
+
* @returns 返回格式化后的时间间隔字符串,格式为"天数 天 小时 时 分钟 分 秒 秒"或"少于1秒"
|
|
1655
2748
|
*/
|
|
1656
|
-
|
|
1657
|
-
|
|
2749
|
+
formatDateInterval(startTime, endTime) {
|
|
2750
|
+
const dateCreateTime = new Date(startTime);
|
|
2751
|
+
const dateFinishTime = new Date(endTime);
|
|
2752
|
+
const dateInterval = dateFinishTime.getTime() - dateCreateTime.getTime();
|
|
2753
|
+
const days = Math.floor(dateInterval / (24 * 3600 * 1e3));
|
|
2754
|
+
const leave1 = dateInterval % (24 * 3600 * 1e3);
|
|
2755
|
+
const hours = Math.floor(leave1 / (3600 * 1e3));
|
|
2756
|
+
const leave2 = leave1 % (3600 * 1e3);
|
|
2757
|
+
const minutes = Math.floor(leave2 / (60 * 1e3));
|
|
2758
|
+
const leave3 = leave2 % (60 * 1e3);
|
|
2759
|
+
const seconds = Math.round(leave3 / 1e3);
|
|
2760
|
+
let intervalDes = "";
|
|
2761
|
+
if (days > 0) {
|
|
2762
|
+
intervalDes += days + "天";
|
|
2763
|
+
}
|
|
2764
|
+
if (hours > 0) {
|
|
2765
|
+
intervalDes += hours + "时";
|
|
2766
|
+
}
|
|
2767
|
+
if (minutes > 0) {
|
|
2768
|
+
intervalDes += minutes + "分";
|
|
2769
|
+
}
|
|
2770
|
+
if (seconds > 0) {
|
|
2771
|
+
intervalDes += seconds + "秒";
|
|
2772
|
+
}
|
|
2773
|
+
if (days === 0 && hours === 0 && minutes === 0 && seconds === 0) {
|
|
2774
|
+
intervalDes = "少于1秒";
|
|
2775
|
+
}
|
|
2776
|
+
return intervalDes;
|
|
1658
2777
|
},
|
|
2778
|
+
formatterCounter(times) {
|
|
2779
|
+
const checked = function(j) {
|
|
2780
|
+
return (j > 10 ? "" : "0") + (j || 0);
|
|
2781
|
+
};
|
|
2782
|
+
const houres = checked(Math.floor(times / 3600));
|
|
2783
|
+
const level1 = times % 3600;
|
|
2784
|
+
const minutes = checked(Math.floor(level1 / 60));
|
|
2785
|
+
const leave2 = level1 % 60;
|
|
2786
|
+
const seconds = checked(Math.round(leave2));
|
|
2787
|
+
return `${houres}:${minutes}:${seconds}`;
|
|
2788
|
+
},
|
|
2789
|
+
sleep(d) {
|
|
2790
|
+
}
|
|
2791
|
+
};
|
|
2792
|
+
function trim(str) {
|
|
2793
|
+
return str.trim ? str.trim() : str.replace(/^\s+|\s+$/g, "");
|
|
2794
|
+
}
|
|
2795
|
+
function splitWords(str) {
|
|
2796
|
+
return trim(str).split(/\s+/);
|
|
2797
|
+
}
|
|
2798
|
+
const DomUtil = {
|
|
1659
2799
|
/**
|
|
1660
|
-
*
|
|
2800
|
+
* 获取元素的样式值
|
|
1661
2801
|
*
|
|
1662
|
-
* @param
|
|
1663
|
-
* @param
|
|
1664
|
-
* @returns
|
|
2802
|
+
* @param el 元素对象
|
|
2803
|
+
* @param style 样式属性名称
|
|
2804
|
+
* @returns 元素的样式值,如果获取不到则返回 null
|
|
1665
2805
|
*/
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
let
|
|
1669
|
-
|
|
2806
|
+
getStyle(el, style) {
|
|
2807
|
+
var _a;
|
|
2808
|
+
let value = el.style[style];
|
|
2809
|
+
if (!value || value === "auto") {
|
|
2810
|
+
const css = (_a = document.defaultView) == null ? void 0 : _a.getComputedStyle(el, null);
|
|
2811
|
+
value = css ? css[style] : null;
|
|
2812
|
+
if (value === "auto") value = null;
|
|
2813
|
+
}
|
|
2814
|
+
return value;
|
|
1670
2815
|
},
|
|
1671
2816
|
/**
|
|
1672
|
-
*
|
|
2817
|
+
* 创建一个HTML元素
|
|
1673
2818
|
*
|
|
1674
|
-
* @param
|
|
1675
|
-
* @param
|
|
1676
|
-
* @
|
|
2819
|
+
* @param tagName 元素标签名
|
|
2820
|
+
* @param className 元素类名
|
|
2821
|
+
* @param container 父容器,若传入,则新创建的元素会被添加到该容器中
|
|
2822
|
+
* @returns 返回新创建的HTML元素
|
|
1677
2823
|
*/
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
2824
|
+
create(tagName, className, container) {
|
|
2825
|
+
const el = document.createElement(tagName);
|
|
2826
|
+
el.className = className || "";
|
|
2827
|
+
if (container) {
|
|
2828
|
+
container.appendChild(el);
|
|
1683
2829
|
}
|
|
1684
|
-
return
|
|
2830
|
+
return el;
|
|
1685
2831
|
},
|
|
1686
2832
|
/**
|
|
1687
|
-
*
|
|
2833
|
+
* 从父节点中移除指定元素。
|
|
1688
2834
|
*
|
|
1689
|
-
* @param
|
|
1690
|
-
* @param lat 纬度字符串
|
|
1691
|
-
* @returns 转换后的经纬度对象
|
|
2835
|
+
* @param el 要移除的元素对象,必须包含parentNode属性。
|
|
1692
2836
|
*/
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
let c = 0;
|
|
1698
|
-
for (let l = 0; l < a.length; l++)
|
|
1699
|
-
c += parseFloat(a[l]) / o, o *= 60;
|
|
1700
|
-
return c;
|
|
2837
|
+
remove(el) {
|
|
2838
|
+
const parent = el.parentNode;
|
|
2839
|
+
if (parent) {
|
|
2840
|
+
parent.removeChild(el);
|
|
1701
2841
|
}
|
|
1702
|
-
if (t && e)
|
|
1703
|
-
return {
|
|
1704
|
-
lng: n(t),
|
|
1705
|
-
lat: n(e)
|
|
1706
|
-
};
|
|
1707
2842
|
},
|
|
1708
2843
|
/**
|
|
1709
|
-
*
|
|
2844
|
+
* 清空给定元素的子节点
|
|
1710
2845
|
*
|
|
1711
|
-
* @param
|
|
1712
|
-
* @param poly 多边形顶点数组,可以是字符串数组或对象数组
|
|
1713
|
-
* @returns 返回字符串,表示点相对于多边形的位置:'in'表示在多边形内,'out'表示在多边形外,'on'表示在多边形上
|
|
2846
|
+
* @param el 要清空子节点的元素,包含firstChild和removeChild属性
|
|
1714
2847
|
*/
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
if (l === n && u === r || h === n && d === r)
|
|
1719
|
-
return "on";
|
|
1720
|
-
if (u < r && d >= r || u >= r && d < r) {
|
|
1721
|
-
var f = l + (r - u) * (h - l) / (d - u);
|
|
1722
|
-
if (f === n)
|
|
1723
|
-
return "on";
|
|
1724
|
-
f > n && (i = !i);
|
|
1725
|
-
}
|
|
2848
|
+
empty(el) {
|
|
2849
|
+
while (el.firstChild) {
|
|
2850
|
+
el.removeChild(el.firstChild);
|
|
1726
2851
|
}
|
|
1727
|
-
return i ? "in" : "out";
|
|
1728
2852
|
},
|
|
1729
2853
|
/**
|
|
1730
|
-
*
|
|
2854
|
+
* 将元素移到父节点的最前面
|
|
1731
2855
|
*
|
|
1732
|
-
* @param
|
|
1733
|
-
* @param p2 旋转中心坐标
|
|
1734
|
-
* @param θ 旋转角度(顺时针旋转为正)
|
|
1735
|
-
* @returns 旋转后点坐标
|
|
2856
|
+
* @param el 要移动的元素,需要包含 parentNode 属性
|
|
1736
2857
|
*/
|
|
1737
|
-
|
|
1738
|
-
const
|
|
1739
|
-
|
|
2858
|
+
toFront(el) {
|
|
2859
|
+
const parent = el.parentNode;
|
|
2860
|
+
if (parent && parent.lastChild !== el) {
|
|
2861
|
+
parent.appendChild(el);
|
|
2862
|
+
}
|
|
1740
2863
|
},
|
|
1741
2864
|
/**
|
|
1742
|
-
*
|
|
2865
|
+
* 将元素移动到其父节点的最前面
|
|
1743
2866
|
*
|
|
1744
|
-
* @param
|
|
1745
|
-
* @param p2 第二个点的坐标对象
|
|
1746
|
-
* @returns 返回一个对象,包含angle和distance属性,分别表示两点之间的角度(以度为单位,取值范围为0~359)和距离
|
|
2867
|
+
* @param el 要移动的元素,需要包含parentNode属性
|
|
1747
2868
|
*/
|
|
1748
|
-
|
|
1749
|
-
const
|
|
1750
|
-
|
|
2869
|
+
toBack(el) {
|
|
2870
|
+
const parent = el.parentNode;
|
|
2871
|
+
if (parent && parent.firstChild !== el) {
|
|
2872
|
+
parent.insertBefore(el, parent.firstChild);
|
|
2873
|
+
}
|
|
1751
2874
|
},
|
|
1752
2875
|
/**
|
|
1753
|
-
*
|
|
2876
|
+
* 获取元素的类名
|
|
1754
2877
|
*
|
|
1755
|
-
* @param
|
|
1756
|
-
* @param
|
|
1757
|
-
* @
|
|
2878
|
+
* @param el 包含对应元素和类名的对象
|
|
2879
|
+
* @param el.correspondingElement 对应的元素
|
|
2880
|
+
* @param el.className 类名对象
|
|
2881
|
+
* @param el.className.baseVal 类名字符串
|
|
2882
|
+
* @returns 返回元素的类名字符串
|
|
1758
2883
|
*/
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
return
|
|
1762
|
-
angle: l,
|
|
1763
|
-
distance: m
|
|
1764
|
-
};
|
|
2884
|
+
getClass(el) {
|
|
2885
|
+
const shadowElement = (el == null ? void 0 : el.host) || el;
|
|
2886
|
+
return shadowElement.className.toString();
|
|
1765
2887
|
},
|
|
1766
2888
|
/**
|
|
1767
|
-
*
|
|
2889
|
+
* 判断元素是否包含指定类名
|
|
1768
2890
|
*
|
|
1769
|
-
* @param
|
|
1770
|
-
* @param
|
|
1771
|
-
* @
|
|
1772
|
-
* @returns 点P到线段P1P2的最短距离
|
|
2891
|
+
* @param el 元素对象,包含classList属性,classList属性包含contains方法
|
|
2892
|
+
* @param name 要判断的类名
|
|
2893
|
+
* @returns 返回一个布尔值,表示元素是否包含指定类名
|
|
1773
2894
|
*/
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
if (
|
|
1777
|
-
return
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
const d = u / h, f = o + (c - o) * d, m = a + (l - a) * d;
|
|
1782
|
-
return Math.sqrt((r - f) * (r - f) + (i - m) * (i - m));
|
|
2895
|
+
hasClass(el, name) {
|
|
2896
|
+
var _a;
|
|
2897
|
+
if ((_a = el.classList) == null ? void 0 : _a.contains(name)) {
|
|
2898
|
+
return true;
|
|
2899
|
+
}
|
|
2900
|
+
const className = this.getClass(el);
|
|
2901
|
+
return className.length > 0 && new RegExp(`(^|\\s)${name}(\\s|$)`).test(className);
|
|
1783
2902
|
},
|
|
1784
2903
|
/**
|
|
1785
|
-
*
|
|
2904
|
+
* 给指定的 HTML 元素添加类名
|
|
1786
2905
|
*
|
|
1787
|
-
* @param
|
|
1788
|
-
* @param
|
|
1789
|
-
* @param distance 距离值,单位为米,表示从当前点出发的距离
|
|
1790
|
-
* @returns 返回计算后的新经纬度点,类型为{lat: number, lng: number}
|
|
2906
|
+
* @param el 要添加类名的 HTML 元素
|
|
2907
|
+
* @param name 要添加的类名,多个类名之间用空格分隔
|
|
1791
2908
|
*/
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
2909
|
+
addClass(el, name) {
|
|
2910
|
+
if (el.classList !== void 0) {
|
|
2911
|
+
const classes = splitWords(name);
|
|
2912
|
+
for (let i = 0, len = classes.length; i < len; i++) {
|
|
2913
|
+
el.classList.add(classes[i]);
|
|
2914
|
+
}
|
|
2915
|
+
} else if (!this.hasClass(el, name)) {
|
|
2916
|
+
const className = this.getClass(el);
|
|
2917
|
+
this.setClass(el, (className ? className + " " : "") + name);
|
|
2918
|
+
}
|
|
1800
2919
|
},
|
|
1801
2920
|
/**
|
|
1802
|
-
*
|
|
2921
|
+
* 从元素中移除指定类名
|
|
1803
2922
|
*
|
|
1804
|
-
* @param
|
|
1805
|
-
* @param
|
|
1806
|
-
* @returns 返回包含转换后的经度lng和纬度lat的对象
|
|
2923
|
+
* @param el 要移除类名的元素
|
|
2924
|
+
* @param name 要移除的类名,多个类名用空格分隔
|
|
1807
2925
|
*/
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
2926
|
+
removeClass(el, name) {
|
|
2927
|
+
if (el.classList !== void 0) {
|
|
2928
|
+
const classes = splitWords(name);
|
|
2929
|
+
classes.forEach((className) => el.classList.remove(className));
|
|
2930
|
+
} else {
|
|
2931
|
+
this.setClass(el, (" " + this.getClass(el) + " ").replace(" " + name + " ", " ").trim());
|
|
2932
|
+
}
|
|
1813
2933
|
},
|
|
1814
2934
|
/**
|
|
1815
|
-
*
|
|
2935
|
+
* 设置元素的 CSS 类名
|
|
1816
2936
|
*
|
|
1817
|
-
* @param
|
|
1818
|
-
* @param
|
|
1819
|
-
* @returns 墨卡托坐标对象,包含x和y属性
|
|
2937
|
+
* @param el HTML 或 SVG 元素
|
|
2938
|
+
* @param name 要设置的类名,多个类名之间用空格分隔
|
|
1820
2939
|
*/
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
return { x: r, y: o };
|
|
2940
|
+
setClass(el, name) {
|
|
2941
|
+
if ("classList" in el) {
|
|
2942
|
+
el.classList.value = "";
|
|
2943
|
+
name.split(" ").forEach((className) => el.classList.add(className));
|
|
2944
|
+
}
|
|
1827
2945
|
},
|
|
1828
2946
|
/**
|
|
1829
|
-
*
|
|
2947
|
+
* 从字符串中解析XML文档,并返回根节点
|
|
1830
2948
|
*
|
|
1831
|
-
* @param
|
|
1832
|
-
* @
|
|
1833
|
-
* @param percent 百分比,取值范围0-1
|
|
1834
|
-
* @returns 返回插值后的坐标
|
|
2949
|
+
* @param str 要解析的XML字符串
|
|
2950
|
+
* @returns 解析后的XML文档的根节点
|
|
1835
2951
|
*/
|
|
1836
|
-
|
|
1837
|
-
const
|
|
1838
|
-
|
|
2952
|
+
parseFromString(str) {
|
|
2953
|
+
const parser = new DOMParser();
|
|
2954
|
+
const doc = parser.parseFromString(str, "text/xml");
|
|
2955
|
+
return doc.children[0];
|
|
1839
2956
|
}
|
|
1840
|
-
}
|
|
2957
|
+
};
|
|
2958
|
+
const FileUtil = {
|
|
1841
2959
|
/**
|
|
1842
2960
|
* 将Base64编码的字符串转换为Blob对象
|
|
1843
2961
|
*
|
|
1844
2962
|
* @param data Base64编码的字符串
|
|
1845
2963
|
* @returns 转换后的Blob对象
|
|
1846
2964
|
*/
|
|
1847
|
-
convertBase64ToBlob(
|
|
1848
|
-
const
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
2965
|
+
convertBase64ToBlob(data) {
|
|
2966
|
+
const mimeString = data.split(",")[0].split(":")[1].split(";")[0];
|
|
2967
|
+
const byteCharacters = atob(data.split(",")[1]);
|
|
2968
|
+
const byteNumbers = new Array(byteCharacters.length);
|
|
2969
|
+
for (let i = 0; i < byteCharacters.length; i++) {
|
|
2970
|
+
byteNumbers[i] = byteCharacters.charCodeAt(i);
|
|
2971
|
+
}
|
|
2972
|
+
const byteArray = new Uint8Array(byteNumbers);
|
|
2973
|
+
const blob = new Blob([byteArray], { type: mimeString });
|
|
2974
|
+
return blob;
|
|
1853
2975
|
},
|
|
1854
2976
|
/**
|
|
1855
2977
|
* 将图片的URL转换为Base64编码
|
|
@@ -1866,11 +2988,17 @@ const V = {
|
|
|
1866
2988
|
* @param filename 文件的名称
|
|
1867
2989
|
* @returns 返回文件对象
|
|
1868
2990
|
*/
|
|
1869
|
-
convertBase64ToFile(
|
|
1870
|
-
const
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
2991
|
+
convertBase64ToFile(dataurl, filename) {
|
|
2992
|
+
const arr = dataurl.split(",");
|
|
2993
|
+
const mimeMatch = arr[0].match(/:(.*?);/);
|
|
2994
|
+
const mime = mimeMatch ? mimeMatch[1] : "image/png";
|
|
2995
|
+
const bstr = atob(arr[1]);
|
|
2996
|
+
const u8arr = new Uint8Array(bstr.length);
|
|
2997
|
+
for (let i = 0; i < bstr.length; i++) {
|
|
2998
|
+
u8arr[i] = bstr.charCodeAt(i);
|
|
2999
|
+
}
|
|
3000
|
+
const file = new File([u8arr], filename, { type: mime });
|
|
3001
|
+
return file;
|
|
1874
3002
|
},
|
|
1875
3003
|
/**
|
|
1876
3004
|
* 从文件下载数据
|
|
@@ -1878,22 +3006,27 @@ const V = {
|
|
|
1878
3006
|
* @param data 要下载的数据,可以是字符串数组、BlobPart 或 MediaSource
|
|
1879
3007
|
* @param saveName 下载后文件的保存名称
|
|
1880
3008
|
*/
|
|
1881
|
-
downloadFromFile(
|
|
1882
|
-
if (typeof
|
|
1883
|
-
if (
|
|
1884
|
-
|
|
1885
|
-
else {
|
|
1886
|
-
const
|
|
1887
|
-
|
|
3009
|
+
downloadFromFile(data, saveName) {
|
|
3010
|
+
if (typeof data == "object") {
|
|
3011
|
+
if (data instanceof Blob) {
|
|
3012
|
+
data = URL.createObjectURL(data);
|
|
3013
|
+
} else {
|
|
3014
|
+
const str = JSON.stringify(data);
|
|
3015
|
+
const blob = new Blob([str], { type: "text/json" });
|
|
3016
|
+
data = window.URL.createObjectURL(blob);
|
|
1888
3017
|
}
|
|
1889
|
-
else if (typeof
|
|
1890
|
-
const
|
|
1891
|
-
|
|
3018
|
+
} else if (typeof data == "string" && data.indexOf("http") === -1) {
|
|
3019
|
+
const blob = new Blob([data], { type: "text/json" });
|
|
3020
|
+
data = window.URL.createObjectURL(blob);
|
|
1892
3021
|
}
|
|
1893
|
-
var
|
|
1894
|
-
|
|
3022
|
+
var link = document.createElement("a");
|
|
3023
|
+
link.href = data;
|
|
3024
|
+
link.download = saveName || "";
|
|
3025
|
+
link.click();
|
|
3026
|
+
window.URL.revokeObjectURL(link.href);
|
|
1895
3027
|
}
|
|
1896
|
-
}
|
|
3028
|
+
};
|
|
3029
|
+
const OptimizeUtil = {
|
|
1897
3030
|
/**
|
|
1898
3031
|
* 防抖函数,在指定的等待时间内,如果连续触发事件,则只在最后一次触发后执行函数。适用于像搜索输入框这种需要用户停止输入后才调用的场景
|
|
1899
3032
|
*
|
|
@@ -1902,16 +3035,35 @@ const V = {
|
|
|
1902
3035
|
* @param immediate 是否立即执行函数,默认为true。
|
|
1903
3036
|
* @returns 返回防抖后的函数。
|
|
1904
3037
|
*/
|
|
1905
|
-
debounce(
|
|
1906
|
-
let
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
3038
|
+
debounce(func, wait, immediate = true) {
|
|
3039
|
+
let timeout = null;
|
|
3040
|
+
let args;
|
|
3041
|
+
let timestamp;
|
|
3042
|
+
let result;
|
|
3043
|
+
const later = () => {
|
|
3044
|
+
const last = Date.now() - timestamp;
|
|
3045
|
+
if (last < wait && last > 0) {
|
|
3046
|
+
timeout = setTimeout(later, wait - last);
|
|
3047
|
+
} else {
|
|
3048
|
+
timeout = null;
|
|
3049
|
+
if (!immediate) {
|
|
3050
|
+
result = func.apply(this, args);
|
|
3051
|
+
}
|
|
3052
|
+
}
|
|
1910
3053
|
};
|
|
1911
|
-
return (...
|
|
1912
|
-
|
|
1913
|
-
const
|
|
1914
|
-
|
|
3054
|
+
return (...args2) => {
|
|
3055
|
+
timestamp = Date.now();
|
|
3056
|
+
const callNow = immediate && !timeout;
|
|
3057
|
+
if (!timeout) {
|
|
3058
|
+
timeout = setTimeout(later, wait);
|
|
3059
|
+
}
|
|
3060
|
+
if (callNow) {
|
|
3061
|
+
result = func.apply(this, args2);
|
|
3062
|
+
if (!timeout) {
|
|
3063
|
+
args2 = null;
|
|
3064
|
+
}
|
|
3065
|
+
}
|
|
3066
|
+
return result;
|
|
1915
3067
|
};
|
|
1916
3068
|
},
|
|
1917
3069
|
/**
|
|
@@ -1922,15 +3074,24 @@ const V = {
|
|
|
1922
3074
|
* @param type 节流类型,1表示时间戳方式,2表示定时器方式
|
|
1923
3075
|
* @returns 返回一个新的函数,该函数在节流控制下执行传入的函数
|
|
1924
3076
|
*/
|
|
1925
|
-
throttle(
|
|
1926
|
-
let
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
3077
|
+
throttle(func, wait, type = 1) {
|
|
3078
|
+
let previous = 0;
|
|
3079
|
+
let timeout = null;
|
|
3080
|
+
return (...args) => {
|
|
3081
|
+
if (type === 1) {
|
|
3082
|
+
const now = Date.now();
|
|
3083
|
+
if (now - previous >= wait) {
|
|
3084
|
+
func.apply(this, args);
|
|
3085
|
+
previous = now;
|
|
3086
|
+
}
|
|
3087
|
+
} else if (type === 2) {
|
|
3088
|
+
if (!timeout) {
|
|
3089
|
+
timeout = setTimeout(() => {
|
|
3090
|
+
timeout = null;
|
|
3091
|
+
func.apply(this, args);
|
|
3092
|
+
}, wait);
|
|
3093
|
+
}
|
|
3094
|
+
}
|
|
1934
3095
|
};
|
|
1935
3096
|
},
|
|
1936
3097
|
/**
|
|
@@ -1939,15 +3100,16 @@ const V = {
|
|
|
1939
3100
|
* @param fn 传入待缓存的函数
|
|
1940
3101
|
* @returns 返回缓存后的函数
|
|
1941
3102
|
*/
|
|
1942
|
-
memoize(
|
|
1943
|
-
const
|
|
1944
|
-
return (...
|
|
1945
|
-
const
|
|
1946
|
-
if (
|
|
1947
|
-
return
|
|
1948
|
-
{
|
|
1949
|
-
const
|
|
1950
|
-
|
|
3103
|
+
memoize(fn) {
|
|
3104
|
+
const cache = /* @__PURE__ */ new Map();
|
|
3105
|
+
return (...args) => {
|
|
3106
|
+
const argsString = JSON.stringify(args);
|
|
3107
|
+
if (cache.has(argsString)) {
|
|
3108
|
+
return cache.get(argsString);
|
|
3109
|
+
} else {
|
|
3110
|
+
const result = fn.apply(this, args);
|
|
3111
|
+
cache.set(argsString, result);
|
|
3112
|
+
return result;
|
|
1951
3113
|
}
|
|
1952
3114
|
};
|
|
1953
3115
|
},
|
|
@@ -1958,253 +3120,50 @@ const V = {
|
|
|
1958
3120
|
* @param frequency 每次调用函数之间的时间间隔,单位为毫秒,默认为500毫秒。
|
|
1959
3121
|
* @param duration 函数递归调用的总时长,单位为毫秒,默认为5000毫秒。
|
|
1960
3122
|
*/
|
|
1961
|
-
recurve(
|
|
1962
|
-
let
|
|
3123
|
+
recurve(fun, frequency = 500, duration = 5e3) {
|
|
3124
|
+
let timer = 0;
|
|
1963
3125
|
setTimeout(() => {
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
/**
|
|
1969
|
-
* 校验字符串是否符合指定类型
|
|
1970
|
-
*
|
|
1971
|
-
* @param str 待校验字符串
|
|
1972
|
-
* @param type 校验类型,可选值包括:
|
|
1973
|
-
* - 'phone': 手机号码
|
|
1974
|
-
* - 'tel': 座机
|
|
1975
|
-
* - 'card': 身份证
|
|
1976
|
-
* - 'pwd': 密码(以字母开头,长度在6~18之间,只能包含字母、数字和下划线)
|
|
1977
|
-
* - 'postal': 邮政编码
|
|
1978
|
-
* - 'QQ': QQ号
|
|
1979
|
-
* - 'email': 邮箱
|
|
1980
|
-
* - 'money': 金额(小数点2位)
|
|
1981
|
-
* - 'URL': 网址
|
|
1982
|
-
* - 'IP': IP地址
|
|
1983
|
-
* - 'date': 日期时间
|
|
1984
|
-
* - 'number': 数字
|
|
1985
|
-
* - 'english': 英文
|
|
1986
|
-
* - 'chinese': 中文
|
|
1987
|
-
* - 'lower': 小写字母
|
|
1988
|
-
* - 'upper': 大写字母
|
|
1989
|
-
* - 'HTML': HTML标记
|
|
1990
|
-
* @returns 校验结果,符合返回true,否则返回false
|
|
1991
|
-
*/
|
|
1992
|
-
checkStr(t, e) {
|
|
1993
|
-
switch (e) {
|
|
1994
|
-
case "phone":
|
|
1995
|
-
return /^1[3|4|5|6|7|8|9][0-9]{9}$/.test(t);
|
|
1996
|
-
case "tel":
|
|
1997
|
-
return /^(0\d{2,3}-\d{7,8})(-\d{1,4})?$/.test(t);
|
|
1998
|
-
case "card":
|
|
1999
|
-
return /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/.test(t);
|
|
2000
|
-
case "pwd":
|
|
2001
|
-
return /^[a-zA-Z]\w{5,17}$/.test(t);
|
|
2002
|
-
case "postal":
|
|
2003
|
-
return /[1-9]\d{5}(?!\d)/.test(t);
|
|
2004
|
-
case "QQ":
|
|
2005
|
-
return /^[1-9][0-9]{4,9}$/.test(t);
|
|
2006
|
-
case "email":
|
|
2007
|
-
return /^[\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)+$/.test(t);
|
|
2008
|
-
case "money":
|
|
2009
|
-
return /^\d*(?:\.\d{0,2})?$/.test(t);
|
|
2010
|
-
case "URL":
|
|
2011
|
-
return /(http|ftp|https):\/\/[\w\-_]+(\.[\w\-_]+)+([\w\-\.,@?^=%&:/~\+#]*[\w\-\@?^=%&/~\+#])?/.test(t);
|
|
2012
|
-
case "IP":
|
|
2013
|
-
return /((?:(?:25[0-5]|2[0-4]\\d|[01]?\\d?\\d)\\.){3}(?:25[0-5]|2[0-4]\\d|[01]?\\d?\\d))/.test(t);
|
|
2014
|
-
case "date":
|
|
2015
|
-
return /^(\d{4})\-(\d{2})\-(\d{2}) (\d{2})(?:\:\d{2}|:(\d{2}):(\d{2}))$/.test(t) || /^(\d{4})\-(\d{2})\-(\d{2})$/.test(t);
|
|
2016
|
-
case "number":
|
|
2017
|
-
return /^[0-9]$/.test(t);
|
|
2018
|
-
case "english":
|
|
2019
|
-
return /^[a-zA-Z]+$/.test(t);
|
|
2020
|
-
case "chinese":
|
|
2021
|
-
return /^[\u4E00-\u9FA5]+$/.test(t);
|
|
2022
|
-
case "lower":
|
|
2023
|
-
return /^[a-z]+$/.test(t);
|
|
2024
|
-
case "upper":
|
|
2025
|
-
return /^[A-Z]+$/.test(t);
|
|
2026
|
-
case "HTML":
|
|
2027
|
-
return /<("[^"]*"|'[^']*'|[^'">])*>/.test(t);
|
|
2028
|
-
default:
|
|
2029
|
-
return !0;
|
|
2030
|
-
}
|
|
2031
|
-
},
|
|
2032
|
-
/**
|
|
2033
|
-
* 转换字符串大小写
|
|
2034
|
-
*
|
|
2035
|
-
* @param str 待转换的字符串
|
|
2036
|
-
* @param type 转换类型,可选值为 1-5,默认为 4
|
|
2037
|
-
* 1:首字母大写,其余小写
|
|
2038
|
-
* 2:首字母小写,其余大写
|
|
2039
|
-
* 3:字母大小写反转
|
|
2040
|
-
* 4:全部大写
|
|
2041
|
-
* 5:全部小写
|
|
2042
|
-
* @returns 转换后的字符串
|
|
2043
|
-
*/
|
|
2044
|
-
changeCase(t, e) {
|
|
2045
|
-
switch (e = e || 4, e) {
|
|
2046
|
-
case 1:
|
|
2047
|
-
return t.replace(/\b\w+\b/g, function(n) {
|
|
2048
|
-
return n.substring(0, 1).toUpperCase() + n.substring(1).toLowerCase();
|
|
2049
|
-
});
|
|
2050
|
-
case 2:
|
|
2051
|
-
return t.replace(/\b\w+\b/g, function(n) {
|
|
2052
|
-
return n.substring(0, 1).toLowerCase() + n.substring(1).toUpperCase();
|
|
2053
|
-
});
|
|
2054
|
-
case 3:
|
|
2055
|
-
return t.split("").map(function(n) {
|
|
2056
|
-
return /[a-z]/.test(n) ? n.toUpperCase() : n.toLowerCase();
|
|
2057
|
-
}).join("");
|
|
2058
|
-
case 4:
|
|
2059
|
-
return t.toUpperCase();
|
|
2060
|
-
case 5:
|
|
2061
|
-
return t.toLowerCase();
|
|
2062
|
-
default:
|
|
2063
|
-
return t;
|
|
2064
|
-
}
|
|
2065
|
-
},
|
|
2066
|
-
/**
|
|
2067
|
-
* 根据字符串数组和参数生成新的字符串
|
|
2068
|
-
*
|
|
2069
|
-
* @param strArray 字符串数组
|
|
2070
|
-
* @param args 可变参数列表,支持 Object、Array 类型和任意其他类型,若为 null 或 undefined,则按类型默认转换为 '{}'、'[]' 或 ''
|
|
2071
|
-
* @returns 返回生成的新字符串
|
|
2072
|
-
*/
|
|
2073
|
-
tag(t, ...e) {
|
|
2074
|
-
return e = e.map((n) => {
|
|
2075
|
-
switch (M.getDataType(n)) {
|
|
2076
|
-
case "Object":
|
|
2077
|
-
return n || "{}";
|
|
2078
|
-
case "Array":
|
|
2079
|
-
return n || "[]";
|
|
2080
|
-
default:
|
|
2081
|
-
return n || "";
|
|
3126
|
+
timer++;
|
|
3127
|
+
if (timer < Math.floor(duration / frequency)) {
|
|
3128
|
+
fun.call(this);
|
|
3129
|
+
setTimeout(this.recurve.bind(this, fun, frequency, duration), frequency);
|
|
2082
3130
|
}
|
|
2083
|
-
}
|
|
2084
|
-
},
|
|
2085
|
-
/**
|
|
2086
|
-
* 计算字符串的字节长度
|
|
2087
|
-
*
|
|
2088
|
-
* @param str 需要计算字节长度的字符串
|
|
2089
|
-
* @returns 返回字符串的字节长度
|
|
2090
|
-
*/
|
|
2091
|
-
getByteLength(t) {
|
|
2092
|
-
return t.replace(/[\u0391-\uFFE5]/g, "aa").length;
|
|
2093
|
-
},
|
|
2094
|
-
/**
|
|
2095
|
-
* 截取字符串中指定字节长度的子串
|
|
2096
|
-
*
|
|
2097
|
-
* @param str 字符串对象,包含replace、length和substring方法
|
|
2098
|
-
* @param start 截取起始位置
|
|
2099
|
-
* @param n 截取字节长度
|
|
2100
|
-
* @returns 返回截取后的子串
|
|
2101
|
-
*/
|
|
2102
|
-
subStringByte(t, e, n) {
|
|
2103
|
-
var r = /[^\x00-\xff]/g;
|
|
2104
|
-
if (t.replace(r, "mm").length <= n)
|
|
2105
|
-
return t;
|
|
2106
|
-
for (var i = Math.floor(n / 2), o = i; o < t.length; o++) {
|
|
2107
|
-
let a = t.substring(e, o);
|
|
2108
|
-
if (a.replace(r, "mm").length >= n)
|
|
2109
|
-
return a;
|
|
2110
|
-
}
|
|
2111
|
-
return t;
|
|
3131
|
+
}, frequency);
|
|
2112
3132
|
},
|
|
2113
3133
|
/**
|
|
2114
|
-
*
|
|
3134
|
+
* 确保函数只被调用一次
|
|
2115
3135
|
*
|
|
2116
|
-
* @param
|
|
2117
|
-
* @returns
|
|
3136
|
+
* @param func 要被调用的函数
|
|
3137
|
+
* @returns 返回一个新的函数,该函数在被首次调用时会执行传入的函数,之后再次调用将不再执行
|
|
2118
3138
|
*/
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
return t;
|
|
2128
|
-
}
|
|
2129
|
-
},
|
|
2130
|
-
replaceAll(t, e, n) {
|
|
2131
|
-
if (!t)
|
|
2132
|
-
return t;
|
|
2133
|
-
for (; t.indexOf(e) > -1; )
|
|
2134
|
-
t = t.replace(e, n);
|
|
2135
|
-
return t;
|
|
2136
|
-
}
|
|
2137
|
-
}, p = class p {
|
|
2138
|
-
static set(e, n = null, r = null) {
|
|
2139
|
-
var i = this._getPrefixedKey(e, r);
|
|
2140
|
-
try {
|
|
2141
|
-
localStorage.setItem(i, JSON.stringify({ data: n }));
|
|
2142
|
-
} catch {
|
|
2143
|
-
console && console.warn("StoreUtil didn't successfully save the '{" + e + ": " + n + "}' pair, because the localStorage is full.");
|
|
2144
|
-
}
|
|
2145
|
-
}
|
|
2146
|
-
static get(e, n, r) {
|
|
2147
|
-
var i = this._getPrefixedKey(e, r), o;
|
|
2148
|
-
try {
|
|
2149
|
-
o = JSON.parse(localStorage.getItem(i) || "");
|
|
2150
|
-
} catch {
|
|
2151
|
-
localStorage[i] ? o = { data: localStorage.getItem(i) } : o = null;
|
|
2152
|
-
}
|
|
2153
|
-
if (o) {
|
|
2154
|
-
if (typeof o == "object" && typeof o.data < "u")
|
|
2155
|
-
return o.data;
|
|
2156
|
-
} else return n;
|
|
2157
|
-
}
|
|
2158
|
-
static keys() {
|
|
2159
|
-
const e = [];
|
|
2160
|
-
var n = Object.keys(localStorage);
|
|
2161
|
-
return p.prefix.length === 0 ? n : (n.forEach(function(r) {
|
|
2162
|
-
r.indexOf(p.prefix) !== -1 && e.push(r.replace(p.prefix, ""));
|
|
2163
|
-
}), e);
|
|
2164
|
-
}
|
|
2165
|
-
static getAll(e) {
|
|
2166
|
-
var n = p.keys();
|
|
2167
|
-
if (e) {
|
|
2168
|
-
const r = [];
|
|
2169
|
-
return n.forEach((i) => {
|
|
2170
|
-
if (e.includes(i)) {
|
|
2171
|
-
const o = {};
|
|
2172
|
-
o[i] = p.get(i, null, null), r.push(o);
|
|
2173
|
-
}
|
|
2174
|
-
}), r;
|
|
2175
|
-
}
|
|
2176
|
-
return n.map((r) => p.get(r, null, null));
|
|
2177
|
-
}
|
|
2178
|
-
static remove(e, n) {
|
|
2179
|
-
var r = this._getPrefixedKey(e, n);
|
|
2180
|
-
localStorage.removeItem(r);
|
|
2181
|
-
}
|
|
2182
|
-
static clear(e) {
|
|
2183
|
-
p.prefix.length ? this.keys().forEach((n) => {
|
|
2184
|
-
localStorage.removeItem(this._getPrefixedKey(n, e));
|
|
2185
|
-
}) : localStorage.clear();
|
|
3139
|
+
once(func) {
|
|
3140
|
+
let called = false;
|
|
3141
|
+
return function(...args) {
|
|
3142
|
+
if (!called) {
|
|
3143
|
+
called = true;
|
|
3144
|
+
return func(...args);
|
|
3145
|
+
}
|
|
3146
|
+
};
|
|
2186
3147
|
}
|
|
2187
3148
|
};
|
|
2188
|
-
|
|
2189
|
-
return n = n || {}, n.noPrefix ? e : p.prefix + e;
|
|
2190
|
-
});
|
|
2191
|
-
let I = p;
|
|
2192
|
-
const rt = {
|
|
3149
|
+
const UrlUtil = {
|
|
2193
3150
|
/**
|
|
2194
3151
|
* 将json对象转换为查询字符串
|
|
2195
3152
|
*
|
|
2196
3153
|
* @param json 待转换的json对象
|
|
2197
3154
|
* @returns 转换后的查询字符串
|
|
2198
3155
|
*/
|
|
2199
|
-
json2Query(
|
|
2200
|
-
var
|
|
2201
|
-
for (var
|
|
2202
|
-
if (
|
|
2203
|
-
var
|
|
2204
|
-
|
|
3156
|
+
json2Query(json) {
|
|
3157
|
+
var tempArr = [];
|
|
3158
|
+
for (var i in json) {
|
|
3159
|
+
if (json.hasOwnProperty(i)) {
|
|
3160
|
+
var key = i;
|
|
3161
|
+
var value = json[i];
|
|
3162
|
+
tempArr.push(encodeURIComponent(key) + "=" + encodeURIComponent(value));
|
|
2205
3163
|
}
|
|
2206
|
-
|
|
2207
|
-
|
|
3164
|
+
}
|
|
3165
|
+
var urlParamsStr = tempArr.join("&");
|
|
3166
|
+
return urlParamsStr;
|
|
2208
3167
|
},
|
|
2209
3168
|
/**
|
|
2210
3169
|
* 从 URL 中解析出查询参数和哈希参数,并以对象的形式返回
|
|
@@ -2213,54 +3172,61 @@ const rt = {
|
|
|
2213
3172
|
* @param needDecode 是否需要解码参数值,默认为 true
|
|
2214
3173
|
* @returns 返回一个包含解析后参数的对象,其中键为参数名,值为参数值
|
|
2215
3174
|
*/
|
|
2216
|
-
query2Json(
|
|
2217
|
-
const
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
3175
|
+
query2Json(href = window.location.href, needDecode = true) {
|
|
3176
|
+
const reg = /([^&=]+)=([\w\W]*?)(&|$|#)/g;
|
|
3177
|
+
const { search, hash } = new URL(href);
|
|
3178
|
+
const args = [search, hash];
|
|
3179
|
+
let obj = {};
|
|
3180
|
+
for (let i = 0; i < args.length; i++) {
|
|
3181
|
+
const str = args[i];
|
|
3182
|
+
if (str) {
|
|
3183
|
+
const s = str.replace(/#|\//g, "");
|
|
3184
|
+
const arr = s.split("?");
|
|
3185
|
+
if (arr.length > 1) {
|
|
3186
|
+
for (let j = 1; j < arr.length; j++) {
|
|
3187
|
+
let res;
|
|
3188
|
+
while (res = reg.exec(arr[j])) {
|
|
3189
|
+
obj[res[1]] = needDecode ? decodeURIComponent(res[2]) : res[2];
|
|
3190
|
+
}
|
|
2228
3191
|
}
|
|
3192
|
+
}
|
|
2229
3193
|
}
|
|
2230
3194
|
}
|
|
2231
|
-
return
|
|
3195
|
+
return obj;
|
|
2232
3196
|
}
|
|
2233
3197
|
};
|
|
2234
3198
|
export {
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
|
|
2248
|
-
|
|
2249
|
-
|
|
2250
|
-
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
3199
|
+
AjaxUtil,
|
|
3200
|
+
ArrayUtil,
|
|
3201
|
+
AssertUtil,
|
|
3202
|
+
AudioPlayer,
|
|
3203
|
+
BrowserUtil,
|
|
3204
|
+
CanvasDrawer,
|
|
3205
|
+
ColorUtil,
|
|
3206
|
+
Cookie,
|
|
3207
|
+
CoordsUtil,
|
|
3208
|
+
DateUtil,
|
|
3209
|
+
DomUtil,
|
|
3210
|
+
ErrorType,
|
|
3211
|
+
EventDispatcher,
|
|
3212
|
+
EventType,
|
|
3213
|
+
FileUtil,
|
|
3214
|
+
GeoJsonUtil,
|
|
3215
|
+
GeoUtil,
|
|
3216
|
+
GraphicType,
|
|
3217
|
+
HashMap,
|
|
3218
|
+
ImageUtil,
|
|
3219
|
+
LayerType,
|
|
3220
|
+
LineSymbol,
|
|
3221
|
+
MathUtils as MathUtil,
|
|
3222
|
+
MeasureMode,
|
|
3223
|
+
MqttClient,
|
|
3224
|
+
ObjectState,
|
|
3225
|
+
ObjectUtil,
|
|
3226
|
+
OptimizeUtil,
|
|
3227
|
+
Storage,
|
|
3228
|
+
StringUtil,
|
|
3229
|
+
UrlUtil,
|
|
3230
|
+
CommUtil as Util,
|
|
3231
|
+
WebSocketClient
|
|
2266
3232
|
};
|