@pooder/kit 0.0.2 → 2.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/CHANGELOG.md +26 -9
- package/dist/index.d.mts +29 -6
- package/dist/index.d.ts +29 -6
- package/dist/index.js +405 -62
- package/dist/index.mjs +435 -68
- package/package.json +2 -2
- package/src/background.ts +183 -173
- package/src/dieline.ts +580 -424
- package/src/film.ts +163 -155
- package/src/geometry.ts +251 -244
- package/src/hole.ts +493 -413
- package/src/image.ts +304 -146
- package/src/index.ts +8 -7
- package/src/mirror.ts +91 -0
- package/src/ruler.ts +255 -238
- package/src/white-ink.ts +329 -302
- package/tsconfig.json +13 -13
package/dist/index.js
CHANGED
|
@@ -35,6 +35,7 @@ __export(index_exports, {
|
|
|
35
35
|
FilmTool: () => FilmTool,
|
|
36
36
|
HoleTool: () => HoleTool,
|
|
37
37
|
ImageTool: () => ImageTool,
|
|
38
|
+
MirrorTool: () => MirrorTool,
|
|
38
39
|
RulerTool: () => RulerTool,
|
|
39
40
|
WhiteInkTool: () => WhiteInkTool
|
|
40
41
|
});
|
|
@@ -124,10 +125,10 @@ var BackgroundTool = class {
|
|
|
124
125
|
editor.canvas.add(backgroundLayer);
|
|
125
126
|
editor.canvas.sendObjectToBack(backgroundLayer);
|
|
126
127
|
}
|
|
127
|
-
this.updateBackground(editor, this.options);
|
|
128
128
|
}
|
|
129
129
|
onMount(editor) {
|
|
130
130
|
this.initLayer(editor);
|
|
131
|
+
this.updateBackground(editor, this.options);
|
|
131
132
|
}
|
|
132
133
|
onUnmount(editor) {
|
|
133
134
|
const layer = editor.getLayer("background");
|
|
@@ -191,8 +192,7 @@ var BackgroundTool = class {
|
|
|
191
192
|
}
|
|
192
193
|
});
|
|
193
194
|
img.scaleToWidth(width);
|
|
194
|
-
if (img.getScaledHeight() < height)
|
|
195
|
-
img.scaleToHeight(height);
|
|
195
|
+
if (img.getScaledHeight() < height) img.scaleToHeight(height);
|
|
196
196
|
layer.add(img);
|
|
197
197
|
}
|
|
198
198
|
}
|
|
@@ -357,7 +357,8 @@ var DielineTool = class {
|
|
|
357
357
|
offset: 0,
|
|
358
358
|
style: "solid",
|
|
359
359
|
insideColor: "rgba(0,0,0,0)",
|
|
360
|
-
outsideColor: "#ffffff"
|
|
360
|
+
outsideColor: "#ffffff",
|
|
361
|
+
showBleedLines: true
|
|
361
362
|
};
|
|
362
363
|
this.schema = {
|
|
363
364
|
shape: {
|
|
@@ -372,6 +373,7 @@ var DielineTool = class {
|
|
|
372
373
|
// Complex object, simplified for now or need custom handler
|
|
373
374
|
borderLength: { type: "number", min: 0, max: 500, label: "Margin" },
|
|
374
375
|
offset: { type: "number", min: -100, max: 100, label: "Bleed Offset" },
|
|
376
|
+
showBleedLines: { type: "boolean", label: "Show Bleed Lines" },
|
|
375
377
|
style: {
|
|
376
378
|
type: "select",
|
|
377
379
|
options: ["solid", "dashed"],
|
|
@@ -391,7 +393,8 @@ var DielineTool = class {
|
|
|
391
393
|
offset: 0,
|
|
392
394
|
style: "solid",
|
|
393
395
|
insideColor: "rgba(0,0,0,0)",
|
|
394
|
-
outsideColor: "#ffffff"
|
|
396
|
+
outsideColor: "#ffffff",
|
|
397
|
+
showBleedLines: true
|
|
395
398
|
};
|
|
396
399
|
this.updateDieline(editor);
|
|
397
400
|
return true;
|
|
@@ -405,7 +408,8 @@ var DielineTool = class {
|
|
|
405
408
|
},
|
|
406
409
|
setDimensions: {
|
|
407
410
|
execute: (editor, width, height) => {
|
|
408
|
-
if (this.options.width === width && this.options.height === height)
|
|
411
|
+
if (this.options.width === width && this.options.height === height)
|
|
412
|
+
return true;
|
|
409
413
|
this.options.width = width;
|
|
410
414
|
this.options.height = height;
|
|
411
415
|
this.updateDieline(editor);
|
|
@@ -460,11 +464,100 @@ var DielineTool = class {
|
|
|
460
464
|
required: true
|
|
461
465
|
}
|
|
462
466
|
}
|
|
467
|
+
},
|
|
468
|
+
exportCutImage: {
|
|
469
|
+
execute: (editor) => {
|
|
470
|
+
var _a, _b, _c, _d;
|
|
471
|
+
const { shape, width, height, radius, position } = this.options;
|
|
472
|
+
const canvasW = editor.canvas.width || 800;
|
|
473
|
+
const canvasH = editor.canvas.height || 600;
|
|
474
|
+
const cx = (_a = position == null ? void 0 : position.x) != null ? _a : canvasW / 2;
|
|
475
|
+
const cy = (_b = position == null ? void 0 : position.y) != null ? _b : canvasH / 2;
|
|
476
|
+
const holeTool = editor.getExtension("HoleTool");
|
|
477
|
+
const holes = holeTool ? holeTool.options.holes || [] : [];
|
|
478
|
+
const innerRadius = holeTool ? holeTool.options.innerRadius || 15 : 15;
|
|
479
|
+
const outerRadius = holeTool ? holeTool.options.outerRadius || 25 : 25;
|
|
480
|
+
const holeData = holes.map((h) => ({
|
|
481
|
+
x: h.x,
|
|
482
|
+
y: h.y,
|
|
483
|
+
innerRadius,
|
|
484
|
+
outerRadius
|
|
485
|
+
}));
|
|
486
|
+
const pathData = generateDielinePath({
|
|
487
|
+
shape,
|
|
488
|
+
width,
|
|
489
|
+
height,
|
|
490
|
+
radius,
|
|
491
|
+
x: cx,
|
|
492
|
+
y: cy,
|
|
493
|
+
holes: holeData
|
|
494
|
+
});
|
|
495
|
+
const clipPath = new import_core2.Path(pathData, {
|
|
496
|
+
left: 0,
|
|
497
|
+
top: 0,
|
|
498
|
+
originX: "left",
|
|
499
|
+
originY: "top",
|
|
500
|
+
absolutePositioned: true
|
|
501
|
+
});
|
|
502
|
+
const layer = this.getLayer(editor, "dieline-overlay");
|
|
503
|
+
const wasVisible = (_c = layer == null ? void 0 : layer.visible) != null ? _c : true;
|
|
504
|
+
if (layer) layer.visible = false;
|
|
505
|
+
const holeMarkers = editor.canvas.getObjects().filter((o) => {
|
|
506
|
+
var _a2;
|
|
507
|
+
return ((_a2 = o.data) == null ? void 0 : _a2.type) === "hole-marker";
|
|
508
|
+
});
|
|
509
|
+
holeMarkers.forEach((o) => o.visible = false);
|
|
510
|
+
const rulerLayer = editor.canvas.getObjects().find((obj) => {
|
|
511
|
+
var _a2;
|
|
512
|
+
return ((_a2 = obj.data) == null ? void 0 : _a2.id) === "ruler-overlay";
|
|
513
|
+
});
|
|
514
|
+
const rulerWasVisible = (_d = rulerLayer == null ? void 0 : rulerLayer.visible) != null ? _d : true;
|
|
515
|
+
if (rulerLayer) rulerLayer.visible = false;
|
|
516
|
+
const originalClip = editor.canvas.clipPath;
|
|
517
|
+
editor.canvas.clipPath = clipPath;
|
|
518
|
+
const bbox = clipPath.getBoundingRect();
|
|
519
|
+
const holeDataRelative = holes.map((h) => ({
|
|
520
|
+
x: h.x - bbox.left,
|
|
521
|
+
y: h.y - bbox.top,
|
|
522
|
+
innerRadius,
|
|
523
|
+
outerRadius
|
|
524
|
+
}));
|
|
525
|
+
const clipPathCorrected = new import_core2.Path(pathData, {
|
|
526
|
+
absolutePositioned: true,
|
|
527
|
+
left: 0,
|
|
528
|
+
top: 0
|
|
529
|
+
});
|
|
530
|
+
const tempPath = new import_core2.Path(pathData);
|
|
531
|
+
const tempBounds = tempPath.getBoundingRect();
|
|
532
|
+
clipPathCorrected.set({
|
|
533
|
+
left: tempBounds.left,
|
|
534
|
+
top: tempBounds.top,
|
|
535
|
+
originX: "left",
|
|
536
|
+
originY: "top"
|
|
537
|
+
});
|
|
538
|
+
editor.canvas.clipPath = clipPathCorrected;
|
|
539
|
+
const exportBbox = clipPathCorrected.getBoundingRect();
|
|
540
|
+
const dataURL = editor.canvas.toDataURL({
|
|
541
|
+
format: "png",
|
|
542
|
+
multiplier: 2,
|
|
543
|
+
left: exportBbox.left,
|
|
544
|
+
top: exportBbox.top,
|
|
545
|
+
width: exportBbox.width,
|
|
546
|
+
height: exportBbox.height
|
|
547
|
+
});
|
|
548
|
+
editor.canvas.clipPath = originalClip;
|
|
549
|
+
if (layer) layer.visible = wasVisible;
|
|
550
|
+
if (rulerLayer) rulerLayer.visible = rulerWasVisible;
|
|
551
|
+
holeMarkers.forEach((o) => o.visible = true);
|
|
552
|
+
editor.canvas.requestRenderAll();
|
|
553
|
+
return dataURL;
|
|
554
|
+
}
|
|
463
555
|
}
|
|
464
556
|
};
|
|
465
557
|
}
|
|
466
558
|
onMount(editor) {
|
|
467
559
|
this.createLayer(editor);
|
|
560
|
+
this.updateDieline(editor);
|
|
468
561
|
}
|
|
469
562
|
onUnmount(editor) {
|
|
470
563
|
this.destroyLayer(editor);
|
|
@@ -496,7 +589,6 @@ var DielineTool = class {
|
|
|
496
589
|
editor.canvas.add(layer);
|
|
497
590
|
}
|
|
498
591
|
editor.canvas.bringObjectToFront(layer);
|
|
499
|
-
this.updateDieline(editor);
|
|
500
592
|
}
|
|
501
593
|
destroyLayer(editor) {
|
|
502
594
|
const layer = this.getLayer(editor, "dieline-overlay");
|
|
@@ -526,7 +618,17 @@ var DielineTool = class {
|
|
|
526
618
|
}
|
|
527
619
|
updateDieline(editor) {
|
|
528
620
|
var _a, _b;
|
|
529
|
-
const {
|
|
621
|
+
const {
|
|
622
|
+
shape,
|
|
623
|
+
radius,
|
|
624
|
+
offset,
|
|
625
|
+
style,
|
|
626
|
+
insideColor,
|
|
627
|
+
outsideColor,
|
|
628
|
+
position,
|
|
629
|
+
borderLength,
|
|
630
|
+
showBleedLines
|
|
631
|
+
} = this.options;
|
|
530
632
|
let { width, height } = this.options;
|
|
531
633
|
const canvasW = editor.canvas.width || 800;
|
|
532
634
|
const canvasH = editor.canvas.height || 600;
|
|
@@ -540,6 +642,9 @@ var DielineTool = class {
|
|
|
540
642
|
if (!layer) return;
|
|
541
643
|
layer.remove(...layer.getObjects());
|
|
542
644
|
const holeTool = editor.getExtension("HoleTool");
|
|
645
|
+
if (holeTool && typeof holeTool.enforceConstraints === "function") {
|
|
646
|
+
holeTool.enforceConstraints(editor);
|
|
647
|
+
}
|
|
543
648
|
const holes = holeTool ? holeTool.options.holes || [] : [];
|
|
544
649
|
const innerRadius = holeTool ? holeTool.options.innerRadius || 15 : 15;
|
|
545
650
|
const outerRadius = holeTool ? holeTool.options.outerRadius || 25 : 25;
|
|
@@ -596,27 +701,32 @@ var DielineTool = class {
|
|
|
596
701
|
layer.add(insideObj);
|
|
597
702
|
}
|
|
598
703
|
if (offset !== 0) {
|
|
599
|
-
const bleedPathData = generateBleedZonePath(
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
704
|
+
const bleedPathData = generateBleedZonePath(
|
|
705
|
+
{
|
|
706
|
+
shape,
|
|
707
|
+
width,
|
|
708
|
+
height,
|
|
709
|
+
radius,
|
|
710
|
+
x: cx,
|
|
711
|
+
y: cy,
|
|
712
|
+
holes: holeData
|
|
713
|
+
},
|
|
714
|
+
offset
|
|
715
|
+
);
|
|
716
|
+
if (showBleedLines !== false) {
|
|
717
|
+
const pattern = this.createHatchPattern("red");
|
|
718
|
+
if (pattern) {
|
|
719
|
+
const bleedObj = new import_core2.Path(bleedPathData, {
|
|
720
|
+
fill: pattern,
|
|
721
|
+
stroke: null,
|
|
722
|
+
selectable: false,
|
|
723
|
+
evented: false,
|
|
724
|
+
objectCaching: false,
|
|
725
|
+
originX: "left",
|
|
726
|
+
originY: "top"
|
|
727
|
+
});
|
|
728
|
+
layer.add(bleedObj);
|
|
729
|
+
}
|
|
620
730
|
}
|
|
621
731
|
const offsetPathData = generateDielinePath({
|
|
622
732
|
shape,
|
|
@@ -712,7 +822,8 @@ var FilmTool = class {
|
|
|
712
822
|
this.commands = {
|
|
713
823
|
setFilmImage: {
|
|
714
824
|
execute: (editor, url, opacity) => {
|
|
715
|
-
if (this.options.url === url && this.options.opacity === opacity)
|
|
825
|
+
if (this.options.url === url && this.options.opacity === opacity)
|
|
826
|
+
return true;
|
|
716
827
|
this.options.url = url;
|
|
717
828
|
this.options.opacity = opacity;
|
|
718
829
|
this.updateFilm(editor, this.options);
|
|
@@ -750,6 +861,7 @@ var FilmTool = class {
|
|
|
750
861
|
}
|
|
751
862
|
}
|
|
752
863
|
onUpdate(editor, state) {
|
|
864
|
+
this.updateFilm(editor, this.options);
|
|
753
865
|
}
|
|
754
866
|
initLayer(editor) {
|
|
755
867
|
let overlayLayer = editor.getLayer("overlay");
|
|
@@ -802,8 +914,7 @@ var FilmTool = class {
|
|
|
802
914
|
} else {
|
|
803
915
|
img = await import_core3.Image.fromURL(url, { crossOrigin: "anonymous" });
|
|
804
916
|
img.scaleToWidth(width);
|
|
805
|
-
if (img.getScaledHeight() < height)
|
|
806
|
-
img.scaleToHeight(height);
|
|
917
|
+
if (img.getScaledHeight() < height) img.scaleToHeight(height);
|
|
807
918
|
img.set({
|
|
808
919
|
originX: "left",
|
|
809
920
|
originY: "top",
|
|
@@ -832,7 +943,8 @@ var HoleTool = class {
|
|
|
832
943
|
innerRadius: 15,
|
|
833
944
|
outerRadius: 25,
|
|
834
945
|
style: "solid",
|
|
835
|
-
holes: []
|
|
946
|
+
holes: [],
|
|
947
|
+
constraintTarget: "bleed"
|
|
836
948
|
};
|
|
837
949
|
this.schema = {
|
|
838
950
|
innerRadius: {
|
|
@@ -852,6 +964,11 @@ var HoleTool = class {
|
|
|
852
964
|
options: ["solid", "dashed"],
|
|
853
965
|
label: "Line Style"
|
|
854
966
|
},
|
|
967
|
+
constraintTarget: {
|
|
968
|
+
type: "select",
|
|
969
|
+
options: ["original", "bleed"],
|
|
970
|
+
label: "Constraint Target"
|
|
971
|
+
},
|
|
855
972
|
holes: {
|
|
856
973
|
type: "json",
|
|
857
974
|
label: "Holes"
|
|
@@ -866,7 +983,10 @@ var HoleTool = class {
|
|
|
866
983
|
const g = this.getDielineGeometry(editor);
|
|
867
984
|
if (g) {
|
|
868
985
|
const topCenter = { x: g.x, y: g.y - g.height / 2 };
|
|
869
|
-
defaultPos = getNearestPointOnDieline(topCenter, {
|
|
986
|
+
defaultPos = getNearestPointOnDieline(topCenter, {
|
|
987
|
+
...g,
|
|
988
|
+
holes: []
|
|
989
|
+
});
|
|
870
990
|
}
|
|
871
991
|
this.options = {
|
|
872
992
|
innerRadius: 15,
|
|
@@ -933,7 +1053,7 @@ var HoleTool = class {
|
|
|
933
1053
|
if (!dielineTool) return null;
|
|
934
1054
|
const geometry = dielineTool.getGeometry(editor);
|
|
935
1055
|
if (!geometry) return null;
|
|
936
|
-
const offset = dielineTool.options.offset || 0;
|
|
1056
|
+
const offset = this.options.constraintTarget === "original" ? 0 : dielineTool.options.offset || 0;
|
|
937
1057
|
return {
|
|
938
1058
|
...geometry,
|
|
939
1059
|
width: Math.max(0, geometry.width + offset * 2),
|
|
@@ -941,6 +1061,39 @@ var HoleTool = class {
|
|
|
941
1061
|
radius: Math.max(0, geometry.radius + offset)
|
|
942
1062
|
};
|
|
943
1063
|
}
|
|
1064
|
+
enforceConstraints(editor) {
|
|
1065
|
+
const geometry = this.getDielineGeometry(editor);
|
|
1066
|
+
if (!geometry) return;
|
|
1067
|
+
const objects = editor.canvas.getObjects().filter((obj) => {
|
|
1068
|
+
var _a;
|
|
1069
|
+
return ((_a = obj.data) == null ? void 0 : _a.type) === "hole-marker";
|
|
1070
|
+
});
|
|
1071
|
+
let changed = false;
|
|
1072
|
+
objects.sort(
|
|
1073
|
+
(a, b) => {
|
|
1074
|
+
var _a, _b, _c, _d;
|
|
1075
|
+
return ((_b = (_a = a.data) == null ? void 0 : _a.index) != null ? _b : 0) - ((_d = (_c = b.data) == null ? void 0 : _c.index) != null ? _d : 0);
|
|
1076
|
+
}
|
|
1077
|
+
);
|
|
1078
|
+
const newHoles = [];
|
|
1079
|
+
objects.forEach((obj) => {
|
|
1080
|
+
const currentPos = new import_core4.Point(obj.left, obj.top);
|
|
1081
|
+
const newPos = this.calculateConstrainedPosition(currentPos, geometry);
|
|
1082
|
+
if (currentPos.distanceFrom(newPos) > 0.1) {
|
|
1083
|
+
obj.set({
|
|
1084
|
+
left: newPos.x,
|
|
1085
|
+
top: newPos.y
|
|
1086
|
+
});
|
|
1087
|
+
obj.setCoords();
|
|
1088
|
+
changed = true;
|
|
1089
|
+
}
|
|
1090
|
+
newHoles.push({ x: obj.left, y: obj.top });
|
|
1091
|
+
});
|
|
1092
|
+
if (changed) {
|
|
1093
|
+
this.options.holes = newHoles;
|
|
1094
|
+
editor.canvas.requestRenderAll();
|
|
1095
|
+
}
|
|
1096
|
+
}
|
|
944
1097
|
setup(editor) {
|
|
945
1098
|
if (!this.handleMoving) {
|
|
946
1099
|
this.handleMoving = (e) => {
|
|
@@ -973,7 +1126,10 @@ var HoleTool = class {
|
|
|
973
1126
|
const g = this.getDielineGeometry(editor);
|
|
974
1127
|
if (g) {
|
|
975
1128
|
const topCenter = { x: g.x, y: g.y - g.height / 2 };
|
|
976
|
-
const snapped = getNearestPointOnDieline(topCenter, {
|
|
1129
|
+
const snapped = getNearestPointOnDieline(topCenter, {
|
|
1130
|
+
...g,
|
|
1131
|
+
holes: []
|
|
1132
|
+
});
|
|
977
1133
|
defaultPos = snapped;
|
|
978
1134
|
}
|
|
979
1135
|
opts.holes = [defaultPos];
|
|
@@ -1002,6 +1158,12 @@ var HoleTool = class {
|
|
|
1002
1158
|
editor.canvas.requestRenderAll();
|
|
1003
1159
|
}
|
|
1004
1160
|
onUpdate(editor, state) {
|
|
1161
|
+
this.enforceConstraints(editor);
|
|
1162
|
+
this.redraw(editor);
|
|
1163
|
+
const dielineTool = editor.getExtension("DielineTool");
|
|
1164
|
+
if (dielineTool && dielineTool.updateDieline) {
|
|
1165
|
+
dielineTool.updateDieline(editor);
|
|
1166
|
+
}
|
|
1005
1167
|
}
|
|
1006
1168
|
syncHolesFromCanvas(editor) {
|
|
1007
1169
|
const objects = editor.canvas.getObjects().filter((obj) => {
|
|
@@ -1090,7 +1252,10 @@ var HoleTool = class {
|
|
|
1090
1252
|
holes: []
|
|
1091
1253
|
// We don't need holes for boundary calculation
|
|
1092
1254
|
};
|
|
1093
|
-
const nearest = getNearestPointOnDieline(
|
|
1255
|
+
const nearest = getNearestPointOnDieline(
|
|
1256
|
+
{ x: p.x, y: p.y },
|
|
1257
|
+
options
|
|
1258
|
+
);
|
|
1094
1259
|
const nearestP = new import_core4.Point(nearest.x, nearest.y);
|
|
1095
1260
|
const dist = p.distanceFrom(nearestP);
|
|
1096
1261
|
const v = p.subtract(nearestP);
|
|
@@ -1121,6 +1286,7 @@ var import_core5 = require("@pooder/core");
|
|
|
1121
1286
|
var ImageTool = class {
|
|
1122
1287
|
constructor() {
|
|
1123
1288
|
this.name = "ImageTool";
|
|
1289
|
+
this._loadingUrl = null;
|
|
1124
1290
|
this.options = {
|
|
1125
1291
|
url: "",
|
|
1126
1292
|
opacity: 1
|
|
@@ -1136,14 +1302,44 @@ var ImageTool = class {
|
|
|
1136
1302
|
max: 1,
|
|
1137
1303
|
step: 0.1,
|
|
1138
1304
|
label: "Opacity"
|
|
1305
|
+
},
|
|
1306
|
+
width: {
|
|
1307
|
+
type: "number",
|
|
1308
|
+
label: "Width",
|
|
1309
|
+
min: 0,
|
|
1310
|
+
max: 5e3
|
|
1311
|
+
},
|
|
1312
|
+
height: {
|
|
1313
|
+
type: "number",
|
|
1314
|
+
label: "Height",
|
|
1315
|
+
min: 0,
|
|
1316
|
+
max: 5e3
|
|
1317
|
+
},
|
|
1318
|
+
angle: {
|
|
1319
|
+
type: "number",
|
|
1320
|
+
label: "Rotation",
|
|
1321
|
+
min: 0,
|
|
1322
|
+
max: 360
|
|
1323
|
+
},
|
|
1324
|
+
left: {
|
|
1325
|
+
type: "number",
|
|
1326
|
+
label: "Left",
|
|
1327
|
+
min: 0,
|
|
1328
|
+
max: 1e3
|
|
1329
|
+
},
|
|
1330
|
+
top: {
|
|
1331
|
+
type: "number",
|
|
1332
|
+
label: "Top",
|
|
1333
|
+
min: 0,
|
|
1334
|
+
max: 1e3
|
|
1139
1335
|
}
|
|
1140
1336
|
};
|
|
1141
1337
|
this.commands = {
|
|
1142
1338
|
setUserImage: {
|
|
1143
|
-
execute: (editor, url, opacity) => {
|
|
1144
|
-
if (this.options.url === url && this.options.opacity === opacity
|
|
1145
|
-
|
|
1146
|
-
this.options
|
|
1339
|
+
execute: (editor, url, opacity, width, height, angle, left, top) => {
|
|
1340
|
+
if (this.options.url === url && this.options.opacity === opacity && this.options.width === width && this.options.height === height && this.options.angle === angle && this.options.left === left && this.options.top === top)
|
|
1341
|
+
return true;
|
|
1342
|
+
this.options = { url, opacity, width, height, angle, left, top };
|
|
1147
1343
|
this.updateImage(editor, this.options);
|
|
1148
1344
|
return true;
|
|
1149
1345
|
},
|
|
@@ -1159,13 +1355,19 @@ var ImageTool = class {
|
|
|
1159
1355
|
min: 0,
|
|
1160
1356
|
max: 1,
|
|
1161
1357
|
required: true
|
|
1162
|
-
}
|
|
1358
|
+
},
|
|
1359
|
+
width: { type: "number", label: "Width" },
|
|
1360
|
+
height: { type: "number", label: "Height" },
|
|
1361
|
+
angle: { type: "number", label: "Angle" },
|
|
1362
|
+
left: { type: "number", label: "Left" },
|
|
1363
|
+
top: { type: "number", label: "Top" }
|
|
1163
1364
|
}
|
|
1164
1365
|
}
|
|
1165
1366
|
};
|
|
1166
1367
|
}
|
|
1167
1368
|
onMount(editor) {
|
|
1168
1369
|
this.ensureLayer(editor);
|
|
1370
|
+
this.updateImage(editor, this.options);
|
|
1169
1371
|
}
|
|
1170
1372
|
onUnmount(editor) {
|
|
1171
1373
|
const layer = editor.getLayer("user");
|
|
@@ -1203,43 +1405,101 @@ var ImageTool = class {
|
|
|
1203
1405
|
}
|
|
1204
1406
|
updateImage(editor, opts) {
|
|
1205
1407
|
var _a, _b;
|
|
1206
|
-
let { url, opacity } = opts;
|
|
1408
|
+
let { url, opacity, width, height, angle, left, top } = opts;
|
|
1207
1409
|
const layer = editor.getLayer("user");
|
|
1208
1410
|
if (!layer) {
|
|
1209
1411
|
console.warn("[ImageTool] User layer not found");
|
|
1210
1412
|
return;
|
|
1211
1413
|
}
|
|
1212
1414
|
const userImage = editor.getObject("user-image", "user");
|
|
1415
|
+
if (this._loadingUrl === url) return;
|
|
1213
1416
|
if (userImage) {
|
|
1214
1417
|
const currentSrc = ((_a = userImage.getSrc) == null ? void 0 : _a.call(userImage)) || ((_b = userImage._element) == null ? void 0 : _b.src);
|
|
1215
1418
|
if (currentSrc !== url) {
|
|
1216
|
-
this.loadImage(editor, layer,
|
|
1419
|
+
this.loadImage(editor, layer, opts);
|
|
1217
1420
|
} else {
|
|
1218
|
-
|
|
1219
|
-
|
|
1421
|
+
const updates = {};
|
|
1422
|
+
const centerX = editor.state.width / 2;
|
|
1423
|
+
const centerY = editor.state.height / 2;
|
|
1424
|
+
if (userImage.opacity !== opacity) updates.opacity = opacity;
|
|
1425
|
+
if (angle !== void 0 && userImage.angle !== angle)
|
|
1426
|
+
updates.angle = angle;
|
|
1427
|
+
if (left !== void 0) {
|
|
1428
|
+
const localLeft = left - centerX;
|
|
1429
|
+
if (Math.abs(userImage.left - localLeft) > 1)
|
|
1430
|
+
updates.left = localLeft;
|
|
1431
|
+
}
|
|
1432
|
+
if (top !== void 0) {
|
|
1433
|
+
const localTop = top - centerY;
|
|
1434
|
+
if (Math.abs(userImage.top - localTop) > 1) updates.top = localTop;
|
|
1435
|
+
}
|
|
1436
|
+
if (width !== void 0 && userImage.width)
|
|
1437
|
+
updates.scaleX = width / userImage.width;
|
|
1438
|
+
if (height !== void 0 && userImage.height)
|
|
1439
|
+
updates.scaleY = height / userImage.height;
|
|
1440
|
+
if (Object.keys(updates).length > 0) {
|
|
1441
|
+
userImage.set(updates);
|
|
1220
1442
|
editor.canvas.requestRenderAll();
|
|
1221
1443
|
}
|
|
1222
1444
|
}
|
|
1223
1445
|
} else {
|
|
1224
|
-
this.loadImage(editor, layer,
|
|
1446
|
+
this.loadImage(editor, layer, opts);
|
|
1225
1447
|
}
|
|
1226
1448
|
}
|
|
1227
|
-
loadImage(editor, layer,
|
|
1449
|
+
loadImage(editor, layer, opts) {
|
|
1450
|
+
const { url } = opts;
|
|
1451
|
+
this._loadingUrl = url;
|
|
1228
1452
|
import_core5.Image.fromURL(url).then((image) => {
|
|
1229
|
-
if (
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1453
|
+
if (this._loadingUrl !== url) return;
|
|
1454
|
+
this._loadingUrl = null;
|
|
1455
|
+
const currentOpts = this.options;
|
|
1456
|
+
const { opacity, width, height, angle, left, top } = currentOpts;
|
|
1457
|
+
const existingImage = editor.getObject("user-image", "user");
|
|
1458
|
+
if (existingImage) {
|
|
1459
|
+
const defaultLeft = existingImage.left;
|
|
1460
|
+
const defaultTop = existingImage.top;
|
|
1461
|
+
const defaultAngle = existingImage.angle;
|
|
1462
|
+
const defaultScaleX = existingImage.scaleX;
|
|
1463
|
+
const defaultScaleY = existingImage.scaleY;
|
|
1464
|
+
image.set({
|
|
1465
|
+
left: left !== void 0 ? left : defaultLeft,
|
|
1466
|
+
top: top !== void 0 ? top : defaultTop,
|
|
1467
|
+
angle: angle !== void 0 ? angle : defaultAngle,
|
|
1468
|
+
scaleX: width !== void 0 && image.width ? width / image.width : defaultScaleX,
|
|
1469
|
+
scaleY: height !== void 0 && image.height ? height / image.height : defaultScaleY
|
|
1470
|
+
});
|
|
1471
|
+
layer.remove(existingImage);
|
|
1472
|
+
} else {
|
|
1473
|
+
if (width !== void 0 && image.width)
|
|
1474
|
+
image.scaleX = width / image.width;
|
|
1475
|
+
if (height !== void 0 && image.height)
|
|
1476
|
+
image.scaleY = height / image.height;
|
|
1477
|
+
if (angle !== void 0) image.angle = angle;
|
|
1478
|
+
if (left !== void 0) image.left = left;
|
|
1479
|
+
if (top !== void 0) image.top = top;
|
|
1233
1480
|
}
|
|
1234
1481
|
image.set({
|
|
1235
|
-
opacity,
|
|
1482
|
+
opacity: opacity !== void 0 ? opacity : 1,
|
|
1236
1483
|
data: {
|
|
1237
1484
|
id: "user-image"
|
|
1238
1485
|
}
|
|
1239
1486
|
});
|
|
1240
1487
|
layer.add(image);
|
|
1488
|
+
image.on("modified", (e) => {
|
|
1489
|
+
const matrix = image.calcTransformMatrix();
|
|
1490
|
+
const globalPoint = import_core5.util.transformPoint(new import_core5.Point(0, 0), matrix);
|
|
1491
|
+
this.options.left = globalPoint.x;
|
|
1492
|
+
this.options.top = globalPoint.y;
|
|
1493
|
+
this.options.angle = e.target.angle;
|
|
1494
|
+
if (image.width)
|
|
1495
|
+
this.options.width = e.target.width * e.target.scaleX;
|
|
1496
|
+
if (image.height)
|
|
1497
|
+
this.options.height = e.target.height * e.target.scaleY;
|
|
1498
|
+
editor.emit("update");
|
|
1499
|
+
});
|
|
1241
1500
|
editor.canvas.requestRenderAll();
|
|
1242
1501
|
}).catch((err) => {
|
|
1502
|
+
if (this._loadingUrl === url) this._loadingUrl = null;
|
|
1243
1503
|
console.error("Failed to load image", url, err);
|
|
1244
1504
|
});
|
|
1245
1505
|
}
|
|
@@ -1263,7 +1523,8 @@ var WhiteInkTool = class {
|
|
|
1263
1523
|
this.commands = {
|
|
1264
1524
|
setWhiteInkImage: {
|
|
1265
1525
|
execute: (editor, customMask, opacity, enableClip = true) => {
|
|
1266
|
-
if (this.options.customMask === customMask && this.options.opacity === opacity && this.options.enableClip === enableClip)
|
|
1526
|
+
if (this.options.customMask === customMask && this.options.opacity === opacity && this.options.enableClip === enableClip)
|
|
1527
|
+
return true;
|
|
1267
1528
|
this.options.customMask = customMask;
|
|
1268
1529
|
this.options.opacity = opacity;
|
|
1269
1530
|
this.options.enableClip = enableClip;
|
|
@@ -1295,6 +1556,7 @@ var WhiteInkTool = class {
|
|
|
1295
1556
|
}
|
|
1296
1557
|
onMount(editor) {
|
|
1297
1558
|
this.setup(editor);
|
|
1559
|
+
this.updateWhiteInk(editor, this.options);
|
|
1298
1560
|
}
|
|
1299
1561
|
onUnmount(editor) {
|
|
1300
1562
|
this.teardown(editor);
|
|
@@ -1335,7 +1597,6 @@ var WhiteInkTool = class {
|
|
|
1335
1597
|
editor.canvas.on("object:rotating", this.syncHandler);
|
|
1336
1598
|
editor.canvas.on("object:modified", this.syncHandler);
|
|
1337
1599
|
}
|
|
1338
|
-
this.updateWhiteInk(editor, this.options);
|
|
1339
1600
|
}
|
|
1340
1601
|
teardown(editor) {
|
|
1341
1602
|
if (this.syncHandler) {
|
|
@@ -1384,7 +1645,14 @@ var WhiteInkTool = class {
|
|
|
1384
1645
|
if (whiteInk) {
|
|
1385
1646
|
const currentSrc = ((_a = whiteInk.getSrc) == null ? void 0 : _a.call(whiteInk)) || ((_b = whiteInk._element) == null ? void 0 : _b.src);
|
|
1386
1647
|
if (currentSrc !== customMask) {
|
|
1387
|
-
this.loadWhiteInk(
|
|
1648
|
+
this.loadWhiteInk(
|
|
1649
|
+
editor,
|
|
1650
|
+
layer,
|
|
1651
|
+
customMask,
|
|
1652
|
+
opacity,
|
|
1653
|
+
enableClip,
|
|
1654
|
+
whiteInk
|
|
1655
|
+
);
|
|
1388
1656
|
} else {
|
|
1389
1657
|
if (whiteInk.opacity !== opacity) {
|
|
1390
1658
|
whiteInk.set({ opacity });
|
|
@@ -1413,10 +1681,12 @@ var WhiteInkTool = class {
|
|
|
1413
1681
|
if (oldImage) {
|
|
1414
1682
|
layer.remove(oldImage);
|
|
1415
1683
|
}
|
|
1416
|
-
(_a = image.filters) == null ? void 0 : _a.push(
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1684
|
+
(_a = image.filters) == null ? void 0 : _a.push(
|
|
1685
|
+
new import_core6.filters.BlendColor({
|
|
1686
|
+
color: "#FFFFFF",
|
|
1687
|
+
mode: "add"
|
|
1688
|
+
})
|
|
1689
|
+
);
|
|
1420
1690
|
image.applyFilters();
|
|
1421
1691
|
image.set({
|
|
1422
1692
|
opacity,
|
|
@@ -1528,7 +1798,8 @@ var RulerTool = class {
|
|
|
1528
1798
|
setTheme: {
|
|
1529
1799
|
execute: (editor, theme) => {
|
|
1530
1800
|
const newOptions = { ...this.options, ...theme };
|
|
1531
|
-
if (JSON.stringify(newOptions) === JSON.stringify(this.options))
|
|
1801
|
+
if (JSON.stringify(newOptions) === JSON.stringify(this.options))
|
|
1802
|
+
return true;
|
|
1532
1803
|
this.options = newOptions;
|
|
1533
1804
|
this.updateRuler(editor);
|
|
1534
1805
|
return true;
|
|
@@ -1545,11 +1816,13 @@ var RulerTool = class {
|
|
|
1545
1816
|
}
|
|
1546
1817
|
onMount(editor) {
|
|
1547
1818
|
this.createLayer(editor);
|
|
1819
|
+
this.updateRuler(editor);
|
|
1548
1820
|
}
|
|
1549
1821
|
onUnmount(editor) {
|
|
1550
1822
|
this.destroyLayer(editor);
|
|
1551
1823
|
}
|
|
1552
1824
|
onUpdate(editor, state) {
|
|
1825
|
+
this.updateRuler(editor);
|
|
1553
1826
|
}
|
|
1554
1827
|
onDestroy(editor) {
|
|
1555
1828
|
this.destroyLayer(editor);
|
|
@@ -1575,7 +1848,6 @@ var RulerTool = class {
|
|
|
1575
1848
|
editor.canvas.add(layer);
|
|
1576
1849
|
}
|
|
1577
1850
|
editor.canvas.bringObjectToFront(layer);
|
|
1578
|
-
this.updateRuler(editor);
|
|
1579
1851
|
}
|
|
1580
1852
|
destroyLayer(editor) {
|
|
1581
1853
|
const layer = this.getLayer(editor);
|
|
@@ -1681,6 +1953,76 @@ var RulerTool = class {
|
|
|
1681
1953
|
editor.canvas.requestRenderAll();
|
|
1682
1954
|
}
|
|
1683
1955
|
};
|
|
1956
|
+
|
|
1957
|
+
// src/mirror.ts
|
|
1958
|
+
var MirrorTool = class {
|
|
1959
|
+
constructor() {
|
|
1960
|
+
this.name = "MirrorTool";
|
|
1961
|
+
this.options = {
|
|
1962
|
+
enabled: false
|
|
1963
|
+
};
|
|
1964
|
+
this.schema = {
|
|
1965
|
+
enabled: {
|
|
1966
|
+
type: "boolean",
|
|
1967
|
+
label: "Mirror View"
|
|
1968
|
+
}
|
|
1969
|
+
};
|
|
1970
|
+
this.commands = {
|
|
1971
|
+
toggleMirror: {
|
|
1972
|
+
execute: (editor) => {
|
|
1973
|
+
this.options.enabled = !this.options.enabled;
|
|
1974
|
+
this.applyMirror(editor, this.options.enabled);
|
|
1975
|
+
return true;
|
|
1976
|
+
}
|
|
1977
|
+
},
|
|
1978
|
+
setMirror: {
|
|
1979
|
+
execute: (editor, enabled) => {
|
|
1980
|
+
if (this.options.enabled === enabled) return true;
|
|
1981
|
+
this.options.enabled = enabled;
|
|
1982
|
+
this.applyMirror(editor, enabled);
|
|
1983
|
+
return true;
|
|
1984
|
+
},
|
|
1985
|
+
schema: {
|
|
1986
|
+
enabled: {
|
|
1987
|
+
type: "boolean",
|
|
1988
|
+
label: "Enabled",
|
|
1989
|
+
required: true
|
|
1990
|
+
}
|
|
1991
|
+
}
|
|
1992
|
+
}
|
|
1993
|
+
};
|
|
1994
|
+
}
|
|
1995
|
+
onMount(editor) {
|
|
1996
|
+
if (this.options.enabled) {
|
|
1997
|
+
this.applyMirror(editor, true);
|
|
1998
|
+
}
|
|
1999
|
+
}
|
|
2000
|
+
onUpdate(editor) {
|
|
2001
|
+
this.applyMirror(editor, this.options.enabled);
|
|
2002
|
+
}
|
|
2003
|
+
onUnmount(editor) {
|
|
2004
|
+
this.applyMirror(editor, false);
|
|
2005
|
+
}
|
|
2006
|
+
applyMirror(editor, enabled) {
|
|
2007
|
+
const canvas = editor.canvas;
|
|
2008
|
+
if (!canvas) return;
|
|
2009
|
+
const width = canvas.width || 800;
|
|
2010
|
+
let vpt = canvas.viewportTransform || [1, 0, 0, 1, 0, 0];
|
|
2011
|
+
vpt = [...vpt];
|
|
2012
|
+
const isFlipped = vpt[0] < 0;
|
|
2013
|
+
if (enabled && !isFlipped) {
|
|
2014
|
+
vpt[0] = -vpt[0];
|
|
2015
|
+
vpt[4] = width - vpt[4];
|
|
2016
|
+
canvas.setViewportTransform(vpt);
|
|
2017
|
+
canvas.requestRenderAll();
|
|
2018
|
+
} else if (!enabled && isFlipped) {
|
|
2019
|
+
vpt[0] = -vpt[0];
|
|
2020
|
+
vpt[4] = width - vpt[4];
|
|
2021
|
+
canvas.setViewportTransform(vpt);
|
|
2022
|
+
canvas.requestRenderAll();
|
|
2023
|
+
}
|
|
2024
|
+
}
|
|
2025
|
+
};
|
|
1684
2026
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1685
2027
|
0 && (module.exports = {
|
|
1686
2028
|
BackgroundTool,
|
|
@@ -1688,6 +2030,7 @@ var RulerTool = class {
|
|
|
1688
2030
|
FilmTool,
|
|
1689
2031
|
HoleTool,
|
|
1690
2032
|
ImageTool,
|
|
2033
|
+
MirrorTool,
|
|
1691
2034
|
RulerTool,
|
|
1692
2035
|
WhiteInkTool
|
|
1693
2036
|
});
|