@pooder/kit 1.0.0 → 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 +11 -0
- package/dist/index.d.mts +29 -6
- package/dist/index.d.ts +29 -6
- package/dist/index.js +398 -58
- package/dist/index.mjs +428 -64
- package/package.json +2 -2
- package/src/background.ts +183 -172
- package/src/dieline.ts +580 -421
- package/src/film.ts +163 -156
- package/src/geometry.ts +251 -244
- package/src/hole.ts +493 -413
- package/src/image.ts +304 -147
- package/src/index.ts +8 -7
- package/src/mirror.ts +91 -0
- package/src/ruler.ts +255 -239
- package/src/white-ink.ts +329 -301
- package/tsconfig.json +13 -13
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
// src/background.ts
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
Image,
|
|
4
|
+
PooderLayer,
|
|
5
|
+
Rect
|
|
6
|
+
} from "@pooder/core";
|
|
3
7
|
var BackgroundTool = class {
|
|
4
8
|
constructor() {
|
|
5
9
|
this.name = "BackgroundTool";
|
|
@@ -149,8 +153,7 @@ var BackgroundTool = class {
|
|
|
149
153
|
}
|
|
150
154
|
});
|
|
151
155
|
img.scaleToWidth(width);
|
|
152
|
-
if (img.getScaledHeight() < height)
|
|
153
|
-
img.scaleToHeight(height);
|
|
156
|
+
if (img.getScaledHeight() < height) img.scaleToHeight(height);
|
|
154
157
|
layer.add(img);
|
|
155
158
|
}
|
|
156
159
|
}
|
|
@@ -162,7 +165,11 @@ var BackgroundTool = class {
|
|
|
162
165
|
};
|
|
163
166
|
|
|
164
167
|
// src/dieline.ts
|
|
165
|
-
import {
|
|
168
|
+
import {
|
|
169
|
+
Path,
|
|
170
|
+
PooderLayer as PooderLayer2,
|
|
171
|
+
Pattern
|
|
172
|
+
} from "@pooder/core";
|
|
166
173
|
|
|
167
174
|
// src/geometry.ts
|
|
168
175
|
import paper from "paper";
|
|
@@ -315,7 +322,8 @@ var DielineTool = class {
|
|
|
315
322
|
offset: 0,
|
|
316
323
|
style: "solid",
|
|
317
324
|
insideColor: "rgba(0,0,0,0)",
|
|
318
|
-
outsideColor: "#ffffff"
|
|
325
|
+
outsideColor: "#ffffff",
|
|
326
|
+
showBleedLines: true
|
|
319
327
|
};
|
|
320
328
|
this.schema = {
|
|
321
329
|
shape: {
|
|
@@ -330,6 +338,7 @@ var DielineTool = class {
|
|
|
330
338
|
// Complex object, simplified for now or need custom handler
|
|
331
339
|
borderLength: { type: "number", min: 0, max: 500, label: "Margin" },
|
|
332
340
|
offset: { type: "number", min: -100, max: 100, label: "Bleed Offset" },
|
|
341
|
+
showBleedLines: { type: "boolean", label: "Show Bleed Lines" },
|
|
333
342
|
style: {
|
|
334
343
|
type: "select",
|
|
335
344
|
options: ["solid", "dashed"],
|
|
@@ -349,7 +358,8 @@ var DielineTool = class {
|
|
|
349
358
|
offset: 0,
|
|
350
359
|
style: "solid",
|
|
351
360
|
insideColor: "rgba(0,0,0,0)",
|
|
352
|
-
outsideColor: "#ffffff"
|
|
361
|
+
outsideColor: "#ffffff",
|
|
362
|
+
showBleedLines: true
|
|
353
363
|
};
|
|
354
364
|
this.updateDieline(editor);
|
|
355
365
|
return true;
|
|
@@ -363,7 +373,8 @@ var DielineTool = class {
|
|
|
363
373
|
},
|
|
364
374
|
setDimensions: {
|
|
365
375
|
execute: (editor, width, height) => {
|
|
366
|
-
if (this.options.width === width && this.options.height === height)
|
|
376
|
+
if (this.options.width === width && this.options.height === height)
|
|
377
|
+
return true;
|
|
367
378
|
this.options.width = width;
|
|
368
379
|
this.options.height = height;
|
|
369
380
|
this.updateDieline(editor);
|
|
@@ -418,6 +429,94 @@ var DielineTool = class {
|
|
|
418
429
|
required: true
|
|
419
430
|
}
|
|
420
431
|
}
|
|
432
|
+
},
|
|
433
|
+
exportCutImage: {
|
|
434
|
+
execute: (editor) => {
|
|
435
|
+
var _a, _b, _c, _d;
|
|
436
|
+
const { shape, width, height, radius, position } = this.options;
|
|
437
|
+
const canvasW = editor.canvas.width || 800;
|
|
438
|
+
const canvasH = editor.canvas.height || 600;
|
|
439
|
+
const cx = (_a = position == null ? void 0 : position.x) != null ? _a : canvasW / 2;
|
|
440
|
+
const cy = (_b = position == null ? void 0 : position.y) != null ? _b : canvasH / 2;
|
|
441
|
+
const holeTool = editor.getExtension("HoleTool");
|
|
442
|
+
const holes = holeTool ? holeTool.options.holes || [] : [];
|
|
443
|
+
const innerRadius = holeTool ? holeTool.options.innerRadius || 15 : 15;
|
|
444
|
+
const outerRadius = holeTool ? holeTool.options.outerRadius || 25 : 25;
|
|
445
|
+
const holeData = holes.map((h) => ({
|
|
446
|
+
x: h.x,
|
|
447
|
+
y: h.y,
|
|
448
|
+
innerRadius,
|
|
449
|
+
outerRadius
|
|
450
|
+
}));
|
|
451
|
+
const pathData = generateDielinePath({
|
|
452
|
+
shape,
|
|
453
|
+
width,
|
|
454
|
+
height,
|
|
455
|
+
radius,
|
|
456
|
+
x: cx,
|
|
457
|
+
y: cy,
|
|
458
|
+
holes: holeData
|
|
459
|
+
});
|
|
460
|
+
const clipPath = new Path(pathData, {
|
|
461
|
+
left: 0,
|
|
462
|
+
top: 0,
|
|
463
|
+
originX: "left",
|
|
464
|
+
originY: "top",
|
|
465
|
+
absolutePositioned: true
|
|
466
|
+
});
|
|
467
|
+
const layer = this.getLayer(editor, "dieline-overlay");
|
|
468
|
+
const wasVisible = (_c = layer == null ? void 0 : layer.visible) != null ? _c : true;
|
|
469
|
+
if (layer) layer.visible = false;
|
|
470
|
+
const holeMarkers = editor.canvas.getObjects().filter((o) => {
|
|
471
|
+
var _a2;
|
|
472
|
+
return ((_a2 = o.data) == null ? void 0 : _a2.type) === "hole-marker";
|
|
473
|
+
});
|
|
474
|
+
holeMarkers.forEach((o) => o.visible = false);
|
|
475
|
+
const rulerLayer = editor.canvas.getObjects().find((obj) => {
|
|
476
|
+
var _a2;
|
|
477
|
+
return ((_a2 = obj.data) == null ? void 0 : _a2.id) === "ruler-overlay";
|
|
478
|
+
});
|
|
479
|
+
const rulerWasVisible = (_d = rulerLayer == null ? void 0 : rulerLayer.visible) != null ? _d : true;
|
|
480
|
+
if (rulerLayer) rulerLayer.visible = false;
|
|
481
|
+
const originalClip = editor.canvas.clipPath;
|
|
482
|
+
editor.canvas.clipPath = clipPath;
|
|
483
|
+
const bbox = clipPath.getBoundingRect();
|
|
484
|
+
const holeDataRelative = holes.map((h) => ({
|
|
485
|
+
x: h.x - bbox.left,
|
|
486
|
+
y: h.y - bbox.top,
|
|
487
|
+
innerRadius,
|
|
488
|
+
outerRadius
|
|
489
|
+
}));
|
|
490
|
+
const clipPathCorrected = new Path(pathData, {
|
|
491
|
+
absolutePositioned: true,
|
|
492
|
+
left: 0,
|
|
493
|
+
top: 0
|
|
494
|
+
});
|
|
495
|
+
const tempPath = new Path(pathData);
|
|
496
|
+
const tempBounds = tempPath.getBoundingRect();
|
|
497
|
+
clipPathCorrected.set({
|
|
498
|
+
left: tempBounds.left,
|
|
499
|
+
top: tempBounds.top,
|
|
500
|
+
originX: "left",
|
|
501
|
+
originY: "top"
|
|
502
|
+
});
|
|
503
|
+
editor.canvas.clipPath = clipPathCorrected;
|
|
504
|
+
const exportBbox = clipPathCorrected.getBoundingRect();
|
|
505
|
+
const dataURL = editor.canvas.toDataURL({
|
|
506
|
+
format: "png",
|
|
507
|
+
multiplier: 2,
|
|
508
|
+
left: exportBbox.left,
|
|
509
|
+
top: exportBbox.top,
|
|
510
|
+
width: exportBbox.width,
|
|
511
|
+
height: exportBbox.height
|
|
512
|
+
});
|
|
513
|
+
editor.canvas.clipPath = originalClip;
|
|
514
|
+
if (layer) layer.visible = wasVisible;
|
|
515
|
+
if (rulerLayer) rulerLayer.visible = rulerWasVisible;
|
|
516
|
+
holeMarkers.forEach((o) => o.visible = true);
|
|
517
|
+
editor.canvas.requestRenderAll();
|
|
518
|
+
return dataURL;
|
|
519
|
+
}
|
|
421
520
|
}
|
|
422
521
|
};
|
|
423
522
|
}
|
|
@@ -484,7 +583,17 @@ var DielineTool = class {
|
|
|
484
583
|
}
|
|
485
584
|
updateDieline(editor) {
|
|
486
585
|
var _a, _b;
|
|
487
|
-
const {
|
|
586
|
+
const {
|
|
587
|
+
shape,
|
|
588
|
+
radius,
|
|
589
|
+
offset,
|
|
590
|
+
style,
|
|
591
|
+
insideColor,
|
|
592
|
+
outsideColor,
|
|
593
|
+
position,
|
|
594
|
+
borderLength,
|
|
595
|
+
showBleedLines
|
|
596
|
+
} = this.options;
|
|
488
597
|
let { width, height } = this.options;
|
|
489
598
|
const canvasW = editor.canvas.width || 800;
|
|
490
599
|
const canvasH = editor.canvas.height || 600;
|
|
@@ -498,6 +607,9 @@ var DielineTool = class {
|
|
|
498
607
|
if (!layer) return;
|
|
499
608
|
layer.remove(...layer.getObjects());
|
|
500
609
|
const holeTool = editor.getExtension("HoleTool");
|
|
610
|
+
if (holeTool && typeof holeTool.enforceConstraints === "function") {
|
|
611
|
+
holeTool.enforceConstraints(editor);
|
|
612
|
+
}
|
|
501
613
|
const holes = holeTool ? holeTool.options.holes || [] : [];
|
|
502
614
|
const innerRadius = holeTool ? holeTool.options.innerRadius || 15 : 15;
|
|
503
615
|
const outerRadius = holeTool ? holeTool.options.outerRadius || 25 : 25;
|
|
@@ -554,27 +666,32 @@ var DielineTool = class {
|
|
|
554
666
|
layer.add(insideObj);
|
|
555
667
|
}
|
|
556
668
|
if (offset !== 0) {
|
|
557
|
-
const bleedPathData = generateBleedZonePath(
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
669
|
+
const bleedPathData = generateBleedZonePath(
|
|
670
|
+
{
|
|
671
|
+
shape,
|
|
672
|
+
width,
|
|
673
|
+
height,
|
|
674
|
+
radius,
|
|
675
|
+
x: cx,
|
|
676
|
+
y: cy,
|
|
677
|
+
holes: holeData
|
|
678
|
+
},
|
|
679
|
+
offset
|
|
680
|
+
);
|
|
681
|
+
if (showBleedLines !== false) {
|
|
682
|
+
const pattern = this.createHatchPattern("red");
|
|
683
|
+
if (pattern) {
|
|
684
|
+
const bleedObj = new Path(bleedPathData, {
|
|
685
|
+
fill: pattern,
|
|
686
|
+
stroke: null,
|
|
687
|
+
selectable: false,
|
|
688
|
+
evented: false,
|
|
689
|
+
objectCaching: false,
|
|
690
|
+
originX: "left",
|
|
691
|
+
originY: "top"
|
|
692
|
+
});
|
|
693
|
+
layer.add(bleedObj);
|
|
694
|
+
}
|
|
578
695
|
}
|
|
579
696
|
const offsetPathData = generateDielinePath({
|
|
580
697
|
shape,
|
|
@@ -646,7 +763,10 @@ var DielineTool = class {
|
|
|
646
763
|
};
|
|
647
764
|
|
|
648
765
|
// src/film.ts
|
|
649
|
-
import {
|
|
766
|
+
import {
|
|
767
|
+
Image as Image2,
|
|
768
|
+
PooderLayer as PooderLayer3
|
|
769
|
+
} from "@pooder/core";
|
|
650
770
|
var FilmTool = class {
|
|
651
771
|
constructor() {
|
|
652
772
|
this.name = "FilmTool";
|
|
@@ -670,7 +790,8 @@ var FilmTool = class {
|
|
|
670
790
|
this.commands = {
|
|
671
791
|
setFilmImage: {
|
|
672
792
|
execute: (editor, url, opacity) => {
|
|
673
|
-
if (this.options.url === url && this.options.opacity === opacity)
|
|
793
|
+
if (this.options.url === url && this.options.opacity === opacity)
|
|
794
|
+
return true;
|
|
674
795
|
this.options.url = url;
|
|
675
796
|
this.options.opacity = opacity;
|
|
676
797
|
this.updateFilm(editor, this.options);
|
|
@@ -761,8 +882,7 @@ var FilmTool = class {
|
|
|
761
882
|
} else {
|
|
762
883
|
img = await Image2.fromURL(url, { crossOrigin: "anonymous" });
|
|
763
884
|
img.scaleToWidth(width);
|
|
764
|
-
if (img.getScaledHeight() < height)
|
|
765
|
-
img.scaleToHeight(height);
|
|
885
|
+
if (img.getScaledHeight() < height) img.scaleToHeight(height);
|
|
766
886
|
img.set({
|
|
767
887
|
originX: "left",
|
|
768
888
|
originY: "top",
|
|
@@ -783,7 +903,11 @@ var FilmTool = class {
|
|
|
783
903
|
};
|
|
784
904
|
|
|
785
905
|
// src/hole.ts
|
|
786
|
-
import {
|
|
906
|
+
import {
|
|
907
|
+
Circle as Circle2,
|
|
908
|
+
Group,
|
|
909
|
+
Point
|
|
910
|
+
} from "@pooder/core";
|
|
787
911
|
var HoleTool = class {
|
|
788
912
|
constructor() {
|
|
789
913
|
this.name = "HoleTool";
|
|
@@ -791,7 +915,8 @@ var HoleTool = class {
|
|
|
791
915
|
innerRadius: 15,
|
|
792
916
|
outerRadius: 25,
|
|
793
917
|
style: "solid",
|
|
794
|
-
holes: []
|
|
918
|
+
holes: [],
|
|
919
|
+
constraintTarget: "bleed"
|
|
795
920
|
};
|
|
796
921
|
this.schema = {
|
|
797
922
|
innerRadius: {
|
|
@@ -811,6 +936,11 @@ var HoleTool = class {
|
|
|
811
936
|
options: ["solid", "dashed"],
|
|
812
937
|
label: "Line Style"
|
|
813
938
|
},
|
|
939
|
+
constraintTarget: {
|
|
940
|
+
type: "select",
|
|
941
|
+
options: ["original", "bleed"],
|
|
942
|
+
label: "Constraint Target"
|
|
943
|
+
},
|
|
814
944
|
holes: {
|
|
815
945
|
type: "json",
|
|
816
946
|
label: "Holes"
|
|
@@ -825,7 +955,10 @@ var HoleTool = class {
|
|
|
825
955
|
const g = this.getDielineGeometry(editor);
|
|
826
956
|
if (g) {
|
|
827
957
|
const topCenter = { x: g.x, y: g.y - g.height / 2 };
|
|
828
|
-
defaultPos = getNearestPointOnDieline(topCenter, {
|
|
958
|
+
defaultPos = getNearestPointOnDieline(topCenter, {
|
|
959
|
+
...g,
|
|
960
|
+
holes: []
|
|
961
|
+
});
|
|
829
962
|
}
|
|
830
963
|
this.options = {
|
|
831
964
|
innerRadius: 15,
|
|
@@ -892,7 +1025,7 @@ var HoleTool = class {
|
|
|
892
1025
|
if (!dielineTool) return null;
|
|
893
1026
|
const geometry = dielineTool.getGeometry(editor);
|
|
894
1027
|
if (!geometry) return null;
|
|
895
|
-
const offset = dielineTool.options.offset || 0;
|
|
1028
|
+
const offset = this.options.constraintTarget === "original" ? 0 : dielineTool.options.offset || 0;
|
|
896
1029
|
return {
|
|
897
1030
|
...geometry,
|
|
898
1031
|
width: Math.max(0, geometry.width + offset * 2),
|
|
@@ -900,6 +1033,39 @@ var HoleTool = class {
|
|
|
900
1033
|
radius: Math.max(0, geometry.radius + offset)
|
|
901
1034
|
};
|
|
902
1035
|
}
|
|
1036
|
+
enforceConstraints(editor) {
|
|
1037
|
+
const geometry = this.getDielineGeometry(editor);
|
|
1038
|
+
if (!geometry) return;
|
|
1039
|
+
const objects = editor.canvas.getObjects().filter((obj) => {
|
|
1040
|
+
var _a;
|
|
1041
|
+
return ((_a = obj.data) == null ? void 0 : _a.type) === "hole-marker";
|
|
1042
|
+
});
|
|
1043
|
+
let changed = false;
|
|
1044
|
+
objects.sort(
|
|
1045
|
+
(a, b) => {
|
|
1046
|
+
var _a, _b, _c, _d;
|
|
1047
|
+
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);
|
|
1048
|
+
}
|
|
1049
|
+
);
|
|
1050
|
+
const newHoles = [];
|
|
1051
|
+
objects.forEach((obj) => {
|
|
1052
|
+
const currentPos = new Point(obj.left, obj.top);
|
|
1053
|
+
const newPos = this.calculateConstrainedPosition(currentPos, geometry);
|
|
1054
|
+
if (currentPos.distanceFrom(newPos) > 0.1) {
|
|
1055
|
+
obj.set({
|
|
1056
|
+
left: newPos.x,
|
|
1057
|
+
top: newPos.y
|
|
1058
|
+
});
|
|
1059
|
+
obj.setCoords();
|
|
1060
|
+
changed = true;
|
|
1061
|
+
}
|
|
1062
|
+
newHoles.push({ x: obj.left, y: obj.top });
|
|
1063
|
+
});
|
|
1064
|
+
if (changed) {
|
|
1065
|
+
this.options.holes = newHoles;
|
|
1066
|
+
editor.canvas.requestRenderAll();
|
|
1067
|
+
}
|
|
1068
|
+
}
|
|
903
1069
|
setup(editor) {
|
|
904
1070
|
if (!this.handleMoving) {
|
|
905
1071
|
this.handleMoving = (e) => {
|
|
@@ -932,7 +1098,10 @@ var HoleTool = class {
|
|
|
932
1098
|
const g = this.getDielineGeometry(editor);
|
|
933
1099
|
if (g) {
|
|
934
1100
|
const topCenter = { x: g.x, y: g.y - g.height / 2 };
|
|
935
|
-
const snapped = getNearestPointOnDieline(topCenter, {
|
|
1101
|
+
const snapped = getNearestPointOnDieline(topCenter, {
|
|
1102
|
+
...g,
|
|
1103
|
+
holes: []
|
|
1104
|
+
});
|
|
936
1105
|
defaultPos = snapped;
|
|
937
1106
|
}
|
|
938
1107
|
opts.holes = [defaultPos];
|
|
@@ -961,6 +1130,12 @@ var HoleTool = class {
|
|
|
961
1130
|
editor.canvas.requestRenderAll();
|
|
962
1131
|
}
|
|
963
1132
|
onUpdate(editor, state) {
|
|
1133
|
+
this.enforceConstraints(editor);
|
|
1134
|
+
this.redraw(editor);
|
|
1135
|
+
const dielineTool = editor.getExtension("DielineTool");
|
|
1136
|
+
if (dielineTool && dielineTool.updateDieline) {
|
|
1137
|
+
dielineTool.updateDieline(editor);
|
|
1138
|
+
}
|
|
964
1139
|
}
|
|
965
1140
|
syncHolesFromCanvas(editor) {
|
|
966
1141
|
const objects = editor.canvas.getObjects().filter((obj) => {
|
|
@@ -1049,7 +1224,10 @@ var HoleTool = class {
|
|
|
1049
1224
|
holes: []
|
|
1050
1225
|
// We don't need holes for boundary calculation
|
|
1051
1226
|
};
|
|
1052
|
-
const nearest = getNearestPointOnDieline(
|
|
1227
|
+
const nearest = getNearestPointOnDieline(
|
|
1228
|
+
{ x: p.x, y: p.y },
|
|
1229
|
+
options
|
|
1230
|
+
);
|
|
1053
1231
|
const nearestP = new Point(nearest.x, nearest.y);
|
|
1054
1232
|
const dist = p.distanceFrom(nearestP);
|
|
1055
1233
|
const v = p.subtract(nearestP);
|
|
@@ -1076,10 +1254,16 @@ var HoleTool = class {
|
|
|
1076
1254
|
};
|
|
1077
1255
|
|
|
1078
1256
|
// src/image.ts
|
|
1079
|
-
import {
|
|
1257
|
+
import {
|
|
1258
|
+
Image as Image3,
|
|
1259
|
+
PooderLayer as PooderLayer4,
|
|
1260
|
+
util,
|
|
1261
|
+
Point as Point2
|
|
1262
|
+
} from "@pooder/core";
|
|
1080
1263
|
var ImageTool = class {
|
|
1081
1264
|
constructor() {
|
|
1082
1265
|
this.name = "ImageTool";
|
|
1266
|
+
this._loadingUrl = null;
|
|
1083
1267
|
this.options = {
|
|
1084
1268
|
url: "",
|
|
1085
1269
|
opacity: 1
|
|
@@ -1095,14 +1279,44 @@ var ImageTool = class {
|
|
|
1095
1279
|
max: 1,
|
|
1096
1280
|
step: 0.1,
|
|
1097
1281
|
label: "Opacity"
|
|
1282
|
+
},
|
|
1283
|
+
width: {
|
|
1284
|
+
type: "number",
|
|
1285
|
+
label: "Width",
|
|
1286
|
+
min: 0,
|
|
1287
|
+
max: 5e3
|
|
1288
|
+
},
|
|
1289
|
+
height: {
|
|
1290
|
+
type: "number",
|
|
1291
|
+
label: "Height",
|
|
1292
|
+
min: 0,
|
|
1293
|
+
max: 5e3
|
|
1294
|
+
},
|
|
1295
|
+
angle: {
|
|
1296
|
+
type: "number",
|
|
1297
|
+
label: "Rotation",
|
|
1298
|
+
min: 0,
|
|
1299
|
+
max: 360
|
|
1300
|
+
},
|
|
1301
|
+
left: {
|
|
1302
|
+
type: "number",
|
|
1303
|
+
label: "Left",
|
|
1304
|
+
min: 0,
|
|
1305
|
+
max: 1e3
|
|
1306
|
+
},
|
|
1307
|
+
top: {
|
|
1308
|
+
type: "number",
|
|
1309
|
+
label: "Top",
|
|
1310
|
+
min: 0,
|
|
1311
|
+
max: 1e3
|
|
1098
1312
|
}
|
|
1099
1313
|
};
|
|
1100
1314
|
this.commands = {
|
|
1101
1315
|
setUserImage: {
|
|
1102
|
-
execute: (editor, url, opacity) => {
|
|
1103
|
-
if (this.options.url === url && this.options.opacity === opacity
|
|
1104
|
-
|
|
1105
|
-
this.options
|
|
1316
|
+
execute: (editor, url, opacity, width, height, angle, left, top) => {
|
|
1317
|
+
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)
|
|
1318
|
+
return true;
|
|
1319
|
+
this.options = { url, opacity, width, height, angle, left, top };
|
|
1106
1320
|
this.updateImage(editor, this.options);
|
|
1107
1321
|
return true;
|
|
1108
1322
|
},
|
|
@@ -1118,7 +1332,12 @@ var ImageTool = class {
|
|
|
1118
1332
|
min: 0,
|
|
1119
1333
|
max: 1,
|
|
1120
1334
|
required: true
|
|
1121
|
-
}
|
|
1335
|
+
},
|
|
1336
|
+
width: { type: "number", label: "Width" },
|
|
1337
|
+
height: { type: "number", label: "Height" },
|
|
1338
|
+
angle: { type: "number", label: "Angle" },
|
|
1339
|
+
left: { type: "number", label: "Left" },
|
|
1340
|
+
top: { type: "number", label: "Top" }
|
|
1122
1341
|
}
|
|
1123
1342
|
}
|
|
1124
1343
|
};
|
|
@@ -1163,43 +1382,101 @@ var ImageTool = class {
|
|
|
1163
1382
|
}
|
|
1164
1383
|
updateImage(editor, opts) {
|
|
1165
1384
|
var _a, _b;
|
|
1166
|
-
let { url, opacity } = opts;
|
|
1385
|
+
let { url, opacity, width, height, angle, left, top } = opts;
|
|
1167
1386
|
const layer = editor.getLayer("user");
|
|
1168
1387
|
if (!layer) {
|
|
1169
1388
|
console.warn("[ImageTool] User layer not found");
|
|
1170
1389
|
return;
|
|
1171
1390
|
}
|
|
1172
1391
|
const userImage = editor.getObject("user-image", "user");
|
|
1392
|
+
if (this._loadingUrl === url) return;
|
|
1173
1393
|
if (userImage) {
|
|
1174
1394
|
const currentSrc = ((_a = userImage.getSrc) == null ? void 0 : _a.call(userImage)) || ((_b = userImage._element) == null ? void 0 : _b.src);
|
|
1175
1395
|
if (currentSrc !== url) {
|
|
1176
|
-
this.loadImage(editor, layer,
|
|
1396
|
+
this.loadImage(editor, layer, opts);
|
|
1177
1397
|
} else {
|
|
1178
|
-
|
|
1179
|
-
|
|
1398
|
+
const updates = {};
|
|
1399
|
+
const centerX = editor.state.width / 2;
|
|
1400
|
+
const centerY = editor.state.height / 2;
|
|
1401
|
+
if (userImage.opacity !== opacity) updates.opacity = opacity;
|
|
1402
|
+
if (angle !== void 0 && userImage.angle !== angle)
|
|
1403
|
+
updates.angle = angle;
|
|
1404
|
+
if (left !== void 0) {
|
|
1405
|
+
const localLeft = left - centerX;
|
|
1406
|
+
if (Math.abs(userImage.left - localLeft) > 1)
|
|
1407
|
+
updates.left = localLeft;
|
|
1408
|
+
}
|
|
1409
|
+
if (top !== void 0) {
|
|
1410
|
+
const localTop = top - centerY;
|
|
1411
|
+
if (Math.abs(userImage.top - localTop) > 1) updates.top = localTop;
|
|
1412
|
+
}
|
|
1413
|
+
if (width !== void 0 && userImage.width)
|
|
1414
|
+
updates.scaleX = width / userImage.width;
|
|
1415
|
+
if (height !== void 0 && userImage.height)
|
|
1416
|
+
updates.scaleY = height / userImage.height;
|
|
1417
|
+
if (Object.keys(updates).length > 0) {
|
|
1418
|
+
userImage.set(updates);
|
|
1180
1419
|
editor.canvas.requestRenderAll();
|
|
1181
1420
|
}
|
|
1182
1421
|
}
|
|
1183
1422
|
} else {
|
|
1184
|
-
this.loadImage(editor, layer,
|
|
1423
|
+
this.loadImage(editor, layer, opts);
|
|
1185
1424
|
}
|
|
1186
1425
|
}
|
|
1187
|
-
loadImage(editor, layer,
|
|
1426
|
+
loadImage(editor, layer, opts) {
|
|
1427
|
+
const { url } = opts;
|
|
1428
|
+
this._loadingUrl = url;
|
|
1188
1429
|
Image3.fromURL(url).then((image) => {
|
|
1189
|
-
if (
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1430
|
+
if (this._loadingUrl !== url) return;
|
|
1431
|
+
this._loadingUrl = null;
|
|
1432
|
+
const currentOpts = this.options;
|
|
1433
|
+
const { opacity, width, height, angle, left, top } = currentOpts;
|
|
1434
|
+
const existingImage = editor.getObject("user-image", "user");
|
|
1435
|
+
if (existingImage) {
|
|
1436
|
+
const defaultLeft = existingImage.left;
|
|
1437
|
+
const defaultTop = existingImage.top;
|
|
1438
|
+
const defaultAngle = existingImage.angle;
|
|
1439
|
+
const defaultScaleX = existingImage.scaleX;
|
|
1440
|
+
const defaultScaleY = existingImage.scaleY;
|
|
1441
|
+
image.set({
|
|
1442
|
+
left: left !== void 0 ? left : defaultLeft,
|
|
1443
|
+
top: top !== void 0 ? top : defaultTop,
|
|
1444
|
+
angle: angle !== void 0 ? angle : defaultAngle,
|
|
1445
|
+
scaleX: width !== void 0 && image.width ? width / image.width : defaultScaleX,
|
|
1446
|
+
scaleY: height !== void 0 && image.height ? height / image.height : defaultScaleY
|
|
1447
|
+
});
|
|
1448
|
+
layer.remove(existingImage);
|
|
1449
|
+
} else {
|
|
1450
|
+
if (width !== void 0 && image.width)
|
|
1451
|
+
image.scaleX = width / image.width;
|
|
1452
|
+
if (height !== void 0 && image.height)
|
|
1453
|
+
image.scaleY = height / image.height;
|
|
1454
|
+
if (angle !== void 0) image.angle = angle;
|
|
1455
|
+
if (left !== void 0) image.left = left;
|
|
1456
|
+
if (top !== void 0) image.top = top;
|
|
1193
1457
|
}
|
|
1194
1458
|
image.set({
|
|
1195
|
-
opacity,
|
|
1459
|
+
opacity: opacity !== void 0 ? opacity : 1,
|
|
1196
1460
|
data: {
|
|
1197
1461
|
id: "user-image"
|
|
1198
1462
|
}
|
|
1199
1463
|
});
|
|
1200
1464
|
layer.add(image);
|
|
1465
|
+
image.on("modified", (e) => {
|
|
1466
|
+
const matrix = image.calcTransformMatrix();
|
|
1467
|
+
const globalPoint = util.transformPoint(new Point2(0, 0), matrix);
|
|
1468
|
+
this.options.left = globalPoint.x;
|
|
1469
|
+
this.options.top = globalPoint.y;
|
|
1470
|
+
this.options.angle = e.target.angle;
|
|
1471
|
+
if (image.width)
|
|
1472
|
+
this.options.width = e.target.width * e.target.scaleX;
|
|
1473
|
+
if (image.height)
|
|
1474
|
+
this.options.height = e.target.height * e.target.scaleY;
|
|
1475
|
+
editor.emit("update");
|
|
1476
|
+
});
|
|
1201
1477
|
editor.canvas.requestRenderAll();
|
|
1202
1478
|
}).catch((err) => {
|
|
1479
|
+
if (this._loadingUrl === url) this._loadingUrl = null;
|
|
1203
1480
|
console.error("Failed to load image", url, err);
|
|
1204
1481
|
});
|
|
1205
1482
|
}
|
|
@@ -1227,7 +1504,8 @@ var WhiteInkTool = class {
|
|
|
1227
1504
|
this.commands = {
|
|
1228
1505
|
setWhiteInkImage: {
|
|
1229
1506
|
execute: (editor, customMask, opacity, enableClip = true) => {
|
|
1230
|
-
if (this.options.customMask === customMask && this.options.opacity === opacity && this.options.enableClip === enableClip)
|
|
1507
|
+
if (this.options.customMask === customMask && this.options.opacity === opacity && this.options.enableClip === enableClip)
|
|
1508
|
+
return true;
|
|
1231
1509
|
this.options.customMask = customMask;
|
|
1232
1510
|
this.options.opacity = opacity;
|
|
1233
1511
|
this.options.enableClip = enableClip;
|
|
@@ -1348,7 +1626,14 @@ var WhiteInkTool = class {
|
|
|
1348
1626
|
if (whiteInk) {
|
|
1349
1627
|
const currentSrc = ((_a = whiteInk.getSrc) == null ? void 0 : _a.call(whiteInk)) || ((_b = whiteInk._element) == null ? void 0 : _b.src);
|
|
1350
1628
|
if (currentSrc !== customMask) {
|
|
1351
|
-
this.loadWhiteInk(
|
|
1629
|
+
this.loadWhiteInk(
|
|
1630
|
+
editor,
|
|
1631
|
+
layer,
|
|
1632
|
+
customMask,
|
|
1633
|
+
opacity,
|
|
1634
|
+
enableClip,
|
|
1635
|
+
whiteInk
|
|
1636
|
+
);
|
|
1352
1637
|
} else {
|
|
1353
1638
|
if (whiteInk.opacity !== opacity) {
|
|
1354
1639
|
whiteInk.set({ opacity });
|
|
@@ -1377,10 +1662,12 @@ var WhiteInkTool = class {
|
|
|
1377
1662
|
if (oldImage) {
|
|
1378
1663
|
layer.remove(oldImage);
|
|
1379
1664
|
}
|
|
1380
|
-
(_a = image.filters) == null ? void 0 : _a.push(
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1665
|
+
(_a = image.filters) == null ? void 0 : _a.push(
|
|
1666
|
+
new filters.BlendColor({
|
|
1667
|
+
color: "#FFFFFF",
|
|
1668
|
+
mode: "add"
|
|
1669
|
+
})
|
|
1670
|
+
);
|
|
1384
1671
|
image.applyFilters();
|
|
1385
1672
|
image.set({
|
|
1386
1673
|
opacity,
|
|
@@ -1448,7 +1735,12 @@ var WhiteInkTool = class {
|
|
|
1448
1735
|
};
|
|
1449
1736
|
|
|
1450
1737
|
// src/ruler.ts
|
|
1451
|
-
import {
|
|
1738
|
+
import {
|
|
1739
|
+
PooderLayer as PooderLayer6,
|
|
1740
|
+
Rect as Rect3,
|
|
1741
|
+
Line,
|
|
1742
|
+
Text
|
|
1743
|
+
} from "@pooder/core";
|
|
1452
1744
|
var RulerTool = class {
|
|
1453
1745
|
constructor() {
|
|
1454
1746
|
this.name = "RulerTool";
|
|
@@ -1492,7 +1784,8 @@ var RulerTool = class {
|
|
|
1492
1784
|
setTheme: {
|
|
1493
1785
|
execute: (editor, theme) => {
|
|
1494
1786
|
const newOptions = { ...this.options, ...theme };
|
|
1495
|
-
if (JSON.stringify(newOptions) === JSON.stringify(this.options))
|
|
1787
|
+
if (JSON.stringify(newOptions) === JSON.stringify(this.options))
|
|
1788
|
+
return true;
|
|
1496
1789
|
this.options = newOptions;
|
|
1497
1790
|
this.updateRuler(editor);
|
|
1498
1791
|
return true;
|
|
@@ -1646,12 +1939,83 @@ var RulerTool = class {
|
|
|
1646
1939
|
editor.canvas.requestRenderAll();
|
|
1647
1940
|
}
|
|
1648
1941
|
};
|
|
1942
|
+
|
|
1943
|
+
// src/mirror.ts
|
|
1944
|
+
var MirrorTool = class {
|
|
1945
|
+
constructor() {
|
|
1946
|
+
this.name = "MirrorTool";
|
|
1947
|
+
this.options = {
|
|
1948
|
+
enabled: false
|
|
1949
|
+
};
|
|
1950
|
+
this.schema = {
|
|
1951
|
+
enabled: {
|
|
1952
|
+
type: "boolean",
|
|
1953
|
+
label: "Mirror View"
|
|
1954
|
+
}
|
|
1955
|
+
};
|
|
1956
|
+
this.commands = {
|
|
1957
|
+
toggleMirror: {
|
|
1958
|
+
execute: (editor) => {
|
|
1959
|
+
this.options.enabled = !this.options.enabled;
|
|
1960
|
+
this.applyMirror(editor, this.options.enabled);
|
|
1961
|
+
return true;
|
|
1962
|
+
}
|
|
1963
|
+
},
|
|
1964
|
+
setMirror: {
|
|
1965
|
+
execute: (editor, enabled) => {
|
|
1966
|
+
if (this.options.enabled === enabled) return true;
|
|
1967
|
+
this.options.enabled = enabled;
|
|
1968
|
+
this.applyMirror(editor, enabled);
|
|
1969
|
+
return true;
|
|
1970
|
+
},
|
|
1971
|
+
schema: {
|
|
1972
|
+
enabled: {
|
|
1973
|
+
type: "boolean",
|
|
1974
|
+
label: "Enabled",
|
|
1975
|
+
required: true
|
|
1976
|
+
}
|
|
1977
|
+
}
|
|
1978
|
+
}
|
|
1979
|
+
};
|
|
1980
|
+
}
|
|
1981
|
+
onMount(editor) {
|
|
1982
|
+
if (this.options.enabled) {
|
|
1983
|
+
this.applyMirror(editor, true);
|
|
1984
|
+
}
|
|
1985
|
+
}
|
|
1986
|
+
onUpdate(editor) {
|
|
1987
|
+
this.applyMirror(editor, this.options.enabled);
|
|
1988
|
+
}
|
|
1989
|
+
onUnmount(editor) {
|
|
1990
|
+
this.applyMirror(editor, false);
|
|
1991
|
+
}
|
|
1992
|
+
applyMirror(editor, enabled) {
|
|
1993
|
+
const canvas = editor.canvas;
|
|
1994
|
+
if (!canvas) return;
|
|
1995
|
+
const width = canvas.width || 800;
|
|
1996
|
+
let vpt = canvas.viewportTransform || [1, 0, 0, 1, 0, 0];
|
|
1997
|
+
vpt = [...vpt];
|
|
1998
|
+
const isFlipped = vpt[0] < 0;
|
|
1999
|
+
if (enabled && !isFlipped) {
|
|
2000
|
+
vpt[0] = -vpt[0];
|
|
2001
|
+
vpt[4] = width - vpt[4];
|
|
2002
|
+
canvas.setViewportTransform(vpt);
|
|
2003
|
+
canvas.requestRenderAll();
|
|
2004
|
+
} else if (!enabled && isFlipped) {
|
|
2005
|
+
vpt[0] = -vpt[0];
|
|
2006
|
+
vpt[4] = width - vpt[4];
|
|
2007
|
+
canvas.setViewportTransform(vpt);
|
|
2008
|
+
canvas.requestRenderAll();
|
|
2009
|
+
}
|
|
2010
|
+
}
|
|
2011
|
+
};
|
|
1649
2012
|
export {
|
|
1650
2013
|
BackgroundTool,
|
|
1651
2014
|
DielineTool,
|
|
1652
2015
|
FilmTool,
|
|
1653
2016
|
HoleTool,
|
|
1654
2017
|
ImageTool,
|
|
2018
|
+
MirrorTool,
|
|
1655
2019
|
RulerTool,
|
|
1656
2020
|
WhiteInkTool
|
|
1657
2021
|
};
|