@pooder/kit 5.3.0 → 5.4.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 +12 -0
- package/dist/index.d.mts +249 -36
- package/dist/index.d.ts +249 -36
- package/dist/index.js +2374 -1049
- package/dist/index.mjs +2375 -1050
- package/package.json +1 -1
- package/src/extensions/background.ts +178 -85
- package/src/extensions/dieline.ts +1149 -1030
- package/src/extensions/dielineShape.ts +109 -0
- package/src/extensions/feature.ts +482 -366
- package/src/extensions/film.ts +148 -76
- package/src/extensions/geometry.ts +210 -44
- package/src/extensions/image.ts +244 -114
- package/src/extensions/ruler.ts +471 -268
- package/src/extensions/sceneLayoutModel.ts +28 -6
- package/src/extensions/sceneVisibility.ts +3 -10
- package/src/extensions/tracer.ts +1019 -980
- package/src/extensions/white-ink.ts +284 -231
- package/src/services/CanvasService.ts +543 -11
- package/src/services/renderSpec.ts +37 -2
- package/.test-dist/src/CanvasService.js +0 -249
- package/.test-dist/src/ViewportSystem.js +0 -75
- package/.test-dist/src/background.js +0 -203
- package/.test-dist/src/bridgeSelection.js +0 -20
- package/.test-dist/src/constraints.js +0 -237
- package/.test-dist/src/coordinate.js +0 -74
- package/.test-dist/src/dieline.js +0 -818
- package/.test-dist/src/edgeScale.js +0 -12
- package/.test-dist/src/extensions/background.js +0 -203
- package/.test-dist/src/extensions/bridgeSelection.js +0 -20
- package/.test-dist/src/extensions/constraints.js +0 -237
- package/.test-dist/src/extensions/dieline.js +0 -828
- package/.test-dist/src/extensions/edgeScale.js +0 -12
- package/.test-dist/src/extensions/feature.js +0 -825
- package/.test-dist/src/extensions/featureComplete.js +0 -32
- package/.test-dist/src/extensions/film.js +0 -167
- package/.test-dist/src/extensions/geometry.js +0 -545
- package/.test-dist/src/extensions/image.js +0 -1529
- package/.test-dist/src/extensions/index.js +0 -30
- package/.test-dist/src/extensions/maskOps.js +0 -279
- package/.test-dist/src/extensions/mirror.js +0 -104
- package/.test-dist/src/extensions/ruler.js +0 -345
- package/.test-dist/src/extensions/sceneLayout.js +0 -96
- package/.test-dist/src/extensions/sceneLayoutModel.js +0 -196
- package/.test-dist/src/extensions/sceneVisibility.js +0 -62
- package/.test-dist/src/extensions/size.js +0 -331
- package/.test-dist/src/extensions/tracer.js +0 -538
- package/.test-dist/src/extensions/white-ink.js +0 -1190
- package/.test-dist/src/extensions/wrappedOffsets.js +0 -33
- package/.test-dist/src/feature.js +0 -826
- package/.test-dist/src/featureComplete.js +0 -32
- package/.test-dist/src/film.js +0 -167
- package/.test-dist/src/geometry.js +0 -506
- package/.test-dist/src/image.js +0 -1250
- package/.test-dist/src/index.js +0 -18
- package/.test-dist/src/maskOps.js +0 -270
- package/.test-dist/src/mirror.js +0 -104
- package/.test-dist/src/renderSpec.js +0 -2
- package/.test-dist/src/ruler.js +0 -343
- package/.test-dist/src/sceneLayout.js +0 -99
- package/.test-dist/src/sceneLayoutModel.js +0 -196
- package/.test-dist/src/sceneView.js +0 -40
- package/.test-dist/src/sceneVisibility.js +0 -42
- package/.test-dist/src/services/CanvasService.js +0 -249
- package/.test-dist/src/services/ViewportSystem.js +0 -76
- package/.test-dist/src/services/index.js +0 -24
- package/.test-dist/src/services/renderSpec.js +0 -2
- package/.test-dist/src/size.js +0 -332
- package/.test-dist/src/tracer.js +0 -544
- package/.test-dist/src/units.js +0 -30
- package/.test-dist/src/white-ink.js +0 -829
- package/.test-dist/src/wrappedOffsets.js +0 -33
- package/.test-dist/tests/run.js +0 -94
package/dist/index.mjs
CHANGED
|
@@ -2,7 +2,12 @@
|
|
|
2
2
|
import {
|
|
3
3
|
ContributionPointIds
|
|
4
4
|
} from "@pooder/core";
|
|
5
|
-
import {
|
|
5
|
+
import { FabricImage } from "fabric";
|
|
6
|
+
var BACKGROUND_LAYER_ID = "background";
|
|
7
|
+
var BACKGROUND_RECT_ID = "background-color-rect";
|
|
8
|
+
var BACKGROUND_IMAGE_ID = "background-image";
|
|
9
|
+
var DEFAULT_WIDTH = 800;
|
|
10
|
+
var DEFAULT_HEIGHT = 600;
|
|
6
11
|
var BackgroundTool = class {
|
|
7
12
|
constructor(options) {
|
|
8
13
|
this.id = "pooder.kit.background";
|
|
@@ -11,17 +16,38 @@ var BackgroundTool = class {
|
|
|
11
16
|
};
|
|
12
17
|
this.color = "";
|
|
13
18
|
this.url = "";
|
|
19
|
+
this.specs = [];
|
|
20
|
+
this.renderSeq = 0;
|
|
21
|
+
this.renderImageUrl = "";
|
|
22
|
+
this.sourceSizeBySrc = /* @__PURE__ */ new Map();
|
|
23
|
+
this.pendingSizeBySrc = /* @__PURE__ */ new Map();
|
|
24
|
+
this.onCanvasResized = () => {
|
|
25
|
+
this.updateBackground();
|
|
26
|
+
};
|
|
14
27
|
if (options) {
|
|
15
28
|
Object.assign(this, options);
|
|
16
29
|
}
|
|
17
30
|
}
|
|
18
31
|
activate(context) {
|
|
32
|
+
var _a;
|
|
19
33
|
this.canvasService = context.services.get("CanvasService");
|
|
20
34
|
if (!this.canvasService) {
|
|
21
35
|
console.warn("CanvasService not found for BackgroundTool");
|
|
22
36
|
return;
|
|
23
37
|
}
|
|
24
|
-
|
|
38
|
+
(_a = this.renderProducerDisposable) == null ? void 0 : _a.dispose();
|
|
39
|
+
this.renderProducerDisposable = this.canvasService.registerRenderProducer(
|
|
40
|
+
this.id,
|
|
41
|
+
() => ({
|
|
42
|
+
layerSpecs: {
|
|
43
|
+
[BACKGROUND_LAYER_ID]: this.specs
|
|
44
|
+
}
|
|
45
|
+
}),
|
|
46
|
+
{ priority: 0 }
|
|
47
|
+
);
|
|
48
|
+
const configService = context.services.get(
|
|
49
|
+
"ConfigurationService"
|
|
50
|
+
);
|
|
25
51
|
if (configService) {
|
|
26
52
|
this.color = configService.get("background.color", this.color);
|
|
27
53
|
this.url = configService.get("background.url", this.url);
|
|
@@ -45,17 +71,25 @@ var BackgroundTool = class {
|
|
|
45
71
|
}
|
|
46
72
|
});
|
|
47
73
|
}
|
|
48
|
-
this.
|
|
74
|
+
context.eventBus.on("canvas:resized", this.onCanvasResized);
|
|
49
75
|
this.updateBackground();
|
|
50
76
|
}
|
|
51
77
|
deactivate(context) {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
78
|
+
var _a;
|
|
79
|
+
context.eventBus.off("canvas:resized", this.onCanvasResized);
|
|
80
|
+
this.renderSeq += 1;
|
|
81
|
+
this.specs = [];
|
|
82
|
+
this.renderImageUrl = "";
|
|
83
|
+
(_a = this.renderProducerDisposable) == null ? void 0 : _a.dispose();
|
|
84
|
+
this.renderProducerDisposable = void 0;
|
|
85
|
+
if (!this.canvasService) return;
|
|
86
|
+
const layer = this.canvasService.getLayer(BACKGROUND_LAYER_ID);
|
|
87
|
+
if (layer) {
|
|
88
|
+
this.canvasService.canvas.remove(layer);
|
|
58
89
|
}
|
|
90
|
+
void this.canvasService.flushRenderFromProducers();
|
|
91
|
+
this.canvasService.requestRenderAll();
|
|
92
|
+
this.canvasService = void 0;
|
|
59
93
|
}
|
|
60
94
|
contribute() {
|
|
61
95
|
return {
|
|
@@ -115,88 +149,131 @@ var BackgroundTool = class {
|
|
|
115
149
|
]
|
|
116
150
|
};
|
|
117
151
|
}
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
evented: false
|
|
127
|
-
});
|
|
128
|
-
this.canvasService.canvas.sendObjectToBack(backgroundLayer);
|
|
129
|
-
}
|
|
152
|
+
getViewportSize() {
|
|
153
|
+
var _a, _b;
|
|
154
|
+
const width = Number(((_a = this.canvasService) == null ? void 0 : _a.canvas.width) || 0);
|
|
155
|
+
const height = Number(((_b = this.canvasService) == null ? void 0 : _b.canvas.height) || 0);
|
|
156
|
+
return {
|
|
157
|
+
width: width > 0 ? width : DEFAULT_WIDTH,
|
|
158
|
+
height: height > 0 ? height : DEFAULT_HEIGHT
|
|
159
|
+
};
|
|
130
160
|
}
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
const
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
161
|
+
buildBackgroundSpecs(color, imageUrl) {
|
|
162
|
+
const { width, height } = this.getViewportSize();
|
|
163
|
+
const specs = [
|
|
164
|
+
{
|
|
165
|
+
id: BACKGROUND_RECT_ID,
|
|
166
|
+
type: "rect",
|
|
167
|
+
space: "screen",
|
|
168
|
+
data: {
|
|
169
|
+
id: BACKGROUND_RECT_ID,
|
|
170
|
+
layerId: BACKGROUND_LAYER_ID,
|
|
171
|
+
type: "background-color"
|
|
172
|
+
},
|
|
173
|
+
props: {
|
|
174
|
+
left: 0,
|
|
175
|
+
top: 0,
|
|
176
|
+
width,
|
|
177
|
+
height,
|
|
178
|
+
originX: "left",
|
|
179
|
+
originY: "top",
|
|
180
|
+
fill: color,
|
|
181
|
+
selectable: false,
|
|
182
|
+
evented: false,
|
|
183
|
+
excludeFromExport: true
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
];
|
|
187
|
+
if (!imageUrl) {
|
|
188
|
+
return specs;
|
|
137
189
|
}
|
|
138
|
-
const
|
|
139
|
-
const
|
|
140
|
-
const
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
190
|
+
const sourceSize = this.sourceSizeBySrc.get(imageUrl);
|
|
191
|
+
const sourceWidth = Math.max(1, Number((sourceSize == null ? void 0 : sourceSize.width) || width));
|
|
192
|
+
const sourceHeight = Math.max(1, Number((sourceSize == null ? void 0 : sourceSize.height) || height));
|
|
193
|
+
const coverScale = Math.max(width / sourceWidth, height / sourceHeight);
|
|
194
|
+
specs.push({
|
|
195
|
+
id: BACKGROUND_IMAGE_ID,
|
|
196
|
+
type: "image",
|
|
197
|
+
src: imageUrl,
|
|
198
|
+
space: "screen",
|
|
199
|
+
data: {
|
|
200
|
+
id: BACKGROUND_IMAGE_ID,
|
|
201
|
+
layerId: BACKGROUND_LAYER_ID,
|
|
202
|
+
type: "background-image"
|
|
203
|
+
},
|
|
204
|
+
props: {
|
|
205
|
+
left: 0,
|
|
206
|
+
top: 0,
|
|
207
|
+
originX: "left",
|
|
208
|
+
originY: "top",
|
|
209
|
+
scaleX: coverScale,
|
|
210
|
+
scaleY: coverScale,
|
|
154
211
|
selectable: false,
|
|
155
212
|
evented: false,
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
213
|
+
excludeFromExport: true
|
|
214
|
+
}
|
|
215
|
+
});
|
|
216
|
+
return specs;
|
|
217
|
+
}
|
|
218
|
+
async ensureImageSize(src) {
|
|
219
|
+
if (!src) return null;
|
|
220
|
+
const cached = this.sourceSizeBySrc.get(src);
|
|
221
|
+
if (cached) return cached;
|
|
222
|
+
const pending = this.pendingSizeBySrc.get(src);
|
|
223
|
+
if (pending) {
|
|
224
|
+
return pending;
|
|
162
225
|
}
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
"background"
|
|
166
|
-
);
|
|
226
|
+
const task = this.loadImageSize(src);
|
|
227
|
+
this.pendingSizeBySrc.set(src, task);
|
|
167
228
|
try {
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
} else {
|
|
173
|
-
layer.remove(img);
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
} else {
|
|
177
|
-
if (url) {
|
|
178
|
-
img = await Image2.fromURL(url, { crossOrigin: "anonymous" });
|
|
179
|
-
img.set({
|
|
180
|
-
originX: "left",
|
|
181
|
-
originY: "top",
|
|
182
|
-
left: 0,
|
|
183
|
-
top: 0,
|
|
184
|
-
selectable: false,
|
|
185
|
-
evented: false,
|
|
186
|
-
data: {
|
|
187
|
-
id: "background-image"
|
|
188
|
-
}
|
|
189
|
-
});
|
|
190
|
-
img.scaleToWidth(width);
|
|
191
|
-
if (img.getScaledHeight() < height) img.scaleToHeight(height);
|
|
192
|
-
layer.add(img);
|
|
193
|
-
}
|
|
229
|
+
return await task;
|
|
230
|
+
} finally {
|
|
231
|
+
if (this.pendingSizeBySrc.get(src) === task) {
|
|
232
|
+
this.pendingSizeBySrc.delete(src);
|
|
194
233
|
}
|
|
195
|
-
this.canvasService.requestRenderAll();
|
|
196
|
-
} catch (e) {
|
|
197
|
-
console.error("[BackgroundTool] Failed to load image", e);
|
|
198
234
|
}
|
|
199
|
-
|
|
235
|
+
}
|
|
236
|
+
async loadImageSize(src) {
|
|
237
|
+
try {
|
|
238
|
+
const image = await FabricImage.fromURL(src, {
|
|
239
|
+
crossOrigin: "anonymous"
|
|
240
|
+
});
|
|
241
|
+
const width = Number((image == null ? void 0 : image.width) || 0);
|
|
242
|
+
const height = Number((image == null ? void 0 : image.height) || 0);
|
|
243
|
+
if (width > 0 && height > 0) {
|
|
244
|
+
const size = { width, height };
|
|
245
|
+
this.sourceSizeBySrc.set(src, size);
|
|
246
|
+
return size;
|
|
247
|
+
}
|
|
248
|
+
} catch (error) {
|
|
249
|
+
console.error("[BackgroundTool] Failed to load image", src, error);
|
|
250
|
+
}
|
|
251
|
+
return null;
|
|
252
|
+
}
|
|
253
|
+
updateBackground() {
|
|
254
|
+
void this.updateBackgroundAsync();
|
|
255
|
+
}
|
|
256
|
+
async updateBackgroundAsync() {
|
|
257
|
+
if (!this.canvasService) return;
|
|
258
|
+
const seq = ++this.renderSeq;
|
|
259
|
+
const color = this.color;
|
|
260
|
+
const nextUrl = String(this.url || "").trim();
|
|
261
|
+
if (!nextUrl) {
|
|
262
|
+
this.renderImageUrl = "";
|
|
263
|
+
} else if (nextUrl !== this.renderImageUrl) {
|
|
264
|
+
const loaded = await this.ensureImageSize(nextUrl);
|
|
265
|
+
if (seq !== this.renderSeq) return;
|
|
266
|
+
if (loaded) {
|
|
267
|
+
this.renderImageUrl = nextUrl;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
this.specs = this.buildBackgroundSpecs(color, this.renderImageUrl);
|
|
271
|
+
await this.canvasService.flushRenderFromProducers();
|
|
272
|
+
if (seq !== this.renderSeq) return;
|
|
273
|
+
const layer = this.canvasService.getLayer(BACKGROUND_LAYER_ID);
|
|
274
|
+
if (layer) {
|
|
275
|
+
this.canvasService.canvas.sendObjectToBack(layer);
|
|
276
|
+
}
|
|
200
277
|
this.canvasService.requestRenderAll();
|
|
201
278
|
}
|
|
202
279
|
};
|
|
@@ -207,11 +284,76 @@ import {
|
|
|
207
284
|
} from "@pooder/core";
|
|
208
285
|
import {
|
|
209
286
|
Canvas as FabricCanvas,
|
|
210
|
-
Image as
|
|
287
|
+
Image as FabricImage2,
|
|
211
288
|
Pattern,
|
|
212
289
|
Point
|
|
213
290
|
} from "fabric";
|
|
214
291
|
|
|
292
|
+
// src/extensions/dielineShape.ts
|
|
293
|
+
var BUILTIN_DIELINE_SHAPES = [
|
|
294
|
+
"rect",
|
|
295
|
+
"circle",
|
|
296
|
+
"ellipse",
|
|
297
|
+
"heart"
|
|
298
|
+
];
|
|
299
|
+
var DIELINE_SHAPES = [...BUILTIN_DIELINE_SHAPES, "custom"];
|
|
300
|
+
var DEFAULT_DIELINE_SHAPE = "rect";
|
|
301
|
+
var DEFAULT_HEART_SHAPE_PARAMS = {
|
|
302
|
+
lobeSpread: 0.46,
|
|
303
|
+
notchDepth: 0.24,
|
|
304
|
+
tipSharpness: 0
|
|
305
|
+
};
|
|
306
|
+
var DEFAULT_DIELINE_SHAPE_STYLE = {
|
|
307
|
+
fitMode: "contain",
|
|
308
|
+
...DEFAULT_HEART_SHAPE_PARAMS
|
|
309
|
+
};
|
|
310
|
+
function isDielineShape(value) {
|
|
311
|
+
return typeof value === "string" && DIELINE_SHAPES.includes(value);
|
|
312
|
+
}
|
|
313
|
+
function normalizeFitMode(value, fallback) {
|
|
314
|
+
if (value === "contain" || value === "stretch") return value;
|
|
315
|
+
return fallback;
|
|
316
|
+
}
|
|
317
|
+
function normalizeUnitInterval(value, fallback) {
|
|
318
|
+
const num = Number(value);
|
|
319
|
+
if (!Number.isFinite(num)) return fallback;
|
|
320
|
+
return Math.max(0, Math.min(1, num));
|
|
321
|
+
}
|
|
322
|
+
function normalizeDielineShape(value, fallback = DEFAULT_DIELINE_SHAPE) {
|
|
323
|
+
return isDielineShape(value) ? value : fallback;
|
|
324
|
+
}
|
|
325
|
+
function normalizeShapeStyle(value, fallback = DEFAULT_DIELINE_SHAPE_STYLE) {
|
|
326
|
+
var _a, _b, _c;
|
|
327
|
+
const raw = value && typeof value === "object" ? value : {};
|
|
328
|
+
return {
|
|
329
|
+
...fallback,
|
|
330
|
+
fitMode: normalizeFitMode(raw.fitMode, fallback.fitMode),
|
|
331
|
+
lobeSpread: normalizeUnitInterval(
|
|
332
|
+
raw.lobeSpread,
|
|
333
|
+
Number((_a = fallback.lobeSpread) != null ? _a : DEFAULT_HEART_SHAPE_PARAMS.lobeSpread)
|
|
334
|
+
),
|
|
335
|
+
notchDepth: normalizeUnitInterval(
|
|
336
|
+
raw.notchDepth,
|
|
337
|
+
Number((_b = fallback.notchDepth) != null ? _b : DEFAULT_HEART_SHAPE_PARAMS.notchDepth)
|
|
338
|
+
),
|
|
339
|
+
tipSharpness: normalizeUnitInterval(
|
|
340
|
+
raw.tipSharpness,
|
|
341
|
+
Number((_c = fallback.tipSharpness) != null ? _c : DEFAULT_HEART_SHAPE_PARAMS.tipSharpness)
|
|
342
|
+
)
|
|
343
|
+
};
|
|
344
|
+
}
|
|
345
|
+
function getShapeFitMode(style) {
|
|
346
|
+
return normalizeShapeStyle(style).fitMode;
|
|
347
|
+
}
|
|
348
|
+
function getHeartShapeParams(style) {
|
|
349
|
+
const normalized = normalizeShapeStyle(style);
|
|
350
|
+
return {
|
|
351
|
+
lobeSpread: Number(normalized.lobeSpread),
|
|
352
|
+
notchDepth: Number(normalized.notchDepth),
|
|
353
|
+
tipSharpness: Number(normalized.tipSharpness)
|
|
354
|
+
};
|
|
355
|
+
}
|
|
356
|
+
|
|
215
357
|
// src/extensions/geometry.ts
|
|
216
358
|
import paper from "paper";
|
|
217
359
|
|
|
@@ -354,45 +496,164 @@ function selectOuterChain(args) {
|
|
|
354
496
|
if (scoreA !== scoreB) return scoreA > scoreB ? pointsA : pointsB;
|
|
355
497
|
return pointsA.length <= pointsB.length ? pointsA : pointsB;
|
|
356
498
|
}
|
|
357
|
-
function
|
|
358
|
-
|
|
359
|
-
const
|
|
360
|
-
|
|
361
|
-
|
|
499
|
+
function fitPathItemToRect(item, rect, fitMode) {
|
|
500
|
+
const { left, top, width, height } = rect;
|
|
501
|
+
const bounds = item.bounds;
|
|
502
|
+
if (width <= 0 || height <= 0 || !Number.isFinite(bounds.width) || !Number.isFinite(bounds.height) || bounds.width <= 0 || bounds.height <= 0) {
|
|
503
|
+
item.position = new paper.Point(left + width / 2, top + height / 2);
|
|
504
|
+
return item;
|
|
505
|
+
}
|
|
506
|
+
item.translate(new paper.Point(-bounds.left, -bounds.top));
|
|
507
|
+
if (fitMode === "stretch") {
|
|
508
|
+
item.scale(width / bounds.width, height / bounds.height, new paper.Point(0, 0));
|
|
509
|
+
item.translate(new paper.Point(left, top));
|
|
510
|
+
return item;
|
|
511
|
+
}
|
|
512
|
+
const uniformScale = Math.min(width / bounds.width, height / bounds.height);
|
|
513
|
+
item.scale(uniformScale, uniformScale, new paper.Point(0, 0));
|
|
514
|
+
const scaledWidth = bounds.width * uniformScale;
|
|
515
|
+
const scaledHeight = bounds.height * uniformScale;
|
|
516
|
+
item.translate(
|
|
517
|
+
new paper.Point(
|
|
518
|
+
left + (width - scaledWidth) / 2,
|
|
519
|
+
top + (height - scaledHeight) / 2
|
|
520
|
+
)
|
|
521
|
+
);
|
|
522
|
+
return item;
|
|
523
|
+
}
|
|
524
|
+
function createNormalizedHeartPath(params) {
|
|
525
|
+
const { lobeSpread, notchDepth, tipSharpness } = params;
|
|
526
|
+
const halfSpread = 0.22 + lobeSpread * 0.18;
|
|
527
|
+
const notchY = 0.06 + notchDepth * 0.2;
|
|
528
|
+
const shoulderY = 0.24 + notchDepth * 0.2;
|
|
529
|
+
const topLift = 0.12 + (1 - notchDepth) * 0.06;
|
|
530
|
+
const topY = notchY - topLift;
|
|
531
|
+
const sideCtrlY = shoulderY - (0.18 - notchDepth * 0.08);
|
|
532
|
+
const lowerCtrlY = 0.58 + (1 - tipSharpness) * 0.16;
|
|
533
|
+
const tipCtrlX = 0.34 - tipSharpness * 0.2;
|
|
534
|
+
const notchCtrlX = 0.06 + lobeSpread * 0.06;
|
|
535
|
+
const lobeCtrlX = 0.1 + lobeSpread * 0.08;
|
|
536
|
+
const notchCtrlY = notchY - topLift * 0.45;
|
|
537
|
+
const xPeakL = 0.5 - halfSpread;
|
|
538
|
+
const xPeakR = 0.5 + halfSpread;
|
|
539
|
+
const heartPath = new paper.Path({ insert: false });
|
|
540
|
+
heartPath.moveTo(new paper.Point(0.5, notchY));
|
|
541
|
+
heartPath.cubicCurveTo(
|
|
542
|
+
new paper.Point(0.5 - notchCtrlX, notchCtrlY),
|
|
543
|
+
new paper.Point(xPeakL + lobeCtrlX, topY),
|
|
544
|
+
new paper.Point(xPeakL, topY)
|
|
545
|
+
);
|
|
546
|
+
heartPath.cubicCurveTo(
|
|
547
|
+
new paper.Point(xPeakL - lobeCtrlX, topY),
|
|
548
|
+
new paper.Point(0, sideCtrlY),
|
|
549
|
+
new paper.Point(0, shoulderY)
|
|
550
|
+
);
|
|
551
|
+
heartPath.cubicCurveTo(
|
|
552
|
+
new paper.Point(0, lowerCtrlY),
|
|
553
|
+
new paper.Point(tipCtrlX, 1),
|
|
554
|
+
new paper.Point(0.5, 1)
|
|
555
|
+
);
|
|
556
|
+
heartPath.cubicCurveTo(
|
|
557
|
+
new paper.Point(1 - tipCtrlX, 1),
|
|
558
|
+
new paper.Point(1, lowerCtrlY),
|
|
559
|
+
new paper.Point(1, shoulderY)
|
|
560
|
+
);
|
|
561
|
+
heartPath.cubicCurveTo(
|
|
562
|
+
new paper.Point(1, sideCtrlY),
|
|
563
|
+
new paper.Point(xPeakR + lobeCtrlX, topY),
|
|
564
|
+
new paper.Point(xPeakR, topY)
|
|
565
|
+
);
|
|
566
|
+
heartPath.cubicCurveTo(
|
|
567
|
+
new paper.Point(xPeakR - lobeCtrlX, topY),
|
|
568
|
+
new paper.Point(0.5 + notchCtrlX, notchCtrlY),
|
|
569
|
+
new paper.Point(0.5, notchY)
|
|
570
|
+
);
|
|
571
|
+
heartPath.closed = true;
|
|
572
|
+
return heartPath;
|
|
573
|
+
}
|
|
574
|
+
function createHeartBaseShape(options) {
|
|
575
|
+
const { x, y, width, height } = options;
|
|
576
|
+
const w = Math.max(0, width);
|
|
577
|
+
const h = Math.max(0, height);
|
|
578
|
+
const left = x - w / 2;
|
|
579
|
+
const top = y - h / 2;
|
|
580
|
+
const fitMode = getShapeFitMode(options.shapeStyle);
|
|
581
|
+
const heartParams = getHeartShapeParams(options.shapeStyle);
|
|
582
|
+
const rawHeart = createNormalizedHeartPath(heartParams);
|
|
583
|
+
return fitPathItemToRect(rawHeart, { left, top, width: w, height: h }, fitMode);
|
|
584
|
+
}
|
|
585
|
+
var BUILTIN_SHAPE_BUILDERS = {
|
|
586
|
+
rect: (options) => {
|
|
587
|
+
const { x, y, width, height, radius } = options;
|
|
362
588
|
return new paper.Path.Rectangle({
|
|
363
589
|
point: [x - width / 2, y - height / 2],
|
|
364
590
|
size: [Math.max(0, width), Math.max(0, height)],
|
|
365
591
|
radius: Math.max(0, radius)
|
|
366
592
|
});
|
|
367
|
-
}
|
|
593
|
+
},
|
|
594
|
+
circle: (options) => {
|
|
595
|
+
const { x, y, width, height } = options;
|
|
368
596
|
const r = Math.min(width, height) / 2;
|
|
369
597
|
return new paper.Path.Circle({
|
|
370
|
-
center,
|
|
598
|
+
center: new paper.Point(x, y),
|
|
371
599
|
radius: Math.max(0, r)
|
|
372
600
|
});
|
|
373
|
-
}
|
|
601
|
+
},
|
|
602
|
+
ellipse: (options) => {
|
|
603
|
+
const { x, y, width, height } = options;
|
|
374
604
|
return new paper.Path.Ellipse({
|
|
375
|
-
center,
|
|
605
|
+
center: new paper.Point(x, y),
|
|
376
606
|
radius: [Math.max(0, width / 2), Math.max(0, height / 2)]
|
|
377
607
|
});
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
608
|
+
},
|
|
609
|
+
heart: createHeartBaseShape
|
|
610
|
+
};
|
|
611
|
+
function createCustomBaseShape(options) {
|
|
612
|
+
var _a;
|
|
613
|
+
const {
|
|
614
|
+
pathData,
|
|
615
|
+
customSourceWidthPx,
|
|
616
|
+
customSourceHeightPx,
|
|
617
|
+
x,
|
|
618
|
+
y,
|
|
619
|
+
width,
|
|
620
|
+
height
|
|
621
|
+
} = options;
|
|
622
|
+
if (typeof pathData !== "string" || pathData.trim().length === 0) {
|
|
623
|
+
return null;
|
|
624
|
+
}
|
|
625
|
+
const center = new paper.Point(x, y);
|
|
626
|
+
const hasMultipleSubPaths = ((_a = (pathData.match(/[Mm]/g) || []).length) != null ? _a : 0) > 1;
|
|
627
|
+
const path = hasMultipleSubPaths ? new paper.CompoundPath(pathData) : (() => {
|
|
628
|
+
const single = new paper.Path();
|
|
629
|
+
single.pathData = pathData;
|
|
630
|
+
return single;
|
|
631
|
+
})();
|
|
632
|
+
const sourceWidth = Number(customSourceWidthPx != null ? customSourceWidthPx : 0);
|
|
633
|
+
const sourceHeight = Number(customSourceHeightPx != null ? customSourceHeightPx : 0);
|
|
634
|
+
if (Number.isFinite(sourceWidth) && Number.isFinite(sourceHeight) && sourceWidth > 0 && sourceHeight > 0 && width > 0 && height > 0) {
|
|
635
|
+
const targetLeft = x - width / 2;
|
|
636
|
+
const targetTop = y - height / 2;
|
|
637
|
+
path.scale(width / sourceWidth, height / sourceHeight, new paper.Point(0, 0));
|
|
638
|
+
path.translate(new paper.Point(targetLeft, targetTop));
|
|
639
|
+
return path;
|
|
640
|
+
}
|
|
641
|
+
if (width > 0 && height > 0 && path.bounds.width > 0 && path.bounds.height > 0) {
|
|
385
642
|
path.position = center;
|
|
386
|
-
|
|
387
|
-
path.scale(width / path.bounds.width, height / path.bounds.height);
|
|
388
|
-
}
|
|
643
|
+
path.scale(width / path.bounds.width, height / path.bounds.height);
|
|
389
644
|
return path;
|
|
390
|
-
} else {
|
|
391
|
-
return new paper.Path.Rectangle({
|
|
392
|
-
point: [x - width / 2, y - height / 2],
|
|
393
|
-
size: [Math.max(0, width), Math.max(0, height)]
|
|
394
|
-
});
|
|
395
645
|
}
|
|
646
|
+
path.position = center;
|
|
647
|
+
return path;
|
|
648
|
+
}
|
|
649
|
+
function createBaseShape(options) {
|
|
650
|
+
const { shape } = options;
|
|
651
|
+
if (shape === "custom") {
|
|
652
|
+
const customShape = createCustomBaseShape(options);
|
|
653
|
+
if (customShape) return customShape;
|
|
654
|
+
return BUILTIN_SHAPE_BUILDERS[DEFAULT_DIELINE_SHAPE](options);
|
|
655
|
+
}
|
|
656
|
+
return BUILTIN_SHAPE_BUILDERS[shape](options);
|
|
396
657
|
}
|
|
397
658
|
function resolveBridgeBasePath(shape, anchor) {
|
|
398
659
|
if (shape instanceof paper.Path) {
|
|
@@ -716,6 +977,18 @@ function getNearestPointOnDieline(point, options) {
|
|
|
716
977
|
shape.remove();
|
|
717
978
|
return result;
|
|
718
979
|
}
|
|
980
|
+
function getPathBounds(pathData) {
|
|
981
|
+
const path = new paper.Path();
|
|
982
|
+
path.pathData = pathData;
|
|
983
|
+
const bounds = path.bounds;
|
|
984
|
+
path.remove();
|
|
985
|
+
return {
|
|
986
|
+
x: bounds.x,
|
|
987
|
+
y: bounds.y,
|
|
988
|
+
width: bounds.width,
|
|
989
|
+
height: bounds.height
|
|
990
|
+
};
|
|
991
|
+
}
|
|
719
992
|
|
|
720
993
|
// src/coordinate.ts
|
|
721
994
|
var Coordinate = class {
|
|
@@ -804,12 +1077,6 @@ function parseLengthToMm(input, defaultUnit) {
|
|
|
804
1077
|
const unit = (_b = (_a = match[2]) == null ? void 0 : _a.toLowerCase()) != null ? _b : defaultUnit;
|
|
805
1078
|
return Coordinate.convertUnit(value, unit, "mm");
|
|
806
1079
|
}
|
|
807
|
-
function formatMm(valueMm, displayUnit, fractionDigits = 2) {
|
|
808
|
-
if (!Number.isFinite(valueMm)) return "0";
|
|
809
|
-
const value = Coordinate.convertUnit(valueMm, "mm", displayUnit);
|
|
810
|
-
const rounded = Number(value.toFixed(fractionDigits));
|
|
811
|
-
return rounded.toString();
|
|
812
|
-
}
|
|
813
1080
|
|
|
814
1081
|
// src/extensions/sceneLayoutModel.ts
|
|
815
1082
|
var DEFAULT_SIZE_STATE = {
|
|
@@ -1020,10 +1287,19 @@ function buildSceneGeometry(configService, layout) {
|
|
|
1020
1287
|
"mm"
|
|
1021
1288
|
);
|
|
1022
1289
|
const offset = (layout.cutRect.width - layout.trimRect.width) / 2;
|
|
1290
|
+
const sourceWidth = Number(configService.get("dieline.customSourceWidthPx", 0));
|
|
1291
|
+
const sourceHeight = Number(
|
|
1292
|
+
configService.get("dieline.customSourceHeightPx", 0)
|
|
1293
|
+
);
|
|
1294
|
+
const shapeStyle = normalizeShapeStyle(
|
|
1295
|
+
configService.get("dieline.shapeStyle", DEFAULT_DIELINE_SHAPE_STYLE)
|
|
1296
|
+
);
|
|
1023
1297
|
return {
|
|
1024
|
-
shape:
|
|
1025
|
-
|
|
1026
|
-
|
|
1298
|
+
shape: normalizeDielineShape(
|
|
1299
|
+
configService.get("dieline.shape", DEFAULT_DIELINE_SHAPE)
|
|
1300
|
+
),
|
|
1301
|
+
shapeStyle,
|
|
1302
|
+
unit: "px",
|
|
1027
1303
|
x: layout.trimRect.centerX,
|
|
1028
1304
|
y: layout.trimRect.centerY,
|
|
1029
1305
|
width: layout.trimRect.width,
|
|
@@ -1031,7 +1307,9 @@ function buildSceneGeometry(configService, layout) {
|
|
|
1031
1307
|
radius: radiusMm * layout.scale,
|
|
1032
1308
|
offset,
|
|
1033
1309
|
scale: layout.scale,
|
|
1034
|
-
pathData: configService.get("dieline.pathData")
|
|
1310
|
+
pathData: configService.get("dieline.pathData"),
|
|
1311
|
+
customSourceWidthPx: Number.isFinite(sourceWidth) && sourceWidth > 0 ? sourceWidth : void 0,
|
|
1312
|
+
customSourceHeightPx: Number.isFinite(sourceHeight) && sourceHeight > 0 ? sourceHeight : void 0
|
|
1035
1313
|
};
|
|
1036
1314
|
}
|
|
1037
1315
|
|
|
@@ -1054,6 +1332,7 @@ var ImageTool = class {
|
|
|
1054
1332
|
this.isImageSelectionActive = false;
|
|
1055
1333
|
this.focusedImageId = null;
|
|
1056
1334
|
this.renderSeq = 0;
|
|
1335
|
+
this.overlaySpecs = [];
|
|
1057
1336
|
this.onToolActivated = (event) => {
|
|
1058
1337
|
const before = this.isToolActive;
|
|
1059
1338
|
this.syncToolActiveFromWorkbench(event.id);
|
|
@@ -1131,28 +1410,41 @@ var ImageTool = class {
|
|
|
1131
1410
|
const frame = this.getFrameRect();
|
|
1132
1411
|
if (!frame.width || !frame.height) return;
|
|
1133
1412
|
const center = target.getCenterPoint ? target.getCenterPoint() : new Point((_c = target.left) != null ? _c : 0, (_d = target.top) != null ? _d : 0);
|
|
1413
|
+
const centerScene = this.canvasService ? this.canvasService.toScenePoint({ x: center.x, y: center.y }) : { x: center.x, y: center.y };
|
|
1134
1414
|
const objectScale = Number.isFinite(target == null ? void 0 : target.scaleX) ? target.scaleX : 1;
|
|
1415
|
+
const objectScaleScene = this.toSceneObjectScale(objectScale || 1);
|
|
1135
1416
|
const workingItem = this.workingItems.find((item) => item.id === id);
|
|
1136
1417
|
const sourceKey = (workingItem == null ? void 0 : workingItem.sourceUrl) || (workingItem == null ? void 0 : workingItem.url) || "";
|
|
1137
1418
|
const sourceSize = this.getSourceSize(sourceKey, target);
|
|
1138
1419
|
const coverScale = this.getCoverScale(frame, sourceSize);
|
|
1139
1420
|
const updates = {
|
|
1140
|
-
left: this.clampNormalized((
|
|
1141
|
-
top: this.clampNormalized((
|
|
1421
|
+
left: this.clampNormalized((centerScene.x - frame.left) / frame.width),
|
|
1422
|
+
top: this.clampNormalized((centerScene.y - frame.top) / frame.height),
|
|
1142
1423
|
angle: Number.isFinite(target.angle) ? target.angle : 0,
|
|
1143
|
-
scale: Math.max(0.05,
|
|
1424
|
+
scale: Math.max(0.05, objectScaleScene / coverScale)
|
|
1144
1425
|
};
|
|
1145
1426
|
this.focusedImageId = id;
|
|
1146
1427
|
this.updateImageInWorking(id, updates);
|
|
1147
1428
|
};
|
|
1148
1429
|
}
|
|
1149
1430
|
activate(context) {
|
|
1431
|
+
var _a;
|
|
1150
1432
|
this.context = context;
|
|
1151
1433
|
this.canvasService = context.services.get("CanvasService");
|
|
1152
1434
|
if (!this.canvasService) {
|
|
1153
1435
|
console.warn("CanvasService not found for ImageTool");
|
|
1154
1436
|
return;
|
|
1155
1437
|
}
|
|
1438
|
+
(_a = this.renderProducerDisposable) == null ? void 0 : _a.dispose();
|
|
1439
|
+
this.renderProducerDisposable = this.canvasService.registerRenderProducer(
|
|
1440
|
+
this.id,
|
|
1441
|
+
() => ({
|
|
1442
|
+
rootLayerSpecs: {
|
|
1443
|
+
[IMAGE_OVERLAY_LAYER_ID]: this.overlaySpecs
|
|
1444
|
+
}
|
|
1445
|
+
}),
|
|
1446
|
+
{ priority: 300 }
|
|
1447
|
+
);
|
|
1156
1448
|
context.eventBus.on("tool:activated", this.onToolActivated);
|
|
1157
1449
|
context.eventBus.on("object:modified", this.onObjectModified);
|
|
1158
1450
|
context.eventBus.on("selection:created", this.onSelectionChanged);
|
|
@@ -1193,7 +1485,7 @@ var ImageTool = class {
|
|
|
1193
1485
|
this.updateImages();
|
|
1194
1486
|
}
|
|
1195
1487
|
deactivate(context) {
|
|
1196
|
-
var _a;
|
|
1488
|
+
var _a, _b;
|
|
1197
1489
|
context.eventBus.off("tool:activated", this.onToolActivated);
|
|
1198
1490
|
context.eventBus.off("object:modified", this.onObjectModified);
|
|
1199
1491
|
context.eventBus.off("selection:created", this.onSelectionChanged);
|
|
@@ -1205,12 +1497,13 @@ var ImageTool = class {
|
|
|
1205
1497
|
this.dirtyTrackerDisposable = void 0;
|
|
1206
1498
|
this.cropShapeHatchPattern = void 0;
|
|
1207
1499
|
this.cropShapeHatchPatternColor = void 0;
|
|
1500
|
+
this.cropShapeHatchPatternKey = void 0;
|
|
1501
|
+
this.overlaySpecs = [];
|
|
1208
1502
|
this.clearRenderedImages();
|
|
1503
|
+
(_b = this.renderProducerDisposable) == null ? void 0 : _b.dispose();
|
|
1504
|
+
this.renderProducerDisposable = void 0;
|
|
1209
1505
|
if (this.canvasService) {
|
|
1210
|
-
void this.canvasService.
|
|
1211
|
-
IMAGE_OVERLAY_LAYER_ID,
|
|
1212
|
-
[]
|
|
1213
|
-
);
|
|
1506
|
+
void this.canvasService.flushRenderFromProducers();
|
|
1214
1507
|
this.canvasService = void 0;
|
|
1215
1508
|
}
|
|
1216
1509
|
this.context = void 0;
|
|
@@ -1621,38 +1914,38 @@ var ImageTool = class {
|
|
|
1621
1914
|
if (!layout) {
|
|
1622
1915
|
return { left: 0, top: 0, width: 0, height: 0 };
|
|
1623
1916
|
}
|
|
1624
|
-
return {
|
|
1917
|
+
return this.canvasService.toSceneRect({
|
|
1625
1918
|
left: layout.cutRect.left,
|
|
1626
1919
|
top: layout.cutRect.top,
|
|
1627
1920
|
width: layout.cutRect.width,
|
|
1628
1921
|
height: layout.cutRect.height
|
|
1922
|
+
});
|
|
1923
|
+
}
|
|
1924
|
+
getFrameRectScreen(frame) {
|
|
1925
|
+
if (!this.canvasService) {
|
|
1926
|
+
return { left: 0, top: 0, width: 0, height: 0 };
|
|
1927
|
+
}
|
|
1928
|
+
return this.canvasService.toScreenRect(frame || this.getFrameRect());
|
|
1929
|
+
}
|
|
1930
|
+
toLayoutSceneRect(rect) {
|
|
1931
|
+
return {
|
|
1932
|
+
left: rect.left,
|
|
1933
|
+
top: rect.top,
|
|
1934
|
+
width: rect.width,
|
|
1935
|
+
height: rect.height,
|
|
1936
|
+
space: "scene"
|
|
1629
1937
|
};
|
|
1630
1938
|
}
|
|
1631
1939
|
async resolveDefaultFitArea() {
|
|
1632
|
-
if (!this.
|
|
1633
|
-
const
|
|
1634
|
-
if (
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
const height = Number(cutRect == null ? void 0 : cutRect.height);
|
|
1642
|
-
const left = Number(cutRect == null ? void 0 : cutRect.left);
|
|
1643
|
-
const top = Number(cutRect == null ? void 0 : cutRect.top);
|
|
1644
|
-
if (!Number.isFinite(width) || !Number.isFinite(height) || !Number.isFinite(left) || !Number.isFinite(top)) {
|
|
1645
|
-
return null;
|
|
1646
|
-
}
|
|
1647
|
-
return {
|
|
1648
|
-
width: Math.max(1, width),
|
|
1649
|
-
height: Math.max(1, height),
|
|
1650
|
-
left: left + width / 2,
|
|
1651
|
-
top: top + height / 2
|
|
1652
|
-
};
|
|
1653
|
-
} catch (e) {
|
|
1654
|
-
return null;
|
|
1655
|
-
}
|
|
1940
|
+
if (!this.canvasService) return null;
|
|
1941
|
+
const frame = this.getFrameRect();
|
|
1942
|
+
if (frame.width <= 0 || frame.height <= 0) return null;
|
|
1943
|
+
return {
|
|
1944
|
+
width: Math.max(1, frame.width),
|
|
1945
|
+
height: Math.max(1, frame.height),
|
|
1946
|
+
left: frame.left + frame.width / 2,
|
|
1947
|
+
top: frame.top + frame.height / 2
|
|
1948
|
+
};
|
|
1656
1949
|
}
|
|
1657
1950
|
async fitImageToDefaultArea(id) {
|
|
1658
1951
|
if (!this.canvasService) return;
|
|
@@ -1661,13 +1954,14 @@ var ImageTool = class {
|
|
|
1661
1954
|
await this.fitImageToArea(id, area);
|
|
1662
1955
|
return;
|
|
1663
1956
|
}
|
|
1664
|
-
const
|
|
1665
|
-
const
|
|
1957
|
+
const viewport = this.canvasService.getSceneViewportRect();
|
|
1958
|
+
const canvasW = Math.max(1, viewport.width || 0);
|
|
1959
|
+
const canvasH = Math.max(1, viewport.height || 0);
|
|
1666
1960
|
await this.fitImageToArea(id, {
|
|
1667
1961
|
width: canvasW,
|
|
1668
1962
|
height: canvasH,
|
|
1669
|
-
left: canvasW / 2,
|
|
1670
|
-
top: canvasH / 2
|
|
1963
|
+
left: viewport.left + canvasW / 2,
|
|
1964
|
+
top: viewport.top + canvasH / 2
|
|
1671
1965
|
});
|
|
1672
1966
|
}
|
|
1673
1967
|
getImageObjects() {
|
|
@@ -1755,13 +2049,17 @@ var ImageTool = class {
|
|
|
1755
2049
|
}
|
|
1756
2050
|
toSceneGeometryLike(raw) {
|
|
1757
2051
|
const shape = raw == null ? void 0 : raw.shape;
|
|
1758
|
-
if (shape
|
|
2052
|
+
if (!isDielineShape(shape)) {
|
|
1759
2053
|
return null;
|
|
1760
2054
|
}
|
|
1761
|
-
const
|
|
1762
|
-
const
|
|
2055
|
+
const radiusRaw = Number(raw == null ? void 0 : raw.radius);
|
|
2056
|
+
const offsetRaw = Number(raw == null ? void 0 : raw.offset);
|
|
2057
|
+
const unit = typeof (raw == null ? void 0 : raw.unit) === "string" ? raw.unit : "px";
|
|
2058
|
+
const radius = unit === "scene" || !this.canvasService ? radiusRaw : this.canvasService.toSceneLength(radiusRaw);
|
|
2059
|
+
const offset = unit === "scene" || !this.canvasService ? offsetRaw : this.canvasService.toSceneLength(offsetRaw);
|
|
1763
2060
|
return {
|
|
1764
2061
|
shape,
|
|
2062
|
+
shapeStyle: normalizeShapeStyle(raw == null ? void 0 : raw.shapeStyle),
|
|
1765
2063
|
radius: Number.isFinite(radius) ? radius : 0,
|
|
1766
2064
|
offset: Number.isFinite(offset) ? offset : 0
|
|
1767
2065
|
};
|
|
@@ -1813,8 +2111,11 @@ var ImageTool = class {
|
|
|
1813
2111
|
return Math.max(0, Math.min(maxRadius, rawCutRadius));
|
|
1814
2112
|
}
|
|
1815
2113
|
getCropShapeHatchPattern(color = "rgba(255, 0, 0, 0.6)") {
|
|
2114
|
+
var _a;
|
|
1816
2115
|
if (typeof document === "undefined") return void 0;
|
|
1817
|
-
|
|
2116
|
+
const sceneScale = ((_a = this.canvasService) == null ? void 0 : _a.getSceneScale()) || 1;
|
|
2117
|
+
const cacheKey = `${color}::${sceneScale.toFixed(6)}`;
|
|
2118
|
+
if (this.cropShapeHatchPattern && this.cropShapeHatchPatternColor === color && this.cropShapeHatchPatternKey === cacheKey) {
|
|
1818
2119
|
return this.cropShapeHatchPattern;
|
|
1819
2120
|
}
|
|
1820
2121
|
const size = 16;
|
|
@@ -1843,11 +2144,21 @@ var ImageTool = class {
|
|
|
1843
2144
|
// @ts-ignore: Fabric Pattern accepts canvas source here.
|
|
1844
2145
|
repetition: "repeat"
|
|
1845
2146
|
});
|
|
2147
|
+
pattern.patternTransform = [
|
|
2148
|
+
1 / sceneScale,
|
|
2149
|
+
0,
|
|
2150
|
+
0,
|
|
2151
|
+
1 / sceneScale,
|
|
2152
|
+
0,
|
|
2153
|
+
0
|
|
2154
|
+
];
|
|
1846
2155
|
this.cropShapeHatchPattern = pattern;
|
|
1847
2156
|
this.cropShapeHatchPatternColor = color;
|
|
2157
|
+
this.cropShapeHatchPatternKey = cacheKey;
|
|
1848
2158
|
return pattern;
|
|
1849
2159
|
}
|
|
1850
2160
|
buildCropShapeOverlaySpecs(frame, sceneGeometry) {
|
|
2161
|
+
var _a, _b;
|
|
1851
2162
|
if (!sceneGeometry) {
|
|
1852
2163
|
this.debug("overlay:shape:skip", { reason: "scene-geometry-missing" });
|
|
1853
2164
|
return [];
|
|
@@ -1857,6 +2168,7 @@ var ImageTool = class {
|
|
|
1857
2168
|
return [];
|
|
1858
2169
|
}
|
|
1859
2170
|
const shape = sceneGeometry.shape;
|
|
2171
|
+
const shapeStyle = sceneGeometry.shapeStyle;
|
|
1860
2172
|
const inset = 0;
|
|
1861
2173
|
const shapeWidth = Math.max(1, frame.width);
|
|
1862
2174
|
const shapeHeight = Math.max(1, frame.height);
|
|
@@ -1866,6 +2178,7 @@ var ImageTool = class {
|
|
|
1866
2178
|
frameWidth: frame.width,
|
|
1867
2179
|
frameHeight: frame.height,
|
|
1868
2180
|
offset: sceneGeometry.offset,
|
|
2181
|
+
shapeStyle,
|
|
1869
2182
|
inset,
|
|
1870
2183
|
shapeWidth,
|
|
1871
2184
|
shapeHeight,
|
|
@@ -1887,6 +2200,7 @@ var ImageTool = class {
|
|
|
1887
2200
|
x: frame.width / 2,
|
|
1888
2201
|
y: frame.height / 2,
|
|
1889
2202
|
features: [],
|
|
2203
|
+
shapeStyle,
|
|
1890
2204
|
canvasWidth: frame.width,
|
|
1891
2205
|
canvasHeight: frame.height
|
|
1892
2206
|
};
|
|
@@ -1904,6 +2218,9 @@ var ImageTool = class {
|
|
|
1904
2218
|
}
|
|
1905
2219
|
const patternFill = this.getCropShapeHatchPattern();
|
|
1906
2220
|
const hatchFill = patternFill || "rgba(255, 0, 0, 0.22)";
|
|
2221
|
+
const shapeBounds = getPathBounds(shapePathData);
|
|
2222
|
+
const hatchBounds = getPathBounds(hatchPathData);
|
|
2223
|
+
const frameRect = this.toLayoutSceneRect(frame);
|
|
1907
2224
|
const hatchPathLength = hatchPathData.length;
|
|
1908
2225
|
const shapePathLength = shapePathData.length;
|
|
1909
2226
|
const specs = [
|
|
@@ -1911,10 +2228,16 @@ var ImageTool = class {
|
|
|
1911
2228
|
id: "image.cropShapeHatch",
|
|
1912
2229
|
type: "path",
|
|
1913
2230
|
data: { id: "image.cropShapeHatch", zIndex: 5 },
|
|
2231
|
+
layout: {
|
|
2232
|
+
reference: "custom",
|
|
2233
|
+
referenceRect: frameRect,
|
|
2234
|
+
alignX: "start",
|
|
2235
|
+
alignY: "start",
|
|
2236
|
+
offsetX: hatchBounds.x,
|
|
2237
|
+
offsetY: hatchBounds.y
|
|
2238
|
+
},
|
|
1914
2239
|
props: {
|
|
1915
2240
|
pathData: hatchPathData,
|
|
1916
|
-
left: frame.left,
|
|
1917
|
-
top: frame.top,
|
|
1918
2241
|
originX: "left",
|
|
1919
2242
|
originY: "top",
|
|
1920
2243
|
fill: hatchFill,
|
|
@@ -1931,15 +2254,21 @@ var ImageTool = class {
|
|
|
1931
2254
|
id: "image.cropShapePath",
|
|
1932
2255
|
type: "path",
|
|
1933
2256
|
data: { id: "image.cropShapePath", zIndex: 6 },
|
|
2257
|
+
layout: {
|
|
2258
|
+
reference: "custom",
|
|
2259
|
+
referenceRect: frameRect,
|
|
2260
|
+
alignX: "start",
|
|
2261
|
+
alignY: "start",
|
|
2262
|
+
offsetX: shapeBounds.x,
|
|
2263
|
+
offsetY: shapeBounds.y
|
|
2264
|
+
},
|
|
1934
2265
|
props: {
|
|
1935
2266
|
pathData: shapePathData,
|
|
1936
|
-
left: frame.left,
|
|
1937
|
-
top: frame.top,
|
|
1938
2267
|
originX: "left",
|
|
1939
2268
|
originY: "top",
|
|
1940
2269
|
fill: "rgba(0,0,0,0)",
|
|
1941
2270
|
stroke: "rgba(255, 0, 0, 0.9)",
|
|
1942
|
-
strokeWidth: 1,
|
|
2271
|
+
strokeWidth: (_b = (_a = this.canvasService) == null ? void 0 : _a.toSceneLength(1)) != null ? _b : 1,
|
|
1943
2272
|
selectable: false,
|
|
1944
2273
|
evented: false,
|
|
1945
2274
|
excludeFromExport: true,
|
|
@@ -1956,6 +2285,8 @@ var ImageTool = class {
|
|
|
1956
2285
|
fillRule: "evenodd",
|
|
1957
2286
|
shapePathLength,
|
|
1958
2287
|
hatchPathLength,
|
|
2288
|
+
shapeBounds,
|
|
2289
|
+
hatchBounds,
|
|
1959
2290
|
hatchFillType: hatchFill && typeof hatchFill === "object" ? "pattern" : "color",
|
|
1960
2291
|
ids: specs.map((spec) => spec.id)
|
|
1961
2292
|
});
|
|
@@ -2018,6 +2349,28 @@ var ImageTool = class {
|
|
|
2018
2349
|
opacity: render.opacity
|
|
2019
2350
|
};
|
|
2020
2351
|
}
|
|
2352
|
+
toScreenObjectProps(props) {
|
|
2353
|
+
if (!this.canvasService) return props;
|
|
2354
|
+
const next = { ...props };
|
|
2355
|
+
if (Number.isFinite(next.left) || Number.isFinite(next.top)) {
|
|
2356
|
+
const mapped = this.canvasService.toScreenPoint({
|
|
2357
|
+
x: Number.isFinite(next.left) ? Number(next.left) : 0,
|
|
2358
|
+
y: Number.isFinite(next.top) ? Number(next.top) : 0
|
|
2359
|
+
});
|
|
2360
|
+
if (Number.isFinite(next.left)) next.left = mapped.x;
|
|
2361
|
+
if (Number.isFinite(next.top)) next.top = mapped.y;
|
|
2362
|
+
}
|
|
2363
|
+
const sceneScale = this.canvasService.getSceneScale();
|
|
2364
|
+
const sx = Number.isFinite(next.scaleX) ? Number(next.scaleX) : 1;
|
|
2365
|
+
const sy = Number.isFinite(next.scaleY) ? Number(next.scaleY) : 1;
|
|
2366
|
+
next.scaleX = sx * sceneScale;
|
|
2367
|
+
next.scaleY = sy * sceneScale;
|
|
2368
|
+
return next;
|
|
2369
|
+
}
|
|
2370
|
+
toSceneObjectScale(value) {
|
|
2371
|
+
if (!this.canvasService) return value;
|
|
2372
|
+
return value / this.canvasService.getSceneScale();
|
|
2373
|
+
}
|
|
2021
2374
|
getCurrentSrc(obj) {
|
|
2022
2375
|
var _a;
|
|
2023
2376
|
if (!obj) return void 0;
|
|
@@ -2050,7 +2403,7 @@ var ImageTool = class {
|
|
|
2050
2403
|
obj = void 0;
|
|
2051
2404
|
}
|
|
2052
2405
|
if (!obj) {
|
|
2053
|
-
const created = await
|
|
2406
|
+
const created = await FabricImage2.fromURL(render.src, {
|
|
2054
2407
|
crossOrigin: "anonymous"
|
|
2055
2408
|
});
|
|
2056
2409
|
if (seq !== this.renderSeq) return;
|
|
@@ -2067,8 +2420,9 @@ var ImageTool = class {
|
|
|
2067
2420
|
this.rememberSourceSize(render.src, obj);
|
|
2068
2421
|
const sourceSize = this.getSourceSize(render.src, obj);
|
|
2069
2422
|
const props = this.computeCanvasProps(render, sourceSize, frame);
|
|
2423
|
+
const screenProps = this.toScreenObjectProps(props);
|
|
2070
2424
|
obj.set({
|
|
2071
|
-
...
|
|
2425
|
+
...screenProps,
|
|
2072
2426
|
data: {
|
|
2073
2427
|
...obj.data || {},
|
|
2074
2428
|
id: item.id,
|
|
@@ -2134,37 +2488,67 @@ var ImageTool = class {
|
|
|
2134
2488
|
});
|
|
2135
2489
|
return [];
|
|
2136
2490
|
}
|
|
2137
|
-
const
|
|
2138
|
-
const
|
|
2491
|
+
const viewport = this.canvasService.getSceneViewportRect();
|
|
2492
|
+
const canvasW = viewport.width || 0;
|
|
2493
|
+
const canvasH = viewport.height || 0;
|
|
2494
|
+
const canvasLeft = viewport.left || 0;
|
|
2495
|
+
const canvasTop = viewport.top || 0;
|
|
2139
2496
|
const visual = this.getFrameVisualConfig();
|
|
2140
|
-
const
|
|
2141
|
-
|
|
2497
|
+
const strokeWidthScene = this.canvasService.toSceneLength(
|
|
2498
|
+
visual.strokeWidth
|
|
2499
|
+
);
|
|
2500
|
+
const dashLengthScene = this.canvasService.toSceneLength(visual.dashLength);
|
|
2501
|
+
const frameLeft = Math.max(
|
|
2502
|
+
canvasLeft,
|
|
2503
|
+
Math.min(canvasLeft + canvasW, frame.left)
|
|
2504
|
+
);
|
|
2505
|
+
const frameTop = Math.max(
|
|
2506
|
+
canvasTop,
|
|
2507
|
+
Math.min(canvasTop + canvasH, frame.top)
|
|
2508
|
+
);
|
|
2142
2509
|
const frameRight = Math.max(
|
|
2143
2510
|
frameLeft,
|
|
2144
|
-
Math.min(canvasW, frame.left + frame.width)
|
|
2511
|
+
Math.min(canvasLeft + canvasW, frame.left + frame.width)
|
|
2145
2512
|
);
|
|
2146
2513
|
const frameBottom = Math.max(
|
|
2147
2514
|
frameTop,
|
|
2148
|
-
Math.min(canvasH, frame.top + frame.height)
|
|
2515
|
+
Math.min(canvasTop + canvasH, frame.top + frame.height)
|
|
2149
2516
|
);
|
|
2150
2517
|
const visibleFrameH = Math.max(0, frameBottom - frameTop);
|
|
2151
|
-
const topH = frameTop;
|
|
2152
|
-
const bottomH = Math.max(0, canvasH - frameBottom);
|
|
2153
|
-
const leftW = frameLeft;
|
|
2154
|
-
const rightW = Math.max(0, canvasW - frameRight);
|
|
2518
|
+
const topH = Math.max(0, frameTop - canvasTop);
|
|
2519
|
+
const bottomH = Math.max(0, canvasTop + canvasH - frameBottom);
|
|
2520
|
+
const leftW = Math.max(0, frameLeft - canvasLeft);
|
|
2521
|
+
const rightW = Math.max(0, canvasLeft + canvasW - frameRight);
|
|
2522
|
+
const viewportRect = this.toLayoutSceneRect({
|
|
2523
|
+
left: canvasLeft,
|
|
2524
|
+
top: canvasTop,
|
|
2525
|
+
width: canvasW,
|
|
2526
|
+
height: canvasH
|
|
2527
|
+
});
|
|
2528
|
+
const visibleFrameBandRect = this.toLayoutSceneRect({
|
|
2529
|
+
left: canvasLeft,
|
|
2530
|
+
top: frameTop,
|
|
2531
|
+
width: canvasW,
|
|
2532
|
+
height: visibleFrameH
|
|
2533
|
+
});
|
|
2534
|
+
const frameRect = this.toLayoutSceneRect(frame);
|
|
2155
2535
|
const shapeOverlay = this.buildCropShapeOverlaySpecs(frame, sceneGeometry);
|
|
2156
2536
|
const mask = [
|
|
2157
2537
|
{
|
|
2158
2538
|
id: "image.cropMask.top",
|
|
2159
2539
|
type: "rect",
|
|
2160
2540
|
data: { id: "image.cropMask.top", zIndex: 1 },
|
|
2541
|
+
layout: {
|
|
2542
|
+
reference: "custom",
|
|
2543
|
+
referenceRect: viewportRect,
|
|
2544
|
+
alignX: "start",
|
|
2545
|
+
alignY: "start",
|
|
2546
|
+
width: "100%",
|
|
2547
|
+
height: topH
|
|
2548
|
+
},
|
|
2161
2549
|
props: {
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
width: canvasW,
|
|
2165
|
-
height: topH,
|
|
2166
|
-
originX: "center",
|
|
2167
|
-
originY: "center",
|
|
2550
|
+
originX: "left",
|
|
2551
|
+
originY: "top",
|
|
2168
2552
|
fill: visual.outerBackground,
|
|
2169
2553
|
selectable: false,
|
|
2170
2554
|
evented: false
|
|
@@ -2174,13 +2558,17 @@ var ImageTool = class {
|
|
|
2174
2558
|
id: "image.cropMask.bottom",
|
|
2175
2559
|
type: "rect",
|
|
2176
2560
|
data: { id: "image.cropMask.bottom", zIndex: 2 },
|
|
2561
|
+
layout: {
|
|
2562
|
+
reference: "custom",
|
|
2563
|
+
referenceRect: viewportRect,
|
|
2564
|
+
alignX: "start",
|
|
2565
|
+
alignY: "end",
|
|
2566
|
+
width: "100%",
|
|
2567
|
+
height: bottomH
|
|
2568
|
+
},
|
|
2177
2569
|
props: {
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
width: canvasW,
|
|
2181
|
-
height: bottomH,
|
|
2182
|
-
originX: "center",
|
|
2183
|
-
originY: "center",
|
|
2570
|
+
originX: "left",
|
|
2571
|
+
originY: "top",
|
|
2184
2572
|
fill: visual.outerBackground,
|
|
2185
2573
|
selectable: false,
|
|
2186
2574
|
evented: false
|
|
@@ -2190,13 +2578,17 @@ var ImageTool = class {
|
|
|
2190
2578
|
id: "image.cropMask.left",
|
|
2191
2579
|
type: "rect",
|
|
2192
2580
|
data: { id: "image.cropMask.left", zIndex: 3 },
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
|
|
2581
|
+
layout: {
|
|
2582
|
+
reference: "custom",
|
|
2583
|
+
referenceRect: visibleFrameBandRect,
|
|
2584
|
+
alignX: "start",
|
|
2585
|
+
alignY: "start",
|
|
2196
2586
|
width: leftW,
|
|
2197
|
-
height:
|
|
2198
|
-
|
|
2199
|
-
|
|
2587
|
+
height: "100%"
|
|
2588
|
+
},
|
|
2589
|
+
props: {
|
|
2590
|
+
originX: "left",
|
|
2591
|
+
originY: "top",
|
|
2200
2592
|
fill: visual.outerBackground,
|
|
2201
2593
|
selectable: false,
|
|
2202
2594
|
evented: false
|
|
@@ -2206,13 +2598,17 @@ var ImageTool = class {
|
|
|
2206
2598
|
id: "image.cropMask.right",
|
|
2207
2599
|
type: "rect",
|
|
2208
2600
|
data: { id: "image.cropMask.right", zIndex: 4 },
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2601
|
+
layout: {
|
|
2602
|
+
reference: "custom",
|
|
2603
|
+
referenceRect: visibleFrameBandRect,
|
|
2604
|
+
alignX: "end",
|
|
2605
|
+
alignY: "start",
|
|
2212
2606
|
width: rightW,
|
|
2213
|
-
height:
|
|
2214
|
-
|
|
2215
|
-
|
|
2607
|
+
height: "100%"
|
|
2608
|
+
},
|
|
2609
|
+
props: {
|
|
2610
|
+
originX: "left",
|
|
2611
|
+
originY: "top",
|
|
2216
2612
|
fill: visual.outerBackground,
|
|
2217
2613
|
selectable: false,
|
|
2218
2614
|
evented: false
|
|
@@ -2223,17 +2619,21 @@ var ImageTool = class {
|
|
|
2223
2619
|
id: "image.cropFrame",
|
|
2224
2620
|
type: "rect",
|
|
2225
2621
|
data: { id: "image.cropFrame", zIndex: 7 },
|
|
2622
|
+
layout: {
|
|
2623
|
+
reference: "custom",
|
|
2624
|
+
referenceRect: frameRect,
|
|
2625
|
+
alignX: "start",
|
|
2626
|
+
alignY: "start",
|
|
2627
|
+
width: "100%",
|
|
2628
|
+
height: "100%"
|
|
2629
|
+
},
|
|
2226
2630
|
props: {
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
width: frame.width,
|
|
2230
|
-
height: frame.height,
|
|
2231
|
-
originX: "center",
|
|
2232
|
-
originY: "center",
|
|
2631
|
+
originX: "left",
|
|
2632
|
+
originY: "top",
|
|
2233
2633
|
fill: visual.innerBackground,
|
|
2234
2634
|
stroke: visual.strokeStyle === "hidden" ? "rgba(0,0,0,0)" : visual.strokeColor,
|
|
2235
|
-
strokeWidth: visual.strokeStyle === "hidden" ? 0 :
|
|
2236
|
-
strokeDashArray: visual.strokeStyle === "dashed" ? [
|
|
2635
|
+
strokeWidth: visual.strokeStyle === "hidden" ? 0 : strokeWidthScene,
|
|
2636
|
+
strokeDashArray: visual.strokeStyle === "dashed" ? [dashLengthScene, dashLengthScene] : void 0,
|
|
2237
2637
|
selectable: false,
|
|
2238
2638
|
evented: false
|
|
2239
2639
|
}
|
|
@@ -2284,10 +2684,8 @@ var ImageTool = class {
|
|
|
2284
2684
|
const sceneGeometry = await this.resolveSceneGeometryForOverlay();
|
|
2285
2685
|
if (seq !== this.renderSeq) return;
|
|
2286
2686
|
const overlaySpecs = this.buildOverlaySpecs(frame, sceneGeometry);
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
overlaySpecs
|
|
2290
|
-
);
|
|
2687
|
+
this.overlaySpecs = overlaySpecs;
|
|
2688
|
+
await this.canvasService.flushRenderFromProducers();
|
|
2291
2689
|
this.syncImageZOrder(renderItems);
|
|
2292
2690
|
const overlayCanvasCount = this.getOverlayObjects().length;
|
|
2293
2691
|
this.debug("render:done", {
|
|
@@ -2378,7 +2776,7 @@ var ImageTool = class {
|
|
|
2378
2776
|
const source = this.getSourceSize(render.src, obj);
|
|
2379
2777
|
const frame = this.getFrameRect();
|
|
2380
2778
|
const coverScale = this.getCoverScale(frame, source);
|
|
2381
|
-
const currentScale = obj.scaleX || 1;
|
|
2779
|
+
const currentScale = this.toSceneObjectScale(obj.scaleX || 1);
|
|
2382
2780
|
const zoom = Math.max(0.05, currentScale / coverScale);
|
|
2383
2781
|
const updated = {
|
|
2384
2782
|
scale: Number.isFinite(zoom) ? zoom : 1,
|
|
@@ -2415,12 +2813,13 @@ var ImageTool = class {
|
|
|
2415
2813
|
Math.max(1, area.width) / Math.max(1, source.width),
|
|
2416
2814
|
Math.max(1, area.height) / Math.max(1, source.height)
|
|
2417
2815
|
);
|
|
2418
|
-
const
|
|
2419
|
-
const
|
|
2816
|
+
const viewport = this.canvasService.getSceneViewportRect();
|
|
2817
|
+
const canvasW = viewport.width || 1;
|
|
2818
|
+
const canvasH = viewport.height || 1;
|
|
2420
2819
|
const areaLeftInput = (_a = area.left) != null ? _a : 0.5;
|
|
2421
2820
|
const areaTopInput = (_b = area.top) != null ? _b : 0.5;
|
|
2422
|
-
const areaLeftPx = areaLeftInput <= 1.5 ? areaLeftInput * canvasW : areaLeftInput;
|
|
2423
|
-
const areaTopPx = areaTopInput <= 1.5 ? areaTopInput * canvasH : areaTopInput;
|
|
2821
|
+
const areaLeftPx = areaLeftInput <= 1.5 ? viewport.left + areaLeftInput * canvasW : areaLeftInput;
|
|
2822
|
+
const areaTopPx = areaTopInput <= 1.5 ? viewport.top + areaTopInput * canvasH : areaTopInput;
|
|
2424
2823
|
const updates = {
|
|
2425
2824
|
scale: Math.max(0.05, desiredScale / baseCover),
|
|
2426
2825
|
left: this.clampNormalized(
|
|
@@ -2458,6 +2857,8 @@ var ImageTool = class {
|
|
|
2458
2857
|
this.normalizeItem({
|
|
2459
2858
|
...item,
|
|
2460
2859
|
url,
|
|
2860
|
+
// Keep original source for next image-tool session editing,
|
|
2861
|
+
// and use committedUrl as non-image-tools render source.
|
|
2461
2862
|
sourceUrl,
|
|
2462
2863
|
committedUrl: url
|
|
2463
2864
|
})
|
|
@@ -2483,7 +2884,8 @@ var ImageTool = class {
|
|
|
2483
2884
|
if (!normalizedIds.length) {
|
|
2484
2885
|
throw new Error("image-ids-required");
|
|
2485
2886
|
}
|
|
2486
|
-
const
|
|
2887
|
+
const frameScene = this.getFrameRect();
|
|
2888
|
+
const frame = this.getFrameRectScreen(frameScene);
|
|
2487
2889
|
const multiplier = Math.max(1, (_a = options.multiplier) != null ? _a : 2);
|
|
2488
2890
|
const format = options.format === "jpeg" ? "jpeg" : "png";
|
|
2489
2891
|
const width = Math.max(1, Math.round(frame.width * multiplier));
|
|
@@ -3365,14 +3767,10 @@ var ImageTracer = class {
|
|
|
3365
3767
|
};
|
|
3366
3768
|
}
|
|
3367
3769
|
const baseUnpaddedContours = baseContours.map(
|
|
3368
|
-
(contour) =>
|
|
3369
|
-
|
|
3370
|
-
|
|
3371
|
-
|
|
3372
|
-
})),
|
|
3373
|
-
width,
|
|
3374
|
-
height
|
|
3375
|
-
)
|
|
3770
|
+
(contour) => contour.map((p) => ({
|
|
3771
|
+
x: p.x - padding,
|
|
3772
|
+
y: p.y - padding
|
|
3773
|
+
}))
|
|
3376
3774
|
).filter((contour) => contour.length > 2);
|
|
3377
3775
|
if (!baseUnpaddedContours.length) {
|
|
3378
3776
|
const w = (_h = options.scaleToWidth) != null ? _h : width;
|
|
@@ -3461,13 +3859,46 @@ var ImageTracer = class {
|
|
|
3461
3859
|
this.flattenContours(baseScaledContours)
|
|
3462
3860
|
);
|
|
3463
3861
|
}
|
|
3464
|
-
|
|
3465
|
-
|
|
3466
|
-
|
|
3467
|
-
|
|
3468
|
-
|
|
3469
|
-
|
|
3470
|
-
|
|
3862
|
+
if (expand > 0) {
|
|
3863
|
+
const expectedExpandedBounds = {
|
|
3864
|
+
x: baseBounds.x - expand,
|
|
3865
|
+
y: baseBounds.y - expand,
|
|
3866
|
+
width: baseBounds.width + expand * 2,
|
|
3867
|
+
height: baseBounds.height + expand * 2
|
|
3868
|
+
};
|
|
3869
|
+
if (expectedExpandedBounds.width > 0 && expectedExpandedBounds.height > 0 && globalBounds.width > 0 && globalBounds.height > 0) {
|
|
3870
|
+
const shouldNormalizeExpandBounds = Math.abs(globalBounds.x - expectedExpandedBounds.x) > 1 || Math.abs(globalBounds.y - expectedExpandedBounds.y) > 1 || Math.abs(globalBounds.width - expectedExpandedBounds.width) > 1 || Math.abs(globalBounds.height - expectedExpandedBounds.height) > 1;
|
|
3871
|
+
if (shouldNormalizeExpandBounds) {
|
|
3872
|
+
const beforeNormalize = globalBounds;
|
|
3873
|
+
finalContours = this.translateContours(
|
|
3874
|
+
this.scaleContours(
|
|
3875
|
+
finalContours,
|
|
3876
|
+
expectedExpandedBounds.width,
|
|
3877
|
+
expectedExpandedBounds.height,
|
|
3878
|
+
globalBounds
|
|
3879
|
+
),
|
|
3880
|
+
expectedExpandedBounds.x,
|
|
3881
|
+
expectedExpandedBounds.y
|
|
3882
|
+
);
|
|
3883
|
+
globalBounds = this.boundsFromPoints(
|
|
3884
|
+
this.flattenContours(finalContours)
|
|
3885
|
+
);
|
|
3886
|
+
debugLog("traceWithBounds:expand-normalized", {
|
|
3887
|
+
expand,
|
|
3888
|
+
expectedExpandedBounds,
|
|
3889
|
+
beforeNormalize,
|
|
3890
|
+
afterNormalize: globalBounds
|
|
3891
|
+
});
|
|
3892
|
+
}
|
|
3893
|
+
}
|
|
3894
|
+
}
|
|
3895
|
+
debugLog("traceWithBounds:contours", {
|
|
3896
|
+
baseContourCount: baseContoursRaw.length,
|
|
3897
|
+
baseSelectedCount: baseContours.length,
|
|
3898
|
+
expandedContourCount: expandedContoursRaw.length,
|
|
3899
|
+
expandedSelectedCount: expandedContours.length,
|
|
3900
|
+
baseBounds,
|
|
3901
|
+
expandedBounds: globalBounds,
|
|
3471
3902
|
expandedDeltaX: globalBounds.width - baseBounds.width,
|
|
3472
3903
|
expandedDeltaY: globalBounds.height - baseBounds.height,
|
|
3473
3904
|
expandedMayOverflowImageBounds: expand > 0,
|
|
@@ -3823,13 +4254,13 @@ var ImageTracer = class {
|
|
|
3823
4254
|
(points) => this.scalePoints(points, targetWidth, targetHeight, bounds)
|
|
3824
4255
|
);
|
|
3825
4256
|
}
|
|
3826
|
-
static
|
|
3827
|
-
|
|
3828
|
-
|
|
3829
|
-
|
|
3830
|
-
|
|
3831
|
-
|
|
3832
|
-
|
|
4257
|
+
static translateContours(contours, offsetX, offsetY) {
|
|
4258
|
+
return contours.map(
|
|
4259
|
+
(points) => points.map((p) => ({
|
|
4260
|
+
x: p.x + offsetX,
|
|
4261
|
+
y: p.y + offsetY
|
|
4262
|
+
}))
|
|
4263
|
+
);
|
|
3833
4264
|
}
|
|
3834
4265
|
static pointsToSVG(points) {
|
|
3835
4266
|
if (points.length === 0) return "";
|
|
@@ -3882,6 +4313,7 @@ var ImageTracer = class {
|
|
|
3882
4313
|
|
|
3883
4314
|
// src/extensions/dieline.ts
|
|
3884
4315
|
var IMAGE_OBJECT_LAYER_ID2 = "image.user";
|
|
4316
|
+
var DIELINE_LAYER_ID = "dieline-overlay";
|
|
3885
4317
|
var DielineTool = class {
|
|
3886
4318
|
constructor(options) {
|
|
3887
4319
|
this.id = "pooder.kit.dieline";
|
|
@@ -3889,8 +4321,8 @@ var DielineTool = class {
|
|
|
3889
4321
|
name: "DielineTool"
|
|
3890
4322
|
};
|
|
3891
4323
|
this.state = {
|
|
3892
|
-
|
|
3893
|
-
|
|
4324
|
+
shape: DEFAULT_DIELINE_SHAPE,
|
|
4325
|
+
shapeStyle: { ...DEFAULT_DIELINE_SHAPE_STYLE },
|
|
3894
4326
|
width: 500,
|
|
3895
4327
|
height: 500,
|
|
3896
4328
|
radius: 0,
|
|
@@ -3913,6 +4345,8 @@ var DielineTool = class {
|
|
|
3913
4345
|
showBleedLines: true,
|
|
3914
4346
|
features: []
|
|
3915
4347
|
};
|
|
4348
|
+
this.specs = [];
|
|
4349
|
+
this.renderSeq = 0;
|
|
3916
4350
|
this.onCanvasResized = () => {
|
|
3917
4351
|
this.updateDieline();
|
|
3918
4352
|
};
|
|
@@ -3925,24 +4359,50 @@ var DielineTool = class {
|
|
|
3925
4359
|
Object.assign(this.state.offsetLine, options.offsetLine);
|
|
3926
4360
|
delete options.offsetLine;
|
|
3927
4361
|
}
|
|
4362
|
+
if (options.shapeStyle) {
|
|
4363
|
+
this.state.shapeStyle = normalizeShapeStyle(
|
|
4364
|
+
options.shapeStyle,
|
|
4365
|
+
this.state.shapeStyle
|
|
4366
|
+
);
|
|
4367
|
+
delete options.shapeStyle;
|
|
4368
|
+
}
|
|
3928
4369
|
Object.assign(this.state, options);
|
|
4370
|
+
this.state.shape = normalizeDielineShape(options.shape, this.state.shape);
|
|
3929
4371
|
}
|
|
3930
4372
|
}
|
|
3931
4373
|
activate(context) {
|
|
4374
|
+
var _a;
|
|
3932
4375
|
this.context = context;
|
|
3933
4376
|
this.canvasService = context.services.get("CanvasService");
|
|
3934
4377
|
if (!this.canvasService) {
|
|
3935
4378
|
console.warn("CanvasService not found for DielineTool");
|
|
3936
4379
|
return;
|
|
3937
4380
|
}
|
|
4381
|
+
(_a = this.renderProducerDisposable) == null ? void 0 : _a.dispose();
|
|
4382
|
+
this.renderProducerDisposable = this.canvasService.registerRenderProducer(
|
|
4383
|
+
this.id,
|
|
4384
|
+
() => ({
|
|
4385
|
+
layerSpecs: {
|
|
4386
|
+
[DIELINE_LAYER_ID]: this.specs
|
|
4387
|
+
},
|
|
4388
|
+
replaceLayerIds: [DIELINE_LAYER_ID]
|
|
4389
|
+
}),
|
|
4390
|
+
{ priority: 250 }
|
|
4391
|
+
);
|
|
3938
4392
|
const configService = context.services.get(
|
|
3939
4393
|
"ConfigurationService"
|
|
3940
4394
|
);
|
|
3941
4395
|
if (configService) {
|
|
3942
4396
|
const s = this.state;
|
|
3943
4397
|
const sizeState = readSizeState(configService);
|
|
3944
|
-
s.
|
|
3945
|
-
|
|
4398
|
+
s.shape = normalizeDielineShape(
|
|
4399
|
+
configService.get("dieline.shape", s.shape),
|
|
4400
|
+
s.shape
|
|
4401
|
+
);
|
|
4402
|
+
s.shapeStyle = normalizeShapeStyle(
|
|
4403
|
+
configService.get("dieline.shapeStyle", s.shapeStyle),
|
|
4404
|
+
s.shapeStyle
|
|
4405
|
+
);
|
|
3946
4406
|
s.width = sizeState.actualWidthMm;
|
|
3947
4407
|
s.height = sizeState.actualHeightMm;
|
|
3948
4408
|
s.radius = parseLengthToMm(
|
|
@@ -3991,10 +4451,17 @@ var DielineTool = class {
|
|
|
3991
4451
|
);
|
|
3992
4452
|
s.features = configService.get("dieline.features", s.features);
|
|
3993
4453
|
s.pathData = configService.get("dieline.pathData", s.pathData);
|
|
4454
|
+
const sourceWidth = Number(
|
|
4455
|
+
configService.get("dieline.customSourceWidthPx", 0)
|
|
4456
|
+
);
|
|
4457
|
+
const sourceHeight = Number(
|
|
4458
|
+
configService.get("dieline.customSourceHeightPx", 0)
|
|
4459
|
+
);
|
|
4460
|
+
s.customSourceWidthPx = Number.isFinite(sourceWidth) && sourceWidth > 0 ? sourceWidth : void 0;
|
|
4461
|
+
s.customSourceHeightPx = Number.isFinite(sourceHeight) && sourceHeight > 0 ? sourceHeight : void 0;
|
|
3994
4462
|
configService.onAnyChange((e) => {
|
|
3995
4463
|
if (e.key.startsWith("size.")) {
|
|
3996
4464
|
const nextSize = readSizeState(configService);
|
|
3997
|
-
s.displayUnit = nextSize.unit;
|
|
3998
4465
|
s.width = nextSize.actualWidthMm;
|
|
3999
4466
|
s.height = nextSize.actualHeightMm;
|
|
4000
4467
|
s.padding = nextSize.viewPadding;
|
|
@@ -4005,7 +4472,10 @@ var DielineTool = class {
|
|
|
4005
4472
|
if (e.key.startsWith("dieline.")) {
|
|
4006
4473
|
switch (e.key) {
|
|
4007
4474
|
case "dieline.shape":
|
|
4008
|
-
s.shape = e.value;
|
|
4475
|
+
s.shape = normalizeDielineShape(e.value, s.shape);
|
|
4476
|
+
break;
|
|
4477
|
+
case "dieline.shapeStyle":
|
|
4478
|
+
s.shapeStyle = normalizeShapeStyle(e.value, s.shapeStyle);
|
|
4009
4479
|
break;
|
|
4010
4480
|
case "dieline.radius":
|
|
4011
4481
|
s.radius = parseLengthToMm(e.value, "mm");
|
|
@@ -4049,18 +4519,30 @@ var DielineTool = class {
|
|
|
4049
4519
|
case "dieline.pathData":
|
|
4050
4520
|
s.pathData = e.value;
|
|
4051
4521
|
break;
|
|
4522
|
+
case "dieline.customSourceWidthPx":
|
|
4523
|
+
s.customSourceWidthPx = Number.isFinite(Number(e.value)) && Number(e.value) > 0 ? Number(e.value) : void 0;
|
|
4524
|
+
break;
|
|
4525
|
+
case "dieline.customSourceHeightPx":
|
|
4526
|
+
s.customSourceHeightPx = Number.isFinite(Number(e.value)) && Number(e.value) > 0 ? Number(e.value) : void 0;
|
|
4527
|
+
break;
|
|
4052
4528
|
}
|
|
4053
4529
|
this.updateDieline();
|
|
4054
4530
|
}
|
|
4055
4531
|
});
|
|
4056
4532
|
}
|
|
4057
4533
|
context.eventBus.on("canvas:resized", this.onCanvasResized);
|
|
4058
|
-
this.createLayer();
|
|
4059
4534
|
this.updateDieline();
|
|
4060
4535
|
}
|
|
4061
4536
|
deactivate(context) {
|
|
4537
|
+
var _a;
|
|
4062
4538
|
context.eventBus.off("canvas:resized", this.onCanvasResized);
|
|
4063
|
-
this.
|
|
4539
|
+
this.renderSeq += 1;
|
|
4540
|
+
this.specs = [];
|
|
4541
|
+
(_a = this.renderProducerDisposable) == null ? void 0 : _a.dispose();
|
|
4542
|
+
this.renderProducerDisposable = void 0;
|
|
4543
|
+
if (this.canvasService) {
|
|
4544
|
+
void this.canvasService.flushRenderFromProducers();
|
|
4545
|
+
}
|
|
4064
4546
|
this.canvasService = void 0;
|
|
4065
4547
|
this.context = void 0;
|
|
4066
4548
|
}
|
|
@@ -4083,7 +4565,7 @@ var DielineTool = class {
|
|
|
4083
4565
|
id: "dieline.shape",
|
|
4084
4566
|
type: "select",
|
|
4085
4567
|
label: "Shape",
|
|
4086
|
-
options:
|
|
4568
|
+
options: Array.from(DIELINE_SHAPES),
|
|
4087
4569
|
default: s.shape
|
|
4088
4570
|
},
|
|
4089
4571
|
{
|
|
@@ -4094,6 +4576,12 @@ var DielineTool = class {
|
|
|
4094
4576
|
max: 500,
|
|
4095
4577
|
default: s.radius
|
|
4096
4578
|
},
|
|
4579
|
+
{
|
|
4580
|
+
id: "dieline.shapeStyle",
|
|
4581
|
+
type: "json",
|
|
4582
|
+
label: "Shape Style",
|
|
4583
|
+
default: s.shapeStyle
|
|
4584
|
+
},
|
|
4097
4585
|
{
|
|
4098
4586
|
id: "dieline.showBleedLines",
|
|
4099
4587
|
type: "boolean",
|
|
@@ -4269,34 +4757,6 @@ var DielineTool = class {
|
|
|
4269
4757
|
]
|
|
4270
4758
|
};
|
|
4271
4759
|
}
|
|
4272
|
-
getLayer() {
|
|
4273
|
-
var _a;
|
|
4274
|
-
return (_a = this.canvasService) == null ? void 0 : _a.getLayer("dieline-overlay");
|
|
4275
|
-
}
|
|
4276
|
-
createLayer() {
|
|
4277
|
-
if (!this.canvasService) return;
|
|
4278
|
-
const width = this.canvasService.canvas.width || 800;
|
|
4279
|
-
const height = this.canvasService.canvas.height || 600;
|
|
4280
|
-
const layer = this.canvasService.createLayer("dieline-overlay", {
|
|
4281
|
-
width,
|
|
4282
|
-
height,
|
|
4283
|
-
selectable: false,
|
|
4284
|
-
evented: false
|
|
4285
|
-
});
|
|
4286
|
-
this.canvasService.canvas.bringObjectToFront(layer);
|
|
4287
|
-
const userLayer = this.canvasService.getLayer("user");
|
|
4288
|
-
if (userLayer) {
|
|
4289
|
-
const userIndex = this.canvasService.canvas.getObjects().indexOf(userLayer);
|
|
4290
|
-
this.canvasService.canvas.moveObjectTo(layer, userIndex + 1);
|
|
4291
|
-
}
|
|
4292
|
-
}
|
|
4293
|
-
destroyLayer() {
|
|
4294
|
-
if (!this.canvasService) return;
|
|
4295
|
-
const layer = this.getLayer();
|
|
4296
|
-
if (layer) {
|
|
4297
|
-
this.canvasService.canvas.remove(layer);
|
|
4298
|
-
}
|
|
4299
|
-
}
|
|
4300
4760
|
createHatchPattern(color = "rgba(0, 0, 0, 0.3)") {
|
|
4301
4761
|
if (typeof document === "undefined") {
|
|
4302
4762
|
return void 0;
|
|
@@ -4325,7 +4785,6 @@ var DielineTool = class {
|
|
|
4325
4785
|
}
|
|
4326
4786
|
syncSizeState(configService) {
|
|
4327
4787
|
const sizeState = readSizeState(configService);
|
|
4328
|
-
this.state.displayUnit = sizeState.unit;
|
|
4329
4788
|
this.state.width = sizeState.actualWidthMm;
|
|
4330
4789
|
this.state.height = sizeState.actualHeightMm;
|
|
4331
4790
|
this.state.padding = sizeState.viewPadding;
|
|
@@ -4339,20 +4798,26 @@ var DielineTool = class {
|
|
|
4339
4798
|
return ((_a = obj == null ? void 0 : obj.data) == null ? void 0 : _a.type) === "feature-marker";
|
|
4340
4799
|
}).forEach((obj) => canvas.bringObjectToFront(obj));
|
|
4341
4800
|
}
|
|
4342
|
-
|
|
4801
|
+
ensureLayerStacking() {
|
|
4343
4802
|
if (!this.canvasService) return;
|
|
4344
|
-
const layer = this.getLayer();
|
|
4803
|
+
const layer = this.canvasService.getLayer(DIELINE_LAYER_ID);
|
|
4345
4804
|
if (!layer) return;
|
|
4346
|
-
const
|
|
4347
|
-
if (
|
|
4348
|
-
|
|
4349
|
-
|
|
4350
|
-
|
|
4351
|
-
|
|
4352
|
-
|
|
4353
|
-
|
|
4805
|
+
const userLayer = this.canvasService.getLayer("user");
|
|
4806
|
+
if (userLayer) {
|
|
4807
|
+
const layerIndex = this.canvasService.canvas.getObjects().indexOf(layer);
|
|
4808
|
+
const userIndex = this.canvasService.canvas.getObjects().indexOf(userLayer);
|
|
4809
|
+
if (layerIndex < userIndex) {
|
|
4810
|
+
this.canvasService.canvas.moveObjectTo(layer, userIndex + 1);
|
|
4811
|
+
}
|
|
4812
|
+
return;
|
|
4813
|
+
}
|
|
4814
|
+
this.canvasService.canvas.bringObjectToFront(layer);
|
|
4815
|
+
}
|
|
4816
|
+
buildDielineSpecs(sceneLayout) {
|
|
4817
|
+
var _a, _b;
|
|
4354
4818
|
const {
|
|
4355
4819
|
shape,
|
|
4820
|
+
shapeStyle,
|
|
4356
4821
|
radius,
|
|
4357
4822
|
mainLine,
|
|
4358
4823
|
offsetLine,
|
|
@@ -4361,8 +4826,8 @@ var DielineTool = class {
|
|
|
4361
4826
|
showBleedLines,
|
|
4362
4827
|
features
|
|
4363
4828
|
} = this.state;
|
|
4364
|
-
const canvasW = sceneLayout.canvasWidth || this.canvasService.canvas.width || 800;
|
|
4365
|
-
const canvasH = sceneLayout.canvasHeight || this.canvasService.canvas.height || 600;
|
|
4829
|
+
const canvasW = sceneLayout.canvasWidth || ((_a = this.canvasService) == null ? void 0 : _a.canvas.width) || 800;
|
|
4830
|
+
const canvasH = sceneLayout.canvasHeight || ((_b = this.canvasService) == null ? void 0 : _b.canvas.height) || 600;
|
|
4366
4831
|
const scale = sceneLayout.scale;
|
|
4367
4832
|
const cx = sceneLayout.trimRect.centerX;
|
|
4368
4833
|
const cy = sceneLayout.trimRect.centerY;
|
|
@@ -4373,7 +4838,6 @@ var DielineTool = class {
|
|
|
4373
4838
|
const cutH = sceneLayout.cutRect.height;
|
|
4374
4839
|
const visualOffset = (cutW - visualWidth) / 2;
|
|
4375
4840
|
const cutR = visualRadius === 0 ? 0 : Math.max(0, visualRadius + visualOffset);
|
|
4376
|
-
layer.remove(...layer.getObjects());
|
|
4377
4841
|
const absoluteFeatures = (features || []).map((f) => ({
|
|
4378
4842
|
...f,
|
|
4379
4843
|
x: f.x,
|
|
@@ -4393,19 +4857,30 @@ var DielineTool = class {
|
|
|
4393
4857
|
x: cx,
|
|
4394
4858
|
y: cy,
|
|
4395
4859
|
features: cutFeatures,
|
|
4396
|
-
|
|
4397
|
-
|
|
4398
|
-
|
|
4399
|
-
|
|
4400
|
-
stroke: null,
|
|
4401
|
-
selectable: false,
|
|
4402
|
-
evented: false,
|
|
4403
|
-
originX: "left",
|
|
4404
|
-
originY: "top",
|
|
4405
|
-
left: 0,
|
|
4406
|
-
top: 0
|
|
4860
|
+
shapeStyle,
|
|
4861
|
+
pathData: this.state.pathData,
|
|
4862
|
+
customSourceWidthPx: this.state.customSourceWidthPx,
|
|
4863
|
+
customSourceHeightPx: this.state.customSourceHeightPx
|
|
4407
4864
|
});
|
|
4408
|
-
|
|
4865
|
+
const specs = [
|
|
4866
|
+
{
|
|
4867
|
+
id: "dieline.mask",
|
|
4868
|
+
type: "path",
|
|
4869
|
+
space: "screen",
|
|
4870
|
+
data: { id: "dieline.mask", type: "dieline" },
|
|
4871
|
+
props: {
|
|
4872
|
+
pathData: maskPathData,
|
|
4873
|
+
fill: outsideColor,
|
|
4874
|
+
stroke: null,
|
|
4875
|
+
selectable: false,
|
|
4876
|
+
evented: false,
|
|
4877
|
+
originX: "left",
|
|
4878
|
+
originY: "top",
|
|
4879
|
+
left: 0,
|
|
4880
|
+
top: 0
|
|
4881
|
+
}
|
|
4882
|
+
}
|
|
4883
|
+
];
|
|
4409
4884
|
if (insideColor && insideColor !== "transparent" && insideColor !== "rgba(0,0,0,0)") {
|
|
4410
4885
|
const productPathData = generateDielinePath({
|
|
4411
4886
|
shape,
|
|
@@ -4415,19 +4890,28 @@ var DielineTool = class {
|
|
|
4415
4890
|
x: cx,
|
|
4416
4891
|
y: cy,
|
|
4417
4892
|
features: cutFeatures,
|
|
4893
|
+
shapeStyle,
|
|
4418
4894
|
pathData: this.state.pathData,
|
|
4895
|
+
customSourceWidthPx: this.state.customSourceWidthPx,
|
|
4896
|
+
customSourceHeightPx: this.state.customSourceHeightPx,
|
|
4419
4897
|
canvasWidth: canvasW,
|
|
4420
4898
|
canvasHeight: canvasH
|
|
4421
4899
|
});
|
|
4422
|
-
|
|
4423
|
-
|
|
4424
|
-
|
|
4425
|
-
|
|
4426
|
-
|
|
4427
|
-
|
|
4428
|
-
|
|
4900
|
+
specs.push({
|
|
4901
|
+
id: "dieline.inside",
|
|
4902
|
+
type: "path",
|
|
4903
|
+
space: "screen",
|
|
4904
|
+
data: { id: "dieline.inside", type: "dieline" },
|
|
4905
|
+
props: {
|
|
4906
|
+
pathData: productPathData,
|
|
4907
|
+
fill: insideColor,
|
|
4908
|
+
stroke: null,
|
|
4909
|
+
selectable: false,
|
|
4910
|
+
evented: false,
|
|
4911
|
+
originX: "left",
|
|
4912
|
+
originY: "top"
|
|
4913
|
+
}
|
|
4429
4914
|
});
|
|
4430
|
-
layer.add(insideObj);
|
|
4431
4915
|
}
|
|
4432
4916
|
if (Math.abs(visualOffset) > 1e-4) {
|
|
4433
4917
|
const bleedPathData = generateBleedZonePath(
|
|
@@ -4439,7 +4923,10 @@ var DielineTool = class {
|
|
|
4439
4923
|
x: cx,
|
|
4440
4924
|
y: cy,
|
|
4441
4925
|
features: cutFeatures,
|
|
4926
|
+
shapeStyle,
|
|
4442
4927
|
pathData: this.state.pathData,
|
|
4928
|
+
customSourceWidthPx: this.state.customSourceWidthPx,
|
|
4929
|
+
customSourceHeightPx: this.state.customSourceHeightPx,
|
|
4443
4930
|
canvasWidth: canvasW,
|
|
4444
4931
|
canvasHeight: canvasH
|
|
4445
4932
|
},
|
|
@@ -4451,7 +4938,10 @@ var DielineTool = class {
|
|
|
4451
4938
|
x: cx,
|
|
4452
4939
|
y: cy,
|
|
4453
4940
|
features: cutFeatures,
|
|
4941
|
+
shapeStyle,
|
|
4454
4942
|
pathData: this.state.pathData,
|
|
4943
|
+
customSourceWidthPx: this.state.customSourceWidthPx,
|
|
4944
|
+
customSourceHeightPx: this.state.customSourceHeightPx,
|
|
4455
4945
|
canvasWidth: canvasW,
|
|
4456
4946
|
canvasHeight: canvasH
|
|
4457
4947
|
},
|
|
@@ -4460,16 +4950,22 @@ var DielineTool = class {
|
|
|
4460
4950
|
if (showBleedLines !== false) {
|
|
4461
4951
|
const pattern = this.createHatchPattern(mainLine.color);
|
|
4462
4952
|
if (pattern) {
|
|
4463
|
-
|
|
4464
|
-
|
|
4465
|
-
|
|
4466
|
-
|
|
4467
|
-
|
|
4468
|
-
|
|
4469
|
-
|
|
4470
|
-
|
|
4953
|
+
specs.push({
|
|
4954
|
+
id: "dieline.bleed-zone",
|
|
4955
|
+
type: "path",
|
|
4956
|
+
space: "screen",
|
|
4957
|
+
data: { id: "dieline.bleed-zone", type: "dieline" },
|
|
4958
|
+
props: {
|
|
4959
|
+
pathData: bleedPathData,
|
|
4960
|
+
fill: pattern,
|
|
4961
|
+
stroke: null,
|
|
4962
|
+
selectable: false,
|
|
4963
|
+
evented: false,
|
|
4964
|
+
objectCaching: false,
|
|
4965
|
+
originX: "left",
|
|
4966
|
+
originY: "top"
|
|
4967
|
+
}
|
|
4471
4968
|
});
|
|
4472
|
-
layer.add(bleedObj);
|
|
4473
4969
|
}
|
|
4474
4970
|
}
|
|
4475
4971
|
const offsetPathData = generateDielinePath({
|
|
@@ -4480,21 +4976,30 @@ var DielineTool = class {
|
|
|
4480
4976
|
x: cx,
|
|
4481
4977
|
y: cy,
|
|
4482
4978
|
features: cutFeatures,
|
|
4979
|
+
shapeStyle,
|
|
4483
4980
|
pathData: this.state.pathData,
|
|
4981
|
+
customSourceWidthPx: this.state.customSourceWidthPx,
|
|
4982
|
+
customSourceHeightPx: this.state.customSourceHeightPx,
|
|
4484
4983
|
canvasWidth: canvasW,
|
|
4485
4984
|
canvasHeight: canvasH
|
|
4486
4985
|
});
|
|
4487
|
-
|
|
4488
|
-
|
|
4489
|
-
|
|
4490
|
-
|
|
4491
|
-
|
|
4492
|
-
|
|
4493
|
-
|
|
4494
|
-
|
|
4495
|
-
|
|
4986
|
+
specs.push({
|
|
4987
|
+
id: "dieline.offset-border",
|
|
4988
|
+
type: "path",
|
|
4989
|
+
space: "screen",
|
|
4990
|
+
data: { id: "dieline.offset-border", type: "dieline" },
|
|
4991
|
+
props: {
|
|
4992
|
+
pathData: offsetPathData,
|
|
4993
|
+
fill: null,
|
|
4994
|
+
stroke: offsetLine.style === "hidden" ? null : offsetLine.color,
|
|
4995
|
+
strokeWidth: offsetLine.width,
|
|
4996
|
+
strokeDashArray: offsetLine.style === "dashed" ? [offsetLine.dashLength, offsetLine.dashLength] : void 0,
|
|
4997
|
+
selectable: false,
|
|
4998
|
+
evented: false,
|
|
4999
|
+
originX: "left",
|
|
5000
|
+
originY: "top"
|
|
5001
|
+
}
|
|
4496
5002
|
});
|
|
4497
|
-
layer.add(offsetBorderObj);
|
|
4498
5003
|
}
|
|
4499
5004
|
const borderPathData = generateDielinePath({
|
|
4500
5005
|
shape,
|
|
@@ -4504,37 +5009,59 @@ var DielineTool = class {
|
|
|
4504
5009
|
x: cx,
|
|
4505
5010
|
y: cy,
|
|
4506
5011
|
features: absoluteFeatures,
|
|
5012
|
+
shapeStyle,
|
|
4507
5013
|
pathData: this.state.pathData,
|
|
5014
|
+
customSourceWidthPx: this.state.customSourceWidthPx,
|
|
5015
|
+
customSourceHeightPx: this.state.customSourceHeightPx,
|
|
4508
5016
|
canvasWidth: canvasW,
|
|
4509
5017
|
canvasHeight: canvasH
|
|
4510
5018
|
});
|
|
4511
|
-
|
|
4512
|
-
|
|
4513
|
-
|
|
4514
|
-
|
|
4515
|
-
|
|
4516
|
-
|
|
4517
|
-
|
|
4518
|
-
|
|
4519
|
-
|
|
4520
|
-
|
|
4521
|
-
|
|
4522
|
-
|
|
4523
|
-
|
|
4524
|
-
|
|
4525
|
-
|
|
4526
|
-
if (layerIndex < userIndex) {
|
|
4527
|
-
this.canvasService.canvas.moveObjectTo(layer, userIndex + 1);
|
|
5019
|
+
specs.push({
|
|
5020
|
+
id: "dieline.border",
|
|
5021
|
+
type: "path",
|
|
5022
|
+
space: "screen",
|
|
5023
|
+
data: { id: "dieline.border", type: "dieline" },
|
|
5024
|
+
props: {
|
|
5025
|
+
pathData: borderPathData,
|
|
5026
|
+
fill: "transparent",
|
|
5027
|
+
stroke: mainLine.style === "hidden" ? null : mainLine.color,
|
|
5028
|
+
strokeWidth: mainLine.width,
|
|
5029
|
+
strokeDashArray: mainLine.style === "dashed" ? [mainLine.dashLength, mainLine.dashLength] : void 0,
|
|
5030
|
+
selectable: false,
|
|
5031
|
+
evented: false,
|
|
5032
|
+
originX: "left",
|
|
5033
|
+
originY: "top"
|
|
4528
5034
|
}
|
|
4529
|
-
}
|
|
4530
|
-
|
|
5035
|
+
});
|
|
5036
|
+
return specs;
|
|
5037
|
+
}
|
|
5038
|
+
updateDieline(_emitEvent = true) {
|
|
5039
|
+
void this.updateDielineAsync();
|
|
5040
|
+
}
|
|
5041
|
+
async updateDielineAsync() {
|
|
5042
|
+
if (!this.canvasService) return;
|
|
5043
|
+
const configService = this.getConfigService();
|
|
5044
|
+
if (!configService) return;
|
|
5045
|
+
const seq = ++this.renderSeq;
|
|
5046
|
+
this.syncSizeState(configService);
|
|
5047
|
+
const sceneLayout = computeSceneLayout(
|
|
5048
|
+
this.canvasService,
|
|
5049
|
+
readSizeState(configService)
|
|
5050
|
+
);
|
|
5051
|
+
if (!sceneLayout) {
|
|
5052
|
+
if (seq !== this.renderSeq) return;
|
|
5053
|
+
this.specs = [];
|
|
5054
|
+
await this.canvasService.flushRenderFromProducers();
|
|
5055
|
+
return;
|
|
4531
5056
|
}
|
|
5057
|
+
const nextSpecs = this.buildDielineSpecs(sceneLayout);
|
|
5058
|
+
if (seq !== this.renderSeq) return;
|
|
5059
|
+
this.specs = nextSpecs;
|
|
5060
|
+
await this.canvasService.flushRenderFromProducers();
|
|
5061
|
+
if (seq !== this.renderSeq) return;
|
|
5062
|
+
this.ensureLayerStacking();
|
|
4532
5063
|
this.bringFeatureMarkersToFront();
|
|
4533
|
-
|
|
4534
|
-
if (rulerLayer) {
|
|
4535
|
-
this.canvasService.canvas.bringObjectToFront(rulerLayer);
|
|
4536
|
-
}
|
|
4537
|
-
layer.dirty = true;
|
|
5064
|
+
this.canvasService.bringLayerToFront("ruler-overlay");
|
|
4538
5065
|
this.canvasService.requestRenderAll();
|
|
4539
5066
|
}
|
|
4540
5067
|
getGeometry() {
|
|
@@ -4550,7 +5077,9 @@ var DielineTool = class {
|
|
|
4550
5077
|
return {
|
|
4551
5078
|
...sceneGeometry,
|
|
4552
5079
|
strokeWidth: this.state.mainLine.width,
|
|
4553
|
-
pathData: this.state.pathData
|
|
5080
|
+
pathData: this.state.pathData,
|
|
5081
|
+
customSourceWidthPx: this.state.customSourceWidthPx,
|
|
5082
|
+
customSourceHeightPx: this.state.customSourceHeightPx
|
|
4554
5083
|
};
|
|
4555
5084
|
}
|
|
4556
5085
|
async exportCutImage(options) {
|
|
@@ -4580,7 +5109,7 @@ var DielineTool = class {
|
|
|
4580
5109
|
);
|
|
4581
5110
|
return null;
|
|
4582
5111
|
}
|
|
4583
|
-
const { shape, radius, features, pathData } = this.state;
|
|
5112
|
+
const { shape, shapeStyle, radius, features, pathData } = this.state;
|
|
4584
5113
|
const canvasW = sceneLayout.canvasWidth || this.canvasService.canvas.width || 800;
|
|
4585
5114
|
const canvasH = sceneLayout.canvasHeight || this.canvasService.canvas.height || 600;
|
|
4586
5115
|
const scale = sceneLayout.scale;
|
|
@@ -4608,7 +5137,10 @@ var DielineTool = class {
|
|
|
4608
5137
|
x: cx,
|
|
4609
5138
|
y: cy,
|
|
4610
5139
|
features: cutFeatures,
|
|
5140
|
+
shapeStyle,
|
|
4611
5141
|
pathData,
|
|
5142
|
+
customSourceWidthPx: this.state.customSourceWidthPx,
|
|
5143
|
+
customSourceHeightPx: this.state.customSourceHeightPx,
|
|
4612
5144
|
canvasWidth: canvasW,
|
|
4613
5145
|
canvasHeight: canvasH
|
|
4614
5146
|
});
|
|
@@ -4720,7 +5252,6 @@ var DielineTool = class {
|
|
|
4720
5252
|
import {
|
|
4721
5253
|
ContributionPointIds as ContributionPointIds5
|
|
4722
5254
|
} from "@pooder/core";
|
|
4723
|
-
import { Circle, Group, Point as Point2, Rect as Rect2 } from "fabric";
|
|
4724
5255
|
|
|
4725
5256
|
// src/extensions/constraints.ts
|
|
4726
5257
|
var ConstraintRegistry = class {
|
|
@@ -4920,6 +5451,10 @@ function completeFeaturesStrict(features, context, update) {
|
|
|
4920
5451
|
}
|
|
4921
5452
|
|
|
4922
5453
|
// src/extensions/feature.ts
|
|
5454
|
+
var FEATURE_OVERLAY_LAYER_ID = "feature-overlay";
|
|
5455
|
+
var FEATURE_STROKE_WIDTH = 2;
|
|
5456
|
+
var DEFAULT_RECT_SIZE = 10;
|
|
5457
|
+
var DEFAULT_CIRCLE_RADIUS = 5;
|
|
4923
5458
|
var FeatureTool = class {
|
|
4924
5459
|
constructor(options) {
|
|
4925
5460
|
this.id = "pooder.kit.feature";
|
|
@@ -4932,6 +5467,8 @@ var FeatureTool = class {
|
|
|
4932
5467
|
this.isFeatureSessionActive = false;
|
|
4933
5468
|
this.sessionOriginalFeatures = null;
|
|
4934
5469
|
this.hasWorkingChanges = false;
|
|
5470
|
+
this.specs = [];
|
|
5471
|
+
this.renderSeq = 0;
|
|
4935
5472
|
this.handleMoving = null;
|
|
4936
5473
|
this.handleModified = null;
|
|
4937
5474
|
this.handleSceneGeometryChange = null;
|
|
@@ -4948,12 +5485,23 @@ var FeatureTool = class {
|
|
|
4948
5485
|
}
|
|
4949
5486
|
}
|
|
4950
5487
|
activate(context) {
|
|
5488
|
+
var _a;
|
|
4951
5489
|
this.context = context;
|
|
4952
5490
|
this.canvasService = context.services.get("CanvasService");
|
|
4953
5491
|
if (!this.canvasService) {
|
|
4954
5492
|
console.warn("CanvasService not found for FeatureTool");
|
|
4955
5493
|
return;
|
|
4956
5494
|
}
|
|
5495
|
+
(_a = this.renderProducerDisposable) == null ? void 0 : _a.dispose();
|
|
5496
|
+
this.renderProducerDisposable = this.canvasService.registerRenderProducer(
|
|
5497
|
+
this.id,
|
|
5498
|
+
() => ({
|
|
5499
|
+
rootLayerSpecs: {
|
|
5500
|
+
[FEATURE_OVERLAY_LAYER_ID]: this.specs
|
|
5501
|
+
}
|
|
5502
|
+
}),
|
|
5503
|
+
{ priority: 350 }
|
|
5504
|
+
);
|
|
4957
5505
|
const configService = context.services.get(
|
|
4958
5506
|
"ConfigurationService"
|
|
4959
5507
|
);
|
|
@@ -4992,21 +5540,7 @@ var FeatureTool = class {
|
|
|
4992
5540
|
this.context = void 0;
|
|
4993
5541
|
}
|
|
4994
5542
|
updateVisibility() {
|
|
4995
|
-
|
|
4996
|
-
const canvas = this.canvasService.canvas;
|
|
4997
|
-
const markers = canvas.getObjects().filter((obj) => {
|
|
4998
|
-
var _a;
|
|
4999
|
-
return ((_a = obj.data) == null ? void 0 : _a.type) === "feature-marker";
|
|
5000
|
-
});
|
|
5001
|
-
markers.forEach((marker) => {
|
|
5002
|
-
marker.set({
|
|
5003
|
-
visible: this.isToolActive,
|
|
5004
|
-
// Or just selectable: false if we want them visible but locked
|
|
5005
|
-
selectable: this.isToolActive,
|
|
5006
|
-
evented: this.isToolActive
|
|
5007
|
-
});
|
|
5008
|
-
});
|
|
5009
|
-
canvas.requestRenderAll();
|
|
5543
|
+
this.redraw();
|
|
5010
5544
|
}
|
|
5011
5545
|
contribute() {
|
|
5012
5546
|
return {
|
|
@@ -5238,8 +5772,7 @@ var FeatureTool = class {
|
|
|
5238
5772
|
if (!changed) return { ok: true };
|
|
5239
5773
|
this.setWorkingFeatures(next);
|
|
5240
5774
|
this.hasWorkingChanges = true;
|
|
5241
|
-
this.redraw();
|
|
5242
|
-
this.enforceConstraints();
|
|
5775
|
+
this.redraw({ enforceConstraints: true });
|
|
5243
5776
|
this.emitWorkingChange();
|
|
5244
5777
|
return { ok: true };
|
|
5245
5778
|
}
|
|
@@ -5287,12 +5820,10 @@ var FeatureTool = class {
|
|
|
5287
5820
|
shape: "rect",
|
|
5288
5821
|
x: 0.5,
|
|
5289
5822
|
y: 0,
|
|
5290
|
-
// Top edge
|
|
5291
5823
|
width: 10,
|
|
5292
5824
|
height: 10,
|
|
5293
5825
|
rotation: 0,
|
|
5294
5826
|
renderBehavior: "edge",
|
|
5295
|
-
// Default constraint: path (snap to edge)
|
|
5296
5827
|
constraints: [{ type: "path" }]
|
|
5297
5828
|
};
|
|
5298
5829
|
this.setWorkingFeatures([...this.workingFeatures || [], newFeature]);
|
|
@@ -5335,7 +5866,7 @@ var FeatureTool = class {
|
|
|
5335
5866
|
this.emitWorkingChange();
|
|
5336
5867
|
return true;
|
|
5337
5868
|
}
|
|
5338
|
-
getGeometryForFeature(geometry,
|
|
5869
|
+
getGeometryForFeature(geometry, _feature) {
|
|
5339
5870
|
return geometry;
|
|
5340
5871
|
}
|
|
5341
5872
|
setup() {
|
|
@@ -5344,8 +5875,7 @@ var FeatureTool = class {
|
|
|
5344
5875
|
if (!this.handleSceneGeometryChange) {
|
|
5345
5876
|
this.handleSceneGeometryChange = (geometry) => {
|
|
5346
5877
|
this.currentGeometry = geometry;
|
|
5347
|
-
this.redraw();
|
|
5348
|
-
this.enforceConstraints();
|
|
5878
|
+
this.redraw({ enforceConstraints: true });
|
|
5349
5879
|
};
|
|
5350
5880
|
this.context.eventBus.on(
|
|
5351
5881
|
"scene:geometry:change",
|
|
@@ -5368,76 +5898,34 @@ var FeatureTool = class {
|
|
|
5368
5898
|
}
|
|
5369
5899
|
if (!this.handleMoving) {
|
|
5370
5900
|
this.handleMoving = (e) => {
|
|
5371
|
-
|
|
5372
|
-
|
|
5373
|
-
|
|
5374
|
-
|
|
5375
|
-
|
|
5376
|
-
|
|
5377
|
-
|
|
5378
|
-
|
|
5379
|
-
|
|
5380
|
-
|
|
5381
|
-
} else {
|
|
5382
|
-
const index = (_d = target.data) == null ? void 0 : _d.index;
|
|
5383
|
-
if (index !== void 0) {
|
|
5384
|
-
feature = this.workingFeatures[index];
|
|
5385
|
-
}
|
|
5386
|
-
}
|
|
5387
|
-
const geometry = this.getGeometryForFeature(
|
|
5388
|
-
this.currentGeometry,
|
|
5901
|
+
const target = this.getDraggableMarkerTarget(e == null ? void 0 : e.target);
|
|
5902
|
+
if (!target || !this.currentGeometry) return;
|
|
5903
|
+
const feature = this.getFeatureForMarker(target);
|
|
5904
|
+
const geometry = this.getGeometryForFeature(this.currentGeometry, feature);
|
|
5905
|
+
const snapped = this.constrainPosition(
|
|
5906
|
+
{
|
|
5907
|
+
x: Number(target.left || 0),
|
|
5908
|
+
y: Number(target.top || 0)
|
|
5909
|
+
},
|
|
5910
|
+
geometry,
|
|
5389
5911
|
feature
|
|
5390
5912
|
);
|
|
5391
|
-
const p = new Point2(target.left, target.top);
|
|
5392
|
-
const markerStrokeWidth = (target.strokeWidth || 2) * (target.scaleX || 1);
|
|
5393
|
-
const minDim = Math.min(
|
|
5394
|
-
target.getScaledWidth(),
|
|
5395
|
-
target.getScaledHeight()
|
|
5396
|
-
);
|
|
5397
|
-
const limit = Math.max(0, minDim / 2 - markerStrokeWidth);
|
|
5398
|
-
const snapped = this.constrainPosition(p, geometry, limit, feature);
|
|
5399
5913
|
target.set({
|
|
5400
5914
|
left: snapped.x,
|
|
5401
5915
|
top: snapped.y
|
|
5402
5916
|
});
|
|
5917
|
+
target.setCoords();
|
|
5918
|
+
this.syncMarkerVisualsByTarget(target, snapped);
|
|
5403
5919
|
};
|
|
5404
5920
|
canvas.on("object:moving", this.handleMoving);
|
|
5405
5921
|
}
|
|
5406
5922
|
if (!this.handleModified) {
|
|
5407
5923
|
this.handleModified = (e) => {
|
|
5408
|
-
var _a
|
|
5409
|
-
const target = e.target;
|
|
5410
|
-
if (!target
|
|
5411
|
-
if ((
|
|
5412
|
-
|
|
5413
|
-
const indices = (_c = groupObj.data) == null ? void 0 : _c.indices;
|
|
5414
|
-
if (!indices) return;
|
|
5415
|
-
const groupCenter = new Point2(groupObj.left, groupObj.top);
|
|
5416
|
-
const newFeatures = [...this.workingFeatures];
|
|
5417
|
-
const { x, y } = this.currentGeometry;
|
|
5418
|
-
groupObj.getObjects().forEach((child, i) => {
|
|
5419
|
-
const originalIndex = indices[i];
|
|
5420
|
-
const feature = this.workingFeatures[originalIndex];
|
|
5421
|
-
const geometry = this.getGeometryForFeature(
|
|
5422
|
-
this.currentGeometry,
|
|
5423
|
-
feature
|
|
5424
|
-
);
|
|
5425
|
-
const { width, height } = geometry;
|
|
5426
|
-
const layoutLeft = x - width / 2;
|
|
5427
|
-
const layoutTop = y - height / 2;
|
|
5428
|
-
const absX = groupCenter.x + (child.left || 0);
|
|
5429
|
-
const absY = groupCenter.y + (child.top || 0);
|
|
5430
|
-
const normalizedX = width > 0 ? (absX - layoutLeft) / width : 0.5;
|
|
5431
|
-
const normalizedY = height > 0 ? (absY - layoutTop) / height : 0.5;
|
|
5432
|
-
newFeatures[originalIndex] = {
|
|
5433
|
-
...newFeatures[originalIndex],
|
|
5434
|
-
x: normalizedX,
|
|
5435
|
-
y: normalizedY
|
|
5436
|
-
};
|
|
5437
|
-
});
|
|
5438
|
-
this.setWorkingFeatures(newFeatures);
|
|
5439
|
-
this.hasWorkingChanges = true;
|
|
5440
|
-
this.emitWorkingChange();
|
|
5924
|
+
var _a;
|
|
5925
|
+
const target = this.getDraggableMarkerTarget(e == null ? void 0 : e.target);
|
|
5926
|
+
if (!target) return;
|
|
5927
|
+
if ((_a = target.data) == null ? void 0 : _a.isGroup) {
|
|
5928
|
+
this.syncGroupFromCanvas(target);
|
|
5441
5929
|
} else {
|
|
5442
5930
|
this.syncFeatureFromCanvas(target);
|
|
5443
5931
|
}
|
|
@@ -5446,6 +5934,7 @@ var FeatureTool = class {
|
|
|
5446
5934
|
}
|
|
5447
5935
|
}
|
|
5448
5936
|
teardown() {
|
|
5937
|
+
var _a;
|
|
5449
5938
|
if (!this.canvasService) return;
|
|
5450
5939
|
const canvas = this.canvasService.canvas;
|
|
5451
5940
|
if (this.handleMoving) {
|
|
@@ -5463,14 +5952,25 @@ var FeatureTool = class {
|
|
|
5463
5952
|
);
|
|
5464
5953
|
this.handleSceneGeometryChange = null;
|
|
5465
5954
|
}
|
|
5466
|
-
|
|
5467
|
-
|
|
5468
|
-
|
|
5469
|
-
|
|
5470
|
-
|
|
5471
|
-
|
|
5955
|
+
this.renderSeq += 1;
|
|
5956
|
+
this.specs = [];
|
|
5957
|
+
(_a = this.renderProducerDisposable) == null ? void 0 : _a.dispose();
|
|
5958
|
+
this.renderProducerDisposable = void 0;
|
|
5959
|
+
void this.canvasService.flushRenderFromProducers();
|
|
5960
|
+
}
|
|
5961
|
+
getDraggableMarkerTarget(target) {
|
|
5962
|
+
var _a, _b;
|
|
5963
|
+
if (!target || ((_a = target.data) == null ? void 0 : _a.type) !== "feature-marker") return null;
|
|
5964
|
+
if (((_b = target.data) == null ? void 0 : _b.markerRole) !== "handle") return null;
|
|
5965
|
+
return target;
|
|
5966
|
+
}
|
|
5967
|
+
getFeatureForMarker(target) {
|
|
5968
|
+
const data = (target == null ? void 0 : target.data) || {};
|
|
5969
|
+
const index = data.isGroup ? this.toFeatureIndex(data.anchorIndex) : this.toFeatureIndex(data.index);
|
|
5970
|
+
if (index === null) return void 0;
|
|
5971
|
+
return this.workingFeatures[index];
|
|
5472
5972
|
}
|
|
5473
|
-
constrainPosition(p, geometry,
|
|
5973
|
+
constrainPosition(p, geometry, feature) {
|
|
5474
5974
|
var _a;
|
|
5475
5975
|
if (!feature) {
|
|
5476
5976
|
return { x: p.x, y: p.y };
|
|
@@ -5501,225 +6001,364 @@ var FeatureTool = class {
|
|
|
5501
6001
|
y: minY + constrained.y * geometry.height
|
|
5502
6002
|
};
|
|
5503
6003
|
}
|
|
6004
|
+
toNormalizedPoint(point, geometry) {
|
|
6005
|
+
const left = geometry.x - geometry.width / 2;
|
|
6006
|
+
const top = geometry.y - geometry.height / 2;
|
|
6007
|
+
return {
|
|
6008
|
+
x: geometry.width > 0 ? (point.x - left) / geometry.width : 0.5,
|
|
6009
|
+
y: geometry.height > 0 ? (point.y - top) / geometry.height : 0.5
|
|
6010
|
+
};
|
|
6011
|
+
}
|
|
5504
6012
|
syncFeatureFromCanvas(target) {
|
|
5505
6013
|
var _a;
|
|
5506
|
-
if (!this.currentGeometry
|
|
5507
|
-
const index = (_a = target.data) == null ? void 0 : _a.index;
|
|
5508
|
-
if (index ===
|
|
5509
|
-
return;
|
|
6014
|
+
if (!this.currentGeometry) return;
|
|
6015
|
+
const index = this.toFeatureIndex((_a = target.data) == null ? void 0 : _a.index);
|
|
6016
|
+
if (index === null || index >= this.workingFeatures.length) return;
|
|
5510
6017
|
const feature = this.workingFeatures[index];
|
|
5511
6018
|
const geometry = this.getGeometryForFeature(this.currentGeometry, feature);
|
|
5512
|
-
const
|
|
5513
|
-
|
|
5514
|
-
|
|
5515
|
-
|
|
5516
|
-
|
|
6019
|
+
const normalized = this.toNormalizedPoint(
|
|
6020
|
+
{
|
|
6021
|
+
x: Number(target.left || 0),
|
|
6022
|
+
y: Number(target.top || 0)
|
|
6023
|
+
},
|
|
6024
|
+
geometry
|
|
6025
|
+
);
|
|
5517
6026
|
const updatedFeature = {
|
|
5518
6027
|
...feature,
|
|
5519
|
-
x:
|
|
5520
|
-
y:
|
|
5521
|
-
// Could also update rotation if we allowed rotating markers
|
|
6028
|
+
x: normalized.x,
|
|
6029
|
+
y: normalized.y
|
|
5522
6030
|
};
|
|
5523
|
-
const
|
|
5524
|
-
|
|
5525
|
-
this.setWorkingFeatures(
|
|
6031
|
+
const next = [...this.workingFeatures];
|
|
6032
|
+
next[index] = updatedFeature;
|
|
6033
|
+
this.setWorkingFeatures(next);
|
|
5526
6034
|
this.hasWorkingChanges = true;
|
|
5527
6035
|
this.emitWorkingChange();
|
|
5528
6036
|
}
|
|
5529
|
-
|
|
5530
|
-
|
|
5531
|
-
|
|
5532
|
-
const
|
|
5533
|
-
|
|
5534
|
-
|
|
5535
|
-
|
|
6037
|
+
syncGroupFromCanvas(target) {
|
|
6038
|
+
var _a, _b;
|
|
6039
|
+
if (!this.currentGeometry) return;
|
|
6040
|
+
const indices = this.readGroupIndices((_a = target.data) == null ? void 0 : _a.indices);
|
|
6041
|
+
if (indices.length === 0) return;
|
|
6042
|
+
const offsets = this.readGroupMemberOffsets((_b = target.data) == null ? void 0 : _b.memberOffsets, indices);
|
|
6043
|
+
const anchorCenter = {
|
|
6044
|
+
x: Number(target.left || 0),
|
|
6045
|
+
y: Number(target.top || 0)
|
|
6046
|
+
};
|
|
6047
|
+
const next = [...this.workingFeatures];
|
|
6048
|
+
let changed = false;
|
|
6049
|
+
offsets.forEach((entry) => {
|
|
6050
|
+
const index = entry.index;
|
|
6051
|
+
if (index < 0 || index >= next.length) return;
|
|
6052
|
+
const feature = next[index];
|
|
6053
|
+
const geometry = this.getGeometryForFeature(this.currentGeometry, feature);
|
|
6054
|
+
const normalized = this.toNormalizedPoint(
|
|
6055
|
+
{
|
|
6056
|
+
x: anchorCenter.x + entry.dx,
|
|
6057
|
+
y: anchorCenter.y + entry.dy
|
|
6058
|
+
},
|
|
6059
|
+
geometry
|
|
6060
|
+
);
|
|
6061
|
+
if (feature.x !== normalized.x || feature.y !== normalized.y) {
|
|
6062
|
+
next[index] = {
|
|
6063
|
+
...feature,
|
|
6064
|
+
x: normalized.x,
|
|
6065
|
+
y: normalized.y
|
|
6066
|
+
};
|
|
6067
|
+
changed = true;
|
|
6068
|
+
}
|
|
5536
6069
|
});
|
|
5537
|
-
|
|
5538
|
-
|
|
5539
|
-
|
|
5540
|
-
|
|
6070
|
+
if (!changed) return;
|
|
6071
|
+
this.setWorkingFeatures(next);
|
|
6072
|
+
this.hasWorkingChanges = true;
|
|
6073
|
+
this.emitWorkingChange();
|
|
6074
|
+
}
|
|
6075
|
+
redraw(options = {}) {
|
|
6076
|
+
void this.redrawAsync(options);
|
|
6077
|
+
}
|
|
6078
|
+
async redrawAsync(options = {}) {
|
|
6079
|
+
if (!this.canvasService) return;
|
|
6080
|
+
const seq = ++this.renderSeq;
|
|
6081
|
+
this.specs = this.buildFeatureSpecs();
|
|
6082
|
+
if (seq !== this.renderSeq) return;
|
|
6083
|
+
await this.canvasService.flushRenderFromProducers();
|
|
6084
|
+
if (seq !== this.renderSeq) return;
|
|
6085
|
+
this.syncOverlayOrder();
|
|
6086
|
+
if (options.enforceConstraints) {
|
|
6087
|
+
this.enforceConstraints();
|
|
5541
6088
|
}
|
|
5542
|
-
|
|
5543
|
-
|
|
5544
|
-
|
|
6089
|
+
}
|
|
6090
|
+
syncOverlayOrder() {
|
|
6091
|
+
if (!this.canvasService) return;
|
|
6092
|
+
this.canvasService.bringLayerToFront(FEATURE_OVERLAY_LAYER_ID);
|
|
6093
|
+
this.canvasService.bringLayerToFront("ruler-overlay");
|
|
6094
|
+
}
|
|
6095
|
+
buildFeatureSpecs() {
|
|
6096
|
+
if (!this.currentGeometry || this.workingFeatures.length === 0) {
|
|
6097
|
+
return [];
|
|
6098
|
+
}
|
|
6099
|
+
const groups = /* @__PURE__ */ new Map();
|
|
5545
6100
|
const singles = [];
|
|
5546
|
-
this.workingFeatures.forEach((
|
|
5547
|
-
|
|
5548
|
-
|
|
5549
|
-
|
|
5550
|
-
|
|
5551
|
-
|
|
6101
|
+
this.workingFeatures.forEach((feature, index) => {
|
|
6102
|
+
const geometry = this.getGeometryForFeature(this.currentGeometry, feature);
|
|
6103
|
+
const position = resolveFeaturePosition(feature, geometry);
|
|
6104
|
+
const scale = geometry.scale || 1;
|
|
6105
|
+
const marker = {
|
|
6106
|
+
feature,
|
|
6107
|
+
index,
|
|
6108
|
+
position,
|
|
6109
|
+
geometry,
|
|
6110
|
+
scale
|
|
6111
|
+
};
|
|
6112
|
+
if (feature.groupId) {
|
|
6113
|
+
const list = groups.get(feature.groupId) || [];
|
|
6114
|
+
list.push(marker);
|
|
6115
|
+
groups.set(feature.groupId, list);
|
|
6116
|
+
return;
|
|
5552
6117
|
}
|
|
6118
|
+
singles.push(marker);
|
|
6119
|
+
});
|
|
6120
|
+
const specs = [];
|
|
6121
|
+
singles.forEach((marker) => {
|
|
6122
|
+
this.appendMarkerSpecs(specs, marker, {
|
|
6123
|
+
markerRole: "handle",
|
|
6124
|
+
isGroup: false
|
|
6125
|
+
});
|
|
6126
|
+
});
|
|
6127
|
+
groups.forEach((members, groupId) => {
|
|
6128
|
+
if (!members.length) return;
|
|
6129
|
+
const anchor = members[0];
|
|
6130
|
+
const memberOffsets = members.map((member) => ({
|
|
6131
|
+
index: member.index,
|
|
6132
|
+
dx: member.position.x - anchor.position.x,
|
|
6133
|
+
dy: member.position.y - anchor.position.y
|
|
6134
|
+
}));
|
|
6135
|
+
const indices = members.map((member) => member.index);
|
|
6136
|
+
members.filter((member) => member.index !== anchor.index).forEach((member) => {
|
|
6137
|
+
this.appendMarkerSpecs(specs, member, {
|
|
6138
|
+
markerRole: "member",
|
|
6139
|
+
isGroup: false,
|
|
6140
|
+
groupId
|
|
6141
|
+
});
|
|
6142
|
+
});
|
|
6143
|
+
this.appendMarkerSpecs(specs, anchor, {
|
|
6144
|
+
markerRole: "handle",
|
|
6145
|
+
isGroup: true,
|
|
6146
|
+
groupId,
|
|
6147
|
+
indices,
|
|
6148
|
+
anchorIndex: anchor.index,
|
|
6149
|
+
memberOffsets
|
|
6150
|
+
});
|
|
5553
6151
|
});
|
|
5554
|
-
|
|
5555
|
-
|
|
5556
|
-
|
|
5557
|
-
|
|
5558
|
-
|
|
5559
|
-
|
|
5560
|
-
|
|
5561
|
-
|
|
5562
|
-
|
|
5563
|
-
|
|
6152
|
+
return specs;
|
|
6153
|
+
}
|
|
6154
|
+
appendMarkerSpecs(specs, marker, options) {
|
|
6155
|
+
var _a, _b, _c, _d, _e;
|
|
6156
|
+
const { feature, index, position, scale, geometry } = marker;
|
|
6157
|
+
const baseRadius = feature.shape === "circle" ? (_a = feature.radius) != null ? _a : DEFAULT_CIRCLE_RADIUS : (_b = feature.radius) != null ? _b : 0;
|
|
6158
|
+
const baseWidth = feature.shape === "circle" ? baseRadius * 2 : (_c = feature.width) != null ? _c : DEFAULT_RECT_SIZE;
|
|
6159
|
+
const baseHeight = feature.shape === "circle" ? baseRadius * 2 : (_d = feature.height) != null ? _d : DEFAULT_RECT_SIZE;
|
|
6160
|
+
const visualWidth = baseWidth * scale;
|
|
6161
|
+
const visualHeight = baseHeight * scale;
|
|
6162
|
+
const visualRadius = baseRadius * scale;
|
|
6163
|
+
const color = feature.color || (feature.operation === "add" ? "#00FF00" : "#FF0000");
|
|
6164
|
+
const strokeDash = feature.strokeDash || (feature.operation === "subtract" ? [4, 4] : void 0);
|
|
6165
|
+
const interactive = options.markerRole === "handle";
|
|
6166
|
+
const baseData = this.buildMarkerData(marker, options);
|
|
6167
|
+
const commonProps = {
|
|
6168
|
+
visible: this.isToolActive,
|
|
6169
|
+
selectable: interactive && this.isToolActive,
|
|
6170
|
+
evented: interactive && this.isToolActive,
|
|
6171
|
+
hasControls: false,
|
|
6172
|
+
hasBorders: false,
|
|
6173
|
+
hoverCursor: interactive ? "move" : "default",
|
|
6174
|
+
lockRotation: true,
|
|
6175
|
+
lockScalingX: true,
|
|
6176
|
+
lockScalingY: true,
|
|
6177
|
+
fill: "transparent",
|
|
6178
|
+
stroke: color,
|
|
6179
|
+
strokeWidth: FEATURE_STROKE_WIDTH,
|
|
6180
|
+
strokeDashArray: strokeDash,
|
|
6181
|
+
originX: "center",
|
|
6182
|
+
originY: "center",
|
|
6183
|
+
left: position.x,
|
|
6184
|
+
top: position.y,
|
|
6185
|
+
angle: feature.rotation || 0
|
|
6186
|
+
};
|
|
6187
|
+
const markerId = this.markerId(index);
|
|
6188
|
+
if (feature.shape === "rect") {
|
|
6189
|
+
specs.push({
|
|
6190
|
+
id: markerId,
|
|
6191
|
+
type: "rect",
|
|
6192
|
+
space: "screen",
|
|
6193
|
+
data: baseData,
|
|
6194
|
+
props: {
|
|
6195
|
+
...commonProps,
|
|
5564
6196
|
width: visualWidth,
|
|
5565
6197
|
height: visualHeight,
|
|
5566
6198
|
rx: visualRadius,
|
|
5567
|
-
ry: visualRadius
|
|
5568
|
-
|
|
5569
|
-
|
|
5570
|
-
|
|
5571
|
-
|
|
5572
|
-
|
|
5573
|
-
|
|
5574
|
-
|
|
5575
|
-
|
|
5576
|
-
|
|
5577
|
-
|
|
5578
|
-
|
|
5579
|
-
|
|
5580
|
-
|
|
5581
|
-
|
|
5582
|
-
|
|
5583
|
-
|
|
5584
|
-
|
|
5585
|
-
|
|
5586
|
-
|
|
5587
|
-
|
|
5588
|
-
|
|
5589
|
-
|
|
5590
|
-
|
|
5591
|
-
|
|
5592
|
-
|
|
5593
|
-
|
|
5594
|
-
|
|
5595
|
-
|
|
5596
|
-
|
|
5597
|
-
|
|
5598
|
-
|
|
5599
|
-
|
|
6199
|
+
ry: visualRadius
|
|
6200
|
+
}
|
|
6201
|
+
});
|
|
6202
|
+
} else {
|
|
6203
|
+
specs.push({
|
|
6204
|
+
id: markerId,
|
|
6205
|
+
type: "rect",
|
|
6206
|
+
space: "screen",
|
|
6207
|
+
data: baseData,
|
|
6208
|
+
props: {
|
|
6209
|
+
...commonProps,
|
|
6210
|
+
width: visualWidth,
|
|
6211
|
+
height: visualHeight,
|
|
6212
|
+
rx: visualRadius,
|
|
6213
|
+
ry: visualRadius
|
|
6214
|
+
}
|
|
6215
|
+
});
|
|
6216
|
+
}
|
|
6217
|
+
if (((_e = feature.bridge) == null ? void 0 : _e.type) === "vertical") {
|
|
6218
|
+
const featureTopY = position.y - visualHeight / 2;
|
|
6219
|
+
const dielineTopY = geometry.y - geometry.height / 2;
|
|
6220
|
+
const bridgeHeight = Math.max(0, featureTopY - dielineTopY);
|
|
6221
|
+
if (bridgeHeight <= 1e-3) {
|
|
6222
|
+
return;
|
|
6223
|
+
}
|
|
6224
|
+
specs.push({
|
|
6225
|
+
id: this.bridgeIndicatorId(index),
|
|
6226
|
+
type: "rect",
|
|
6227
|
+
space: "screen",
|
|
6228
|
+
data: {
|
|
6229
|
+
...baseData,
|
|
6230
|
+
markerRole: "indicator",
|
|
6231
|
+
markerOffsetX: 0,
|
|
6232
|
+
markerOffsetY: -visualHeight / 2
|
|
6233
|
+
},
|
|
6234
|
+
props: {
|
|
6235
|
+
visible: this.isToolActive,
|
|
6236
|
+
selectable: false,
|
|
6237
|
+
evented: false,
|
|
6238
|
+
width: visualWidth,
|
|
6239
|
+
height: bridgeHeight,
|
|
6240
|
+
fill: "transparent",
|
|
6241
|
+
stroke: "#888",
|
|
5600
6242
|
strokeWidth: 1,
|
|
5601
6243
|
strokeDashArray: [2, 2],
|
|
5602
|
-
originX: "center",
|
|
5603
|
-
originY: "bottom",
|
|
5604
|
-
// Anchor at bottom so it extends up
|
|
5605
|
-
left: pos.x,
|
|
5606
|
-
top: pos.y - visualHeight / 2,
|
|
5607
|
-
// Start from top of feature
|
|
5608
6244
|
opacity: 0.5,
|
|
5609
|
-
selectable: false,
|
|
5610
|
-
evented: false
|
|
5611
|
-
});
|
|
5612
|
-
const group = new Group([bridgeIndicator, shape], {
|
|
5613
6245
|
originX: "center",
|
|
5614
|
-
originY: "
|
|
5615
|
-
left:
|
|
5616
|
-
top:
|
|
6246
|
+
originY: "bottom",
|
|
6247
|
+
left: position.x,
|
|
6248
|
+
top: position.y - visualHeight / 2
|
|
6249
|
+
}
|
|
6250
|
+
});
|
|
6251
|
+
}
|
|
6252
|
+
}
|
|
6253
|
+
buildMarkerData(marker, options) {
|
|
6254
|
+
const data = {
|
|
6255
|
+
type: "feature-marker",
|
|
6256
|
+
index: marker.index,
|
|
6257
|
+
featureId: marker.feature.id,
|
|
6258
|
+
markerRole: options.markerRole,
|
|
6259
|
+
markerOffsetX: 0,
|
|
6260
|
+
markerOffsetY: 0,
|
|
6261
|
+
isGroup: options.isGroup
|
|
6262
|
+
};
|
|
6263
|
+
if (options.groupId) data.groupId = options.groupId;
|
|
6264
|
+
if (options.indices) data.indices = options.indices;
|
|
6265
|
+
if (options.anchorIndex !== void 0) data.anchorIndex = options.anchorIndex;
|
|
6266
|
+
if (options.memberOffsets) data.memberOffsets = options.memberOffsets;
|
|
6267
|
+
return data;
|
|
6268
|
+
}
|
|
6269
|
+
markerId(index) {
|
|
6270
|
+
return `feature.marker.${index}`;
|
|
6271
|
+
}
|
|
6272
|
+
bridgeIndicatorId(index) {
|
|
6273
|
+
return `feature.marker.${index}.bridge`;
|
|
6274
|
+
}
|
|
6275
|
+
toFeatureIndex(value) {
|
|
6276
|
+
const numeric = Number(value);
|
|
6277
|
+
if (!Number.isInteger(numeric) || numeric < 0) return null;
|
|
6278
|
+
return numeric;
|
|
6279
|
+
}
|
|
6280
|
+
readGroupIndices(raw) {
|
|
6281
|
+
if (!Array.isArray(raw)) return [];
|
|
6282
|
+
return raw.map((value) => this.toFeatureIndex(value)).filter((value) => value !== null);
|
|
6283
|
+
}
|
|
6284
|
+
readGroupMemberOffsets(raw, fallbackIndices = []) {
|
|
6285
|
+
if (Array.isArray(raw)) {
|
|
6286
|
+
const parsed = raw.map((entry) => {
|
|
6287
|
+
const index = this.toFeatureIndex(entry == null ? void 0 : entry.index);
|
|
6288
|
+
const dx = Number(entry == null ? void 0 : entry.dx);
|
|
6289
|
+
const dy = Number(entry == null ? void 0 : entry.dy);
|
|
6290
|
+
if (index === null || !Number.isFinite(dx) || !Number.isFinite(dy)) {
|
|
6291
|
+
return null;
|
|
6292
|
+
}
|
|
6293
|
+
return { index, dx, dy };
|
|
6294
|
+
}).filter((value) => !!value);
|
|
6295
|
+
if (parsed.length > 0) return parsed;
|
|
6296
|
+
}
|
|
6297
|
+
return fallbackIndices.map((index) => ({ index, dx: 0, dy: 0 }));
|
|
6298
|
+
}
|
|
6299
|
+
syncMarkerVisualsByTarget(target, center) {
|
|
6300
|
+
var _a, _b, _c, _d, _e, _f;
|
|
6301
|
+
if ((_a = target.data) == null ? void 0 : _a.isGroup) {
|
|
6302
|
+
const indices = this.readGroupIndices((_b = target.data) == null ? void 0 : _b.indices);
|
|
6303
|
+
const offsets = this.readGroupMemberOffsets((_c = target.data) == null ? void 0 : _c.memberOffsets, indices);
|
|
6304
|
+
offsets.forEach((entry) => {
|
|
6305
|
+
this.syncMarkerVisualObjectsToCenter(entry.index, {
|
|
6306
|
+
x: center.x + entry.dx,
|
|
6307
|
+
y: center.y + entry.dy
|
|
5617
6308
|
});
|
|
5618
|
-
|
|
6309
|
+
});
|
|
6310
|
+
(_d = this.canvasService) == null ? void 0 : _d.requestRenderAll();
|
|
6311
|
+
return;
|
|
6312
|
+
}
|
|
6313
|
+
const index = this.toFeatureIndex((_e = target.data) == null ? void 0 : _e.index);
|
|
6314
|
+
if (index === null) return;
|
|
6315
|
+
this.syncMarkerVisualObjectsToCenter(index, center);
|
|
6316
|
+
(_f = this.canvasService) == null ? void 0 : _f.requestRenderAll();
|
|
6317
|
+
}
|
|
6318
|
+
syncMarkerVisualObjectsToCenter(index, center) {
|
|
6319
|
+
if (!this.canvasService) return;
|
|
6320
|
+
const markers = this.canvasService.canvas.getObjects().filter(
|
|
6321
|
+
(obj) => {
|
|
6322
|
+
var _a, _b;
|
|
6323
|
+
return ((_a = obj == null ? void 0 : obj.data) == null ? void 0 : _a.type) === "feature-marker" && this.toFeatureIndex((_b = obj == null ? void 0 : obj.data) == null ? void 0 : _b.index) === index;
|
|
5619
6324
|
}
|
|
5620
|
-
|
|
5621
|
-
|
|
5622
|
-
|
|
5623
|
-
const
|
|
5624
|
-
|
|
5625
|
-
feature
|
|
5626
|
-
);
|
|
5627
|
-
const pos = resolveFeaturePosition(feature, geometry2);
|
|
5628
|
-
const marker = createMarkerShape(feature, pos);
|
|
6325
|
+
);
|
|
6326
|
+
markers.forEach((marker) => {
|
|
6327
|
+
var _a, _b;
|
|
6328
|
+
const offsetX = Number(((_a = marker == null ? void 0 : marker.data) == null ? void 0 : _a.markerOffsetX) || 0);
|
|
6329
|
+
const offsetY = Number(((_b = marker == null ? void 0 : marker.data) == null ? void 0 : _b.markerOffsetY) || 0);
|
|
5629
6330
|
marker.set({
|
|
5630
|
-
|
|
5631
|
-
|
|
5632
|
-
evented: this.isToolActive,
|
|
5633
|
-
hasControls: false,
|
|
5634
|
-
hasBorders: false,
|
|
5635
|
-
hoverCursor: "move",
|
|
5636
|
-
lockRotation: true,
|
|
5637
|
-
lockScalingX: true,
|
|
5638
|
-
lockScalingY: true,
|
|
5639
|
-
data: { type: "feature-marker", index, isGroup: false }
|
|
5640
|
-
});
|
|
5641
|
-
canvas.add(marker);
|
|
5642
|
-
canvas.bringObjectToFront(marker);
|
|
5643
|
-
});
|
|
5644
|
-
Object.keys(groups).forEach((groupId) => {
|
|
5645
|
-
const members = groups[groupId];
|
|
5646
|
-
if (members.length === 0) return;
|
|
5647
|
-
const shapes = members.map(({ feature }) => {
|
|
5648
|
-
const geometry2 = this.getGeometryForFeature(
|
|
5649
|
-
this.currentGeometry,
|
|
5650
|
-
feature
|
|
5651
|
-
);
|
|
5652
|
-
const pos = resolveFeaturePosition(feature, geometry2);
|
|
5653
|
-
return createMarkerShape(feature, pos);
|
|
5654
|
-
});
|
|
5655
|
-
const groupObj = new Group(shapes, {
|
|
5656
|
-
visible: this.isToolActive,
|
|
5657
|
-
selectable: this.isToolActive,
|
|
5658
|
-
evented: this.isToolActive,
|
|
5659
|
-
hasControls: false,
|
|
5660
|
-
hasBorders: false,
|
|
5661
|
-
hoverCursor: "move",
|
|
5662
|
-
lockRotation: true,
|
|
5663
|
-
lockScalingX: true,
|
|
5664
|
-
lockScalingY: true,
|
|
5665
|
-
subTargetCheck: true,
|
|
5666
|
-
// Allow events to pass through if needed, but we treat as one
|
|
5667
|
-
interactive: false,
|
|
5668
|
-
// Children not interactive
|
|
5669
|
-
// @ts-ignore
|
|
5670
|
-
data: {
|
|
5671
|
-
type: "feature-marker",
|
|
5672
|
-
isGroup: true,
|
|
5673
|
-
groupId,
|
|
5674
|
-
indices: members.map((m) => m.index)
|
|
5675
|
-
}
|
|
6331
|
+
left: center.x + offsetX,
|
|
6332
|
+
top: center.y + offsetY
|
|
5676
6333
|
});
|
|
5677
|
-
|
|
5678
|
-
canvas.bringObjectToFront(groupObj);
|
|
6334
|
+
marker.setCoords();
|
|
5679
6335
|
});
|
|
5680
|
-
this.canvasService.requestRenderAll();
|
|
5681
6336
|
}
|
|
5682
6337
|
enforceConstraints() {
|
|
5683
6338
|
if (!this.canvasService || !this.currentGeometry) return;
|
|
5684
|
-
const
|
|
5685
|
-
|
|
5686
|
-
|
|
5687
|
-
|
|
5688
|
-
});
|
|
5689
|
-
markers.forEach((marker) => {
|
|
5690
|
-
var _a, _b, _c;
|
|
5691
|
-
let feature;
|
|
5692
|
-
if ((_a = marker.data) == null ? void 0 : _a.isGroup) {
|
|
5693
|
-
const indices = (_b = marker.data) == null ? void 0 : _b.indices;
|
|
5694
|
-
if (indices && indices.length > 0) {
|
|
5695
|
-
feature = this.workingFeatures[indices[0]];
|
|
5696
|
-
}
|
|
5697
|
-
} else {
|
|
5698
|
-
const index = (_c = marker.data) == null ? void 0 : _c.index;
|
|
5699
|
-
if (index !== void 0) {
|
|
5700
|
-
feature = this.workingFeatures[index];
|
|
5701
|
-
}
|
|
6339
|
+
const handles = this.canvasService.canvas.getObjects().filter(
|
|
6340
|
+
(obj) => {
|
|
6341
|
+
var _a, _b;
|
|
6342
|
+
return ((_a = obj == null ? void 0 : obj.data) == null ? void 0 : _a.type) === "feature-marker" && ((_b = obj == null ? void 0 : obj.data) == null ? void 0 : _b.markerRole) === "handle";
|
|
5702
6343
|
}
|
|
5703
|
-
|
|
5704
|
-
|
|
5705
|
-
|
|
5706
|
-
);
|
|
5707
|
-
const
|
|
5708
|
-
const minDim = Math.min(
|
|
5709
|
-
marker.getScaledWidth(),
|
|
5710
|
-
marker.getScaledHeight()
|
|
5711
|
-
);
|
|
5712
|
-
const limit = Math.max(0, minDim / 2 - markerStrokeWidth);
|
|
6344
|
+
);
|
|
6345
|
+
handles.forEach((marker) => {
|
|
6346
|
+
const feature = this.getFeatureForMarker(marker);
|
|
6347
|
+
if (!feature) return;
|
|
6348
|
+
const geometry = this.getGeometryForFeature(this.currentGeometry, feature);
|
|
5713
6349
|
const snapped = this.constrainPosition(
|
|
5714
|
-
|
|
6350
|
+
{
|
|
6351
|
+
x: Number(marker.left || 0),
|
|
6352
|
+
y: Number(marker.top || 0)
|
|
6353
|
+
},
|
|
5715
6354
|
geometry,
|
|
5716
|
-
limit,
|
|
5717
6355
|
feature
|
|
5718
6356
|
);
|
|
5719
6357
|
marker.set({ left: snapped.x, top: snapped.y });
|
|
5720
6358
|
marker.setCoords();
|
|
6359
|
+
this.syncMarkerVisualsByTarget(marker, snapped);
|
|
5721
6360
|
});
|
|
5722
|
-
canvas.requestRenderAll();
|
|
6361
|
+
this.canvasService.canvas.requestRenderAll();
|
|
5723
6362
|
}
|
|
5724
6363
|
};
|
|
5725
6364
|
|
|
@@ -5727,7 +6366,11 @@ var FeatureTool = class {
|
|
|
5727
6366
|
import {
|
|
5728
6367
|
ContributionPointIds as ContributionPointIds6
|
|
5729
6368
|
} from "@pooder/core";
|
|
5730
|
-
import { FabricImage as
|
|
6369
|
+
import { FabricImage as FabricImage3 } from "fabric";
|
|
6370
|
+
var FILM_LAYER_ID = "overlay";
|
|
6371
|
+
var FILM_IMAGE_ID = "film-image";
|
|
6372
|
+
var DEFAULT_WIDTH2 = 800;
|
|
6373
|
+
var DEFAULT_HEIGHT2 = 600;
|
|
5731
6374
|
var FilmTool = class {
|
|
5732
6375
|
constructor(options) {
|
|
5733
6376
|
this.id = "pooder.kit.film";
|
|
@@ -5736,17 +6379,38 @@ var FilmTool = class {
|
|
|
5736
6379
|
};
|
|
5737
6380
|
this.url = "";
|
|
5738
6381
|
this.opacity = 0.5;
|
|
6382
|
+
this.specs = [];
|
|
6383
|
+
this.renderSeq = 0;
|
|
6384
|
+
this.renderImageUrl = "";
|
|
6385
|
+
this.sourceSizeBySrc = /* @__PURE__ */ new Map();
|
|
6386
|
+
this.pendingSizeBySrc = /* @__PURE__ */ new Map();
|
|
6387
|
+
this.onCanvasResized = () => {
|
|
6388
|
+
this.updateFilm();
|
|
6389
|
+
};
|
|
5739
6390
|
if (options) {
|
|
5740
6391
|
Object.assign(this, options);
|
|
5741
6392
|
}
|
|
5742
6393
|
}
|
|
5743
6394
|
activate(context) {
|
|
6395
|
+
var _a;
|
|
5744
6396
|
this.canvasService = context.services.get("CanvasService");
|
|
5745
6397
|
if (!this.canvasService) {
|
|
5746
6398
|
console.warn("CanvasService not found for FilmTool");
|
|
5747
6399
|
return;
|
|
5748
6400
|
}
|
|
5749
|
-
|
|
6401
|
+
(_a = this.renderProducerDisposable) == null ? void 0 : _a.dispose();
|
|
6402
|
+
this.renderProducerDisposable = this.canvasService.registerRenderProducer(
|
|
6403
|
+
this.id,
|
|
6404
|
+
() => ({
|
|
6405
|
+
layerSpecs: {
|
|
6406
|
+
[FILM_LAYER_ID]: this.specs
|
|
6407
|
+
}
|
|
6408
|
+
}),
|
|
6409
|
+
{ priority: 500 }
|
|
6410
|
+
);
|
|
6411
|
+
const configService = context.services.get(
|
|
6412
|
+
"ConfigurationService"
|
|
6413
|
+
);
|
|
5750
6414
|
if (configService) {
|
|
5751
6415
|
this.url = configService.get("film.url", this.url);
|
|
5752
6416
|
this.opacity = configService.get("film.opacity", this.opacity);
|
|
@@ -5763,21 +6427,21 @@ var FilmTool = class {
|
|
|
5763
6427
|
}
|
|
5764
6428
|
});
|
|
5765
6429
|
}
|
|
5766
|
-
this.
|
|
6430
|
+
context.eventBus.on("canvas:resized", this.onCanvasResized);
|
|
5767
6431
|
this.updateFilm();
|
|
5768
6432
|
}
|
|
5769
6433
|
deactivate(context) {
|
|
5770
|
-
|
|
5771
|
-
|
|
5772
|
-
|
|
5773
|
-
|
|
5774
|
-
|
|
5775
|
-
|
|
5776
|
-
|
|
5777
|
-
|
|
5778
|
-
|
|
5779
|
-
|
|
5780
|
-
|
|
6434
|
+
var _a;
|
|
6435
|
+
context.eventBus.off("canvas:resized", this.onCanvasResized);
|
|
6436
|
+
this.renderSeq += 1;
|
|
6437
|
+
this.specs = [];
|
|
6438
|
+
this.renderImageUrl = "";
|
|
6439
|
+
(_a = this.renderProducerDisposable) == null ? void 0 : _a.dispose();
|
|
6440
|
+
this.renderProducerDisposable = void 0;
|
|
6441
|
+
if (!this.canvasService) return;
|
|
6442
|
+
void this.canvasService.flushRenderFromProducers();
|
|
6443
|
+
this.canvasService.requestRenderAll();
|
|
6444
|
+
this.canvasService = void 0;
|
|
5781
6445
|
}
|
|
5782
6446
|
contribute() {
|
|
5783
6447
|
return {
|
|
@@ -5813,73 +6477,108 @@ var FilmTool = class {
|
|
|
5813
6477
|
]
|
|
5814
6478
|
};
|
|
5815
6479
|
}
|
|
5816
|
-
|
|
5817
|
-
|
|
5818
|
-
|
|
5819
|
-
|
|
5820
|
-
|
|
5821
|
-
|
|
5822
|
-
|
|
5823
|
-
|
|
5824
|
-
height,
|
|
5825
|
-
left: 0,
|
|
5826
|
-
top: 0,
|
|
5827
|
-
originX: "left",
|
|
5828
|
-
originY: "top",
|
|
5829
|
-
selectable: false,
|
|
5830
|
-
evented: false,
|
|
5831
|
-
subTargetCheck: false,
|
|
5832
|
-
interactive: false
|
|
5833
|
-
});
|
|
5834
|
-
this.canvasService.canvas.bringObjectToFront(layer);
|
|
5835
|
-
}
|
|
6480
|
+
getViewportSize() {
|
|
6481
|
+
var _a, _b;
|
|
6482
|
+
const width = Number(((_a = this.canvasService) == null ? void 0 : _a.canvas.width) || 0);
|
|
6483
|
+
const height = Number(((_b = this.canvasService) == null ? void 0 : _b.canvas.height) || 0);
|
|
6484
|
+
return {
|
|
6485
|
+
width: width > 0 ? width : DEFAULT_WIDTH2,
|
|
6486
|
+
height: height > 0 ? height : DEFAULT_HEIGHT2
|
|
6487
|
+
};
|
|
5836
6488
|
}
|
|
5837
|
-
|
|
5838
|
-
|
|
5839
|
-
|
|
5840
|
-
|
|
5841
|
-
|
|
5842
|
-
return;
|
|
5843
|
-
}
|
|
5844
|
-
const { url, opacity } = this;
|
|
5845
|
-
if (!url) {
|
|
5846
|
-
const img2 = this.canvasService.getObject("film-image", "overlay");
|
|
5847
|
-
if (img2) {
|
|
5848
|
-
layer.remove(img2);
|
|
5849
|
-
this.canvasService.requestRenderAll();
|
|
5850
|
-
}
|
|
5851
|
-
return;
|
|
6489
|
+
clampOpacity(value) {
|
|
6490
|
+
return Math.max(0, Math.min(1, Number(value)));
|
|
6491
|
+
}
|
|
6492
|
+
buildFilmSpecs(imageUrl, opacity) {
|
|
6493
|
+
if (!imageUrl) {
|
|
6494
|
+
return [];
|
|
5852
6495
|
}
|
|
5853
|
-
const width = this.
|
|
5854
|
-
const
|
|
5855
|
-
|
|
5856
|
-
|
|
5857
|
-
|
|
5858
|
-
|
|
5859
|
-
|
|
5860
|
-
|
|
5861
|
-
|
|
5862
|
-
|
|
5863
|
-
|
|
5864
|
-
|
|
5865
|
-
|
|
5866
|
-
|
|
5867
|
-
|
|
5868
|
-
|
|
6496
|
+
const { width, height } = this.getViewportSize();
|
|
6497
|
+
const sourceSize = this.sourceSizeBySrc.get(imageUrl);
|
|
6498
|
+
const sourceWidth = Math.max(1, Number((sourceSize == null ? void 0 : sourceSize.width) || width));
|
|
6499
|
+
const sourceHeight = Math.max(1, Number((sourceSize == null ? void 0 : sourceSize.height) || height));
|
|
6500
|
+
const coverScale = Math.max(width / sourceWidth, height / sourceHeight);
|
|
6501
|
+
return [
|
|
6502
|
+
{
|
|
6503
|
+
id: FILM_IMAGE_ID,
|
|
6504
|
+
type: "image",
|
|
6505
|
+
src: imageUrl,
|
|
6506
|
+
space: "screen",
|
|
6507
|
+
data: {
|
|
6508
|
+
id: FILM_IMAGE_ID,
|
|
6509
|
+
layerId: FILM_LAYER_ID,
|
|
6510
|
+
type: "film-image"
|
|
6511
|
+
},
|
|
6512
|
+
props: {
|
|
5869
6513
|
left: 0,
|
|
5870
6514
|
top: 0,
|
|
5871
|
-
|
|
6515
|
+
originX: "left",
|
|
6516
|
+
originY: "top",
|
|
6517
|
+
opacity: this.clampOpacity(opacity),
|
|
6518
|
+
scaleX: coverScale,
|
|
6519
|
+
scaleY: coverScale,
|
|
5872
6520
|
selectable: false,
|
|
5873
6521
|
evented: false,
|
|
5874
|
-
|
|
5875
|
-
}
|
|
5876
|
-
|
|
6522
|
+
excludeFromExport: true
|
|
6523
|
+
}
|
|
6524
|
+
}
|
|
6525
|
+
];
|
|
6526
|
+
}
|
|
6527
|
+
async ensureImageSize(src) {
|
|
6528
|
+
if (!src) return null;
|
|
6529
|
+
const cached = this.sourceSizeBySrc.get(src);
|
|
6530
|
+
if (cached) return cached;
|
|
6531
|
+
const pending = this.pendingSizeBySrc.get(src);
|
|
6532
|
+
if (pending) {
|
|
6533
|
+
return pending;
|
|
6534
|
+
}
|
|
6535
|
+
const task = this.loadImageSize(src);
|
|
6536
|
+
this.pendingSizeBySrc.set(src, task);
|
|
6537
|
+
try {
|
|
6538
|
+
return await task;
|
|
6539
|
+
} finally {
|
|
6540
|
+
if (this.pendingSizeBySrc.get(src) === task) {
|
|
6541
|
+
this.pendingSizeBySrc.delete(src);
|
|
6542
|
+
}
|
|
6543
|
+
}
|
|
6544
|
+
}
|
|
6545
|
+
async loadImageSize(src) {
|
|
6546
|
+
try {
|
|
6547
|
+
const image = await FabricImage3.fromURL(src, {
|
|
6548
|
+
crossOrigin: "anonymous"
|
|
6549
|
+
});
|
|
6550
|
+
const width = Number((image == null ? void 0 : image.width) || 0);
|
|
6551
|
+
const height = Number((image == null ? void 0 : image.height) || 0);
|
|
6552
|
+
if (width > 0 && height > 0) {
|
|
6553
|
+
const size = { width, height };
|
|
6554
|
+
this.sourceSizeBySrc.set(src, size);
|
|
6555
|
+
return size;
|
|
5877
6556
|
}
|
|
5878
|
-
this.canvasService.requestRenderAll();
|
|
5879
6557
|
} catch (error) {
|
|
5880
|
-
console.error("[FilmTool] Failed to load film image",
|
|
6558
|
+
console.error("[FilmTool] Failed to load film image", src, error);
|
|
6559
|
+
}
|
|
6560
|
+
return null;
|
|
6561
|
+
}
|
|
6562
|
+
updateFilm() {
|
|
6563
|
+
void this.updateFilmAsync();
|
|
6564
|
+
}
|
|
6565
|
+
async updateFilmAsync() {
|
|
6566
|
+
if (!this.canvasService) return;
|
|
6567
|
+
const seq = ++this.renderSeq;
|
|
6568
|
+
const nextUrl = String(this.url || "").trim();
|
|
6569
|
+
if (!nextUrl) {
|
|
6570
|
+
this.renderImageUrl = "";
|
|
6571
|
+
} else if (nextUrl !== this.renderImageUrl) {
|
|
6572
|
+
const loaded = await this.ensureImageSize(nextUrl);
|
|
6573
|
+
if (seq !== this.renderSeq) return;
|
|
6574
|
+
if (loaded) {
|
|
6575
|
+
this.renderImageUrl = nextUrl;
|
|
6576
|
+
}
|
|
5881
6577
|
}
|
|
5882
|
-
|
|
6578
|
+
this.specs = this.buildFilmSpecs(this.renderImageUrl, this.opacity);
|
|
6579
|
+
await this.canvasService.flushRenderFromProducers();
|
|
6580
|
+
if (seq !== this.renderSeq) return;
|
|
6581
|
+
this.canvasService.bringLayerToFront(FILM_LAYER_ID);
|
|
5883
6582
|
this.canvasService.requestRenderAll();
|
|
5884
6583
|
}
|
|
5885
6584
|
};
|
|
@@ -5980,19 +6679,37 @@ var MirrorTool = class {
|
|
|
5980
6679
|
import {
|
|
5981
6680
|
ContributionPointIds as ContributionPointIds8
|
|
5982
6681
|
} from "@pooder/core";
|
|
5983
|
-
|
|
6682
|
+
var RULER_LAYER_ID = "ruler-overlay";
|
|
6683
|
+
var EXTENSION_LINE_LENGTH = 5;
|
|
6684
|
+
var MIN_ARROW_SIZE = 4;
|
|
6685
|
+
var THICKNESS_TO_STROKE_WIDTH_RATIO = 20;
|
|
6686
|
+
var DEFAULT_THICKNESS = 20;
|
|
6687
|
+
var DEFAULT_GAP = 45;
|
|
6688
|
+
var DEFAULT_FONT_SIZE = 10;
|
|
6689
|
+
var DEFAULT_BACKGROUND_COLOR = "#f0f0f0";
|
|
6690
|
+
var DEFAULT_TEXT_COLOR = "#333333";
|
|
6691
|
+
var DEFAULT_LINE_COLOR = "#999999";
|
|
6692
|
+
var RULER_THICKNESS_MIN = 10;
|
|
6693
|
+
var RULER_THICKNESS_MAX = 100;
|
|
6694
|
+
var RULER_GAP_MIN = 0;
|
|
6695
|
+
var RULER_GAP_MAX = 100;
|
|
6696
|
+
var RULER_FONT_SIZE_MIN = 8;
|
|
6697
|
+
var RULER_FONT_SIZE_MAX = 24;
|
|
5984
6698
|
var RulerTool = class {
|
|
5985
6699
|
constructor(options) {
|
|
5986
6700
|
this.id = "pooder.kit.ruler";
|
|
5987
6701
|
this.metadata = {
|
|
5988
6702
|
name: "RulerTool"
|
|
5989
6703
|
};
|
|
5990
|
-
this.thickness =
|
|
5991
|
-
this.gap =
|
|
5992
|
-
this.backgroundColor =
|
|
5993
|
-
this.textColor =
|
|
5994
|
-
this.lineColor =
|
|
5995
|
-
this.fontSize =
|
|
6704
|
+
this.thickness = DEFAULT_THICKNESS;
|
|
6705
|
+
this.gap = DEFAULT_GAP;
|
|
6706
|
+
this.backgroundColor = DEFAULT_BACKGROUND_COLOR;
|
|
6707
|
+
this.textColor = DEFAULT_TEXT_COLOR;
|
|
6708
|
+
this.lineColor = DEFAULT_LINE_COLOR;
|
|
6709
|
+
this.fontSize = DEFAULT_FONT_SIZE;
|
|
6710
|
+
this.renderSeq = 0;
|
|
6711
|
+
this.numericProps = /* @__PURE__ */ new Set(["thickness", "gap", "fontSize"]);
|
|
6712
|
+
this.specs = [];
|
|
5996
6713
|
this.onCanvasResized = () => {
|
|
5997
6714
|
this.updateRuler();
|
|
5998
6715
|
};
|
|
@@ -6001,50 +6718,73 @@ var RulerTool = class {
|
|
|
6001
6718
|
}
|
|
6002
6719
|
}
|
|
6003
6720
|
activate(context) {
|
|
6721
|
+
var _a;
|
|
6004
6722
|
this.context = context;
|
|
6005
6723
|
this.canvasService = context.services.get("CanvasService");
|
|
6006
6724
|
if (!this.canvasService) {
|
|
6007
|
-
console.warn("CanvasService not found
|
|
6725
|
+
console.warn("[RulerTool] CanvasService not found.");
|
|
6008
6726
|
return;
|
|
6009
6727
|
}
|
|
6728
|
+
(_a = this.renderProducerDisposable) == null ? void 0 : _a.dispose();
|
|
6729
|
+
this.renderProducerDisposable = this.canvasService.registerRenderProducer(
|
|
6730
|
+
this.id,
|
|
6731
|
+
() => ({
|
|
6732
|
+
rootLayerSpecs: {
|
|
6733
|
+
[RULER_LAYER_ID]: this.specs
|
|
6734
|
+
},
|
|
6735
|
+
replaceRootLayerIds: [RULER_LAYER_ID]
|
|
6736
|
+
}),
|
|
6737
|
+
{ priority: 400 }
|
|
6738
|
+
);
|
|
6010
6739
|
const configService = context.services.get(
|
|
6011
6740
|
"ConfigurationService"
|
|
6012
6741
|
);
|
|
6013
6742
|
if (configService) {
|
|
6014
|
-
this.
|
|
6015
|
-
this.gap = configService.get("ruler.gap", this.gap);
|
|
6016
|
-
this.backgroundColor = configService.get(
|
|
6017
|
-
"ruler.backgroundColor",
|
|
6018
|
-
this.backgroundColor
|
|
6019
|
-
);
|
|
6020
|
-
this.textColor = configService.get("ruler.textColor", this.textColor);
|
|
6021
|
-
this.lineColor = configService.get("ruler.lineColor", this.lineColor);
|
|
6022
|
-
this.fontSize = configService.get("ruler.fontSize", this.fontSize);
|
|
6743
|
+
this.syncConfig(configService);
|
|
6023
6744
|
configService.onAnyChange((e) => {
|
|
6024
6745
|
let shouldUpdate = false;
|
|
6025
6746
|
if (e.key.startsWith("ruler.")) {
|
|
6026
6747
|
const prop = e.key.split(".")[1];
|
|
6027
6748
|
if (prop && prop in this) {
|
|
6028
|
-
this
|
|
6749
|
+
if (this.numericProps.has(prop)) {
|
|
6750
|
+
this[prop] = this.toFiniteNumber(
|
|
6751
|
+
e.value,
|
|
6752
|
+
this[prop]
|
|
6753
|
+
);
|
|
6754
|
+
} else {
|
|
6755
|
+
this[prop] = e.value;
|
|
6756
|
+
}
|
|
6029
6757
|
shouldUpdate = true;
|
|
6758
|
+
this.log("config:update", {
|
|
6759
|
+
key: e.key,
|
|
6760
|
+
raw: e.value,
|
|
6761
|
+
normalized: this[prop]
|
|
6762
|
+
});
|
|
6030
6763
|
}
|
|
6031
6764
|
} else if (e.key.startsWith("size.")) {
|
|
6032
6765
|
shouldUpdate = true;
|
|
6766
|
+
this.log("size:update", { key: e.key, value: e.value });
|
|
6033
6767
|
}
|
|
6034
6768
|
if (shouldUpdate) {
|
|
6035
6769
|
this.updateRuler();
|
|
6036
6770
|
}
|
|
6037
6771
|
});
|
|
6038
6772
|
}
|
|
6039
|
-
this.createLayer();
|
|
6040
6773
|
context.eventBus.on("canvas:resized", this.onCanvasResized);
|
|
6041
6774
|
this.updateRuler();
|
|
6042
6775
|
}
|
|
6043
6776
|
deactivate(context) {
|
|
6777
|
+
var _a;
|
|
6044
6778
|
context.eventBus.off("canvas:resized", this.onCanvasResized);
|
|
6045
|
-
this.
|
|
6779
|
+
this.specs = [];
|
|
6780
|
+
(_a = this.renderProducerDisposable) == null ? void 0 : _a.dispose();
|
|
6781
|
+
this.renderProducerDisposable = void 0;
|
|
6782
|
+
if (this.canvasService) {
|
|
6783
|
+
void this.canvasService.flushRenderFromProducers();
|
|
6784
|
+
}
|
|
6046
6785
|
this.canvasService = void 0;
|
|
6047
6786
|
this.context = void 0;
|
|
6787
|
+
this.renderSeq = 0;
|
|
6048
6788
|
}
|
|
6049
6789
|
contribute() {
|
|
6050
6790
|
return {
|
|
@@ -6053,43 +6793,43 @@ var RulerTool = class {
|
|
|
6053
6793
|
id: "ruler.thickness",
|
|
6054
6794
|
type: "number",
|
|
6055
6795
|
label: "Thickness",
|
|
6056
|
-
min:
|
|
6057
|
-
max:
|
|
6058
|
-
default:
|
|
6796
|
+
min: RULER_THICKNESS_MIN,
|
|
6797
|
+
max: RULER_THICKNESS_MAX,
|
|
6798
|
+
default: DEFAULT_THICKNESS
|
|
6059
6799
|
},
|
|
6060
6800
|
{
|
|
6061
6801
|
id: "ruler.gap",
|
|
6062
6802
|
type: "number",
|
|
6063
6803
|
label: "Gap",
|
|
6064
|
-
min:
|
|
6065
|
-
max:
|
|
6066
|
-
default:
|
|
6804
|
+
min: RULER_GAP_MIN,
|
|
6805
|
+
max: RULER_GAP_MAX,
|
|
6806
|
+
default: DEFAULT_GAP
|
|
6067
6807
|
},
|
|
6068
6808
|
{
|
|
6069
6809
|
id: "ruler.backgroundColor",
|
|
6070
6810
|
type: "color",
|
|
6071
6811
|
label: "Background Color",
|
|
6072
|
-
default:
|
|
6812
|
+
default: DEFAULT_BACKGROUND_COLOR
|
|
6073
6813
|
},
|
|
6074
6814
|
{
|
|
6075
6815
|
id: "ruler.textColor",
|
|
6076
6816
|
type: "color",
|
|
6077
6817
|
label: "Text Color",
|
|
6078
|
-
default:
|
|
6818
|
+
default: DEFAULT_TEXT_COLOR
|
|
6079
6819
|
},
|
|
6080
6820
|
{
|
|
6081
6821
|
id: "ruler.lineColor",
|
|
6082
6822
|
type: "color",
|
|
6083
6823
|
label: "Line Color",
|
|
6084
|
-
default:
|
|
6824
|
+
default: DEFAULT_LINE_COLOR
|
|
6085
6825
|
},
|
|
6086
6826
|
{
|
|
6087
6827
|
id: "ruler.fontSize",
|
|
6088
6828
|
type: "number",
|
|
6089
6829
|
label: "Font Size",
|
|
6090
|
-
min:
|
|
6091
|
-
max:
|
|
6092
|
-
default:
|
|
6830
|
+
min: RULER_FONT_SIZE_MIN,
|
|
6831
|
+
max: RULER_FONT_SIZE_MAX,
|
|
6832
|
+
default: DEFAULT_FONT_SIZE
|
|
6093
6833
|
}
|
|
6094
6834
|
],
|
|
6095
6835
|
[ContributionPointIds8.COMMANDS]: [
|
|
@@ -6102,12 +6842,23 @@ var RulerTool = class {
|
|
|
6102
6842
|
textColor: this.textColor,
|
|
6103
6843
|
lineColor: this.lineColor,
|
|
6104
6844
|
fontSize: this.fontSize,
|
|
6105
|
-
thickness: this.thickness
|
|
6845
|
+
thickness: this.thickness,
|
|
6846
|
+
gap: this.gap
|
|
6106
6847
|
};
|
|
6107
6848
|
const newState = { ...oldState, ...theme };
|
|
6108
|
-
if (JSON.stringify(newState) === JSON.stringify(oldState))
|
|
6849
|
+
if (JSON.stringify(newState) === JSON.stringify(oldState)) {
|
|
6109
6850
|
return true;
|
|
6851
|
+
}
|
|
6110
6852
|
Object.assign(this, newState);
|
|
6853
|
+
this.thickness = this.toFiniteNumber(
|
|
6854
|
+
this.thickness,
|
|
6855
|
+
DEFAULT_THICKNESS
|
|
6856
|
+
);
|
|
6857
|
+
this.gap = this.toFiniteNumber(this.gap, DEFAULT_GAP);
|
|
6858
|
+
this.fontSize = this.toFiniteNumber(
|
|
6859
|
+
this.fontSize,
|
|
6860
|
+
DEFAULT_FONT_SIZE
|
|
6861
|
+
);
|
|
6111
6862
|
this.updateRuler();
|
|
6112
6863
|
return true;
|
|
6113
6864
|
}
|
|
@@ -6115,225 +6866,367 @@ var RulerTool = class {
|
|
|
6115
6866
|
]
|
|
6116
6867
|
};
|
|
6117
6868
|
}
|
|
6118
|
-
|
|
6119
|
-
|
|
6120
|
-
|
|
6869
|
+
log(step, payload) {
|
|
6870
|
+
if (payload) {
|
|
6871
|
+
console.debug(`[RulerTool] ${step}`, payload);
|
|
6872
|
+
return;
|
|
6873
|
+
}
|
|
6874
|
+
console.debug(`[RulerTool] ${step}`);
|
|
6121
6875
|
}
|
|
6122
|
-
|
|
6123
|
-
|
|
6124
|
-
|
|
6125
|
-
|
|
6126
|
-
|
|
6127
|
-
|
|
6128
|
-
|
|
6129
|
-
|
|
6130
|
-
|
|
6131
|
-
|
|
6132
|
-
|
|
6133
|
-
|
|
6134
|
-
|
|
6135
|
-
|
|
6876
|
+
syncConfig(configService) {
|
|
6877
|
+
this.thickness = this.toFiniteNumber(
|
|
6878
|
+
configService.get("ruler.thickness", this.thickness),
|
|
6879
|
+
DEFAULT_THICKNESS
|
|
6880
|
+
);
|
|
6881
|
+
this.gap = Math.max(
|
|
6882
|
+
0,
|
|
6883
|
+
this.toFiniteNumber(
|
|
6884
|
+
configService.get("ruler.gap", this.gap),
|
|
6885
|
+
DEFAULT_GAP
|
|
6886
|
+
)
|
|
6887
|
+
);
|
|
6888
|
+
this.backgroundColor = configService.get(
|
|
6889
|
+
"ruler.backgroundColor",
|
|
6890
|
+
this.backgroundColor
|
|
6891
|
+
);
|
|
6892
|
+
this.textColor = configService.get("ruler.textColor", this.textColor);
|
|
6893
|
+
this.lineColor = configService.get("ruler.lineColor", this.lineColor);
|
|
6894
|
+
this.fontSize = this.toFiniteNumber(
|
|
6895
|
+
configService.get("ruler.fontSize", this.fontSize),
|
|
6896
|
+
DEFAULT_FONT_SIZE
|
|
6897
|
+
);
|
|
6898
|
+
this.log("config:loaded", {
|
|
6899
|
+
thickness: this.thickness,
|
|
6900
|
+
gap: this.gap,
|
|
6901
|
+
fontSize: this.fontSize,
|
|
6902
|
+
backgroundColor: this.backgroundColor,
|
|
6903
|
+
textColor: this.textColor,
|
|
6904
|
+
lineColor: this.lineColor
|
|
6136
6905
|
});
|
|
6137
|
-
canvas.bringObjectToFront(layer);
|
|
6138
6906
|
}
|
|
6139
|
-
|
|
6140
|
-
|
|
6141
|
-
|
|
6142
|
-
if (layer) {
|
|
6143
|
-
this.canvasService.canvas.remove(layer);
|
|
6144
|
-
}
|
|
6907
|
+
toFiniteNumber(value, fallback) {
|
|
6908
|
+
const numeric = Number(value);
|
|
6909
|
+
return Number.isFinite(numeric) ? numeric : fallback;
|
|
6145
6910
|
}
|
|
6146
|
-
|
|
6147
|
-
|
|
6148
|
-
|
|
6149
|
-
|
|
6150
|
-
|
|
6151
|
-
|
|
6152
|
-
|
|
6153
|
-
|
|
6154
|
-
|
|
6155
|
-
|
|
6156
|
-
const
|
|
6157
|
-
|
|
6158
|
-
|
|
6159
|
-
|
|
6160
|
-
|
|
6161
|
-
|
|
6162
|
-
|
|
6163
|
-
|
|
6164
|
-
|
|
6165
|
-
|
|
6166
|
-
|
|
6911
|
+
toSceneDisplayLength(value) {
|
|
6912
|
+
if (!this.canvasService) return value;
|
|
6913
|
+
return this.canvasService.toSceneLength(value);
|
|
6914
|
+
}
|
|
6915
|
+
formatLengthMm(valueMm, unit) {
|
|
6916
|
+
const converted = fromMm(valueMm, unit);
|
|
6917
|
+
const fractionDigits = unit === "in" ? 3 : 2;
|
|
6918
|
+
return Number(converted.toFixed(fractionDigits)).toString();
|
|
6919
|
+
}
|
|
6920
|
+
buildLinePath(start, end) {
|
|
6921
|
+
const dx = end.x - start.x;
|
|
6922
|
+
const dy = end.y - start.y;
|
|
6923
|
+
return `M 0 0 L ${dx} ${dy}`;
|
|
6924
|
+
}
|
|
6925
|
+
buildStartArrowPath(size) {
|
|
6926
|
+
return `M 0 0 L ${size} ${-size / 2} L ${size} ${size / 2} Z`;
|
|
6927
|
+
}
|
|
6928
|
+
buildEndArrowPath(size) {
|
|
6929
|
+
return `M 0 0 L ${-size} ${-size / 2} L ${-size} ${size / 2} Z`;
|
|
6930
|
+
}
|
|
6931
|
+
createPathSpec(id, pathData, position, options) {
|
|
6932
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
6933
|
+
return {
|
|
6934
|
+
id,
|
|
6935
|
+
type: "path",
|
|
6936
|
+
data: {
|
|
6937
|
+
id,
|
|
6938
|
+
type: "ruler"
|
|
6939
|
+
},
|
|
6940
|
+
props: {
|
|
6941
|
+
pathData,
|
|
6942
|
+
left: position.x,
|
|
6943
|
+
top: position.y,
|
|
6944
|
+
originX: (_a = options.originX) != null ? _a : "left",
|
|
6945
|
+
originY: (_b = options.originY) != null ? _b : "top",
|
|
6946
|
+
angle: (_c = options.angle) != null ? _c : 0,
|
|
6947
|
+
stroke: (_d = options.stroke) != null ? _d : null,
|
|
6948
|
+
fill: (_e = options.fill) != null ? _e : null,
|
|
6949
|
+
strokeWidth: (_f = options.strokeWidth) != null ? _f : 1,
|
|
6950
|
+
strokeLineCap: (_g = options.strokeLineCap) != null ? _g : "butt",
|
|
6951
|
+
selectable: false,
|
|
6952
|
+
evented: false,
|
|
6953
|
+
excludeFromExport: true
|
|
6954
|
+
}
|
|
6955
|
+
};
|
|
6956
|
+
}
|
|
6957
|
+
createTextSpec(id, text, position, angle = 0) {
|
|
6958
|
+
return {
|
|
6959
|
+
id,
|
|
6960
|
+
type: "text",
|
|
6961
|
+
data: {
|
|
6962
|
+
id,
|
|
6963
|
+
type: "ruler"
|
|
6964
|
+
},
|
|
6965
|
+
props: {
|
|
6966
|
+
text,
|
|
6967
|
+
left: position.x,
|
|
6968
|
+
top: position.y,
|
|
6969
|
+
angle,
|
|
6970
|
+
fontSize: this.toSceneDisplayLength(this.fontSize),
|
|
6971
|
+
fill: this.textColor,
|
|
6972
|
+
fontFamily: "Arial",
|
|
6973
|
+
originX: "center",
|
|
6167
6974
|
originY: "center",
|
|
6168
|
-
|
|
6975
|
+
backgroundColor: this.backgroundColor,
|
|
6169
6976
|
selectable: false,
|
|
6170
|
-
evented: false
|
|
6977
|
+
evented: false,
|
|
6978
|
+
excludeFromExport: true
|
|
6171
6979
|
}
|
|
6980
|
+
};
|
|
6981
|
+
}
|
|
6982
|
+
buildRulerSpecs(input) {
|
|
6983
|
+
const { left, top, right, bottom, widthLabel, heightLabel } = input;
|
|
6984
|
+
const gap = Math.max(
|
|
6985
|
+
0,
|
|
6986
|
+
this.toSceneDisplayLength(this.toFiniteNumber(this.gap, DEFAULT_GAP))
|
|
6987
|
+
);
|
|
6988
|
+
const topY = top - gap;
|
|
6989
|
+
const leftX = left - gap;
|
|
6990
|
+
const arrowSize = Math.max(
|
|
6991
|
+
this.toSceneDisplayLength(MIN_ARROW_SIZE),
|
|
6992
|
+
this.toSceneDisplayLength(this.thickness * 0.3)
|
|
6993
|
+
);
|
|
6994
|
+
const strokeWidth = Math.max(
|
|
6995
|
+
this.toSceneDisplayLength(1),
|
|
6996
|
+
this.toSceneDisplayLength(
|
|
6997
|
+
this.thickness / THICKNESS_TO_STROKE_WIDTH_RATIO
|
|
6998
|
+
)
|
|
6999
|
+
);
|
|
7000
|
+
const extensionLength = this.toSceneDisplayLength(EXTENSION_LINE_LENGTH);
|
|
7001
|
+
const topLineAngleDeg = 0;
|
|
7002
|
+
const leftLineAngleDeg = 90;
|
|
7003
|
+
const topMidX = left + (right - left) / 2;
|
|
7004
|
+
const leftMidY = top + (bottom - top) / 2;
|
|
7005
|
+
const topLineStartX = Math.min(left + arrowSize, topMidX);
|
|
7006
|
+
const topLineEndX = Math.max(right - arrowSize, topMidX);
|
|
7007
|
+
const leftLineStartY = Math.min(top + arrowSize, leftMidY);
|
|
7008
|
+
const leftLineEndY = Math.max(bottom - arrowSize, leftMidY);
|
|
7009
|
+
const specs = [];
|
|
7010
|
+
specs.push(
|
|
7011
|
+
this.createPathSpec(
|
|
7012
|
+
"ruler.top.line",
|
|
7013
|
+
this.buildLinePath(
|
|
7014
|
+
{ x: topLineStartX, y: topY },
|
|
7015
|
+
{ x: topLineEndX, y: topY }
|
|
7016
|
+
),
|
|
7017
|
+
{ x: topLineStartX, y: topY },
|
|
7018
|
+
{
|
|
7019
|
+
stroke: this.lineColor,
|
|
7020
|
+
strokeWidth,
|
|
7021
|
+
strokeLineCap: "butt"
|
|
7022
|
+
}
|
|
7023
|
+
),
|
|
7024
|
+
this.createPathSpec(
|
|
7025
|
+
"ruler.top.arrow.start",
|
|
7026
|
+
this.buildStartArrowPath(arrowSize),
|
|
7027
|
+
{ x: left, y: topY },
|
|
7028
|
+
{
|
|
7029
|
+
fill: this.lineColor,
|
|
7030
|
+
stroke: this.lineColor,
|
|
7031
|
+
strokeWidth: this.toSceneDisplayLength(1),
|
|
7032
|
+
originX: "left",
|
|
7033
|
+
originY: "center",
|
|
7034
|
+
angle: topLineAngleDeg
|
|
7035
|
+
}
|
|
7036
|
+
),
|
|
7037
|
+
this.createPathSpec(
|
|
7038
|
+
"ruler.top.arrow.end",
|
|
7039
|
+
this.buildEndArrowPath(arrowSize),
|
|
7040
|
+
{ x: right, y: topY },
|
|
7041
|
+
{
|
|
7042
|
+
fill: this.lineColor,
|
|
7043
|
+
stroke: this.lineColor,
|
|
7044
|
+
strokeWidth: this.toSceneDisplayLength(1),
|
|
7045
|
+
originX: "right",
|
|
7046
|
+
originY: "center",
|
|
7047
|
+
angle: topLineAngleDeg
|
|
7048
|
+
}
|
|
7049
|
+
),
|
|
7050
|
+
this.createPathSpec(
|
|
7051
|
+
"ruler.top.ext.start",
|
|
7052
|
+
this.buildLinePath(
|
|
7053
|
+
{ x: left, y: topY - extensionLength },
|
|
7054
|
+
{ x: left, y: topY + extensionLength }
|
|
7055
|
+
),
|
|
7056
|
+
{ x: left, y: topY - extensionLength },
|
|
7057
|
+
{
|
|
7058
|
+
stroke: this.lineColor,
|
|
7059
|
+
strokeWidth: this.toSceneDisplayLength(1)
|
|
7060
|
+
}
|
|
7061
|
+
),
|
|
7062
|
+
this.createPathSpec(
|
|
7063
|
+
"ruler.top.ext.end",
|
|
7064
|
+
this.buildLinePath(
|
|
7065
|
+
{ x: right, y: topY - extensionLength },
|
|
7066
|
+
{ x: right, y: topY + extensionLength }
|
|
7067
|
+
),
|
|
7068
|
+
{ x: right, y: topY - extensionLength },
|
|
7069
|
+
{
|
|
7070
|
+
stroke: this.lineColor,
|
|
7071
|
+
strokeWidth: this.toSceneDisplayLength(1)
|
|
7072
|
+
}
|
|
7073
|
+
),
|
|
7074
|
+
this.createTextSpec("ruler.top.label", widthLabel, {
|
|
7075
|
+
x: left + (right - left) / 2,
|
|
7076
|
+
y: topY
|
|
7077
|
+
})
|
|
6172
7078
|
);
|
|
6173
|
-
|
|
6174
|
-
|
|
6175
|
-
|
|
6176
|
-
|
|
6177
|
-
|
|
6178
|
-
|
|
6179
|
-
|
|
6180
|
-
|
|
6181
|
-
|
|
6182
|
-
|
|
6183
|
-
|
|
6184
|
-
|
|
6185
|
-
|
|
6186
|
-
|
|
6187
|
-
|
|
6188
|
-
|
|
7079
|
+
specs.push(
|
|
7080
|
+
this.createPathSpec(
|
|
7081
|
+
"ruler.left.line",
|
|
7082
|
+
this.buildLinePath(
|
|
7083
|
+
{ x: leftX, y: leftLineStartY },
|
|
7084
|
+
{ x: leftX, y: leftLineEndY }
|
|
7085
|
+
),
|
|
7086
|
+
{ x: leftX, y: leftLineStartY },
|
|
7087
|
+
{
|
|
7088
|
+
stroke: this.lineColor,
|
|
7089
|
+
strokeWidth,
|
|
7090
|
+
strokeLineCap: "butt"
|
|
7091
|
+
}
|
|
7092
|
+
),
|
|
7093
|
+
this.createPathSpec(
|
|
7094
|
+
"ruler.left.arrow.start",
|
|
7095
|
+
this.buildStartArrowPath(arrowSize),
|
|
7096
|
+
{ x: leftX, y: top },
|
|
7097
|
+
{
|
|
7098
|
+
fill: this.lineColor,
|
|
7099
|
+
stroke: this.lineColor,
|
|
7100
|
+
strokeWidth: this.toSceneDisplayLength(1),
|
|
7101
|
+
originX: "left",
|
|
7102
|
+
originY: "center",
|
|
7103
|
+
angle: leftLineAngleDeg
|
|
7104
|
+
}
|
|
7105
|
+
),
|
|
7106
|
+
this.createPathSpec(
|
|
7107
|
+
"ruler.left.arrow.end",
|
|
7108
|
+
this.buildEndArrowPath(arrowSize),
|
|
7109
|
+
{ x: leftX, y: bottom },
|
|
7110
|
+
{
|
|
7111
|
+
fill: this.lineColor,
|
|
7112
|
+
stroke: this.lineColor,
|
|
7113
|
+
strokeWidth: this.toSceneDisplayLength(1),
|
|
7114
|
+
originX: "right",
|
|
7115
|
+
originY: "center",
|
|
7116
|
+
angle: leftLineAngleDeg
|
|
7117
|
+
}
|
|
7118
|
+
),
|
|
7119
|
+
this.createPathSpec(
|
|
7120
|
+
"ruler.left.ext.start",
|
|
7121
|
+
this.buildLinePath(
|
|
7122
|
+
{ x: leftX - extensionLength, y: top },
|
|
7123
|
+
{ x: leftX + extensionLength, y: top }
|
|
7124
|
+
),
|
|
7125
|
+
{ x: leftX - extensionLength, y: top },
|
|
7126
|
+
{
|
|
7127
|
+
stroke: this.lineColor,
|
|
7128
|
+
strokeWidth: this.toSceneDisplayLength(1)
|
|
7129
|
+
}
|
|
7130
|
+
),
|
|
7131
|
+
this.createPathSpec(
|
|
7132
|
+
"ruler.left.ext.end",
|
|
7133
|
+
this.buildLinePath(
|
|
7134
|
+
{ x: leftX - extensionLength, y: bottom },
|
|
7135
|
+
{ x: leftX + extensionLength, y: bottom }
|
|
7136
|
+
),
|
|
7137
|
+
{ x: leftX - extensionLength, y: bottom },
|
|
7138
|
+
{
|
|
7139
|
+
stroke: this.lineColor,
|
|
7140
|
+
strokeWidth: this.toSceneDisplayLength(1)
|
|
7141
|
+
}
|
|
7142
|
+
),
|
|
7143
|
+
this.createTextSpec(
|
|
7144
|
+
"ruler.left.label",
|
|
7145
|
+
heightLabel,
|
|
7146
|
+
{
|
|
7147
|
+
x: leftX,
|
|
7148
|
+
y: top + (bottom - top) / 2
|
|
7149
|
+
},
|
|
7150
|
+
-90
|
|
7151
|
+
)
|
|
6189
7152
|
);
|
|
6190
|
-
return
|
|
6191
|
-
selectable: false,
|
|
6192
|
-
evented: false
|
|
6193
|
-
});
|
|
7153
|
+
return specs;
|
|
6194
7154
|
}
|
|
6195
7155
|
updateRuler() {
|
|
6196
|
-
|
|
7156
|
+
void this.updateRulerAsync();
|
|
7157
|
+
}
|
|
7158
|
+
async updateRulerAsync() {
|
|
7159
|
+
var _a, _b;
|
|
6197
7160
|
if (!this.canvasService) return;
|
|
6198
|
-
const layer = this.getLayer();
|
|
6199
|
-
if (!layer) return;
|
|
6200
|
-
layer.remove(...layer.getObjects());
|
|
6201
|
-
const { backgroundColor, lineColor, textColor, fontSize } = this;
|
|
6202
7161
|
const configService = (_a = this.context) == null ? void 0 : _a.services.get(
|
|
6203
7162
|
"ConfigurationService"
|
|
6204
7163
|
);
|
|
6205
7164
|
if (!configService) return;
|
|
7165
|
+
const seq = ++this.renderSeq;
|
|
6206
7166
|
const sizeState = readSizeState(configService);
|
|
6207
7167
|
const layout = computeSceneLayout(this.canvasService, sizeState);
|
|
6208
|
-
|
|
6209
|
-
|
|
6210
|
-
|
|
6211
|
-
|
|
6212
|
-
|
|
6213
|
-
|
|
6214
|
-
|
|
6215
|
-
|
|
6216
|
-
const rulerRight = rulerRect.left + rulerRect.width;
|
|
6217
|
-
const rulerBottom = rulerRect.top + rulerRect.height;
|
|
6218
|
-
const displayWidthMm = useCutAsRuler ? layout.cutWidthMm : layout.trimWidthMm;
|
|
6219
|
-
const displayHeightMm = useCutAsRuler ? layout.cutHeightMm : layout.trimHeightMm;
|
|
6220
|
-
const displayUnit = sizeState.unit;
|
|
6221
|
-
const topRulerY = rulerTop - gap;
|
|
6222
|
-
const topRulerXStart = rulerLeft;
|
|
6223
|
-
const topRulerXEnd = rulerRight;
|
|
6224
|
-
const leftRulerX = rulerLeft - gap;
|
|
6225
|
-
const leftRulerYStart = rulerTop;
|
|
6226
|
-
const leftRulerYEnd = rulerBottom;
|
|
6227
|
-
const topDimLine = this.createArrowLine(
|
|
6228
|
-
topRulerXStart,
|
|
6229
|
-
topRulerY,
|
|
6230
|
-
topRulerXEnd,
|
|
6231
|
-
topRulerY,
|
|
6232
|
-
lineColor
|
|
6233
|
-
);
|
|
6234
|
-
layer.add(topDimLine);
|
|
6235
|
-
const extLen = 5;
|
|
6236
|
-
layer.add(
|
|
6237
|
-
new Line(
|
|
6238
|
-
[
|
|
6239
|
-
topRulerXStart,
|
|
6240
|
-
topRulerY - extLen,
|
|
6241
|
-
topRulerXStart,
|
|
6242
|
-
topRulerY + extLen
|
|
6243
|
-
],
|
|
6244
|
-
{
|
|
6245
|
-
stroke: lineColor,
|
|
6246
|
-
strokeWidth: 1,
|
|
6247
|
-
selectable: false,
|
|
6248
|
-
evented: false
|
|
6249
|
-
}
|
|
6250
|
-
)
|
|
6251
|
-
);
|
|
6252
|
-
layer.add(
|
|
6253
|
-
new Line(
|
|
6254
|
-
[topRulerXEnd, topRulerY - extLen, topRulerXEnd, topRulerY + extLen],
|
|
6255
|
-
{
|
|
6256
|
-
stroke: lineColor,
|
|
6257
|
-
strokeWidth: 1,
|
|
6258
|
-
selectable: false,
|
|
6259
|
-
evented: false
|
|
6260
|
-
}
|
|
6261
|
-
)
|
|
6262
|
-
);
|
|
6263
|
-
const widthStr = formatMm(displayWidthMm, displayUnit);
|
|
6264
|
-
const topTextContent = `${widthStr} ${displayUnit}`;
|
|
6265
|
-
const topText = new Text(topTextContent, {
|
|
6266
|
-
left: topRulerXStart + (rulerRight - rulerLeft) / 2,
|
|
6267
|
-
top: topRulerY,
|
|
6268
|
-
fontSize,
|
|
6269
|
-
fill: textColor,
|
|
6270
|
-
fontFamily: "Arial",
|
|
6271
|
-
originX: "center",
|
|
6272
|
-
originY: "center",
|
|
6273
|
-
backgroundColor,
|
|
6274
|
-
// Background mask for readability
|
|
6275
|
-
selectable: false,
|
|
6276
|
-
evented: false
|
|
7168
|
+
this.log("render:start", {
|
|
7169
|
+
seq,
|
|
7170
|
+
unit: sizeState.unit,
|
|
7171
|
+
gap: this.gap,
|
|
7172
|
+
thickness: this.thickness,
|
|
7173
|
+
fontSize: this.fontSize,
|
|
7174
|
+
hasLayout: !!layout,
|
|
7175
|
+
scale: (_b = layout == null ? void 0 : layout.scale) != null ? _b : null
|
|
6277
7176
|
});
|
|
6278
|
-
|
|
6279
|
-
|
|
6280
|
-
|
|
6281
|
-
|
|
6282
|
-
|
|
6283
|
-
|
|
6284
|
-
|
|
6285
|
-
);
|
|
6286
|
-
|
|
6287
|
-
|
|
6288
|
-
|
|
6289
|
-
|
|
6290
|
-
|
|
6291
|
-
|
|
6292
|
-
leftRulerX + extLen,
|
|
6293
|
-
leftRulerYStart
|
|
6294
|
-
],
|
|
6295
|
-
{
|
|
6296
|
-
stroke: lineColor,
|
|
6297
|
-
strokeWidth: 1,
|
|
6298
|
-
selectable: false,
|
|
6299
|
-
evented: false
|
|
6300
|
-
}
|
|
6301
|
-
)
|
|
6302
|
-
);
|
|
6303
|
-
layer.add(
|
|
6304
|
-
new Line(
|
|
6305
|
-
[
|
|
6306
|
-
leftRulerX - extLen,
|
|
6307
|
-
leftRulerYEnd,
|
|
6308
|
-
leftRulerX + extLen,
|
|
6309
|
-
leftRulerYEnd
|
|
6310
|
-
],
|
|
6311
|
-
{
|
|
6312
|
-
stroke: lineColor,
|
|
6313
|
-
strokeWidth: 1,
|
|
6314
|
-
selectable: false,
|
|
6315
|
-
evented: false
|
|
6316
|
-
}
|
|
6317
|
-
)
|
|
6318
|
-
);
|
|
6319
|
-
const heightStr = formatMm(displayHeightMm, displayUnit);
|
|
6320
|
-
const leftTextContent = `${heightStr} ${displayUnit}`;
|
|
6321
|
-
const leftText = new Text(leftTextContent, {
|
|
6322
|
-
left: leftRulerX,
|
|
6323
|
-
top: leftRulerYStart + (rulerBottom - rulerTop) / 2,
|
|
6324
|
-
angle: -90,
|
|
6325
|
-
fontSize,
|
|
6326
|
-
fill: textColor,
|
|
6327
|
-
fontFamily: "Arial",
|
|
6328
|
-
originX: "center",
|
|
6329
|
-
originY: "center",
|
|
6330
|
-
backgroundColor,
|
|
6331
|
-
selectable: false,
|
|
6332
|
-
evented: false
|
|
7177
|
+
if (!layout || layout.scale <= 0) {
|
|
7178
|
+
if (seq !== this.renderSeq) return;
|
|
7179
|
+
this.log("render:skip", { seq, reason: "invalid-layout" });
|
|
7180
|
+
this.specs = [];
|
|
7181
|
+
await this.canvasService.flushRenderFromProducers();
|
|
7182
|
+
return;
|
|
7183
|
+
}
|
|
7184
|
+
const geometry = buildSceneGeometry(configService, layout);
|
|
7185
|
+
if (geometry.unit !== "px") {
|
|
7186
|
+
console.warn("[RulerTool] Unexpected geometry unit.", geometry.unit);
|
|
7187
|
+
}
|
|
7188
|
+
const centerScene = this.canvasService.toScenePoint({
|
|
7189
|
+
x: geometry.x,
|
|
7190
|
+
y: geometry.y
|
|
6333
7191
|
});
|
|
6334
|
-
|
|
6335
|
-
this.canvasService.
|
|
6336
|
-
|
|
7192
|
+
const widthScene = this.canvasService.toSceneLength(geometry.width);
|
|
7193
|
+
const heightScene = this.canvasService.toSceneLength(geometry.height);
|
|
7194
|
+
const rulerLeft = centerScene.x - widthScene / 2;
|
|
7195
|
+
const rulerTop = centerScene.y - heightScene / 2;
|
|
7196
|
+
const rulerRight = rulerLeft + widthScene;
|
|
7197
|
+
const rulerBottom = rulerTop + heightScene;
|
|
7198
|
+
const widthMm = widthScene;
|
|
7199
|
+
const heightMm = heightScene;
|
|
7200
|
+
const unit = sizeState.unit;
|
|
7201
|
+
const widthLabel = `${this.formatLengthMm(widthMm, unit)} ${unit}`;
|
|
7202
|
+
const heightLabel = `${this.formatLengthMm(heightMm, unit)} ${unit}`;
|
|
7203
|
+
const specs = this.buildRulerSpecs({
|
|
7204
|
+
left: rulerLeft,
|
|
7205
|
+
top: rulerTop,
|
|
7206
|
+
right: rulerRight,
|
|
7207
|
+
bottom: rulerBottom,
|
|
7208
|
+
widthLabel,
|
|
7209
|
+
heightLabel
|
|
7210
|
+
});
|
|
7211
|
+
this.log("render:geometry", {
|
|
7212
|
+
seq,
|
|
7213
|
+
left: rulerLeft,
|
|
7214
|
+
top: rulerTop,
|
|
7215
|
+
right: rulerRight,
|
|
7216
|
+
bottom: rulerBottom,
|
|
7217
|
+
widthScene,
|
|
7218
|
+
heightScene,
|
|
7219
|
+
widthMm,
|
|
7220
|
+
heightMm,
|
|
7221
|
+
specCount: specs.length
|
|
7222
|
+
});
|
|
7223
|
+
if (seq !== this.renderSeq) return;
|
|
7224
|
+
this.specs = specs;
|
|
7225
|
+
await this.canvasService.flushRenderFromProducers();
|
|
7226
|
+
if (seq !== this.renderSeq) return;
|
|
7227
|
+
this.canvasService.bringLayerToFront(RULER_LAYER_ID);
|
|
7228
|
+
this.canvasService.requestRenderAll();
|
|
7229
|
+
this.log("render:done", { seq });
|
|
6337
7230
|
}
|
|
6338
7231
|
};
|
|
6339
7232
|
|
|
@@ -6372,6 +7265,9 @@ var WhiteInkTool = class {
|
|
|
6372
7265
|
this.printWithWhiteInk = true;
|
|
6373
7266
|
this.previewImageVisible = true;
|
|
6374
7267
|
this.renderSeq = 0;
|
|
7268
|
+
this.whiteSpecs = [];
|
|
7269
|
+
this.coverSpecs = [];
|
|
7270
|
+
this.overlaySpecs = [];
|
|
6375
7271
|
this.onToolActivated = (event) => {
|
|
6376
7272
|
const before = this.isToolActive;
|
|
6377
7273
|
this.syncToolActiveFromWorkbench(event.id);
|
|
@@ -6409,12 +7305,25 @@ var WhiteInkTool = class {
|
|
|
6409
7305
|
};
|
|
6410
7306
|
}
|
|
6411
7307
|
activate(context) {
|
|
7308
|
+
var _a;
|
|
6412
7309
|
this.context = context;
|
|
6413
7310
|
this.canvasService = context.services.get("CanvasService");
|
|
6414
7311
|
if (!this.canvasService) {
|
|
6415
7312
|
console.warn("CanvasService not found for WhiteInkTool");
|
|
6416
7313
|
return;
|
|
6417
7314
|
}
|
|
7315
|
+
(_a = this.renderProducerDisposable) == null ? void 0 : _a.dispose();
|
|
7316
|
+
this.renderProducerDisposable = this.canvasService.registerRenderProducer(
|
|
7317
|
+
this.id,
|
|
7318
|
+
() => ({
|
|
7319
|
+
rootLayerSpecs: {
|
|
7320
|
+
[WHITE_INK_OBJECT_LAYER_ID]: this.whiteSpecs,
|
|
7321
|
+
[WHITE_INK_COVER_LAYER_ID]: this.coverSpecs,
|
|
7322
|
+
[WHITE_INK_OVERLAY_LAYER_ID]: this.overlaySpecs
|
|
7323
|
+
}
|
|
7324
|
+
}),
|
|
7325
|
+
{ priority: 260 }
|
|
7326
|
+
);
|
|
6418
7327
|
context.eventBus.on("tool:activated", this.onToolActivated);
|
|
6419
7328
|
context.eventBus.on("scene:layout:change", this.onSceneLayoutChanged);
|
|
6420
7329
|
context.eventBus.on("object:added", this.onObjectAdded);
|
|
@@ -6480,7 +7389,7 @@ var WhiteInkTool = class {
|
|
|
6480
7389
|
this.updateWhiteInks();
|
|
6481
7390
|
}
|
|
6482
7391
|
deactivate(context) {
|
|
6483
|
-
var _a;
|
|
7392
|
+
var _a, _b;
|
|
6484
7393
|
context.eventBus.off("tool:activated", this.onToolActivated);
|
|
6485
7394
|
context.eventBus.off("scene:layout:change", this.onSceneLayoutChanged);
|
|
6486
7395
|
context.eventBus.off("object:added", this.onObjectAdded);
|
|
@@ -6491,6 +7400,11 @@ var WhiteInkTool = class {
|
|
|
6491
7400
|
this.dirtyTrackerDisposable = void 0;
|
|
6492
7401
|
this.clearRenderedWhiteInks();
|
|
6493
7402
|
this.applyImageVisibilityForWhiteInk(false);
|
|
7403
|
+
(_b = this.renderProducerDisposable) == null ? void 0 : _b.dispose();
|
|
7404
|
+
this.renderProducerDisposable = void 0;
|
|
7405
|
+
if (this.canvasService) {
|
|
7406
|
+
void this.canvasService.flushRenderFromProducers();
|
|
7407
|
+
}
|
|
6494
7408
|
this.canvasService = void 0;
|
|
6495
7409
|
this.context = void 0;
|
|
6496
7410
|
}
|
|
@@ -6913,11 +7827,20 @@ var WhiteInkTool = class {
|
|
|
6913
7827
|
if (!layout) {
|
|
6914
7828
|
return { left: 0, top: 0, width: 0, height: 0 };
|
|
6915
7829
|
}
|
|
6916
|
-
return {
|
|
7830
|
+
return this.canvasService.toSceneRect({
|
|
6917
7831
|
left: layout.cutRect.left,
|
|
6918
7832
|
top: layout.cutRect.top,
|
|
6919
7833
|
width: layout.cutRect.width,
|
|
6920
7834
|
height: layout.cutRect.height
|
|
7835
|
+
});
|
|
7836
|
+
}
|
|
7837
|
+
toLayoutSceneRect(rect) {
|
|
7838
|
+
return {
|
|
7839
|
+
left: rect.left,
|
|
7840
|
+
top: rect.top,
|
|
7841
|
+
width: rect.width,
|
|
7842
|
+
height: rect.height,
|
|
7843
|
+
space: "scene"
|
|
6921
7844
|
};
|
|
6922
7845
|
}
|
|
6923
7846
|
getImageObjects() {
|
|
@@ -6940,7 +7863,7 @@ var WhiteInkTool = class {
|
|
|
6940
7863
|
return (_a = obj == null ? void 0 : obj._originalElement) == null ? void 0 : _a.src;
|
|
6941
7864
|
}
|
|
6942
7865
|
getImageSnapshot(obj) {
|
|
6943
|
-
var _a;
|
|
7866
|
+
var _a, _b;
|
|
6944
7867
|
if (!obj) return null;
|
|
6945
7868
|
const src = this.getCurrentSrc(obj);
|
|
6946
7869
|
if (!src) return null;
|
|
@@ -6948,14 +7871,18 @@ var WhiteInkTool = class {
|
|
|
6948
7871
|
const width = Number((obj == null ? void 0 : obj.width) || 0);
|
|
6949
7872
|
const height = Number((obj == null ? void 0 : obj.height) || 0);
|
|
6950
7873
|
this.rememberSourceSize(src, { width, height });
|
|
7874
|
+
const sceneScale = ((_a = this.canvasService) == null ? void 0 : _a.getSceneScale()) || 1;
|
|
7875
|
+
const leftScreen = Number.isFinite(obj == null ? void 0 : obj.left) ? Number(obj.left) : 0;
|
|
7876
|
+
const topScreen = Number.isFinite(obj == null ? void 0 : obj.top) ? Number(obj.top) : 0;
|
|
7877
|
+
const scenePoint = this.canvasService ? this.canvasService.toScenePoint({ x: leftScreen, y: topScreen }) : { x: leftScreen, y: topScreen };
|
|
6951
7878
|
return {
|
|
6952
|
-
id: String(((
|
|
7879
|
+
id: String(((_b = obj == null ? void 0 : obj.data) == null ? void 0 : _b.id) || "image"),
|
|
6953
7880
|
src,
|
|
6954
7881
|
element,
|
|
6955
|
-
left:
|
|
6956
|
-
top:
|
|
6957
|
-
scaleX: Number.isFinite(obj == null ? void 0 : obj.scaleX) ? Number(obj.scaleX) : 1,
|
|
6958
|
-
scaleY: Number.isFinite(obj == null ? void 0 : obj.scaleY) ? Number(obj.scaleY) : 1,
|
|
7882
|
+
left: scenePoint.x,
|
|
7883
|
+
top: scenePoint.y,
|
|
7884
|
+
scaleX: (Number.isFinite(obj == null ? void 0 : obj.scaleX) ? Number(obj.scaleX) : 1) / sceneScale,
|
|
7885
|
+
scaleY: (Number.isFinite(obj == null ? void 0 : obj.scaleY) ? Number(obj.scaleY) : 1) / sceneScale,
|
|
6959
7886
|
angle: Number.isFinite(obj == null ? void 0 : obj.angle) ? Number(obj.angle) : 0,
|
|
6960
7887
|
originX: typeof (obj == null ? void 0 : obj.originX) === "string" ? obj.originX : "center",
|
|
6961
7888
|
originY: typeof (obj == null ? void 0 : obj.originY) === "string" ? obj.originY : "center",
|
|
@@ -7130,8 +8057,11 @@ var WhiteInkTool = class {
|
|
|
7130
8057
|
var _a, _b;
|
|
7131
8058
|
if (!this.isToolActive || !this.canvasService) return [];
|
|
7132
8059
|
if (frame.width <= 0 || frame.height <= 0) return [];
|
|
7133
|
-
const
|
|
7134
|
-
const
|
|
8060
|
+
const viewport = this.canvasService.getSceneViewportRect();
|
|
8061
|
+
const canvasW = viewport.width || 0;
|
|
8062
|
+
const canvasH = viewport.height || 0;
|
|
8063
|
+
const canvasLeft = viewport.left || 0;
|
|
8064
|
+
const canvasTop = viewport.top || 0;
|
|
7135
8065
|
const strokeColor = this.getConfig("image.frame.strokeColor", "#808080") || "#808080";
|
|
7136
8066
|
const strokeWidthRaw = Number(
|
|
7137
8067
|
(_a = this.getConfig("image.frame.strokeWidth", 2)) != null ? _a : 2
|
|
@@ -7143,21 +8073,42 @@ var WhiteInkTool = class {
|
|
|
7143
8073
|
const innerBackground = this.getConfig("image.frame.innerBackground", "rgba(0,0,0,0)") || "rgba(0,0,0,0)";
|
|
7144
8074
|
const strokeWidth = Number.isFinite(strokeWidthRaw) ? Math.max(0, strokeWidthRaw) : 2;
|
|
7145
8075
|
const dashLength = Number.isFinite(dashLengthRaw) ? Math.max(1, dashLengthRaw) : 8;
|
|
7146
|
-
const
|
|
7147
|
-
const
|
|
8076
|
+
const strokeWidthScene = this.canvasService.toSceneLength(strokeWidth);
|
|
8077
|
+
const dashLengthScene = this.canvasService.toSceneLength(dashLength);
|
|
8078
|
+
const frameLeft = Math.max(
|
|
8079
|
+
canvasLeft,
|
|
8080
|
+
Math.min(canvasLeft + canvasW, frame.left)
|
|
8081
|
+
);
|
|
8082
|
+
const frameTop = Math.max(
|
|
8083
|
+
canvasTop,
|
|
8084
|
+
Math.min(canvasTop + canvasH, frame.top)
|
|
8085
|
+
);
|
|
7148
8086
|
const frameRight = Math.max(
|
|
7149
8087
|
frameLeft,
|
|
7150
|
-
Math.min(canvasW, frame.left + frame.width)
|
|
8088
|
+
Math.min(canvasLeft + canvasW, frame.left + frame.width)
|
|
7151
8089
|
);
|
|
7152
8090
|
const frameBottom = Math.max(
|
|
7153
8091
|
frameTop,
|
|
7154
|
-
Math.min(canvasH, frame.top + frame.height)
|
|
8092
|
+
Math.min(canvasTop + canvasH, frame.top + frame.height)
|
|
7155
8093
|
);
|
|
7156
8094
|
const visibleFrameH = Math.max(0, frameBottom - frameTop);
|
|
7157
|
-
const topH = frameTop;
|
|
7158
|
-
const bottomH = Math.max(0, canvasH - frameBottom);
|
|
7159
|
-
const leftW = frameLeft;
|
|
7160
|
-
const rightW = Math.max(0, canvasW - frameRight);
|
|
8095
|
+
const topH = Math.max(0, frameTop - canvasTop);
|
|
8096
|
+
const bottomH = Math.max(0, canvasTop + canvasH - frameBottom);
|
|
8097
|
+
const leftW = Math.max(0, frameLeft - canvasLeft);
|
|
8098
|
+
const rightW = Math.max(0, canvasLeft + canvasW - frameRight);
|
|
8099
|
+
const viewportRect = this.toLayoutSceneRect({
|
|
8100
|
+
left: canvasLeft,
|
|
8101
|
+
top: canvasTop,
|
|
8102
|
+
width: canvasW,
|
|
8103
|
+
height: canvasH
|
|
8104
|
+
});
|
|
8105
|
+
const visibleFrameBandRect = this.toLayoutSceneRect({
|
|
8106
|
+
left: canvasLeft,
|
|
8107
|
+
top: frameTop,
|
|
8108
|
+
width: canvasW,
|
|
8109
|
+
height: visibleFrameH
|
|
8110
|
+
});
|
|
8111
|
+
const frameRect = this.toLayoutSceneRect(frame);
|
|
7161
8112
|
const maskSpecs = [
|
|
7162
8113
|
{
|
|
7163
8114
|
id: "white-ink.cropMask.top",
|
|
@@ -7167,13 +8118,17 @@ var WhiteInkTool = class {
|
|
|
7167
8118
|
layerId: WHITE_INK_OVERLAY_LAYER_ID,
|
|
7168
8119
|
type: "white-ink-mask"
|
|
7169
8120
|
},
|
|
8121
|
+
layout: {
|
|
8122
|
+
reference: "custom",
|
|
8123
|
+
referenceRect: viewportRect,
|
|
8124
|
+
alignX: "start",
|
|
8125
|
+
alignY: "start",
|
|
8126
|
+
width: "100%",
|
|
8127
|
+
height: topH
|
|
8128
|
+
},
|
|
7170
8129
|
props: {
|
|
7171
|
-
|
|
7172
|
-
|
|
7173
|
-
width: canvasW,
|
|
7174
|
-
height: topH,
|
|
7175
|
-
originX: "center",
|
|
7176
|
-
originY: "center",
|
|
8130
|
+
originX: "left",
|
|
8131
|
+
originY: "top",
|
|
7177
8132
|
fill: outerBackground,
|
|
7178
8133
|
selectable: false,
|
|
7179
8134
|
evented: false,
|
|
@@ -7188,13 +8143,17 @@ var WhiteInkTool = class {
|
|
|
7188
8143
|
layerId: WHITE_INK_OVERLAY_LAYER_ID,
|
|
7189
8144
|
type: "white-ink-mask"
|
|
7190
8145
|
},
|
|
8146
|
+
layout: {
|
|
8147
|
+
reference: "custom",
|
|
8148
|
+
referenceRect: viewportRect,
|
|
8149
|
+
alignX: "start",
|
|
8150
|
+
alignY: "end",
|
|
8151
|
+
width: "100%",
|
|
8152
|
+
height: bottomH
|
|
8153
|
+
},
|
|
7191
8154
|
props: {
|
|
7192
|
-
|
|
7193
|
-
|
|
7194
|
-
width: canvasW,
|
|
7195
|
-
height: bottomH,
|
|
7196
|
-
originX: "center",
|
|
7197
|
-
originY: "center",
|
|
8155
|
+
originX: "left",
|
|
8156
|
+
originY: "top",
|
|
7198
8157
|
fill: outerBackground,
|
|
7199
8158
|
selectable: false,
|
|
7200
8159
|
evented: false,
|
|
@@ -7209,13 +8168,17 @@ var WhiteInkTool = class {
|
|
|
7209
8168
|
layerId: WHITE_INK_OVERLAY_LAYER_ID,
|
|
7210
8169
|
type: "white-ink-mask"
|
|
7211
8170
|
},
|
|
7212
|
-
|
|
7213
|
-
|
|
7214
|
-
|
|
8171
|
+
layout: {
|
|
8172
|
+
reference: "custom",
|
|
8173
|
+
referenceRect: visibleFrameBandRect,
|
|
8174
|
+
alignX: "start",
|
|
8175
|
+
alignY: "start",
|
|
7215
8176
|
width: leftW,
|
|
7216
|
-
height:
|
|
7217
|
-
|
|
7218
|
-
|
|
8177
|
+
height: "100%"
|
|
8178
|
+
},
|
|
8179
|
+
props: {
|
|
8180
|
+
originX: "left",
|
|
8181
|
+
originY: "top",
|
|
7219
8182
|
fill: outerBackground,
|
|
7220
8183
|
selectable: false,
|
|
7221
8184
|
evented: false,
|
|
@@ -7230,13 +8193,17 @@ var WhiteInkTool = class {
|
|
|
7230
8193
|
layerId: WHITE_INK_OVERLAY_LAYER_ID,
|
|
7231
8194
|
type: "white-ink-mask"
|
|
7232
8195
|
},
|
|
7233
|
-
|
|
7234
|
-
|
|
7235
|
-
|
|
8196
|
+
layout: {
|
|
8197
|
+
reference: "custom",
|
|
8198
|
+
referenceRect: visibleFrameBandRect,
|
|
8199
|
+
alignX: "end",
|
|
8200
|
+
alignY: "start",
|
|
7236
8201
|
width: rightW,
|
|
7237
|
-
height:
|
|
7238
|
-
|
|
7239
|
-
|
|
8202
|
+
height: "100%"
|
|
8203
|
+
},
|
|
8204
|
+
props: {
|
|
8205
|
+
originX: "left",
|
|
8206
|
+
originY: "top",
|
|
7240
8207
|
fill: outerBackground,
|
|
7241
8208
|
selectable: false,
|
|
7242
8209
|
evented: false,
|
|
@@ -7254,17 +8221,21 @@ var WhiteInkTool = class {
|
|
|
7254
8221
|
layerId: WHITE_INK_OVERLAY_LAYER_ID,
|
|
7255
8222
|
type: "white-ink-frame"
|
|
7256
8223
|
},
|
|
8224
|
+
layout: {
|
|
8225
|
+
reference: "custom",
|
|
8226
|
+
referenceRect: frameRect,
|
|
8227
|
+
alignX: "start",
|
|
8228
|
+
alignY: "start",
|
|
8229
|
+
width: "100%",
|
|
8230
|
+
height: "100%"
|
|
8231
|
+
},
|
|
7257
8232
|
props: {
|
|
7258
|
-
|
|
7259
|
-
|
|
7260
|
-
width: frame.width,
|
|
7261
|
-
height: frame.height,
|
|
7262
|
-
originX: "center",
|
|
7263
|
-
originY: "center",
|
|
8233
|
+
originX: "left",
|
|
8234
|
+
originY: "top",
|
|
7264
8235
|
fill: innerBackground,
|
|
7265
8236
|
stroke: strokeColor,
|
|
7266
|
-
strokeWidth,
|
|
7267
|
-
strokeDashArray: [
|
|
8237
|
+
strokeWidth: strokeWidthScene,
|
|
8238
|
+
strokeDashArray: [dashLengthScene, dashLengthScene],
|
|
7268
8239
|
selectable: false,
|
|
7269
8240
|
evented: false,
|
|
7270
8241
|
excludeFromExport: true
|
|
@@ -7340,50 +8311,30 @@ var WhiteInkTool = class {
|
|
|
7340
8311
|
}
|
|
7341
8312
|
).filter((index) => index >= 0);
|
|
7342
8313
|
let whiteInsertIndex = imageIndexes.length ? Math.min(...imageIndexes) : this.resolveDefaultInsertIndex(currentObjects);
|
|
7343
|
-
|
|
7344
|
-
canvas.moveObjectTo(obj, whiteInsertIndex);
|
|
7345
|
-
whiteInsertIndex += 1;
|
|
7346
|
-
});
|
|
7347
|
-
const afterWhiteObjects = canvas.getObjects();
|
|
7348
|
-
const afterImageIndexes = afterWhiteObjects.map(
|
|
7349
|
-
(obj, index) => {
|
|
7350
|
-
var _a;
|
|
7351
|
-
return ((_a = obj == null ? void 0 : obj.data) == null ? void 0 : _a.layerId) === IMAGE_OBJECT_LAYER_ID3 ? index : -1;
|
|
7352
|
-
}
|
|
7353
|
-
).filter((index) => index >= 0);
|
|
7354
|
-
let coverInsertIndex = afterImageIndexes.length ? Math.max(...afterImageIndexes) + 1 : whiteInsertIndex;
|
|
8314
|
+
let coverInsertIndex = whiteInsertIndex;
|
|
7355
8315
|
coverObjects.forEach((obj) => {
|
|
7356
8316
|
canvas.moveObjectTo(obj, coverInsertIndex);
|
|
7357
8317
|
coverInsertIndex += 1;
|
|
7358
8318
|
});
|
|
8319
|
+
whiteInsertIndex = coverInsertIndex;
|
|
8320
|
+
whiteObjects.forEach((obj) => {
|
|
8321
|
+
canvas.moveObjectTo(obj, whiteInsertIndex);
|
|
8322
|
+
whiteInsertIndex += 1;
|
|
8323
|
+
});
|
|
7359
8324
|
frameObjects.forEach((obj) => canvas.bringObjectToFront(obj));
|
|
7360
8325
|
canvas.getObjects().filter((obj) => {
|
|
7361
8326
|
var _a;
|
|
7362
8327
|
return ((_a = obj == null ? void 0 : obj.data) == null ? void 0 : _a.layerId) === IMAGE_OVERLAY_LAYER_ID2;
|
|
7363
8328
|
}).forEach((obj) => canvas.bringObjectToFront(obj));
|
|
7364
|
-
|
|
7365
|
-
|
|
7366
|
-
canvas.bringObjectToFront(dielineOverlay);
|
|
7367
|
-
}
|
|
7368
|
-
const rulerOverlay = this.canvasService.getLayer("ruler-overlay");
|
|
7369
|
-
if (rulerOverlay) {
|
|
7370
|
-
canvas.bringObjectToFront(rulerOverlay);
|
|
7371
|
-
}
|
|
8329
|
+
this.canvasService.bringLayerToFront("dieline-overlay");
|
|
8330
|
+
this.canvasService.bringLayerToFront("ruler-overlay");
|
|
7372
8331
|
}
|
|
7373
8332
|
clearRenderedWhiteInks() {
|
|
7374
8333
|
if (!this.canvasService) return;
|
|
7375
|
-
|
|
7376
|
-
|
|
7377
|
-
|
|
7378
|
-
);
|
|
7379
|
-
void this.canvasService.applyObjectSpecsToRootLayer(
|
|
7380
|
-
WHITE_INK_COVER_LAYER_ID,
|
|
7381
|
-
[]
|
|
7382
|
-
);
|
|
7383
|
-
void this.canvasService.applyObjectSpecsToRootLayer(
|
|
7384
|
-
WHITE_INK_OVERLAY_LAYER_ID,
|
|
7385
|
-
[]
|
|
7386
|
-
);
|
|
8334
|
+
this.whiteSpecs = [];
|
|
8335
|
+
this.coverSpecs = [];
|
|
8336
|
+
this.overlaySpecs = [];
|
|
8337
|
+
this.canvasService.requestRenderFromProducers();
|
|
7387
8338
|
}
|
|
7388
8339
|
purgeSourceCaches(item) {
|
|
7389
8340
|
const sourceUrl = this.resolveSourceUrl(item);
|
|
@@ -7450,20 +8401,12 @@ var WhiteInkTool = class {
|
|
|
7450
8401
|
}
|
|
7451
8402
|
}
|
|
7452
8403
|
}
|
|
7453
|
-
|
|
7454
|
-
WHITE_INK_OBJECT_LAYER_ID,
|
|
7455
|
-
whiteSpecs
|
|
7456
|
-
);
|
|
8404
|
+
this.whiteSpecs = whiteSpecs;
|
|
7457
8405
|
if (seq !== this.renderSeq) return;
|
|
7458
|
-
|
|
7459
|
-
WHITE_INK_COVER_LAYER_ID,
|
|
7460
|
-
coverSpecs
|
|
7461
|
-
);
|
|
8406
|
+
this.coverSpecs = coverSpecs;
|
|
7462
8407
|
if (seq !== this.renderSeq) return;
|
|
7463
|
-
|
|
7464
|
-
|
|
7465
|
-
frameSpecs
|
|
7466
|
-
);
|
|
8408
|
+
this.overlaySpecs = frameSpecs;
|
|
8409
|
+
await this.canvasService.flushRenderFromProducers();
|
|
7467
8410
|
if (seq !== this.renderSeq) return;
|
|
7468
8411
|
this.syncZOrder();
|
|
7469
8412
|
this.canvasService.requestRenderAll();
|
|
@@ -7696,23 +8639,16 @@ var SceneVisibilityService = class {
|
|
|
7696
8639
|
const dielineLayer = this.canvasService.getLayer("dieline-overlay");
|
|
7697
8640
|
if (dielineLayer) {
|
|
7698
8641
|
const visible = !HIDDEN_DIELINE_TOOLS.has(this.activeToolId || "");
|
|
7699
|
-
|
|
7700
|
-
dielineLayer.set({ visible });
|
|
7701
|
-
}
|
|
7702
|
-
}
|
|
7703
|
-
const rulerLayer = this.canvasService.getLayer("ruler-overlay");
|
|
7704
|
-
if (rulerLayer) {
|
|
7705
|
-
const visible = !HIDDEN_RULER_TOOLS.has(this.activeToolId || "");
|
|
7706
|
-
if (rulerLayer.visible !== visible) {
|
|
7707
|
-
rulerLayer.set({ visible });
|
|
7708
|
-
}
|
|
8642
|
+
this.canvasService.setLayerVisibility("dieline-overlay", visible);
|
|
7709
8643
|
}
|
|
8644
|
+
const rulerVisible = !HIDDEN_RULER_TOOLS.has(this.activeToolId || "");
|
|
8645
|
+
this.canvasService.setLayerVisibility("ruler-overlay", rulerVisible);
|
|
7710
8646
|
this.canvasService.requestRenderAll();
|
|
7711
8647
|
}
|
|
7712
8648
|
};
|
|
7713
8649
|
|
|
7714
8650
|
// src/services/CanvasService.ts
|
|
7715
|
-
import { Canvas, Group
|
|
8651
|
+
import { Canvas, Group, Rect, Path as Path2, Image as Image2, Text } from "fabric";
|
|
7716
8652
|
|
|
7717
8653
|
// src/services/ViewportSystem.ts
|
|
7718
8654
|
var ViewportSystem = class {
|
|
@@ -7790,6 +8726,13 @@ var ViewportSystem = class {
|
|
|
7790
8726
|
// src/services/CanvasService.ts
|
|
7791
8727
|
var CanvasService = class {
|
|
7792
8728
|
constructor(el, options) {
|
|
8729
|
+
this.renderProducers = /* @__PURE__ */ new Map();
|
|
8730
|
+
this.producerOrder = 0;
|
|
8731
|
+
this.producerFlushRequested = false;
|
|
8732
|
+
this.producerLoopPending = false;
|
|
8733
|
+
this.producerLoopPromise = null;
|
|
8734
|
+
this.managedProducerLayerIds = /* @__PURE__ */ new Set();
|
|
8735
|
+
this.managedProducerRootLayerIds = /* @__PURE__ */ new Set();
|
|
7793
8736
|
if (el instanceof Canvas) {
|
|
7794
8737
|
this.canvas = el;
|
|
7795
8738
|
} else {
|
|
@@ -7822,8 +8765,156 @@ var CanvasService = class {
|
|
|
7822
8765
|
this.canvas.on("object:removed", forward("object:removed"));
|
|
7823
8766
|
}
|
|
7824
8767
|
dispose() {
|
|
8768
|
+
this.renderProducers.clear();
|
|
8769
|
+
this.managedProducerLayerIds.clear();
|
|
8770
|
+
this.managedProducerRootLayerIds.clear();
|
|
8771
|
+
this.producerFlushRequested = false;
|
|
7825
8772
|
this.canvas.dispose();
|
|
7826
8773
|
}
|
|
8774
|
+
registerRenderProducer(toolId, producer, options = {}) {
|
|
8775
|
+
const normalizedToolId = String(toolId || "").trim();
|
|
8776
|
+
if (!normalizedToolId) {
|
|
8777
|
+
throw new Error(
|
|
8778
|
+
"[CanvasService] registerRenderProducer requires a toolId."
|
|
8779
|
+
);
|
|
8780
|
+
}
|
|
8781
|
+
if (typeof producer !== "function") {
|
|
8782
|
+
throw new Error(
|
|
8783
|
+
`[CanvasService] registerRenderProducer("${normalizedToolId}") requires a producer function.`
|
|
8784
|
+
);
|
|
8785
|
+
}
|
|
8786
|
+
const entry = {
|
|
8787
|
+
toolId: normalizedToolId,
|
|
8788
|
+
producer,
|
|
8789
|
+
priority: Number.isFinite(options.priority) ? Number(options.priority) : 0,
|
|
8790
|
+
order: this.producerOrder++
|
|
8791
|
+
};
|
|
8792
|
+
this.renderProducers.set(normalizedToolId, entry);
|
|
8793
|
+
this.requestRenderFromProducers();
|
|
8794
|
+
return {
|
|
8795
|
+
dispose: () => {
|
|
8796
|
+
this.unregisterRenderProducer(normalizedToolId);
|
|
8797
|
+
}
|
|
8798
|
+
};
|
|
8799
|
+
}
|
|
8800
|
+
unregisterRenderProducer(toolId) {
|
|
8801
|
+
const normalizedToolId = String(toolId || "").trim();
|
|
8802
|
+
if (!normalizedToolId) return false;
|
|
8803
|
+
const removed = this.renderProducers.delete(normalizedToolId);
|
|
8804
|
+
if (removed) {
|
|
8805
|
+
this.requestRenderFromProducers();
|
|
8806
|
+
}
|
|
8807
|
+
return removed;
|
|
8808
|
+
}
|
|
8809
|
+
requestRenderFromProducers() {
|
|
8810
|
+
this.producerFlushRequested = true;
|
|
8811
|
+
this.scheduleProducerLoop();
|
|
8812
|
+
}
|
|
8813
|
+
async flushRenderFromProducers() {
|
|
8814
|
+
this.requestRenderFromProducers();
|
|
8815
|
+
if (this.producerLoopPromise) {
|
|
8816
|
+
await this.producerLoopPromise;
|
|
8817
|
+
}
|
|
8818
|
+
}
|
|
8819
|
+
scheduleProducerLoop() {
|
|
8820
|
+
if (this.producerLoopPending) return;
|
|
8821
|
+
this.producerLoopPending = true;
|
|
8822
|
+
this.producerLoopPromise = Promise.resolve().then(() => this.runProducerLoop()).catch((error) => {
|
|
8823
|
+
console.error("[CanvasService] render producer loop failed.", error);
|
|
8824
|
+
}).finally(() => {
|
|
8825
|
+
this.producerLoopPending = false;
|
|
8826
|
+
if (this.producerFlushRequested) {
|
|
8827
|
+
this.scheduleProducerLoop();
|
|
8828
|
+
}
|
|
8829
|
+
});
|
|
8830
|
+
}
|
|
8831
|
+
async runProducerLoop() {
|
|
8832
|
+
while (this.producerFlushRequested) {
|
|
8833
|
+
this.producerFlushRequested = false;
|
|
8834
|
+
await this.collectAndApplyProducerSpecs();
|
|
8835
|
+
}
|
|
8836
|
+
}
|
|
8837
|
+
sortedRenderProducerEntries() {
|
|
8838
|
+
return Array.from(this.renderProducers.values()).sort((a, b) => {
|
|
8839
|
+
if (a.priority !== b.priority) {
|
|
8840
|
+
return a.priority - b.priority;
|
|
8841
|
+
}
|
|
8842
|
+
if (a.order !== b.order) {
|
|
8843
|
+
return a.order - b.order;
|
|
8844
|
+
}
|
|
8845
|
+
return a.toolId.localeCompare(b.toolId);
|
|
8846
|
+
});
|
|
8847
|
+
}
|
|
8848
|
+
appendLayerSpecMap(map, source) {
|
|
8849
|
+
if (!source) return;
|
|
8850
|
+
Object.entries(source).forEach(([layerId, specs]) => {
|
|
8851
|
+
if (!Array.isArray(specs)) return;
|
|
8852
|
+
const list = map.get(layerId) || [];
|
|
8853
|
+
list.push(...specs);
|
|
8854
|
+
map.set(layerId, list);
|
|
8855
|
+
});
|
|
8856
|
+
}
|
|
8857
|
+
async collectAndApplyProducerSpecs() {
|
|
8858
|
+
const groupLayerSpecs = /* @__PURE__ */ new Map();
|
|
8859
|
+
const rootLayerSpecs = /* @__PURE__ */ new Map();
|
|
8860
|
+
const replaceLayerIds = /* @__PURE__ */ new Set();
|
|
8861
|
+
const replaceRootLayerIds = /* @__PURE__ */ new Set();
|
|
8862
|
+
const entries = this.sortedRenderProducerEntries();
|
|
8863
|
+
for (const entry of entries) {
|
|
8864
|
+
try {
|
|
8865
|
+
const result = await entry.producer();
|
|
8866
|
+
if (!result) continue;
|
|
8867
|
+
this.appendLayerSpecMap(groupLayerSpecs, result.layerSpecs);
|
|
8868
|
+
this.appendLayerSpecMap(rootLayerSpecs, result.rootLayerSpecs);
|
|
8869
|
+
if (Array.isArray(result.replaceLayerIds)) {
|
|
8870
|
+
result.replaceLayerIds.forEach((layerId) => {
|
|
8871
|
+
if (layerId) replaceLayerIds.add(layerId);
|
|
8872
|
+
});
|
|
8873
|
+
}
|
|
8874
|
+
if (Array.isArray(result.replaceRootLayerIds)) {
|
|
8875
|
+
result.replaceRootLayerIds.forEach((layerId) => {
|
|
8876
|
+
if (layerId) replaceRootLayerIds.add(layerId);
|
|
8877
|
+
});
|
|
8878
|
+
}
|
|
8879
|
+
} catch (error) {
|
|
8880
|
+
console.error(
|
|
8881
|
+
`[CanvasService] render producer "${entry.toolId}" failed.`,
|
|
8882
|
+
error
|
|
8883
|
+
);
|
|
8884
|
+
}
|
|
8885
|
+
}
|
|
8886
|
+
const nextLayerIds = new Set(groupLayerSpecs.keys());
|
|
8887
|
+
const nextRootLayerIds = new Set(rootLayerSpecs.keys());
|
|
8888
|
+
for (const [layerId, specs] of groupLayerSpecs.entries()) {
|
|
8889
|
+
if (replaceLayerIds.has(layerId)) {
|
|
8890
|
+
const layer = this.getLayer(layerId);
|
|
8891
|
+
if (layer) {
|
|
8892
|
+
layer.getObjects().forEach((obj) => layer.remove(obj));
|
|
8893
|
+
}
|
|
8894
|
+
}
|
|
8895
|
+
await this.applyObjectSpecsToLayer(layerId, specs, { render: false });
|
|
8896
|
+
}
|
|
8897
|
+
for (const layerId of this.managedProducerLayerIds) {
|
|
8898
|
+
if (nextLayerIds.has(layerId)) continue;
|
|
8899
|
+
const layer = this.getLayer(layerId);
|
|
8900
|
+
if (!layer) continue;
|
|
8901
|
+
await this.applyObjectSpecsToContainer(layer, [], { render: false });
|
|
8902
|
+
}
|
|
8903
|
+
for (const [layerId, specs] of rootLayerSpecs.entries()) {
|
|
8904
|
+
if (replaceRootLayerIds.has(layerId)) {
|
|
8905
|
+
const existing = this.getRootLayerObjects(layerId);
|
|
8906
|
+
existing.forEach((obj) => this.canvas.remove(obj));
|
|
8907
|
+
}
|
|
8908
|
+
await this.applyObjectSpecsToRootLayer(layerId, specs, { render: false });
|
|
8909
|
+
}
|
|
8910
|
+
for (const layerId of this.managedProducerRootLayerIds) {
|
|
8911
|
+
if (nextRootLayerIds.has(layerId)) continue;
|
|
8912
|
+
await this.applyObjectSpecsToRootLayer(layerId, [], { render: false });
|
|
8913
|
+
}
|
|
8914
|
+
this.managedProducerLayerIds = nextLayerIds;
|
|
8915
|
+
this.managedProducerRootLayerIds = nextRootLayerIds;
|
|
8916
|
+
this.requestRenderAll();
|
|
8917
|
+
}
|
|
7827
8918
|
/**
|
|
7828
8919
|
* Get a layer (Group) by its ID.
|
|
7829
8920
|
* We assume layers are Groups directly on the canvas with a data.id property.
|
|
@@ -7846,7 +8937,7 @@ var CanvasService = class {
|
|
|
7846
8937
|
...options,
|
|
7847
8938
|
data: { ...options.data, id }
|
|
7848
8939
|
};
|
|
7849
|
-
layer = new
|
|
8940
|
+
layer = new Group([], defaultOptions);
|
|
7850
8941
|
this.canvas.add(layer);
|
|
7851
8942
|
}
|
|
7852
8943
|
return layer;
|
|
@@ -7878,13 +8969,206 @@ var CanvasService = class {
|
|
|
7878
8969
|
(_a = this.eventBus) == null ? void 0 : _a.emit("canvas:resized", { width, height });
|
|
7879
8970
|
this.requestRenderAll();
|
|
7880
8971
|
}
|
|
8972
|
+
getSceneScale() {
|
|
8973
|
+
const scale = Number(this.viewport.scale);
|
|
8974
|
+
return Number.isFinite(scale) && scale > 0 ? scale : 1;
|
|
8975
|
+
}
|
|
8976
|
+
getSceneOffset() {
|
|
8977
|
+
const offset = this.viewport.offset;
|
|
8978
|
+
const x = Number(offset.x);
|
|
8979
|
+
const y = Number(offset.y);
|
|
8980
|
+
return {
|
|
8981
|
+
x: Number.isFinite(x) ? x : 0,
|
|
8982
|
+
y: Number.isFinite(y) ? y : 0
|
|
8983
|
+
};
|
|
8984
|
+
}
|
|
8985
|
+
toScreenPoint(point) {
|
|
8986
|
+
const scale = this.getSceneScale();
|
|
8987
|
+
const offset = this.getSceneOffset();
|
|
8988
|
+
return {
|
|
8989
|
+
x: point.x * scale + offset.x,
|
|
8990
|
+
y: point.y * scale + offset.y
|
|
8991
|
+
};
|
|
8992
|
+
}
|
|
8993
|
+
toScenePoint(point) {
|
|
8994
|
+
const scale = this.getSceneScale();
|
|
8995
|
+
const offset = this.getSceneOffset();
|
|
8996
|
+
return {
|
|
8997
|
+
x: (point.x - offset.x) / scale,
|
|
8998
|
+
y: (point.y - offset.y) / scale
|
|
8999
|
+
};
|
|
9000
|
+
}
|
|
9001
|
+
toScreenLength(value) {
|
|
9002
|
+
return value * this.getSceneScale();
|
|
9003
|
+
}
|
|
9004
|
+
toSceneLength(value) {
|
|
9005
|
+
return value / this.getSceneScale();
|
|
9006
|
+
}
|
|
9007
|
+
toScreenRect(rect) {
|
|
9008
|
+
const start = this.toScreenPoint({ x: rect.left, y: rect.top });
|
|
9009
|
+
return {
|
|
9010
|
+
left: start.x,
|
|
9011
|
+
top: start.y,
|
|
9012
|
+
width: this.toScreenLength(rect.width),
|
|
9013
|
+
height: this.toScreenLength(rect.height)
|
|
9014
|
+
};
|
|
9015
|
+
}
|
|
9016
|
+
toSceneRect(rect) {
|
|
9017
|
+
const start = this.toScenePoint({ x: rect.left, y: rect.top });
|
|
9018
|
+
return {
|
|
9019
|
+
left: start.x,
|
|
9020
|
+
top: start.y,
|
|
9021
|
+
width: this.toSceneLength(rect.width),
|
|
9022
|
+
height: this.toSceneLength(rect.height)
|
|
9023
|
+
};
|
|
9024
|
+
}
|
|
9025
|
+
getSceneViewportRect() {
|
|
9026
|
+
const width = Number(this.canvas.width || 0);
|
|
9027
|
+
const height = Number(this.canvas.height || 0);
|
|
9028
|
+
return this.toSceneRect({ left: 0, top: 0, width, height });
|
|
9029
|
+
}
|
|
9030
|
+
getScreenViewportRect() {
|
|
9031
|
+
return {
|
|
9032
|
+
left: 0,
|
|
9033
|
+
top: 0,
|
|
9034
|
+
width: Number(this.canvas.width || 0),
|
|
9035
|
+
height: Number(this.canvas.height || 0)
|
|
9036
|
+
};
|
|
9037
|
+
}
|
|
9038
|
+
toSpaceRect(rect, from, to) {
|
|
9039
|
+
if (from === to) return { ...rect };
|
|
9040
|
+
if (from === "scene") {
|
|
9041
|
+
return this.toScreenRect(rect);
|
|
9042
|
+
}
|
|
9043
|
+
return this.toSceneRect(rect);
|
|
9044
|
+
}
|
|
9045
|
+
resolveLayoutLength(value, base) {
|
|
9046
|
+
if (typeof value === "number") {
|
|
9047
|
+
return Number.isFinite(value) ? value : void 0;
|
|
9048
|
+
}
|
|
9049
|
+
if (typeof value !== "string") {
|
|
9050
|
+
return void 0;
|
|
9051
|
+
}
|
|
9052
|
+
const raw = value.trim();
|
|
9053
|
+
if (!raw) return void 0;
|
|
9054
|
+
if (raw.endsWith("%")) {
|
|
9055
|
+
const percent = parseFloat(raw.slice(0, -1));
|
|
9056
|
+
if (!Number.isFinite(percent)) return void 0;
|
|
9057
|
+
return base * percent / 100;
|
|
9058
|
+
}
|
|
9059
|
+
const parsed = parseFloat(raw);
|
|
9060
|
+
return Number.isFinite(parsed) ? parsed : void 0;
|
|
9061
|
+
}
|
|
9062
|
+
resolveLayoutInsets(inset, reference) {
|
|
9063
|
+
var _a, _b, _c, _d, _e;
|
|
9064
|
+
if (typeof inset === "number" || typeof inset === "string") {
|
|
9065
|
+
const all = (_a = this.resolveLayoutLength(
|
|
9066
|
+
inset,
|
|
9067
|
+
Math.min(reference.width, reference.height)
|
|
9068
|
+
)) != null ? _a : 0;
|
|
9069
|
+
return { top: all, right: all, bottom: all, left: all };
|
|
9070
|
+
}
|
|
9071
|
+
const source = inset || {};
|
|
9072
|
+
const top = (_b = this.resolveLayoutLength(source.top, reference.height)) != null ? _b : 0;
|
|
9073
|
+
const right = (_c = this.resolveLayoutLength(source.right, reference.width)) != null ? _c : 0;
|
|
9074
|
+
const bottom = (_d = this.resolveLayoutLength(source.bottom, reference.height)) != null ? _d : 0;
|
|
9075
|
+
const left = (_e = this.resolveLayoutLength(source.left, reference.width)) != null ? _e : 0;
|
|
9076
|
+
return { top, right, bottom, left };
|
|
9077
|
+
}
|
|
9078
|
+
resolveLayoutReferenceRect(layout, space) {
|
|
9079
|
+
if (layout.referenceRect) {
|
|
9080
|
+
const sourceSpace = layout.referenceRect.space || space;
|
|
9081
|
+
return this.toSpaceRect(layout.referenceRect, sourceSpace, space);
|
|
9082
|
+
}
|
|
9083
|
+
const reference = layout.reference || "sceneViewport";
|
|
9084
|
+
if (reference === "screenViewport") {
|
|
9085
|
+
const screenRect = this.getScreenViewportRect();
|
|
9086
|
+
return space === "screen" ? screenRect : this.toSceneRect(screenRect);
|
|
9087
|
+
}
|
|
9088
|
+
const sceneRect = this.getSceneViewportRect();
|
|
9089
|
+
return space === "scene" ? sceneRect : this.toScreenRect(sceneRect);
|
|
9090
|
+
}
|
|
9091
|
+
alignFactor(value) {
|
|
9092
|
+
if (value === "end") return 1;
|
|
9093
|
+
if (value === "center") return 0.5;
|
|
9094
|
+
return 0;
|
|
9095
|
+
}
|
|
9096
|
+
normalizeOriginX(value) {
|
|
9097
|
+
if (value === "center") return "center";
|
|
9098
|
+
if (value === "right") return "right";
|
|
9099
|
+
return "left";
|
|
9100
|
+
}
|
|
9101
|
+
normalizeOriginY(value) {
|
|
9102
|
+
if (value === "center") return "center";
|
|
9103
|
+
if (value === "bottom") return "bottom";
|
|
9104
|
+
return "top";
|
|
9105
|
+
}
|
|
9106
|
+
originFactor(value) {
|
|
9107
|
+
if (value === "center") return 0.5;
|
|
9108
|
+
if (value === "right" || value === "bottom") return 1;
|
|
9109
|
+
return 0;
|
|
9110
|
+
}
|
|
9111
|
+
resolveLayoutProps(spec, props) {
|
|
9112
|
+
var _a, _b, _c, _d;
|
|
9113
|
+
const layout = spec.layout;
|
|
9114
|
+
if (!layout) {
|
|
9115
|
+
return { ...props };
|
|
9116
|
+
}
|
|
9117
|
+
const space = spec.space || "scene";
|
|
9118
|
+
const reference = this.resolveLayoutReferenceRect(layout, space);
|
|
9119
|
+
const inset = this.resolveLayoutInsets(layout.inset, reference);
|
|
9120
|
+
const area = {
|
|
9121
|
+
left: reference.left + inset.left,
|
|
9122
|
+
top: reference.top + inset.top,
|
|
9123
|
+
width: Math.max(0, reference.width - inset.left - inset.right),
|
|
9124
|
+
height: Math.max(0, reference.height - inset.top - inset.bottom)
|
|
9125
|
+
};
|
|
9126
|
+
const next = { ...props };
|
|
9127
|
+
const width = (_a = this.resolveLayoutLength(layout.width, area.width)) != null ? _a : Number.isFinite(next.width) ? Number(next.width) : void 0;
|
|
9128
|
+
const height = (_b = this.resolveLayoutLength(layout.height, area.height)) != null ? _b : Number.isFinite(next.height) ? Number(next.height) : void 0;
|
|
9129
|
+
if (width !== void 0) next.width = width;
|
|
9130
|
+
if (height !== void 0) next.height = height;
|
|
9131
|
+
const alignX = this.alignFactor(layout.alignX);
|
|
9132
|
+
const alignY = this.alignFactor(layout.alignY);
|
|
9133
|
+
const offsetX = (_c = this.resolveLayoutLength(layout.offsetX, area.width)) != null ? _c : 0;
|
|
9134
|
+
const offsetY = (_d = this.resolveLayoutLength(layout.offsetY, area.height)) != null ? _d : 0;
|
|
9135
|
+
const objectWidth = Number.isFinite(next.width) ? Number(next.width) : 0;
|
|
9136
|
+
const objectHeight = Number.isFinite(next.height) ? Number(next.height) : 0;
|
|
9137
|
+
const objectLeft = area.left + (area.width - objectWidth) * alignX + offsetX;
|
|
9138
|
+
const objectTop = area.top + (area.height - objectHeight) * alignY + offsetY;
|
|
9139
|
+
const originX = this.normalizeOriginX(next.originX);
|
|
9140
|
+
const originY = this.normalizeOriginY(next.originY);
|
|
9141
|
+
next.left = objectLeft + objectWidth * this.originFactor(originX);
|
|
9142
|
+
next.top = objectTop + objectHeight * this.originFactor(originY);
|
|
9143
|
+
return next;
|
|
9144
|
+
}
|
|
9145
|
+
setLayerVisibility(layerId, visible) {
|
|
9146
|
+
const layer = this.getLayer(layerId);
|
|
9147
|
+
if (layer) {
|
|
9148
|
+
layer.set({ visible });
|
|
9149
|
+
}
|
|
9150
|
+
const objects = this.getRootLayerObjects(layerId);
|
|
9151
|
+
objects.forEach((obj) => {
|
|
9152
|
+
var _a, _b;
|
|
9153
|
+
(_a = obj.set) == null ? void 0 : _a.call(obj, { visible });
|
|
9154
|
+
(_b = obj.setCoords) == null ? void 0 : _b.call(obj);
|
|
9155
|
+
});
|
|
9156
|
+
}
|
|
9157
|
+
bringLayerToFront(layerId) {
|
|
9158
|
+
const layer = this.getLayer(layerId);
|
|
9159
|
+
if (layer) {
|
|
9160
|
+
this.canvas.bringObjectToFront(layer);
|
|
9161
|
+
}
|
|
9162
|
+
const objects = this.getRootLayerObjects(layerId);
|
|
9163
|
+
objects.forEach((obj) => this.canvas.bringObjectToFront(obj));
|
|
9164
|
+
}
|
|
7881
9165
|
async applyLayerSpec(spec) {
|
|
7882
9166
|
const layer = this.createLayer(spec.id, spec.props || {});
|
|
7883
9167
|
await this.applyObjectSpecsToContainer(layer, spec.objects);
|
|
7884
9168
|
}
|
|
7885
|
-
async applyObjectSpecsToLayer(layerId, objects) {
|
|
9169
|
+
async applyObjectSpecsToLayer(layerId, objects, options = {}) {
|
|
7886
9170
|
const layer = this.createLayer(layerId, {});
|
|
7887
|
-
await this.applyObjectSpecsToContainer(layer, objects);
|
|
9171
|
+
await this.applyObjectSpecsToContainer(layer, objects, options);
|
|
7888
9172
|
}
|
|
7889
9173
|
getRootLayerObjects(layerId) {
|
|
7890
9174
|
return this.canvas.getObjects().filter((obj) => {
|
|
@@ -7892,7 +9176,7 @@ var CanvasService = class {
|
|
|
7892
9176
|
return ((_a = obj == null ? void 0 : obj.data) == null ? void 0 : _a.layerId) === layerId;
|
|
7893
9177
|
});
|
|
7894
9178
|
}
|
|
7895
|
-
async applyObjectSpecsToRootLayer(layerId, specs) {
|
|
9179
|
+
async applyObjectSpecsToRootLayer(layerId, specs, options = {}) {
|
|
7896
9180
|
const desiredIds = new Set(specs.map((s) => s.id));
|
|
7897
9181
|
const existing = this.getRootLayerObjects(layerId);
|
|
7898
9182
|
existing.forEach((obj) => {
|
|
@@ -7926,9 +9210,11 @@ var CanvasService = class {
|
|
|
7926
9210
|
}
|
|
7927
9211
|
this.patchFabricObject(current, spec, { layerId });
|
|
7928
9212
|
}
|
|
7929
|
-
|
|
9213
|
+
if (options.render !== false) {
|
|
9214
|
+
this.requestRenderAll();
|
|
9215
|
+
}
|
|
7930
9216
|
}
|
|
7931
|
-
async applyObjectSpecsToContainer(container, specs) {
|
|
9217
|
+
async applyObjectSpecsToContainer(container, specs, options = {}) {
|
|
7932
9218
|
const desiredIds = new Set(specs.map((s) => s.id));
|
|
7933
9219
|
const existing = container.getObjects();
|
|
7934
9220
|
existing.forEach((obj) => {
|
|
@@ -7964,7 +9250,9 @@ var CanvasService = class {
|
|
|
7964
9250
|
this.moveObjectInContainer(container, current, index);
|
|
7965
9251
|
}
|
|
7966
9252
|
container.dirty = true;
|
|
7967
|
-
|
|
9253
|
+
if (options.render !== false) {
|
|
9254
|
+
this.requestRenderAll();
|
|
9255
|
+
}
|
|
7968
9256
|
}
|
|
7969
9257
|
patchFabricObject(obj, spec, extraData) {
|
|
7970
9258
|
const nextData = {
|
|
@@ -7973,9 +9261,33 @@ var CanvasService = class {
|
|
|
7973
9261
|
...extraData || {},
|
|
7974
9262
|
id: spec.id
|
|
7975
9263
|
};
|
|
7976
|
-
|
|
9264
|
+
const props = this.resolveFabricProps(spec, spec.props || {});
|
|
9265
|
+
obj.set({ ...props, data: nextData });
|
|
7977
9266
|
obj.setCoords();
|
|
7978
9267
|
}
|
|
9268
|
+
resolveFabricProps(spec, props) {
|
|
9269
|
+
const space = spec.space || "scene";
|
|
9270
|
+
const next = this.resolveLayoutProps(spec, props);
|
|
9271
|
+
if (space === "screen") {
|
|
9272
|
+
return next;
|
|
9273
|
+
}
|
|
9274
|
+
const hasLeft = Number.isFinite(next.left);
|
|
9275
|
+
const hasTop = Number.isFinite(next.top);
|
|
9276
|
+
if (hasLeft || hasTop) {
|
|
9277
|
+
const mapped = this.toScreenPoint({
|
|
9278
|
+
x: hasLeft ? Number(next.left) : 0,
|
|
9279
|
+
y: hasTop ? Number(next.top) : 0
|
|
9280
|
+
});
|
|
9281
|
+
if (hasLeft) next.left = mapped.x;
|
|
9282
|
+
if (hasTop) next.top = mapped.y;
|
|
9283
|
+
}
|
|
9284
|
+
const rawScaleX = Number.isFinite(next.scaleX) ? Number(next.scaleX) : 1;
|
|
9285
|
+
const rawScaleY = Number.isFinite(next.scaleY) ? Number(next.scaleY) : 1;
|
|
9286
|
+
const sceneScale = this.getSceneScale();
|
|
9287
|
+
next.scaleX = rawScaleX * sceneScale;
|
|
9288
|
+
next.scaleY = rawScaleY * sceneScale;
|
|
9289
|
+
return next;
|
|
9290
|
+
}
|
|
7979
9291
|
moveObjectInContainer(container, obj, index) {
|
|
7980
9292
|
if (!obj) return;
|
|
7981
9293
|
const moveObjectTo = container.moveObjectTo;
|
|
@@ -7995,10 +9307,11 @@ var CanvasService = class {
|
|
|
7995
9307
|
}
|
|
7996
9308
|
}
|
|
7997
9309
|
async createFabricObject(spec) {
|
|
7998
|
-
var _a, _b;
|
|
9310
|
+
var _a, _b, _c, _d;
|
|
7999
9311
|
if (spec.type === "rect") {
|
|
8000
|
-
const
|
|
8001
|
-
|
|
9312
|
+
const props = this.resolveFabricProps(spec, spec.props || {});
|
|
9313
|
+
const rect = new Rect({
|
|
9314
|
+
...props,
|
|
8002
9315
|
data: { ...spec.data || {}, id: spec.id }
|
|
8003
9316
|
});
|
|
8004
9317
|
rect.setCoords();
|
|
@@ -8007,8 +9320,9 @@ var CanvasService = class {
|
|
|
8007
9320
|
if (spec.type === "path") {
|
|
8008
9321
|
const pathData = ((_a = spec.props) == null ? void 0 : _a.path) || ((_b = spec.props) == null ? void 0 : _b.pathData);
|
|
8009
9322
|
if (!pathData) return void 0;
|
|
9323
|
+
const props = this.resolveFabricProps(spec, spec.props || {});
|
|
8010
9324
|
const path = new Path2(pathData, {
|
|
8011
|
-
...
|
|
9325
|
+
...props,
|
|
8012
9326
|
data: { ...spec.data || {}, id: spec.id }
|
|
8013
9327
|
});
|
|
8014
9328
|
path.setCoords();
|
|
@@ -8016,14 +9330,25 @@ var CanvasService = class {
|
|
|
8016
9330
|
}
|
|
8017
9331
|
if (spec.type === "image") {
|
|
8018
9332
|
if (!spec.src) return void 0;
|
|
8019
|
-
const image = await
|
|
9333
|
+
const image = await Image2.fromURL(spec.src, { crossOrigin: "anonymous" });
|
|
9334
|
+
const props = this.resolveFabricProps(spec, spec.props || {});
|
|
8020
9335
|
image.set({
|
|
8021
|
-
...
|
|
9336
|
+
...props,
|
|
8022
9337
|
data: { ...spec.data || {}, id: spec.id }
|
|
8023
9338
|
});
|
|
8024
9339
|
image.setCoords();
|
|
8025
9340
|
return image;
|
|
8026
9341
|
}
|
|
9342
|
+
if (spec.type === "text") {
|
|
9343
|
+
const content = String((_d = (_c = spec.props) == null ? void 0 : _c.text) != null ? _d : "");
|
|
9344
|
+
const props = this.resolveFabricProps(spec, spec.props || {});
|
|
9345
|
+
const text = new Text(content, {
|
|
9346
|
+
...props,
|
|
9347
|
+
data: { ...spec.data || {}, id: spec.id }
|
|
9348
|
+
});
|
|
9349
|
+
text.setCoords();
|
|
9350
|
+
return text;
|
|
9351
|
+
}
|
|
8027
9352
|
return void 0;
|
|
8028
9353
|
}
|
|
8029
9354
|
};
|