sculp-js 1.9.0 → 1.10.1

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.
Files changed (63) hide show
  1. package/lib/cjs/array.js +18 -1
  2. package/lib/cjs/async.js +1 -1
  3. package/lib/cjs/base64.js +1 -1
  4. package/lib/cjs/clipboard.js +1 -1
  5. package/lib/cjs/cloneDeep.js +1 -1
  6. package/lib/cjs/cookie.js +1 -1
  7. package/lib/cjs/date.js +1 -1
  8. package/lib/cjs/dom.js +11 -7
  9. package/lib/cjs/download.js +1 -1
  10. package/lib/cjs/easing.js +1 -1
  11. package/lib/cjs/file.js +76 -50
  12. package/lib/cjs/func.js +1 -1
  13. package/lib/cjs/index.js +1 -1
  14. package/lib/cjs/isEqual.js +1 -1
  15. package/lib/cjs/math.js +1 -1
  16. package/lib/cjs/number.js +10 -4
  17. package/lib/cjs/object.js +1 -1
  18. package/lib/cjs/path.js +1 -1
  19. package/lib/cjs/qs.js +1 -1
  20. package/lib/cjs/random.js +1 -1
  21. package/lib/cjs/string.js +1 -1
  22. package/lib/cjs/tooltip.js +25 -18
  23. package/lib/cjs/tree.js +1 -1
  24. package/lib/cjs/type.js +1 -1
  25. package/lib/cjs/unique.js +1 -1
  26. package/lib/cjs/url.js +1 -1
  27. package/lib/cjs/validator.js +1 -1
  28. package/lib/cjs/variable.js +1 -1
  29. package/lib/cjs/watermark.js +20 -19
  30. package/lib/cjs/we-decode.js +1 -1
  31. package/lib/es/array.js +18 -1
  32. package/lib/es/async.js +1 -1
  33. package/lib/es/base64.js +1 -1
  34. package/lib/es/clipboard.js +1 -1
  35. package/lib/es/cloneDeep.js +1 -1
  36. package/lib/es/cookie.js +1 -1
  37. package/lib/es/date.js +1 -1
  38. package/lib/es/dom.js +11 -7
  39. package/lib/es/download.js +1 -1
  40. package/lib/es/easing.js +1 -1
  41. package/lib/es/file.js +76 -50
  42. package/lib/es/func.js +1 -1
  43. package/lib/es/index.js +1 -1
  44. package/lib/es/isEqual.js +1 -1
  45. package/lib/es/math.js +1 -1
  46. package/lib/es/number.js +10 -4
  47. package/lib/es/object.js +1 -1
  48. package/lib/es/path.js +1 -1
  49. package/lib/es/qs.js +1 -1
  50. package/lib/es/random.js +1 -1
  51. package/lib/es/string.js +1 -1
  52. package/lib/es/tooltip.js +25 -18
  53. package/lib/es/tree.js +1 -1
  54. package/lib/es/type.js +1 -1
  55. package/lib/es/unique.js +1 -1
  56. package/lib/es/url.js +1 -1
  57. package/lib/es/validator.js +1 -1
  58. package/lib/es/variable.js +1 -1
  59. package/lib/es/watermark.js +20 -19
  60. package/lib/es/we-decode.js +1 -1
  61. package/lib/index.d.ts +50 -26
  62. package/lib/umd/index.js +151 -94
  63. package/package.json +2 -1
