@pooder/kit 5.0.3 → 5.1.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 +239 -269
- package/dist/index.d.ts +239 -269
- package/dist/index.js +6485 -5833
- package/dist/index.mjs +6587 -5923
- 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} +190 -192
- 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
|
@@ -7,8 +7,8 @@ import {
|
|
|
7
7
|
ConfigurationService,
|
|
8
8
|
} from "@pooder/core";
|
|
9
9
|
import { Rect, Line, Text, Group, Polygon } from "fabric";
|
|
10
|
-
import CanvasService from "
|
|
11
|
-
import { formatMm } from "
|
|
10
|
+
import { CanvasService } from "../services";
|
|
11
|
+
import { formatMm } from "../units";
|
|
12
12
|
import { computeSceneLayout, readSizeState } from "./sceneLayoutModel";
|
|
13
13
|
|
|
14
14
|
export class RulerTool implements Extension {
|
|
@@ -304,7 +304,9 @@ export class RulerTool implements Extension {
|
|
|
304
304
|
const rulerBottom = rulerRect.top + rulerRect.height;
|
|
305
305
|
|
|
306
306
|
// Display Dimensions (Physical)
|
|
307
|
-
const displayWidthMm = useCutAsRuler
|
|
307
|
+
const displayWidthMm = useCutAsRuler
|
|
308
|
+
? layout.cutWidthMm
|
|
309
|
+
: layout.trimWidthMm;
|
|
308
310
|
const displayHeightMm = useCutAsRuler
|
|
309
311
|
? layout.cutHeightMm
|
|
310
312
|
: layout.trimHeightMm;
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import {
|
|
2
|
+
COMMAND_SERVICE,
|
|
3
|
+
CONFIGURATION_SERVICE,
|
|
4
|
+
CommandService,
|
|
5
|
+
ConfigurationService,
|
|
6
|
+
Service,
|
|
7
|
+
ServiceContext,
|
|
8
|
+
} from "@pooder/core";
|
|
9
|
+
import { CanvasService } from "../services";
|
|
10
|
+
import {
|
|
11
|
+
buildSceneGeometry,
|
|
12
|
+
computeSceneLayout,
|
|
13
|
+
readSizeState,
|
|
14
|
+
type SceneGeometrySnapshot,
|
|
15
|
+
type SceneLayoutSnapshot,
|
|
16
|
+
} from "./sceneLayoutModel";
|
|
17
|
+
|
|
18
|
+
interface ConfigChangeEvent {
|
|
19
|
+
key: string;
|
|
20
|
+
value: unknown;
|
|
21
|
+
oldValue: unknown;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const CONFIG_WATCH_PREFIXES = ["size.", "dieline."] as const;
|
|
25
|
+
const CANVAS_SERVICE_ID = "CanvasService";
|
|
26
|
+
const GET_SCENE_LAYOUT_COMMAND = "getSceneLayout";
|
|
27
|
+
const GET_SCENE_GEOMETRY_COMMAND = "getSceneGeometry";
|
|
28
|
+
|
|
29
|
+
export class SceneLayoutService implements Service {
|
|
30
|
+
private context?: ServiceContext;
|
|
31
|
+
private canvasService?: CanvasService;
|
|
32
|
+
private configService?: ConfigurationService;
|
|
33
|
+
private lastLayout: SceneLayoutSnapshot | null = null;
|
|
34
|
+
private lastGeometry: SceneGeometrySnapshot | null = null;
|
|
35
|
+
private onConfigChange?: { dispose(): void };
|
|
36
|
+
private commandDisposables: Array<{ dispose(): void }> = [];
|
|
37
|
+
|
|
38
|
+
init(context: ServiceContext) {
|
|
39
|
+
if (this.context) {
|
|
40
|
+
this.dispose(this.context);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const canvasService =
|
|
44
|
+
context.get<CanvasService>(CANVAS_SERVICE_ID);
|
|
45
|
+
const configService =
|
|
46
|
+
context.get<ConfigurationService>(CONFIGURATION_SERVICE);
|
|
47
|
+
const commandService = context.get<CommandService>(COMMAND_SERVICE);
|
|
48
|
+
|
|
49
|
+
if (!canvasService || !configService || !commandService) {
|
|
50
|
+
throw new Error(
|
|
51
|
+
"[SceneLayoutService] CanvasService, ConfigurationService and CommandService are required.",
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
this.context = context;
|
|
56
|
+
this.canvasService = canvasService;
|
|
57
|
+
this.configService = configService;
|
|
58
|
+
|
|
59
|
+
this.commandDisposables.push(
|
|
60
|
+
commandService.registerCommand(GET_SCENE_LAYOUT_COMMAND, () =>
|
|
61
|
+
this.getLayout(),
|
|
62
|
+
),
|
|
63
|
+
commandService.registerCommand(GET_SCENE_GEOMETRY_COMMAND, () =>
|
|
64
|
+
this.getGeometry(),
|
|
65
|
+
),
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
this.onConfigChange = configService.onAnyChange(this.onConfigChanged);
|
|
69
|
+
context.eventBus.on("canvas:resized", this.onCanvasResized);
|
|
70
|
+
this.refresh();
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
dispose(context: ServiceContext) {
|
|
74
|
+
const activeContext = this.context ?? context;
|
|
75
|
+
activeContext.eventBus.off("canvas:resized", this.onCanvasResized);
|
|
76
|
+
this.onConfigChange?.dispose();
|
|
77
|
+
this.onConfigChange = undefined;
|
|
78
|
+
this.commandDisposables.forEach((item) => item.dispose());
|
|
79
|
+
this.commandDisposables = [];
|
|
80
|
+
this.context = undefined;
|
|
81
|
+
this.canvasService = undefined;
|
|
82
|
+
this.configService = undefined;
|
|
83
|
+
this.lastLayout = null;
|
|
84
|
+
this.lastGeometry = null;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
private onCanvasResized = () => {
|
|
88
|
+
this.refresh();
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
private onConfigChanged = (e: ConfigChangeEvent) => {
|
|
92
|
+
if (CONFIG_WATCH_PREFIXES.some((prefix) => e.key.startsWith(prefix))) {
|
|
93
|
+
this.refresh();
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
private refresh() {
|
|
98
|
+
const layout = this.getLayout(true);
|
|
99
|
+
if (!layout) {
|
|
100
|
+
this.lastGeometry = null;
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
this.context?.eventBus.emit("scene:layout:change", layout);
|
|
105
|
+
|
|
106
|
+
const geometry = this.getGeometry(true);
|
|
107
|
+
if (geometry) {
|
|
108
|
+
this.context?.eventBus.emit("scene:geometry:change", geometry);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
getLayout(forceRefresh = false): SceneLayoutSnapshot | null {
|
|
113
|
+
if (!this.canvasService || !this.configService) return null;
|
|
114
|
+
if (!forceRefresh && this.lastLayout) return this.lastLayout;
|
|
115
|
+
|
|
116
|
+
const state = readSizeState(this.configService);
|
|
117
|
+
const layout = computeSceneLayout(this.canvasService, state);
|
|
118
|
+
if (!layout) {
|
|
119
|
+
this.lastLayout = null;
|
|
120
|
+
return null;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
this.lastLayout = layout;
|
|
124
|
+
return layout;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
getGeometry(forceRefresh = false): SceneGeometrySnapshot | null {
|
|
128
|
+
if (!this.configService) return null;
|
|
129
|
+
const layout = this.getLayout(forceRefresh);
|
|
130
|
+
if (!layout) {
|
|
131
|
+
this.lastGeometry = null;
|
|
132
|
+
return null;
|
|
133
|
+
}
|
|
134
|
+
if (!forceRefresh && this.lastGeometry) return this.lastGeometry;
|
|
135
|
+
|
|
136
|
+
const geometry = buildSceneGeometry(this.configService, layout);
|
|
137
|
+
this.lastGeometry = geometry;
|
|
138
|
+
return geometry;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { ConfigurationService } from "@pooder/core";
|
|
2
|
-
import type CanvasService from "
|
|
3
|
-
import { Coordinate, Unit } from "
|
|
4
|
-
import { parseLengthToMm } from "
|
|
2
|
+
import type { CanvasService } from "../services";
|
|
3
|
+
import { Coordinate, Unit } from "../coordinate";
|
|
4
|
+
import { parseLengthToMm } from "../units";
|
|
5
5
|
|
|
6
6
|
export type SizeConstraintMode = "free" | "lockAspect" | "equal";
|
|
7
7
|
export type CutMode = "trim" | "outset" | "inset";
|
|
@@ -158,17 +158,17 @@ export function readSizeState(configService: ConfigurationService): SizeState {
|
|
|
158
158
|
);
|
|
159
159
|
const actualHeightMm = sanitizeMmValue(
|
|
160
160
|
parseLengthToMm(
|
|
161
|
-
configService.get(
|
|
161
|
+
configService.get(
|
|
162
|
+
"size.actualHeightMm",
|
|
163
|
+
DEFAULT_SIZE_STATE.actualHeightMm,
|
|
164
|
+
),
|
|
162
165
|
"mm",
|
|
163
166
|
),
|
|
164
167
|
{ minMm, maxMm, stepMm },
|
|
165
168
|
);
|
|
166
169
|
|
|
167
170
|
const aspectRaw = Number(
|
|
168
|
-
configService.get(
|
|
169
|
-
"size.aspectRatio",
|
|
170
|
-
DEFAULT_SIZE_STATE.aspectRatio,
|
|
171
|
-
),
|
|
171
|
+
configService.get("size.aspectRatio", DEFAULT_SIZE_STATE.aspectRatio),
|
|
172
172
|
);
|
|
173
173
|
const aspectRatio =
|
|
174
174
|
Number.isFinite(aspectRaw) && aspectRaw > 0
|
|
@@ -265,7 +265,11 @@ export function computeSceneLayout(
|
|
|
265
265
|
return null;
|
|
266
266
|
}
|
|
267
267
|
|
|
268
|
-
const paddingPx = resolvePaddingPx(
|
|
268
|
+
const paddingPx = resolvePaddingPx(
|
|
269
|
+
size.viewPadding,
|
|
270
|
+
canvasWidth,
|
|
271
|
+
canvasHeight,
|
|
272
|
+
);
|
|
269
273
|
canvasService.viewport.updateContainer(canvasWidth, canvasHeight);
|
|
270
274
|
canvasService.viewport.setPadding(paddingPx);
|
|
271
275
|
canvasService.viewport.updatePhysical(viewWidthMm, viewHeightMm);
|
|
@@ -316,7 +320,10 @@ export function buildSceneGeometry(
|
|
|
316
320
|
configService: ConfigurationService,
|
|
317
321
|
layout: SceneLayoutSnapshot,
|
|
318
322
|
): SceneGeometrySnapshot {
|
|
319
|
-
const radiusMm = parseLengthToMm(
|
|
323
|
+
const radiusMm = parseLengthToMm(
|
|
324
|
+
configService.get("dieline.radius", 0),
|
|
325
|
+
"mm",
|
|
326
|
+
);
|
|
320
327
|
const offset = (layout.cutRect.width - layout.trimRect.width) / 2;
|
|
321
328
|
|
|
322
329
|
return {
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { Service, ServiceContext, WORKBENCH_SERVICE } from "@pooder/core";
|
|
2
|
+
import { CanvasService } from "../services";
|
|
3
|
+
|
|
4
|
+
const CANVAS_SERVICE_ID = "CanvasService";
|
|
5
|
+
const HIDDEN_DIELINE_TOOLS = new Set(["pooder.kit.image", "pooder.kit.white-ink"]);
|
|
6
|
+
const HIDDEN_RULER_TOOLS = new Set(["pooder.kit.white-ink"]);
|
|
7
|
+
|
|
8
|
+
export class SceneVisibilityService implements Service {
|
|
9
|
+
private context?: ServiceContext;
|
|
10
|
+
private activeToolId: string | null = null;
|
|
11
|
+
private canvasService?: CanvasService;
|
|
12
|
+
|
|
13
|
+
init(context: ServiceContext) {
|
|
14
|
+
if (this.context) {
|
|
15
|
+
this.dispose(this.context);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const canvasService =
|
|
19
|
+
context.get<CanvasService>(CANVAS_SERVICE_ID);
|
|
20
|
+
if (!canvasService) {
|
|
21
|
+
throw new Error("[SceneVisibilityService] CanvasService is required.");
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
this.context = context;
|
|
25
|
+
this.canvasService = canvasService;
|
|
26
|
+
this.activeToolId = context.get(WORKBENCH_SERVICE)?.activeToolId ?? null;
|
|
27
|
+
context.eventBus.on("tool:activated", this.onToolActivated);
|
|
28
|
+
context.eventBus.on("object:added", this.onObjectAdded);
|
|
29
|
+
this.apply();
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
dispose(context: ServiceContext) {
|
|
33
|
+
const activeContext = this.context ?? context;
|
|
34
|
+
activeContext.eventBus.off("tool:activated", this.onToolActivated);
|
|
35
|
+
activeContext.eventBus.off("object:added", this.onObjectAdded);
|
|
36
|
+
this.context = undefined;
|
|
37
|
+
this.activeToolId = null;
|
|
38
|
+
this.canvasService = undefined;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
private onToolActivated = (e: { id: string | null }) => {
|
|
42
|
+
this.activeToolId = e.id;
|
|
43
|
+
this.apply();
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
private onObjectAdded = () => {
|
|
47
|
+
this.apply();
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
private apply() {
|
|
51
|
+
if (!this.canvasService) return;
|
|
52
|
+
|
|
53
|
+
const dielineLayer = this.canvasService.getLayer("dieline-overlay");
|
|
54
|
+
if (dielineLayer) {
|
|
55
|
+
const visible = !HIDDEN_DIELINE_TOOLS.has(this.activeToolId || "");
|
|
56
|
+
if (dielineLayer.visible !== visible) {
|
|
57
|
+
dielineLayer.set({ visible });
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const rulerLayer = this.canvasService.getLayer("ruler-overlay");
|
|
62
|
+
if (rulerLayer) {
|
|
63
|
+
const visible = !HIDDEN_RULER_TOOLS.has(this.activeToolId || "");
|
|
64
|
+
if (rulerLayer.visible !== visible) {
|
|
65
|
+
rulerLayer.set({ visible });
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
this.canvasService.requestRenderAll();
|
|
70
|
+
}
|
|
71
|
+
}
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
Extension,
|
|
7
7
|
ExtensionContext,
|
|
8
8
|
} from "@pooder/core";
|
|
9
|
-
import CanvasService from "
|
|
9
|
+
import { CanvasService } from "../services";
|
|
10
10
|
import {
|
|
11
11
|
fromMm,
|
|
12
12
|
normalizeConstraintMode,
|
|
@@ -18,7 +18,7 @@ import {
|
|
|
18
18
|
type SizeConstraintMode,
|
|
19
19
|
computeSceneLayout,
|
|
20
20
|
} from "./sceneLayoutModel";
|
|
21
|
-
import type { Unit } from "
|
|
21
|
+
import type { Unit } from "../coordinate";
|
|
22
22
|
|
|
23
23
|
type ChangedField = "width" | "height" | "both";
|
|
24
24
|
|
|
@@ -194,7 +194,9 @@ export class SizeTool implements Extension {
|
|
|
194
194
|
}
|
|
195
195
|
|
|
196
196
|
private getConfigService(): ConfigurationService | undefined {
|
|
197
|
-
return this.context?.services.get<ConfigurationService>(
|
|
197
|
+
return this.context?.services.get<ConfigurationService>(
|
|
198
|
+
"ConfigurationService",
|
|
199
|
+
);
|
|
198
200
|
}
|
|
199
201
|
|
|
200
202
|
private ensureDefaults(configService: ConfigurationService) {
|
|
@@ -264,7 +266,7 @@ export class SizeTool implements Extension {
|
|
|
264
266
|
? nextHeightMm
|
|
265
267
|
: changed === "width"
|
|
266
268
|
? nextWidthMm
|
|
267
|
-
: providedWidthMm ?? providedHeightMm ?? nextWidthMm;
|
|
269
|
+
: (providedWidthMm ?? providedHeightMm ?? nextWidthMm);
|
|
268
270
|
nextWidthMm = anchor;
|
|
269
271
|
nextHeightMm = anchor;
|
|
270
272
|
} else if (state.constraintMode === "lockAspect") {
|
|
@@ -311,11 +313,14 @@ export class SizeTool implements Extension {
|
|
|
311
313
|
configService.update("size.aspectRatio", ratio);
|
|
312
314
|
}
|
|
313
315
|
if (mode === "equal") {
|
|
314
|
-
const value = sanitizeMmValue(
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
316
|
+
const value = sanitizeMmValue(
|
|
317
|
+
Math.max(state.actualWidthMm, state.actualHeightMm),
|
|
318
|
+
{
|
|
319
|
+
minMm: state.minMm,
|
|
320
|
+
maxMm: state.maxMm,
|
|
321
|
+
stepMm: state.stepMm,
|
|
322
|
+
},
|
|
323
|
+
);
|
|
319
324
|
configService.update("size.actualWidthMm", value);
|
|
320
325
|
configService.update("size.actualHeightMm", value);
|
|
321
326
|
configService.update("size.aspectRatio", 1);
|
|
@@ -353,15 +358,20 @@ export class SizeTool implements Extension {
|
|
|
353
358
|
|
|
354
359
|
const all = this.canvasService.canvas.getObjects() as any[];
|
|
355
360
|
const active = this.canvasService.canvas.getActiveObject() as any;
|
|
356
|
-
const activeId =
|
|
361
|
+
const activeId =
|
|
362
|
+
active?.data?.layerId === "image.user" ? active?.data?.id : null;
|
|
357
363
|
const targetId = id || activeId;
|
|
358
364
|
const target =
|
|
359
|
-
all.find(
|
|
360
|
-
|
|
365
|
+
all.find(
|
|
366
|
+
(obj) =>
|
|
367
|
+
obj?.data?.layerId === "image.user" && obj?.data?.id === targetId,
|
|
368
|
+
) || all.find((obj) => obj?.data?.layerId === "image.user");
|
|
361
369
|
if (!target) return null;
|
|
362
370
|
|
|
363
371
|
const objectWidthPx = Math.abs((target.width || 0) * (target.scaleX || 1));
|
|
364
|
-
const objectHeightPx = Math.abs(
|
|
372
|
+
const objectHeightPx = Math.abs(
|
|
373
|
+
(target.height || 0) * (target.scaleY || 1),
|
|
374
|
+
);
|
|
365
375
|
if (objectWidthPx <= 0 || objectHeightPx <= 0) return null;
|
|
366
376
|
|
|
367
377
|
const widthMm = objectWidthPx / layout.scale;
|