jmgraph 3.2.25 → 3.2.27

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/jmgraph.js CHANGED
@@ -2714,31 +2714,63 @@ var jmGradient = /*#__PURE__*/function () {
2714
2714
  }
2715
2715
 
2716
2716
  if (!d) {
2717
- d = Math.min(location.width, location.height);
2718
- } //let offsetLine = 1;//渐变长度或半径
2719
- //处理百分比参数
2717
+ d = Math.min(location.width || 0, location.height || 0);
2718
+ }
2719
+
2720
+ if (d <= 0) {
2721
+ d = Math.max(bounds.width || 0, bounds.height || 0, 100);
2722
+ }
2720
2723
 
2724
+ var width = bounds.width || d;
2725
+ var height = bounds.height || d;
2721
2726
 
2722
2727
  if (_jmUtils.jmUtils.checkPercent(x1)) {
2723
- x1 = _jmUtils.jmUtils.percentToNumber(x1) * (bounds.width || d);
2728
+ x1 = _jmUtils.jmUtils.percentToNumber(x1) * width;
2729
+ } else if (typeof x1 === 'number' && x1 >= 0 && x1 <= 1) {
2730
+ x1 = x1 * width;
2731
+ } else if (typeof x1 === 'string') {
2732
+ var num = parseFloat(x1);
2733
+ if (!isNaN(num)) x1 = num;
2724
2734
  }
2725
2735
 
2726
2736
  if (_jmUtils.jmUtils.checkPercent(x2)) {
2727
- x2 = _jmUtils.jmUtils.percentToNumber(x2) * (bounds.width || d);
2737
+ x2 = _jmUtils.jmUtils.percentToNumber(x2) * width;
2738
+ } else if (typeof x2 === 'number' && x2 >= 0 && x2 <= 1) {
2739
+ x2 = x2 * width;
2740
+ } else if (typeof x2 === 'string') {
2741
+ var _num = parseFloat(x2);
2742
+
2743
+ if (!isNaN(_num)) x2 = _num;
2728
2744
  }
2729
2745
 
2730
2746
  if (_jmUtils.jmUtils.checkPercent(y1)) {
2731
- y1 = _jmUtils.jmUtils.percentToNumber(y1) * (bounds.height || d);
2747
+ y1 = _jmUtils.jmUtils.percentToNumber(y1) * height;
2748
+ } else if (typeof y1 === 'number' && y1 >= 0 && y1 <= 1) {
2749
+ y1 = y1 * height;
2750
+ } else if (typeof y1 === 'string') {
2751
+ var _num2 = parseFloat(y1);
2752
+
2753
+ if (!isNaN(_num2)) y1 = _num2;
2732
2754
  }
2733
2755
 
2734
2756
  if (_jmUtils.jmUtils.checkPercent(y2)) {
2735
- y2 = _jmUtils.jmUtils.percentToNumber(y2) * (bounds.height || d);
2757
+ y2 = _jmUtils.jmUtils.percentToNumber(y2) * height;
2758
+ } else if (typeof y2 === 'number' && y2 >= 0 && y2 <= 1) {
2759
+ y2 = y2 * height;
2760
+ } else if (typeof y2 === 'string') {
2761
+ var _num3 = parseFloat(y2);
2762
+
2763
+ if (!isNaN(_num3)) y2 = _num3;
2736
2764
  }
2737
2765
 
2738
- var sx1 = Number(x1) + bounds.left;
2739
- var sy1 = Number(y1) + bounds.top;
2740
- var sx2 = Number(x2) + bounds.left;
2741
- var sy2 = Number(y2) + bounds.top;
2766
+ x1 = Number(x1) || 0;
2767
+ y1 = Number(y1) || 0;
2768
+ x2 = Number(x2) || 0;
2769
+ y2 = Number(y2) || 0;
2770
+ var sx1 = x1 + (bounds.left || 0);
2771
+ var sy1 = y1 + (bounds.top || 0);
2772
+ var sx2 = x2 + (bounds.left || 0);
2773
+ var sy2 = y2 + (bounds.top || 0);
2742
2774
 
