gis-common 4.2.2 → 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.
@@ -274,17 +274,14 @@ class CanvasDrawer {
274
274
  }
275
275
  }
276
276
  static createCanvas(width = 1, height = 1) {
277
- let canvas;
278
- if (typeof document !== "undefined") {
279
- canvas = document.createElement("canvas");
280
- if (width) {
281
- canvas.width = width;
282
- }
283
- if (height) {
284
- canvas.height = height;
285
- }
286
- return canvas;
277
+ const canvas = document.createElement("canvas");
278
+ if (width) {
279
+ canvas.width = width;
280
+ }
281
+ if (height) {
282
+ canvas.height = height;
287
283
  }
284
+ return canvas;
288
285
  }
289
286
  }
290
287
  class EventDispatcher {
@@ -476,7 +473,7 @@ class WebSocketClient extends EventDispatcher {
476
473
  }, 1e3);
477
474
  }
478
475
  }
479
- const CommUtils = {
476
+ const CommUtil = {
480
477
  /**
481
478
  * 获取数据类型
482
479
  *
@@ -535,9 +532,6 @@ const CommUtils = {
535
532
  return false;
536
533
  }
537
534
  },
538
- isNotEmpty(val) {
539
- return !this.isEmpty(val);
540
- },
541
535
  /**
542
536
  * 将JSON对象转换为FormData对象
543
537
  *
@@ -937,10 +931,10 @@ const _MqttClient = class _MqttClient extends EventDispatcher {
937
931
  __publicField(this, "options");
938
932
  __publicField(this, "client");
939
933
  __publicField(this, "topics");
940
- this.context = CommUtils.extend(_MqttClient.defaultContext, config);
934
+ this.context = CommUtil.extend(_MqttClient.defaultContext, config);
941
935
  this.options = {
942
936
  connectTimeout: this.context.MQTT_TIMEOUTM,
943
- clientId: CommUtils.guid(),
937
+ clientId: CommUtil.guid(),
944
938
  username: this.context.MQTT_USERNAME,
945
939
  password: this.context.MQTT_PASSWORD,
946
940
  clean: true
@@ -1247,7 +1241,7 @@ const AjaxUtil = {
1247
1241
  * @param callback - callback function when completed
1248
1242
  */
1249
1243
  jsonp(url, callback) {
1250
- const name = "_jsonp_" + CommUtils.guid();
1244
+ const name = "_jsonp_" + CommUtil.guid();
1251
1245
  const head = document.getElementsByTagName("head")[0];
1252
1246
  if (url.includes("?")) {
1253
1247
  url += "&callback=" + name;
@@ -1286,7 +1280,7 @@ const AjaxUtil = {
1286
1280
  * );
1287
1281
  */
1288
1282
  get(url, options, cb) {
1289
- if (CommUtils.isFunction(options)) {
1283
+ if (CommUtil.isFunction(options)) {
1290
1284
  const t = cb;
1291
1285
  cb = options;
1292
1286
  options = t;
@@ -1418,7 +1412,7 @@ const AjaxUtil = {
1418
1412
  * );
1419
1413
  */
1420
1414
  getArrayBuffer(url, options, cb) {
1421
- if (CommUtils.isFunction(options)) {
1415
+ if (CommUtil.isFunction(options)) {
1422
1416
  const t = cb;
1423
1417
  cb = options;
1424
1418
  options = t;
@@ -1471,7 +1465,7 @@ const AjaxUtil = {
1471
1465
  * );
1472
1466
  */
1473
1467
  getJSON(url, options, cb) {
1474
- if (CommUtils.isFunction(options)) {
1468
+ if (CommUtil.isFunction(options)) {
1475
1469
  const t = cb;
1476
1470
  cb = options;
1477
1471
  options = t;
@@ -1488,691 +1482,519 @@ const AjaxUtil = {
1488
1482
  return this.get(url, options, callback);
1489
1483
  }
1490
1484
  };
1491
- const BrowserUtil = {
1485
+ const GeoUtil = {
1486
+ toRadian: Math.PI / 180,
1487
+ R: 6371393,
1492
1488
  /**
1493
- * 获取浏览器类型
1489
+ * 判断给定的经纬度是否合法
1494
1490
  *
1495
- * @returns 返回浏览器类型字符串,可能的值为 'IE'、'Firefox'、'Chrome'、'Opera'、'Safari' 或 'Unknown'
1491
+ * @param lng 经度值
1492
+ * @param lat 纬度值
1493
+ * @returns 如果经纬度合法,返回true;否则返回false
1496
1494
  */
1497
- getExplorer() {
1498
- var explorer = window.navigator.userAgent;
1499
- if (explorer.indexOf("MSIE") >= 0 || /Trident\//.test(explorer)) {
1500
- return "IE";
1501
- } else if (explorer.indexOf("Firefox") >= 0) {
1502
- return "Firefox";
1503
- } else if (explorer.indexOf("Chrome") >= 0) {
1504
- return "Chrome";
1505
- } else if (explorer.indexOf("Opera") >= 0) {
1506
- return "Opera";
1507
- } else if (explorer.indexOf("Safari") >= 0 && explorer.indexOf("Chrome") === -1) {
1508
- return "Safari";
1509
- }
1510
- return "Unknown";
1495
+ isLnglat(lng, lat) {
1496
+ return !isNaN(lng) && !isNaN(lat) && !!(+lat > -90 && +lat < 90 && +lng > -180 && +lng < 180);
1511
1497
  },
1512
1498
  /**
1513
- * 检测操作系统类型
1499
+ * 计算两哥平面坐标点间的距离
1514
1500
  *
1515
- * @returns 返回操作系统类型字符串,可能的值有:'MS Windows'、'Apple mac'、'Linux'、'Unix'
1501
+ * @param p1 坐标点1,包含x和y属性
1502
+ * @param p2 坐标点2,包含x和y属性
1503
+ * @returns 返回两点间的欧几里得距离
1516
1504
  */
1517
- detectOS() {
1518
- let os_type = "";
1519
- const windows = navigator.userAgent.indexOf("Windows", 0) != -1 ? 1 : 0;
1520
- const mac = navigator.userAgent.indexOf("mac", 0) != -1 ? 1 : 0;
1521
- const linux = navigator.userAgent.indexOf("Linux", 0) != -1 ? 1 : 0;
1522
- const unix = navigator.userAgent.indexOf("X11", 0) != -1 ? 1 : 0;
1523
- if (windows) os_type = "MS Windows";
1524
- else if (mac) os_type = "Apple mac";
1525
- else if (linux) os_type = "Linux";
1526
- else if (unix) os_type = "Unix";
1527
- return os_type;
1505
+ distance(p1, p2) {
1506
+ return Math.sqrt(Math.pow(p2.x - p1.x, 2) + Math.pow(p2.y - p1.y, 2));
1528
1507
  },
1529
1508
  /**
1530
- * 切换全屏状态
1509
+ * 计算两个经纬度点之间的距离
1531
1510
  *
1532
- * @param status 是否全屏
1511
+ * @param A 经纬度点A,包含lng(经度)和lat(纬度)两个属性
1512
+ * @param B 经纬度点B,包含lng(经度)和lat(纬度)两个属性
1513
+ * @returns 返回两点之间的距离,单位为米
1533
1514
  */
1534
- switchFullScreen(status) {
1535
- if (status) {
1536
- const element = document.documentElement;
1537
- if (element.requestFullscreen) {
1538
- element.requestFullscreen();
1539
- } else if ("msRequestFullscreen" in element) {
1540
- element.msRequestFullscreen();
1541
- } else if ("mozRequestFullScreen" in element) {
1542
- element.mozRequestFullScreen();
1543
- } else if ("webkitRequestFullscreen" in element) {
1544
- element.webkitRequestFullscreen();
1545
- }
1546
- } else {
1547
- if (document.exitFullscreen) {
1548
- document.exitFullscreen();
1549
- } else if ("msExitFullscreen" in document) {
1550
- document.msExitFullscreen();
1551
- } else if ("mozCancelFullScreen" in document) {
1552
- document.mozCancelFullScreen();
1553
- } else if ("webkitExitFullscreen" in document) {
1554
- document.webkitExitFullscreen();
1555
- }
1556
- }
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;
1557
1527
  },
1558
1528
  /**
1559
- * 刷新缩放比例
1529
+ * 格式化经纬度为度分秒格式
1560
1530
  *
1561
- * @returns 无返回值
1531
+ * @param lng 经度
1532
+ * @param lat 纬度
1533
+ * @returns 返回格式化后的经纬度字符串,格式为:经度度分秒,纬度度分秒
1562
1534
  */
1563
- refreshScale() {
1564
- const baseWidth = document.documentElement.clientWidth || 0;
1565
- const baseHeight = document.documentElement.clientHeight || 0;
1566
- const appElement = document.getElementById("app");
1567
- if (!appElement) return;
1568
- const appStyle = appElement.style;
1569
- const realRatio = baseWidth / baseHeight;
1570
- const designRatio = 16 / 9;
1571
- let scaleRate = baseWidth / 1920;
1572
- if (realRatio > designRatio) {
1573
- scaleRate = baseHeight / 1080;
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)}″`;
1574
1542
  }
1575
- appStyle.transformOrigin = "left top";
1576
- appStyle.transform = `scale(${scaleRate}) translateX(-49.99%)`;
1577
- appStyle.width = `${baseWidth / scaleRate}px`;
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;
1578
1551
  },
1579
1552
  /**
1580
- * 获取HTML字体大小
1553
+ * 将经纬度字符串转换为度
1581
1554
  *
1582
- * @returns 无返回值,该函数会直接修改HTML元素的字体大小
1555
+ * @param lng 经度字符串
1556
+ * @param lat 纬度字符串
1557
+ * @returns 转换后的经纬度对象
1583
1558
  */
1584
- getHtmlFontSize() {
1585
- const htmlwidth = document.documentElement.clientWidth || document.body.clientWidth;
1586
- const htmlDom = document.querySelector("html");
1587
- if (htmlDom) {
1588
- htmlDom.style.fontSize = htmlwidth / 192 + "px";
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
+ };
1589
1576
  }
1590
- }
1591
- };
1592
- const CoordsUtil = {
1593
- PI: 3.141592653589793,
1594
- XPI: 3.141592653589793 * 3e3 / 180,
1595
- delta(lat, lng) {
1596
- const a = 6378245;
1597
- const ee = 0.006693421622965943;
1598
- let dLat = this.transformLat(lng - 105, lat - 35);
1599
- let dLon = this.transformLon(lng - 105, lat - 35);
1600
- const radLat = lat / 180 * this.PI;
1601
- let magic = Math.sin(radLat);
1602
- magic = 1 - ee * magic * magic;
1603
- const sqrtMagic = Math.sqrt(magic);
1604
- dLat = dLat * 180 / (a * (1 - ee) / (magic * sqrtMagic) * this.PI);
1605
- dLon = dLon * 180 / (a / sqrtMagic * Math.cos(radLat) * this.PI);
1606
- return { lat: dLat, lng: dLon };
1607
1577
  },
1608
1578
  /**
1609
- * 判断经纬度是否不在中国境内
1579
+ * 射线法判断点是否在多边形内
1610
1580
  *
1611
- * @param lng 经度
1612
- * @param lat 纬度
1613
- * @returns 如果经纬度不在中国境内则返回true,否则返回false
1581
+ * @param p 点对象,包含x和y属性
1582
+ * @param poly 多边形顶点数组,可以是字符串数组或对象数组
1583
+ * @returns 返回字符串,表示点相对于多边形的位置:'in'表示在多边形内,'out'表示在多边形外,'on'表示在多边形上
1614
1584
  */
1615
- outOfChina(lng, lat) {
1616
- if (lng < 72.004 || lng > 137.8347) {
1617
- return true;
1618
- }
1619
- if (lat < 0.8293 || lat > 55.8271) {
1620
- return true;
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
+ }
1621
1601
  }
1622
- return false;
1602
+ return flag ? "in" : "out";
1623
1603
  },
1624
- // WGS-84 to GCJ-02
1625
- gcjEncrypt(wgsLat, wgsLon) {
1626
- if (this.outOfChina(wgsLat, wgsLon)) {
1627
- return { lat: wgsLat, lng: wgsLon };
1628
- }
1629
- const d = this.delta(wgsLat, wgsLon);
1630
- return { lat: wgsLat + d.lat, lng: wgsLon + d.lng };
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 };
1631
1616
  },
1632
- // GCJ-02 to WGS-84
1633
- gcjDecrypt(gcjLat, gcjLon) {
1634
- if (this.outOfChina(gcjLat, gcjLon)) {
1635
- return { lat: gcjLat, lng: gcjLon };
1636
- }
1637
- const d = this.delta(gcjLat, gcjLon);
1638
- return { lat: gcjLat - d.lat, lng: gcjLon - d.lng };
1639
- },
1640
- // GCJ-02 to WGS-84 exactly
1641
- gcjDecryptExact(gcjLat, gcjLon) {
1642
- const initDelta = 0.01;
1643
- const threshold = 1e-9;
1644
- let dLat = initDelta;
1645
- let dLon = initDelta;
1646
- let mLat = gcjLat - dLat;
1647
- let mLon = gcjLon - dLon;
1648
- let pLat = gcjLat + dLat;
1649
- let pLon = gcjLon + dLon;
1650
- let wgsLat = 0;
1651
- let wgsLon = 0;
1652
- let i = 0;
1653
- while (1) {
1654
- wgsLat = (mLat + pLat) / 2;
1655
- wgsLon = (mLon + pLon) / 2;
1656
- const tmp = this.gcjEncrypt(wgsLat, wgsLon);
1657
- dLat = tmp.lat - gcjLat;
1658
- dLon = tmp.lng - gcjLon;
1659
- if (Math.abs(dLat) < threshold && Math.abs(dLon) < threshold) {
1660
- break;
1661
- }
1662
- if (dLat > 0) pLat = wgsLat;
1663
- else mLat = wgsLat;
1664
- if (dLon > 0) pLon = wgsLon;
1665
- else mLon = wgsLon;
1666
- if (++i > 1e4) break;
1667
- }
1668
- return { lat: wgsLat, lng: wgsLon };
1669
- },
1670
- // GCJ-02 to BD-09
1671
- bdEncrypt(gcjLat, gcjLon) {
1672
- const x = gcjLon;
1673
- const y = gcjLat;
1674
- const z = Math.sqrt(x * x + y * y) + 2e-5 * Math.sin(y * this.XPI);
1675
- const theta = Math.atan2(y, x) + 3e-6 * Math.cos(x * this.XPI);
1676
- const bdLon = z * Math.cos(theta) + 65e-4;
1677
- const bdLat = z * Math.sin(theta) + 6e-3;
1678
- return { lat: bdLat, lng: bdLon };
1679
- },
1680
- // BD-09 to GCJ-02
1681
- bdDecrypt(bdLat, bdLon) {
1682
- const x = bdLon - 65e-4;
1683
- const y = bdLat - 6e-3;
1684
- const z = Math.sqrt(x * x + y * y) - 2e-5 * Math.sin(y * this.XPI);
1685
- const theta = Math.atan2(y, x) - 3e-6 * Math.cos(x * this.XPI);
1686
- const gcjLon = z * Math.cos(theta);
1687
- const gcjLat = z * Math.sin(theta);
1688
- return { lat: gcjLat, lng: gcjLon };
1689
- },
1690
- // WGS-84 to Web mercator
1691
- // mercatorLat -> y mercatorLon -> x
1692
- mercatorEncrypt(wgsLat, wgsLon) {
1693
- const x = wgsLon * 2003750834e-2 / 180;
1694
- let y = Math.log(Math.tan((90 + wgsLat) * this.PI / 360)) / (this.PI / 180);
1695
- y = y * 2003750834e-2 / 180;
1696
- return { lat: y, lng: x };
1697
- },
1698
- // Web mercator to WGS-84
1699
- // mercatorLat -> y mercatorLon -> x
1700
- mercatorDecrypt(mercatorLat, mercatorLon) {
1701
- const x = mercatorLon / 2003750834e-2 * 180;
1702
- let y = mercatorLat / 2003750834e-2 * 180;
1703
- y = 180 / this.PI * (2 * Math.atan(Math.exp(y * this.PI / 180)) - this.PI / 2);
1704
- return { lat: y, lng: x };
1705
- },
1706
- transformLat(x, y) {
1707
- let ret = -100 + 2 * x + 3 * y + 0.2 * y * y + 0.1 * x * y + 0.2 * Math.sqrt(Math.abs(x));
1708
- ret += (20 * Math.sin(6 * x * this.PI) + 20 * Math.sin(2 * x * this.PI)) * 2 / 3;
1709
- ret += (20 * Math.sin(y * this.PI) + 40 * Math.sin(y / 3 * this.PI)) * 2 / 3;
1710
- ret += (160 * Math.sin(y / 12 * this.PI) + 320 * Math.sin(y * this.PI / 30)) * 2 / 3;
1711
- return ret;
1712
- },
1713
- transformLon(x, y) {
1714
- let ret = 300 + x + 2 * y + 0.1 * x * x + 0.1 * x * y + 0.1 * Math.sqrt(Math.abs(x));
1715
- ret += (20 * Math.sin(6 * x * this.PI) + 20 * Math.sin(2 * x * this.PI)) * 2 / 3;
1716
- ret += (20 * Math.sin(x * this.PI) + 40 * Math.sin(x / 3 * this.PI)) * 2 / 3;
1717
- ret += (150 * Math.sin(x / 12 * this.PI) + 300 * Math.sin(x / 30 * this.PI)) * 2 / 3;
1718
- return ret;
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 };
1719
1633
  },
1720
1634
  /**
1721
- * 生成指定范围内的随机经纬度坐标
1635
+ * 根据两个经纬度点计算方位角和距离
1722
1636
  *
1723
- * @param min 最小坐标,包含属性 x 和 y,分别表示最小经度和最小纬度
1724
- * @param max 最大坐标,包含属性 x 和 y,分别表示最大经度和最大纬度
1725
- * @returns 返回生成的随机经纬度坐标,包含属性 lat 和 lng,分别表示纬度和经度
1637
+ * @param latlng1 第一个经纬度点
1638
+ * @param latlng2 第二个经纬度点
1639
+ * @returns 包含方位角和距离的对象
1726
1640
  */
1727
- random({ x: minX, y: minY }, { x: maxX, y: maxY }) {
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;
1728
1651
  return {
1729
- lat: Math.random() * (maxY - minY) + minY,
1730
- lng: Math.random() * (maxX - minX) + minX
1652
+ angle,
1653
+ distance
1731
1654
  };
1732
1655
  },
1733
- deCompose(arr, fn, context) {
1734
- if (!Array.isArray(arr)) {
1735
- return context ? fn.call(context, arr) : fn(arr);
1656
+ /**
1657
+ * 计算点P到线段P1P2的最短距离
1658
+ *
1659
+ * @param p 点P的坐标
1660
+ * @param p1 线段起点P1的坐标
1661
+ * @param p2 线段终点P2的坐标
1662
+ * @returns 点P到线段P1P2的最短距离
1663
+ */
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));
1736
1669
  }
1737
- const result = [];
1738
- let p, pp;
1739
- for (let i = 0, len = arr.length; i < len; i++) {
1740
- p = arr[i];
1741
- if (CommUtils.isNil(p)) {
1742
- result.push(null);
1743
- continue;
1744
- }
1745
- if (Array.isArray(p)) {
1746
- result.push(this.deCompose(p, fn, context));
1747
- } else {
1748
- pp = context ? fn.call(context, p) : fn(p);
1749
- result.push(pp);
1750
- }
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));
1751
1673
  }
1752
- return result;
1753
- }
1754
- };
1755
- const ColorUtil = {
1756
- random() {
1757
- let r = Math.floor(Math.random() * 256).toString(16);
1758
- let g = Math.floor(Math.random() * 256).toString(16);
1759
- let b = Math.floor(Math.random() * 256).toString(16);
1760
- r = r.length === 1 ? "0" + r : r;
1761
- g = g.length === 1 ? "0" + g : g;
1762
- b = b.length === 1 ? "0" + b : b;
1763
- return "#" + r + g + b;
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));
1764
1678
  },
1765
1679
  /**
1766
- * 将RGB颜色值转换为十六进制颜色值
1680
+ * 根据给定的经纬度、角度和距离计算新的经纬度点
1767
1681
  *
1768
- * @param rgb RGB颜色值数组,包含三个0-255之间的整数
1769
- * @returns 转换后的十六进制颜色值,以#开头
1682
+ * @param latlng 给定的经纬度点,类型为LngLat
1683
+ * @param angle 角度值,单位为度,表示从当前点出发的方向
1684
+ * @param distance 距离值,单位为米,表示从当前点出发的距离
1685
+ * @returns 返回计算后的新经纬度点,类型为{lat: number, lng: number}
1770
1686
  */
1771
- rgb2hex(rgb) {
1772
- var hex = "#" + ((1 << 24) + (rgb[0] << 16) + (rgb[1] << 8) + rgb[2]).toString(16).slice(1);
1773
- return hex;
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
+ };
1774
1698
  },
1775
1699
  /**
1776
- * 将RGB颜色值转换为RGBA颜色值,并返回转换后的颜色值。
1700
+ * 将墨卡托坐标转换为经纬度坐标
1777
1701
  *
1778
- * @param rgbValue RGB颜色值,格式为"rgb(r, g, b)"。
1779
- * @returns 转换后的RGBA颜色值,格式为"rgba(r, g, b, 1)"。如果输入值不符合RGB格式,则返回原值。
1702
+ * @param x 墨卡托坐标的x值
1703
+ * @param y 墨卡托坐标的y值
1704
+ * @returns 返回包含转换后的经度lng和纬度lat的对象
1780
1705
  */
1781
- rgbToRgba(rgbValue) {
1782
- const rgb = /rgb\((\d+,\s*[\d]+,\s*[\d]+)\)/g.exec(rgbValue);
1783
- return rgb ? `rgba(${rgb[1]}, 1)` : rgbValue;
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 };
1784
1711
  },
1785
1712
  /**
1786
- * 将十六进制颜色值转换为rgba格式的颜色值
1713
+ * 将经纬度坐标转换为墨卡托坐标
1787
1714
  *
1788
- * @param hexValue 十六进制颜色值,可带或不带#前缀,支持3位和6位表示
1789
- * @returns 返回rgba格式的颜色值,格式为rgba(r,g,b,1)
1715
+ * @param lng 经度值
1716
+ * @param lat 纬度值
1717
+ * @returns 墨卡托坐标对象,包含x和y属性
1790
1718
  */
1791
- hexToRgba(hexValue) {
1792
- const rgxShort = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
1793
- const hex = hexValue.replace(rgxShort, (m, r2, g2, b2) => r2 + r2 + g2 + g2 + b2 + b2);
1794
- const rgx = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i;
1795
- const rgb = rgx.exec(hex);
1796
- if (!rgb) {
1797
- return hexValue;
1798
- }
1799
- const r = parseInt(rgb[1], 16);
1800
- const g = parseInt(rgb[2], 16);
1801
- const b = parseInt(rgb[3], 16);
1802
- return `rgba(${r},${g},${b},1)`;
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 };
1803
1725
  },
1804
1726
  /**
1805
- * 将 HSL 颜色值转换为 RGBA 颜色值
1727
+ * 根据百分比获取坐标
1806
1728
  *
1807
- * @param hslValue HSL 颜色值字符串,格式为 "hsl(h, s%, l%)" 或 "hsla(h, s%, l%, a)",其中 h 为色相,s 为饱和度,l 为亮度,a 为透明度(可选)。
1808
- * @returns 转换后的 RGBA 颜色值字符串,格式为 "rgba(r, g, b, a)",其中 r、g、b 为红绿蓝分量,a 为透明度。若输入为空或无效,则返回 null。
1729
+ * @param start 起点坐标
1730
+ * @param end 终点坐标
1731
+ * @param percent 百分比,取值范围0-1
1732
+ * @returns 返回插值后的坐标
1809
1733
  */
1810
- hslToRgba(hslValue) {
1811
- if (!hslValue) {
1812
- return null;
1813
- }
1814
- const hsl = /hsl\((\d+),\s*([\d.]+)%,\s*([\d.]+)%\)/g.exec(hslValue) || /hsla\((\d+),\s*([\d.]+)%,\s*([\d.]+)%,\s*([\d.]+)\)/g.exec(hslValue);
1815
- if (!hsl) {
1816
- return null;
1817
- }
1818
- const h = parseInt(hsl[1], 10) / 360;
1819
- const s = parseInt(hsl[2], 10) / 100;
1820
- const l = parseInt(hsl[3], 10) / 100;
1821
- const a = hsl[4] ? parseFloat(hsl[4]) : 1;
1822
- function hue2rgb(p, q, t) {
1823
- if (t < 0) t += 1;
1824
- if (t > 1) t -= 1;
1825
- if (t < 1 / 6) return p + (q - p) * 6 * t;
1826
- if (t < 1 / 2) return q;
1827
- if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
1828
- return p;
1829
- }
1830
- let r, g, b;
1831
- if (s === 0) {
1832
- r = g = b = l;
1833
- } else {
1834
- const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
1835
- const p = 2 * l - q;
1836
- r = hue2rgb(p, q, h + 1 / 3);
1837
- g = hue2rgb(p, q, h);
1838
- b = hue2rgb(p, q, h - 1 / 3);
1839
- }
1840
- return `rgba(${Math.round(r * 255)},${Math.round(g * 255)},${Math.round(b * 255)},${a})`;
1841
- },
1842
- isHex(a) {
1843
- return /(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)/i.test(a);
1844
- },
1845
- isRgb(a) {
1846
- return /^rgb/.test(a);
1847
- },
1848
- isHsl(a) {
1849
- return /^hsl/.test(a);
1850
- },
1851
- isColor(a) {
1852
- return this.isHex(a) || this.isRgb(a) || this.isHsl(a);
1853
- },
1854
- colorToRgb(val) {
1855
- if (this.isRgb(val)) return this.rgbToRgba(val);
1856
- if (this.isHex(val)) return this.hexToRgba(val);
1857
- if (this.isHsl(val)) return this.hslToRgba(val);
1858
- }
1859
- };
1860
- const myDate = Object.create(Date);
1861
- myDate.prototype.format = function(fmt = "yyyy-MM-dd hh:mm:ss") {
1862
- const o = {
1863
- "M+": this.getMonth() + 1,
1864
- // 月份
1865
- "d+": this.getDate(),
1866
- // 日
1867
- "h+": this.getHours() % 12,
1868
- // 小时
1869
- "H+": this.getHours(),
1870
- // 小时 (24小时制)
1871
- "m+": this.getMinutes(),
1872
- // 分
1873
- "s+": this.getSeconds(),
1874
- // 秒
1875
- "q+": Math.floor((this.getMonth() + 3) / 3),
1876
- // 季度
1877
- S: this.getMilliseconds()
1878
- // 毫秒
1879
- };
1880
- if (/(y+)/.test(fmt)) {
1881
- fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));
1882
- }
1883
- for (const k in o) {
1884
- if (new RegExp("(" + k + ")").test(fmt)) {
1885
- const len = k.length === 1 ? 1 : Number(k.slice(1));
1886
- fmt = fmt.replace(RegExp.$1, ("00" + o[k]).substr(("" + o[k]).length + len - (o[k] + "").length));
1887
- }
1888
- }
1889
- return fmt;
1890
- };
1891
- myDate.prototype.addDate = function(interval, number) {
1892
- const date = new Date(this);
1893
- switch (interval) {
1894
- case "y":
1895
- date.setFullYear(this.getFullYear() + number);
1896
- break;
1897
- case "q":
1898
- date.setMonth(this.getMonth() + number * 3);
1899
- break;
1900
- case "M":
1901
- date.setMonth(this.getMonth() + number);
1902
- break;
1903
- case "w":
1904
- date.setDate(this.getDate() + number * 7);
1905
- break;
1906
- case "d":
1907
- date.setDate(this.getDate() + number);
1908
- break;
1909
- case "h":
1910
- date.setHours(this.getHours() + number);
1911
- break;
1912
- case "m":
1913
- date.setMinutes(this.getMinutes() + number);
1914
- break;
1915
- case "s":
1916
- date.setSeconds(this.getSeconds() + number);
1917
- break;
1918
- default:
1919
- date.setDate(this.getDate() + number);
1920
- break;
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 };
1921
1737
  }
1922
- return date;
1923
1738
  };
1924
- const DateUtil = {
1925
- lastMonthDate: new Date((/* @__PURE__ */ new Date()).getFullYear(), (/* @__PURE__ */ new Date()).getMonth() - 1, 1),
1926
- thisMonthDate: new Date((/* @__PURE__ */ new Date()).getFullYear(), (/* @__PURE__ */ new Date()).getMonth(), 1),
1927
- nextMonthDate: new Date((/* @__PURE__ */ new Date()).getFullYear(), (/* @__PURE__ */ new Date()).getMonth() + 1, 1),
1928
- lastWeekDate: new Date((/* @__PURE__ */ new Date()).getFullYear(), (/* @__PURE__ */ new Date()).getMonth(), (/* @__PURE__ */ new Date()).getDate() + 1 - 7 - (/* @__PURE__ */ new Date()).getDay()),
1929
- thisWeekDate: new Date((/* @__PURE__ */ new Date()).getFullYear(), (/* @__PURE__ */ new Date()).getMonth(), (/* @__PURE__ */ new Date()).getDate() + 1 - (/* @__PURE__ */ new Date()).getDay()),
1930
- nextWeekDate: new Date((/* @__PURE__ */ new Date()).getFullYear(), (/* @__PURE__ */ new Date()).getMonth(), (/* @__PURE__ */ new Date()).getDate() + 1 + 7 - (/* @__PURE__ */ new Date()).getDay()),
1931
- lastDayDate: new Date((/* @__PURE__ */ new Date()).getFullYear(), (/* @__PURE__ */ new Date()).getMonth(), (/* @__PURE__ */ new Date()).getDate() - 1),
1932
- thisDayDate: new Date((/* @__PURE__ */ new Date()).setHours(0, 0, 0, 0)),
1933
- nextDayDate: new Date((/* @__PURE__ */ new Date()).getFullYear(), (/* @__PURE__ */ new Date()).getMonth(), (/* @__PURE__ */ new Date()).getDate() + 1),
1934
- parseDate(str) {
1935
- if (typeof str == "string") {
1936
- var results = str.match(/^ *(\d{4})-(\d{1,2})-(\d{1,2}) *$/);
1937
- if (results && results.length > 3) return new Date(parseInt(results[1]), parseInt(results[2]) - 1, parseInt(results[3]));
1938
- results = str.match(/^ *(\d{4})-(\d{1,2})-(\d{1,2}) +(\d{1,2}):(\d{1,2}):(\d{1,2}) *$/);
1939
- if (results && results.length > 6)
1940
- return new Date(
1941
- parseInt(results[1]),
1942
- parseInt(results[2]) - 1,
1943
- parseInt(results[3]),
1944
- parseInt(results[4]),
1945
- parseInt(results[5]),
1946
- parseInt(results[6])
1947
- );
1948
- results = str.match(/^ *(\d{4})-(\d{1,2})-(\d{1,2}) +(\d{1,2}):(\d{1,2}):(\d{1,2})\.(\d{1,9}) *$/);
1949
- if (results && results.length > 7)
1950
- return new Date(
1951
- parseInt(results[1]),
1952
- parseInt(results[2]) - 1,
1953
- parseInt(results[3]),
1954
- parseInt(results[4]),
1955
- parseInt(results[5]),
1956
- parseInt(results[6]),
1957
- parseInt(results[7])
1958
- );
1959
- }
1960
- return null;
1961
- },
1739
+ const StringUtil = {
1962
1740
  /**
1963
- * 格式化时间间隔
1741
+ * 校验字符串是否符合指定类型
1964
1742
  *
1965
- * @param startTime 开始时间,可以是字符串、数字或日期类型
1966
- * @param endTime 结束时间,可以是字符串、数字或日期类型
1967
- * @returns 返回格式化后的时间间隔字符串,格式为"天数 天 小时 时 分钟 分 秒 秒"或"少于1秒"
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
1968
1763
  */
1969
- formatDateInterval(startTime, endTime) {
1970
- const dateCreateTime = new Date(startTime);
1971
- const dateFinishTime = new Date(endTime);
1972
- const dateInterval = dateFinishTime.getTime() - dateCreateTime.getTime();
1973
- const days = Math.floor(dateInterval / (24 * 3600 * 1e3));
1974
- const leave1 = dateInterval % (24 * 3600 * 1e3);
1975
- const hours = Math.floor(leave1 / (3600 * 1e3));
1976
- const leave2 = leave1 % (3600 * 1e3);
1977
- const minutes = Math.floor(leave2 / (60 * 1e3));
1978
- const leave3 = leave2 % (60 * 1e3);
1979
- const seconds = Math.round(leave3 / 1e3);
1980
- let intervalDes = "";
1981
- if (days > 0) {
1982
- intervalDes += days + "天";
1983
- }
1984
- if (hours > 0) {
1985
- intervalDes += hours + "";
1986
- }
1987
- if (minutes > 0) {
1988
- intervalDes += minutes + "分";
1989
- }
1990
- if (seconds > 0) {
1991
- intervalDes += seconds + "";
1992
- }
1993
- if (days === 0 && hours === 0 && minutes === 0 && seconds === 0) {
1994
- intervalDes = "少于1秒";
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;
1995
1802
  }
1996
- return intervalDes;
1997
1803
  },
1998
- formatterCounter(times) {
1999
- const checked = function(j) {
2000
- return (j > 10 ? "" : "0") + (j || 0);
2001
- };
2002
- const houres = checked(Math.floor(times / 3600));
2003
- const level1 = times % 3600;
2004
- const minutes = checked(Math.floor(level1 / 60));
2005
- const leave2 = level1 % 60;
2006
- const seconds = checked(Math.round(leave2));
2007
- return `${houres}:${minutes}:${seconds}`;
2008
- },
2009
- sleep(d) {
2010
- }
2011
- };
2012
- function trim(str) {
2013
- return str.trim ? str.trim() : str.replace(/^\s+|\s+$/g, "");
2014
- }
2015
- function splitWords(str) {
2016
- return trim(str).split(/\s+/);
2017
- }
2018
- const DomUtil = {
2019
1804
  /**
2020
- * 获取元素的样式值
1805
+ * 转换字符串大小写
2021
1806
  *
2022
- * @param el 元素对象
2023
- * @param style 样式属性名称
2024
- * @returns 元素的样式值,如果获取不到则返回 null
1807
+ * @param str 待转换的字符串
1808
+ * @param type 转换类型,可选值为 1-5,默认为 4
1809
+ * 1:首字母大写,其余小写
1810
+ * 2:首字母小写,其余大写
1811
+ * 3:字母大小写反转
1812
+ * 4:全部大写
1813
+ * 5:全部小写
1814
+ * @returns 转换后的字符串
2025
1815
  */
2026
- getStyle(el, style) {
2027
- var _a;
2028
- let value = el.style[style];
2029
- if (!value || value === "auto") {
2030
- const css = (_a = document.defaultView) == null ? void 0 : _a.getComputedStyle(el, null);
2031
- value = css ? css[style] : null;
2032
- if (value === "auto") value = null;
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;
2033
1841
  }
2034
- return value;
2035
1842
  },
2036
1843
  /**
2037
- * 创建一个HTML元素
1844
+ * 根据字符串数组和参数生成新的字符串
2038
1845
  *
2039
- * @param tagName 元素标签名
2040
- * @param className 元素类名
2041
- * @param container 父容器,若传入,则新创建的元素会被添加到该容器中
2042
- * @returns 返回新创建的HTML元素
1846
+ * @param strArray 字符串数组
1847
+ * @param args 可变参数列表,支持 Object、Array 类型和任意其他类型,若为 null 或 undefined,则按类型默认转换为 '{}'、'[]' 或 ''
1848
+ * @returns 返回生成的新字符串
2043
1849
  */
2044
- create(tagName, className, container) {
2045
- const el = document.createElement(tagName);
2046
- el.className = className || "";
2047
- if (container) {
2048
- container.appendChild(el);
2049
- }
2050
- return el;
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}`);
2051
1862
  },
2052
1863
  /**
2053
- * 从父节点中移除指定元素。
1864
+ * 计算字符串的字节长度
2054
1865
  *
2055
- * @param el 要移除的元素对象,必须包含parentNode属性。
1866
+ * @param str 需要计算字节长度的字符串
1867
+ * @returns 返回字符串的字节长度
2056
1868
  */
2057
- remove(el) {
2058
- const parent = el.parentNode;
2059
- if (parent) {
2060
- parent.removeChild(el);
2061
- }
1869
+ getByteLength(str) {
1870
+ return str.replace(/[\u0391-\uFFE5]/g, "aa").length;
2062
1871
  },
2063
1872
  /**
2064
- * 清空给定元素的子节点
1873
+ * 截取字符串中指定字节长度的子串
2065
1874
  *
2066
- * @param el 要清空子节点的元素,包含firstChildremoveChild属性
1875
+ * @param str 字符串对象,包含replace、lengthsubstring方法
1876
+ * @param start 截取起始位置
1877
+ * @param n 截取字节长度
1878
+ * @returns 返回截取后的子串
2067
1879
  */
2068
- empty(el) {
2069
- while (el.firstChild) {
2070
- el.removeChild(el.firstChild);
1880
+ subStringByte(str, start, n) {
1881
+ var r = /[^\x00-\xff]/g;
1882
+ if (str.replace(r, "mm").length <= n) {
1883
+ return str;
2071
1884
  }
2072
- },
2073
- /**
2074
- * 将元素移到父节点的最前面
2075
- *
2076
- * @param el 要移动的元素,需要包含 parentNode 属性
2077
- */
2078
- toFront(el) {
2079
- const parent = el.parentNode;
2080
- if (parent && parent.lastChild !== el) {
2081
- parent.appendChild(el);
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
+ }
2082
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;
2083
1904
  },
2084
1905
  /**
2085
- * 将元素移动到其父节点的最前面
1906
+ * 将RGB颜色值转换为十六进制颜色值
2086
1907
  *
2087
- * @param el 要移动的元素,需要包含parentNode属性
1908
+ * @param rgb RGB颜色值数组,包含三个0-255之间的整数
1909
+ * @returns 转换后的十六进制颜色值,以#开头
2088
1910
  */
2089
- toBack(el) {
2090
- const parent = el.parentNode;
2091
- if (parent && parent.firstChild !== el) {
2092
- parent.insertBefore(el, parent.firstChild);
2093
- }
1911
+ rgb2hex(rgb) {
1912
+ var hex = "#" + ((1 << 24) + (rgb[0] << 16) + (rgb[1] << 8) + rgb[2]).toString(16).slice(1);
1913
+ return hex;
2094
1914
  },
2095
1915
  /**
2096
- * 获取元素的类名
1916
+ * 将RGB颜色值转换为RGBA颜色值,并返回转换后的颜色值。
2097
1917
  *
2098
- * @param el 包含对应元素和类名的对象
2099
- * @param el.correspondingElement 对应的元素
2100
- * @param el.className 类名对象
2101
- * @param el.className.baseVal 类名字符串
2102
- * @returns 返回元素的类名字符串
1918
+ * @param rgbValue RGB颜色值,格式为"rgb(r, g, b)"。
1919
+ * @returns 转换后的RGBA颜色值,格式为"rgba(r, g, b, 1)"。如果输入值不符合RGB格式,则返回原值。
2103
1920
  */
2104
- getClass(el) {
2105
- const shadowElement = (el == null ? void 0 : el.host) || el;
2106
- return shadowElement.className.toString();
1921
+ rgbToRgba(rgbValue) {
1922
+ const rgb = /rgb\((\d+,\s*[\d]+,\s*[\d]+)\)/g.exec(rgbValue);
1923
+ return rgb ? `rgba(${rgb[1]}, 1)` : rgbValue;
2107
1924
  },
2108
1925
  /**
2109
- * 判断元素是否包含指定类名
1926
+ * 将十六进制颜色值转换为rgba格式的颜色值
2110
1927
  *
2111
- * @param el 元素对象,包含classList属性,classList属性包含contains方法
2112
- * @param name 要判断的类名
2113
- * @returns 返回一个布尔值,表示元素是否包含指定类名
1928
+ * @param hexValue 十六进制颜色值,可带或不带#前缀,支持3位和6位表示
1929
+ * @returns 返回rgba格式的颜色值,格式为rgba(r,g,b,1)
2114
1930
  */
2115
- hasClass(el, name) {
2116
- var _a;
2117
- if ((_a = el.classList) == null ? void 0 : _a.contains(name)) {
2118
- return true;
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;
2119
1938
  }
2120
- const className = this.getClass(el);
2121
- return className.length > 0 && new RegExp(`(^|\\s)${name}(\\s|$)`).test(className);
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)`;
2122
1943
  },
2123
1944
  /**
2124
- * 给指定的 HTML 元素添加类名
1945
+ * HSL 颜色值转换为 RGBA 颜色值
2125
1946
  *
2126
- * @param el 要添加类名的 HTML 元素
2127
- * @param name 要添加的类名,多个类名之间用空格分隔
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。
2128
1949
  */
2129
- addClass(el, name) {
2130
- if (el.classList !== void 0) {
2131
- const classes = splitWords(name);
2132
- for (let i = 0, len = classes.length; i < len; i++) {
2133
- el.classList.add(classes[i]);
2134
- }
2135
- } else if (!this.hasClass(el, name)) {
2136
- const className = this.getClass(el);
2137
- this.setClass(el, (className ? className + " " : "") + name);
1950
+ hslToRgba(hslValue) {
1951
+ if (!hslValue) {
1952
+ return null;
2138
1953
  }
2139
- },
2140
- /**
2141
- * 从元素中移除指定类名
2142
- *
2143
- * @param el 要移除类名的元素
2144
- * @param name 要移除的类名,多个类名用空格分隔
2145
- */
2146
- removeClass(el, name) {
2147
- if (el.classList !== void 0) {
2148
- const classes = splitWords(name);
2149
- classes.forEach((className) => el.classList.remove(className));
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;
2150
1973
  } else {
2151
- this.setClass(el, (" " + this.getClass(el) + " ").replace(" " + name + " ", " ").trim());
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);
2152
1979
  }
1980
+ return `rgba(${Math.round(r * 255)},${Math.round(g * 255)},${Math.round(b * 255)},${a})`;
2153
1981
  },
2154
- /**
2155
- * 设置元素的 CSS 类名
2156
- *
2157
- * @param el HTML 或 SVG 元素
2158
- * @param name 要设置的类名,多个类名之间用空格分隔
2159
- */
2160
- setClass(el, name) {
2161
- if ("classList" in el) {
2162
- el.classList.value = "";
2163
- name.split(" ").forEach((className) => el.classList.add(className));
2164
- }
1982
+ isHex(a) {
1983
+ return /(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)/i.test(a);
2165
1984
  },
2166
- /**
2167
- * 从字符串中解析XML文档,并返回根节点
2168
- *
2169
- * @param str 要解析的XML字符串
2170
- * @returns 解析后的XML文档的根节点
2171
- */
2172
- parseFromString(str) {
2173
- const parser = new DOMParser();
2174
- const doc = parser.parseFromString(str, "text/xml");
2175
- return doc.children[0];
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);
2176
1998
  }
2177
1999
  };
2178
2000
  const TYPES = ["Point", "MultiPoint", "LineString", "MultiLineString", "Polygon", "MultiPolygon"];
@@ -2365,309 +2187,772 @@ const GeoJsonUtil = {
2365
2187
  break;
2366
2188
  }
2367
2189
  }
2368
- if (fType) {
2369
- for (let i = 0, len = coordinates.length; i < len; i++) {
2370
- features.push({
2371
- type: "Feature",
2372
- geometry: {
2373
- type: fType,
2374
- coordinates: coordinates[i]
2375
- },
2376
- properties
2377
- });
2190
+ if (fType) {
2191
+ for (let i = 0, len = coordinates.length; i < len; i++) {
2192
+ features.push({
2193
+ type: "Feature",
2194
+ geometry: {
2195
+ type: fType,
2196
+ coordinates: coordinates[i]
2197
+ },
2198
+ properties
2199
+ });
2200
+ }
2201
+ } else {
2202
+ features.push(feature);
2203
+ }
2204
+ return features;
2205
+ },
2206
+ /**
2207
+ * 根据坐标数组生成GeoJSON要素
2208
+ *
2209
+ * @param coordinates 坐标数组
2210
+ * @returns GeoJSONFeature 生成的GeoJSON要素
2211
+ * @throws Error 如果coordinates参数格式错误
2212
+ */
2213
+ getGeoJsonByCoordinates(coordinates) {
2214
+ if (!Array.isArray(coordinates)) {
2215
+ throw Error("coordinates 参数格式错误");
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 {
2230
+ throw Error("coordinates 参数格式错误");
2231
+ }
2232
+ } else {
2233
+ throw Error("coordinates 参数格式错误");
2234
+ }
2235
+ return {
2236
+ type: "Feature",
2237
+ geometry: { type, coordinates }
2238
+ };
2239
+ }
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
+ },
2308
+ /**
2309
+ * 判断字符串是否合法
2310
+ *
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'
2381
+ */
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";
2396
+ },
2397
+ /**
2398
+ * 检测操作系统类型
2399
+ *
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;
2378
2546
  }
2379
- } else {
2380
- features.push(feature);
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;
2381
2552
  }
2382
- return features;
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;
2383
2604
  },
2384
2605
  /**
2385
- * 根据坐标数组生成GeoJSON要素
2606
+ * 生成指定范围内的随机经纬度坐标
2386
2607
  *
2387
- * @param coordinates 坐标数组
2388
- * @returns GeoJSONFeature 生成的GeoJSON要素
2389
- * @throws Error 如果coordinates参数格式错误
2608
+ * @param min 最小坐标,包含属性 x 和 y,分别表示最小经度和最小纬度
2609
+ * @param max 最大坐标,包含属性 x 和 y,分别表示最大经度和最大纬度
2610
+ * @returns 返回生成的随机经纬度坐标,包含属性 lat 和 lng,分别表示纬度和经度
2390
2611
  */
2391
- getGeoJsonByCoordinates(coordinates) {
2392
- if (!Array.isArray(coordinates)) {
2393
- throw Error("coordinates 参数格式错误");
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);
2394
2621
  }
2395
- let type;
2396
- if (coordinates.length === 2 && typeof coordinates[0] === "number" && typeof coordinates[1] === "number") {
2397
- type = "Point";
2398
- } else if (Array.isArray(coordinates[0]) && coordinates[0].length === 2) {
2399
- type = "LineString";
2400
- } else if (Array.isArray(coordinates[0]) && Array.isArray(coordinates[0][0])) {
2401
- const outerRing = coordinates[0];
2402
- const isClosed = outerRing[0].join(",") === outerRing[outerRing.length - 1].join(",");
2403
- if (isClosed) {
2404
- type = "Polygon";
2405
- } else if (coordinates.length > 1) {
2406
- type = "MultiPolygon";
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));
2407
2632
  } else {
2408
- throw Error("coordinates 参数格式错误");
2633
+ pp = context ? fn.call(context, p) : fn(p);
2634
+ result.push(pp);
2409
2635
  }
2410
- } else {
2411
- throw Error("coordinates 参数格式错误");
2412
2636
  }
2413
- return {
2414
- type: "Feature",
2415
- geometry: { type, coordinates }
2416
- };
2637
+ return result;
2417
2638
  }
2418
2639
  };
2419
- const GeoUtil = {
2420
- toRadian: Math.PI / 180,
2421
- R: 6371393,
2422
- /**
2423
- * 判断给定的经纬度是否合法
2424
- *
2425
- * @param lng 经度值
2426
- * @param lat 纬度值
2427
- * @returns 如果经纬度合法,返回true;否则返回false
2428
- */
2429
- isLnglat(lng, lat) {
2430
- return !isNaN(lng) && !isNaN(lat) && !!(+lat > -90 && +lat < 90 && +lng > -180 && +lng < 180);
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;
2431
2741
  },
2432
2742
  /**
2433
- * 计算两哥平面坐标点间的距离
2743
+ * 格式化时间间隔
2434
2744
  *
2435
- * @param p1 坐标点1,包含x和y属性
2436
- * @param p2 坐标点2,包含x和y属性
2437
- * @returns 返回两点间的欧几里得距离
2745
+ * @param startTime 开始时间,可以是字符串、数字或日期类型
2746
+ * @param endTime 结束时间,可以是字符串、数字或日期类型
2747
+ * @returns 返回格式化后的时间间隔字符串,格式为"天数 天 小时 时 分钟 分 秒 秒"或"少于1秒"
2438
2748
  */
2439
- distance(p1, p2) {
2440
- return Math.sqrt(Math.pow(p2.x - p1.x, 2) + Math.pow(p2.y - p1.y, 2));
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;
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}`;
2441
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 = {
2442
2799
  /**
2443
- * 计算两个经纬度点之间的距离
2800
+ * 获取元素的样式值
2444
2801
  *
2445
- * @param A 经纬度点A,包含lng(经度)和lat(纬度)两个属性
2446
- * @param B 经纬度点B,包含lng(经度)和lat(纬度)两个属性
2447
- * @returns 返回两点之间的距离,单位为米
2802
+ * @param el 元素对象
2803
+ * @param style 样式属性名称
2804
+ * @returns 元素的样式值,如果获取不到则返回 null
2448
2805
  */
2449
- distanceByPoints(A, B) {
2450
- const { lng: lngA, lat: latA } = A;
2451
- const { lng: lngB, lat: latB } = B;
2452
- const earthR = 6371e3;
2453
- const x = Math.cos(latA * Math.PI / 180) * Math.cos(latB * Math.PI / 180) * Math.cos((lngA - lngB) * Math.PI / 180);
2454
- const y = Math.sin(latA * Math.PI / 180) * Math.sin(latB * Math.PI / 180);
2455
- let s = x + y;
2456
- if (s > 1) s = 1;
2457
- if (s < -1) s = -1;
2458
- const alpha = Math.acos(s);
2459
- const distance = alpha * earthR;
2460
- return distance;
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;
2461
2815
  },
2462
2816
  /**
2463
- * 格式化经纬度为度分秒格式
2817
+ * 创建一个HTML元素
2464
2818
  *
2465
- * @param lng 经度
2466
- * @param lat 纬度
2467
- * @returns 返回格式化后的经纬度字符串,格式为:经度度分秒,纬度度分秒
2819
+ * @param tagName 元素标签名
2820
+ * @param className 元素类名
2821
+ * @param container 父容器,若传入,则新创建的元素会被添加到该容器中
2822
+ * @returns 返回新创建的HTML元素
2468
2823
  */
2469
- formatLnglat(lng, lat) {
2470
- let res = "";
2471
- function formatDegreeToDMS(valueInDegrees) {
2472
- const degree = Math.floor(valueInDegrees);
2473
- const minutes = Math.floor((valueInDegrees - degree) * 60);
2474
- const seconds = (valueInDegrees - degree) * 3600 - minutes * 60;
2475
- return `${degree}°${minutes}′${seconds.toFixed(2)}″`;
2476
- }
2477
- if (this.isLnglat(lng, lat)) {
2478
- res = formatDegreeToDMS(lng) + "," + formatDegreeToDMS(lat);
2479
- } else if (!isNaN(lng)) {
2480
- res = formatDegreeToDMS(lng);
2481
- } else if (!isNaN(lat)) {
2482
- res = formatDegreeToDMS(lat);
2824
+ create(tagName, className, container) {
2825
+ const el = document.createElement(tagName);
2826
+ el.className = className || "";
2827
+ if (container) {
2828
+ container.appendChild(el);
2483
2829
  }
2484
- return res;
2830
+ return el;
2485
2831
  },
2486
2832
  /**
2487
- * 将经纬度字符串转换为度
2833
+ * 从父节点中移除指定元素。
2488
2834
  *
2489
- * @param lng 经度字符串
2490
- * @param lat 纬度字符串
2491
- * @returns 转换后的经纬度对象
2835
+ * @param el 要移除的元素对象,必须包含parentNode属性。
2492
2836
  */
2493
- transformLnglat(lng, lat) {
2494
- function dms2deg(dmsString) {
2495
- const isNegative = /[sw]/i.test(dmsString);
2496
- let factor = isNegative ? -1 : 1;
2497
- const numericParts = dmsString.match(/[\d.]+/g) || [];
2498
- let degrees = 0;
2499
- for (let i = 0; i < numericParts.length; i++) {
2500
- degrees += parseFloat(numericParts[i]) / factor;
2501
- factor *= 60;
2502
- }
2503
- return degrees;
2504
- }
2505
- if (lng && lat) {
2506
- return {
2507
- lng: dms2deg(lng),
2508
- lat: dms2deg(lat)
2509
- };
2837
+ remove(el) {
2838
+ const parent = el.parentNode;
2839
+ if (parent) {
2840
+ parent.removeChild(el);
2510
2841
  }
2511
2842
  },
2512
2843
  /**
2513
- * 射线法判断点是否在多边形内
2844
+ * 清空给定元素的子节点
2514
2845
  *
2515
- * @param p 点对象,包含xy属性
2516
- * @param poly 多边形顶点数组,可以是字符串数组或对象数组
2517
- * @returns 返回字符串,表示点相对于多边形的位置:'in'表示在多边形内,'out'表示在多边形外,'on'表示在多边形上
2846
+ * @param el 要清空子节点的元素,包含firstChildremoveChild属性
2518
2847
  */
2519
- rayCasting(p, poly) {
2520
- var px = p.x, py = p.y, flag = false;
2521
- for (var i = 0, l = poly.length, j = l - 1; i < l; j = i, i++) {
2522
- var sx = poly[i].x, sy = poly[i].y, tx = poly[j].x, ty = poly[j].y;
2523
- if (sx === px && sy === py || tx === px && ty === py) {
2524
- return "on";
2525
- }
2526
- if (sy < py && ty >= py || sy >= py && ty < py) {
2527
- var x = sx + (py - sy) * (tx - sx) / (ty - sy);
2528
- if (x === px) {
2529
- return "on";
2530
- }
2531
- if (x > px) {
2532
- flag = !flag;
2533
- }
2534
- }
2848
+ empty(el) {
2849
+ while (el.firstChild) {
2850
+ el.removeChild(el.firstChild);
2535
2851
  }
2536
- return flag ? "in" : "out";
2537
2852
  },
2538
2853
  /**
2539
- * 旋转点
2854
+ * 将元素移到父节点的最前面
2540
2855
  *
2541
- * @param p1 旋转前点坐标
2542
- * @param p2 旋转中心坐标
2543
- * @param θ 旋转角度(顺时针旋转为正)
2544
- * @returns 旋转后点坐标
2856
+ * @param el 要移动的元素,需要包含 parentNode 属性
2545
2857
  */
2546
- rotatePoint(p1, p2, θ) {
2547
- const x = (p1.x - p2.x) * Math.cos(Math.PI / 180 * -θ) - (p1.y - p2.y) * Math.sin(Math.PI / 180 * -θ) + p2.x;
2548
- const y = (p1.x - p2.x) * Math.sin(Math.PI / 180 * -θ) + (p1.y - p2.y) * Math.cos(Math.PI / 180 * -θ) + p2.y;
2549
- return { x, y };
2858
+ toFront(el) {
2859
+ const parent = el.parentNode;
2860
+ if (parent && parent.lastChild !== el) {
2861
+ parent.appendChild(el);
2862
+ }
2550
2863
  },
2551
2864
  /**
2552
- * 根据两个平面坐标点计算方位角和距离
2865
+ * 将元素移动到其父节点的最前面
2553
2866
  *
2554
- * @param p1 第一个点的坐标对象
2555
- * @param p2 第二个点的坐标对象
2556
- * @returns 返回一个对象,包含angle和distance属性,分别表示两点之间的角度(以度为单位,取值范围为0~359)和距离
2867
+ * @param el 要移动的元素,需要包含parentNode属性
2557
2868
  */
2558
- calcBearAndDis(p1, p2) {
2559
- const { x: x1, y: y1 } = p1;
2560
- const { x: x2, y: y2 } = p2;
2561
- const dx = x2 - x1;
2562
- const dy = y2 - y1;
2563
- const distance = Math.sqrt(dx * dx + dy * dy);
2564
- const angleInRadians = Math.atan2(dy, dx);
2565
- const angle = (angleInRadians * (180 / Math.PI) + 360 + 90) % 360;
2566
- return { angle, distance };
2869
+ toBack(el) {
2870
+ const parent = el.parentNode;
2871
+ if (parent && parent.firstChild !== el) {
2872
+ parent.insertBefore(el, parent.firstChild);
2873
+ }
2567
2874
  },
2568
2875
  /**
2569
- * 根据两个经纬度点计算方位角和距离
2876
+ * 获取元素的类名
2570
2877
  *
2571
- * @param latlng1 第一个经纬度点
2572
- * @param latlng2 第二个经纬度点
2573
- * @returns 包含方位角和距离的对象
2878
+ * @param el 包含对应元素和类名的对象
2879
+ * @param el.correspondingElement 对应的元素
2880
+ * @param el.className 类名对象
2881
+ * @param el.className.baseVal 类名字符串
2882
+ * @returns 返回元素的类名字符串
2574
2883
  */
2575
- calcBearAndDisByPoints(latlng1, latlng2) {
2576
- var f1 = latlng1.lat * 1, l1 = latlng1.lng * 1, f2 = latlng2.lat * 1, l2 = latlng2.lng * 1;
2577
- var y = Math.sin((l2 - l1) * this.toRadian) * Math.cos(f2 * this.toRadian);
2578
- 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);
2579
- var angle = Math.atan2(y, x) * (180 / Math.PI);
2580
- var deltaF = (f2 - f1) * this.toRadian;
2581
- var deltaL = (l2 - l1) * this.toRadian;
2582
- 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);
2583
- var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
2584
- var distance = this.R * c;
2585
- return {
2586
- angle,
2587
- distance
2588
- };
2884
+ getClass(el) {
2885
+ const shadowElement = (el == null ? void 0 : el.host) || el;
2886
+ return shadowElement.className.toString();
2589
2887
  },
2590
2888
  /**
2591
- * 计算点P到线段P1P2的最短距离
2889
+ * 判断元素是否包含指定类名
2592
2890
  *
2593
- * @param p 点P的坐标
2594
- * @param p1 线段起点P1的坐标
2595
- * @param p2 线段终点P2的坐标
2596
- * @returns 点P到线段P1P2的最短距离
2891
+ * @param el 元素对象,包含classList属性,classList属性包含contains方法
2892
+ * @param name 要判断的类名
2893
+ * @returns 返回一个布尔值,表示元素是否包含指定类名
2597
2894
  */
2598
- distanceToSegment(p, p1, p2) {
2599
- const x = p.x, y = p.y, x1 = p1.x, y1 = p1.y, x2 = p2.x, y2 = p2.y;
2600
- const cross = (x2 - x1) * (x - x1) + (y2 - y1) * (y - y1);
2601
- if (cross <= 0) {
2602
- return Math.sqrt((x - x1) * (x - x1) + (y - y1) * (y - y1));
2603
- }
2604
- const d2 = (x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1);
2605
- if (cross >= d2) {
2606
- return Math.sqrt((x - x2) * (x - x2) + (y - y2) * (y - y2));
2895
+ hasClass(el, name) {
2896
+ var _a;
2897
+ if ((_a = el.classList) == null ? void 0 : _a.contains(name)) {
2898
+ return true;
2607
2899
  }
2608
- const r = cross / d2;
2609
- const px = x1 + (x2 - x1) * r;
2610
- const py = y1 + (y2 - y1) * r;
2611
- return Math.sqrt((x - px) * (x - px) + (y - py) * (y - py));
2900
+ const className = this.getClass(el);
2901
+ return className.length > 0 && new RegExp(`(^|\\s)${name}(\\s|$)`).test(className);
2612
2902
  },
2613
2903
  /**
2614
- * 根据给定的经纬度、角度和距离计算新的经纬度点
2904
+ * 给指定的 HTML 元素添加类名
2615
2905
  *
2616
- * @param latlng 给定的经纬度点,类型为LngLat
2617
- * @param angle 角度值,单位为度,表示从当前点出发的方向
2618
- * @param distance 距离值,单位为米,表示从当前点出发的距离
2619
- * @returns 返回计算后的新经纬度点,类型为{lat: number, lng: number}
2906
+ * @param el 要添加类名的 HTML 元素
2907
+ * @param name 要添加的类名,多个类名之间用空格分隔
2620
2908
  */
2621
- calcPointByBearAndDis(latlng, angle, distance) {
2622
- const sLat = MathUtils.deg2Rad(latlng.lat * 1);
2623
- const sLng = MathUtils.deg2Rad(latlng.lng * 1);
2624
- const d = distance / this.R;
2625
- angle = MathUtils.deg2Rad(angle);
2626
- const lat = Math.asin(Math.sin(sLat) * Math.cos(d) + Math.cos(sLat) * Math.sin(d) * Math.cos(angle));
2627
- const lon = sLng + Math.atan2(Math.sin(angle) * Math.sin(d) * Math.cos(sLat), Math.cos(d) - Math.sin(sLat) * Math.sin(lat));
2628
- return {
2629
- lat: MathUtils.rad2Deg(lat),
2630
- lng: MathUtils.rad2Deg(lon)
2631
- };
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
+ }
2632
2919
  },
2633
2920
  /**
2634
- * 将墨卡托坐标转换为经纬度坐标
2921
+ * 从元素中移除指定类名
2635
2922
  *
2636
- * @param x 墨卡托坐标的x值
2637
- * @param y 墨卡托坐标的y值
2638
- * @returns 返回包含转换后的经度lng和纬度lat的对象
2923
+ * @param el 要移除类名的元素
2924
+ * @param name 要移除的类名,多个类名用空格分隔
2639
2925
  */
2640
- mercatorTolonlat(x, y) {
2641
- const lng = x / 2003750834e-2 * 180;
2642
- var mmy = y / 2003750834e-2 * 180;
2643
- const lat = 180 / Math.PI * (2 * Math.atan(Math.exp(mmy * Math.PI / 180)) - Math.PI / 2);
2644
- return { lng, lat };
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
+ }
2645
2933
  },
2646
2934
  /**
2647
- * 将经纬度坐标转换为墨卡托坐标
2935
+ * 设置元素的 CSS 类名
2648
2936
  *
2649
- * @param lng 经度值
2650
- * @param lat 纬度值
2651
- * @returns 墨卡托坐标对象,包含x和y属性
2937
+ * @param el HTML 或 SVG 元素
2938
+ * @param name 要设置的类名,多个类名之间用空格分隔
2652
2939
  */
2653
- lonlatToMercator(lng, lat) {
2654
- var earthRad = 6378137;
2655
- const x = lng * Math.PI / 180 * earthRad;
2656
- var a = lat * Math.PI / 180;
2657
- const y = earthRad / 2 * Math.log((1 + Math.sin(a)) / (1 - Math.sin(a)));
2658
- return { x, y };
2940
+ setClass(el, name) {
2941
+ if ("classList" in el) {
2942
+ el.classList.value = "";
2943
+ name.split(" ").forEach((className) => el.classList.add(className));
2944
+ }
2659
2945
  },
2660
2946
  /**
2661
- * 根据百分比获取坐标
2947
+ * 从字符串中解析XML文档,并返回根节点
2662
2948
  *
2663
- * @param start 起点坐标
2664
- * @param end 终点坐标
2665
- * @param percent 百分比,取值范围0-1
2666
- * @returns 返回插值后的坐标
2949
+ * @param str 要解析的XML字符串
2950
+ * @returns 解析后的XML文档的根节点
2667
2951
  */
2668
- interpolate({ x: x1, y: y1, z: z1 = 0 }, { x: x2, y: y2, z: z2 = 0 }, percent) {
2669
- const dx = x2 - x1, dy = y2 - y1, dz = z2 - z1;
2670
- return { x: x1 + dx * percent, y: y1 + dy * percent, z: z1 + dz * percent };
2952
+ parseFromString(str) {
2953
+ const parser = new DOMParser();
2954
+ const doc = parser.parseFromString(str, "text/xml");
2955
+ return doc.children[0];
2671
2956
  }
2672
2957
  };
2673
2958
  const FileUtil = {
@@ -2861,162 +3146,6 @@ const OptimizeUtil = {
2861
3146
  };
2862
3147
  }
2863
3148
  };
2864
- const StringUtil = {
2865
- /**
2866
- * 校验字符串是否符合指定类型
2867
- *
2868
- * @param str 待校验字符串
2869
- * @param type 校验类型,可选值包括:
2870
- * - 'phone': 手机号码
2871
- * - 'tel': 座机
2872
- * - 'card': 身份证
2873
- * - 'pwd': 密码(以字母开头,长度在6~18之间,只能包含字母、数字和下划线)
2874
- * - 'postal': 邮政编码
2875
- * - 'QQ': QQ号
2876
- * - 'email': 邮箱
2877
- * - 'money': 金额(小数点2位)
2878
- * - 'URL': 网址
2879
- * - 'IP': IP地址
2880
- * - 'date': 日期时间
2881
- * - 'number': 数字
2882
- * - 'english': 英文
2883
- * - 'chinese': 中文
2884
- * - 'lower': 小写字母
2885
- * - 'upper': 大写字母
2886
- * - 'HTML': HTML标记
2887
- * @returns 校验结果,符合返回true,否则返回false
2888
- */
2889
- checkStr(str, type) {
2890
- switch (type) {
2891
- case "phone":
2892
- return /^1[3|4|5|6|7|8|9][0-9]{9}$/.test(str);
2893
- case "tel":
2894
- return /^(0\d{2,3}-\d{7,8})(-\d{1,4})?$/.test(str);
2895
- case "card":
2896
- return /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/.test(str);
2897
- case "pwd":
2898
- return /^[a-zA-Z]\w{5,17}$/.test(str);
2899
- case "postal":
2900
- return /[1-9]\d{5}(?!\d)/.test(str);
2901
- case "QQ":
2902
- return /^[1-9][0-9]{4,9}$/.test(str);
2903
- case "email":
2904
- return /^[\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)+$/.test(str);
2905
- case "money":
2906
- return /^\d*(?:\.\d{0,2})?$/.test(str);
2907
- case "URL":
2908
- return /(http|ftp|https):\/\/[\w\-_]+(\.[\w\-_]+)+([\w\-\.,@?^=%&:/~\+#]*[\w\-\@?^=%&/~\+#])?/.test(str);
2909
- case "IP":
2910
- return /((?:(?:25[0-5]|2[0-4]\\d|[01]?\\d?\\d)\\.){3}(?:25[0-5]|2[0-4]\\d|[01]?\\d?\\d))/.test(str);
2911
- case "date":
2912
- 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);
2913
- case "number":
2914
- return /^[0-9]$/.test(str);
2915
- case "english":
2916
- return /^[a-zA-Z]+$/.test(str);
2917
- case "chinese":
2918
- return /^[\u4E00-\u9FA5]+$/.test(str);
2919
- case "lower":
2920
- return /^[a-z]+$/.test(str);
2921
- case "upper":
2922
- return /^[A-Z]+$/.test(str);
2923
- case "HTML":
2924
- return /<("[^"]*"|'[^']*'|[^'">])*>/.test(str);
2925
- default:
2926
- return true;
2927
- }
2928
- },
2929
- /**
2930
- * 转换字符串大小写
2931
- *
2932
- * @param str 待转换的字符串
2933
- * @param type 转换类型,可选值为 1-5,默认为 4
2934
- * 1:首字母大写,其余小写
2935
- * 2:首字母小写,其余大写
2936
- * 3:字母大小写反转
2937
- * 4:全部大写
2938
- * 5:全部小写
2939
- * @returns 转换后的字符串
2940
- */
2941
- changeCase(str, type) {
2942
- type = type || 4;
2943
- switch (type) {
2944
- case 1:
2945
- return str.replace(/\b\w+\b/g, function(word) {
2946
- return word.substring(0, 1).toUpperCase() + word.substring(1).toLowerCase();
2947
- });
2948
- case 2:
2949
- return str.replace(/\b\w+\b/g, function(word) {
2950
- return word.substring(0, 1).toLowerCase() + word.substring(1).toUpperCase();
2951
- });
2952
- case 3:
2953
- return str.split("").map(function(word) {
2954
- if (/[a-z]/.test(word)) {
2955
- return word.toUpperCase();
2956
- } else {
2957
- return word.toLowerCase();
2958
- }
2959
- }).join("");
2960
- case 4:
2961
- return str.toUpperCase();
2962
- case 5:
2963
- return str.toLowerCase();
2964
- default:
2965
- return str;
2966
- }
2967
- },
2968
- /**
2969
- * 根据字符串数组和参数生成新的字符串
2970
- *
2971
- * @param strArray 字符串数组
2972
- * @param args 可变参数列表,支持 Object、Array 类型和任意其他类型,若为 null 或 undefined,则按类型默认转换为 '{}'、'[]' 或 ''
2973
- * @returns 返回生成的新字符串
2974
- */
2975
- tag(strArray, ...args) {
2976
- args = args.map((val) => {
2977
- switch (CommUtils.getDataType(val)) {
2978
- case "Object":
2979
- return val || "{}";
2980
- case "Array":
2981
- return val || "[]";
2982
- default:
2983
- return val || "";
2984
- }
2985
- });
2986
- return strArray.reduce((prev, next, index) => `${prev}${args[index - 1]}${next}`);
2987
- },
2988
- /**
2989
- * 计算字符串的字节长度
2990
- *
2991
- * @param str 需要计算字节长度的字符串
2992
- * @returns 返回字符串的字节长度
2993
- */
2994
- getByteLength(str) {
2995
- return str.replace(/[\u0391-\uFFE5]/g, "aa").length;
2996
- },
2997
- /**
2998
- * 截取字符串中指定字节长度的子串
2999
- *
3000
- * @param str 字符串对象,包含replace、length和substring方法
3001
- * @param start 截取起始位置
3002
- * @param n 截取字节长度
3003
- * @returns 返回截取后的子串
3004
- */
3005
- subStringByte(str, start, n) {
3006
- var r = /[^\x00-\xff]/g;
3007
- if (str.replace(r, "mm").length <= n) {
3008
- return str;
3009
- }
3010
- var m = Math.floor(n / 2);
3011
- for (var i = m; i < str.length; i++) {
3012
- let sub = str.substring(start, i);
3013
- if (sub.replace(r, "mm").length >= n) {
3014
- return sub;
3015
- }
3016
- }
3017
- return str;
3018
- }
3019
- };
3020
3149
  const UrlUtil = {
3021
3150
  /**
3022
3151
  * 将json对象转换为查询字符串
@@ -3069,6 +3198,7 @@ const UrlUtil = {
3069
3198
  export {
3070
3199
  AjaxUtil,
3071
3200
  ArrayUtil,
3201
+ AssertUtil,
3072
3202
  AudioPlayer,
3073
3203
  BrowserUtil,
3074
3204
  CanvasDrawer,
@@ -3097,6 +3227,6 @@ export {
3097
3227
  Storage,
3098
3228
  StringUtil,
3099
3229
  UrlUtil,
3100
- CommUtils as Util,
3230
+ CommUtil as Util,
3101
3231
  WebSocketClient
3102
3232
  };