jmgraph 3.2.19 → 3.2.21

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/README.md +311 -6
  2. package/dist/jmgraph.core.min.js +1 -1
  3. package/dist/jmgraph.core.min.js.map +1 -1
  4. package/dist/jmgraph.js +2022 -368
  5. package/dist/jmgraph.min.js +1 -1
  6. package/index.js +23 -25
  7. package/package.json +1 -1
  8. package/src/core/jmControl.js +199 -30
  9. package/src/core/jmFilter.js +150 -0
  10. package/src/core/jmGraph.js +207 -7
  11. package/src/core/jmLayer.js +142 -0
  12. package/src/core/jmPath.js +55 -0
  13. package/src/core/jmUtils.js +46 -37
  14. package/src/lib/webgl/base.js +10 -36
  15. package/src/lib/webgl/gradient.js +16 -3
  16. package/src/lib/webgl/index.js +5 -4
  17. package/src/lib/webgl/path.js +156 -33
  18. package/src/shapes/jmEllipse.js +91 -0
  19. package/src/shapes/jmLabel.js +126 -75
  20. package/src/shapes/jmPolygon.js +129 -0
  21. package/src/shapes/jmRect.js +107 -29
  22. package/src/shapes/jmStar.js +160 -0
  23. package/example/ball.html +0 -217
  24. package/example/base.html +0 -112
  25. package/example/canvas.html +0 -54
  26. package/example/cell.html +0 -284
  27. package/example/controls/arc.html +0 -129
  28. package/example/controls/arrowline.html +0 -78
  29. package/example/controls/bezier.html +0 -299
  30. package/example/controls/img.html +0 -97
  31. package/example/controls/label.html +0 -87
  32. package/example/controls/line.html +0 -173
  33. package/example/controls/prismatic.html +0 -63
  34. package/example/controls/rect.html +0 -64
  35. package/example/controls/resize.html +0 -112
  36. package/example/controls/test.html +0 -360
  37. package/example/es.html +0 -70
  38. package/example/es5module.html +0 -63
  39. package/example/heartarc.html +0 -116
  40. package/example/index.html +0 -47
  41. package/example/js/require.js +0 -5
  42. package/example/love/img/bling/bling.tps +0 -265
  43. package/example/love/img/bling.json +0 -87
  44. package/example/love/img/bling.tps +0 -295
  45. package/example/love/img/doc/bling.gif +0 -0
  46. package/example/love/img/love.json +0 -95
  47. package/example/love/img/love.tps +0 -315
  48. package/example/love/img/qq/qq.tps +0 -399
  49. package/example/love/img/qq.json +0 -242
  50. package/example/love/index.html +0 -40
  51. package/example/love/js/game.js +0 -558
  52. package/example/music.html +0 -211
  53. package/example/node/test.js +0 -138
  54. package/example/pdf.html +0 -187
  55. package/example/progress.html +0 -173
  56. package/example/pso.html +0 -148
  57. package/example/sort.html +0 -805
  58. package/example/tweenjs.html +0 -84
  59. package/example/webgl.html +0 -278
  60. package/example/xfj/img/dr_die.gif +0 -0
  61. package/example/xfj/index.html +0 -332
  62. package/example/xfj/shake.js +0 -49
  63. package/example/xfj/testori.html +0 -76
package/dist/jmgraph.js CHANGED
@@ -78,6 +78,24 @@ Object.defineProperty(exports, "jmResize", {
78
78
  return _jmResize.jmResize;
79
79
  }
80
80
  });
