@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.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";
|
|
@@ -82,10 +86,10 @@ var BackgroundTool = class {
|
|
|
82
86
|
editor.canvas.add(backgroundLayer);
|
|
83
87
|
editor.canvas.sendObjectToBack(backgroundLayer);
|
|
84
88
|
}
|
|
85
|
-
this.updateBackground(editor, this.options);
|
|
86
89
|
}
|
|
87
90
|
onMount(editor) {
|
|
88
91
|
this.initLayer(editor);
|
|
92
|
+
this.updateBackground(editor, this.options);
|
|
89
93
|
}
|
|
90
94
|
onUnmount(editor) {
|
|
91
95
|
const layer = editor.getLayer("background");
|
|
@@ -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,11 +429,100 @@ 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
|
}
|
|
424
523
|
onMount(editor) {
|
|
425
524
|
this.createLayer(editor);
|
|
525
|
+
this.updateDieline(editor);
|
|
426
526
|
}
|
|
427
527
|
onUnmount(editor) {
|
|
428
528
|
this.destroyLayer(editor);
|
|
@@ -454,7 +554,6 @@ var DielineTool = class {
|
|
|
454
554
|
editor.canvas.add(layer);
|
|
455
555
|
}
|
|
456
556
|
editor.canvas.bringObjectToFront(layer);
|
|
457
|
-
this.updateDieline(editor);
|
|
458
557
|
}
|
|
459
558
|
destroyLayer(editor) {
|
|
460
559
|
const layer = this.getLayer(editor, "dieline-overlay");
|
|
@@ -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);
|
|
@@ -708,6 +829,7 @@ var FilmTool = class {
|
|
|
708
829
|
}
|
|
709
830
|
}
|
|
710
831
|
onUpdate(editor, state) {
|
|
832
|
+
this.updateFilm(editor, this.options);
|
|
711
833
|
}
|
|
712
834
|
initLayer(editor) {
|
|
713
835
|
let overlayLayer = editor.getLayer("overlay");
|
|
@@ -760,8 +882,7 @@ var FilmTool = class {
|
|
|
760
882
|
} else {
|
|
761
883
|
img = await Image2.fromURL(url, { crossOrigin: "anonymous" });
|
|
762
884
|
img.scaleToWidth(width);
|
|
763
|
-
if (img.getScaledHeight() < height)
|
|
764
|
-
img.scaleToHeight(height);
|
|
885
|
+
if (img.getScaledHeight() < height) img.scaleToHeight(height);
|
|
765
886
|
img.set({
|
|
766
887
|
originX: "left",
|
|
767
888
|
originY: "top",
|
|
@@ -782,7 +903,11 @@ var FilmTool = class {
|
|
|
782
903
|
};
|
|
783
904
|
|
|
784
905
|
// src/hole.ts
|
|
785
|
-
import {
|
|
906
|
+
import {
|
|
907
|
+
Circle as Circle2,
|
|
908
|
+
Group,
|
|
909
|
+
Point
|
|
910
|
+
} from "@pooder/core";
|
|
786
911
|
var HoleTool = class {
|
|
787
912
|
constructor() {
|
|
788
913
|
this.name = "HoleTool";
|
|
@@ -790,7 +915,8 @@ var HoleTool = class {
|
|
|
790
915
|
innerRadius: 15,
|
|
791
916
|
outerRadius: 25,
|
|
792
917
|
style: "solid",
|
|
793
|
-
holes: []
|
|
918
|
+
holes: [],
|
|
919
|
+
constraintTarget: "bleed"
|
|
794
920
|
};
|
|
795
921
|
this.schema = {
|
|
796
922
|
innerRadius: {
|
|
@@ -810,6 +936,11 @@ var HoleTool = class {
|
|
|
810
936
|
options: ["solid", "dashed"],
|
|
811
937
|
label: "Line Style"
|
|
812
938
|
},
|
|
939
|
+
constraintTarget: {
|
|
940
|
+
type: "select",
|
|
941
|
+
options: ["original", "bleed"],
|
|
942
|
+
label: "Constraint Target"
|
|
943
|
+
},
|
|
813
944
|
holes: {
|
|
814
945
|
type: "json",
|
|
815
946
|
label: "Holes"
|
|
@@ -824,7 +955,10 @@ var HoleTool = class {
|
|
|
824
955
|
const g = this.getDielineGeometry(editor);
|
|
825
956
|
if (g) {
|
|
826
957
|
const topCenter = { x: g.x, y: g.y - g.height / 2 };
|
|
827
|
-
defaultPos = getNearestPointOnDieline(topCenter, {
|
|
958
|
+
defaultPos = getNearestPointOnDieline(topCenter, {
|
|
959
|
+
...g,
|
|
960
|
+
holes: []
|
|
961
|
+
});
|
|
828
962
|
}
|
|
829
963
|
this.options = {
|
|
830
964
|
innerRadius: 15,
|
|
@@ -891,7 +1025,7 @@ var HoleTool = class {
|
|
|
891
1025
|
if (!dielineTool) return null;
|
|
892
1026
|
const geometry = dielineTool.getGeometry(editor);
|
|
893
1027
|
if (!geometry) return null;
|
|
894
|
-
const offset = dielineTool.options.offset || 0;
|
|
1028
|
+
const offset = this.options.constraintTarget === "original" ? 0 : dielineTool.options.offset || 0;
|
|
895
1029
|
return {
|
|
896
1030
|
...geometry,
|
|
897
1031
|
width: Math.max(0, geometry.width + offset * 2),
|
|
@@ -899,6 +1033,39 @@ var HoleTool = class {
|
|
|
899
1033
|
radius: Math.max(0, geometry.radius + offset)
|
|
900
1034
|
};
|
|
901
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
|
+
}
|
|
902
1069
|
setup(editor) {
|
|
903
1070
|
if (!this.handleMoving) {
|
|
904
1071
|
this.handleMoving = (e) => {
|
|
@@ -931,7 +1098,10 @@ var HoleTool = class {
|
|
|
931
1098
|
const g = this.getDielineGeometry(editor);
|
|
932
1099
|
if (g) {
|
|
933
1100
|
const topCenter = { x: g.x, y: g.y - g.height / 2 };
|
|
934
|
-
const snapped = getNearestPointOnDieline(topCenter, {
|
|
1101
|
+
const snapped = getNearestPointOnDieline(topCenter, {
|
|
1102
|
+
...g,
|
|
1103
|
+
holes: []
|
|
1104
|
+
});
|
|
935
1105
|
defaultPos = snapped;
|
|
936
1106
|
}
|
|
937
1107
|
opts.holes = [defaultPos];
|
|
@@ -960,6 +1130,12 @@ var HoleTool = class {
|
|
|
960
1130
|
editor.canvas.requestRenderAll();
|
|
961
1131
|
}
|
|
962
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
|
+
}
|
|
963
1139
|
}
|
|
964
1140
|
syncHolesFromCanvas(editor) {
|
|
965
1141
|
const objects = editor.canvas.getObjects().filter((obj) => {
|
|
@@ -1048,7 +1224,10 @@ var HoleTool = class {
|
|
|
1048
1224
|
holes: []
|
|
1049
1225
|
// We don't need holes for boundary calculation
|
|
1050
1226
|
};
|
|
1051
|
-
const nearest = getNearestPointOnDieline(
|
|
1227
|
+
const nearest = getNearestPointOnDieline(
|
|
1228
|
+
{ x: p.x, y: p.y },
|
|
1229
|
+
options
|
|
1230
|
+
);
|
|
1052
1231
|
const nearestP = new Point(nearest.x, nearest.y);
|
|
1053
1232
|
const dist = p.distanceFrom(nearestP);
|
|
1054
1233
|
const v = p.subtract(nearestP);
|
|
@@ -1075,10 +1254,16 @@ var HoleTool = class {
|
|
|
1075
1254
|
};
|
|
1076
1255
|
|
|
1077
1256
|
// src/image.ts
|
|
1078
|
-
import {
|
|
1257
|
+
import {
|
|
1258
|
+
Image as Image3,
|
|
1259
|
+
PooderLayer as PooderLayer4,
|
|
1260
|
+
util,
|
|
1261
|
+
Point as Point2
|
|
1262
|
+
} from "@pooder/core";
|
|
1079
1263
|
var ImageTool = class {
|
|
1080
1264
|
constructor() {
|
|
1081
1265
|
this.name = "ImageTool";
|
|
1266
|
+
this._loadingUrl = null;
|
|
1082
1267
|
this.options = {
|
|
1083
1268
|
url: "",
|
|
1084
1269
|
opacity: 1
|
|
@@ -1094,14 +1279,44 @@ var ImageTool = class {
|
|
|
1094
1279
|
max: 1,
|
|
1095
1280
|
step: 0.1,
|
|
1096
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
|
|
1097
1312
|
}
|
|
1098
1313
|
};
|
|
1099
1314
|
this.commands = {
|
|
1100
1315
|
setUserImage: {
|
|
1101
|
-
execute: (editor, url, opacity) => {
|
|
1102
|
-
if (this.options.url === url && this.options.opacity === opacity
|
|
1103
|
-
|
|
1104
|
-
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 };
|
|
1105
1320
|
this.updateImage(editor, this.options);
|
|
1106
1321
|
return true;
|
|
1107
1322
|
},
|
|
@@ -1117,13 +1332,19 @@ var ImageTool = class {
|
|
|
1117
1332
|
min: 0,
|
|
1118
1333
|
max: 1,
|
|
1119
1334
|
required: true
|
|
1120
|
-
}
|
|
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" }
|
|
1121
1341
|
}
|
|
1122
1342
|
}
|
|
1123
1343
|
};
|
|
1124
1344
|
}
|
|
1125
1345
|
onMount(editor) {
|
|
1126
1346
|
this.ensureLayer(editor);
|
|
1347
|
+
this.updateImage(editor, this.options);
|
|
1127
1348
|
}
|
|
1128
1349
|
onUnmount(editor) {
|
|
1129
1350
|
const layer = editor.getLayer("user");
|
|
@@ -1161,43 +1382,101 @@ var ImageTool = class {
|
|
|
1161
1382
|
}
|
|
1162
1383
|
updateImage(editor, opts) {
|
|
1163
1384
|
var _a, _b;
|
|
1164
|
-
let { url, opacity } = opts;
|
|
1385
|
+
let { url, opacity, width, height, angle, left, top } = opts;
|
|
1165
1386
|
const layer = editor.getLayer("user");
|
|
1166
1387
|
if (!layer) {
|
|
1167
1388
|
console.warn("[ImageTool] User layer not found");
|
|
1168
1389
|
return;
|
|
1169
1390
|
}
|
|
1170
1391
|
const userImage = editor.getObject("user-image", "user");
|
|
1392
|
+
if (this._loadingUrl === url) return;
|
|
1171
1393
|
if (userImage) {
|
|
1172
1394
|
const currentSrc = ((_a = userImage.getSrc) == null ? void 0 : _a.call(userImage)) || ((_b = userImage._element) == null ? void 0 : _b.src);
|
|
1173
1395
|
if (currentSrc !== url) {
|
|
1174
|
-
this.loadImage(editor, layer,
|
|
1396
|
+
this.loadImage(editor, layer, opts);
|
|
1175
1397
|
} else {
|
|
1176
|
-
|
|
1177
|
-
|
|
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);
|
|
1178
1419
|
editor.canvas.requestRenderAll();
|
|
1179
1420
|
}
|
|
1180
1421
|
}
|
|
1181
1422
|
} else {
|
|
1182
|
-
this.loadImage(editor, layer,
|
|
1423
|
+
this.loadImage(editor, layer, opts);
|
|
1183
1424
|
}
|
|
1184
1425
|
}
|
|
1185
|
-
loadImage(editor, layer,
|
|
1426
|
+
loadImage(editor, layer, opts) {
|
|
1427
|
+
const { url } = opts;
|
|
1428
|
+
this._loadingUrl = url;
|
|
1186
1429
|
Image3.fromURL(url).then((image) => {
|
|
1187
|
-
if (
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
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;
|
|
1191
1457
|
}
|
|
1192
1458
|
image.set({
|
|
1193
|
-
opacity,
|
|
1459
|
+
opacity: opacity !== void 0 ? opacity : 1,
|
|
1194
1460
|
data: {
|
|
1195
1461
|
id: "user-image"
|
|
1196
1462
|
}
|
|
1197
1463
|
});
|
|
1198
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
|
+
});
|
|
1199
1477
|
editor.canvas.requestRenderAll();
|
|
1200
1478
|
}).catch((err) => {
|
|
1479
|
+
if (this._loadingUrl === url) this._loadingUrl = null;
|
|
1201
1480
|
console.error("Failed to load image", url, err);
|
|
1202
1481
|
});
|
|
1203
1482
|
}
|
|
@@ -1225,7 +1504,8 @@ var WhiteInkTool = class {
|
|
|
1225
1504
|
this.commands = {
|
|
1226
1505
|
setWhiteInkImage: {
|
|
1227
1506
|
execute: (editor, customMask, opacity, enableClip = true) => {
|
|
1228
|
-
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;
|
|
1229
1509
|
this.options.customMask = customMask;
|
|
1230
1510
|
this.options.opacity = opacity;
|
|
1231
1511
|
this.options.enableClip = enableClip;
|
|
@@ -1257,6 +1537,7 @@ var WhiteInkTool = class {
|
|
|
1257
1537
|
}
|
|
1258
1538
|
onMount(editor) {
|
|
1259
1539
|
this.setup(editor);
|
|
1540
|
+
this.updateWhiteInk(editor, this.options);
|
|
1260
1541
|
}
|
|
1261
1542
|
onUnmount(editor) {
|
|
1262
1543
|
this.teardown(editor);
|
|
@@ -1297,7 +1578,6 @@ var WhiteInkTool = class {
|
|
|
1297
1578
|
editor.canvas.on("object:rotating", this.syncHandler);
|
|
1298
1579
|
editor.canvas.on("object:modified", this.syncHandler);
|
|
1299
1580
|
}
|
|
1300
|
-
this.updateWhiteInk(editor, this.options);
|
|
1301
1581
|
}
|
|
1302
1582
|
teardown(editor) {
|
|
1303
1583
|
if (this.syncHandler) {
|
|
@@ -1346,7 +1626,14 @@ var WhiteInkTool = class {
|
|
|
1346
1626
|
if (whiteInk) {
|
|
1347
1627
|
const currentSrc = ((_a = whiteInk.getSrc) == null ? void 0 : _a.call(whiteInk)) || ((_b = whiteInk._element) == null ? void 0 : _b.src);
|
|
1348
1628
|
if (currentSrc !== customMask) {
|
|
1349
|
-
this.loadWhiteInk(
|
|
1629
|
+
this.loadWhiteInk(
|
|
1630
|
+
editor,
|
|
1631
|
+
layer,
|
|
1632
|
+
customMask,
|
|
1633
|
+
opacity,
|
|
1634
|
+
enableClip,
|
|
1635
|
+
whiteInk
|
|
1636
|
+
);
|
|
1350
1637
|
} else {
|
|
1351
1638
|
if (whiteInk.opacity !== opacity) {
|
|
1352
1639
|
whiteInk.set({ opacity });
|
|
@@ -1375,10 +1662,12 @@ var WhiteInkTool = class {
|
|
|
1375
1662
|
if (oldImage) {
|
|
1376
1663
|
layer.remove(oldImage);
|
|
1377
1664
|
}
|
|
1378
|
-
(_a = image.filters) == null ? void 0 : _a.push(
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1665
|
+
(_a = image.filters) == null ? void 0 : _a.push(
|
|
1666
|
+
new filters.BlendColor({
|
|
1667
|
+
color: "#FFFFFF",
|
|
1668
|
+
mode: "add"
|
|
1669
|
+
})
|
|
1670
|
+
);
|
|
1382
1671
|
image.applyFilters();
|
|
1383
1672
|
image.set({
|
|
1384
1673
|
opacity,
|
|
@@ -1446,7 +1735,12 @@ var WhiteInkTool = class {
|
|
|
1446
1735
|
};
|
|
1447
1736
|
|
|
1448
1737
|
// src/ruler.ts
|
|
1449
|
-
import {
|
|
1738
|
+
import {
|
|
1739
|
+
PooderLayer as PooderLayer6,
|
|
1740
|
+
Rect as Rect3,
|
|
1741
|
+
Line,
|
|
1742
|
+
Text
|
|
1743
|
+
} from "@pooder/core";
|
|
1450
1744
|
var RulerTool = class {
|
|
1451
1745
|
constructor() {
|
|
1452
1746
|
this.name = "RulerTool";
|
|
@@ -1490,7 +1784,8 @@ var RulerTool = class {
|
|
|
1490
1784
|
setTheme: {
|
|
1491
1785
|
execute: (editor, theme) => {
|
|
1492
1786
|
const newOptions = { ...this.options, ...theme };
|
|
1493
|
-
if (JSON.stringify(newOptions) === JSON.stringify(this.options))
|
|
1787
|
+
if (JSON.stringify(newOptions) === JSON.stringify(this.options))
|
|
1788
|
+
return true;
|
|
1494
1789
|
this.options = newOptions;
|
|
1495
1790
|
this.updateRuler(editor);
|
|
1496
1791
|
return true;
|
|
@@ -1507,11 +1802,13 @@ var RulerTool = class {
|
|
|
1507
1802
|
}
|
|
1508
1803
|
onMount(editor) {
|
|
1509
1804
|
this.createLayer(editor);
|
|
1805
|
+
this.updateRuler(editor);
|
|
1510
1806
|
}
|
|
1511
1807
|
onUnmount(editor) {
|
|
1512
1808
|
this.destroyLayer(editor);
|
|
1513
1809
|
}
|
|
1514
1810
|
onUpdate(editor, state) {
|
|
1811
|
+
this.updateRuler(editor);
|
|
1515
1812
|
}
|
|
1516
1813
|
onDestroy(editor) {
|
|
1517
1814
|
this.destroyLayer(editor);
|
|
@@ -1537,7 +1834,6 @@ var RulerTool = class {
|
|
|
1537
1834
|
editor.canvas.add(layer);
|
|
1538
1835
|
}
|
|
1539
1836
|
editor.canvas.bringObjectToFront(layer);
|
|
1540
|
-
this.updateRuler(editor);
|
|
1541
1837
|
}
|
|
1542
1838
|
destroyLayer(editor) {
|
|
1543
1839
|
const layer = this.getLayer(editor);
|
|
@@ -1643,12 +1939,83 @@ var RulerTool = class {
|
|
|
1643
1939
|
editor.canvas.requestRenderAll();
|
|
1644
1940
|
}
|
|
1645
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
|
+
};
|
|
1646
2012
|
export {
|
|
1647
2013
|
BackgroundTool,
|
|
1648
2014
|
DielineTool,
|
|
1649
2015
|
FilmTool,
|
|
1650
2016
|
HoleTool,
|
|
1651
2017
|
ImageTool,
|
|
2018
|
+
MirrorTool,
|
|
1652
2019
|
RulerTool,
|
|
1653
2020
|
WhiteInkTool
|
|
1654
2021
|
};
|