package/lib/index.d.ts CHANGED
@@ -106,6 +106,23 @@ declare function arrayEach<V>(array: ArrayLike<V>, iterator: (val: V, idx: numbe
106
106
  * @param {ArrayLike<V>} array 数组
107
107
  * @param {(val: V, idx: number) => Promise<any>} iterator 支持Promise类型的回调函数
108
108
  * @param {boolean} reverse 是否反向遍历
109
+ * @example
110
+ * 使用范例如下:
111
+ * const start = async () => {
112
+ * await arrayEachAsync(result, async (item) => {
113
+ * await request(item);
114
+ * count++;
115
+ * })
116
+ * console.log('发送次数', count);
117
+ * }
118
+
119
+ * for await...of 使用范例如下
120
+ * const loadImages = async (images) => {
121
+ * for await (const item of images) {
122
+ * await request(item);
123
+ * count++;
124
+ * }
125
+ * }
109
126
  */
110
127
  declare function arrayEachAsync<V>(array: ArrayLike<V>, iterator: (val: V, idx: number) => Promise<any> | any, reverse?: boolean): Promise<void>;
111
128
  /**
@@ -285,10 +302,10 @@ declare function getComputedCssVal(el: HTMLElement, property: string, reNumber?:
285
302
  * 字符串的像素宽度
286
303
  * @param {string} str 目标字符串
287
304
  * @param {number} fontSize 字符串字体大小
288
- * @param {boolean} isRemoveDom 计算后是否移除中间dom元素
305
+ * @param {boolean} isRemove 计算后是否移除创建的dom元素
289
306
  * @returns {*}
290
307
  */
291
- declare function getStrWidthPx(str: string, fontSize?: number, isRemoveDom?: boolean): number;
308
+ declare function getStrWidthPx(str: string, fontSize?: number, isRemove?: boolean): number;
292
309
 
293
310
  interface Params<T = string | number> {
294
311
  [key: string]: T | Array<T>;
@@ -589,30 +606,31 @@ interface ICompressOptions {
589
606
  }
590
607
  /**
591
608
  * Web端:等比例压缩图片批量处理 (size小于200KB,不压缩)
592
- * @param {File | FileList} file 文件
593
- * @param {ICompressOptions} options
609
+ *
610
+ * @param {File | FileList} file 图片或图片数组
611
+ * @param {ICompressOptions} options 压缩图片配置项,default: {quality:0.52,mime:'image/jpeg'}
594
612
  * @returns {Promise<object> | undefined}
595
613
  */
596
- declare function compressImg(file: File | FileList, options: ICompressOptions): Promise<object> | undefined;
614
+ declare function compressImg(file: File | FileList, options?: ICompressOptions): Promise<object> | undefined;
597
615
 
598
616
  interface ICanvasWM {
599
- container: HTMLElement;
600
- width: string;
601
- height: string;
602
- textAlign: CanvasTextAlign;
603
- textBaseline: CanvasTextBaseline;
604
- font: string;
605
- fillStyle: string;
606
- content: string;
607
- rotate: number;
608
- zIndex: number;
617
+ rootContainer?: HTMLElement | string;
618
+ width?: string;
619
+ height?: string;
620
+ textAlign?: CanvasTextAlign;
621
+ textBaseline?: CanvasTextBaseline;
622
+ font?: string;
623
+ fillStyle?: string;
624
+ rotate?: number;
625
+ zIndex?: number;
626
+ watermarkId?: string;
609
627
  }
610
628
  /**
611
629
  * canvas 实现 水印, 具备防删除功能
612
630
  * @param {ICanvasWM} canvasWM
613
631
  * @example genCanvasWM({ content: 'QQMusicFE' })
614
632
  */
615
- declare function genCanvasWM(canvasWM: ICanvasWM): void;
633
+ declare function genCanvasWM(content?: string, canvasWM?: ICanvasWM): void;
616
634
 
617
635
  interface DebounceFunc<F extends AnyFunc> {
618
636
  (...args: Parameters<F>): void;
@@ -715,6 +733,7 @@ interface IHumanFileSizeOptions {
715
733
  decimals?: number;
716
734
  si?: boolean;
717
735
  separator?: string;
736
+ baseUnit?: string;
718
737
  maxUnit?: string;
719
738
  }
720
739
  /**
@@ -728,7 +747,7 @@ interface IHumanFileSizeOptions {
728
747
  * ['Byte', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB']
729
748
  * @returns
730
749
  */
731
- declare function humanFileSize(num: number | string, options: IHumanFileSizeOptions): string;
750
+ declare function humanFileSize(num: number | string, options?: IHumanFileSizeOptions): string;
732
751
  /**
733
752
  * 将数字格式化成千位分隔符显示的字符串
734
753
  * @param {number|string} num 数字
@@ -759,30 +778,35 @@ interface UniqueString {
759
778
  declare const uniqueString: UniqueString;
760
779
 
761
780
  /**
762
- * @title tooltip
781
+ * 自定义的 tooltip, 支持鼠标移动动悬浮提示
763
782
  * @Desc 自定义的tooltip方法, 支持拖动悬浮提示
764
783
  * Created by chendeqiao on 2017/5/8.
765
784
  * @example
766
- * <span onmouseleave="handleMouseLeave('#root')" onmousemove="handleMouseEnter({rootElId: '#root', title: 'title content', event: event})"
767
- * onmouseenter="handleMouseEnter({'#root', title: 'title content', event: event})">title content </span>
785
+ * <span onmouseleave="handleMouseLeave('#root')"
786
+ * onmousemove="handleMouseEnter({rootContainer: '#root', title: 'title content', event: event})"
787
+ * onmouseenter="handleMouseEnter({rootContainer:'#root', title: 'title content', event: event})">
788
+ * title content
789
+ * </span>
768
790
  */
769
791
  interface ITooltipParams {
770
- rootElId: string;
792
+ rootContainer: HTMLElement | string;
771
793
  title: string;
772
- event: PointerEvent;
794
+ event: PointerEvent | MouseEvent;
795
+ bgColor?: string;
796
+ color?: string;
773
797
  }
774
798
  /**
775
799
  * 自定义title提示功能的mouseenter事件句柄
776
- * @param {ITooltipParams} param1
800
+ * @param {ITooltipParams} param
777
801
  * @returns {*}
778
802
  */
779
- declare function handleMouseEnter({ rootElId, title, event }: ITooltipParams): void;
803
+ declare function handleMouseEnter({ rootContainer, title, event, bgColor, color }: ITooltipParams): void;
780
804
  /**
781
805
  * 移除提示文案dom的事件句柄
782
- * @param {string} rootElId
806
+ * @param {string} rootContainer
783
807
  * @returns {*}
784
808
  */
785
- declare function handleMouseLeave(rootElId?: string): void;
809
+ declare function handleMouseLeave(rootContainer?: HTMLElement | string): void;
786
810
  declare const tooltipEvent: {
787
811
  handleMouseEnter: typeof handleMouseEnter;
788
812
  handleMouseLeave: typeof handleMouseLeave;
package/lib/umd/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * sculp-js v1.9.0
2
+ * sculp-js v1.10.1
3
3
  * (c) 2023-present chandq
4
4
  * Released under the MIT License.
5
5
  */
@@ -45,6 +45,23 @@
45
45
  * @param {ArrayLike<V>} array 数组
46
46
  * @param {(val: V, idx: number) => Promise<any>} iterator 支持Promise类型的回调函数
47
47
  * @param {boolean} reverse 是否反向遍历
48
+ * @example
49
+ * 使用范例如下:
50
+ * const start = async () => {
51
+ * await arrayEachAsync(result, async (item) => {
52
+ * await request(item);
53
+ * count++;
54
+ * })
55
+ * console.log('发送次数', count);
56
+ * }
57
+
58
+ * for await...of 使用范例如下
59
+ * const loadImages = async (images) => {
60
+ * for await (const item of images) {
61
+ * await request(item);
62
+ * count++;
63
+ * }
64
+ * }
48
65
  */
49
66
  async function arrayEachAsync(array, iterator, reverse = false) {
50
67
  if (reverse) {
@@ -964,28 +981,32 @@
964
981
  * 字符串的像素宽度
965
982
  * @param {string} str 目标字符串
966
983
  * @param {number} fontSize 字符串字体大小
967
- * @param {boolean} isRemoveDom 计算后是否移除中间dom元素
984
+ * @param {boolean} isRemove 计算后是否移除创建的dom元素
968
985
  * @returns {*}
969
986
  */
970
- function getStrWidthPx(str, fontSize = 14, isRemoveDom = false) {
987
+ function getStrWidthPx(str, fontSize = 14, isRemove = true) {
971
988
  let strWidth = 0;
972
989
  console.assert(isString(str), `${str} 不是有效的字符串`);
973
990
  if (isString(str) && str.length > 0) {
974
- let getEle = document.querySelector('#getStrWidth1494304949567');
991
+ const id = 'getStrWidth1494304949567';
992
+ let getEle = document.querySelector(`#${id}`);
975
993
  if (!getEle) {
976
994
  const _ele = document.createElement('span');
977
- _ele.id = 'getStrWidth1494304949567';
995
+ _ele.id = id;
978
996
  _ele.style.fontSize = fontSize + 'px';
979
997
  _ele.style.whiteSpace = 'nowrap';
980
998
  _ele.style.visibility = 'hidden';
999
+ _ele.style.position = 'absolute';
1000
+ _ele.style.top = '-9999px';
1001
+ _ele.style.left = '-9999px';
981
1002
  _ele.textContent = str;
982
1003
  document.body.appendChild(_ele);
983
1004
  getEle = _ele;
984
1005
  }
985
1006
  getEle.textContent = str;
986
1007
  strWidth = getEle.offsetWidth;
987
- if (isRemoveDom) {
988
- document.body.appendChild(getEle);
1008
+ if (isRemove) {
1009
+ getEle.remove();
989
1010
  }
990
1011
  }
991
1012
  return strWidth;
@@ -1481,16 +1502,73 @@
1481
1502
  };
1482
1503
  return inputObj;
1483
1504
  }
1505
+ /**
1506
+ * 计算图片压缩后的尺寸
1507
+ *
1508
+ * @param {number} maxWidth
1509
+ * @param {number} maxHeight
1510
+ * @param {number} originWidth
1511
+ * @param {number} originHeight
1512
+ * @returns {*}
1513
+ */
1514
+ function calculateSize({ maxWidth, maxHeight, originWidth, originHeight }) {
1515
+ let width = originWidth, height = originHeight;
1516
+ // 图片尺寸超过限制
1517
+ if (originWidth > maxWidth || originHeight > maxHeight) {
1518
+ if (originWidth / originHeight > maxWidth / maxHeight) {
1519
+ // 更宽,按照宽度限定尺寸
1520
+ width = maxWidth;
1521
+ height = Math.round(maxWidth * (originHeight / originWidth));
1522
+ }
1523
+ else {
1524
+ height = maxHeight;
1525
+ width = Math.round(maxHeight * (originWidth / originHeight));
1526
+ }
1527
+ }
1528
+ return { width, height };
1529
+ }
1530
+ /**
1531
+ * 根据原始图片的不同尺寸计算等比例缩放后的宽高尺寸
1532
+ *
1533
+ * @param {number} sizeKB
1534
+ * @param {number} originWidth
1535
+ * @param {number} originHeight
1536
+ * @returns {*}
1537
+ */
1538
+ function scalingByAspectRatio({ sizeKB, originWidth, originHeight }) {
1539
+ let targetWidth = originWidth, targetHeight = originHeight;
1540
+ if (1 * 1024 <= sizeKB && sizeKB < 10 * 1024) {
1541
+ // [1MB, 10MB)
1542
+ const maxWidth = 1600, maxHeight = 1600;
1543
+ const { width, height } = calculateSize({ maxWidth, maxHeight, originWidth, originHeight });
1544
+ targetWidth = width;
1545
+ targetHeight = height;
1546
+ }
1547
+ else if (10 * 1024 <= sizeKB) {
1548
+ // [10MB, Infinity)
1549
+ const maxWidth = originWidth > 15000 ? 8192 : originWidth > 10000 ? 4096 : 2000, maxHeight = originHeight > 15000 ? 8192 : originHeight > 10000 ? 4096 : 2000;
1550
+ const { width, height } = calculateSize({ maxWidth, maxHeight, originWidth, originHeight });
1551
+ targetWidth = width;
1552
+ targetHeight = height;
1553
+ }
1554
+ return { width: targetWidth, height: targetHeight };
1555
+ }
1484
1556
  /**
1485
1557
  * Web端:等比例压缩图片批量处理 (size小于200KB,不压缩)
1486
- * @param {File | FileList} file 文件
1487
- * @param {ICompressOptions} options
1558
+ *
1559
+ * @param {File | FileList} file 图片或图片数组
1560
+ * @param {ICompressOptions} options 压缩图片配置项,default: {quality:0.52,mime:'image/jpeg'}
1488
1561
  * @returns {Promise<object> | undefined}
1489
1562
  */
1490
- function compressImg(file, options) {
1491
- console.assert(file instanceof File || file instanceof FileList, `${file} 必须是File或FileList类型`);
1492
- console.assert(supportCanvas(), `当前环境不支持 Canvas`);
1493
- let targetQuality = 0.52;
1563
+ function compressImg(file, options = { quality: 0.52, mime: 'image/jpeg' }) {
1564
+ if (!(file instanceof File || file instanceof FileList)) {
1565
+ throw new Error(`${file} require be File or FileList`);
1566
+ }
1567
+ else if (!supportCanvas()) {
1568
+ throw new Error(`Current runtime environment not support Canvas`);
1569
+ }
1570
+ const { quality = 0.52, mime = 'image/jpeg' } = isObject(options) ? options : {};
1571
+ let targetQuality = quality;
1494
1572
  if (file instanceof File) {
1495
1573
  const sizeKB = +parseInt((file.size / 1024).toFixed(2));
1496
1574
  if (sizeKB < 1 * 1024) {
@@ -1499,8 +1577,11 @@
1499
1577
  else if (sizeKB >= 1 * 1024 && sizeKB < 5 * 1024) {
1500
1578
  targetQuality = 0.62;
1501
1579
  }
1502
- else if (sizeKB >= 5 * 1024) {
1503
- targetQuality = 0.52;
1580
+ else if (sizeKB >= 5 * 1024 && sizeKB < 10 * 1024) {
1581
+ targetQuality = 0.75;
1582
+ }
1583
+ else if (sizeKB >= 10 * 1024) {
1584
+ targetQuality = 0.92;
1504
1585
  }
1505
1586
  }
1506
1587
  if (options.quality) {
@@ -1525,49 +1606,14 @@
1525
1606
  image.onload = () => {
1526
1607
  const canvas = document.createElement('canvas'); // 创建 canvas 元素
1527
1608
  const context = canvas.getContext('2d');
1528
- let targetWidth = image.width;
1529
- let targetHeight = image.height;
1530
1609
  const originWidth = image.width;
1531
1610
  const originHeight = image.height;
1532
- if (1 * 1024 <= sizeKB && sizeKB < 10 * 1024) {
1533
- const maxWidth = 1600, maxHeight = 1600;
1534
- targetWidth = originWidth;
1535
- targetHeight = originHeight;
1536
- // 图片尺寸超过的限制
1537
- if (originWidth > maxWidth || originHeight > maxHeight) {
1538
- if (originWidth / originHeight > maxWidth / maxHeight) {
1539
- // 更宽,按照宽度限定尺寸
1540
- targetWidth = maxWidth;
1541
- targetHeight = Math.round(maxWidth * (originHeight / originWidth));
1542
- }
1543
- else {
1544
- targetHeight = maxHeight;
1545
- targetWidth = Math.round(maxHeight * (originWidth / originHeight));
1546
- }
1547
- }
1548
- }
1549
- if (10 * 1024 <= sizeKB && sizeKB <= 20 * 1024) {
1550
- const maxWidth = 1400, maxHeight = 1400;
1551
- targetWidth = originWidth;
1552
- targetHeight = originHeight;
1553
- // 图片尺寸超过的限制
1554
- if (originWidth > maxWidth || originHeight > maxHeight) {
1555
- if (originWidth / originHeight > maxWidth / maxHeight) {
1556
- // 更宽,按照宽度限定尺寸
1557
- targetWidth = maxWidth;
1558
- targetHeight = Math.round(maxWidth * (originHeight / originWidth));
1559
- }
1560
- else {
1561
- targetHeight = maxHeight;
1562
- targetWidth = Math.round(maxHeight * (originWidth / originHeight));
1563
- }
1564
- }
1565
- }
1566
- canvas.width = targetWidth;
1567
- canvas.height = targetHeight;
1568
- context.clearRect(0, 0, targetWidth, targetHeight);
1569
- context.drawImage(image, 0, 0, targetWidth, targetHeight); // 绘制 canvas
1570
- const canvasURL = canvas.toDataURL(options.mime, targetQuality);
1611
+ const { width, height } = scalingByAspectRatio({ sizeKB, originWidth, originHeight });
1612
+ canvas.width = width;
1613
+ canvas.height = height;
1614
+ context.clearRect(0, 0, width, height);
1615
+ context.drawImage(image, 0, 0, width, height); // 绘制 canvas
1616
+ const canvasURL = canvas.toDataURL(mime, targetQuality);
1571
1617
  const buffer = weAtob(canvasURL.split(',')[1]);
1572
1618
  let length = buffer.length;
1573
1619
  const bufferArray = new Uint8Array(new ArrayBuffer(length));
@@ -1606,15 +1652,14 @@
1606
1652
  * @param {ICanvasWM} canvasWM
1607
1653
  * @example genCanvasWM({ content: 'QQMusicFE' })
1608
1654
  */
1609
- function genCanvasWM(canvasWM) {
1610
- const { container = document.body, width = '300px', height = '200px', textAlign = 'center', textBaseline = 'middle', font = '20px PingFangSC-Medium,PingFang SC',
1655
+ function genCanvasWM(content = '请勿外传', canvasWM) {
1656
+ const { rootContainer = document.body, width = '300px', height = '150px', textAlign = 'center', textBaseline = 'middle', font = '20px PingFangSC-Medium,PingFang SC',
1611
1657
  // fontWeight = 500,
1612
- fillStyle = 'rgba(189, 177, 167, .3)', content = '请勿外传', rotate = 30, zIndex = 2147483647 } = canvasWM;
1613
- // 仅限主页面添加水印
1614
- // if (!location.pathname.includes('/home')) {
1615
- // return;
1616
- // }
1617
- const args = canvasWM;
1658
+ fillStyle = 'rgba(189, 177, 167, .3)', rotate = -20, zIndex = 2147483647, watermarkId = '__wm' } = isNullOrUnDef(canvasWM) ? {} : canvasWM;
1659
+ const container = isString(rootContainer) ? document.querySelector(rootContainer) : rootContainer;
1660
+ if (!container) {
1661
+ throw new Error(`${rootContainer} is not valid Html Element or element selector`);
1662
+ }
1618
1663
  const canvas = document.createElement('canvas');
1619
1664
  canvas.setAttribute('width', width);
1620
1665
  canvas.setAttribute('height', height);
@@ -1627,36 +1672,36 @@
1627
1672
  ctx.rotate((Math.PI / 180) * rotate);
1628
1673
  ctx.fillText(content, parseFloat(width) / 4, parseFloat(height) / 2);
1629
1674
  const base64Url = canvas.toDataURL();
1630
- const __wm = document.querySelector('.__wm');
1675
+ const __wm = document.querySelector(`#${watermarkId}`);
1631
1676
  const watermarkDiv = __wm || document.createElement('div');
1632
1677
  const styleStr = `opacity: 1 !important; display: block !important; visibility: visible !important; position:absolute; left:0; top:0; width:100%; height:100%; z-index:${zIndex}; pointer-events:none; background-repeat:repeat; background-image:url('${base64Url}')`;
1633
1678
  watermarkDiv.setAttribute('style', styleStr);
1634
- watermarkDiv.classList.add('__wm');
1679
+ watermarkDiv.setAttribute('id', watermarkId);
1635
1680
  watermarkDiv.classList.add('nav-height');
1636
1681
  if (!__wm) {
1637
1682
  container.style.position = 'relative';
1638
1683
  container.appendChild(watermarkDiv);
1639
1684
  }
1640
1685
  const getMutableStyle = (ele) => {
1641
- const computedStle = getComputedStyle(ele);
1686
+ const computedStyle = getComputedStyle(ele);
1642
1687
  return {
1643
- opacity: computedStle.getPropertyValue('opacity'),
1644
- zIndex: computedStle.getPropertyValue('z-index'),
1645
- display: computedStle.getPropertyValue('display'),
1646
- visibility: computedStle.getPropertyValue('visibility')
1688
+ opacity: computedStyle.getPropertyValue('opacity'),
1689
+ zIndex: computedStyle.getPropertyValue('z-index'),
1690
+ display: computedStyle.getPropertyValue('display'),
1691
+ visibility: computedStyle.getPropertyValue('visibility')
1647
1692
  };
1648
1693
  };
1649
1694
  //@ts-ignore
1650
1695
  const MutationObserver = window.MutationObserver || window.WebKitMutationObserver;
1651
1696
  if (MutationObserver) {
1652
1697
  let mo = new MutationObserver(function () {
1653
- const __wm = document.querySelector('.__wm'); // 只在__wm元素变动才重新调用 __canvasWM
1698
+ const __wm = document.querySelector(`#${watermarkId}`); // 只在__wm元素变动才重新调用 __canvasWM
1654
1699
  if (!__wm) {
1655
1700
  // 避免一直触发
1656
1701
  // console.log('regenerate watermark by delete::')
1657
1702
  mo.disconnect();
1658
1703
  mo = null;
1659
- genCanvasWM(JSON.parse(JSON.stringify(args)));
1704
+ genCanvasWM(content, canvasWM);
1660
1705
  }
1661
1706
  else {
1662
1707
  const { opacity, zIndex, display, visibility } = getMutableStyle(__wm);
@@ -1668,7 +1713,7 @@
1668
1713
  mo.disconnect();
1669
1714
  mo = null;
1670
1715
  container.removeChild(__wm);
1671
- genCanvasWM(JSON.parse(JSON.stringify(args)));
1716
+ genCanvasWM(content, canvasWM);
1672
1717
  }
1673
1718
  }
1674
1719
  });
@@ -1921,11 +1966,17 @@
1921
1966
  * ['Byte', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB']
1922
1967
  * @returns
1923
1968
  */
1924
- function humanFileSize(num, options) {
1925
- const { decimals = 0, si = false, separator = ' ', maxUnit } = options;
1926
- const units = si
1969
+ function humanFileSize(num, options = { decimals: 0, si: false, separator: ' ' }) {
1970
+ const { decimals = 0, si = false, separator = ' ', baseUnit, maxUnit } = options;
1971
+ let units = si
1927
1972
  ? ['B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']
1928
1973
  : ['Byte', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB'];
1974
+ if (!isNullOrUnDef(baseUnit)) {
1975
+ const targetIndex = units.findIndex(el => el === baseUnit);
1976
+ if (targetIndex !== -1) {
1977
+ units = units.slice(targetIndex);
1978
+ }
1979
+ }
1929
1980
  if (!isNullOrUnDef(maxUnit)) {
1930
1981
  const targetIndex = units.findIndex(el => el === maxUnit);
1931
1982
  if (targetIndex !== -1) {
@@ -2023,49 +2074,55 @@
2023
2074
  };
2024
2075
 
2025
2076
  /**
2026
- * @title tooltip
2077
+ * 自定义的 tooltip, 支持鼠标移动动悬浮提示
2027
2078
  * @Desc 自定义的tooltip方法, 支持拖动悬浮提示
2028
2079
  * Created by chendeqiao on 2017/5/8.
2029
2080
  * @example
2030
- * <span onmouseleave="handleMouseLeave('#root')" onmousemove="handleMouseEnter({rootElId: '#root', title: 'title content', event: event})"
2031
- * onmouseenter="handleMouseEnter({'#root', title: 'title content', event: event})">title content </span>
2081
+ * <span onmouseleave="handleMouseLeave('#root')"
2082
+ * onmousemove="handleMouseEnter({rootContainer: '#root', title: 'title content', event: event})"
2083
+ * onmouseenter="handleMouseEnter({rootContainer:'#root', title: 'title content', event: event})">
2084
+ * title content
2085
+ * </span>
2032
2086
  */
2033
2087
  /**
2034
2088
  * 自定义title提示功能的mouseenter事件句柄
2035
- * @param {ITooltipParams} param1
2089
+ * @param {ITooltipParams} param
2036
2090
  * @returns {*}
2037
2091
  */
2038
- function handleMouseEnter({ rootElId = '#root', title, event }) {
2092
+ function handleMouseEnter({ rootContainer = '#root', title, event, bgColor = '#000', color = '#fff' }) {
2039
2093
  try {
2040
- const $rootEl = document.querySelector(rootElId);
2041
- console.assert($rootEl !== null, `未找到id为 ${rootElId} 的dom元素`);
2094
+ const $rootEl = isString(rootContainer) ? document.querySelector(rootContainer) : rootContainer;
2095
+ if (!$rootEl) {
2096
+ throw new Error(`${rootContainer} is not valid Html Element or element selector`);
2097
+ }
2042
2098
  let $customTitle = null;
2099
+ const styleId = 'style-tooltip-inner1494304949567';
2043
2100
  // 动态创建class样式,并加入到head中
2044
- if (!document.querySelector('.tooltip-inner1494304949567')) {
2101
+ if (!document.querySelector(`#${styleId}`)) {
2045
2102
  const tooltipWrapperClass = document.createElement('style');
2046
2103
  tooltipWrapperClass.type = 'text/css';
2104
+ tooltipWrapperClass.id = styleId;
2047
2105
  tooltipWrapperClass.innerHTML = `
2048
2106
  .tooltip-inner1494304949567 {
2049
2107
  max-width: 250px;
2050
2108
  padding: 3px 8px;
2051
- color: #fff;
2109
+ color: ${color};
2052
2110
  text-decoration: none;
2053
2111
  border-radius: 4px;
2054
2112
  text-align: left;
2113
+ background-color: ${bgColor};
2055
2114
  }
2056
2115
  `;
2057
2116
  document.querySelector('head').appendChild(tooltipWrapperClass);
2058
2117
  }
2059
- if (document.querySelector('#customTitle1494304949567')) {
2060
- $customTitle = document.querySelector('#customTitle1494304949567');
2118
+ $customTitle = document.querySelector('#customTitle1494304949567');
2119
+ if ($customTitle) {
2061
2120
  mouseenter($customTitle, title, event);
2062
2121
  }
2063
2122
  else {
2064
2123
  const $contentContainer = document.createElement('div');
2065
- $contentContainer.className = 'customTitle';
2066
2124
  $contentContainer.id = 'customTitle1494304949567';
2067
- $contentContainer.className = 'tooltip';
2068
- $contentContainer.style.cssText = 'z-index: 99999999; visibility: hidden;';
2125
+ $contentContainer.style.cssText = 'z-index: 99999999; visibility: hidden; position: absolute;';
2069
2126
  $contentContainer.innerHTML =
2070
2127
  '<div class="tooltip-inner1494304949567" style="word-wrap: break-word; max-width: 44px;">皮肤</div>';
2071
2128
  $rootEl.appendChild($contentContainer);
@@ -2118,11 +2175,11 @@
2118
2175
  }
2119
2176
  /**
2120
2177
  * 移除提示文案dom的事件句柄
2121
- * @param {string} rootElId
2178
+ * @param {string} rootContainer
2122
2179
  * @returns {*}
2123
2180
  */
2124
- function handleMouseLeave(rootElId = '#root') {
2125
- const rootEl = document.querySelector(rootElId), titleEl = document.querySelector('#customTitle1494304949567');
2181
+ function handleMouseLeave(rootContainer = '#root') {
2182
+ const rootEl = isString(rootContainer) ? document.querySelector(rootContainer) : rootContainer, titleEl = document.querySelector('#customTitle1494304949567');
2126
2183
  if (rootEl && titleEl) {
2127
2184
  rootEl.removeChild(titleEl);
2128
2185
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sculp-js",
3
- "version": "1.9.0",
3
+ "version": "1.10.1",
4
4
  "packageManager": "npm@8.19.2",
5
5
  "description": "js utils library, includes function library、class library",
6
6
  "scripts": {
@@ -79,6 +79,7 @@
79
79
  "eslint-plugin-standard": "^5.0.0",
80
80
  "husky": "^8.0.3",
81
81
  "jest": "^29.7.0",
82
+ "jest-canvas-mock": "^2.5.2",
82
83
  "jest-environment-jsdom": "^29.7.0",
83
84
  "lint-staged": "^13.2.2",
84
85
  "prettier": "^3.0.3",