81
+ Object.defineProperty(exports, "jmEllipse", {
82
+ enumerable: true,
83
+ get: function get() {
84
+ return _jmEllipse.jmEllipse;
85
+ }
86
+ });
87
+ Object.defineProperty(exports, "jmPolygon", {
88
+ enumerable: true,
89
+ get: function get() {
90
+ return _jmPolygon.jmPolygon;
91
+ }
92
+ });
93
+ Object.defineProperty(exports, "jmStar", {
94
+ enumerable: true,
95
+ get: function get() {
96
+ return _jmStar.jmStar;
97
+ }
98
+ });
81
99
  Object.defineProperty(exports, "jmUtils", {
82
100
  enumerable: true,
83
101
  get: function get() {
@@ -102,6 +120,12 @@ Object.defineProperty(exports, "jmGradient", {
102
120
  return _jmGraph.jmGradient;
103
121
  }
104
122
  });
123
+ Object.defineProperty(exports, "jmFilter", {
124
+ enumerable: true,
125
+ get: function get() {
126
+ return _jmGraph.jmFilter;
127
+ }
128
+ });
105
129
  Object.defineProperty(exports, "jmControl", {
106
130
  enumerable: true,
107
131
  get: function get() {
@@ -140,16 +164,18 @@ var _jmLabel = require("./src/shapes/jmLabel.js");
140
164
 
141
165
  var _jmResize = require("./src/shapes/jmResize.js");
142
166
 
167
+ var _jmEllipse = require("./src/shapes/jmEllipse.js");
168
+
169
+ var _jmPolygon = require("./src/shapes/jmPolygon.js");
170
+
171
+ var _jmStar = require("./src/shapes/jmStar.js");
172
+
143
173
  var _jmGraph = require("./src/core/jmGraph.js");
144
174
 
145
175
  function _construct(Parent, args, Class) { if (_isNativeReflectConstruct()) { _construct = Reflect.construct; } else { _construct = function _construct(Parent, args, Class) { var a = [null]; a.push.apply(a, args); var Constructor = Function.bind.apply(Parent, a); var instance = new Constructor(); if (Class) _setPrototypeOf(instance, Class.prototype); return instance; }; } return _construct.apply(null, arguments); }
146
176
 
147
177
  function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
148
178
 
149
- function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
150
-
151
- function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
152
-
153
179
  function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }
154
180
 
155
181
  function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
@@ -177,30 +203,23 @@ var shapes = {
177
203
  "image": _jmImage.jmImage,
178
204
  "img": _jmImage.jmImage,
179
205
  "label": _jmLabel.jmLabel,
180
- "resize": _jmResize.jmResize
206
+ "resize": _jmResize.jmResize,
207
+ "ellipse": _jmEllipse.jmEllipse,
208
+ "polygon": _jmPolygon.jmPolygon,
209
+ "star": _jmStar.jmStar
181
210
  };
182
211
 
183
- var jmGraph = /*#__PURE__*/function (_jmGraphCore) {
184
- _inherits(jmGraph, _jmGraphCore);
185
-
186
- var _super = _createSuper(jmGraph);
187
-
188
- function jmGraph(canvas, option, callback) {
189
- var _this;
212
+ var jmGraphImpl = /*#__PURE__*/function (_jmGraphCore) {
213
+ _inherits(jmGraphImpl, _jmGraphCore);
190
214
 
191
- _classCallCheck(this, jmGraph);
215
+ var _super = _createSuper(jmGraphImpl);
192
216
 
193
- var targetType = this instanceof jmGraph ? this.constructor : void 0; // 合并shapes
217
+ function jmGraphImpl(canvas, option, callback) {
218
+ _classCallCheck(this, jmGraphImpl);
194
219
 
220
+ // 合并shapes
195
221
  option = Object.assign({}, option);
196
- option.shapes = Object.assign(shapes, option.shapes || {}); //不是用new实例化的话,返回一个promise
197
-
198
- if (!targetType || !(targetType.prototype instanceof _jmGraph.jmGraph)) {
199
- return _possibleConstructorReturn(_this, new Promise(function (resolve, reject) {
200
- var g = new jmGraph(canvas, option, callback);
201
- if (resolve) resolve(g);
202
- }));
203
- }
222
+ option.shapes = Object.assign(shapes, option.shapes || {});
204
223
 
205
224
  if (typeof option == 'function') {
206
225
  callback = option;
@@ -210,30 +229,25 @@ var jmGraph = /*#__PURE__*/function (_jmGraphCore) {
210
229
  return _super.call(this, canvas, option, callback);
211
230
  }
212
231
 
213
- _createClass(jmGraph, null, [{
214
- key: "create",
215
- value: function create() {
216
- return createJmGraph.apply(void 0, arguments);
217
- }
218
- }]);
219
-
220
- return jmGraph;
221
- }(_jmGraph.jmGraph); //创建实例
232
+ return jmGraphImpl;
233
+ }(_jmGraph.jmGraph); //创建实例,支持不加 new 直接调用
222
234
 
223
235
 
224
- exports.jmGraph = exports["default"] = jmGraph;
236
+ exports.jmGraph = jmGraphImpl;
225
237
 
226
238
  var createJmGraph = function createJmGraph() {
227
239
  for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
228
240
  args[_key] = arguments[_key];
229
241
  }
230
242
 
231
- return _construct(jmGraph, args);
243
+ return _construct(jmGraphImpl, args);
232
244
  };
233
245
 
234
246
  exports.create = createJmGraph;
247
+ var _default = jmGraphImpl;
248
+ exports["default"] = _default;
235
249
 
236
- },{"./src/core/jmGraph.js":5,"./src/shapes/jmArc.js":22,"./src/shapes/jmArrow.js":23,"./src/shapes/jmArrowLine.js":24,"./src/shapes/jmBezier.js":25,"./src/shapes/jmCircle.js":26,"./src/shapes/jmHArc.js":27,"./src/shapes/jmImage.js":28,"./src/shapes/jmLabel.js":29,"./src/shapes/jmLine.js":30,"./src/shapes/jmPrismatic.js":31,"./src/shapes/jmRect.js":32,"./src/shapes/jmResize.js":33}],2:[function(require,module,exports){
250
+ },{"./src/core/jmGraph.js":6,"./src/shapes/jmArc.js":23,"./src/shapes/jmArrow.js":24,"./src/shapes/jmArrowLine.js":25,"./src/shapes/jmBezier.js":26,"./src/shapes/jmCircle.js":27,"./src/shapes/jmEllipse.js":28,"./src/shapes/jmHArc.js":29,"./src/shapes/jmImage.js":30,"./src/shapes/jmLabel.js":31,"./src/shapes/jmLine.js":32,"./src/shapes/jmPolygon.js":33,"./src/shapes/jmPrismatic.js":34,"./src/shapes/jmRect.js":35,"./src/shapes/jmResize.js":36,"./src/shapes/jmStar.js":37}],2:[function(require,module,exports){
237
251
  "use strict";
238
252
 
239
253
  Object.defineProperty(exports, "__esModule", {
@@ -249,20 +263,14 @@ var _jmGradient = require("./jmGradient.js");
249
263
 
250
264
  var _jmShadow = require("./jmShadow.js");
251
265
 
266
+ var _jmFilter = require("./jmFilter.js");
267
+
252
268
  var _jmProperty2 = require("./jmProperty.js");
253
269
 
254
270
  var _path = _interopRequireDefault(require("../lib/webgl/path.js"));
255
271
 
256
272
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
257
273
 
258
- function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); }
259
-
260
- function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
261
-
262
- function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); }
263
-
264
- function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); }
265
-
266
274
  function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) { symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; }
267
275
 
268
276
  function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
@@ -318,7 +326,9 @@ var jmStyleMap = {
318
326
  'shadowOffsetY': 'shadowOffsetY',
319
327
  'shadowColor': 'shadowColor',
320
328
  'lineJoin': 'lineJoin',
321
- 'lineCap': 'lineCap'
329
+ 'lineCap': 'lineCap',
330
+ 'lineDashOffset': 'lineDashOffset',
331
+ 'globalCompositeOperation': 'globalCompositeOperation'
322
332
  };
323
333
 
324
334
  var jmControl = /*#__PURE__*/function (_jmProperty) {
@@ -560,7 +570,10 @@ var jmControl = /*#__PURE__*/function (_jmProperty) {
560
570
  value: function setStyle(style) {
561
571
  var _this3 = this;
562
572
 
563
- style = style || _jmUtils.jmUtils.clone(this.style, true);
573
+ if (!style) {
574
+ style = this.style;
575
+ }
576
+
564
577
  if (!style) return;
565
578
 
566
579
  var __setStyle = function __setStyle(style, name, mpkey) {
@@ -648,6 +661,153 @@ var jmControl = /*#__PURE__*/function (_jmProperty) {
648
661
  case 'cursor':
649
662
  {
650
663
  _this3.cursor = styleValue;
664
+ break;
665
+ }
666
+ // ===== 新增样式特性 =====
667
+ // 虚线样式:支持自定义lineDash模式 (如 [5, 3, 2] 或 "5,3,2")
668
+
669
+ case 'lineDash':
670
+ {
671
+ if (!_this3.context.setLineDash) break;
672
+ var dash;
673
+
674
+ if (typeof styleValue === 'string') {
675
+ dash = styleValue.split(',').map(function (v) {
676
+ return parseFloat(v.trim());
677
+ }).filter(function (v) {
678
+ return !isNaN(v);
679
+ });
680
+ } else if (Array.isArray(styleValue)) {
681
+ dash = styleValue.map(function (v) {
682
+ return parseFloat(v);
683
+ }).filter(function (v) {
684
+ return !isNaN(v);
685
+ });
686
+ }
687
+
688
+ if (dash && dash.length) {
689
+ _this3.context.setLineDash(dash);
690
+ } else {
691
+ _this3.context.setLineDash([]);
692
+ }
693
+
694
+ break;
695
+ }
696
+ // 虚线偏移量
697
+
698
+ case 'lineDashOffset':
699
+ {
700
+ if (!_this3.context.setLineDash) break;
701
+ _this3.context.lineDashOffset = Number(styleValue) || 0;
702
+ break;
703
+ }
704
+ // CSS滤镜效果 (blur, grayscale, sepia, brightness, contrast, saturate, hue-rotate, invert, opacity)
705
+
706
+ case 'filter':
707
+ {
708
+ if (_this3.context.filter === undefined) break;
709
+
710
+ if (styleValue instanceof _jmFilter.jmFilter) {
711
+ _this3.context.filter = styleValue.toCanvasFilter();
712
+ } else if (typeof styleValue === 'string') {
713
+ _this3.context.filter = styleValue || 'none';
714
+ } else if (_typeof(styleValue) === 'object') {
715
+ _this3.context.filter = new _jmFilter.jmFilter(styleValue).toCanvasFilter();
716
+ }
717
+
718
+ break;
719
+ }
720
+ // 混合模式 (source-over, multiply, screen, overlay, darken, lighten, etc.)
721
+
722
+ case 'globalCompositeOperation':
723
+ {
724
+ if (!_this3.context.globalCompositeOperation) break;
725
+ _this3.context.globalCompositeOperation = styleValue;
726
+ break;
727
+ }
728
+ // 裁剪路径:通过canvas clip实现
729
+
730
+ case 'clipPath':
731
+ {
732
+ if (!_this3.context.clip) break; // clipPath可以是一个图形控件实例
733
+
734
+ if (styleValue && styleValue.points && styleValue.points.length > 0) {
735
+ var bounds = _this3.parent && _this3.parent.absoluteBounds ? _this3.parent.absoluteBounds : _this3.absoluteBounds;
736
+
737
+ _this3.context.beginPath();
738
+
739
+ _this3.context.moveTo(styleValue.points[0].x + (bounds ? bounds.left : 0), styleValue.points[0].y + (bounds ? bounds.top : 0));
740
+
741
+ for (var i = 1; i < styleValue.points.length; i++) {
742
+ if (styleValue.points[i].m) {
743
+ _this3.context.moveTo(styleValue.points[i].x + (bounds ? bounds.left : 0), styleValue.points[i].y + (bounds ? bounds.top : 0));
744
+ } else {
745
+ _this3.context.lineTo(styleValue.points[i].x + (bounds ? bounds.left : 0), styleValue.points[i].y + (bounds ? bounds.top : 0));
746
+ }
747
+ }
748
+
749
+ if (styleValue.style && styleValue.style.close) {
750
+ _this3.context.closePath();
751
+ }
752
+
753
+ _this3.context.clip();
754
+ }
755
+
756
+ break;
757
+ }
758
+ // 遮罩效果:通过globalCompositeOperation + destination-in实现
759
+
760
+ case 'mask':
761
+ {
762
+ if (!_this3.context.globalCompositeOperation) break; // mask是一个图形控件实例,在绘制前需要先应用mask
763
+ // 这里只是标记,实际绘制在paint流程中处理
764
+
765
+ _this3.__mask = styleValue;
766
+ break;
767
+ }
768
+ // 图片阴影描边阴影(WebGL纹理canvas用)
769
+
770
+ case 'shadowColor':
771
+ {
772
+ if (_this3.webglControl) {
773
+ _this3.webglControl.setStyle('shadowColor', styleValue);
774
+ } else {
775
+ _this3.context.shadowColor = _jmUtils.jmUtils.toColor(styleValue);
776
+ }
777
+
778
+ break;
779
+ }
780
+
781
+ case 'shadowBlur':
782
+ {
783
+ if (_this3.webglControl) {
784
+ _this3.webglControl.setStyle('shadowBlur', styleValue);
785
+ } else {
786
+ _this3.context.shadowBlur = Number(styleValue) || 0;
787
+ }
788
+
789
+ break;
790
+ }
791
+
792
+ case 'shadowOffsetX':
793
+ {
794
+ if (_this3.webglControl) {
795
+ _this3.webglControl.setStyle('shadowOffsetX', styleValue);
796
+ } else {
797
+ _this3.context.shadowOffsetX = Number(styleValue) || 0;
798
+ }
799
+
800
+ break;
801
+ }
802
+
803
+ case 'shadowOffsetY':
804
+ {
805
+ if (_this3.webglControl) {
806
+ _this3.webglControl.setStyle('shadowOffsetY', styleValue);
807
+ } else {
808
+ _this3.context.shadowOffsetY = Number(styleValue) || 0;
809
+ }
810
+
651
811
  break;
652
812
  }
653
813
  }
@@ -672,6 +832,8 @@ var jmControl = /*#__PURE__*/function (_jmProperty) {
672
832
  style[k] = new _jmGradient.jmGradient(style[k]);
673
833
  } else if (t == 'string' && k == 'shadow') {
674
834
  style[k] = new _jmShadow.jmShadow(style[k]);
835
+ } else if (t == 'string' && k == 'filter') {
836
+ style[k] = new _jmFilter.jmFilter(style[k]);
675
837
  }
676
838
 
677
839
  __setStyle(style[k], k);
@@ -849,7 +1011,6 @@ var jmControl = /*#__PURE__*/function (_jmProperty) {
849
1011
  }, {
850
1012
  key: "getLocation",
851
1013
  value: function getLocation() {
852
- var clone = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
853
1014
  //如果已经计算过则直接返回
854
1015
  //在开画之前会清空此对象
855
1016
  //if(reset !== true && this.location) return this.location;
@@ -858,32 +1019,34 @@ var jmControl = /*#__PURE__*/function (_jmProperty) {
858
1019
  top: 0,
859
1020
  width: 0,
860
1021
  height: 0
861
- };
862
- local.position = typeof this.position == 'function' ? this.position() : _jmUtils.jmUtils.clone(this.position);
863
- local.center = this.center && typeof this.center === 'function' ? this.center() : _jmUtils.jmUtils.clone(this.center); //中心
1022
+ }; // 检查是否有百分比参数需要解析,没有则直接引用避免克隆开销
1023
+
1024
+ var needResolve = this.parent && (_jmUtils.jmUtils.checkPercent(this.width) || _jmUtils.jmUtils.checkPercent(this.height) || this.position && _jmUtils.jmUtils.checkPercent(this.position.x) || this.position && _jmUtils.jmUtils.checkPercent(this.position.y));
864
1025
 
865
- local.start = this.start && typeof this.start === 'function' ? this.start() : _jmUtils.jmUtils.clone(this.start); //起点
1026
+ local.position = typeof this.position == 'function' ? this.position() : needResolve ? _jmUtils.jmUtils.clone(this.position) : this.position;
1027
+ local.center = this.center && typeof this.center === 'function' ? this.center() : needResolve ? _jmUtils.jmUtils.clone(this.center) : this.center; //中心
866
1028
 
867
- local.end = this.end && typeof this.end === 'function' ? this.end() : _jmUtils.jmUtils.clone(this.end); //起点
1029
+ local.start = this.start && typeof this.start === 'function' ? this.start() : needResolve ? _jmUtils.jmUtils.clone(this.start) : this.start; //起点
1030
+
1031
+ local.end = this.end && typeof this.end === 'function' ? this.end() : needResolve ? _jmUtils.jmUtils.clone(this.end) : this.end; //起点
868
1032
 
869
1033
  local.radius = this.radius; //半径
870
1034
 
871
1035
  local.width = this.width;
872
1036
  local.height = this.height;
873
-
874
- var margin = _jmUtils.jmUtils.clone(this.style.margin, {});
875
-
876
- margin.left = margin.left || 0;
877
- margin.top = margin.top || 0;
878
- margin.right = margin.right || 0;
879
- margin.bottom = margin.bottom || 0; //如果没有指定位置,但指定了margin。则位置取margin偏移量
1037
+ var margin = this.style.margin;
1038
+ var marginObj = needResolve && margin ? _jmUtils.jmUtils.clone(margin, {}) : margin || {};
1039
+ marginObj.left = marginObj.left || 0;
1040
+ marginObj.top = marginObj.top || 0;
1041
+ marginObj.right = marginObj.right || 0;
1042
+ marginObj.bottom = marginObj.bottom || 0; //如果没有指定位置,但指定了margin。则位置取margin偏移量
880
1043
 
881
1044
  if (local.position) {
882
1045
  local.left = local.position.x;
883
1046
  local.top = local.position.y;
884
1047
  } else {
885
- local.left = margin.left;
886
- local.top = margin.top;
1048
+ local.left = marginObj.left;
1049
+ local.top = marginObj.top;
887
1050
  }
888
1051
 
889
1052
  if (this.parent) {
@@ -1177,25 +1340,36 @@ var jmControl = /*#__PURE__*/function (_jmProperty) {
1177
1340
  if (this.style.close) {
1178
1341
  if (this.webglControl) this.webglControl.closePath();
1179
1342
  this.context.closePath && this.context.closePath();
1180
- }
1343
+ } // 根据渲染模式选择不同的绘制路径
1181
1344
 
1182
- var fill = this.style['fill'] || this.style['fillStyle'];
1183
1345
 
1184
- if (fill) {
1185
- if (this.webglControl) {
1346
+ if (this.webglControl) {
1347
+ // WebGL 模式:使用 WebGL 绘制
1348
+ var fill = this.style['fill'] || this.style['fillStyle'];
1349
+
1350
+ if (fill) {
1186
1351
  var bounds = this.getBounds();
1187
1352
  this.webglControl.fill(bounds);
1188
1353
  }
1189
1354
 
1190
- this.context.fill && this.context.fill();
1191
- }
1355
+ if (this.style['stroke'] || !fill && !this.is('jmGraph')) {
1356
+ this.webglControl.stroke();
1357
+ }
1358
+
1359
+ if (this.webglControl.endDraw) this.webglControl.endDraw();
1360
+ } else {
1361
+ // 2D 模式:使用 Canvas 2D API 绘制
1362
+ var _fill = this.style['fill'] || this.style['fillStyle'];
1363
+
1364
+ if (_fill) {
1365
+ this.context.fill && this.context.fill();
1366
+ }
1192
1367
 
1193
- if (this.style['stroke'] || !fill && !this.is('jmGraph')) {
1194
- if (this.webglControl) this.webglControl.stroke();
1195
- this.context.stroke && this.context.stroke();
1368
+ if (this.style['stroke'] || !_fill && !this.is('jmGraph')) {
1369
+ this.context.stroke && this.context.stroke();
1370
+ }
1196
1371
  }
1197
1372
 
1198
- if (this.webglControl && this.webglControl.endDraw) this.webglControl.endDraw();
1199
1373
  this.needUpdate = false;
1200
1374
  }
1201
1375
  /**
@@ -1214,7 +1388,7 @@ var jmControl = /*#__PURE__*/function (_jmProperty) {
1214
1388
 
1215
1389
  if (this.webglControl) {
1216
1390
  this.webglControl.setParentBounds(bounds);
1217
- this.webglControl.draw(_toConsumableArray(this.points));
1391
+ this.webglControl.draw(this.points);
1218
1392
  } else if (this.context && this.context.moveTo) {
1219
1393
  this.context.moveTo(this.points[0].x + bounds.left, this.points[0].y + bounds.top);
1220
1394
  var len = this.points.length;
@@ -1255,10 +1429,47 @@ var jmControl = /*#__PURE__*/function (_jmProperty) {
1255
1429
  this.context.save && this.context.save();
1256
1430
  this.emit('beginDraw', this);
1257
1431
  this.setStyle(); //设定样式
1432
+ // 应用mask遮罩效果:在mask区域内绘制当前控件
1433
+ // 使用 destination-in 合成模式,只保留mask区域内的内容
1434
+
1435
+ var maskStyle = this.style.mask || this.__mask;
1436
+
1437
+ if (maskStyle && maskStyle.points && this.context.globalCompositeOperation) {
1438
+ // 先绘制当前控件
1439
+ if (needDraw && this.beginDraw) this.beginDraw();
1440
+ if (needDraw && this.draw) this.draw();
1441
+ if (needDraw && this.endDraw) this.endDraw(); // 再应用mask裁剪
1442
+
1443
+ this.context.globalCompositeOperation = 'destination-in';
1444
+ if (maskStyle.initPoints) maskStyle.initPoints();
1445
+ var mBounds = maskStyle.parent && maskStyle.parent.absoluteBounds ? maskStyle.parent.absoluteBounds : this.absoluteBounds;
1446
+ this.context.beginPath();
1447
+
1448
+ if (maskStyle.points && maskStyle.points.length > 0) {
1449
+ this.context.moveTo(maskStyle.points[0].x + (mBounds ? mBounds.left : 0), maskStyle.points[0].y + (mBounds ? mBounds.top : 0));
1450
+
1451
+ for (var i = 1; i < maskStyle.points.length; i++) {
1452
+ if (maskStyle.points[i].m) {
1453
+ this.context.moveTo(maskStyle.points[i].x + (mBounds ? mBounds.left : 0), maskStyle.points[i].y + (mBounds ? mBounds.top : 0));
1454
+ } else {
1455
+ this.context.lineTo(maskStyle.points[i].x + (mBounds ? mBounds.left : 0), maskStyle.points[i].y + (mBounds ? mBounds.top : 0));
1456
+ }
1457
+ }
1458
+
1459
+ if (maskStyle.style && maskStyle.style.close) {
1460
+ this.context.closePath();
1461
+ }
1462
+ }
1463
+
1464
+ this.context.fillStyle = '#ffffff';
1465
+ this.context.fill(); // 恢复合成模式
1258
1466
 
1259
- if (needDraw && this.beginDraw) this.beginDraw();
1260
- if (needDraw && this.draw) this.draw();
1261
- if (needDraw && this.endDraw) this.endDraw();
1467
+ this.context.globalCompositeOperation = 'source-over';
1468
+ } else {
1469
+ if (needDraw && this.beginDraw) this.beginDraw();
1470
+ if (needDraw && this.draw) this.draw();
1471
+ if (needDraw && this.endDraw) this.endDraw();
1472
+ }
1262
1473
 
1263
1474
  if (this.children) {
1264
1475
  this.children.each(function (i, item) {
@@ -1895,7 +2106,7 @@ var jmControl = /*#__PURE__*/function (_jmProperty) {
1895
2106
  exports.jmControl = exports["default"] = jmControl;
1896
2107
  ;
1897
2108
 
1898
- },{"../lib/webgl/path.js":21,"./jmGradient.js":4,"./jmList.js":6,"./jmProperty.js":9,"./jmShadow.js":10,"./jmUtils.js":11}],3:[function(require,module,exports){
2109
+ },{"../lib/webgl/path.js":22,"./jmFilter.js":4,"./jmGradient.js":5,"./jmList.js":7,"./jmProperty.js":10,"./jmShadow.js":11,"./jmUtils.js":12}],3:[function(require,module,exports){
1899
2110
  "use strict";
1900
2111
 
1901
2112
  Object.defineProperty(exports, "__esModule", {
@@ -2169,7 +2380,210 @@ var jmKeyEvent = /*#__PURE__*/function () {
2169
2380
  return jmKeyEvent;
2170
2381
  }();
2171
2382
 
2172
- },{"./jmUtils.js":11}],4:[function(require,module,exports){
2383
+ },{"./jmUtils.js":12}],4:[function(require,module,exports){
2384
+ "use strict";
2385
+
2386
+ Object.defineProperty(exports, "__esModule", {
2387
+ value: true
2388
+ });
2389
+ exports.jmFilter = exports["default"] = void 0;
2390
+
2391
+ var _jmUtils = require("./jmUtils.js");
2392
+
2393
+ function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
2394
+
2395
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
2396
+
2397
+ function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
2398
+
2399
+ function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
2400
+
2401
+ /**
2402
+ * CSS滤镜效果类
2403
+ * 支持的滤镜: blur, grayscale, sepia, brightness, contrast, saturate, hue-rotate, invert, opacity
2404
+ *
2405
+ * @class jmFilter
2406
+ * @param {string|object} opt 滤镜参数
2407
+ * 字符串格式: "blur(2px) grayscale(50%) brightness(1.2)"
2408
+ * 对象格式: { blur: 2, grayscale: 0.5, brightness: 1.2 }
2409
+ */
2410
+ var jmFilter = /*#__PURE__*/function () {
2411
+ function jmFilter(opt) {
2412
+ _classCallCheck(this, jmFilter);
2413
+
2414
+ this.filters = [];
2415
+
2416
+ if (typeof opt === 'string') {
2417
+ this.fromString(opt);
2418
+ } else if (opt && _typeof(opt) === 'object') {
2419
+ for (var k in opt) {
2420
+ if (k === 'constructor' || k === 'filters') continue;
2421
+ this.addFilter(k, opt[k]);
2422
+ }
2423
+ }
2424
+ }
2425
+ /**
2426
+ * 添加单个滤镜
2427
+ * @param {string} name 滤镜名称 (blur, grayscale, sepia, brightness, contrast, saturate, hue-rotate, invert, opacity)
2428
+ * @param {number|string} value 滤镜值
2429
+ */
2430
+
2431
+
2432
+ _createClass(jmFilter, [{
2433
+ key: "addFilter",
2434
+ value: function addFilter(name, value) {
2435
+ name = name.toLowerCase().trim();
2436
+
2437
+ if (typeof value === 'string') {
2438
+ value = parseFloat(value);
2439
+ }
2440
+
2441
+ if (isNaN(value)) return; // 规范化滤镜名称
2442
+
2443
+ var normalized = {
2444
+ 'blur': 'blur',
2445
+ 'grayscale': 'grayscale',
2446
+ 'greyscale': 'grayscale',
2447
+ 'sepia': 'sepia',
2448
+ 'brightness': 'brightness',
2449
+ 'contrast': 'contrast',
2450
+ 'saturate': 'saturate',
2451
+ 'hue-rotate': 'hueRotate',
2452
+ 'hueRotate': 'hueRotate',
2453
+ 'invert': 'invert',
2454
+ 'opacity': 'opacity'
2455
+ }[name];
2456
+ if (!normalized) return; // 检查是否已有同名滤镜,有则更新
2457
+
2458
+ var existing = this.filters.find(function (f) {
2459
+ return f.name === normalized;
2460
+ });
2461
+
2462
+ if (existing) {
2463
+ existing.value = value;
2464
+ } else {
2465
+ this.filters.push({
2466
+ name: normalized,
2467
+ value: value
2468
+ });
2469
+ }
2470
+ }
2471
+ /**
2472
+ * 从字符串格式解析滤镜
2473
+ * 格式: "blur(2px) grayscale(50%) brightness(1.2)"
2474
+ * @param {string} s 滤镜字符串
2475
+ */
2476
+
2477
+ }, {
2478
+ key: "fromString",
2479
+ value: function fromString(s) {
2480
+ if (!s || typeof s !== 'string') return; // 匹配 filterName(value) 模式
2481
+
2482
+ var regex = /([a-zA-Z-]+)\s*\(\s*([^)]+)\s*\)/g;
2483
+ var match;
2484
+
2485
+ while ((match = regex.exec(s)) !== null) {
2486
+ var name = match[1];
2487
+ var valueStr = match[2].replace(/[a-z%]+$/i, '').trim();
2488
+ var value = parseFloat(valueStr);
2489
+
2490
+ if (!isNaN(value)) {
2491
+ this.addFilter(name, value);
2492
+ }
2493
+ }
2494
+ }
2495
+ /**
2496
+ * 转换为CSS filter字符串格式
2497
+ * @returns {string}
2498
+ */
2499
+
2500
+ }, {
2501
+ key: "toString",
2502
+ value: function toString() {
2503
+ return this.filters.map(function (f) {
2504
+ switch (f.name) {
2505
+ case 'blur':
2506
+ return "blur(".concat(f.value, "px)");
2507
+
2508
+ case 'hueRotate':
2509
+ return "hue-rotate(".concat(f.value, "deg)");
2510
+
2511
+ default:
2512
+ return "".concat(f.name, "(").concat(f.value, ")");
2513
+ }
2514
+ }).join(' ');
2515
+ }
2516
+ /**
2517
+ * 转换为Canvas context.filter可用的字符串
2518
+ * @returns {string}
2519
+ */
2520
+
2521
+ }, {
2522
+ key: "toCanvasFilter",
2523
+ value: function toCanvasFilter() {
2524
+ if (this.filters.length === 0) return 'none';
2525
+ return this.toString();
2526
+ }
2527
+ /**
2528
+ * 检查是否有指定名称的滤镜
2529
+ * @param {string} name 滤镜名称
2530
+ * @returns {boolean}
2531
+ */
2532
+
2533
+ }, {
2534
+ key: "has",
2535
+ value: function has(name) {
2536
+ return this.filters.some(function (f) {
2537
+ return f.name === name;
2538
+ });
2539
+ }
2540
+ /**
2541
+ * 获取指定滤镜的值
2542
+ * @param {string} name 滤镜名称
2543
+ * @returns {number|undefined}
2544
+ */
2545
+
2546
+ }, {
2547
+ key: "get",
2548
+ value: function get(name) {
2549
+ var f = this.filters.find(function (f) {
2550
+ return f.name === name;
2551
+ });
2552
+ return f ? f.value : undefined;
2553
+ }
2554
+ /**
2555
+ * 移除指定滤镜
2556
+ * @param {string} name 滤镜名称
2557
+ */
2558
+
2559
+ }, {
2560
+ key: "remove",
2561
+ value: function remove(name) {
2562
+ var index = this.filters.findIndex(function (f) {
2563
+ return f.name === name;
2564
+ });
2565
+
2566
+ if (index > -1) {
2567
+ this.filters.splice(index, 1);
2568
+ }
2569
+ }
2570
+ /**
2571
+ * 清空所有滤镜
2572
+ */
2573
+
2574
+ }, {
2575
+ key: "clear",
2576
+ value: function clear() {
2577
+ this.filters = [];
2578
+ }
2579
+ }]);
2580
+
2581
+ return jmFilter;
2582
+ }();
2583
+
2584
+ exports.jmFilter = exports["default"] = jmFilter;
2585
+
2586
+ },{"./jmUtils.js":12}],5:[function(require,module,exports){
2173
2587
  "use strict";
2174
2588
 
2175
2589
  Object.defineProperty(exports, "__esModule", {
@@ -2452,7 +2866,7 @@ var jmGradient = /*#__PURE__*/function () {
2452
2866
 
2453
2867
  exports.jmGradient = exports["default"] = jmGradient;
2454
2868
 
2455
- },{"./jmList.js":6,"./jmUtils.js":11}],5:[function(require,module,exports){
2869
+ },{"./jmList.js":7,"./jmUtils.js":12}],6:[function(require,module,exports){
2456
2870
  "use strict";
2457
2871
 
2458
2872
  function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
@@ -2490,6 +2904,12 @@ Object.defineProperty(exports, "jmGradient", {
2490
2904
  return _jmGradient.jmGradient;
2491
2905
  }
2492
2906
  });
2907
+ Object.defineProperty(exports, "jmFilter", {
2908
+ enumerable: true,
2909
+ get: function get() {
2910
+ return _jmFilter.jmFilter;
2911
+ }
2912
+ });
2493
2913
  Object.defineProperty(exports, "jmEvents", {
2494
2914
  enumerable: true,
2495
2915
  get: function get() {
@@ -2520,6 +2940,8 @@ var _jmShadow = require("./jmShadow.js");
2520
2940
 
2521
2941
  var _jmGradient = require("./jmGradient.js");
2522
2942
 
2943
+ var _jmFilter = require("./jmFilter.js");
2944
+
2523
2945
  var _jmEvents = require("./jmEvents.js");
2524
2946
 
2525
2947
  var _jmControl2 = require("./jmControl.js");
@@ -2597,7 +3019,13 @@ var jmGraph = /*#__PURE__*/function (_jmControl) {
2597
3019
 
2598
3020
  _this.util = _this.utils = _jmUtils.jmUtils; // 模式 webgl | 2d
2599
3021
 
2600
- _this.mode = option.mode || '2d'; //如果是小程序
3022
+ _this.mode = option.mode || '2d'; // 缩放和平移相关
3023
+
3024
+ _this.scaleFactor = 1;
3025
+ _this.translation = {
3026
+ x: 0,
3027
+ y: 0
3028
+ }; //如果是小程序
2601
3029
 
2602
3030
  if (typeof wx != 'undefined' && wx.canIUse && wx.canIUse('canvas')) {
2603
3031
  if (typeof canvas === 'string') canvas = wx.createSelectorQuery().select('#' + canvas);
@@ -2683,14 +3111,24 @@ var jmGraph = /*#__PURE__*/function (_jmControl) {
2683
3111
  */
2684
3112
 
2685
3113
  this.on('beginDraw', function () {
2686
- this.context.translate && this.context.translate(0.5, 0.5);
3114
+ this.context.translate && this.context.translate(0.5, 0.5); // 应用缩放和平移变换
3115
+
3116
+ if (this.context.translate && this.context.scale) {
3117
+ this.context.translate(this.translation.x, this.translation.y);
3118
+ this.context.scale(this.scaleFactor, this.scaleFactor);
3119
+ }
2687
3120
  });
2688
3121
  /**
2689
3122
  * 结束控件绘制 为了解决一像素线条问题
2690
3123
  */
2691
3124
 
2692
3125
  this.on('endDraw', function () {
2693
- this.context.translate && this.context.translate(-0.5, -0.5);
3126
+ this.context.translate && this.context.translate(-0.5, -0.5); // 恢复缩放和平移变换
3127
+
3128
+ if (this.context.translate && this.context.scale) {
3129
+ this.context.scale(1 / this.scaleFactor, 1 / this.scaleFactor);
3130
+ this.context.translate(-this.translation.x, -this.translation.y);
3131
+ }
2694
3132
  }); // devicePixelRatio初始化
2695
3133
 
2696
3134
  var dpr = typeof window != 'undefined' && window.devicePixelRatio > 1 ? window.devicePixelRatio : 1;
@@ -3128,6 +3566,93 @@ var jmGraph = /*#__PURE__*/function (_jmControl) {
3128
3566
 
3129
3567
  this.canvas.style && (this.canvas.style.transform = "scale(".concat(this.scaleSize.x, ", ").concat(this.scaleSize.y, ")"));
3130
3568
  }
3569
+ /**
3570
+ * 设置缩放因子
3571
+ * 支持以指定点为中心进行缩放,保持该点在屏幕上的位置不变
3572
+ *
3573
+ * @method setZoom
3574
+ * @param {number} zoom 缩放因子(建议范围:0.1 - 10)
3575
+ * @param {number} [x] 缩放中心X坐标(画布坐标)
3576
+ * @param {number} [y] 缩放中心Y坐标(画布坐标)
3577
+ * @return {jmGraph} 返回当前实例,支持链式调用
3578
+ */
3579
+
3580
+ }, {
3581
+ key: "setZoom",
3582
+ value: function setZoom(zoom, x, y) {
3583
+ // 参数验证
3584
+ if (typeof zoom !== 'number' || isNaN(zoom)) {
3585
+ console.warn('jmGraph: setZoom - 无效的缩放因子');
3586
+ return this;
3587
+ } // 限制缩放范围,防止过度缩放导致性能问题或显示异常
3588
+
3589
+
3590
+ var minZoom = 0.1; // 最小缩放到10%
3591
+
3592
+ var maxZoom = 10; // 最大放大到10倍
3593
+
3594
+ zoom = Math.max(minZoom, Math.min(maxZoom, zoom));
3595
+
3596
+ if (x !== undefined && y !== undefined) {
3597
+ // 计算缩放前后的坐标偏移
3598
+ // 保持缩放中心点在屏幕上的位置不变
3599
+ var oldZoom = this.scaleFactor;
3600
+ var newZoom = zoom; // 调整平移量以保持缩放中心位置不变
3601
+
3602
+ this.translation.x = x - (x - this.translation.x) * (newZoom / oldZoom);
3603
+ this.translation.y = y - (y - this.translation.y) * (newZoom / oldZoom);
3604
+ }
3605
+
3606
+ this.scaleFactor = zoom;
3607
+ this.needUpdate = true;
3608
+ this.redraw();
3609
+ return this; // 支持链式调用
3610
+ }
3611
+ /**
3612
+ * 平移画布
3613
+ * 移动画布视图,改变可视区域
3614
+ *
3615
+ * @method pan
3616
+ * @param {number} dx X轴平移量(像素)
3617
+ * @param {number} dy Y轴平移量(像素)
3618
+ * @return {jmGraph} 返回当前实例,支持链式调用
3619
+ */
3620
+
3621
+ }, {
3622
+ key: "pan",
3623
+ value: function pan(dx, dy) {
3624
+ // 参数验证
3625
+ if (typeof dx !== 'number' || typeof dy !== 'number' || isNaN(dx) || isNaN(dy)) {
3626
+ console.warn('jmGraph: pan - 无效的平移参数');
3627
+ return this;
3628
+ }
3629
+
3630
+ this.translation.x += dx;
3631
+ this.translation.y += dy;
3632
+ this.needUpdate = true;
3633
+ this.redraw();
3634
+ return this; // 支持链式调用
3635
+ }
3636
+ /**
3637
+ * 重置缩放和平移
3638
+ * 恢复画布到初始状态(缩放为1,平移为0)
3639
+ *
3640
+ * @method resetTransform
3641
+ * @return {jmGraph} 返回当前实例,支持链式调用
3642
+ */
3643
+
3644
+ }, {
3645
+ key: "resetTransform",
3646
+ value: function resetTransform() {
3647
+ this.scaleFactor = 1;
3648
+ this.translation = {
3649
+ x: 0,
3650
+ y: 0
3651
+ };
3652
+ this.needUpdate = true;
3653
+ this.redraw();
3654
+ return this; // 支持链式调用
3655
+ }
3131
3656
  /**
3132
3657
  * 保存为base64图形数据
3133
3658
  *
@@ -3141,6 +3666,126 @@ var jmGraph = /*#__PURE__*/function (_jmControl) {
3141
3666
  var data = this.canvas.toDataURL ? this.canvas.toDataURL() : '';
3142
3667
  return data;
3143
3668
  }
3669
+ /**
3670
+ * 导出为PNG图片
3671
+ * 使用Canvas的toDataURL方法导出当前画布内容
3672
+ *
3673
+ * @method exportToPNG
3674
+ * @param {string} [fileName='jmgraph-export'] 文件名(不含扩展名)
3675
+ * @param {string} [format='image/png'] 图片格式,支持image/png和image/jpeg
3676
+ * @param {number} [quality=0.9] 图片质量(0-1之间,仅对JPEG格式有效)
3677
+ */
3678
+
3679
+ }, {
3680
+ key: "exportToPNG",
3681
+ value: function exportToPNG() {
3682
+ var fileName = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'jmgraph-export';
3683
+ var format = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'image/png';
3684
+ var quality = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0.9;
3685
+
3686
+ try {
3687
+ // 确保画布已渲染
3688
+ this.redraw();
3689
+ var dataURL = this.canvas.toDataURL(format, quality);
3690
+ this.downloadFile(dataURL, fileName, 'png');
3691
+ } catch (error) {
3692
+ console.error('jmGraph: exportToPNG - 导出失败', error);
3693
+ }
3694
+ }
3695
+ /**
3696
+ * 导出为JPEG图片
3697
+ *
3698
+ * @method exportToJPEG
3699
+ * @param {string} [fileName='jmgraph-export'] 文件名(不含扩展名)
3700
+ * @param {number} [quality=0.9] 图片质量(0-1之间)
3701
+ */
3702
+
3703
+ }, {
3704
+ key: "exportToJPEG",
3705
+ value: function exportToJPEG() {
3706
+ var fileName = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'jmgraph-export';
3707
+ var quality = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0.9;
3708
+ this.exportToPNG(fileName, 'image/jpeg', quality);
3709
+ }
3710
+ /**
3711
+ * 导出为SVG文件
3712
+ * 将当前画布内容转换为SVG格式
3713
+ * 注意:只有实现了toSVG方法的形状才能被导出
3714
+ *
3715
+ * @method exportToSVG
3716
+ * @param {string} [fileName='jmgraph-export'] 文件名(不含扩展名)
3717
+ */
3718
+
3719
+ }, {
3720
+ key: "exportToSVG",
3721
+ value: function exportToSVG() {
3722
+ var fileName = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'jmgraph-export';
3723
+
3724
+ try {
3725
+ var svg = this.toSVG();
3726
+ var blob = new Blob([svg], {
3727
+ type: 'image/svg+xml;charset=utf-8'
3728
+ });
3729
+ var url = URL.createObjectURL(blob);
3730
+ this.downloadFile(url, fileName, 'svg'); // 释放URL对象,避免内存泄漏
3731
+
3732
+ setTimeout(function () {
3733
+ return URL.revokeObjectURL(url);
3734
+ }, 100);
3735
+ } catch (error) {
3736
+ console.error('jmGraph: exportToSVG - 导出失败', error);
3737
+ }
3738
+ }
3739
+ /**
3740
+ * 遍历所有形状,生成SVG标记
3741
+ *
3742
+ * @method toSVG
3743
+ * @return {string} SVG字符串
3744
+ */
3745
+
3746
+ }, {
3747
+ key: "toSVG",
3748
+ value: function toSVG() {
3749
+ // SVG头部,包含命名空间和画布尺寸
3750
+ var svg = "<svg width=\"".concat(this.width, "\" height=\"").concat(this.height, "\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 ").concat(this.width, " ").concat(this.height, "\">"); // 添加背景色(如果有)
3751
+
3752
+ if (this.style && this.style.fill) {
3753
+ svg += "<rect width=\"100%\" height=\"100%\" fill=\"".concat(this.style.fill, "\"/>");
3754
+ } // 遍历所有直接添加的形状
3755
+
3756
+
3757
+ this.children.each(function (i, shape) {
3758
+ if (shape.toSVG) {
3759
+ svg += shape.toSVG();
3760
+ }
3761
+ });
3762
+ svg += '</svg>';
3763
+ return svg;
3764
+ }
3765
+ /**
3766
+ * 下载文件
3767
+ * 创建临时链接元素触发浏览器下载
3768
+ *
3769
+ * @method downloadFile
3770
+ * @private
3771
+ * @param {string} url 文件URL或Data URL
3772
+ * @param {string} fileName 文件名(不含扩展名)
3773
+ * @param {string} extension 文件扩展名
3774
+ */
3775
+
3776
+ }, {
3777
+ key: "downloadFile",
3778
+ value: function downloadFile(url, fileName, extension) {
3779
+ // 创建临时链接元素
3780
+ var link = document.createElement('a');
3781
+ link.href = url;
3782
+ link.download = "".concat(fileName, ".").concat(extension); // 添加到DOM并触发点击
3783
+
3784
+ document.body.appendChild(link);
3785
+ link.click(); // 清理DOM
3786
+
3787
+ document.body.removeChild(link);
3788
+ }
3144
3789
  /**
3145
3790
  * 自动刷新画版
3146
3791
  * @param {function} callback 执行回调
@@ -3196,7 +3841,7 @@ var jmGraph = /*#__PURE__*/function (_jmControl) {
3196
3841
 
3197
3842
  exports.jmGraph = exports["default"] = jmGraph;
3198
3843
 
3199
- },{"./jmControl.js":2,"./jmEvents.js":3,"./jmGradient.js":4,"./jmList.js":6,"./jmPath.js":8,"./jmProperty.js":9,"./jmShadow.js":10,"./jmUtils.js":11}],6:[function(require,module,exports){
3844
+ },{"./jmControl.js":2,"./jmEvents.js":3,"./jmFilter.js":4,"./jmGradient.js":5,"./jmList.js":7,"./jmPath.js":9,"./jmProperty.js":10,"./jmShadow.js":11,"./jmUtils.js":12}],7:[function(require,module,exports){
3200
3845
  "use strict";
3201
3846
 
3202
3847
  Object.defineProperty(exports, "__esModule", {
@@ -3360,7 +4005,7 @@ var jmList = /*#__PURE__*/function (_Array) {
3360
4005
 
3361
4006
  exports.jmList = exports["default"] = jmList;
3362
4007
 
3363
- },{}],7:[function(require,module,exports){
4008
+ },{}],8:[function(require,module,exports){
3364
4009
  "use strict";
3365
4010
 
3366
4011
  Object.defineProperty(exports, "__esModule", {
@@ -3475,7 +4120,7 @@ var jmObject = /*#__PURE__*/function () {
3475
4120
 
3476
4121
  exports.jmObject = exports["default"] = jmObject;
3477
4122
 
3478
- },{"./jmList.js":6}],8:[function(require,module,exports){
4123
+ },{"./jmList.js":7}],9:[function(require,module,exports){
3479
4124
  "use strict";
3480
4125
 
3481
4126
  function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
@@ -3549,6 +4194,63 @@ var jmPath = /*#__PURE__*/function (_jmControl) {
3549
4194
  this.needUpdate = true;
3550
4195
  return this.property('points', v);
3551
4196
  }
4197
+ /**
4198
+ * 转换为SVG路径
4199
+ *
4200
+ * @method toSVG
4201
+ * @return {string} SVG路径字符串
4202
+ */
4203
+
4204
+ }, {
4205
+ key: "toSVG",
4206
+ value: function toSVG() {
4207
+ if (!this.points || this.points.length === 0) return '';
4208
+ var pathData = '';
4209
+ var points = this.points; // 移动到起点
4210
+
4211
+ pathData += "M ".concat(points[0].x, " ").concat(points[0].y); // 绘制路径
4212
+
4213
+ for (var i = 1; i < points.length; i++) {
4214
+ var p = points[i];
4215
+
4216
+ if (p.m) {
4217
+ // 移动到新位置
4218
+ pathData += " M ".concat(p.x, " ").concat(p.y);
4219
+ } else {
4220
+ // 直线到
4221
+ pathData += " L ".concat(p.x, " ").concat(p.y);
4222
+ }
4223
+ } // 如果是封闭路径
4224
+
4225
+
4226
+ if (this.style && this.style.close) {
4227
+ pathData += ' Z';
4228
+ } // 构建SVG元素
4229
+
4230
+
4231
+ var svg = '<path d="' + pathData + '"'; // 添加样式
4232
+
4233
+ if (this.style) {
4234
+ if (this.style.fill) {
4235
+ svg += ' fill="' + this.style.fill + '"';
4236
+ }
4237
+
4238
+ if (this.style.stroke) {
4239
+ svg += ' stroke="' + this.style.stroke + '"';
4240
+ }
4241
+
4242
+ if (this.style.lineWidth) {
4243
+ svg += ' stroke-width="' + this.style.lineWidth + '"';
4244
+ }
4245
+
4246
+ if (this.style.opacity) {
4247
+ svg += ' opacity="' + this.style.opacity + '"';
4248
+ }
4249
+ }
4250
+
4251
+ svg += '/>';
4252
+ return svg;
4253
+ }
3552
4254
  }]);
3553
4255
 
3554
4256
  return jmPath;
@@ -3556,7 +4258,7 @@ var jmPath = /*#__PURE__*/function (_jmControl) {
3556
4258
 
3557
4259
  exports.jmPath = exports["default"] = jmPath;
3558
4260
 
3559
- },{"./jmControl.js":2}],9:[function(require,module,exports){
4261
+ },{"./jmControl.js":2}],10:[function(require,module,exports){
3560
4262
  "use strict";
3561
4263
 
3562
4264
  function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
@@ -3682,7 +4384,7 @@ var jmProperty = /*#__PURE__*/function (_jmObject) {
3682
4384
 
3683
4385
  exports.jmProperty = exports["default"] = jmProperty;
3684
4386
 
3685
- },{"./jmObject.js":7,"./jmUtils.js":11}],10:[function(require,module,exports){
4387
+ },{"./jmObject.js":8,"./jmUtils.js":12}],11:[function(require,module,exports){
3686
4388
  "use strict";
3687
4389
 
3688
4390
  Object.defineProperty(exports, "__esModule", {
@@ -3775,7 +4477,7 @@ var jmShadow = /*#__PURE__*/function () {
3775
4477
 
3776
4478
  exports.jmShadow = exports["default"] = jmShadow;
3777
4479
 
3778
- },{"./jmUtils.js":11}],11:[function(require,module,exports){
4480
+ },{"./jmUtils.js":12}],12:[function(require,module,exports){
3779
4481
  "use strict";
3780
4482
 
3781
4483
  Object.defineProperty(exports, "__esModule", {
@@ -3785,6 +4487,12 @@ exports.jmUtils = exports["default"] = void 0;
3785
4487
 
3786
4488
  var _jmList = require("./jmList.js");
3787
4489
 
4490
+ function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; }
4491
+
4492
+ function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
4493
+
4494
+ function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
4495
+
3788
4496
  function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
3789
4497
 
3790
4498
  function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
@@ -3968,68 +4676,89 @@ var jmUtils = /*#__PURE__*/function () {
3968
4676
  var deep = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
3969
4677
  var copyHandler = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null;
3970
4678
  var deepIndex = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 0;
4679
+ var cloned = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : null;
3971
4680
 
3972
4681
  // 如果有指定回调,则用回调处理,否则走后面的复制逻辑
3973
4682
  if (typeof copyHandler === 'function') {
3974
4683
  var obj = copyHandler(source, deep, deepIndex);
3975
4684
  if (obj) return obj;
3976
- }
4685
+ } // 首次调用时初始化克隆映射表(用于处理循环引用)
3977
4686
 
3978
- deepIndex++; // 每执行一次,需要判断最大拷贝深度
4687
+
4688
+ if (!cloned) cloned = new WeakMap();
3979
4689
 
3980
4690
  if (typeof target === 'boolean') {
3981
4691
  deep = target;
3982
4692
  target = undefined;
3983
- } // 超过100拷贝深度,直接返回
4693
+ } // 非对象直接返回
3984
4694
 
3985
4695
 
3986
- if (deepIndex > 100) {
3987
- return target;
3988
- }
4696
+ if (!source || _typeof(source) !== 'object') {
4697
+ return typeof target !== 'undefined' ? target : source;
4698
+ } // 如果source已经被克隆过,直接返回之前的克隆对象,打破循环引用
3989
4699
 
3990
- if (source && _typeof(source) === 'object') {
3991
- target = target || {}; //如果为当前泛型,则直接new
3992
4700
 
4701
+ if (cloned.has(source)) return cloned.get(source); // 数组处理
4702
+
4703
+ if (Array.isArray(source)) {
4704
+ //如果为当前泛型,则直接new
3993
4705
  if (this.isType(source, _jmList.jmList)) {
3994
4706
  return new _jmList.jmList(source);
3995
- } else if (Array.isArray(source)) {
3996
- //如果是深度复,则拷贝每个对象
3997
- if (deep) {
3998
- var dest = [];
4707
+ }
3999
4708
 
4000
- for (var i = 0; i < source.length; i++) {
4001
- dest.push(this.clone(source[i], target[i], deep, copyHandler, deepIndex));
4002
- }
4709
+ if (deep) {
4710
+ var dest = [];
4711
+ cloned.set(source, dest);
4003
4712
 
4004
- return dest;
4713
+ for (var i = 0; i < source.length; i++) {
4714
+ dest.push(this.clone(source[i], undefined, deep, copyHandler, deepIndex + 1, cloned));
4005
4715
  }
4006
4716
 
4007
- return source.slice(0);
4717
+ return dest;
4008
4718
  }
4009
4719
 
4010
- if (source.__proto__) target.__proto__ = source.__proto__;
4720
+ return source.slice(0);
4721
+ } // 不复制页面元素和class对象(如jmControl实例等复杂对象保持引用)
4722
+
4011
4723
 
4012
- for (var k in source) {
4724
+ if (source.tagName || source.getContext || source.emit) {
4725
+ return source;
4726
+ } // 普通对象处理
4727
+
4728
+
4729
+ target = target || {};
4730
+ cloned.set(source, target); // 保持原型链一致
4731
+
4732
+ if (source.__proto__) target.__proto__ = source.__proto__; // 遍历自身可枚举属性(字符串键 + Symbol键),避免触发原型链上宿主对象的getter
4733
+
4734
+ var keys = Object.keys(source).concat(Object.getOwnPropertySymbols(source));
4735
+
4736
+ var _iterator = _createForOfIteratorHelper(keys),
4737
+ _step;
4738
+
4739
+ try {
4740
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
4741
+ var k = _step.value;
4013
4742
  if (k === 'constructor') continue;
4014
4743
  var v = source[k]; // 不复制页面元素和class对象
4015
4744
 
4016
- if (v && (v.tagName || v.getContext)) {
4745
+ if (v && (v.tagName || v.getContext || v.emit)) {
4017
4746
  target[k] = v;
4018
4747
  continue;
4019
4748
  } // 如果不是对象和空,则采用target的属性
4020
4749
 
4021
4750
 
4022
4751
  if (_typeof(target[k]) === 'object' || typeof target[k] === 'undefined') {
4023
- target[k] = this.clone(v, target[k], deep, copyHandler, deepIndex);
4752
+ target[k] = this.clone(v, target[k], deep, copyHandler, deepIndex + 1, cloned);
4024
4753
  }
4025
4754
  }
4026
-
4027
- return target;
4028
- } else if (typeof target != 'undefined') {
4029
- return target;
4755
+ } catch (err) {
4756
+ _iterator.e(err);
4757
+ } finally {
4758
+ _iterator.f();
4030
4759
  }
4031
4760
 
4032
- return source;
4761
+ return target;
4033
4762
  }
4034
4763
  /**
4035
4764
  * 绑定事件到html对象
@@ -4777,7 +5506,7 @@ var jmUtils = /*#__PURE__*/function () {
4777
5506
 
4778
5507
  exports.jmUtils = exports["default"] = jmUtils;
4779
5508
 
4780
- },{"./jmList.js":6}],12:[function(require,module,exports){
5509
+ },{"./jmList.js":7}],13:[function(require,module,exports){
4781
5510
  'use strict';
4782
5511
 
4783
5512
  Object.defineProperty(exports, "__esModule", {
@@ -5440,7 +6169,7 @@ earcut.flatten = function (data) {
5440
6169
  return result;
5441
6170
  };
5442
6171
 
5443
- },{}],13:[function(require,module,exports){
6172
+ },{}],14:[function(require,module,exports){
5444
6173
  "use strict";
5445
6174
 
5446
6175
  Object.defineProperty(exports, "__esModule", {
@@ -5710,7 +6439,6 @@ var WeblBase = /*#__PURE__*/function () {
5710
6439
  }, {
5711
6440
  key: "createProgram",
5712
6441
  value: function createProgram(vertexSrc, fragmentSrc) {
5713
- this.context.lineWidth(1);
5714
6442
  return (0, _program.createProgram)(this.context, vertexSrc, fragmentSrc);
5715
6443
  } // 指定使用某个程序
5716
6444
 
@@ -5844,8 +6572,10 @@ var WeblBase = /*#__PURE__*/function () {
5844
6572
  }, {
5845
6573
  key: "earCutPointsToTriangles",
5846
6574
  value: function earCutPointsToTriangles(points) {
5847
- this.earCutCache = this.earCutCache || (this.earCutCache = {});
5848
- var key = JSON.stringify(points);
6575
+ this.earCutCache = this.earCutCache || (this.earCutCache = {}); // 快速缓存 key:用长度和首尾点坐标
6576
+
6577
+ var len = points.length;
6578
+ var key = len + '_' + points[0].x + '_' + points[0].y + '_' + points[len - 1].x + '_' + points[len - 1].y;
5849
6579
  if (this.earCutCache[key]) return this.earCutCache[key];
5850
6580
  var ps = this.earCutPoints(points); // 切割得到3角色顶点索引,
5851
6581
 
@@ -5963,34 +6693,13 @@ var WeblBase = /*#__PURE__*/function () {
5963
6693
  }
5964
6694
 
5965
6695
  this.textureContext.clearRect(0, 0, canvas.width, canvas.height);
5966
- this.textureContext.fillStyle = fillStyle;
5967
- this.textureContext.beginPath();
6696
+ this.textureContext.fillStyle = fillStyle; // 规则图形用 fillRect,比 beginPath/lineTo/fill 快
5968
6697
 
5969
6698
  if (!points || !points.length) {
5970
- points = [];
5971
- points.push({
5972
- x: bounds.left,
5973
- y: bounds.top
5974
- });
5975
- points.push({
5976
- x: bounds.left + bounds.width,
5977
- y: bounds.top
5978
- });
5979
- points.push({
5980
- x: bounds.left + bounds.width,
5981
- y: bounds.top + bounds.height
5982
- });
5983
- points.push({
5984
- x: bounds.left,
5985
- y: bounds.top + bounds.height
5986
- });
5987
- points.push({
5988
- x: bounds.left,
5989
- y: bounds.top
5990
- });
5991
- }
6699
+ this.textureContext.fillRect(0, 0, bounds.width, bounds.height);
6700
+ } else {
6701
+ this.textureContext.beginPath();
5992
6702
 
5993
- if (points && points.length) {
5994
6703
  var _iterator = _createForOfIteratorHelper(points),
5995
6704
  _step;
5996
6705
 
@@ -6010,16 +6719,11 @@ var WeblBase = /*#__PURE__*/function () {
6010
6719
  } finally {
6011
6720
  _iterator.f();
6012
6721
  }
6013
- } else {
6014
- this.textureContext.moveTo(0, 0);
6015
- this.textureContext.lineTo(bounds.width, 0);
6016
- this.textureContext.lineTo(bounds.width, bounds.height);
6017
- this.textureContext.lineTo(0, bounds.height);
6018
- this.textureContext.lineTo(0, 0);
6722
+
6723
+ this.textureContext.closePath();
6724
+ this.textureContext.fill();
6019
6725
  }
6020
6726
 
6021
- this.textureContext.closePath();
6022
- this.textureContext.fill();
6023
6727
  var data = this.textureContext.getImageData(0, 0, canvas.width, canvas.height);
6024
6728
  return {
6025
6729
  data: data,
@@ -6034,7 +6738,7 @@ var WeblBase = /*#__PURE__*/function () {
6034
6738
  var _default = WeblBase;
6035
6739
  exports["default"] = _default;
6036
6740
 
6037
- },{"../earcut.js":12,"./core/buffer.js":14,"./core/program.js":17,"./core/texture.js":19,"./gradient.js":20}],14:[function(require,module,exports){
6741
+ },{"../earcut.js":13,"./core/buffer.js":15,"./core/program.js":18,"./core/texture.js":20,"./gradient.js":21}],15:[function(require,module,exports){
6038
6742
  "use strict";
6039
6743
 
6040
6744
  Object.defineProperty(exports, "__esModule", {
@@ -6095,7 +6799,7 @@ function deleteBuffer(gl, buffer) {
6095
6799
  gl.deleteBuffer(buffer.buffer || buffer);
6096
6800
  }
6097
6801
 
6098
- },{}],15:[function(require,module,exports){
6802
+ },{}],16:[function(require,module,exports){
6099
6803
  "use strict";
6100
6804
 
6101
6805
  Object.defineProperty(exports, "__esModule", {
@@ -6133,7 +6837,7 @@ var mapSize = function mapSize(type) {
6133
6837
 
6134
6838
  exports.mapSize = mapSize;
6135
6839
 
6136
- },{}],16:[function(require,module,exports){
6840
+ },{}],17:[function(require,module,exports){
6137
6841
  "use strict";
6138
6842
 
6139
6843
  Object.defineProperty(exports, "__esModule", {
@@ -6176,7 +6880,7 @@ var mapType = function mapType(gl, type) {
6176
6880
 
6177
6881
  exports.mapType = mapType;
6178
6882
 
6179
- },{}],17:[function(require,module,exports){
6883
+ },{}],18:[function(require,module,exports){
6180
6884
  "use strict";
6181
6885
 
6182
6886
  Object.defineProperty(exports, "__esModule", {
@@ -6312,7 +7016,7 @@ function getUniformLocation(gl, program, name) {
6312
7016
  return gl.getUniformLocation(program, name);
6313
7017
  }
6314
7018
 
6315
- },{"./mapSize.js":15,"./mapType.js":16,"./shader.js":18}],18:[function(require,module,exports){
7019
+ },{"./mapSize.js":16,"./mapType.js":17,"./shader.js":19}],19:[function(require,module,exports){
6316
7020
  "use strict";
6317
7021
 
6318
7022
  Object.defineProperty(exports, "__esModule", {
@@ -6333,7 +7037,7 @@ function createShader(gl, type, src) {
6333
7037
  return shader;
6334
7038
  }
6335
7039
 
6336
- },{}],19:[function(require,module,exports){
7040
+ },{}],20:[function(require,module,exports){
6337
7041
  "use strict";
6338
7042
 
6339
7043
  Object.defineProperty(exports, "__esModule", {
@@ -6399,7 +7103,7 @@ function deleteTexture(gl, texture) {
6399
7103
  return gl.deleteTexture(texture);
6400
7104
  }
6401
7105
 
6402
- },{}],20:[function(require,module,exports){
7106
+ },{}],21:[function(require,module,exports){
6403
7107
  "use strict";
6404
7108
 
6405
7109
  Object.defineProperty(exports, "__esModule", {
@@ -6472,9 +7176,13 @@ var WebglGradient = /*#__PURE__*/function () {
6472
7176
  key: "toImageData",
6473
7177
  value: function toImageData(control, bounds) {
6474
7178
  var points = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;
7179
+ // 缓存基于渐变参数(不含 bounds,因为同一个渐变只是位置不同时纹理相同)
7180
+ var gradientKey = this.toString();
7181
+
7182
+ if (this.__cachedData && this.__cacheKey === gradientKey && this.__cachedData.data && this.__cachedData.data.width === Math.ceil(bounds.width) && this.__cachedData.data.data && this.__cachedData.data.data.height === Math.ceil(bounds.height)) {
7183
+ return this.__cachedData;
7184
+ }
6475
7185
 
6476
- //const key = this.key || this.toString();
6477
- //if(WebglGradientTextureCache[key]) return WebglGradientTextureCache[key];
6478
7186
  if (!control.textureContext) {
6479
7187
  return null;
6480
7188
  }
@@ -6491,9 +7199,17 @@ var WebglGradient = /*#__PURE__*/function () {
6491
7199
  var c = control.graph.utils.toColor(s.color);
6492
7200
  gradient && gradient.addColorStop(s.offset, c);
6493
7201
  });
6494
- var data = control.toFillTexture(gradient, bounds, points); //WebglGradientTextureCache[key] = data;
6495
-
7202
+ var data = control.toFillTexture(gradient, bounds, points);
7203
+ this.__cachedData = data;
7204
+ this.__cacheKey = gradientKey;
6496
7205
  return data;
7206
+ } // 当渐变参数变化时使缓存失效
7207
+
7208
+ }, {
7209
+ key: "invalidateCache",
7210
+ value: function invalidateCache() {
7211
+ this.__cachedData = null;
7212
+ this.__cacheKey = null;
6497
7213
  } // 根据绘制图形的坐标计算出对应点的颜色
6498
7214
 
6499
7215
  /*
@@ -6595,7 +7311,7 @@ var WebglGradient = /*#__PURE__*/function () {
6595
7311
  var _default = WebglGradient;
6596
7312
  exports["default"] = _default;
6597
7313
 
6598
- },{}],21:[function(require,module,exports){
7314
+ },{}],22:[function(require,module,exports){
6599
7315
  "use strict";
6600
7316
 
6601
7317
  function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
@@ -6617,7 +7333,15 @@ function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && iter[Symb
6617
7333
 
6618
7334
  function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); }
6619
7335
 
6620
- function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; }
7336
+ function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
7337
+
7338
+ function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
7339
+
7340
+ function _iterableToArrayLimit(arr, i) { var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"]; if (_i == null) return; var _arr = []; var _n = true; var _d = false; var _s, _e; try { for (_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; }
7341
+
7342
+ function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
7343
+
7344
+ function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e2) { throw _e2; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e3) { didErr = true; err = _e3; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; }
6621
7345
 
6622
7346
  function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
6623
7347
 
@@ -6663,12 +7387,66 @@ var WebglPath = /*#__PURE__*/function (_WebglBase) {
6663
7387
  _this.isRegular = option.isRegular || false;
6664
7388
  _this.needCut = option.needCut || false;
6665
7389
  _this.control = option.control;
6666
- _this.points = [];
7390
+ _this.points = []; // 缓存 buffer 和纹理,避免每帧创建/销毁
7391
+
7392
+ _this.__cachedBuffers = [];
7393
+ _this.__cachedTexture = null;
7394
+ _this.__cachedTextureKey = null;
6667
7395
  return _this;
6668
- } // 应用变换到点
7396
+ } // 释放缓存的 WebGL 资源
6669
7397
 
6670
7398
 
6671
7399
  _createClass(WebglPath, [{
7400
+ key: "dispose",
7401
+ value: function dispose() {
7402
+ var _iterator = _createForOfIteratorHelper(this.__cachedBuffers),
7403
+ _step;
7404
+
7405
+ try {
7406
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
7407
+ var buf = _step.value;
7408
+ this.deleteBuffer(buf);
7409
+ }
7410
+ } catch (err) {
7411
+ _iterator.e(err);
7412
+ } finally {
7413
+ _iterator.f();
7414
+ }
7415
+
7416
+ this.__cachedBuffers = [];
7417
+
7418
+ if (this.__cachedTexture) {
7419
+ this.deleteTexture(this.__cachedTexture);
7420
+ this.__cachedTexture = null;
7421
+ this.__cachedTextureKey = null;
7422
+ }
7423
+ } // 获取或创建 buffer,优先复用缓存
7424
+
7425
+ }, {
7426
+ key: "getOrCreateBuffer",
7427
+ value: function getOrCreateBuffer(data, attr) {
7428
+ var buffer = this.__cachedBuffers.find(function (b) {
7429
+ return b.attr === attr;
7430
+ });
7431
+
7432
+ if (buffer) {
7433
+ var gl = this.context;
7434
+ var float32 = new Float32Array(data);
7435
+ gl.bindBuffer(gl.ARRAY_BUFFER, buffer.buffer);
7436
+ gl.bufferData(gl.ARRAY_BUFFER, float32, gl.DYNAMIC_DRAW);
7437
+ buffer.data = data;
7438
+ return buffer;
7439
+ }
7440
+
7441
+ buffer = this.createFloat32Buffer(data);
7442
+ buffer.attr = attr;
7443
+
7444
+ this.__cachedBuffers.push(buffer);
7445
+
7446
+ return buffer;
7447
+ } // 应用变换到点
7448
+
7449
+ }, {
6672
7450
  key: "applyTransform",
6673
7451
  value: function applyTransform(point) {
6674
7452
  return _get(_getPrototypeOf(WebglPath.prototype), "applyTransform", this).call(this, point);
@@ -6694,20 +7472,20 @@ var WebglPath = /*#__PURE__*/function (_WebglBase) {
6694
7472
 
6695
7473
  var colorData = [];
6696
7474
 
6697
- var _iterator = _createForOfIteratorHelper(color),
6698
- _step;
7475
+ var _iterator2 = _createForOfIteratorHelper(color),
7476
+ _step2;
6699
7477
 
6700
7478
  try {
6701
- for (_iterator.s(); !(_step = _iterator.n()).done;) {
6702
- var c = _step.value;
7479
+ for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
7480
+ var c = _step2.value;
6703
7481
  c = this.convertColor(c);
6704
7482
  if (typeof c.a === 'undefined') c.a = 1;
6705
7483
  colorData.push(c.r, c.g, c.b, c.a * this.style.globalAlpha);
6706
7484
  }
6707
7485
  } catch (err) {
6708
- _iterator.e(err);
7486
+ _iterator2.e(err);
6709
7487
  } finally {
6710
- _iterator.f();
7488
+ _iterator2.f();
6711
7489
  }
6712
7490
 
6713
7491
  var colorBuffer = this.createFloat32Buffer(colorData);
@@ -6733,7 +7511,7 @@ var WebglPath = /*#__PURE__*/function (_WebglBase) {
6733
7511
  key: "endDraw",
6734
7512
  value: function endDraw() {
6735
7513
  if (this.points) delete this.points;
6736
- if (this.pathPoints) delete this.pathPoints;
7514
+ if (this.pathPoints) delete this.pathPoints; // 缓存的纹理保留到下次绘制(渐变可能不变)
6737
7515
  } // 图形封闭
6738
7516
 
6739
7517
  }, {
@@ -6744,7 +7522,7 @@ var WebglPath = /*#__PURE__*/function (_WebglBase) {
6744
7522
  var end = this.points[this.points.length - 1];
6745
7523
  if (start != end && !(start.x === end.x && start.y === end.y)) this.points.push(start);
6746
7524
  }
6747
- } // 绘制点数组
7525
+ } // 绘制点数组(使用 DYNAMIC_DRAW 复用 buffer,避免每帧 create/delete)
6748
7526
 
6749
7527
  }, {
6750
7528
  key: "writePoints",
@@ -6752,25 +7530,64 @@ var WebglPath = /*#__PURE__*/function (_WebglBase) {
6752
7530
  var attr = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.program.attrs.a_position;
6753
7531
  var fixedPoints = [];
6754
7532
 
6755
- var _iterator2 = _createForOfIteratorHelper(points),
6756
- _step2;
7533
+ var _this$transformMatrix = _slicedToArray(this.transformMatrix, 6),
7534
+ a = _this$transformMatrix[0],
7535
+ b = _this$transformMatrix[1],
7536
+ c = _this$transformMatrix[2],
7537
+ d = _this$transformMatrix[3],
7538
+ tx = _this$transformMatrix[4],
7539
+ ty = _this$transformMatrix[5];
6757
7540
 
6758
- try {
6759
- for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
6760
- var p = _step2.value;
6761
- // 应用变换矩阵
6762
- var transformedPoint = this.applyTransform(p);
6763
- fixedPoints.push(transformedPoint.x + this.parentAbsoluteBounds.left, transformedPoint.y + this.parentAbsoluteBounds.top);
7541
+ var isIdentity = a === 1 && b === 0 && c === 0 && d === 1 && tx === 0 && ty === 0;
7542
+ var offsetLeft = this.parentAbsoluteBounds.left;
7543
+ var offsetTop = this.parentAbsoluteBounds.top;
7544
+
7545
+ if (isIdentity) {
7546
+ // 单位矩阵时直接加偏移,避免逐点调用 applyTransform
7547
+ for (var i = 0; i < points.length; i++) {
7548
+ fixedPoints.push(points[i].x + offsetLeft, points[i].y + offsetTop);
7549
+ }
7550
+ } else {
7551
+ var _iterator3 = _createForOfIteratorHelper(points),
7552
+ _step3;
7553
+
7554
+ try {
7555
+ for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
7556
+ var p = _step3.value;
7557
+ var transformedPoint = this.applyTransform(p);
7558
+ fixedPoints.push(transformedPoint.x + offsetLeft, transformedPoint.y + offsetTop);
7559
+ }
7560
+ } catch (err) {
7561
+ _iterator3.e(err);
7562
+ } finally {
7563
+ _iterator3.f();
7564
+ }
7565
+ }
7566
+
7567
+ var float32 = new Float32Array(fixedPoints);
7568
+ var gl = this.context; // 复用已有 buffer 或创建新的
7569
+
7570
+ if (this.__cachedBuffers.length > 0) {
7571
+ // 找一个同 attr 的 buffer 复用
7572
+ var buffer = this.__cachedBuffers.find(function (b) {
7573
+ return b.attr === attr;
7574
+ });
7575
+
7576
+ if (buffer) {
7577
+ gl.bindBuffer(gl.ARRAY_BUFFER, buffer.buffer);
7578
+ gl.bufferData(gl.ARRAY_BUFFER, float32, gl.DYNAMIC_DRAW);
7579
+ buffer.data = fixedPoints;
7580
+ this.writeVertexAttrib(buffer, attr, 2, 0, 0);
7581
+ return buffer;
6764
7582
  }
6765
- } catch (err) {
6766
- _iterator2.e(err);
6767
- } finally {
6768
- _iterator2.f();
6769
7583
  }
6770
7584
 
6771
- var vertexBuffer = this.createFloat32Buffer(fixedPoints);
7585
+ var vertexBuffer = this.createFloat32Buffer(float32, gl.ARRAY_BUFFER, gl.DYNAMIC_DRAW);
6772
7586
  this.writeVertexAttrib(vertexBuffer, attr, 2, 0, 0);
6773
7587
  vertexBuffer.attr = attr;
7588
+
7589
+ this.__cachedBuffers.push(vertexBuffer);
7590
+
6774
7591
  return vertexBuffer;
6775
7592
  } // 连接二个点
6776
7593
 
@@ -7083,27 +7900,29 @@ var WebglPath = /*#__PURE__*/function (_WebglBase) {
7083
7900
  }, {
7084
7901
  key: "getTriangles",
7085
7902
  value: function getTriangles(points) {
7086
- this.trianglesCache = this.trianglesCache || (this.trianglesCache = {});
7087
- var key = JSON.stringify(points);
7903
+ this.trianglesCache = this.trianglesCache || (this.trianglesCache = {}); // 快速缓存 key:用长度和首尾点坐标(比 JSON.stringify 快几个数量级)
7904
+
7905
+ var len = points.length;
7906
+ var key = len + '_' + points[0].x + '_' + points[0].y + '_' + points[len - 1].x + '_' + points[len - 1].y;
7088
7907
  if (this.trianglesCache[key]) return this.trianglesCache[key];
7089
7908
  var res = [];
7090
7909
  var polygons = this.getPolygon(points);
7091
7910
 
7092
7911
  if (polygons.length) {
7093
- var _iterator3 = _createForOfIteratorHelper(polygons),
7094
- _step3;
7912
+ var _iterator4 = _createForOfIteratorHelper(polygons),
7913
+ _step4;
7095
7914
 
7096
7915
  try {
7097
- for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
7098
- var polygon = _step3.value;
7916
+ for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
7917
+ var polygon = _step4.value;
7099
7918
  // 需要分割三角形,不然填充会有问题
7100
7919
  var triangles = this.earCutPointsToTriangles(polygon);
7101
7920
  res.push.apply(res, _toConsumableArray(triangles));
7102
7921
  }
7103
7922
  } catch (err) {
7104
- _iterator3.e(err);
7923
+ _iterator4.e(err);
7105
7924
  } finally {
7106
- _iterator3.f();
7925
+ _iterator4.f();
7107
7926
  }
7108
7927
  }
7109
7928
 
@@ -7140,12 +7959,10 @@ var WebglPath = /*#__PURE__*/function (_WebglBase) {
7140
7959
  var regular = lineWidth <= 1.2;
7141
7960
  points = regular ? points : this.pathToPoints(points);
7142
7961
  var buffer = this.writePoints(points);
7143
- this.context.drawArrays(regular ? this.context.LINE_LOOP : this.context.POINTS, 0, points.length);
7144
- this.deleteBuffer(buffer);
7962
+ this.context.drawArrays(regular ? this.context.LINE_LOOP : this.context.POINTS, 0, points.length); // buffer 由 endDraw 统一清理
7145
7963
  }
7146
7964
 
7147
- colorBuffer && this.deleteBuffer(colorBuffer);
7148
- colorBuffer && this.disableVertexAttribArray(colorBuffer.attr);
7965
+ colorBuffer && this.disableVertexAttribArray(colorBuffer && colorBuffer.attr);
7149
7966
  } // 填充图形
7150
7967
 
7151
7968
  }, {
@@ -7185,8 +8002,7 @@ var WebglPath = /*#__PURE__*/function (_WebglBase) {
7185
8002
  this.context.uniform1i(this.program.uniforms.a_type.location, type);
7186
8003
  var colorBuffer = this.setFragColor(color);
7187
8004
  this.fillPolygons(points);
7188
- colorBuffer && this.deleteBuffer(colorBuffer);
7189
- colorBuffer && this.disableVertexAttribArray(colorBuffer.attr);
8005
+ colorBuffer && this.disableVertexAttribArray(colorBuffer && colorBuffer.attr);
7190
8006
  } // 区域填充图片
7191
8007
  // points绘制的图形顶点
7192
8008
  // 图片整体绘制区域
@@ -7194,16 +8010,39 @@ var WebglPath = /*#__PURE__*/function (_WebglBase) {
7194
8010
  }, {
7195
8011
  key: "fillImage",
7196
8012
  value: function fillImage(img, points, bounds) {
7197
- if (!img) return; // 设置纹理
8013
+ if (!img) return; // 对于 ImageData,生成缓存 key(基于渐变参数或 bounds),复用纹理
8014
+
8015
+ var texture = null;
8016
+
8017
+ if (img instanceof ImageData) {
8018
+ var key = "".concat(img.width, "_").concat(img.height, "_").concat(bounds.width, "_").concat(bounds.height, "_").concat(bounds.left, "_").concat(bounds.top);
8019
+
8020
+ if (this.__cachedTexture && this.__cachedTextureKey === key) {
8021
+ texture = this.__cachedTexture;
8022
+ } else {
8023
+ texture = this.createDataTexture(img); // 释放旧纹理
8024
+
8025
+ if (this.__cachedTexture) {
8026
+ this.deleteTexture(this.__cachedTexture);
8027
+ }
8028
+
8029
+ this.__cachedTexture = texture;
8030
+ this.__cachedTextureKey = key;
8031
+ }
8032
+ } else {
8033
+ texture = this.createImgTexture(img);
8034
+ }
7198
8035
 
7199
- var texture = img instanceof ImageData ? this.createDataTexture(img) : this.createImgTexture(img);
7200
8036
  this.context.uniform1i(this.program.uniforms.u_sample.location, 0); // 纹理单元传递给着色器
7201
8037
  // 指定纹理区域尺寸
7202
8038
 
7203
8039
  this.context.uniform4f(this.program.uniforms.v_texture_bounds.location, bounds.left + this.parentAbsoluteBounds.left, bounds.top + this.parentAbsoluteBounds.top, bounds.width, bounds.height); // 纹理单元传递给着色器
7204
8040
 
7205
- this.fillTexture(points);
7206
- this.deleteTexture(texture);
8041
+ this.fillTexture(points); // 仅对非缓存纹理(非 ImageData)立即删除
8042
+
8043
+ if (!(img instanceof ImageData)) {
8044
+ this.deleteTexture(texture);
8045
+ }
7207
8046
  }
7208
8047
  }, {
7209
8048
  key: "fillTexture",
@@ -7222,34 +8061,104 @@ var WebglPath = /*#__PURE__*/function (_WebglBase) {
7222
8061
  }, {
7223
8062
  key: "fillPolygons",
7224
8063
  value: function fillPolygons(points) {
8064
+ var _this2 = this;
8065
+
7225
8066
  var isTexture = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
7226
8067
 
7227
- if (points.length > 3) {
7228
- var triangles = this.needCut ? this.earCutPointsToTriangles(points) : this.getTriangles(points);
8068
+ if (points.length <= 3) {
8069
+ // 3个点以下的三角形直接画
8070
+ var buffer = this.writePoints(points);
8071
+ var coordBuffer = isTexture ? this.writePoints(points, this.program.attrs.a_text_coord) : null;
8072
+ this.context.drawArrays(this.context.TRIANGLE_FAN, 0, points.length);
8073
+ return;
8074
+ } // 规则图形(凸多边形,如圆):直接用 TRIANGLE_FAN 一次性绘制,无需 earcut
8075
+
8076
+
8077
+ if (this.isRegular) {
8078
+ var _buffer = this.writePoints(points);
8079
+
8080
+ var _coordBuffer = isTexture ? this.writePoints(points, this.program.attrs.a_text_coord) : null;
7229
8081
 
7230
- if (triangles.length) {
7231
- var _iterator4 = _createForOfIteratorHelper(triangles),
7232
- _step4;
8082
+ this.context.drawArrays(this.context.TRIANGLE_FAN, 0, points.length);
8083
+ return;
8084
+ } // 不规则图形:需要 earcut 三角化后,合并为一个大的顶点缓冲区,单次 drawArrays
8085
+
8086
+
8087
+ var triangles = this.needCut ? this.earCutPointsToTriangles(points) : this.getTriangles(points);
8088
+ if (!triangles.length) return; // 合并所有三角形的顶点到一个数组
8089
+
8090
+ var allVertices = [];
8091
+ var allTexCoords = [];
8092
+
8093
+ var _iterator5 = _createForOfIteratorHelper(triangles),
8094
+ _step5;
8095
+
8096
+ try {
8097
+ for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) {
8098
+ var triangle = _step5.value;
8099
+
8100
+ var _iterator6 = _createForOfIteratorHelper(triangle),
8101
+ _step6;
7233
8102
 
7234
8103
  try {
7235
- for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
7236
- var triangle = _step4.value;
7237
- this.fillPolygons(triangle, isTexture); // 这里就变成了规则的图形了
8104
+ for (_iterator6.s(); !(_step6 = _iterator6.n()).done;) {
8105
+ var p = _step6.value;
8106
+ allVertices.push(p.x, p.y);
8107
+ if (isTexture) allTexCoords.push(p.x, p.y);
7238
8108
  }
7239
8109
  } catch (err) {
7240
- _iterator4.e(err);
8110
+ _iterator6.e(err);
7241
8111
  } finally {
7242
- _iterator4.f();
8112
+ _iterator6.f();
7243
8113
  }
7244
- }
8114
+ } // 一次性上传所有数据并绘制
8115
+
8116
+ } catch (err) {
8117
+ _iterator5.e(err);
8118
+ } finally {
8119
+ _iterator5.f();
8120
+ }
8121
+
8122
+ var vertexData = new Float32Array(allVertices);
8123
+ var gl = this.context; // 复用或创建 position buffer
8124
+
8125
+ var posBuffer = this.__cachedBuffers.find(function (b) {
8126
+ return b.attr === _this2.program.attrs.a_position;
8127
+ });
8128
+
8129
+ if (!posBuffer) {
8130
+ posBuffer = this.createFloat32Buffer(vertexData, gl.ARRAY_BUFFER, gl.DYNAMIC_DRAW);
8131
+ posBuffer.attr = this.program.attrs.a_position;
8132
+
8133
+ this.__cachedBuffers.push(posBuffer);
7245
8134
  } else {
7246
- var buffer = this.writePoints(points); // 纹理坐标
8135
+ gl.bindBuffer(gl.ARRAY_BUFFER, posBuffer.buffer);
8136
+ gl.bufferData(gl.ARRAY_BUFFER, vertexData, gl.DYNAMIC_DRAW);
8137
+ }
7247
8138
 
7248
- var coordBuffer = isTexture ? this.writePoints(points, this.program.attrs.a_text_coord) : null;
7249
- this.context.drawArrays(this.context.TRIANGLE_FAN, 0, points.length);
7250
- this.deleteBuffer(buffer);
7251
- coordBuffer && this.deleteBuffer(coordBuffer);
8139
+ this.writeVertexAttrib(posBuffer, this.program.attrs.a_position, 2, 0, 0);
8140
+
8141
+ if (isTexture && allTexCoords.length) {
8142
+ var texData = new Float32Array(allTexCoords);
8143
+
8144
+ var texBuffer = this.__cachedBuffers.find(function (b) {
8145
+ return b.attr === _this2.program.attrs.a_text_coord;
8146
+ });
8147
+
8148
+ if (!texBuffer) {
8149
+ texBuffer = this.createFloat32Buffer(texData, gl.ARRAY_BUFFER, gl.DYNAMIC_DRAW);
8150
+ texBuffer.attr = this.program.attrs.a_text_coord;
8151
+
8152
+ this.__cachedBuffers.push(texBuffer);
8153
+ } else {
8154
+ gl.bindBuffer(gl.ARRAY_BUFFER, texBuffer.buffer);
8155
+ gl.bufferData(gl.ARRAY_BUFFER, texData, gl.DYNAMIC_DRAW);
8156
+ }
8157
+
8158
+ this.writeVertexAttrib(texBuffer, this.program.attrs.a_text_coord, 2, 0, 0);
7252
8159
  }
8160
+
8161
+ gl.drawArrays(gl.TRIANGLES, 0, allVertices.length / 2);
7253
8162
  } // 填充图形
7254
8163
 
7255
8164
  }, {
@@ -7319,7 +8228,7 @@ var WebglPath = /*#__PURE__*/function (_WebglBase) {
7319
8228
  var _default = WebglPath;
7320
8229
  exports["default"] = _default;
7321
8230
 
7322
- },{"./base.js":13}],22:[function(require,module,exports){
8231
+ },{"./base.js":14}],23:[function(require,module,exports){
7323
8232
  "use strict";
7324
8233
 
7325
8234
  function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
@@ -7526,7 +8435,7 @@ var jmArc = /*#__PURE__*/function (_jmPath) {
7526
8435
 
7527
8436
  exports.jmArc = exports["default"] = jmArc;
7528
8437
 
7529
- },{"../core/jmPath.js":8}],23:[function(require,module,exports){
8438
+ },{"../core/jmPath.js":9}],24:[function(require,module,exports){
7530
8439
  "use strict";
7531
8440
 
7532
8441
  function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
@@ -7750,7 +8659,7 @@ var jmArrow = /*#__PURE__*/function (_jmPath) {
7750
8659
 
7751
8660
  exports.jmArrow = exports["default"] = jmArrow;
7752
8661
 
7753
- },{"../core/jmPath.js":8,"../core/jmUtils.js":11}],24:[function(require,module,exports){
8662
+ },{"../core/jmPath.js":9,"../core/jmUtils.js":12}],25:[function(require,module,exports){
7754
8663
  "use strict";
7755
8664
 
7756
8665
  function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
@@ -7844,7 +8753,7 @@ var jmArrowLine = /*#__PURE__*/function (_jmLine) {
7844
8753
 
7845
8754
  exports.jmArrowLine = exports["default"] = jmArrowLine;
7846
8755
 
7847
- },{"./jmArrow.js":23,"./jmLine.js":30}],25:[function(require,module,exports){
8756
+ },{"./jmArrow.js":24,"./jmLine.js":32}],26:[function(require,module,exports){
7848
8757
  "use strict";
7849
8758
 
7850
8759
  function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
@@ -8016,7 +8925,7 @@ var jmBezier = /*#__PURE__*/function (_jmPath) {
8016
8925
 
8017
8926
  exports.jmBezier = exports["default"] = jmBezier;
8018
8927
 
8019
- },{"../core/jmPath.js":8}],26:[function(require,module,exports){
8928
+ },{"../core/jmPath.js":9}],27:[function(require,module,exports){
8020
8929
  "use strict";
8021
8930
 
8022
8931
  function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
@@ -8146,7 +9055,157 @@ var jmCircle = /*#__PURE__*/function (_jmArc) {
8146
9055
 
8147
9056
  exports.jmCircle = exports["default"] = jmCircle;
8148
9057
 
8149
- },{"./jmArc.js":22}],27:[function(require,module,exports){
9058
+ },{"./jmArc.js":23}],28:[function(require,module,exports){
9059
+ "use strict";
9060
+
9061
+ function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
9062
+
9063
+ Object.defineProperty(exports, "__esModule", {
9064
+ value: true
9065
+ });
9066
+ exports.jmEllipse = exports["default"] = void 0;
9067
+
9068
+ var _jmArc2 = require("./jmArc.js");
9069
+
9070
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
9071
+
9072
+ function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
9073
+
9074
+ function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
9075
+
9076
+ function _get(target, property, receiver) { if (typeof Reflect !== "undefined" && Reflect.get) { _get = Reflect.get; } else { _get = function _get(target, property, receiver) { var base = _superPropBase(target, property); if (!base) return; var desc = Object.getOwnPropertyDescriptor(base, property); if (desc.get) { return desc.get.call(receiver); } return desc.value; }; } return _get(target, property, receiver || target); }
9077
+
9078
+ function _superPropBase(object, property) { while (!Object.prototype.hasOwnProperty.call(object, property)) { object = _getPrototypeOf(object); if (object === null) break; } return object; }
9079
+
9080
+ function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }
9081
+
9082
+ function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
9083
+
9084
+ function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
9085
+
9086
+ function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); }
9087
+
9088
+ function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
9089
+
9090
+ function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }
9091
+
9092
+ function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
9093
+
9094
+ /**
9095
+ * 画椭圆
9096
+ * 椭圆是通过缩放圆形来实现的,支持完整的椭圆和椭圆弧
9097
+ * 可以指定起始角度和结束角度来绘制椭圆弧
9098
+ *
9099
+ * @class jmEllipse
9100
+ * @extends jmArc
9101
+ * @param {object} params 椭圆的参数
9102
+ * @param {object} [params.center={x:0,y:0}] 椭圆中心点坐标
9103
+ * @param {number} [params.width=100] 椭圆宽度(长轴直径)
9104
+ * @param {number} [params.height=60] 椭圆高度(短轴直径)
9105
+ * @param {number} [params.startAngle=0] 起始角度(弧度)
9106
+ * @param {number} [params.endAngle=Math.PI*2] 结束角度(弧度)
9107
+ * @param {boolean} [params.anticlockwise=false] 是否逆时针绘制
9108
+ */
9109
+ var jmEllipse = /*#__PURE__*/function (_jmArc) {
9110
+ _inherits(jmEllipse, _jmArc);
9111
+
9112
+ var _super = _createSuper(jmEllipse);
9113
+
9114
+ function jmEllipse(params) {
9115
+ var t = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'jmEllipse';
9116
+
9117
+ _classCallCheck(this, jmEllipse);
9118
+
9119
+ params = params || {};
9120
+ params.isRegular = true; // 标记为规则图形
9121
+
9122
+ return _super.call(this, params, t);
9123
+ }
9124
+ /**
9125
+ * 初始化图形点
9126
+ * 为WebGL模式生成控制点,2D模式使用draw方法直接绘制
9127
+ *
9128
+ * @method initPoints
9129
+ * @private
9130
+ * @for jmEllipse
9131
+ */
9132
+
9133
+
9134
+ _createClass(jmEllipse, [{
9135
+ key: "initPoints",
9136
+ value: function initPoints() {
9137
+ // WebGL模式使用父类的点生成方法
9138
+ if (this.graph.mode === 'webgl') {
9139
+ return _get(_getPrototypeOf(jmEllipse.prototype), "initPoints", this).call(this);
9140
+ } // 2D模式:生成4个控制点用于边界计算
9141
+ // 这些点不是实际的绘制点,而是用于碰撞检测和边界计算
9142
+
9143
+
9144
+ var location = this.getLocation();
9145
+ this.points = [];
9146
+ this.points.push({
9147
+ x: location.center.x - location.width / 2,
9148
+ y: location.center.y
9149
+ }); // 左
9150
+
9151
+ this.points.push({
9152
+ x: location.center.x,
9153
+ y: location.center.y - location.height / 2
9154
+ }); // 上
9155
+
9156
+ this.points.push({
9157
+ x: location.center.x + location.width / 2,
9158
+ y: location.center.y
9159
+ }); // 右
9160
+
9161
+ this.points.push({
9162
+ x: location.center.x,
9163
+ y: location.center.y + location.height / 2
9164
+ }); // 下
9165
+ }
9166
+ /**
9167
+ * 重写基类画图,此处为画一个椭圆
9168
+ * 使用Canvas的变换功能(平移和缩放)来绘制椭圆
9169
+ *
9170
+ * @method draw
9171
+ */
9172
+
9173
+ }, {
9174
+ key: "draw",
9175
+ value: function draw() {
9176
+ // WebGL模式使用父类的绘制方法
9177
+ if (this.graph.mode === 'webgl') {
9178
+ return _get(_getPrototypeOf(jmEllipse.prototype), "draw", this).call(this);
9179
+ } // 获取边界和位置信息
9180
+
9181
+
9182
+ var bounds = this.parent && this.parent.absoluteBounds ? this.parent.absoluteBounds : this.absoluteBounds;
9183
+ var location = this.getLocation(); // 获取椭圆弧参数
9184
+
9185
+ var start = this.startAngle || 0;
9186
+ var end = this.endAngle || Math.PI * 2;
9187
+ var anticlockwise = this.anticlockwise || false; // 椭圆绘制:通过变换圆形来实现
9188
+ // 1. 保存当前绘图状态
9189
+
9190
+ this.context.save(); // 2. 平移到椭圆中心
9191
+
9192
+ this.context.translate(location.center.x + bounds.left, location.center.y + bounds.top); // 3. 缩放坐标系,使圆形变为椭圆
9193
+ // 将X轴缩放width/2,Y轴缩放height/2,这样单位圆就变成了椭圆
9194
+
9195
+ this.context.scale(location.width / 2, location.height / 2); // 4. 绘制单位圆(会被缩放成椭圆)
9196
+
9197
+ this.context.arc(0, 0, 1, start, end, anticlockwise); // 5. 恢复绘图状态
9198
+
9199
+ this.context.restore();
9200
+ }
9201
+ }]);
9202
+
9203
+ return jmEllipse;
9204
+ }(_jmArc2.jmArc);
9205
+
9206
+ exports.jmEllipse = exports["default"] = jmEllipse;
9207
+
9208
+ },{"./jmArc.js":23}],29:[function(require,module,exports){
8150
9209
  "use strict";
8151
9210
 
8152
9211
  function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
@@ -8306,7 +9365,7 @@ var jmHArc = /*#__PURE__*/function (_jmArc) {
8306
9365
 
8307
9366
  exports.jmHArc = exports["default"] = jmHArc;
8308
9367
 
8309
- },{"./jmArc.js":22}],28:[function(require,module,exports){
9368
+ },{"./jmArc.js":23}],30:[function(require,module,exports){
8310
9369
  "use strict";
8311
9370
 
8312
9371
  function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
@@ -8608,7 +9667,7 @@ var jmImage = /*#__PURE__*/function (_jmControl) {
8608
9667
 
8609
9668
  exports.jmImage = exports["default"] = jmImage;
8610
9669
 
8611
- },{"../core/jmControl.js":2}],29:[function(require,module,exports){
9670
+ },{"../core/jmControl.js":2}],31:[function(require,module,exports){
8612
9671
  "use strict";
8613
9672
 
8614
9673
  function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
@@ -8620,11 +9679,11 @@ exports.jmLabel = exports["default"] = void 0;
8620
9679
 
8621
9680
  var _jmControl2 = require("../core/jmControl.js");
8622
9681
 
8623
- function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) { symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; }
9682
+ function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; }
8624
9683
 
8625
- function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
9684
+ function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
8626
9685
 
8627
- function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
9686
+ function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
8628
9687
 
8629
9688
  function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
8630
9689
 
@@ -8679,7 +9738,7 @@ var jmLabel = /*#__PURE__*/function (_jmControl) {
8679
9738
  _this.style.textAlign = _this.style.textAlign || 'left'; //文字垂直对齐
8680
9739
 
8681
9740
  _this.style.textBaseline = _this.style.textBaseline || 'middle';
8682
- _this.text = params.text || '';
9741
+ _this.text = params.text || params.value || '';
8683
9742
  _this.center = params.center || null;
8684
9743
  return _this;
8685
9744
  }
@@ -8786,32 +9845,145 @@ var jmLabel = /*#__PURE__*/function (_jmControl) {
8786
9845
  }
8787
9846
  /**
8788
9847
  * 测试获取文本所占大小
8789
- *
9848
+ * 计算文本渲染所需的宽度和高度,支持自动换行
9849
+ *
8790
9850
  * @method testSize
8791
- * @return {object} 含文本大小的对象
9851
+ * @return {object} 含文本大小的对象 {width, height}
8792
9852
  */
8793
9853
 
8794
9854
  }, {
8795
9855
  key: "testSize",
8796
9856
  value: function testSize() {
9857
+ // 使用缓存提高性能,避免重复计算
8797
9858
  if (this.__size) return this.__size;
8798
- if (this.webglControl) this.__size = this.webglControl.testSize(this.text, this.style);else {
8799
- this.context.save && this.context.save(); // 修改字体,用来计算
9859
+
9860
+ if (this.webglControl) {
9861
+ this.__size = this.webglControl.testSize(this.text, this.style);
9862
+ } else {
9863
+ this.context.save && this.context.save(); // 设置字体样式用于测量
8800
9864
 
8801
9865
  this.setStyle({
8802
9866
  font: this.style.font || this.style.fontSize + 'px ' + this.style.fontFamily
8803
- }); //计算宽度
9867
+ }); // 计算文本尺寸
9868
+
9869
+ if (this.style.maxWidth && this.text) {
9870
+ // 文本换行处理
9871
+ var lines = this.wrapText(this.text, this.style.maxWidth);
9872
+ var maxWidth = 0; // 找出最宽的一行
9873
+
9874
+ var _iterator = _createForOfIteratorHelper(lines),
9875
+ _step;
9876
+
9877
+ try {
9878
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
9879
+ var line = _step.value;
9880
+ var width = this.context.measureText(line).width;
9881
+ if (width > maxWidth) maxWidth = width;
9882
+ } // 计算总高度(行数 × 行高)
9883
+
9884
+ } catch (err) {
9885
+ _iterator.e(err);
9886
+ } finally {
9887
+ _iterator.f();
9888
+ }
9889
+
9890
+ var lineHeight = this.style.lineHeight || this.style.fontSize * 1.2;
9891
+ this.__size = {
9892
+ width: maxWidth,
9893
+ height: lineHeight * lines.length
9894
+ };
9895
+ } else {
9896
+ // 单行文本
9897
+ this.__size = this.context.measureText ? this.context.measureText(this.text) : {
9898
+ width: 15
9899
+ };
9900
+ this.__size.height = this.style.fontSize ? this.style.fontSize : 15;
9901
+ }
8804
9902
 
8805
- this.__size = this.context.measureText ? this.context.measureText(this.text) : {
8806
- width: 15
8807
- };
8808
9903
  this.context.restore && this.context.restore();
8809
- this.__size.height = this.style.fontSize ? this.style.fontSize : 15;
8810
- }
9904
+ } // 设置默认宽高
9905
+
9906
+
8811
9907
  if (!this.width) this.width = this.__size.width;
8812
9908
  if (!this.height) this.height = this.__size.height;
8813
9909
  return this.__size;
8814
9910
  }
9911
+ /**
9912
+ * 文本换行处理
9913
+ * 根据最大宽度将文本分割成多行
9914
+ * 支持中英文混合文本,优先在空格处换行
9915
+ *
9916
+ * @method wrapText
9917
+ * @param {string} text 文本内容
9918
+ * @param {number} maxWidth 最大宽度(像素)
9919
+ * @return {array} 换行后的文本数组
9920
+ */
9921
+
9922
+ }, {
9923
+ key: "wrapText",
9924
+ value: function wrapText(text, maxWidth) {
9925
+ // 参数验证
9926
+ if (!text || !maxWidth) return [text || '']; // 检查缓存,避免重复计算
9927
+
9928
+ var cacheKey = "".concat(text, "_").concat(maxWidth);
9929
+
9930
+ if (this.__wrapTextCache && this.__wrapTextCache.key === cacheKey) {
9931
+ return this.__wrapTextCache.lines;
9932
+ }
9933
+
9934
+ var lines = []; // 先按换行符分割
9935
+
9936
+ var paragraphs = text.split('\n');
9937
+
9938
+ var _iterator2 = _createForOfIteratorHelper(paragraphs),
9939
+ _step2;
9940
+
9941
+ try {
9942
+ for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
9943
+ var paragraph = _step2.value;
9944
+
9945
+ // 如果段落为空,添加空行
9946
+ if (!paragraph) {
9947
+ lines.push('');
9948
+ continue;
9949
+ } // 按空格分割单词
9950
+
9951
+
9952
+ var words = paragraph.split(' ');
9953
+ var currentLine = words[0];
9954
+
9955
+ for (var i = 1; i < words.length; i++) {
9956
+ var word = words[i];
9957
+ var testLine = currentLine + ' ' + word;
9958
+ var metrics = this.context.measureText(testLine);
9959
+ var testWidth = metrics.width;
9960
+
9961
+ if (testWidth <= maxWidth) {
9962
+ // 当前行还能容纳这个单词
9963
+ currentLine = testLine;
9964
+ } else {
9965
+ // 当前行已满,保存当前行并开始新行
9966
+ if (currentLine) lines.push(currentLine);
9967
+ currentLine = word;
9968
+ }
9969
+ } // 添加最后一行
9970
+
9971
+
9972
+ if (currentLine) lines.push(currentLine);
9973
+ } // 缓存结果
9974
+
9975
+ } catch (err) {
9976
+ _iterator2.e(err);
9977
+ } finally {
9978
+ _iterator2.f();
9979
+ }
9980
+
9981
+ this.__wrapTextCache = {
9982
+ key: cacheKey,
9983
+ lines: lines
9984
+ };
9985
+ return lines;
9986
+ }
8815
9987
  /**
8816
9988
  * 根据位置偏移画字符串
8817
9989
  *
@@ -8868,78 +10040,36 @@ var jmLabel = /*#__PURE__*/function (_jmControl) {
8868
10040
  this.webglControl.drawText(txt, x, y, location);
8869
10041
  } else if (this.style.fill && this.context.fillText) {
8870
10042
  if (this.style.maxWidth) {
8871
- this.context.fillText(txt, x, y, this.style.maxWidth);
10043
+ // 绘制换行文本
10044
+ var lines = this.wrapText(txt, this.style.maxWidth);
10045
+ var lineHeight = this.style.fontSize; // 调整起始Y位置以支持垂直对齐
10046
+
10047
+ var startY = y - (lines.length - 1) * lineHeight / 2;
10048
+
10049
+ for (var i = 0; i < lines.length; i++) {
10050
+ var lineY = startY + i * lineHeight;
10051
+ this.context.fillText(lines[i], x, lineY);
10052
+ }
8872
10053
  } else {
8873
10054
  this.context.fillText(txt, x, y);
8874
10055
  }
8875
10056
  } else if (this.context.strokeText) {
8876
10057
  if (this.style.maxWidth) {
8877
- this.context.strokeText(txt, x, y, this.style.maxWidth);
8878
- } else {
8879
- this.context.strokeText(txt, x, y);
8880
- }
8881
- }
8882
- } //如果有指定边框,则画出边框
8883
-
8884
-
8885
- if (this.style.border) {
8886
- //如果指定了边框样式
8887
- if (this.style.border.style) {
8888
- this.context.save && this.context.save();
8889
- this.setStyle(this.style.border.style);
8890
- }
8891
-
8892
- if (this.mode === '2d') {
8893
- this.context.moveTo(this.points[0].x + bounds.left, this.points[0].y + bounds.top);
8894
-
8895
- if (this.style.border.top) {
8896
- this.context.lineTo(this.points[1].x + bounds.left, this.points[1].y + bounds.top);
8897
- }
8898
-
8899
- if (this.style.border.right) {
8900
- this.context.moveTo(this.points[1].x + bounds.left, this.points[1].y + bounds.top);
8901
- this.context.lineTo(this.points[2].x + bounds.left, this.points[2].y + bounds.top);
8902
- }
8903
-
8904
- if (this.style.border.bottom) {
8905
- this.context.moveTo(this.points[2].x + bounds.left, this.points[2].y + bounds.top);
8906
- this.context.lineTo(this.points[3].x + bounds.left, this.points[3].y + bounds.top);
8907
- }
8908
-
8909
- if (this.style.border.left) {
8910
- this.context.moveTo(this.points[3].x + bounds.left, this.points[3].y + bounds.top);
8911
- this.context.lineTo(this.points[0].x + bounds.left, this.points[0].y + bounds.top);
8912
- }
8913
- } else {
8914
- var points = [];
10058
+ // 绘制换行文本
10059
+ var _lines = this.wrapText(txt, this.style.maxWidth);
8915
10060
 
8916
- if (this.style.border.top) {
8917
- points.push(this.points[0]);
8918
- points.push(this.points[1]);
8919
- }
10061
+ var _lineHeight = this.style.fontSize; // 调整起始Y位置以支持垂直对齐
8920
10062
 
8921
- if (this.style.border.right) {
8922
- points.push(_objectSpread(_objectSpread({}, this.points[1]), {}, {
8923
- m: true
8924
- }));
8925
- points.push(this.points[2]);
8926
- }
10063
+ var _startY = y - (_lines.length - 1) * _lineHeight / 2;
8927
10064
 
8928
- if (this.style.border.bottom) {
8929
- points.push(_objectSpread(_objectSpread({}, this.points[2]), {}, {
8930
- m: true
8931
- }));
8932
- points.push(this.points[3]);
8933
- }
10065
+ for (var _i = 0; _i < _lines.length; _i++) {
10066
+ var _lineY = _startY + _i * _lineHeight;
8934
10067
 
8935
- if (this.style.border.left) {
8936
- points.push(_objectSpread(_objectSpread({}, this.points[3]), {}, {
8937
- m: true
8938
- }));
8939
- points.push(this.points[0]);
10068
+ this.context.strokeText(_lines[_i], x, _lineY);
10069
+ }
10070
+ } else {
10071
+ this.context.strokeText(txt, x, y);
8940
10072
  }
8941
-
8942
- points.length && this.webglControl && this.webglControl.stroke(points);
8943
10073
  }
8944
10074
  }
8945
10075
  }
@@ -8957,7 +10087,7 @@ var jmLabel = /*#__PURE__*/function (_jmControl) {
8957
10087
 
8958
10088
  exports.jmLabel = exports["default"] = jmLabel;
8959
10089
 
8960
- },{"../core/jmControl.js":2}],30:[function(require,module,exports){
10090
+ },{"../core/jmControl.js":2}],32:[function(require,module,exports){
8961
10091
  "use strict";
8962
10092
 
8963
10093
  function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
@@ -9112,7 +10242,7 @@ var jmLine = /*#__PURE__*/function (_jmPath) {
9112
10242
 
9113
10243
  exports.jmLine = exports["default"] = jmLine;
9114
10244
 
9115
- },{"../core/jmPath.js":8}],31:[function(require,module,exports){
10245
+ },{"../core/jmPath.js":9}],33:[function(require,module,exports){
9116
10246
  "use strict";
9117
10247
 
9118
10248
  function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
@@ -9120,7 +10250,7 @@ function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "functi
9120
10250
  Object.defineProperty(exports, "__esModule", {
9121
10251
  value: true
9122
10252
  });
9123
- exports.jmPrismatic = exports["default"] = void 0;
10253
+ exports.jmPolygon = exports["default"] = void 0;
9124
10254
 
9125
10255
  var _jmPath2 = require("../core/jmPath.js");
9126
10256
 
@@ -9144,12 +10274,208 @@ function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Re
9144
10274
 
9145
10275
  function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
9146
10276
 
9147
- /**
9148
- * 画棱形
9149
- *
9150
- * @class jmPrismatic
9151
- * @extends jmPath
9152
- * @param {object} params 参数 center=棱形中心点,width=棱形宽,height=棱形高
10277
+ /**
10278
+ * 画多边形
10279
+ * 支持规则多边形(正多边形)和自定义多边形
10280
+ * 规则多边形通过边数和半径自动计算顶点,自定义多边形通过顶点数组定义
10281
+ *
10282
+ * @class jmPolygon
10283
+ * @extends jmPath
10284
+ * @param {object} params 多边形的参数
10285
+ * @param {array} [params.points] 自定义顶点数组,如果提供则忽略sides和radius
10286
+ * @param {number} [params.sides=3] 多边形边数(3-100)
10287
+ * @param {number} [params.radius=50] 多边形半径(像素)
10288
+ * @param {object} [params.center={x:0,y:0}] 多边形中心点坐标
10289
+ */
10290
+ var jmPolygon = /*#__PURE__*/function (_jmPath) {
10291
+ _inherits(jmPolygon, _jmPath);
10292
+
10293
+ var _super = _createSuper(jmPolygon);
10294
+
10295
+ function jmPolygon(params) {
10296
+ var _params$points;
10297
+
10298
+ var _this;
10299
+
10300
+ var t = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'jmPolygon';
10301
+
10302
+ _classCallCheck(this, jmPolygon);
10303
+
10304
+ params = params || {};
10305
+ params.isRegular = true; // 标记为规则图形,便于优化渲染
10306
+
10307
+ _this = _super.call(this, params, t); // 参数验证和初始化
10308
+
10309
+ _this.sides = params.sides || ((_params$points = params.points) === null || _params$points === void 0 ? void 0 : _params$points.length) || 3;
10310
+ _this.radius = params.radius || 50;
10311
+ _this.center = params.center || {
10312
+ x: 0,
10313
+ y: 0
10314
+ };
10315
+ return _this;
10316
+ }
10317
+ /**
10318
+ * 设定或获取多边形边数
10319
+ * 边数决定了多边形的形状,最小为3(三角形)
10320
+ *
10321
+ * @property sides
10322
+ * @for jmPolygon
10323
+ * @type {number}
10324
+ */
10325
+
10326
+
10327
+ _createClass(jmPolygon, [{
10328
+ key: "sides",
10329
+ get: function get() {
10330
+ return this.property('sides');
10331
+ },
10332
+ set: function set(v) {
10333
+ // 参数验证:边数必须在3-100之间
10334
+ if (typeof v !== 'number' || isNaN(v) || v < 3) {
10335
+ console.warn('jmPolygon: sides must be a number >= 3');
10336
+ v = 3;
10337
+ }
10338
+
10339
+ if (v > 100) {
10340
+ console.warn('jmPolygon: sides should not exceed 100 for performance reasons');
10341
+ v = 100;
10342
+ }
10343
+
10344
+ this.needUpdate = true;
10345
+ return this.property('sides', Math.floor(v)); // 确保是整数
10346
+ }
10347
+ /**
10348
+ * 设定或获取多边形半径
10349
+ * 半径是从中心点到顶点的距离
10350
+ *
10351
+ * @property radius
10352
+ * @for jmPolygon
10353
+ * @type {number}
10354
+ */
10355
+
10356
+ }, {
10357
+ key: "radius",
10358
+ get: function get() {
10359
+ return this.property('radius');
10360
+ },
10361
+ set: function set(v) {
10362
+ // 参数验证:半径必须为正数
10363
+ if (typeof v !== 'number' || isNaN(v) || v <= 0) {
10364
+ console.warn('jmPolygon: radius must be a positive number');
10365
+ v = 1;
10366
+ }
10367
+
10368
+ this.needUpdate = true;
10369
+ return this.property('radius', v);
10370
+ }
10371
+ /**
10372
+ * 设定或获取多边形中心
10373
+ * 中心点是多边形的几何中心
10374
+ *
10375
+ * @property center
10376
+ * @for jmPolygon
10377
+ * @type {object}
10378
+ */
10379
+
10380
+ }, {
10381
+ key: "center",
10382
+ get: function get() {
10383
+ return this.property('center');
10384
+ },
10385
+ set: function set(v) {
10386
+ // 参数验证:中心点必须包含x和y属性
10387
+ if (!v || typeof v.x !== 'number' || typeof v.y !== 'number') {
10388
+ console.warn('jmPolygon: center must be an object with x and y properties');
10389
+ v = {
10390
+ x: 0,
10391
+ y: 0
10392
+ };
10393
+ }
10394
+
10395
+ this.needUpdate = true;
10396
+ return this.property('center', v);
10397
+ }
10398
+ /**
10399
+ * 初始化图形点
10400
+ * 如果提供了自定义顶点,则使用自定义顶点
10401
+ * 否则根据边数和半径自动计算规则多边形的顶点
10402
+ *
10403
+ * @method initPoints
10404
+ * @private
10405
+ * @for jmPolygon
10406
+ */
10407
+
10408
+ }, {
10409
+ key: "initPoints",
10410
+ value: function initPoints() {
10411
+ // 如果提供了自定义顶点,直接使用
10412
+ if (this.points && this.points.length > 0) {
10413
+ return;
10414
+ } // 计算规则多边形的顶点
10415
+
10416
+
10417
+ var points = [];
10418
+ var sides = this.sides;
10419
+ var radius = this.radius;
10420
+ var center = this.center; // 从顶部开始绘制(-90度),顺时针方向
10421
+
10422
+ for (var i = 0; i < sides; i++) {
10423
+ var angle = i / sides * Math.PI * 2 - Math.PI / 2;
10424
+ var x = center.x + Math.cos(angle) * radius;
10425
+ var y = center.y + Math.sin(angle) * radius;
10426
+ points.push({
10427
+ x: x,
10428
+ y: y
10429
+ });
10430
+ }
10431
+
10432
+ this.points = points;
10433
+ }
10434
+ }]);
10435
+
10436
+ return jmPolygon;
10437
+ }(_jmPath2.jmPath);
10438
+
10439
+ exports.jmPolygon = exports["default"] = jmPolygon;
10440
+
10441
+ },{"../core/jmPath.js":9}],34:[function(require,module,exports){
10442
+ "use strict";
10443
+
10444
+ function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
10445
+
10446
+ Object.defineProperty(exports, "__esModule", {
10447
+ value: true
10448
+ });
10449
+ exports.jmPrismatic = exports["default"] = void 0;
10450
+
10451
+ var _jmPath2 = require("../core/jmPath.js");
10452
+
10453
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
10454
+
10455
+ function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
10456
+
10457
+ function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
10458
+
10459
+ function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }
10460
+
10461
+ function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
10462
+
10463
+ function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
10464
+
10465
+ function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); }
10466
+
10467
+ function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
10468
+
10469
+ function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }
10470
+
10471
+ function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
10472
+
10473
+ /**
10474
+ * 画棱形
10475
+ *
10476
+ * @class jmPrismatic
10477
+ * @extends jmPath
10478
+ * @param {object} params 参数 center=棱形中心点,width=棱形宽,height=棱形高
9153
10479
  */
9154
10480
  var jmPrismatic = /*#__PURE__*/function (_jmPath) {
9155
10481
  _inherits(jmPrismatic, _jmPath);
@@ -9232,11 +10558,9 @@ var jmPrismatic = /*#__PURE__*/function (_jmPath) {
9232
10558
 
9233
10559
  exports.jmPrismatic = exports["default"] = jmPrismatic;
9234
10560
 
9235
- },{"../core/jmPath.js":8}],32:[function(require,module,exports){
10561
+ },{"../core/jmPath.js":9}],35:[function(require,module,exports){
9236
10562
  "use strict";
9237
10563
 
9238
- function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
9239
-
9240
10564
  Object.defineProperty(exports, "__esModule", {
9241
10565
  value: true
9242
10566
  });
@@ -9248,6 +10572,8 @@ var _jmArc = require("./jmArc.js");
9248
10572
 
9249
10573
  var _jmLine = require("./jmLine.js");
9250
10574
 
10575
+ function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
10576
+
9251
10577
  function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
9252
10578
 
9253
10579
  function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
@@ -9274,6 +10600,7 @@ function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.g
9274
10600
  * @class jmRect
9275
10601
  * @extends jmPath
9276
10602
  * @param {object} params 参数 position=矩形左上角顶点坐标,width=宽,height=高,radius=边角弧度
10603
+ * radius支持数字(四角相同)或对象 { topLeft, topRight, bottomRight, bottomLeft }
9277
10604
  */
9278
10605
  var jmRect = /*#__PURE__*/function (_jmPath) {
9279
10606
  _inherits(jmRect, _jmPath);
@@ -9292,13 +10619,26 @@ var jmRect = /*#__PURE__*/function (_jmPath) {
9292
10619
 
9293
10620
  _this = _super.call(this, params, t);
9294
10621
  _this.style.close = true;
9295
- _this.radius = params.radius || _this.style.radius || 0;
10622
+ var r = params.radius || _this.style.radius || _this.style.borderRadius || 0;
10623
+
10624
+ if (_typeof(r) === 'object' && r !== null) {
10625
+ // 四角独立圆角
10626
+ _this.radius = {
10627
+ topLeft: Number(r.topLeft) || 0,
10628
+ topRight: Number(r.topRight) || 0,
10629
+ bottomRight: Number(r.bottomRight) || 0,
10630
+ bottomLeft: Number(r.bottomLeft) || 0
10631
+ };
10632
+ } else {
10633
+ _this.radius = r;
10634
+ }
10635
+
9296
10636
  return _this;
9297
10637
  }
9298
10638
  /**
9299
- * 圆角半径
10639
+ * 圆角半径,支持数字或四角独立对象
9300
10640
  * @property radius
9301
- * @type {number}
10641
+ * @type {number|object}
9302
10642
  */
9303
10643
 
9304
10644
 
@@ -9311,6 +10651,53 @@ var jmRect = /*#__PURE__*/function (_jmPath) {
9311
10651
  this.needUpdate = true;
9312
10652
  return this.property('radius', v);
9313
10653
  }
10654
+ /**
10655
+ * 获取规范化的圆角值(四角独立)
10656
+ * @returns {object} { topLeft, topRight, bottomRight, bottomLeft }
10657
+ */
10658
+
10659
+ }, {
10660
+ key: "getNormalizedRadius",
10661
+ value: function getNormalizedRadius() {
10662
+ var r = this.radius;
10663
+
10664
+ if (typeof r === 'number') {
10665
+ var v = Math.max(0, r);
10666
+ return {
10667
+ topLeft: v,
10668
+ topRight: v,
10669
+ bottomRight: v,
10670
+ bottomLeft: v
10671
+ };
10672
+ }
10673
+
10674
+ if (_typeof(r) === 'object' && r !== null) {
10675
+ return {
10676
+ topLeft: Math.max(0, Number(r.topLeft) || 0),
10677
+ topRight: Math.max(0, Number(r.topRight) || 0),
10678
+ bottomRight: Math.max(0, Number(r.bottomRight) || 0),
10679
+ bottomLeft: Math.max(0, Number(r.bottomLeft) || 0)
10680
+ };
10681
+ }
10682
+
10683
+ return {
10684
+ topLeft: 0,
10685
+ topRight: 0,
10686
+ bottomRight: 0,
10687
+ bottomLeft: 0
10688
+ };
10689
+ }
10690
+ /**
10691
+ * 检查是否有圆角
10692
+ * @returns {boolean}
10693
+ */
10694
+
10695
+ }, {
10696
+ key: "hasRadius",
10697
+ value: function hasRadius() {
10698
+ var nr = this.getNormalizedRadius();
10699
+ return nr.topLeft > 0 || nr.topRight > 0 || nr.bottomRight > 0 || nr.bottomLeft > 0;
10700
+ }
9314
10701
  /**
9315
10702
  * 当前位置左上角
9316
10703
  * @property position
@@ -9373,7 +10760,7 @@ var jmRect = /*#__PURE__*/function (_jmPath) {
9373
10760
 
9374
10761
  /**
9375
10762
  * 初始化图形点
9376
- * 如果有边角弧度则类型圆绝计算其描点
10763
+ * 支持四角独立圆角,借助圆弧对象计算描点
9377
10764
  *
9378
10765
  * @method initPoints
9379
10766
  * @private
@@ -9404,55 +10791,93 @@ var jmRect = /*#__PURE__*/function (_jmPath) {
9404
10791
  this.dottedLine = this.graph.createShape(_jmLine.jmLine, {
9405
10792
  style: this.style
9406
10793
  });
9407
- } //如果有边界弧度则借助圆弧对象计算描点
10794
+ }
9408
10795
 
10796
+ var nr = this.getNormalizedRadius();
10797
+ var hasRadius = this.hasRadius(); // 如果有圆角(支持四角独立),借助圆弧对象计算描点
10798
+
10799
+ if (hasRadius) {
10800
+ var q = Math.PI / 2; // 限制圆角不超过短边的一半
10801
+
10802
+ var maxR = Math.min(location.width / 2, location.height / 2);
10803
+ var rtl = Math.min(nr.topLeft, maxR);
10804
+ var rtr = Math.min(nr.topRight, maxR);
10805
+ var rbr = Math.min(nr.bottomRight, maxR);
10806
+ var rbl = Math.min(nr.bottomLeft, maxR); // 左上角圆弧
10807
+
10808
+ if (rtl > 0) {
10809
+ var arc = this.graph.createShape(_jmArc.jmArc, {
10810
+ radius: rtl,
10811
+ anticlockwise: false
10812
+ });
10813
+ arc.center = {
10814
+ x: location.left + rtl,
10815
+ y: location.top + rtl
10816
+ };
10817
+ arc.startAngle = Math.PI;
10818
+ arc.endAngle = Math.PI + q;
10819
+ var ps1 = arc.initPoints();
10820
+ } else {
10821
+ var ps1 = [p1];
10822
+ } // 右上角圆弧
10823
+
10824
+
10825
+ if (rtr > 0) {
10826
+ var _arc = this.graph.createShape(_jmArc.jmArc, {
10827
+ radius: rtr,
10828
+ anticlockwise: false
10829
+ });
10830
+
10831
+ _arc.center = {
10832
+ x: p2.x - rtr,
10833
+ y: p2.y + rtr
10834
+ };
10835
+ _arc.startAngle = Math.PI + q;
10836
+ _arc.endAngle = Math.PI * 2;
10837
+
10838
+ var ps2 = _arc.initPoints();
10839
+ } else {
10840
+ var ps2 = [p2];
10841
+ } // 右下角圆弧
10842
+
10843
+
10844
+ if (rbr > 0) {
10845
+ var _arc2 = this.graph.createShape(_jmArc.jmArc, {
10846
+ radius: rbr,
10847
+ anticlockwise: false
10848
+ });
10849
+
10850
+ _arc2.center = {
10851
+ x: p3.x - rbr,
10852
+ y: p3.y - rbr
10853
+ };
10854
+ _arc2.startAngle = 0;
10855
+ _arc2.endAngle = q;
10856
+
10857
+ var ps3 = _arc2.initPoints();
10858
+ } else {
10859
+ var ps3 = [p3];
10860
+ } // 左下角圆弧
10861
+
10862
+
10863
+ if (rbl > 0) {
10864
+ var _arc3 = this.graph.createShape(_jmArc.jmArc, {
10865
+ radius: rbl,
10866
+ anticlockwise: false
10867
+ });
10868
+
10869
+ _arc3.center = {
10870
+ x: p4.x + rbl,
10871
+ y: p4.y - rbl
10872
+ };
10873
+ _arc3.startAngle = q;
10874
+ _arc3.endAngle = Math.PI;
10875
+
10876
+ var ps4 = _arc3.initPoints();
10877
+ } else {
10878
+ var ps4 = [p4];
10879
+ }
9409
10880
 
9410
- if (location.radius && location.radius < location.width / 2 && location.radius < location.height / 2) {
9411
- var q = Math.PI / 2;
9412
- var arc = this.graph.createShape(_jmArc.jmArc, {
9413
- radius: location.radius,
9414
- anticlockwise: false
9415
- });
9416
- arc.center = {
9417
- x: location.left + location.radius,
9418
- y: location.top + location.radius
9419
- };
9420
- arc.startAngle = Math.PI;
9421
- arc.endAngle = Math.PI + q;
9422
- var ps1 = arc.initPoints();
9423
- arc = this.graph.createShape(_jmArc.jmArc, {
9424
- radius: location.radius,
9425
- anticlockwise: false
9426
- });
9427
- arc.center = {
9428
- x: p2.x - location.radius,
9429
- y: p2.y + location.radius
9430
- };
9431
- arc.startAngle = Math.PI + q;
9432
- arc.endAngle = Math.PI * 2;
9433
- var ps2 = arc.initPoints();
9434
- arc = this.graph.createShape(_jmArc.jmArc, {
9435
- radius: location.radius,
9436
- anticlockwise: false
9437
- });
9438
- arc.center = {
9439
- x: p3.x - location.radius,
9440
- y: p3.y - location.radius
9441
- };
9442
- arc.startAngle = 0;
9443
- arc.endAngle = q;
9444
- var ps3 = arc.initPoints();
9445
- arc = this.graph.createShape(_jmArc.jmArc, {
9446
- radius: location.radius,
9447
- anticlockwise: false
9448
- });
9449
- arc.center = {
9450
- x: p4.x + location.radius,
9451
- y: p4.y - location.radius
9452
- };
9453
- arc.startAngle = q;
9454
- arc.endAngle = Math.PI;
9455
- var ps4 = arc.initPoints();
9456
10881
  this.points = ps1.concat(ps2, ps3, ps4);
9457
10882
  } else {
9458
10883
  this.points = [];
@@ -9498,7 +10923,7 @@ var jmRect = /*#__PURE__*/function (_jmPath) {
9498
10923
 
9499
10924
  exports.jmRect = exports["default"] = jmRect;
9500
10925
 
9501
- },{"../core/jmPath.js":8,"./jmArc.js":22,"./jmLine.js":30}],33:[function(require,module,exports){
10926
+ },{"../core/jmPath.js":9,"./jmArc.js":23,"./jmLine.js":32}],36:[function(require,module,exports){
9502
10927
  "use strict";
9503
10928
 
9504
10929
  function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
@@ -9898,5 +11323,234 @@ var jmResize = /*#__PURE__*/function (_jmRect) {
9898
11323
 
9899
11324
  exports.jmResize = exports["default"] = jmResize;
9900
11325
 
9901
- },{"./jmRect.js":32}]},{},[1]);
11326
+ },{"./jmRect.js":35}],37:[function(require,module,exports){
11327
+ "use strict";
11328
+
11329
+ function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
11330
+
11331
+ Object.defineProperty(exports, "__esModule", {
11332
+ value: true
11333
+ });
11334
+ exports.jmStar = exports["default"] = void 0;
11335
+
11336
+ var _jmPath2 = require("../core/jmPath.js");
11337
+
11338
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
11339
+
11340
+ function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
11341
+
11342
+ function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
11343
+
11344
+ function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }
11345
+
11346
+ function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
11347
+
11348
+ function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
11349
+
11350
+ function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); }
11351
+
11352
+ function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
11353
+
11354
+ function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }
11355
+
11356
+ function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
11357
+
11358
+ /**
11359
+ * 画星形
11360
+ * 支持自定义顶点数和内外半径,创建各种星形图案
11361
+ * 星形由交替的外半径和内半径顶点组成
11362
+ *
11363
+ * @class jmStar
11364
+ * @extends jmPath
11365
+ * @param {object} params 星形的参数
11366
+ * @param {array} [params.points] 自定义顶点数组,如果提供则忽略其他参数
11367
+ * @param {number} [params.points=5] 星形顶点数(角数,3-50)
11368
+ * @param {number} [params.radius=50] 星形外半径(从中心到尖角的距离)
11369
+ * @param {number} [params.innerRadius=25] 星形内半径(从中心到凹陷处的距离)
11370
+ * @param {object} [params.center={x:0,y:0}] 星形中心点坐标
11371
+ */
11372
+ var jmStar = /*#__PURE__*/function (_jmPath) {
11373
+ _inherits(jmStar, _jmPath);
11374
+
11375
+ var _super = _createSuper(jmStar);
11376
+
11377
+ function jmStar(params) {
11378
+ var _this;
11379
+
11380
+ var t = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'jmStar';
11381
+
11382
+ _classCallCheck(this, jmStar);
11383
+
11384
+ params = params || {};
11385
+ params.isRegular = true; // 标记为规则图形
11386
+
11387
+ _this = _super.call(this, params, t); // 参数验证和初始化
11388
+
11389
+ _this.pointsCount = params.points || 5;
11390
+ _this.radius = params.radius || 50;
11391
+ _this.innerRadius = params.innerRadius || 25;
11392
+ _this.center = params.center || {
11393
+ x: 0,
11394
+ y: 0
11395
+ };
11396
+ return _this;
11397
+ }
11398
+ /**
11399
+ * 设定或获取星形顶点数(角数)
11400
+ * 顶点数决定了星形的角数,例如5表示五角星
11401
+ *
11402
+ * @property pointsCount
11403
+ * @for jmStar
11404
+ * @type {number}
11405
+ */
11406
+
11407
+
11408
+ _createClass(jmStar, [{
11409
+ key: "pointsCount",
11410
+ get: function get() {
11411
+ return this.property('pointsCount');
11412
+ },
11413
+ set: function set(v) {
11414
+ // 参数验证:顶点数必须在3-50之间
11415
+ if (typeof v !== 'number' || isNaN(v) || v < 3) {
11416
+ console.warn('jmStar: pointsCount must be a number >= 3');
11417
+ v = 3;
11418
+ }
11419
+
11420
+ if (v > 50) {
11421
+ console.warn('jmStar: pointsCount should not exceed 50 for performance reasons');
11422
+ v = 50;
11423
+ }
11424
+
11425
+ this.needUpdate = true;
11426
+ return this.property('pointsCount', Math.floor(v)); // 确保是整数
11427
+ }
11428
+ /**
11429
+ * 设定或获取星形外半径
11430
+ * 外半径是从中心到尖角的距离
11431
+ *
11432
+ * @property radius
11433
+ * @for jmStar
11434
+ * @type {number}
11435
+ */
11436
+
11437
+ }, {
11438
+ key: "radius",
11439
+ get: function get() {
11440
+ return this.property('radius');
11441
+ },
11442
+ set: function set(v) {
11443
+ // 参数验证:半径必须为正数
11444
+ if (typeof v !== 'number' || isNaN(v) || v <= 0) {
11445
+ console.warn('jmStar: radius must be a positive number');
11446
+ v = 1;
11447
+ }
11448
+
11449
+ this.needUpdate = true;
11450
+ return this.property('radius', v);
11451
+ }
11452
+ /**
11453
+ * 设定或获取星形内半径
11454
+ * 内半径是从中心到凹陷处的距离
11455
+ * 内半径应该小于外半径,否则会产生奇怪的形状
11456
+ *
11457
+ * @property innerRadius
11458
+ * @for jmStar
11459
+ * @type {number}
11460
+ */
11461
+
11462
+ }, {
11463
+ key: "innerRadius",
11464
+ get: function get() {
11465
+ return this.property('innerRadius');
11466
+ },
11467
+ set: function set(v) {
11468
+ // 参数验证:内半径必须为正数
11469
+ if (typeof v !== 'number' || isNaN(v) || v <= 0) {
11470
+ console.warn('jmStar: innerRadius must be a positive number');
11471
+ v = 1;
11472
+ } // 警告:内半径不应大于外半径
11473
+
11474
+
11475
+ if (v >= this.radius) {
11476
+ console.warn('jmStar: innerRadius should be less than radius for proper star shape');
11477
+ }
11478
+
11479
+ this.needUpdate = true;
11480
+ return this.property('innerRadius', v);
11481
+ }
11482
+ /**
11483
+ * 设定或获取星形中心
11484
+ * 中心点是星形的几何中心
11485
+ *
11486
+ * @property center
11487
+ * @for jmStar
11488
+ * @type {object}
11489
+ */
11490
+
11491
+ }, {
11492
+ key: "center",
11493
+ get: function get() {
11494
+ return this.property('center');
11495
+ },
11496
+ set: function set(v) {
11497
+ // 参数验证:中心点必须包含x和y属性
11498
+ if (!v || typeof v.x !== 'number' || typeof v.y !== 'number') {
11499
+ console.warn('jmStar: center must be an object with x and y properties');
11500
+ v = {
11501
+ x: 0,
11502
+ y: 0
11503
+ };
11504
+ }
11505
+
11506
+ this.needUpdate = true;
11507
+ return this.property('center', v);
11508
+ }
11509
+ /**
11510
+ * 初始化图形点
11511
+ * 计算星形的顶点坐标,交替使用外半径和内半径
11512
+ *
11513
+ * @method initPoints
11514
+ * @private
11515
+ * @for jmStar
11516
+ */
11517
+
11518
+ }, {
11519
+ key: "initPoints",
11520
+ value: function initPoints() {
11521
+ // 如果提供了自定义顶点,直接使用
11522
+ if (this.points && this.points.length > 0) {
11523
+ return;
11524
+ } // 计算星形顶点
11525
+
11526
+
11527
+ var points = [];
11528
+ var pointsCount = this.pointsCount;
11529
+ var radius = this.radius;
11530
+ var innerRadius = this.innerRadius;
11531
+ var center = this.center; // 星形有2倍顶点数的点(外半径和内半径交替)
11532
+ // 从顶部开始绘制(-90度),顺时针方向
11533
+
11534
+ for (var i = 0; i < pointsCount * 2; i++) {
11535
+ var angle = i / pointsCount * Math.PI - Math.PI / 2; // 偶数索引使用外半径,奇数索引使用内半径
11536
+
11537
+ var r = i % 2 === 0 ? radius : innerRadius;
11538
+ var x = center.x + Math.cos(angle) * r;
11539
+ var y = center.y + Math.sin(angle) * r;
11540
+ points.push({
11541
+ x: x,
11542
+ y: y
11543
+ });
11544
+ }
11545
+
11546
+ this.points = points;
11547
+ }
11548
+ }]);
11549
+
11550
+ return jmStar;
11551
+ }(_jmPath2.jmPath);
11552
+
11553
+ exports.jmStar = exports["default"] = jmStar;
11554
+
11555
+ },{"../core/jmPath.js":9}]},{},[1]);
9902
11556
  var _r=_m(1);_g.jmGraph=_r;return _r;})})(typeof window!=='undefined'?window:(typeof global!=='undefined'?global:(typeof self!=='undefined'?self:this)));