@xrubik/fabric-to-leafer-elements 0.0.0-stage → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs ADDED
@@ -0,0 +1,1071 @@
1
+ // src/button.js
2
+ import { Box, Rect, Text, Line } from "leafer-ui";
3
+
4
+ // src/utils.js
5
+ function normalizeColor(color) {
6
+ if (typeof color !== "string") return color;
7
+ const value = color.trim();
8
+ const rgbaHex = value.match(/^#([0-9a-fA-F]{8})$/);
9
+ if (!rgbaHex) return color;
10
+ const hex = rgbaHex[1];
11
+ const alpha = parseInt(hex.slice(6, 8), 16);
12
+ if (alpha === 255) return "#" + hex.slice(0, 6);
13
+ const r = parseInt(hex.slice(0, 2), 16);
14
+ const g = parseInt(hex.slice(2, 4), 16);
15
+ const b = parseInt(hex.slice(4, 6), 16);
16
+ return `rgba(${r},${g},${b},${Math.round(alpha / 255 * 1e3) / 1e3})`;
17
+ }
18
+
19
+ // src/button.js
20
+ var DEFAULT_FILL = "#969696";
21
+ var DEFAULT_FONT = "Times New Roman";
22
+ var DEFAULT_FONT_WEIGHT = "normal";
23
+ var EDGE_LIGHT = "#ffffff";
24
+ var EDGE_DARK = "#020000";
25
+ var EDGE_PRESS_LIGHT = "#EFEFEF";
26
+ var EDGE_PRESS_DARK = "#5F5F5F";
27
+ var normalizeButtonFill = function(fill, fallback = DEFAULT_FILL) {
28
+ return normalizeColor(fill === "" || fill === null || typeof fill === "undefined" ? fallback : fill);
29
+ };
30
+ var normalizeButtonTextFill = function(fill) {
31
+ return normalizeColor(fill === "" || fill === null || typeof fill === "undefined" ? "#000000" : fill);
32
+ };
33
+ var toTextWrap = function(wordWrap) {
34
+ if (wordWrap === "char") return "break";
35
+ return "none";
36
+ };
37
+ var toWordWrap = function(textWrap) {
38
+ if (textWrap === "break") return "char";
39
+ if (textWrap === "none") return "none";
40
+ return "word";
41
+ };
42
+ var requestRubikRender = function(obj) {
43
+ const leafer = obj && obj.leafer;
44
+ if (leafer) {
45
+ leafer.requestRender();
46
+ }
47
+ };
48
+ var Button = class extends Box {
49
+ get __tag() {
50
+ return "Button";
51
+ }
52
+ constructor(data) {
53
+ let {
54
+ text,
55
+ fontSize,
56
+ fontWeight,
57
+ fontColor,
58
+ fontFamily,
59
+ fill,
60
+ backgroundColor,
61
+ buttonScaleBaseWidth,
62
+ buttonScaleBaseHeight,
63
+ wordWrap,
64
+ down,
65
+ ...buttonData
66
+ } = data || {};
67
+ if ((fontColor === void 0 || fontColor === null) && backgroundColor !== void 0 && fill !== void 0 && fill !== backgroundColor) {
68
+ fontColor = fill;
69
+ }
70
+ super({
71
+ // button: true,
72
+ ...buttonData,
73
+ cursor: "pointer"
74
+ });
75
+ this.childlessJSON = true;
76
+ this.defaultFill = normalizeButtonFill(backgroundColor === void 0 ? fill : backgroundColor);
77
+ this.originalFill = this.defaultFill;
78
+ this.buttonScaleBaseWidth = buttonScaleBaseWidth || this.width || 0;
79
+ this.buttonScaleBaseHeight = buttonScaleBaseHeight || this.height || 0;
80
+ this._wordWrap = wordWrap || "word";
81
+ this._down = !!down;
82
+ fontSize = fontSize || 12;
83
+ this.fill = this.originalFill;
84
+ this.hoverElement = new Rect({
85
+ x: 0,
86
+ y: 0,
87
+ width: this.width,
88
+ height: this.height,
89
+ fill: "rgba(64,32,125,0.16)",
90
+ stroke: "transparent",
91
+ strokeWidth: 0,
92
+ visible: false
93
+ });
94
+ this.textElement = new Text({
95
+ text,
96
+ fontSize,
97
+ fill: normalizeButtonTextFill(fontColor),
98
+ textAlign: "center",
99
+ verticalAlign: "middle",
100
+ fontFamily: fontFamily || DEFAULT_FONT,
101
+ textWrap: toTextWrap(this._wordWrap),
102
+ x: 0,
103
+ y: 0,
104
+ width: this.width,
105
+ height: this.height,
106
+ fontWeight: fontWeight || DEFAULT_FONT_WEIGHT
107
+ });
108
+ this.topLine = new Line({
109
+ points: [0, 0, this.width, 0],
110
+ stroke: EDGE_LIGHT,
111
+ strokeWidth: 0.5
112
+ });
113
+ this.leftLine = new Line({
114
+ points: [0, 0, 0, this.height],
115
+ stroke: EDGE_LIGHT,
116
+ strokeWidth: 0.5
117
+ });
118
+ this.rightLine = new Line({
119
+ points: [this.width, 0, this.width, this.height],
120
+ stroke: EDGE_DARK,
121
+ strokeWidth: 0.5
122
+ });
123
+ this.bottomLine = new Line({
124
+ points: [0, this.height, this.width, this.height],
125
+ stroke: EDGE_DARK,
126
+ strokeWidth: 0.5
127
+ });
128
+ this.add(this.hoverElement);
129
+ this.add(this.topLine);
130
+ this.add(this.bottomLine);
131
+ this.add(this.rightLine);
132
+ this.add(this.leftLine);
133
+ this.add(this.textElement);
134
+ this.updateLayout();
135
+ }
136
+ get type() {
137
+ return "button";
138
+ }
139
+ set type(value) {
140
+ this._type = value;
141
+ }
142
+ get backgroundColor() {
143
+ return this.originalFill;
144
+ }
145
+ set backgroundColor(value) {
146
+ this.setButtonFill(value);
147
+ }
148
+ set(data, transition) {
149
+ if (typeof data === "string") {
150
+ data = { [data]: transition };
151
+ }
152
+ if (!data || typeof data !== "object") {
153
+ return super.set(data, transition);
154
+ }
155
+ const hasBackgroundColor = Object.prototype.hasOwnProperty.call(data, "backgroundColor");
156
+ const hasFill = Object.prototype.hasOwnProperty.call(data, "fill");
157
+ const next = { ...data };
158
+ if (hasBackgroundColor) {
159
+ delete next.backgroundColor;
160
+ }
161
+ if (hasFill) {
162
+ delete next.fill;
163
+ }
164
+ if (Object.prototype.hasOwnProperty.call(next, "wordWrap")) {
165
+ this.wordWrap = next.wordWrap;
166
+ delete next.wordWrap;
167
+ }
168
+ if (Object.prototype.hasOwnProperty.call(next, "splitByGrapheme")) {
169
+ if (!Object.prototype.hasOwnProperty.call(data, "wordWrap")) {
170
+ this.wordWrap = data.splitByGrapheme ? "char" : this.wordWrap;
171
+ }
172
+ delete next.splitByGrapheme;
173
+ }
174
+ if (Object.prototype.hasOwnProperty.call(next, "down")) {
175
+ this.down = !!next.down;
176
+ delete next.down;
177
+ }
178
+ if (Object.prototype.hasOwnProperty.call(next, "text")) {
179
+ this.text = next.text === void 0 || next.text === null ? "" : String(next.text);
180
+ delete next.text;
181
+ }
182
+ if (Object.prototype.hasOwnProperty.call(next, "fontSize")) {
183
+ this.fontSize = next.fontSize;
184
+ delete next.fontSize;
185
+ }
186
+ if (Object.prototype.hasOwnProperty.call(next, "fontColor")) {
187
+ this.fontColor = next.fontColor;
188
+ delete next.fontColor;
189
+ }
190
+ if (Object.prototype.hasOwnProperty.call(next, "fontFamily")) {
191
+ this.fontFamily = next.fontFamily;
192
+ delete next.fontFamily;
193
+ }
194
+ if (Object.prototype.hasOwnProperty.call(next, "fontWeight")) {
195
+ this.fontWeight = next.fontWeight;
196
+ delete next.fontWeight;
197
+ }
198
+ const result = Object.keys(next).length ? super.set(next, transition) : this;
199
+ if (hasBackgroundColor) {
200
+ this.setButtonFill(data.backgroundColor);
201
+ } else if (hasFill) {
202
+ this.setButtonFill(data.fill);
203
+ }
204
+ if (data && (Object.prototype.hasOwnProperty.call(data, "width") || Object.prototype.hasOwnProperty.call(data, "height") || Object.prototype.hasOwnProperty.call(data, "strokeWidth"))) {
205
+ this.updateLayout();
206
+ }
207
+ return result;
208
+ }
209
+ setButtonFill(value) {
210
+ this.originalFill = normalizeButtonFill(value, this.defaultFill || DEFAULT_FILL);
211
+ this.fill = this.originalFill;
212
+ requestRubikRender(this);
213
+ return this;
214
+ }
215
+ setButtonScale(key, value) {
216
+ value = typeof value === "undefined" ? 1 : value;
217
+ if (key === "scaleX") {
218
+ this.width = (this.buttonScaleBaseWidth || this.width || 0) * Math.abs(value);
219
+ } else {
220
+ this.height = (this.buttonScaleBaseHeight || this.height || 0) * Math.abs(value);
221
+ }
222
+ this.updateLayout();
223
+ requestRubikRender(this);
224
+ return this;
225
+ }
226
+ updateLayout() {
227
+ const width = this.width || 0;
228
+ const height = this.height || 0;
229
+ const strokeWidth = Math.min(4, Math.max(0.5, Number(this.strokeWidth) || 1));
230
+ this.textElement && this.textElement.set({ width, height });
231
+ this.hoverElement && this.hoverElement.set({ width, height });
232
+ this.topLine && this.topLine.set({ points: [0, 0, width, 0], strokeWidth });
233
+ this.leftLine && this.leftLine.set({ points: [0, 0, 0, height], strokeWidth });
234
+ this.rightLine && this.rightLine.set({ points: [width, 0, width, height], strokeWidth });
235
+ this.bottomLine && this.bottomLine.set({ points: [0, height, width, height], strokeWidth });
236
+ this.updatePressState();
237
+ }
238
+ get down() {
239
+ return !!this._down;
240
+ }
241
+ set down(value) {
242
+ this._down = !!value;
243
+ this.updatePressState();
244
+ requestRubikRender(this);
245
+ }
246
+ // 运行态唯一的交互状态入口: 悬停/按下一起给, 元素自己不再监听指针事件。
247
+ // Fabric 里被其它图元盖住的按钮也会变色, 所以状态由运行态按穿透目标统一驱动。
248
+ setInteraction(state) {
249
+ const blocked = !!this.disabled;
250
+ const hovered = !blocked && !!(state && state.hovered);
251
+ const pressed = !blocked && !!(state && state.pressed);
252
+ if (this._hovered === hovered && this._pressed === pressed) return;
253
+ this._hovered = hovered;
254
+ this._pressed = pressed;
255
+ this.updatePressState();
256
+ requestRubikRender(this);
257
+ }
258
+ // 按下 = 文字右下移 1px + 边框倒角翻转 + 悬停遮罩隐藏, 与 Fabric Button 一致
259
+ updatePressState() {
260
+ const pressed = this._down || !!this._pressed;
261
+ const lightEdge = pressed ? EDGE_PRESS_DARK : EDGE_LIGHT;
262
+ const darkEdge = pressed ? EDGE_PRESS_LIGHT : EDGE_DARK;
263
+ if (this.topLine && this.topLine.stroke !== lightEdge) this.topLine.stroke = lightEdge;
264
+ if (this.leftLine && this.leftLine.stroke !== lightEdge) this.leftLine.stroke = lightEdge;
265
+ if (this.rightLine && this.rightLine.stroke !== darkEdge) this.rightLine.stroke = darkEdge;
266
+ if (this.bottomLine && this.bottomLine.stroke !== darkEdge) this.bottomLine.stroke = darkEdge;
267
+ if (this.hoverElement) this.hoverElement.visible = !!this._hovered && !pressed;
268
+ if (this.textElement) {
269
+ const offset = pressed ? 1 : 0;
270
+ this.textElement.x = offset;
271
+ this.textElement.y = offset;
272
+ }
273
+ }
274
+ toJSON(options) {
275
+ const data = super.toJSON(options);
276
+ delete data.children;
277
+ data.type = "button";
278
+ data.text = this.text;
279
+ data.fontSize = this.fontSize;
280
+ data.fontFamily = this.fontFamily;
281
+ data.fontWeight = this.fontWeight;
282
+ data.fontColor = this.fontColor;
283
+ data.fill = this.originalFill;
284
+ data.backgroundColor = this.originalFill;
285
+ data.buttonScaleBaseWidth = this.buttonScaleBaseWidth;
286
+ data.buttonScaleBaseHeight = this.buttonScaleBaseHeight;
287
+ data.wordWrap = this.wordWrap;
288
+ data.down = this.down;
289
+ return data;
290
+ }
291
+ get wordWrap() {
292
+ return this._wordWrap || toWordWrap(this.textElement && this.textElement.textWrap);
293
+ }
294
+ set wordWrap(value) {
295
+ this._wordWrap = value || "word";
296
+ if (this.textElement) {
297
+ this.textElement.textWrap = toTextWrap(this._wordWrap);
298
+ requestRubikRender(this);
299
+ }
300
+ }
301
+ get text() {
302
+ return this.textElement.text;
303
+ }
304
+ set text(value) {
305
+ this.textElement.text = value;
306
+ requestRubikRender(this);
307
+ }
308
+ get fontSize() {
309
+ return this.textElement.fontSize;
310
+ }
311
+ set fontSize(value) {
312
+ this.textElement.fontSize = value;
313
+ }
314
+ get fontFamily() {
315
+ return this.textElement.fontFamily;
316
+ }
317
+ set fontFamily(value) {
318
+ this.textElement.fontFamily = value;
319
+ }
320
+ get fontColor() {
321
+ return this.textElement.fill;
322
+ }
323
+ set fontColor(value) {
324
+ this.textElement.fill = normalizeButtonTextFill(value);
325
+ requestRubikRender(this);
326
+ }
327
+ get fontWeight() {
328
+ return this.textElement.fontWeight;
329
+ }
330
+ set fontWeight(value) {
331
+ this.textElement.fontWeight = value;
332
+ }
333
+ };
334
+ Button.registerUI();
335
+ var button_default = Button;
336
+
337
+ // src/bar.js
338
+ import { Box as Box2, Path, PropertyEvent, Rect as Rect2 } from "leafer-ui";
339
+ var clamp = function(value, min, max) {
340
+ value = Number(value) || 0;
341
+ return Math.max(min, Math.min(max, value));
342
+ };
343
+ var normalizeFill = function(fill) {
344
+ return fill === "" || fill === null || typeof fill === "undefined" ? "transparent" : fill;
345
+ };
346
+ var hasOwn = function(data, key) {
347
+ return data && Object.prototype.hasOwnProperty.call(data, key);
348
+ };
349
+ var requestFrame = function(callback) {
350
+ if (typeof window !== "undefined" && window.requestAnimationFrame) {
351
+ return window.requestAnimationFrame(callback);
352
+ }
353
+ return setTimeout(() => callback(Date.now()), 16);
354
+ };
355
+ var cancelFrame = function(frameId) {
356
+ if (!frameId) {
357
+ return;
358
+ }
359
+ if (typeof window !== "undefined" && window.cancelAnimationFrame) {
360
+ window.cancelAnimationFrame(frameId);
361
+ } else {
362
+ clearTimeout(frameId);
363
+ }
364
+ };
365
+ var getNow = function() {
366
+ if (typeof performance !== "undefined" && performance.now) {
367
+ return performance.now();
368
+ }
369
+ return Date.now();
370
+ };
371
+ var requestRubikRender2 = function(obj) {
372
+ const leafer = obj && obj.leafer;
373
+ if (leafer) {
374
+ leafer.requestRender();
375
+ }
376
+ };
377
+ var Bar = class extends Box2 {
378
+ get __tag() {
379
+ return "Bar";
380
+ }
381
+ constructor(data = {}) {
382
+ const inputData = { ...data };
383
+ delete inputData.children;
384
+ delete inputData.tag;
385
+ const {
386
+ fill,
387
+ stroke,
388
+ strokeWidth,
389
+ backgroundFill,
390
+ backgroundColor,
391
+ fpct,
392
+ fdir,
393
+ fstyle,
394
+ ...barData
395
+ } = inputData;
396
+ super({
397
+ ...barData,
398
+ hitFill: "all",
399
+ overflow: "hide",
400
+ cursor: barData.cursor
401
+ });
402
+ this.childlessJSON = true;
403
+ this._barFill = normalizeFill(fill);
404
+ this._barStroke = stroke;
405
+ this._barStrokeWidth = strokeWidth || 1;
406
+ this._backgroundFill = backgroundFill || backgroundColor || "transparent";
407
+ this._fpct = fpct === void 0 ? 0 : Number(fpct) || 0;
408
+ this._fdir = Number(fdir) || 0;
409
+ this._fstyle = fstyle || "rect";
410
+ this.backgroundElement = new Rect2({
411
+ x: 0,
412
+ y: 0,
413
+ width: this.width || 0,
414
+ height: this.height || 0,
415
+ fill: this._backgroundFill,
416
+ stroke: "transparent",
417
+ strokeWidth: 0
418
+ });
419
+ this.fillElement = new Path({
420
+ fill: this._barFill,
421
+ stroke: "transparent",
422
+ strokeWidth: 0
423
+ });
424
+ this.strokeElement = new Path({
425
+ fill: "transparent",
426
+ stroke: this._barStroke,
427
+ strokeWidth: this._barStrokeWidth
428
+ });
429
+ this.add(this.backgroundElement);
430
+ this.add(this.fillElement);
431
+ this.add(this.strokeElement);
432
+ this.updateBar();
433
+ this.on(PropertyEvent.CHANGE, (event) => {
434
+ const name = event && event.attrName;
435
+ if (!name || name === "width" || name === "height") this.updateBar();
436
+ });
437
+ }
438
+ get type() {
439
+ return "bar";
440
+ }
441
+ set type(value) {
442
+ this._type = value;
443
+ }
444
+ get fill() {
445
+ return this._barFill;
446
+ }
447
+ set fill(value) {
448
+ this._barFill = normalizeFill(value);
449
+ if (this.fillElement) {
450
+ this.fillElement.fill = this._barFill;
451
+ }
452
+ }
453
+ get stroke() {
454
+ return this._barStroke;
455
+ }
456
+ set stroke(value) {
457
+ this._barStroke = value;
458
+ if (this.strokeElement) {
459
+ this.strokeElement.stroke = value;
460
+ }
461
+ }
462
+ get strokeWidth() {
463
+ return this._barStrokeWidth;
464
+ }
465
+ set strokeWidth(value) {
466
+ this._barStrokeWidth = value || 0;
467
+ if (this.strokeElement) {
468
+ this.strokeElement.strokeWidth = this._barStrokeWidth;
469
+ }
470
+ }
471
+ get backgroundFill() {
472
+ return this._backgroundFill;
473
+ }
474
+ set backgroundFill(value) {
475
+ this._backgroundFill = value || "transparent";
476
+ if (this.backgroundElement) {
477
+ this.backgroundElement.fill = this._backgroundFill;
478
+ }
479
+ }
480
+ get backgroundColor() {
481
+ return this._backgroundFill;
482
+ }
483
+ set backgroundColor(value) {
484
+ this.backgroundFill = value;
485
+ }
486
+ get fpct() {
487
+ return this._fpct;
488
+ }
489
+ set fpct(value) {
490
+ this._fpct = Number(value) || 0;
491
+ this.updateBar();
492
+ }
493
+ get fdir() {
494
+ return this._fdir;
495
+ }
496
+ set fdir(value) {
497
+ this._fdir = Number(value) || 0;
498
+ this.updateBar();
499
+ }
500
+ get fstyle() {
501
+ return this._fstyle;
502
+ }
503
+ set fstyle(value) {
504
+ this._fstyle = value || "rect";
505
+ this.updateBar();
506
+ }
507
+ set(data, transition) {
508
+ if (typeof data === "string") {
509
+ data = { [data]: transition };
510
+ }
511
+ const baseData = { ...data || {} };
512
+ if (hasOwn(data, "fill")) {
513
+ this._barFill = normalizeFill(data.fill);
514
+ delete baseData.fill;
515
+ }
516
+ if (hasOwn(data, "stroke")) {
517
+ this._barStroke = data.stroke;
518
+ delete baseData.stroke;
519
+ }
520
+ if (hasOwn(data, "strokeWidth")) {
521
+ this._barStrokeWidth = data.strokeWidth || 0;
522
+ delete baseData.strokeWidth;
523
+ }
524
+ if (hasOwn(data, "backgroundFill")) {
525
+ this._backgroundFill = normalizeFill(data.backgroundFill);
526
+ delete baseData.backgroundFill;
527
+ }
528
+ if (hasOwn(data, "backgroundColor")) {
529
+ this._backgroundFill = normalizeFill(data.backgroundColor);
530
+ delete baseData.backgroundColor;
531
+ }
532
+ if (hasOwn(data, "fpct")) {
533
+ this._fpct = Number(data.fpct) || 0;
534
+ this.fpctSeted = true;
535
+ delete baseData.fpct;
536
+ }
537
+ if (hasOwn(data, "fdir")) {
538
+ this._fdir = Number(data.fdir) || 0;
539
+ delete baseData.fdir;
540
+ }
541
+ if (hasOwn(data, "fstyle")) {
542
+ this._fstyle = data.fstyle || "rect";
543
+ delete baseData.fstyle;
544
+ }
545
+ const result = super.set(baseData, transition);
546
+ this.updateBar();
547
+ return result;
548
+ }
549
+ setFpct(value, option = {}) {
550
+ const target = Number(value) || 0;
551
+ const loop = this.leafer && this.leafer.__loop || 0;
552
+ if (option.animate === false || !this.fpctSeted || loop < 4) {
553
+ this.fpctSeted = true;
554
+ this.cancelFpctAnimation();
555
+ this._fpct = target;
556
+ this.updateBar();
557
+ return this;
558
+ }
559
+ return this.animateFpct(target, option);
560
+ }
561
+ animateFpct(target, option = {}) {
562
+ const start = Number(this._fpct) || 0;
563
+ const duration = Math.max(0, Number(option.duration) || 500);
564
+ if (duration === 0 || start === target) {
565
+ this.cancelFpctAnimation();
566
+ this._fpct = target;
567
+ this.updateBar();
568
+ return this;
569
+ }
570
+ this.fpctSeted = true;
571
+ this.cancelFpctAnimation();
572
+ const startTime = getNow();
573
+ const step = (time) => {
574
+ const progress = Math.min(1, (time - startTime) / duration);
575
+ this._fpct = start + (target - start) * progress;
576
+ this.updateBar();
577
+ if (progress < 1) {
578
+ this._fpctFrame = requestFrame(step);
579
+ } else {
580
+ this._fpctFrame = null;
581
+ }
582
+ };
583
+ this._fpctFrame = requestFrame(step);
584
+ return this;
585
+ }
586
+ cancelFpctAnimation() {
587
+ cancelFrame(this._fpctFrame);
588
+ this._fpctFrame = null;
589
+ }
590
+ toJSON(options) {
591
+ const data = super.toJSON(options);
592
+ data.type = "bar";
593
+ data.fill = this._barFill;
594
+ data.stroke = this._barStroke;
595
+ data.strokeWidth = this._barStrokeWidth;
596
+ data.backgroundFill = this._backgroundFill;
597
+ data.backgroundColor = this._backgroundFill;
598
+ data.fpct = this._fpct;
599
+ data.fdir = this._fdir;
600
+ data.fstyle = this._fstyle;
601
+ return data;
602
+ }
603
+ updateBar() {
604
+ if (!this.fillElement || !this.strokeElement || !this.backgroundElement) {
605
+ return;
606
+ }
607
+ const width = Math.max(Number(this.width) || 0, 0);
608
+ const height = Math.max(Number(this.height) || 0, 0);
609
+ this.backgroundElement.set({
610
+ x: 0,
611
+ y: 0,
612
+ width,
613
+ height,
614
+ fill: this._backgroundFill
615
+ });
616
+ if (this._fstyle === "circle") {
617
+ this.updateCircleBar(width, height);
618
+ } else {
619
+ this.updateRectBar(width, height);
620
+ }
621
+ requestRubikRender2(this);
622
+ }
623
+ updateRectBar(width, height) {
624
+ let x = 0;
625
+ let y = 0;
626
+ let w = width;
627
+ let h = height;
628
+ let fdir = this._fdir % 5;
629
+ if (fdir < 0) {
630
+ fdir += 5;
631
+ }
632
+ let fpct = clamp(this._fpct, fdir < 4 ? 0 : -1, 1);
633
+ switch (fdir) {
634
+ case 1:
635
+ w = width * fpct;
636
+ break;
637
+ case 2:
638
+ h = height * fpct;
639
+ break;
640
+ case 3:
641
+ w = width * fpct;
642
+ x = width - w;
643
+ break;
644
+ case 4:
645
+ if (fpct >= 0) {
646
+ h = height / 2 * fpct;
647
+ y = height / 2 - h;
648
+ } else {
649
+ h = height / 2 * -fpct;
650
+ y = height / 2;
651
+ }
652
+ break;
653
+ case 0:
654
+ default:
655
+ h = height * fpct;
656
+ y = height - h;
657
+ break;
658
+ }
659
+ this.fillElement.set({
660
+ path: this.rectPath(x, y, w, h),
661
+ fill: this._barFill
662
+ });
663
+ this.strokeElement.set({
664
+ path: this.rectPath(0, 0, width, height),
665
+ stroke: this._barStroke,
666
+ strokeWidth: this._barStrokeWidth
667
+ });
668
+ }
669
+ updateCircleBar(width, height) {
670
+ const fpct = clamp(this._fpct, 0, 1);
671
+ let fdir = this._fdir % 4;
672
+ if (fdir < 0) {
673
+ fdir += 4;
674
+ }
675
+ this.fillElement.set({
676
+ path: this.circleFillPath(width, height, fpct, fdir),
677
+ fill: this._barFill
678
+ });
679
+ this.strokeElement.set({
680
+ path: this.ellipsePath(width, height),
681
+ stroke: this._barStroke,
682
+ strokeWidth: this._barStrokeWidth
683
+ });
684
+ }
685
+ rectPath(x, y, width, height) {
686
+ if (width <= 0 || height <= 0) {
687
+ return "";
688
+ }
689
+ return `M ${x} ${y} L ${x + width} ${y} L ${x + width} ${y + height} L ${x} ${y + height} Z`;
690
+ }
691
+ ellipsePath(width, height) {
692
+ if (width <= 0 || height <= 0) {
693
+ return "";
694
+ }
695
+ const rx = width / 2;
696
+ const ry = height / 2;
697
+ const cx = rx;
698
+ const cy = ry;
699
+ return `M ${cx - rx} ${cy} A ${rx} ${ry} 0 1 0 ${cx + rx} ${cy} A ${rx} ${ry} 0 1 0 ${cx - rx} ${cy} Z`;
700
+ }
701
+ circleFillPath(width, height, fpct, fdir) {
702
+ if (width <= 0 || height <= 0 || fpct <= 0) {
703
+ return "";
704
+ }
705
+ if (fpct >= 1) {
706
+ return this.ellipsePath(width, height);
707
+ }
708
+ const rx = width / 2;
709
+ const ry = height / 2;
710
+ const cx = rx;
711
+ const cy = ry;
712
+ let startAngle = Math.asin((0.5 - fpct) * 2);
713
+ let endAngle = Math.PI - startAngle;
714
+ startAngle += Math.PI / 2 * fdir;
715
+ endAngle += Math.PI / 2 * fdir;
716
+ const start = this.ellipsePoint(cx, cy, rx, ry, startAngle);
717
+ const end = this.ellipsePoint(cx, cy, rx, ry, endAngle);
718
+ const largeArc = endAngle - startAngle > Math.PI ? 1 : 0;
719
+ return `M ${start.x} ${start.y} A ${rx} ${ry} 0 ${largeArc} 1 ${end.x} ${end.y} Z`;
720
+ }
721
+ ellipsePoint(cx, cy, rx, ry, angle) {
722
+ return {
723
+ x: cx + Math.cos(angle) * rx,
724
+ y: cy + Math.sin(angle) * ry
725
+ };
726
+ }
727
+ };
728
+ Bar.registerUI();
729
+ var bar_default = Bar;
730
+
731
+ // src/circle.js
732
+ import { Path as Path2 } from "leafer-ui";
733
+ var TWO_PI = Math.PI * 2;
734
+ var buildPath = function(width, height, startAngle, endAngle, filled) {
735
+ const rx = Math.max(0, Number(width) || 0) / 2;
736
+ const ry = Math.max(0, Number(height) || 0) / 2;
737
+ if (!rx || !ry) {
738
+ return "";
739
+ }
740
+ const cx = rx;
741
+ const cy = ry;
742
+ let start = Number(startAngle) || 0;
743
+ let end = Number(endAngle) || 0;
744
+ if (Math.abs(end - start) >= TWO_PI - 1e-4) {
745
+ return `M ${cx - rx} ${cy} A ${rx} ${ry} 0 1 0 ${cx + rx} ${cy} A ${rx} ${ry} 0 1 0 ${cx - rx} ${cy} Z`;
746
+ }
747
+ if (start === end) {
748
+ return "";
749
+ }
750
+ if (Math.abs(end - start) > TWO_PI) {
751
+ end = start + TWO_PI * Math.sign(end - start);
752
+ }
753
+ const sx = cx + Math.cos(start) * rx;
754
+ const sy = cy + Math.sin(start) * ry;
755
+ const ex = cx + Math.cos(end) * rx;
756
+ const ey = cy + Math.sin(end) * ry;
757
+ const largeArc = Math.abs(end - start) > Math.PI ? 1 : 0;
758
+ const sweep = end > start ? 1 : 0;
759
+ if (filled) {
760
+ return `M ${cx} ${cy} L ${sx} ${sy} A ${rx} ${ry} 0 ${largeArc} ${sweep} ${ex} ${ey} Z`;
761
+ }
762
+ return `M ${sx} ${sy} A ${rx} ${ry} 0 ${largeArc} ${sweep} ${ex} ${ey}`;
763
+ };
764
+ var Circle = class extends Path2 {
765
+ get __tag() {
766
+ return "Circle";
767
+ }
768
+ constructor(data = {}) {
769
+ const input = { ...data };
770
+ const startAngle = input.startAngle === void 0 ? 0 : input.startAngle;
771
+ const endAngle = input.endAngle === void 0 ? TWO_PI : input.endAngle;
772
+ const filled = input.fill !== "" && input.fill !== void 0 && input.fill !== null && input.fill !== "transparent";
773
+ super({
774
+ ...input,
775
+ path: buildPath(input.width, input.height, startAngle, endAngle, filled)
776
+ });
777
+ this.startAngle = startAngle;
778
+ this.endAngle = endAngle;
779
+ this._filled = filled;
780
+ }
781
+ get type() {
782
+ return "circle";
783
+ }
784
+ set type(value) {
785
+ this._type = value;
786
+ }
787
+ get startAngle() {
788
+ return this._startAngle || 0;
789
+ }
790
+ set startAngle(value) {
791
+ this._startAngle = Number(value) || 0;
792
+ this.updateArc();
793
+ }
794
+ get endAngle() {
795
+ return this._endAngle === void 0 ? TWO_PI : this._endAngle;
796
+ }
797
+ set endAngle(value) {
798
+ this._endAngle = Number(value) || 0;
799
+ this.updateArc();
800
+ }
801
+ set(data, transition) {
802
+ if (typeof data === "string") {
803
+ data = { [data]: transition };
804
+ }
805
+ if (data && typeof data === "object") {
806
+ if (Object.prototype.hasOwnProperty.call(data, "startAngle")) {
807
+ this._startAngle = Number(data.startAngle) || 0;
808
+ }
809
+ if (Object.prototype.hasOwnProperty.call(data, "endAngle")) {
810
+ this._endAngle = Number(data.endAngle) || 0;
811
+ }
812
+ if (Object.prototype.hasOwnProperty.call(data, "fill")) {
813
+ const fill = data.fill;
814
+ this._filled = fill !== "" && fill !== void 0 && fill !== null && fill !== "transparent";
815
+ }
816
+ }
817
+ const result = super.set(data, transition);
818
+ if (data && typeof data === "object" && (Object.prototype.hasOwnProperty.call(data, "width") || Object.prototype.hasOwnProperty.call(data, "height") || Object.prototype.hasOwnProperty.call(data, "startAngle") || Object.prototype.hasOwnProperty.call(data, "endAngle") || Object.prototype.hasOwnProperty.call(data, "fill"))) {
819
+ this.updateArc();
820
+ }
821
+ return result;
822
+ }
823
+ updateArc() {
824
+ this.path = buildPath(this.width, this.height, this.startAngle, this.endAngle, this._filled);
825
+ }
826
+ toJSON(options) {
827
+ const data = super.toJSON(options);
828
+ data.type = "circle";
829
+ data.startAngle = this.startAngle;
830
+ data.endAngle = this.endAngle;
831
+ return data;
832
+ }
833
+ };
834
+ Circle.registerUI();
835
+ var circle_default = Circle;
836
+
837
+ // src/layer.js
838
+ import { Group } from "leafer-ui";
839
+ var Layer = class extends Group {
840
+ get __tag() {
841
+ return "Layer";
842
+ }
843
+ constructor(data = {}) {
844
+ const next = { ...data || {} };
845
+ delete next.x;
846
+ delete next.y;
847
+ delete next.scaleX;
848
+ delete next.scaleY;
849
+ delete next.rotation;
850
+ Object.keys(next).forEach((key) => {
851
+ if (next[key] === void 0) delete next[key];
852
+ });
853
+ next.x = 0;
854
+ next.y = 0;
855
+ next.editable = false;
856
+ next.draggable = false;
857
+ next.hittable = true;
858
+ next.hitChildren = true;
859
+ super(next);
860
+ }
861
+ get type() {
862
+ return "layer";
863
+ }
864
+ set type(value) {
865
+ this._type = value;
866
+ }
867
+ };
868
+ Layer.registerUI();
869
+ var layer_default = Layer;
870
+
871
+ // src/lib.js
872
+ import { Group as Group2 } from "leafer-ui";
873
+ var Lib = class extends Group2 {
874
+ get __tag() {
875
+ return "Lib";
876
+ }
877
+ constructor(data = {}) {
878
+ const {
879
+ libName,
880
+ originParam,
881
+ param,
882
+ ...groupData
883
+ } = data || {};
884
+ super(groupData);
885
+ this.libName = libName || "";
886
+ this.originParam = originParam || {};
887
+ this.param = param || {};
888
+ }
889
+ get type() {
890
+ return "lib";
891
+ }
892
+ set type(value) {
893
+ this._type = value;
894
+ }
895
+ };
896
+ Lib.registerUI();
897
+ var lib_default = Lib;
898
+
899
+ // src/text.js
900
+ import { Box as Box3, Text as Text2 } from "leafer-ui";
901
+ var TEXT_PROPS = [
902
+ "text",
903
+ "fontSize",
904
+ "fontFamily",
905
+ "fontWeight",
906
+ "fontStyle",
907
+ "letterSpacing",
908
+ "lineHeight",
909
+ "textAlign",
910
+ "verticalAlign",
911
+ "textDecoration",
912
+ "textWrap",
913
+ "fill",
914
+ "stroke",
915
+ "strokeWidth",
916
+ "shadow",
917
+ "boxStyle",
918
+ "textBackgroundColor"
919
+ ];
920
+ var DEFAULT_FONT_SIZE = 12;
921
+ var DEFAULT_FILL2 = "#000000";
922
+ var pickTextProps = function(data) {
923
+ const props = {};
924
+ TEXT_PROPS.forEach((key) => {
925
+ if (data[key] !== void 0) {
926
+ props[key] = data[key];
927
+ }
928
+ });
929
+ return props;
930
+ };
931
+ var IText = class extends Box3 {
932
+ get __tag() {
933
+ return "IText";
934
+ }
935
+ constructor(data = {}) {
936
+ const input = data || {};
937
+ const textData = pickTextProps(input);
938
+ const groupData = { ...input };
939
+ TEXT_PROPS.forEach((key) => {
940
+ delete groupData[key];
941
+ });
942
+ delete groupData.children;
943
+ super({ ...groupData, fill: "transparent" });
944
+ this.childlessJSON = true;
945
+ this.editInner = "IText";
946
+ this.textBox = true;
947
+ this.textElement = new Text2({
948
+ x: 0,
949
+ y: 0,
950
+ around: "top-left",
951
+ textWrap: "none",
952
+ fontSize: DEFAULT_FONT_SIZE,
953
+ fill: DEFAULT_FILL2,
954
+ hittable: false,
955
+ draggable: false,
956
+ editable: false,
957
+ ...textData
958
+ });
959
+ this.add(this.textElement);
960
+ this.updateText();
961
+ }
962
+ set(data, transition) {
963
+ if (typeof data === "string") {
964
+ data = { [data]: transition };
965
+ }
966
+ if (!data || typeof data !== "object") {
967
+ return super.set(data, transition);
968
+ }
969
+ const textData = pickTextProps(data);
970
+ const rest = { ...data };
971
+ TEXT_PROPS.forEach((key) => {
972
+ delete rest[key];
973
+ });
974
+ const result = Object.keys(rest).length ? super.set(rest, transition) : this;
975
+ if (this.textElement) {
976
+ if (Object.keys(textData).length) {
977
+ this.textElement.set(textData);
978
+ }
979
+ if (Object.keys(textData).length || Object.prototype.hasOwnProperty.call(rest, "width") || Object.prototype.hasOwnProperty.call(rest, "height")) {
980
+ this.updateText();
981
+ }
982
+ }
983
+ return result;
984
+ }
985
+ /**
986
+ * 换行模式要固定宽度才能断行;不换行时交还内容自适应。
987
+ * 盒子尺寸也在这里同步给内部文字。
988
+ */
989
+ updateText() {
990
+ const text = this.textElement;
991
+ if (!text) return;
992
+ const { width } = this.boxSize();
993
+ if (text.textWrap !== "none" && width > 0) {
994
+ if (Number(text.width) !== width) {
995
+ text.width = width;
996
+ }
997
+ } else if (text.width !== void 0 && text.width !== null) {
998
+ text.width = null;
999
+ }
1000
+ this.syncFit();
1001
+ }
1002
+ /** 盒子尺寸:转换/保存下来的宽高是权威值,缺省时按内容走 */
1003
+ boxSize() {
1004
+ const input = this.__;
1005
+ return {
1006
+ width: Number(input.__getInput("width")) || 0,
1007
+ height: Number(input.__getInput("height")) || 0
1008
+ };
1009
+ }
1010
+ /** 按盒子宽高拉伸内部文字,让文字铺满包围盒(文字会被拉变形) */
1011
+ syncFit() {
1012
+ const text = this.textElement;
1013
+ const layout = text && text.__layout;
1014
+ if (!layout) return;
1015
+ if (text.x) text.x = 0;
1016
+ if (text.y) text.y = 0;
1017
+ const { width, height } = this.boxSize();
1018
+ const natural = layout.boxBounds;
1019
+ if (!width || !height || !natural.width || !natural.height) return;
1020
+ const scaleX = width / natural.width;
1021
+ const scaleY = height / natural.height;
1022
+ if (Math.abs(Number(text.scaleX) - scaleX) > 1e-4) text.scaleX = scaleX;
1023
+ if (Math.abs(Number(text.scaleY) - scaleY) > 1e-4) text.scaleY = scaleY;
1024
+ }
1025
+ // 排版发生在布局阶段:按盒子宽高重新拉伸内部文字(Box 的包围盒就是宽高,不用再改)
1026
+ __updateBoxBounds(secondLayout, bounds) {
1027
+ this.syncFit();
1028
+ super.__updateBoxBounds(secondLayout, bounds);
1029
+ }
1030
+ toJSON(options) {
1031
+ const data = super.toJSON(options);
1032
+ const text = this.textElement;
1033
+ if (text) {
1034
+ TEXT_PROPS.forEach((key) => {
1035
+ const value = text[key];
1036
+ if (value !== void 0) {
1037
+ data[key] = value;
1038
+ }
1039
+ });
1040
+ }
1041
+ delete data.children;
1042
+ return data;
1043
+ }
1044
+ };
1045
+ TEXT_PROPS.forEach((key) => {
1046
+ Object.defineProperty(IText.prototype, key, {
1047
+ configurable: true,
1048
+ get() {
1049
+ const text = this.textElement;
1050
+ return text ? text[key] : void 0;
1051
+ },
1052
+ set(value) {
1053
+ const text = this.textElement;
1054
+ if (!text) return;
1055
+ if (text[key] === value) return;
1056
+ text[key] = value;
1057
+ this.updateText();
1058
+ }
1059
+ });
1060
+ });
1061
+ IText.registerUI();
1062
+ var text_default = IText;
1063
+ export {
1064
+ bar_default as Bar,
1065
+ button_default as Button,
1066
+ circle_default as Circle,
1067
+ text_default as IText,
1068
+ layer_default as Layer,
1069
+ lib_default as Lib
1070
+ };
1071
+ //# sourceMappingURL=index.mjs.map