@pooder/kit 5.0.4 → 5.2.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 +17 -0
- package/dist/index.d.mts +248 -267
- package/dist/index.d.ts +248 -267
- package/dist/index.js +6729 -5797
- package/dist/index.mjs +6690 -5741
- package/package.json +2 -2
- package/src/{background.ts → extensions/background.ts} +1 -1
- package/src/{dieline.ts → extensions/dieline.ts} +39 -17
- package/src/{feature.ts → extensions/feature.ts} +80 -67
- package/src/{film.ts → extensions/film.ts} +1 -1
- package/src/{geometry.ts → extensions/geometry.ts} +151 -105
- package/src/{image.ts → extensions/image.ts} +436 -93
- package/src/extensions/index.ts +11 -0
- package/src/{maskOps.ts → extensions/maskOps.ts} +28 -10
- package/src/{mirror.ts → extensions/mirror.ts} +1 -1
- package/src/{ruler.ts → extensions/ruler.ts} +5 -3
- package/src/extensions/sceneLayout.ts +140 -0
- package/src/{sceneLayoutModel.ts → extensions/sceneLayoutModel.ts} +17 -10
- package/src/extensions/sceneVisibility.ts +71 -0
- package/src/{size.ts → extensions/size.ts} +23 -13
- package/src/{tracer.ts → extensions/tracer.ts} +374 -45
- package/src/{white-ink.ts → extensions/white-ink.ts} +620 -236
- package/src/index.ts +2 -14
- package/src/{ViewportSystem.ts → services/ViewportSystem.ts} +5 -2
- package/src/services/index.ts +3 -0
- package/src/sceneLayout.ts +0 -121
- package/src/sceneVisibility.ts +0 -49
- /package/src/{bridgeSelection.ts → extensions/bridgeSelection.ts} +0 -0
- /package/src/{constraints.ts → extensions/constraints.ts} +0 -0
- /package/src/{edgeScale.ts → extensions/edgeScale.ts} +0 -0
- /package/src/{featureComplete.ts → extensions/featureComplete.ts} +0 -0
- /package/src/{wrappedOffsets.ts → extensions/wrappedOffsets.ts} +0 -0
- /package/src/{CanvasService.ts → services/CanvasService.ts} +0 -0
- /package/src/{renderSpec.ts → services/renderSpec.ts} +0 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pooder/kit",
|
|
3
|
-
"version": "5.0
|
|
3
|
+
"version": "5.2.0",
|
|
4
4
|
"description": "Standard plugins for Pooder editor",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"dependencies": {
|
|
20
20
|
"paper": "^0.12.18",
|
|
21
21
|
"fabric": "^7.0.0",
|
|
22
|
-
"@pooder/core": "2.
|
|
22
|
+
"@pooder/core": "2.2.0"
|
|
23
23
|
},
|
|
24
24
|
"scripts": {
|
|
25
25
|
"build": "tsup src/index.ts --format cjs,esm --dts",
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
ConfigurationContribution,
|
|
7
7
|
} from "@pooder/core";
|
|
8
8
|
import { Rect, FabricImage as Image } from "fabric";
|
|
9
|
-
import CanvasService from "
|
|
9
|
+
import { CanvasService } from "../services";
|
|
10
10
|
|
|
11
11
|
export class BackgroundTool implements Extension {
|
|
12
12
|
id = "pooder.kit.background";
|
|
@@ -7,10 +7,10 @@ import {
|
|
|
7
7
|
ConfigurationService,
|
|
8
8
|
} from "@pooder/core";
|
|
9
9
|
import { Canvas as FabricCanvas, Path, Pattern } from "fabric";
|
|
10
|
-
import CanvasService from "
|
|
10
|
+
import { CanvasService } from "../services";
|
|
11
11
|
import { ImageTracer } from "./tracer";
|
|
12
|
-
import { Unit } from "
|
|
13
|
-
import { parseLengthToMm } from "
|
|
12
|
+
import { Unit } from "../coordinate";
|
|
13
|
+
import { parseLengthToMm } from "../units";
|
|
14
14
|
import {
|
|
15
15
|
generateDielinePath,
|
|
16
16
|
generateMaskPath,
|
|
@@ -466,9 +466,17 @@ export class DielineTool implements Extension {
|
|
|
466
466
|
options: {
|
|
467
467
|
expand: detectOptions.expand ?? 0,
|
|
468
468
|
morphologyRadius: detectOptions.morphologyRadius,
|
|
469
|
+
connectRadiusMax: detectOptions.connectRadiusMax,
|
|
469
470
|
smoothing: detectOptions.smoothing,
|
|
470
471
|
simplifyTolerance: detectOptions.simplifyTolerance,
|
|
471
472
|
threshold: detectOptions.threshold,
|
|
473
|
+
maskMode: detectOptions.maskMode,
|
|
474
|
+
whiteThreshold: detectOptions.whiteThreshold,
|
|
475
|
+
alphaOpaqueCutoff: detectOptions.alphaOpaqueCutoff,
|
|
476
|
+
noChannels: detectOptions.noChannels,
|
|
477
|
+
componentMode: detectOptions.componentMode,
|
|
478
|
+
minComponentArea: detectOptions.minComponentArea,
|
|
479
|
+
forceConnected: detectOptions.forceConnected,
|
|
472
480
|
},
|
|
473
481
|
});
|
|
474
482
|
}
|
|
@@ -552,7 +560,9 @@ export class DielineTool implements Extension {
|
|
|
552
560
|
}
|
|
553
561
|
|
|
554
562
|
private getConfigService(): ConfigurationService | undefined {
|
|
555
|
-
return this.context?.services.get<ConfigurationService>(
|
|
563
|
+
return this.context?.services.get<ConfigurationService>(
|
|
564
|
+
"ConfigurationService",
|
|
565
|
+
);
|
|
556
566
|
}
|
|
557
567
|
|
|
558
568
|
private syncSizeState(configService: ConfigurationService) {
|
|
@@ -603,8 +613,10 @@ export class DielineTool implements Extension {
|
|
|
603
613
|
features,
|
|
604
614
|
} = this.state;
|
|
605
615
|
|
|
606
|
-
const canvasW =
|
|
607
|
-
|
|
616
|
+
const canvasW =
|
|
617
|
+
sceneLayout.canvasWidth || this.canvasService.canvas.width || 800;
|
|
618
|
+
const canvasH =
|
|
619
|
+
sceneLayout.canvasHeight || this.canvasService.canvas.height || 600;
|
|
608
620
|
const scale = sceneLayout.scale;
|
|
609
621
|
const cx = sceneLayout.trimRect.centerX;
|
|
610
622
|
const cy = sceneLayout.trimRect.centerY;
|
|
@@ -830,7 +842,9 @@ export class DielineTool implements Extension {
|
|
|
830
842
|
const debug = options?.debug === true;
|
|
831
843
|
|
|
832
844
|
if (!this.canvasService) {
|
|
833
|
-
console.warn(
|
|
845
|
+
console.warn(
|
|
846
|
+
"[DielineTool] exportCutImage returned null: canvas-not-ready",
|
|
847
|
+
);
|
|
834
848
|
return null;
|
|
835
849
|
}
|
|
836
850
|
const configService = this.getConfigService();
|
|
@@ -847,13 +861,17 @@ export class DielineTool implements Extension {
|
|
|
847
861
|
readSizeState(configService),
|
|
848
862
|
);
|
|
849
863
|
if (!sceneLayout) {
|
|
850
|
-
console.warn(
|
|
864
|
+
console.warn(
|
|
865
|
+
"[DielineTool] exportCutImage returned null: scene-layout-null",
|
|
866
|
+
);
|
|
851
867
|
return null;
|
|
852
868
|
}
|
|
853
869
|
|
|
854
870
|
const { shape, radius, features, pathData } = this.state;
|
|
855
|
-
const canvasW =
|
|
856
|
-
|
|
871
|
+
const canvasW =
|
|
872
|
+
sceneLayout.canvasWidth || this.canvasService.canvas.width || 800;
|
|
873
|
+
const canvasH =
|
|
874
|
+
sceneLayout.canvasHeight || this.canvasService.canvas.height || 600;
|
|
857
875
|
const scale = sceneLayout.scale;
|
|
858
876
|
const cx = sceneLayout.trimRect.centerX;
|
|
859
877
|
const cy = sceneLayout.trimRect.centerY;
|
|
@@ -916,16 +934,21 @@ export class DielineTool implements Extension {
|
|
|
916
934
|
pathBounds.width <= 0 ||
|
|
917
935
|
pathBounds.height <= 0
|
|
918
936
|
) {
|
|
919
|
-
console.warn(
|
|
920
|
-
|
|
921
|
-
|
|
937
|
+
console.warn(
|
|
938
|
+
"[DielineTool] exportCutImage returned null: invalid-cut-bounds",
|
|
939
|
+
{
|
|
940
|
+
bounds: pathBounds,
|
|
941
|
+
},
|
|
942
|
+
);
|
|
922
943
|
return null;
|
|
923
944
|
}
|
|
924
945
|
const exportBounds = pathBounds;
|
|
925
946
|
|
|
926
|
-
const sourceImages = this.canvasService.canvas
|
|
927
|
-
|
|
928
|
-
|
|
947
|
+
const sourceImages = this.canvasService.canvas
|
|
948
|
+
.getObjects()
|
|
949
|
+
.filter((obj: any) => {
|
|
950
|
+
return obj?.data?.layerId === IMAGE_OBJECT_LAYER_ID;
|
|
951
|
+
});
|
|
929
952
|
if (!sourceImages.length) {
|
|
930
953
|
console.warn(
|
|
931
954
|
"[DielineTool] exportCutImage returned null: no-image-objects-on-canvas",
|
|
@@ -1001,5 +1024,4 @@ export class DielineTool implements Extension {
|
|
|
1001
1024
|
exportCanvas.dispose();
|
|
1002
1025
|
}
|
|
1003
1026
|
}
|
|
1004
|
-
|
|
1005
1027
|
}
|
|
@@ -7,16 +7,14 @@ import {
|
|
|
7
7
|
ToolSessionService,
|
|
8
8
|
} from "@pooder/core";
|
|
9
9
|
import { Circle, Group, Point, Rect } from "fabric";
|
|
10
|
-
import CanvasService from "
|
|
10
|
+
import { CanvasService } from "../services";
|
|
11
11
|
import {
|
|
12
12
|
getNearestPointOnDieline,
|
|
13
13
|
DielineFeature,
|
|
14
14
|
resolveFeaturePosition,
|
|
15
15
|
} from "./geometry";
|
|
16
16
|
import { ConstraintRegistry, ConstraintFeature } from "./constraints";
|
|
17
|
-
import {
|
|
18
|
-
completeFeaturesStrict,
|
|
19
|
-
} from "./featureComplete";
|
|
17
|
+
import { completeFeaturesStrict } from "./featureComplete";
|
|
20
18
|
import {
|
|
21
19
|
readSizeState,
|
|
22
20
|
type SceneGeometrySnapshot as DielineGeometry,
|
|
@@ -41,8 +39,9 @@ export class FeatureTool implements Extension {
|
|
|
41
39
|
|
|
42
40
|
private handleMoving: ((e: any) => void) | null = null;
|
|
43
41
|
private handleModified: ((e: any) => void) | null = null;
|
|
44
|
-
private handleSceneGeometryChange:
|
|
45
|
-
|
|
42
|
+
private handleSceneGeometryChange:
|
|
43
|
+
| ((geometry: DielineGeometry) => void)
|
|
44
|
+
| null = null;
|
|
46
45
|
|
|
47
46
|
private currentGeometry: DielineGeometry | null = null;
|
|
48
47
|
|
|
@@ -125,16 +124,16 @@ export class FeatureTool implements Extension {
|
|
|
125
124
|
const markers = canvas
|
|
126
125
|
.getObjects()
|
|
127
126
|
.filter((obj: any) => obj.data?.type === "feature-marker");
|
|
128
|
-
|
|
127
|
+
|
|
129
128
|
markers.forEach((marker: any) => {
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
129
|
+
// If tool active, allow selection. If not, disable selection.
|
|
130
|
+
// Also might want to hide them entirely or just disable interaction.
|
|
131
|
+
// Assuming we only want to see/edit holes when tool is active.
|
|
132
|
+
marker.set({
|
|
133
|
+
visible: this.isToolActive, // Or just selectable: false if we want them visible but locked
|
|
134
|
+
selectable: this.isToolActive,
|
|
135
|
+
evented: this.isToolActive,
|
|
136
|
+
});
|
|
138
137
|
});
|
|
139
138
|
canvas.requestRenderAll();
|
|
140
139
|
}
|
|
@@ -276,7 +275,9 @@ export class FeatureTool implements Extension {
|
|
|
276
275
|
}
|
|
277
276
|
|
|
278
277
|
private getConfigService(): ConfigurationService | undefined {
|
|
279
|
-
return this.context?.services.get<ConfigurationService>(
|
|
278
|
+
return this.context?.services.get<ConfigurationService>(
|
|
279
|
+
"ConfigurationService",
|
|
280
|
+
);
|
|
280
281
|
}
|
|
281
282
|
|
|
282
283
|
private getCommittedFeatures(): ConstraintFeature[] {
|
|
@@ -349,8 +350,9 @@ export class FeatureTool implements Extension {
|
|
|
349
350
|
private updateWorkingGroupPosition(groupId: string, x: number, y: number) {
|
|
350
351
|
if (!groupId) return { ok: false };
|
|
351
352
|
|
|
352
|
-
const configService =
|
|
353
|
-
|
|
353
|
+
const configService = this.context?.services.get<ConfigurationService>(
|
|
354
|
+
"ConfigurationService",
|
|
355
|
+
);
|
|
354
356
|
if (!configService) return { ok: false };
|
|
355
357
|
|
|
356
358
|
const sizeState = readSizeState(configService);
|
|
@@ -397,8 +399,9 @@ export class FeatureTool implements Extension {
|
|
|
397
399
|
reason: string;
|
|
398
400
|
}>;
|
|
399
401
|
} {
|
|
400
|
-
const configService =
|
|
401
|
-
|
|
402
|
+
const configService = this.context?.services.get<ConfigurationService>(
|
|
403
|
+
"ConfigurationService",
|
|
404
|
+
);
|
|
402
405
|
if (!configService) {
|
|
403
406
|
return {
|
|
404
407
|
ok: false,
|
|
@@ -573,14 +576,18 @@ export class FeatureTool implements Extension {
|
|
|
573
576
|
// For Group, target.left/top is group center (or top-left depending on origin)
|
|
574
577
|
// We snap the target position itself.
|
|
575
578
|
const p = new Point(target.left, target.top);
|
|
576
|
-
|
|
579
|
+
|
|
577
580
|
// Calculate limit based on target size (min dimension / 2 ensures overlap)
|
|
578
581
|
// Also subtract stroke width to ensure visual overlap (not just tangent)
|
|
579
582
|
// target.strokeWidth for group is usually 0, need a safe default (e.g. 2 for markers)
|
|
580
|
-
const markerStrokeWidth =
|
|
581
|
-
|
|
583
|
+
const markerStrokeWidth =
|
|
584
|
+
(target.strokeWidth || 2) * (target.scaleX || 1);
|
|
585
|
+
const minDim = Math.min(
|
|
586
|
+
target.getScaledWidth(),
|
|
587
|
+
target.getScaledHeight(),
|
|
588
|
+
);
|
|
582
589
|
const limit = Math.max(0, minDim / 2 - markerStrokeWidth);
|
|
583
|
-
|
|
590
|
+
|
|
584
591
|
const snapped = this.constrainPosition(p, geometry, limit, feature);
|
|
585
592
|
|
|
586
593
|
target.set({
|
|
@@ -691,7 +698,7 @@ export class FeatureTool implements Extension {
|
|
|
691
698
|
p: Point,
|
|
692
699
|
geometry: DielineGeometry,
|
|
693
700
|
limit: number,
|
|
694
|
-
feature?: ConstraintFeature
|
|
701
|
+
feature?: ConstraintFeature,
|
|
695
702
|
): { x: number; y: number } {
|
|
696
703
|
if (!feature) {
|
|
697
704
|
return { x: p.x, y: p.y };
|
|
@@ -709,7 +716,9 @@ export class FeatureTool implements Extension {
|
|
|
709
716
|
const dielineHeight = geometry.height / scale;
|
|
710
717
|
|
|
711
718
|
// Filter constraints: only apply those that are NOT validateOnly
|
|
712
|
-
const activeConstraints = feature.constraints?.filter(
|
|
719
|
+
const activeConstraints = feature.constraints?.filter(
|
|
720
|
+
(c) => !c.validateOnly,
|
|
721
|
+
);
|
|
713
722
|
|
|
714
723
|
const constrained = ConstraintRegistry.apply(
|
|
715
724
|
nx,
|
|
@@ -788,8 +797,9 @@ export class FeatureTool implements Extension {
|
|
|
788
797
|
const finalScale = scale;
|
|
789
798
|
|
|
790
799
|
// Group features by groupId
|
|
791
|
-
const groups: {
|
|
792
|
-
{};
|
|
800
|
+
const groups: {
|
|
801
|
+
[key: string]: { feature: ConstraintFeature; index: number }[];
|
|
802
|
+
} = {};
|
|
793
803
|
const singles: { feature: ConstraintFeature; index: number }[] = [];
|
|
794
804
|
|
|
795
805
|
this.workingFeatures.forEach((f: ConstraintFeature, i: number) => {
|
|
@@ -812,8 +822,7 @@ export class FeatureTool implements Extension {
|
|
|
812
822
|
const visualHeight = (feature.height || 10) * featureScale;
|
|
813
823
|
const visualRadius = (feature.radius || 0) * featureScale;
|
|
814
824
|
const color =
|
|
815
|
-
feature.color ||
|
|
816
|
-
(feature.operation === "add" ? "#00FF00" : "#FF0000");
|
|
825
|
+
feature.color || (feature.operation === "add" ? "#00FF00" : "#FF0000");
|
|
817
826
|
const strokeDash =
|
|
818
827
|
feature.strokeDash ||
|
|
819
828
|
(feature.operation === "subtract" ? [4, 4] : undefined);
|
|
@@ -850,42 +859,42 @@ export class FeatureTool implements Extension {
|
|
|
850
859
|
if (feature.rotation) {
|
|
851
860
|
shape.rotate(feature.rotation);
|
|
852
861
|
}
|
|
853
|
-
|
|
862
|
+
|
|
854
863
|
// Handle Indicator for Bridge
|
|
855
864
|
if (feature.bridge && feature.bridge.type === "vertical") {
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
865
|
+
// Create a visual indicator for the bridge
|
|
866
|
+
// A dashed rectangle extending upwards
|
|
867
|
+
const bridgeIndicator = new Rect({
|
|
868
|
+
width: visualWidth,
|
|
869
|
+
height: 100 * featureScale, // Arbitrary long length to show direction
|
|
870
|
+
fill: "transparent",
|
|
871
|
+
stroke: "#888",
|
|
872
|
+
strokeWidth: 1,
|
|
873
|
+
strokeDashArray: [2, 2],
|
|
874
|
+
originX: "center",
|
|
875
|
+
originY: "bottom", // Anchor at bottom so it extends up
|
|
876
|
+
left: pos.x,
|
|
877
|
+
top: pos.y - visualHeight / 2, // Start from top of feature
|
|
878
|
+
opacity: 0.5,
|
|
879
|
+
selectable: false,
|
|
880
|
+
evented: false,
|
|
881
|
+
});
|
|
882
|
+
|
|
883
|
+
// We need to return a group containing both shape and indicator
|
|
884
|
+
// But createMarkerShape is expected to return one object.
|
|
885
|
+
// If we return a Group, Fabric handles it.
|
|
886
|
+
// But the caller might wrap this in another Group if it's part of a feature group.
|
|
887
|
+
// Fabric supports nested groups.
|
|
888
|
+
|
|
889
|
+
const group = new Group([bridgeIndicator, shape], {
|
|
890
|
+
originX: "center",
|
|
891
|
+
originY: "center",
|
|
892
|
+
left: pos.x,
|
|
893
|
+
top: pos.y,
|
|
894
|
+
});
|
|
895
|
+
return group;
|
|
887
896
|
}
|
|
888
|
-
|
|
897
|
+
|
|
889
898
|
return shape;
|
|
890
899
|
};
|
|
891
900
|
|
|
@@ -990,15 +999,19 @@ export class FeatureTool implements Extension {
|
|
|
990
999
|
feature,
|
|
991
1000
|
);
|
|
992
1001
|
|
|
993
|
-
const markerStrokeWidth =
|
|
994
|
-
|
|
1002
|
+
const markerStrokeWidth =
|
|
1003
|
+
(marker.strokeWidth || 2) * (marker.scaleX || 1);
|
|
1004
|
+
const minDim = Math.min(
|
|
1005
|
+
marker.getScaledWidth(),
|
|
1006
|
+
marker.getScaledHeight(),
|
|
1007
|
+
);
|
|
995
1008
|
const limit = Math.max(0, minDim / 2 - markerStrokeWidth);
|
|
996
|
-
|
|
1009
|
+
|
|
997
1010
|
const snapped = this.constrainPosition(
|
|
998
1011
|
new Point(marker.left, marker.top),
|
|
999
1012
|
geometry,
|
|
1000
1013
|
limit,
|
|
1001
|
-
feature
|
|
1014
|
+
feature,
|
|
1002
1015
|
);
|
|
1003
1016
|
marker.set({ left: snapped.x, top: snapped.y });
|
|
1004
1017
|
marker.setCoords();
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
ConfigurationContribution,
|
|
7
7
|
} from "@pooder/core";
|
|
8
8
|
import { FabricImage as Image } from "fabric";
|
|
9
|
-
import CanvasService from "
|
|
9
|
+
import { CanvasService } from "../services";
|
|
10
10
|
|
|
11
11
|
export class FilmTool implements Extension {
|
|
12
12
|
id = "pooder.kit.film";
|