2743
2775
  if (this.type === 'linear') {
2744
2776
  if (control.mode === 'webgl' && control.webglControl) {
@@ -2752,25 +2784,41 @@ var jmGradient = /*#__PURE__*/function () {
2752
2784
  var r1 = this.r1 || 0;
2753
2785
  var r2 = this.r2;
2754
2786
 
2787
+ if (d <= 0) {
2788
+ d = Math.max(bounds.width || 0, bounds.height || 0, 1);
2789
+ }
2790
+
2755
2791
  if (_jmUtils.jmUtils.checkPercent(r1)) {
2756
2792
  r1 = _jmUtils.jmUtils.percentToNumber(r1);
2757
2793
  r1 = d * r1;
2794
+ } else if (typeof r1 === 'number' && r1 >= 0 && r1 <= 1) {
2795
+ r1 = r1 * d;
2796
+ } else if (typeof r1 === 'string') {
2797
+ r1 = parseFloat(r1) || 0;
2758
2798
  }
2759
2799
 
2760
2800
  if (_jmUtils.jmUtils.checkPercent(r2)) {
2761
2801
  r2 = _jmUtils.jmUtils.percentToNumber(r2);
2762
2802
  r2 = d * r2;
2803
+ } else if (typeof r2 === 'number' && r2 >= 0 && r2 <= 1) {
2804
+ r2 = r2 * d;
2805
+ } else if (typeof r2 === 'string') {
2806
+ r2 = parseFloat(r2);
2763
2807
  }
2764
2808
 
2809
+ if (r2 === undefined || r2 === null || isNaN(Number(r2)) || Number(r2) <= 0) {
2810
+ r2 = d / 2;
2811
+ }
2812
+
2813
+ r1 = Number(r1) || 0;
2814
+ r2 = Number(r2) || d / 2;
2815
+
2765
2816
  if (control.mode === 'webgl' && control.webglControl) {
2766
- // WebGL 着色器中 v_text_coord 是绝对坐标,需要传递绝对坐标
2767
2817
  gradient = control.webglControl.createRadialGradient(sx1, sy1, r1, sx2, sy2, r2, bounds);
2768
2818
  gradient.key = this.toString();
2769
- } //offsetLine = Math.abs(r2 - r1);//二圆半径差
2770
- else if (context.createRadialGradient) {
2819
+ } else if (context.createRadialGradient) {
2771
2820
  gradient = context.createRadialGradient(sx1, sy1, r1, sx2, sy2, r2);
2772
- } //小程序的接口特殊
2773
- else if (context.createCircularGradient) {
2821
+ } else if (context.createCircularGradient) {
2774
2822
  gradient = context.createCircularGradient(sx1, sy1, r2);
2775
2823
  }
2776
2824
  } //颜色渐变
@@ -2791,74 +2839,695 @@ var jmGradient = /*#__PURE__*/function () {
2791
2839
  return gradient;
2792
2840
  }
2793
2841
  /**
2794
- * 变换为字条串格式
2795
- * linear-gradient(x1 y1 x2 y2, color1 step, color2 step, ...); //radial-gradient(x1 y1 r1 x2 y2 r2, color1 step,color2 step, ...);
2796
- * linear-gradient线性渐变,x1 y1表示起点,x2 y2表示结束点,color表颜色,step为当前颜色偏移
2797
- * radial-gradient径向渐变,x1 y1 r1分别表示内圆中心和半径,x2 y2 r2为结束圆 中心和半径,颜色例似线性渐变 step为0-1之间
2842
+ * 解析渐变字符串
2843
+ * 支持的格式:
2844
+ * - linear-gradient(180deg, #8b5cf6 0%, #6366f1 50%, #4f46e5 100%)
2845
+ * - linear-gradient(to top, red, blue)
2846
+ * - linear-gradient(to right bottom, red, blue)
2847
+ * - linear-gradient(45deg, red, blue)
2848
+ * - linear-gradient(0.5turn, red, blue)
2849
+ * - radial-gradient(circle, red, blue)
2850
+ * - radial-gradient(ellipse at top, red, blue)
2798
2851
  *
2799
2852
  * @method fromString
2800
2853
  * @for jmGradient
2801
- * @return {string}
2854
+ * @param {string} s 渐变字符串
2802
2855
  */
2803
2856
 
2804
2857
  }, {
2805
2858
  key: "fromString",
2806
2859
  value: function fromString(s) {
2807
- if (!s) return;
2808
- var ms = s.match(/(linear|radial)-gradient\s*\(\s*([^,]+)\s*,\s*((.|\s)+)\)/i);
2809
- if (!ms || ms.length < 3) return;
2810
- this.type = ms[1].toLowerCase();
2860
+ if (!s) {
2861
+ console.warn('jmGradient: 渐变字符串为空');
2862
+ return;
2863
+ } // 使用 [\s\S] 匹配任意字符(包括换行符),支持多行渐变字符串
2811
2864
 
2812
- var ps = _jmUtils.jmUtils.trim(ms[2]).split(/\s+/); //线性渐变
2813
2865
 
2866
+ var gradientMatch = s.match(/(linear|radial)-gradient\s*\(\s*([\s\S]+)\)/i);
2814
2867
 
2815
- if (this.type == 'linear') {
2816
- if (ps.length <= 2) {
2817
- this.x2 = ps[0];
2818
- this.y2 = ps[1] || 0;
2819
- } else {
2820
- this.x1 = ps[0];
2821
- this.y1 = ps[1];
2822
- this.x2 = ps[2];
2823
- this.y2 = ps[3];
2824
- }
2825
- } //径向渐变
2826
- else {
2827
- if (ps.length <= 3) {
2828
- this.x2 = ps[0];
2829
- this.y2 = ps[1] || 0;
2830
- this.r2 = ps[2] || 0;
2831
- } else {
2832
- this.x1 = ps[0];
2833
- this.y1 = ps[1];
2834
- this.r1 = ps[2];
2835
- this.x2 = ps[3];
2836
- this.y2 = ps[3];
2837
- this.r2 = ps[3];
2868
+ if (!gradientMatch || gradientMatch.length < 3) {
2869
+ console.warn('jmGradient: 无效的渐变字符串格式: "' + s + '"');
2870
+ return;
2871
+ }
2872
+
2873
+ var type = gradientMatch[1].toLowerCase();
2874
+
2875
+ if (type !== 'linear' && type !== 'radial') {
2876
+ console.warn('jmGradient: 不支持的渐变类型 "' + type + '",仅支持 linear 和 radial');
2877
+ return;
2878
+ }
2879
+
2880
+ this.type = type;
2881
+
2882
+ var content = _jmUtils.jmUtils.trim(gradientMatch[2]);
2883
+
2884
+ var splitIndex = this._findSplitIndex(content);
2885
+
2886
+ if (splitIndex < 0) {
2887
+ console.warn('jmGradient: 无法解析渐变内容: "' + content + '"');
2888
+ return;
2889
+ }
2890
+
2891
+ var params = content.substring(0, splitIndex).trim();
2892
+ var colorPart = content.substring(splitIndex + 1).trim();
2893
+
2894
+ if (!colorPart) {
2895
+ console.warn('jmGradient: 未找到颜色停止点');
2896
+ return;
2897
+ }
2898
+
2899
+ if (this.type === 'linear') {
2900
+ this._parseLinearParams(params);
2901
+ } else {
2902
+ this._parseRadialParams(params);
2903
+ }
2904
+
2905
+ var colorCount = this._parseColorStops(colorPart);
2906
+
2907
+ if (colorCount === 0) {
2908
+ console.warn('jmGradient: 未找到有效的颜色停止点: "' + colorPart + '"');
2909
+ } else if (colorCount < 2) {
2910
+ console.warn('jmGradient: 颜色停止点至少需要2个,当前只有 ' + colorCount + ' 个');
2911
+ }
2912
+ }
2913
+ /**
2914
+ * 找到参数和颜色的分割位置(第一个不在括号内的逗号)
2915
+ * @param {string} content 内容字符串
2916
+ * @returns {number} 分割位置索引
2917
+ */
2918
+
2919
+ }, {
2920
+ key: "_findSplitIndex",
2921
+ value: function _findSplitIndex(content) {
2922
+ var depth = 0;
2923
+
2924
+ for (var i = 0; i < content.length; i++) {
2925
+ var _char = content[i];
2926
+
2927
+ if (_char === '(') {
2928
+ depth++;
2929
+ } else if (_char === ')') {
2930
+ depth--;
2931
+ } else if (_char === ',' && depth === 0) {
2932
+ return i;
2933
+ }
2934
+ }
2935
+
2936
+ return -1;
2937
+ }
2938
+ /**
2939
+ * 验证渐变配置是否有效
2940
+ * @returns {boolean} 是否有效
2941
+ */
2942
+
2943
+ }, {
2944
+ key: "isValid",
2945
+ value: function isValid() {
2946
+ if (!this.type) return false;
2947
+
2948
+ if (this.type === 'linear') {
2949
+ return typeof this.x1 !== 'undefined' || typeof this.x2 !== 'undefined' || typeof this._angle !== 'undefined';
2950
+ }
2951
+
2952
+ if (this.type === 'radial') {
2953
+ return this.stops && this.stops.length >= 2;
2954
+ }
2955
+
2956
+ return false;
2957
+ }
2958
+ /**
2959
+ * 解析线性渐变参数
2960
+ * @param {string} params 参数字符串
2961
+ */
2962
+
2963
+ }, {
2964
+ key: "_parseLinearParams",
2965
+ value: function _parseLinearParams(params) {
2966
+ var trimmed = _jmUtils.jmUtils.trim(params);
2967
+
2968
+ if (trimmed.startsWith('to ')) {
2969
+ var direction = trimmed.substring(3).toLowerCase().trim();
2970
+
2971
+ var dir = this._directionToAngle(direction);
2972
+
2973
+ this._angle = dir.angle;
2974
+ this.x1 = dir.x1;
2975
+ this.y1 = dir.y1;
2976
+ this.x2 = dir.x2;
2977
+ this.y2 = dir.y2;
2978
+ } else if (this._hasAngleUnit(trimmed)) {
2979
+ var angle = this._parseAngle(trimmed);
2980
+
2981
+ this._angle = angle;
2982
+
2983
+ var coords = this._angleToCoords(angle);
2984
+
2985
+ this.x1 = coords.x1;
2986
+ this.y1 = coords.y1;
2987
+ this.x2 = coords.x2;
2988
+ this.y2 = coords.y2;
2989
+ } else if (trimmed.startsWith('at ')) {
2990
+ var radialMatch = trimmed.match(/at\s+(.+)/i);
2991
+
2992
+ if (radialMatch) {
2993
+ this._parseRadialParams(trimmed);
2994
+ }
2995
+ } else {
2996
+ var parts = trimmed.split(/\s+/);
2997
+
2998
+ if (parts.length >= 4) {
2999
+ this.x1 = parts[0];
3000
+ this.y1 = parts[1];
3001
+ this.x2 = parts[2];
3002
+ this.y2 = parts[3];
3003
+ } else if (parts.length === 2) {
3004
+ this.x1 = 0;
3005
+ this.y1 = 0;
3006
+ this.x2 = parts[0];
3007
+ this.y2 = parts[1];
3008
+ }
3009
+ }
3010
+ }
3011
+ /**
3012
+ * 解析径向渐变参数
3013
+ * @param {string} params 参数字符串
3014
+ */
3015
+
3016
+ }, {
3017
+ key: "_parseRadialParams",
3018
+ value: function _parseRadialParams(params) {
3019
+ var trimmed = _jmUtils.jmUtils.trim(params);
3020
+
3021
+ this.shape = 'ellipse';
3022
+ this.position = {
3023
+ x: '50%',
3024
+ y: '50%'
3025
+ };
3026
+ var atMatch = trimmed.match(/^(.+?)\s+at\s+(.+)$/i);
3027
+
3028
+ if (atMatch) {
3029
+ var shapePart = _jmUtils.jmUtils.trim(atMatch[1]);
3030
+
3031
+ var posPart = _jmUtils.jmUtils.trim(atMatch[2]);
3032
+
3033
+ this._parseRadialShape(shapePart);
3034
+
3035
+ this._parseRadialPosition(posPart);
3036
+ } else if (trimmed.startsWith('circle') || trimmed.startsWith('ellipse')) {
3037
+ this._parseRadialShape(trimmed);
3038
+
3039
+ this.x1 = '50%';
3040
+ this.y1 = '50%';
3041
+ this.x2 = '50%';
3042
+ this.y2 = '50%';
3043
+ } else {
3044
+ var parts = trimmed.split(/\s+/);
3045
+
3046
+ if (parts.length >= 3) {
3047
+ this.x1 = parts[0];
3048
+ this.y1 = parts[1];
3049
+ this.r1 = parts[2];
3050
+ }
3051
+
3052
+ if (parts.length >= 6) {
3053
+ this.x2 = parts[3];
3054
+ this.y2 = parts[4];
3055
+ this.r2 = parts[5];
3056
+ }
3057
+ }
3058
+
3059
+ if (this.x1 === undefined && this.y1 === undefined) {
3060
+ this.x1 = '50%';
3061
+ this.y1 = '50%';
3062
+ }
3063
+
3064
+ if (this.x2 === undefined && this.y2 === undefined) {
3065
+ this.x2 = '50%';
3066
+ this.y2 = '50%';
3067
+ }
3068
+
3069
+ if (this.r2 === undefined) {
3070
+ this.r2 = '50%';
3071
+ }
3072
+ }
3073
+ /**
3074
+ * 解析径向渐变形状
3075
+ * @param {string} shapePart 形状描述
3076
+ */
3077
+
3078
+ }, {
3079
+ key: "_parseRadialShape",
3080
+ value: function _parseRadialShape(shapePart) {
3081
+ if (shapePart.startsWith('circle')) {
3082
+ this.shape = 'circle';
3083
+ var sizeMatch = shapePart.match(/circle\s*\(\s*([^)]+)\s*\)/i);
3084
+
3085
+ if (sizeMatch) {
3086
+ this.r2 = _jmUtils.jmUtils.trim(sizeMatch[1]);
3087
+ }
3088
+ } else if (shapePart.startsWith('ellipse')) {
3089
+ this.shape = 'ellipse';
3090
+
3091
+ var _sizeMatch = shapePart.match(/ellipse\s*\(\s*([^)]+)\s*\)/i);
3092
+
3093
+ if (_sizeMatch) {
3094
+ var sizes = _jmUtils.jmUtils.trim(_sizeMatch[1]).split(/\s+/);
3095
+
3096
+ if (sizes.length >= 2) {
3097
+ this.rx = sizes[0];
3098
+ this.ry = sizes[1];
3099
+ }
3100
+ }
3101
+ }
3102
+ }
3103
+ /**
3104
+ * 解析径向渐变位置
3105
+ * @param {string} posPart 位置描述
3106
+ */
3107
+
3108
+ }, {
3109
+ key: "_parseRadialPosition",
3110
+ value: function _parseRadialPosition(posPart) {
3111
+ var parts = posPart.split(/\s+/);
3112
+
3113
+ if (parts.length >= 2) {
3114
+ this.x1 = parts[0];
3115
+ this.y1 = parts[1];
3116
+ this.x2 = parts[0];
3117
+ this.y2 = parts[1];
3118
+ }
3119
+ }
3120
+ /**
3121
+ * 解析颜色停止点
3122
+ * @param {string} colorPart 颜色部分字符串
3123
+ * @returns {number} 成功解析的颜色数量
3124
+ */
3125
+
3126
+ }, {
3127
+ key: "_parseColorStops",
3128
+ value: function _parseColorStops(colorPart) {
3129
+ if (!colorPart) {
3130
+ return 0;
3131
+ }
3132
+
3133
+ var stops = this._splitColorStops(colorPart);
3134
+
3135
+ var lastOffset = -1;
3136
+ var colorCount = 0;
3137
+
3138
+ for (var i = 0; i < stops.length; i++) {
3139
+ var stop = _jmUtils.jmUtils.trim(stops[i]);
3140
+
3141
+ if (!stop) continue;
3142
+
3143
+ var parsed = this._parseSingleColorStop(stop);
3144
+
3145
+ if (!parsed) {
3146
+ continue;
2838
3147
  }
2839
- } //解析颜色偏移
2840
- //color step
2841
3148
 
3149
+ var color = parsed.color,
3150
+ offset = parsed.offset;
2842
3151
 
2843
- var pars = ms[3].match(/((rgb(a)?\s*\([\d,\.\s]+\))|(#[a-zA-Z\d]+))\s+([\d\.]+)/ig);
3152
+ if (color === 'transparent') {
3153
+ color = 'rgba(0,0,0,0)';
3154
+ }
2844
3155
 
2845
- if (pars && pars.length) {
2846
- for (var i = 0; i < pars.length; i++) {
2847
- var par = _jmUtils.jmUtils.trim(pars[i]);
3156
+ if (!this._isValidColor(color)) {
3157
+ console.warn('jmGradient: 无效的颜色格式 "' + color + '"');
3158
+ continue;
3159
+ }
2848
3160
 
2849
- var spindex = par.lastIndexOf(' ');
3161
+ var normalizedOffset = this._normalizeOffset(offset);
2850
3162
 
2851
- if (spindex > -1) {
2852
- var offset = Number(par.substr(spindex + 1));
3163
+ var finalOffset = normalizedOffset;
2853
3164
 
2854
- var color = _jmUtils.jmUtils.trim(par.substr(0, spindex));
3165
+ if (finalOffset === null) {
3166
+ if (i === 0) {
3167
+ finalOffset = 0;
3168
+ } else if (i === stops.length - 1) {
3169
+ finalOffset = 1;
3170
+ } else {
3171
+ var nextOffset = this._findNextOffset(stops, i);
2855
3172
 
2856
- if (!isNaN(offset) && color) {
2857
- this.addStop(offset, color);
3173
+ if (nextOffset !== null) {
3174
+ finalOffset = (lastOffset + nextOffset) / 2;
3175
+ } else {
3176
+ finalOffset = Math.min(1, lastOffset + (1 - lastOffset) / (stops.length - i));
2858
3177
  }
2859
3178
  }
2860
3179
  }
3180
+
3181
+ if (finalOffset !== null) {
3182
+ if (finalOffset < 0 || finalOffset > 1) {
3183
+ console.warn('jmGradient: 颜色偏移量 ' + finalOffset + ' 超出有效范围 [0, 1],将调整为有效范围');
3184
+ finalOffset = Math.max(0, Math.min(1, finalOffset));
3185
+ }
3186
+
3187
+ lastOffset = finalOffset;
3188
+ this.addStop(finalOffset, color);
3189
+ colorCount++;
3190
+ }
3191
+ }
3192
+
3193
+ return colorCount;
3194
+ }
3195
+ /**
3196
+ * 分割颜色停止点字符串
3197
+ * @param {string} colorPart 颜色部分字符串
3198
+ * @returns {string[]} 颜色停止点数组
3199
+ */
3200
+
3201
+ }, {
3202
+ key: "_splitColorStops",
3203
+ value: function _splitColorStops(colorPart) {
3204
+ var stops = [];
3205
+ var depth = 0;
3206
+ var current = '';
3207
+
3208
+ for (var i = 0; i < colorPart.length; i++) {
3209
+ var _char2 = colorPart[i];
3210
+
3211
+ if (_char2 === '(') {
3212
+ depth++;
3213
+ current += _char2;
3214
+ } else if (_char2 === ')') {
3215
+ depth--;
3216
+ current += _char2;
3217
+ } else if (_char2 === ',' && depth === 0) {
3218
+ stops.push(current.trim());
3219
+ current = '';
3220
+ } else {
3221
+ current += _char2;
3222
+ }
3223
+ }
3224
+
3225
+ if (current.trim()) {
3226
+ stops.push(current.trim());
3227
+ }
3228
+
3229
+ return stops;
3230
+ }
3231
+ /**
3232
+ * 解析单个颜色停止点
3233
+ * @param {string} stop 单个颜色停止点字符串
3234
+ * @returns {object|null} {color, offset} 或 null
3235
+ */
3236
+
3237
+ }, {
3238
+ key: "_parseSingleColorStop",
3239
+ value: function _parseSingleColorStop(stop) {
3240
+ var hexMatch = stop.match(/^(#[a-fA-F0-9]{3,8})\s*(\d+(?:\.\d+)?%?)?$/i);
3241
+
3242
+ if (hexMatch) {
3243
+ return {
3244
+ color: hexMatch[1],
3245
+ offset: hexMatch[2] || null
3246
+ };
3247
+ }
3248
+
3249
+ var rgbaMatch = stop.match(/^(rgba?\s*\([^)]+\))\s*(\d+(?:\.\d+)?%?)?$/i);
3250
+
3251
+ if (rgbaMatch) {
3252
+ return {
3253
+ color: rgbaMatch[1],
3254
+ offset: rgbaMatch[2] || null
3255
+ };
3256
+ }
3257
+
3258
+ var hslaMatch = stop.match(/^(hsla?\s*\([^)]+\))\s*(\d+(?:\.\d+)?%?)?$/i);
3259
+
3260
+ if (hslaMatch) {
3261
+ return {
3262
+ color: hslaMatch[1],
3263
+ offset: hslaMatch[2] || null
3264
+ };
3265
+ }
3266
+
3267
+ var namedMatch = stop.match(/^([a-zA-Z]+)\s*(\d+(?:\.\d+)?%?)?$/i);
3268
+
3269
+ if (namedMatch && this._isValidColor(namedMatch[1])) {
3270
+ return {
3271
+ color: namedMatch[1],
3272
+ offset: namedMatch[2] || null
3273
+ };
3274
+ }
3275
+
3276
+ return null;
3277
+ }
3278
+ /**
3279
+ * 查找下一个有偏移量的颜色停止点
3280
+ * @param {string[]} stops 颜色停止点数组
3281
+ * @param {number} currentIndex 当前索引
3282
+ * @returns {number|null} 下一个偏移量或null
3283
+ */
3284
+
3285
+ }, {
3286
+ key: "_findNextOffset",
3287
+ value: function _findNextOffset(stops, currentIndex) {
3288
+ for (var i = currentIndex + 1; i < stops.length; i++) {
3289
+ var parsed = this._parseSingleColorStop(_jmUtils.jmUtils.trim(stops[i]));
3290
+
3291
+ if (parsed && parsed.offset) {
3292
+ return this._normalizeOffset(parsed.offset);
3293
+ }
3294
+ }
3295
+
3296
+ return null;
3297
+ }
3298
+ /**
3299
+ * 验证颜色格式是否有效
3300
+ * @param {string} color 颜色字符串
3301
+ * @returns {boolean} 是否有效
3302
+ */
3303
+
3304
+ }, {
3305
+ key: "_isValidColor",
3306
+ value: function _isValidColor(color) {
3307
+ if (!color) return false;
3308
+ var hexPattern = /^#([a-fA-F0-9]{3,8})$/;
3309
+ if (hexPattern.test(color)) return true; // 支持 rgba(r,g,b,a) 和 rgba(r, g, b, a) 等各种空格格式
3310
+
3311
+ var rgbPattern = /^rgba?\s*\(\s*\d{1,3}\s*,\s*\d{1,3}\s*,\s*\d{1,3}\s*(,\s*[\d.]+\s*)?\)$/i;
3312
+ if (rgbPattern.test(color)) return true;
3313
+ var hslPattern = /^hsla?\s*\(\s*\d{1,3}\s*,\s*\d{1,3}%?\s*,\s*\d{1,3}%?\s*(,\s*[\d.]+\s*)?\)$/i;
3314
+ if (hslPattern.test(color)) return true; // 使用 jmUtils 中的完整 CSS 颜色关键字表
3315
+
3316
+ if (_jmUtils.colorKeywords && _jmUtils.colorKeywords[color.toLowerCase()]) return true; // 宽松处理:符合 CSS 关键字命名规则的字符串也视为有效颜色
3317
+ // (纯字母,可能在运行时被浏览器或其他环境解析)
3318
+
3319
+ if (/^[a-zA-Z]+$/.test(color)) return true;
3320
+ return false;
3321
+ }
3322
+ /**
3323
+ * 标准化偏移值
3324
+ * @param {string} offset 偏移字符串
3325
+ * @returns {number|null} 0-1之间的数值或null
3326
+ */
3327
+
3328
+ }, {
3329
+ key: "_normalizeOffset",
3330
+ value: function _normalizeOffset(offset) {
3331
+ if (!offset) return null;
3332
+ offset = _jmUtils.jmUtils.trim(offset);
3333
+
3334
+ if (offset.endsWith('%')) {
3335
+ return parseFloat(offset) / 100;
3336
+ }
3337
+
3338
+ var num = parseFloat(offset);
3339
+ if (isNaN(num)) return null;
3340
+
3341
+ if (num > 1) {
3342
+ return num / 100;
3343
+ }
3344
+
3345
+ return num;
3346
+ }
3347
+ /**
3348
+ * 检查字符串是否包含角度单位
3349
+ * @param {string} str 待检查字符串
3350
+ * @returns {boolean}
3351
+ */
3352
+
3353
+ }, {
3354
+ key: "_hasAngleUnit",
3355
+ value: function _hasAngleUnit(str) {
3356
+ return /^-?\d+(\.\d+)?\s*(deg|rad|grad|turn)$/i.test(str);
3357
+ }
3358
+ /**
3359
+ * 解析角度值
3360
+ * @param {string} angleStr 角度字符串
3361
+ * @returns {number} 弧度值
3362
+ */
3363
+
3364
+ }, {
3365
+ key: "_parseAngle",
3366
+ value: function _parseAngle(angleStr) {
3367
+ angleStr = _jmUtils.jmUtils.trim(angleStr);
3368
+ var match = angleStr.match(/^(-?\d+(\.\d+)?)\s*(deg|rad|grad|turn)?$/i);
3369
+ if (!match) return 0;
3370
+ var value = parseFloat(match[1]);
3371
+ var unit = (match[3] || 'deg').toLowerCase();
3372
+
3373
+ switch (unit) {
3374
+ case 'deg':
3375
+ return value * Math.PI / 180;
3376
+
3377
+ case 'rad':
3378
+ return value;
3379
+
3380
+ case 'grad':
3381
+ return value * Math.PI / 200;
3382
+
3383
+ case 'turn':
3384
+ return value * 2 * Math.PI;
3385
+
3386
+ default:
3387
+ return value * Math.PI / 180;
3388
+ }
3389
+ }
3390
+ /**
3391
+ * 将角度转换为起点和终点坐标
3392
+ * @param {number} angle 弧度值
3393
+ * @returns {object} 坐标对象
3394
+ */
3395
+
3396
+ }, {
3397
+ key: "_angleToCoords",
3398
+ value: function _angleToCoords(angle) {
3399
+ var x = Math.cos(angle);
3400
+ var y = -Math.sin(angle);
3401
+ return {
3402
+ x1: Math.round((0.5 - x * 0.5) * 1000) / 1000,
3403
+ y1: Math.round((0.5 + y * 0.5) * 1000) / 1000,
3404
+ x2: Math.round((0.5 + x * 0.5) * 1000) / 1000,
3405
+ y2: Math.round((0.5 - y * 0.5) * 1000) / 1000
3406
+ };
3407
+ }
3408
+ /**
3409
+ * 将方向关键词转换为角度和坐标
3410
+ * @param {string} direction 方向描述
3411
+ * @returns {object} 包含angle和坐标的对象
3412
+ */
3413
+
3414
+ }, {
3415
+ key: "_directionToAngle",
3416
+ value: function _directionToAngle(direction) {
3417
+ var directions = {
3418
+ 'to top': {
3419
+ angle: 0,
3420
+ x1: '50%',
3421
+ y1: '100%',
3422
+ x2: '50%',
3423
+ y2: '0%'
3424
+ },
3425
+ 'to bottom': {
3426
+ angle: Math.PI,
3427
+ x1: '50%',
3428
+ y1: '0%',
3429
+ x2: '50%',
3430
+ y2: '100%'
3431
+ },
3432
+ 'to left': {
3433
+ angle: -Math.PI / 2,
3434
+ x1: '100%',
3435
+ y1: '50%',
3436
+ x2: '0%',
3437
+ y2: '50%'
3438
+ },
3439
+ 'to right': {
3440
+ angle: Math.PI / 2,
3441
+ x1: '0%',
3442
+ y1: '50%',
3443
+ x2: '100%',
3444
+ y2: '50%'
3445
+ },
3446
+ 'to top left': {
3447
+ angle: -Math.PI * 3 / 4,
3448
+ x1: '100%',
3449
+ y1: '100%',
3450
+ x2: '0%',
3451
+ y2: '0%'
3452
+ },
3453
+ 'to top right': {
3454
+ angle: -Math.PI / 4,
3455
+ x1: '0%',
3456
+ y1: '100%',
3457
+ x2: '100%',
3458
+ y2: '0%'
3459
+ },
3460
+ 'to bottom left': {
3461
+ angle: Math.PI * 3 / 4,
3462
+ x1: '100%',
3463
+ y1: '0%',
3464
+ x2: '0%',
3465
+ y2: '100%'
3466
+ },
3467
+ 'to bottom right': {
3468
+ angle: Math.PI / 4,
3469
+ x1: '0%',
3470
+ y1: '0%',
3471
+ x2: '100%',
3472
+ y2: '100%'
3473
+ },
3474
+ 'top': {
3475
+ angle: 0,
3476
+ x1: '50%',
3477
+ y1: '100%',
3478
+ x2: '50%',
3479
+ y2: '0%'
3480
+ },
3481
+ 'bottom': {
3482
+ angle: Math.PI,
3483
+ x1: '50%',
3484
+ y1: '0%',
3485
+ x2: '50%',
3486
+ y2: '100%'
3487
+ },
3488
+ 'left': {
3489
+ angle: -Math.PI / 2,
3490
+ x1: '100%',
3491
+ y1: '50%',
3492
+ x2: '0%',
3493
+ y2: '50%'
3494
+ },
3495
+ 'right': {
3496
+ angle: Math.PI / 2,
3497
+ x1: '0%',
3498
+ y1: '50%',
3499
+ x2: '100%',
3500
+ y2: '50%'
3501
+ }
3502
+ };
3503
+ var dir = directions[direction];
3504
+
3505
+ if (dir) {
3506
+ return dir;
3507
+ }
3508
+
3509
+ var keywordMatch = direction.match(/to\s+(top|bottom|left|right)/i);
3510
+
3511
+ if (keywordMatch) {
3512
+ var mainDir = keywordMatch[1].toLowerCase();
3513
+ var secDir = direction.replace(keywordMatch[0], '').trim();
3514
+
3515
+ if (secDir) {
3516
+ var combined = "to ".concat(mainDir, " ").concat(secDir);
3517
+
3518
+ if (directions[combined]) {
3519
+ return directions[combined];
3520
+ }
3521
+ }
2861
3522
  }
3523
+
3524
+ return {
3525
+ angle: 0,
3526
+ x1: '50%',
3527
+ y1: '100%',
3528
+ x2: '50%',
3529
+ y2: '0%'
3530
+ };
2862
3531
  }
2863
3532
  /**
2864
3533
  * 转换为渐变的字符串表达
@@ -4517,7 +5186,7 @@ exports.jmShadow = exports["default"] = jmShadow;
4517
5186
  Object.defineProperty(exports, "__esModule", {
4518
5187
  value: true
4519
5188
  });
4520
- exports.jmUtils = exports["default"] = void 0;
5189
+ exports.colorKeywords = exports.jmUtils = exports["default"] = void 0;
4521
5190
 
4522
5191
  var _jmList = require("./jmList.js");
4523
5192
 
@@ -4572,11 +5241,13 @@ var colorKeywords = {
4572
5241
  darkseagreen: "#8fbc8f",
4573
5242
  darkslateblue: "#483d8b",
4574
5243
  darkslategray: "#2f4f4f",
5244
+ darkslategrey: "#2f4f4f",
4575
5245
  darkturquoise: "#00ced1",
4576
5246
  darkviolet: "#9400d3",
4577
5247
  deeppink: "#ff1493",
4578
5248
  deepskyblue: "#00bfff",
4579
5249
  dimgray: "#696969",
5250
+ dimgrey: "#696969",
4580
5251
  dodgerblue: "#1e90ff",
4581
5252
  firebrick: "#b22222",
4582
5253
  floralwhite: "#fffaf0",
@@ -4611,6 +5282,7 @@ var colorKeywords = {
4611
5282
  lightseagreen: "#20b2aa",
4612
5283
  lightskyblue: "#87cefa",
4613
5284
  lightslategray: "#778899",
5285
+ lightslategrey: "#778899",
4614
5286
  lightsteelblue: "#b0c4de",
4615
5287
  lightyellow: "#ffffe0",
4616
5288
  lime: "#00ff00",
@@ -4651,6 +5323,7 @@ var colorKeywords = {
4651
5323
  powderblue: "#b0e0e6",
4652
5324
  purple: "#800080",
4653
5325
  red: "#ff0000",
5326
+ rebeccapurple: "#663399",
4654
5327
  rosybrown: "#bc8f8f",
4655
5328
  royalblue: "#4169e1",
4656
5329
  saddlebrown: "#8b4513",
@@ -4663,6 +5336,7 @@ var colorKeywords = {
4663
5336
  skyblue: "#87ceeb",
4664
5337
  slateblue: "#6a5acd",
4665
5338
  slategray: "#708090",
5339
+ slategrey: "#708090",
4666
5340
  snow: "#fffafa",
4667
5341
  springgreen: "#00ff7f",
4668
5342
  steelblue: "#4682b4",
@@ -4677,7 +5351,37 @@ var colorKeywords = {
4677
5351
  whitesmoke: "#f5f5f5",
4678
5352
  yellow: "#ffff00",
4679
5353
  yellowgreen: "#9acd32",
4680
- transparent: "rgba(0,0,0,0)"
5354
+ transparent: "rgba(0,0,0,0)",
5355
+ // grey 别名(已有 darkslategrey/lightslategrey/slategrey/dimgrey)
5356
+ // 以下为 CSS 系统颜色
5357
+ activeborder: "#bfcaca",
5358
+ activecaption: "#000080",
5359
+ appworkspace: "#ababab",
5360
+ background: "#636363",
5361
+ buttonface: "#c0c0c0",
5362
+ buttonhighlight: "#dedede",
5363
+ buttonshadow: "#808080",
5364
+ buttontext: "#000000",
5365
+ captiontext: "#000000",
5366
+ graytext: "#808080",
5367
+ highlight: "#b3d4fc",
5368
+ highlighttext: "#000000",
5369
+ inactiveborder: "#d4d0c8",
5370
+ inactivecaption: "#bfbbb0",
5371
+ inactivecaptiontext: "#545454",
5372
+ infobackground: "#fbfcc5",
5373
+ infotext: "#000000",
5374
+ menu: "#c0c0c0",
5375
+ menutext: "#000000",
5376
+ scrollbar: "#c0c0c0",
5377
+ threeddarkshadow: "#696969",
5378
+ threedface: "#c0c0c0",
5379
+ threedhighlight: "#dfdfdf",
5380
+ threedlightshadow: "#dcdcdc",
5381
+ threedshadow: "#808080",
5382
+ window: "#ffffff",
5383
+ windowframe: "#646464",
5384
+ windowtext: "#000000"
4681
5385
  };
4682
5386
  /**
4683
5387
  * 画图基础对象
@@ -4687,6 +5391,8 @@ var colorKeywords = {
4687
5391
  * @static
4688
5392
  */
4689
5393
 
5394
+ exports.colorKeywords = colorKeywords;
5395
+
4690
5396
  var jmUtils = /*#__PURE__*/function () {
4691
5397
  function jmUtils() {
4692
5398
  _classCallCheck(this, jmUtils);