@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.js
CHANGED
|
@@ -49,6 +49,11 @@ module.exports = __toCommonJS(index_exports);
|
|
|
49
49
|
// src/extensions/background.ts
|
|
50
50
|
var import_core = require("@pooder/core");
|
|
51
51
|
var import_fabric = require("fabric");
|
|
52
|
+
var BACKGROUND_LAYER_ID = "background";
|
|
53
|
+
var BACKGROUND_RECT_ID = "background-color-rect";
|
|
54
|
+
var BACKGROUND_IMAGE_ID = "background-image";
|
|
55
|
+
var DEFAULT_WIDTH = 800;
|
|
56
|
+
var DEFAULT_HEIGHT = 600;
|
|
52
57
|
var BackgroundTool = class {
|
|
53
58
|
constructor(options) {
|
|
54
59
|
this.id = "pooder.kit.background";
|
|
@@ -57,17 +62,38 @@ var BackgroundTool = class {
|
|
|
57
62
|
};
|
|
58
63
|
this.color = "";
|
|
59
64
|
this.url = "";
|
|
65
|
+
this.specs = [];
|
|
66
|
+
this.renderSeq = 0;
|
|
67
|
+
this.renderImageUrl = "";
|
|
68
|
+
this.sourceSizeBySrc = /* @__PURE__ */ new Map();
|
|
69
|
+
this.pendingSizeBySrc = /* @__PURE__ */ new Map();
|
|
70
|
+
this.onCanvasResized = () => {
|
|
71
|
+
this.updateBackground();
|
|
72
|
+
};
|
|
60
73
|
if (options) {
|
|
61
74
|
Object.assign(this, options);
|
|
62
75
|
}
|
|
63
76
|
}
|
|
64
77
|
activate(context) {
|
|
78
|
+
var _a;
|
|
65
79
|
this.canvasService = context.services.get("CanvasService");
|
|
66
80
|
if (!this.canvasService) {
|
|
67
81
|
console.warn("CanvasService not found for BackgroundTool");
|
|
68
82
|
return;
|
|
69
83
|
}
|
|
70
|
-
|
|
84
|
+
(_a = this.renderProducerDisposable) == null ? void 0 : _a.dispose();
|
|
85
|
+
this.renderProducerDisposable = this.canvasService.registerRenderProducer(
|
|
86
|
+
this.id,
|
|
87
|
+
() => ({
|
|
88
|
+
layerSpecs: {
|
|
89
|
+
[BACKGROUND_LAYER_ID]: this.specs
|
|
90
|
+
}
|
|
91
|
+
}),
|
|
92
|
+
{ priority: 0 }
|
|
93
|
+
);
|
|
94
|
+
const configService = context.services.get(
|
|
95
|
+
"ConfigurationService"
|
|
96
|
+
);
|
|
71
97
|
if (configService) {
|
|
72
98
|
this.color = configService.get("background.color", this.color);
|
|
73
99
|
this.url = configService.get("background.url", this.url);
|
|
@@ -91,17 +117,25 @@ var BackgroundTool = class {
|
|
|
91
117
|
}
|
|
92
118
|
});
|
|
93
119
|
}
|
|
94
|
-
this.
|
|
120
|
+
context.eventBus.on("canvas:resized", this.onCanvasResized);
|
|
95
121
|
this.updateBackground();
|
|
96
122
|
}
|
|
97
123
|
deactivate(context) {
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
124
|
+
var _a;
|
|
125
|
+
context.eventBus.off("canvas:resized", this.onCanvasResized);
|
|
126
|
+
this.renderSeq += 1;
|
|
127
|
+
this.specs = [];
|
|
128
|
+
this.renderImageUrl = "";
|
|
129
|
+
(_a = this.renderProducerDisposable) == null ? void 0 : _a.dispose();
|
|
130
|
+
this.renderProducerDisposable = void 0;
|
|
131
|
+
if (!this.canvasService) return;
|
|
132
|
+
const layer = this.canvasService.getLayer(BACKGROUND_LAYER_ID);
|
|
133
|
+
if (layer) {
|
|
134
|
+
this.canvasService.canvas.remove(layer);
|
|
104
135
|
}
|
|
136
|
+
void this.canvasService.flushRenderFromProducers();
|
|
137
|
+
this.canvasService.requestRenderAll();
|
|
138
|
+
this.canvasService = void 0;
|
|
105
139
|
}
|
|
106
140
|
contribute() {
|
|
107
141
|
return {
|
|
@@ -161,88 +195,131 @@ var BackgroundTool = class {
|
|
|
161
195
|
]
|
|
162
196
|
};
|
|
163
197
|
}
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
evented: false
|
|
173
|
-
});
|
|
174
|
-
this.canvasService.canvas.sendObjectToBack(backgroundLayer);
|
|
175
|
-
}
|
|
198
|
+
getViewportSize() {
|
|
199
|
+
var _a, _b;
|
|
200
|
+
const width = Number(((_a = this.canvasService) == null ? void 0 : _a.canvas.width) || 0);
|
|
201
|
+
const height = Number(((_b = this.canvasService) == null ? void 0 : _b.canvas.height) || 0);
|
|
202
|
+
return {
|
|
203
|
+
width: width > 0 ? width : DEFAULT_WIDTH,
|
|
204
|
+
height: height > 0 ? height : DEFAULT_HEIGHT
|
|
205
|
+
};
|
|
176
206
|
}
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
const
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
207
|
+
buildBackgroundSpecs(color, imageUrl) {
|
|
208
|
+
const { width, height } = this.getViewportSize();
|
|
209
|
+
const specs = [
|
|
210
|
+
{
|
|
211
|
+
id: BACKGROUND_RECT_ID,
|
|
212
|
+
type: "rect",
|
|
213
|
+
space: "screen",
|
|
214
|
+
data: {
|
|
215
|
+
id: BACKGROUND_RECT_ID,
|
|
216
|
+
layerId: BACKGROUND_LAYER_ID,
|
|
217
|
+
type: "background-color"
|
|
218
|
+
},
|
|
219
|
+
props: {
|
|
220
|
+
left: 0,
|
|
221
|
+
top: 0,
|
|
222
|
+
width,
|
|
223
|
+
height,
|
|
224
|
+
originX: "left",
|
|
225
|
+
originY: "top",
|
|
226
|
+
fill: color,
|
|
227
|
+
selectable: false,
|
|
228
|
+
evented: false,
|
|
229
|
+
excludeFromExport: true
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
];
|
|
233
|
+
if (!imageUrl) {
|
|
234
|
+
return specs;
|
|
183
235
|
}
|
|
184
|
-
const
|
|
185
|
-
const
|
|
186
|
-
const
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
236
|
+
const sourceSize = this.sourceSizeBySrc.get(imageUrl);
|
|
237
|
+
const sourceWidth = Math.max(1, Number((sourceSize == null ? void 0 : sourceSize.width) || width));
|
|
238
|
+
const sourceHeight = Math.max(1, Number((sourceSize == null ? void 0 : sourceSize.height) || height));
|
|
239
|
+
const coverScale = Math.max(width / sourceWidth, height / sourceHeight);
|
|
240
|
+
specs.push({
|
|
241
|
+
id: BACKGROUND_IMAGE_ID,
|
|
242
|
+
type: "image",
|
|
243
|
+
src: imageUrl,
|
|
244
|
+
space: "screen",
|
|
245
|
+
data: {
|
|
246
|
+
id: BACKGROUND_IMAGE_ID,
|
|
247
|
+
layerId: BACKGROUND_LAYER_ID,
|
|
248
|
+
type: "background-image"
|
|
249
|
+
},
|
|
250
|
+
props: {
|
|
251
|
+
left: 0,
|
|
252
|
+
top: 0,
|
|
253
|
+
originX: "left",
|
|
254
|
+
originY: "top",
|
|
255
|
+
scaleX: coverScale,
|
|
256
|
+
scaleY: coverScale,
|
|
200
257
|
selectable: false,
|
|
201
258
|
evented: false,
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
259
|
+
excludeFromExport: true
|
|
260
|
+
}
|
|
261
|
+
});
|
|
262
|
+
return specs;
|
|
263
|
+
}
|
|
264
|
+
async ensureImageSize(src) {
|
|
265
|
+
if (!src) return null;
|
|
266
|
+
const cached = this.sourceSizeBySrc.get(src);
|
|
267
|
+
if (cached) return cached;
|
|
268
|
+
const pending = this.pendingSizeBySrc.get(src);
|
|
269
|
+
if (pending) {
|
|
270
|
+
return pending;
|
|
208
271
|
}
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
"background"
|
|
212
|
-
);
|
|
272
|
+
const task = this.loadImageSize(src);
|
|
273
|
+
this.pendingSizeBySrc.set(src, task);
|
|
213
274
|
try {
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
} else {
|
|
219
|
-
layer.remove(img);
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
} else {
|
|
223
|
-
if (url) {
|
|
224
|
-
img = await import_fabric.FabricImage.fromURL(url, { crossOrigin: "anonymous" });
|
|
225
|
-
img.set({
|
|
226
|
-
originX: "left",
|
|
227
|
-
originY: "top",
|
|
228
|
-
left: 0,
|
|
229
|
-
top: 0,
|
|
230
|
-
selectable: false,
|
|
231
|
-
evented: false,
|
|
232
|
-
data: {
|
|
233
|
-
id: "background-image"
|
|
234
|
-
}
|
|
235
|
-
});
|
|
236
|
-
img.scaleToWidth(width);
|
|
237
|
-
if (img.getScaledHeight() < height) img.scaleToHeight(height);
|
|
238
|
-
layer.add(img);
|
|
239
|
-
}
|
|
275
|
+
return await task;
|
|
276
|
+
} finally {
|
|
277
|
+
if (this.pendingSizeBySrc.get(src) === task) {
|
|
278
|
+
this.pendingSizeBySrc.delete(src);
|
|
240
279
|
}
|
|
241
|
-
this.canvasService.requestRenderAll();
|
|
242
|
-
} catch (e) {
|
|
243
|
-
console.error("[BackgroundTool] Failed to load image", e);
|
|
244
280
|
}
|
|
245
|
-
|
|
281
|
+
}
|
|
282
|
+
async loadImageSize(src) {
|
|
283
|
+
try {
|
|
284
|
+
const image = await import_fabric.FabricImage.fromURL(src, {
|
|
285
|
+
crossOrigin: "anonymous"
|
|
286
|
+
});
|
|
287
|
+
const width = Number((image == null ? void 0 : image.width) || 0);
|
|
288
|
+
const height = Number((image == null ? void 0 : image.height) || 0);
|
|
289
|
+
if (width > 0 && height > 0) {
|
|
290
|
+
const size = { width, height };
|
|
291
|
+
this.sourceSizeBySrc.set(src, size);
|
|
292
|
+
return size;
|
|
293
|
+
}
|
|
294
|
+
} catch (error) {
|
|
295
|
+
console.error("[BackgroundTool] Failed to load image", src, error);
|
|
296
|
+
}
|
|
297
|
+
return null;
|
|
298
|
+
}
|
|
299
|
+
updateBackground() {
|
|
300
|
+
void this.updateBackgroundAsync();
|
|
301
|
+
}
|
|
302
|
+
async updateBackgroundAsync() {
|
|
303
|
+
if (!this.canvasService) return;
|
|
304
|
+
const seq = ++this.renderSeq;
|
|
305
|
+
const color = this.color;
|
|
306
|
+
const nextUrl = String(this.url || "").trim();
|
|
307
|
+
if (!nextUrl) {
|
|
308
|
+
this.renderImageUrl = "";
|
|
309
|
+
} else if (nextUrl !== this.renderImageUrl) {
|
|
310
|
+
const loaded = await this.ensureImageSize(nextUrl);
|
|
311
|
+
if (seq !== this.renderSeq) return;
|
|
312
|
+
if (loaded) {
|
|
313
|
+
this.renderImageUrl = nextUrl;
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
this.specs = this.buildBackgroundSpecs(color, this.renderImageUrl);
|
|
317
|
+
await this.canvasService.flushRenderFromProducers();
|
|
318
|
+
if (seq !== this.renderSeq) return;
|
|
319
|
+
const layer = this.canvasService.getLayer(BACKGROUND_LAYER_ID);
|
|
320
|
+
if (layer) {
|
|
321
|
+
this.canvasService.canvas.sendObjectToBack(layer);
|
|
322
|
+
}
|
|
246
323
|
this.canvasService.requestRenderAll();
|
|
247
324
|
}
|
|
248
325
|
};
|
|
@@ -251,6 +328,71 @@ var BackgroundTool = class {
|
|
|
251
328
|
var import_core2 = require("@pooder/core");
|
|
252
329
|
var import_fabric2 = require("fabric");
|
|
253
330
|
|
|
331
|
+
// src/extensions/dielineShape.ts
|
|
332
|
+
var BUILTIN_DIELINE_SHAPES = [
|
|
333
|
+
"rect",
|
|
334
|
+
"circle",
|
|
335
|
+
"ellipse",
|
|
336
|
+
"heart"
|
|
337
|
+
];
|
|
338
|
+
var DIELINE_SHAPES = [...BUILTIN_DIELINE_SHAPES, "custom"];
|
|
339
|
+
var DEFAULT_DIELINE_SHAPE = "rect";
|
|
340
|
+
var DEFAULT_HEART_SHAPE_PARAMS = {
|
|
341
|
+
lobeSpread: 0.46,
|
|
342
|
+
notchDepth: 0.24,
|
|
343
|
+
tipSharpness: 0
|
|
344
|
+
};
|
|
345
|
+
var DEFAULT_DIELINE_SHAPE_STYLE = {
|
|
346
|
+
fitMode: "contain",
|
|
347
|
+
...DEFAULT_HEART_SHAPE_PARAMS
|
|
348
|
+
};
|
|
349
|
+
function isDielineShape(value) {
|
|
350
|
+
return typeof value === "string" && DIELINE_SHAPES.includes(value);
|
|
351
|
+
}
|
|
352
|
+
function normalizeFitMode(value, fallback) {
|
|
353
|
+
if (value === "contain" || value === "stretch") return value;
|
|
354
|
+
return fallback;
|
|
355
|
+
}
|
|
356
|
+
function normalizeUnitInterval(value, fallback) {
|
|
357
|
+
const num = Number(value);
|
|
358
|
+
if (!Number.isFinite(num)) return fallback;
|
|
359
|
+
return Math.max(0, Math.min(1, num));
|
|
360
|
+
}
|
|
361
|
+
function normalizeDielineShape(value, fallback = DEFAULT_DIELINE_SHAPE) {
|
|
362
|
+
return isDielineShape(value) ? value : fallback;
|
|
363
|
+
}
|
|
364
|
+
function normalizeShapeStyle(value, fallback = DEFAULT_DIELINE_SHAPE_STYLE) {
|
|
365
|
+
var _a, _b, _c;
|
|
366
|
+
const raw = value && typeof value === "object" ? value : {};
|
|
367
|
+
return {
|
|
368
|
+
...fallback,
|
|
369
|
+
fitMode: normalizeFitMode(raw.fitMode, fallback.fitMode),
|
|
370
|
+
lobeSpread: normalizeUnitInterval(
|
|
371
|
+
raw.lobeSpread,
|
|
372
|
+
Number((_a = fallback.lobeSpread) != null ? _a : DEFAULT_HEART_SHAPE_PARAMS.lobeSpread)
|
|
373
|
+
),
|
|
374
|
+
notchDepth: normalizeUnitInterval(
|
|
375
|
+
raw.notchDepth,
|
|
376
|
+
Number((_b = fallback.notchDepth) != null ? _b : DEFAULT_HEART_SHAPE_PARAMS.notchDepth)
|
|
377
|
+
),
|
|
378
|
+
tipSharpness: normalizeUnitInterval(
|
|
379
|
+
raw.tipSharpness,
|
|
380
|
+
Number((_c = fallback.tipSharpness) != null ? _c : DEFAULT_HEART_SHAPE_PARAMS.tipSharpness)
|
|
381
|
+
)
|
|
382
|
+
};
|
|
383
|
+
}
|
|
384
|
+
function getShapeFitMode(style) {
|
|
385
|
+
return normalizeShapeStyle(style).fitMode;
|
|
386
|
+
}
|
|
387
|
+
function getHeartShapeParams(style) {
|
|
388
|
+
const normalized = normalizeShapeStyle(style);
|
|
389
|
+
return {
|
|
390
|
+
lobeSpread: Number(normalized.lobeSpread),
|
|
391
|
+
notchDepth: Number(normalized.notchDepth),
|
|
392
|
+
tipSharpness: Number(normalized.tipSharpness)
|
|
393
|
+
};
|
|
394
|
+
}
|
|
395
|
+
|
|
254
396
|
// src/extensions/geometry.ts
|
|
255
397
|
var import_paper = __toESM(require("paper"));
|
|
256
398
|
|
|
@@ -393,45 +535,164 @@ function selectOuterChain(args) {
|
|
|
393
535
|
if (scoreA !== scoreB) return scoreA > scoreB ? pointsA : pointsB;
|
|
394
536
|
return pointsA.length <= pointsB.length ? pointsA : pointsB;
|
|
395
537
|
}
|
|
396
|
-
function
|
|
397
|
-
|
|
398
|
-
const
|
|
399
|
-
|
|
400
|
-
|
|
538
|
+
function fitPathItemToRect(item, rect, fitMode) {
|
|
539
|
+
const { left, top, width, height } = rect;
|
|
540
|
+
const bounds = item.bounds;
|
|
541
|
+
if (width <= 0 || height <= 0 || !Number.isFinite(bounds.width) || !Number.isFinite(bounds.height) || bounds.width <= 0 || bounds.height <= 0) {
|
|
542
|
+
item.position = new import_paper.default.Point(left + width / 2, top + height / 2);
|
|
543
|
+
return item;
|
|
544
|
+
}
|
|
545
|
+
item.translate(new import_paper.default.Point(-bounds.left, -bounds.top));
|
|
546
|
+
if (fitMode === "stretch") {
|
|
547
|
+
item.scale(width / bounds.width, height / bounds.height, new import_paper.default.Point(0, 0));
|
|
548
|
+
item.translate(new import_paper.default.Point(left, top));
|
|
549
|
+
return item;
|
|
550
|
+
}
|
|
551
|
+
const uniformScale = Math.min(width / bounds.width, height / bounds.height);
|
|
552
|
+
item.scale(uniformScale, uniformScale, new import_paper.default.Point(0, 0));
|
|
553
|
+
const scaledWidth = bounds.width * uniformScale;
|
|
554
|
+
const scaledHeight = bounds.height * uniformScale;
|
|
555
|
+
item.translate(
|
|
556
|
+
new import_paper.default.Point(
|
|
557
|
+
left + (width - scaledWidth) / 2,
|
|
558
|
+
top + (height - scaledHeight) / 2
|
|
559
|
+
)
|
|
560
|
+
);
|
|
561
|
+
return item;
|
|
562
|
+
}
|
|
563
|
+
function createNormalizedHeartPath(params) {
|
|
564
|
+
const { lobeSpread, notchDepth, tipSharpness } = params;
|
|
565
|
+
const halfSpread = 0.22 + lobeSpread * 0.18;
|
|
566
|
+
const notchY = 0.06 + notchDepth * 0.2;
|
|
567
|
+
const shoulderY = 0.24 + notchDepth * 0.2;
|
|
568
|
+
const topLift = 0.12 + (1 - notchDepth) * 0.06;
|
|
569
|
+
const topY = notchY - topLift;
|
|
570
|
+
const sideCtrlY = shoulderY - (0.18 - notchDepth * 0.08);
|
|
571
|
+
const lowerCtrlY = 0.58 + (1 - tipSharpness) * 0.16;
|
|
572
|
+
const tipCtrlX = 0.34 - tipSharpness * 0.2;
|
|
573
|
+
const notchCtrlX = 0.06 + lobeSpread * 0.06;
|
|
574
|
+
const lobeCtrlX = 0.1 + lobeSpread * 0.08;
|
|
575
|
+
const notchCtrlY = notchY - topLift * 0.45;
|
|
576
|
+
const xPeakL = 0.5 - halfSpread;
|
|
577
|
+
const xPeakR = 0.5 + halfSpread;
|
|
578
|
+
const heartPath = new import_paper.default.Path({ insert: false });
|
|
579
|
+
heartPath.moveTo(new import_paper.default.Point(0.5, notchY));
|
|
580
|
+
heartPath.cubicCurveTo(
|
|
581
|
+
new import_paper.default.Point(0.5 - notchCtrlX, notchCtrlY),
|
|
582
|
+
new import_paper.default.Point(xPeakL + lobeCtrlX, topY),
|
|
583
|
+
new import_paper.default.Point(xPeakL, topY)
|
|
584
|
+
);
|
|
585
|
+
heartPath.cubicCurveTo(
|
|
586
|
+
new import_paper.default.Point(xPeakL - lobeCtrlX, topY),
|
|
587
|
+
new import_paper.default.Point(0, sideCtrlY),
|
|
588
|
+
new import_paper.default.Point(0, shoulderY)
|
|
589
|
+
);
|
|
590
|
+
heartPath.cubicCurveTo(
|
|
591
|
+
new import_paper.default.Point(0, lowerCtrlY),
|
|
592
|
+
new import_paper.default.Point(tipCtrlX, 1),
|
|
593
|
+
new import_paper.default.Point(0.5, 1)
|
|
594
|
+
);
|
|
595
|
+
heartPath.cubicCurveTo(
|
|
596
|
+
new import_paper.default.Point(1 - tipCtrlX, 1),
|
|
597
|
+
new import_paper.default.Point(1, lowerCtrlY),
|
|
598
|
+
new import_paper.default.Point(1, shoulderY)
|
|
599
|
+
);
|
|
600
|
+
heartPath.cubicCurveTo(
|
|
601
|
+
new import_paper.default.Point(1, sideCtrlY),
|
|
602
|
+
new import_paper.default.Point(xPeakR + lobeCtrlX, topY),
|
|
603
|
+
new import_paper.default.Point(xPeakR, topY)
|
|
604
|
+
);
|
|
605
|
+
heartPath.cubicCurveTo(
|
|
606
|
+
new import_paper.default.Point(xPeakR - lobeCtrlX, topY),
|
|
607
|
+
new import_paper.default.Point(0.5 + notchCtrlX, notchCtrlY),
|
|
608
|
+
new import_paper.default.Point(0.5, notchY)
|
|
609
|
+
);
|
|
610
|
+
heartPath.closed = true;
|
|
611
|
+
return heartPath;
|
|
612
|
+
}
|
|
613
|
+
function createHeartBaseShape(options) {
|
|
614
|
+
const { x, y, width, height } = options;
|
|
615
|
+
const w = Math.max(0, width);
|
|
616
|
+
const h = Math.max(0, height);
|
|
617
|
+
const left = x - w / 2;
|
|
618
|
+
const top = y - h / 2;
|
|
619
|
+
const fitMode = getShapeFitMode(options.shapeStyle);
|
|
620
|
+
const heartParams = getHeartShapeParams(options.shapeStyle);
|
|
621
|
+
const rawHeart = createNormalizedHeartPath(heartParams);
|
|
622
|
+
return fitPathItemToRect(rawHeart, { left, top, width: w, height: h }, fitMode);
|
|
623
|
+
}
|
|
624
|
+
var BUILTIN_SHAPE_BUILDERS = {
|
|
625
|
+
rect: (options) => {
|
|
626
|
+
const { x, y, width, height, radius } = options;
|
|
401
627
|
return new import_paper.default.Path.Rectangle({
|
|
402
628
|
point: [x - width / 2, y - height / 2],
|
|
403
629
|
size: [Math.max(0, width), Math.max(0, height)],
|
|
404
630
|
radius: Math.max(0, radius)
|
|
405
631
|
});
|
|
406
|
-
}
|
|
632
|
+
},
|
|
633
|
+
circle: (options) => {
|
|
634
|
+
const { x, y, width, height } = options;
|
|
407
635
|
const r = Math.min(width, height) / 2;
|
|
408
636
|
return new import_paper.default.Path.Circle({
|
|
409
|
-
center,
|
|
637
|
+
center: new import_paper.default.Point(x, y),
|
|
410
638
|
radius: Math.max(0, r)
|
|
411
639
|
});
|
|
412
|
-
}
|
|
640
|
+
},
|
|
641
|
+
ellipse: (options) => {
|
|
642
|
+
const { x, y, width, height } = options;
|
|
413
643
|
return new import_paper.default.Path.Ellipse({
|
|
414
|
-
center,
|
|
644
|
+
center: new import_paper.default.Point(x, y),
|
|
415
645
|
radius: [Math.max(0, width / 2), Math.max(0, height / 2)]
|
|
416
646
|
});
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
647
|
+
},
|
|
648
|
+
heart: createHeartBaseShape
|
|
649
|
+
};
|
|
650
|
+
function createCustomBaseShape(options) {
|
|
651
|
+
var _a;
|
|
652
|
+
const {
|
|
653
|
+
pathData,
|
|
654
|
+
customSourceWidthPx,
|
|
655
|
+
customSourceHeightPx,
|
|
656
|
+
x,
|
|
657
|
+
y,
|
|
658
|
+
width,
|
|
659
|
+
height
|
|
660
|
+
} = options;
|
|
661
|
+
if (typeof pathData !== "string" || pathData.trim().length === 0) {
|
|
662
|
+
return null;
|
|
663
|
+
}
|
|
664
|
+
const center = new import_paper.default.Point(x, y);
|
|
665
|
+
const hasMultipleSubPaths = ((_a = (pathData.match(/[Mm]/g) || []).length) != null ? _a : 0) > 1;
|
|
666
|
+
const path = hasMultipleSubPaths ? new import_paper.default.CompoundPath(pathData) : (() => {
|
|
667
|
+
const single = new import_paper.default.Path();
|
|
668
|
+
single.pathData = pathData;
|
|
669
|
+
return single;
|
|
670
|
+
})();
|
|
671
|
+
const sourceWidth = Number(customSourceWidthPx != null ? customSourceWidthPx : 0);
|
|
672
|
+
const sourceHeight = Number(customSourceHeightPx != null ? customSourceHeightPx : 0);
|
|
673
|
+
if (Number.isFinite(sourceWidth) && Number.isFinite(sourceHeight) && sourceWidth > 0 && sourceHeight > 0 && width > 0 && height > 0) {
|
|
674
|
+
const targetLeft = x - width / 2;
|
|
675
|
+
const targetTop = y - height / 2;
|
|
676
|
+
path.scale(width / sourceWidth, height / sourceHeight, new import_paper.default.Point(0, 0));
|
|
677
|
+
path.translate(new import_paper.default.Point(targetLeft, targetTop));
|
|
678
|
+
return path;
|
|
679
|
+
}
|
|
680
|
+
if (width > 0 && height > 0 && path.bounds.width > 0 && path.bounds.height > 0) {
|
|
424
681
|
path.position = center;
|
|
425
|
-
|
|
426
|
-
path.scale(width / path.bounds.width, height / path.bounds.height);
|
|
427
|
-
}
|
|
682
|
+
path.scale(width / path.bounds.width, height / path.bounds.height);
|
|
428
683
|
return path;
|
|
429
|
-
} else {
|
|
430
|
-
return new import_paper.default.Path.Rectangle({
|
|
431
|
-
point: [x - width / 2, y - height / 2],
|
|
432
|
-
size: [Math.max(0, width), Math.max(0, height)]
|
|
433
|
-
});
|
|
434
684
|
}
|
|
685
|
+
path.position = center;
|
|
686
|
+
return path;
|
|
687
|
+
}
|
|
688
|
+
function createBaseShape(options) {
|
|
689
|
+
const { shape } = options;
|
|
690
|
+
if (shape === "custom") {
|
|
691
|
+
const customShape = createCustomBaseShape(options);
|
|
692
|
+
if (customShape) return customShape;
|
|
693
|
+
return BUILTIN_SHAPE_BUILDERS[DEFAULT_DIELINE_SHAPE](options);
|
|
694
|
+
}
|
|
695
|
+
return BUILTIN_SHAPE_BUILDERS[shape](options);
|
|
435
696
|
}
|
|
436
697
|
function resolveBridgeBasePath(shape, anchor) {
|
|
437
698
|
if (shape instanceof import_paper.default.Path) {
|
|
@@ -755,6 +1016,18 @@ function getNearestPointOnDieline(point, options) {
|
|
|
755
1016
|
shape.remove();
|
|
756
1017
|
return result;
|
|
757
1018
|
}
|
|
1019
|
+
function getPathBounds(pathData) {
|
|
1020
|
+
const path = new import_paper.default.Path();
|
|
1021
|
+
path.pathData = pathData;
|
|
1022
|
+
const bounds = path.bounds;
|
|
1023
|
+
path.remove();
|
|
1024
|
+
return {
|
|
1025
|
+
x: bounds.x,
|
|
1026
|
+
y: bounds.y,
|
|
1027
|
+
width: bounds.width,
|
|
1028
|
+
height: bounds.height
|
|
1029
|
+
};
|
|
1030
|
+
}
|
|
758
1031
|
|
|
759
1032
|
// src/coordinate.ts
|
|
760
1033
|
var Coordinate = class {
|
|
@@ -843,12 +1116,6 @@ function parseLengthToMm(input, defaultUnit) {
|
|
|
843
1116
|
const unit = (_b = (_a = match[2]) == null ? void 0 : _a.toLowerCase()) != null ? _b : defaultUnit;
|
|
844
1117
|
return Coordinate.convertUnit(value, unit, "mm");
|
|
845
1118
|
}
|
|
846
|
-
function formatMm(valueMm, displayUnit, fractionDigits = 2) {
|
|
847
|
-
if (!Number.isFinite(valueMm)) return "0";
|
|
848
|
-
const value = Coordinate.convertUnit(valueMm, "mm", displayUnit);
|
|
849
|
-
const rounded = Number(value.toFixed(fractionDigits));
|
|
850
|
-
return rounded.toString();
|
|
851
|
-
}
|
|
852
1119
|
|
|
853
1120
|
// src/extensions/sceneLayoutModel.ts
|
|
854
1121
|
var DEFAULT_SIZE_STATE = {
|
|
@@ -1059,10 +1326,19 @@ function buildSceneGeometry(configService, layout) {
|
|
|
1059
1326
|
"mm"
|
|
1060
1327
|
);
|
|
1061
1328
|
const offset = (layout.cutRect.width - layout.trimRect.width) / 2;
|
|
1329
|
+
const sourceWidth = Number(configService.get("dieline.customSourceWidthPx", 0));
|
|
1330
|
+
const sourceHeight = Number(
|
|
1331
|
+
configService.get("dieline.customSourceHeightPx", 0)
|
|
1332
|
+
);
|
|
1333
|
+
const shapeStyle = normalizeShapeStyle(
|
|
1334
|
+
configService.get("dieline.shapeStyle", DEFAULT_DIELINE_SHAPE_STYLE)
|
|
1335
|
+
);
|
|
1062
1336
|
return {
|
|
1063
|
-
shape:
|
|
1064
|
-
|
|
1065
|
-
|
|
1337
|
+
shape: normalizeDielineShape(
|
|
1338
|
+
configService.get("dieline.shape", DEFAULT_DIELINE_SHAPE)
|
|
1339
|
+
),
|
|
1340
|
+
shapeStyle,
|
|
1341
|
+
unit: "px",
|
|
1066
1342
|
x: layout.trimRect.centerX,
|
|
1067
1343
|
y: layout.trimRect.centerY,
|
|
1068
1344
|
width: layout.trimRect.width,
|
|
@@ -1070,7 +1346,9 @@ function buildSceneGeometry(configService, layout) {
|
|
|
1070
1346
|
radius: radiusMm * layout.scale,
|
|
1071
1347
|
offset,
|
|
1072
1348
|
scale: layout.scale,
|
|
1073
|
-
pathData: configService.get("dieline.pathData")
|
|
1349
|
+
pathData: configService.get("dieline.pathData"),
|
|
1350
|
+
customSourceWidthPx: Number.isFinite(sourceWidth) && sourceWidth > 0 ? sourceWidth : void 0,
|
|
1351
|
+
customSourceHeightPx: Number.isFinite(sourceHeight) && sourceHeight > 0 ? sourceHeight : void 0
|
|
1074
1352
|
};
|
|
1075
1353
|
}
|
|
1076
1354
|
|
|
@@ -1093,6 +1371,7 @@ var ImageTool = class {
|
|
|
1093
1371
|
this.isImageSelectionActive = false;
|
|
1094
1372
|
this.focusedImageId = null;
|
|
1095
1373
|
this.renderSeq = 0;
|
|
1374
|
+
this.overlaySpecs = [];
|
|
1096
1375
|
this.onToolActivated = (event) => {
|
|
1097
1376
|
const before = this.isToolActive;
|
|
1098
1377
|
this.syncToolActiveFromWorkbench(event.id);
|
|
@@ -1170,28 +1449,41 @@ var ImageTool = class {
|
|
|
1170
1449
|
const frame = this.getFrameRect();
|
|
1171
1450
|
if (!frame.width || !frame.height) return;
|
|
1172
1451
|
const center = target.getCenterPoint ? target.getCenterPoint() : new import_fabric2.Point((_c = target.left) != null ? _c : 0, (_d = target.top) != null ? _d : 0);
|
|
1452
|
+
const centerScene = this.canvasService ? this.canvasService.toScenePoint({ x: center.x, y: center.y }) : { x: center.x, y: center.y };
|
|
1173
1453
|
const objectScale = Number.isFinite(target == null ? void 0 : target.scaleX) ? target.scaleX : 1;
|
|
1454
|
+
const objectScaleScene = this.toSceneObjectScale(objectScale || 1);
|
|
1174
1455
|
const workingItem = this.workingItems.find((item) => item.id === id);
|
|
1175
1456
|
const sourceKey = (workingItem == null ? void 0 : workingItem.sourceUrl) || (workingItem == null ? void 0 : workingItem.url) || "";
|
|
1176
1457
|
const sourceSize = this.getSourceSize(sourceKey, target);
|
|
1177
1458
|
const coverScale = this.getCoverScale(frame, sourceSize);
|
|
1178
1459
|
const updates = {
|
|
1179
|
-
left: this.clampNormalized((
|
|
1180
|
-
top: this.clampNormalized((
|
|
1460
|
+
left: this.clampNormalized((centerScene.x - frame.left) / frame.width),
|
|
1461
|
+
top: this.clampNormalized((centerScene.y - frame.top) / frame.height),
|
|
1181
1462
|
angle: Number.isFinite(target.angle) ? target.angle : 0,
|
|
1182
|
-
scale: Math.max(0.05,
|
|
1463
|
+
scale: Math.max(0.05, objectScaleScene / coverScale)
|
|
1183
1464
|
};
|
|
1184
1465
|
this.focusedImageId = id;
|
|
1185
1466
|
this.updateImageInWorking(id, updates);
|
|
1186
1467
|
};
|
|
1187
1468
|
}
|
|
1188
1469
|
activate(context) {
|
|
1470
|
+
var _a;
|
|
1189
1471
|
this.context = context;
|
|
1190
1472
|
this.canvasService = context.services.get("CanvasService");
|
|
1191
1473
|
if (!this.canvasService) {
|
|
1192
1474
|
console.warn("CanvasService not found for ImageTool");
|
|
1193
1475
|
return;
|
|
1194
1476
|
}
|
|
1477
|
+
(_a = this.renderProducerDisposable) == null ? void 0 : _a.dispose();
|
|
1478
|
+
this.renderProducerDisposable = this.canvasService.registerRenderProducer(
|
|
1479
|
+
this.id,
|
|
1480
|
+
() => ({
|
|
1481
|
+
rootLayerSpecs: {
|
|
1482
|
+
[IMAGE_OVERLAY_LAYER_ID]: this.overlaySpecs
|
|
1483
|
+
}
|
|
1484
|
+
}),
|
|
1485
|
+
{ priority: 300 }
|
|
1486
|
+
);
|
|
1195
1487
|
context.eventBus.on("tool:activated", this.onToolActivated);
|
|
1196
1488
|
context.eventBus.on("object:modified", this.onObjectModified);
|
|
1197
1489
|
context.eventBus.on("selection:created", this.onSelectionChanged);
|
|
@@ -1232,7 +1524,7 @@ var ImageTool = class {
|
|
|
1232
1524
|
this.updateImages();
|
|
1233
1525
|
}
|
|
1234
1526
|
deactivate(context) {
|
|
1235
|
-
var _a;
|
|
1527
|
+
var _a, _b;
|
|
1236
1528
|
context.eventBus.off("tool:activated", this.onToolActivated);
|
|
1237
1529
|
context.eventBus.off("object:modified", this.onObjectModified);
|
|
1238
1530
|
context.eventBus.off("selection:created", this.onSelectionChanged);
|
|
@@ -1244,12 +1536,13 @@ var ImageTool = class {
|
|
|
1244
1536
|
this.dirtyTrackerDisposable = void 0;
|
|
1245
1537
|
this.cropShapeHatchPattern = void 0;
|
|
1246
1538
|
this.cropShapeHatchPatternColor = void 0;
|
|
1539
|
+
this.cropShapeHatchPatternKey = void 0;
|
|
1540
|
+
this.overlaySpecs = [];
|
|
1247
1541
|
this.clearRenderedImages();
|
|
1542
|
+
(_b = this.renderProducerDisposable) == null ? void 0 : _b.dispose();
|
|
1543
|
+
this.renderProducerDisposable = void 0;
|
|
1248
1544
|
if (this.canvasService) {
|
|
1249
|
-
void this.canvasService.
|
|
1250
|
-
IMAGE_OVERLAY_LAYER_ID,
|
|
1251
|
-
[]
|
|
1252
|
-
);
|
|
1545
|
+
void this.canvasService.flushRenderFromProducers();
|
|
1253
1546
|
this.canvasService = void 0;
|
|
1254
1547
|
}
|
|
1255
1548
|
this.context = void 0;
|
|
@@ -1660,38 +1953,38 @@ var ImageTool = class {
|
|
|
1660
1953
|
if (!layout) {
|
|
1661
1954
|
return { left: 0, top: 0, width: 0, height: 0 };
|
|
1662
1955
|
}
|
|
1663
|
-
return {
|
|
1956
|
+
return this.canvasService.toSceneRect({
|
|
1664
1957
|
left: layout.cutRect.left,
|
|
1665
1958
|
top: layout.cutRect.top,
|
|
1666
1959
|
width: layout.cutRect.width,
|
|
1667
1960
|
height: layout.cutRect.height
|
|
1961
|
+
});
|
|
1962
|
+
}
|
|
1963
|
+
getFrameRectScreen(frame) {
|
|
1964
|
+
if (!this.canvasService) {
|
|
1965
|
+
return { left: 0, top: 0, width: 0, height: 0 };
|
|
1966
|
+
}
|
|
1967
|
+
return this.canvasService.toScreenRect(frame || this.getFrameRect());
|
|
1968
|
+
}
|
|
1969
|
+
toLayoutSceneRect(rect) {
|
|
1970
|
+
return {
|
|
1971
|
+
left: rect.left,
|
|
1972
|
+
top: rect.top,
|
|
1973
|
+
width: rect.width,
|
|
1974
|
+
height: rect.height,
|
|
1975
|
+
space: "scene"
|
|
1668
1976
|
};
|
|
1669
1977
|
}
|
|
1670
1978
|
async resolveDefaultFitArea() {
|
|
1671
|
-
if (!this.
|
|
1672
|
-
const
|
|
1673
|
-
if (
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
const height = Number(cutRect == null ? void 0 : cutRect.height);
|
|
1681
|
-
const left = Number(cutRect == null ? void 0 : cutRect.left);
|
|
1682
|
-
const top = Number(cutRect == null ? void 0 : cutRect.top);
|
|
1683
|
-
if (!Number.isFinite(width) || !Number.isFinite(height) || !Number.isFinite(left) || !Number.isFinite(top)) {
|
|
1684
|
-
return null;
|
|
1685
|
-
}
|
|
1686
|
-
return {
|
|
1687
|
-
width: Math.max(1, width),
|
|
1688
|
-
height: Math.max(1, height),
|
|
1689
|
-
left: left + width / 2,
|
|
1690
|
-
top: top + height / 2
|
|
1691
|
-
};
|
|
1692
|
-
} catch (e) {
|
|
1693
|
-
return null;
|
|
1694
|
-
}
|
|
1979
|
+
if (!this.canvasService) return null;
|
|
1980
|
+
const frame = this.getFrameRect();
|
|
1981
|
+
if (frame.width <= 0 || frame.height <= 0) return null;
|
|
1982
|
+
return {
|
|
1983
|
+
width: Math.max(1, frame.width),
|
|
1984
|
+
height: Math.max(1, frame.height),
|
|
1985
|
+
left: frame.left + frame.width / 2,
|
|
1986
|
+
top: frame.top + frame.height / 2
|
|
1987
|
+
};
|
|
1695
1988
|
}
|
|
1696
1989
|
async fitImageToDefaultArea(id) {
|
|
1697
1990
|
if (!this.canvasService) return;
|
|
@@ -1700,13 +1993,14 @@ var ImageTool = class {
|
|
|
1700
1993
|
await this.fitImageToArea(id, area);
|
|
1701
1994
|
return;
|
|
1702
1995
|
}
|
|
1703
|
-
const
|
|
1704
|
-
const
|
|
1996
|
+
const viewport = this.canvasService.getSceneViewportRect();
|
|
1997
|
+
const canvasW = Math.max(1, viewport.width || 0);
|
|
1998
|
+
const canvasH = Math.max(1, viewport.height || 0);
|
|
1705
1999
|
await this.fitImageToArea(id, {
|
|
1706
2000
|
width: canvasW,
|
|
1707
2001
|
height: canvasH,
|
|
1708
|
-
left: canvasW / 2,
|
|
1709
|
-
top: canvasH / 2
|
|
2002
|
+
left: viewport.left + canvasW / 2,
|
|
2003
|
+
top: viewport.top + canvasH / 2
|
|
1710
2004
|
});
|
|
1711
2005
|
}
|
|
1712
2006
|
getImageObjects() {
|
|
@@ -1794,13 +2088,17 @@ var ImageTool = class {
|
|
|
1794
2088
|
}
|
|
1795
2089
|
toSceneGeometryLike(raw) {
|
|
1796
2090
|
const shape = raw == null ? void 0 : raw.shape;
|
|
1797
|
-
if (shape
|
|
2091
|
+
if (!isDielineShape(shape)) {
|
|
1798
2092
|
return null;
|
|
1799
2093
|
}
|
|
1800
|
-
const
|
|
1801
|
-
const
|
|
2094
|
+
const radiusRaw = Number(raw == null ? void 0 : raw.radius);
|
|
2095
|
+
const offsetRaw = Number(raw == null ? void 0 : raw.offset);
|
|
2096
|
+
const unit = typeof (raw == null ? void 0 : raw.unit) === "string" ? raw.unit : "px";
|
|
2097
|
+
const radius = unit === "scene" || !this.canvasService ? radiusRaw : this.canvasService.toSceneLength(radiusRaw);
|
|
2098
|
+
const offset = unit === "scene" || !this.canvasService ? offsetRaw : this.canvasService.toSceneLength(offsetRaw);
|
|
1802
2099
|
return {
|
|
1803
2100
|
shape,
|
|
2101
|
+
shapeStyle: normalizeShapeStyle(raw == null ? void 0 : raw.shapeStyle),
|
|
1804
2102
|
radius: Number.isFinite(radius) ? radius : 0,
|
|
1805
2103
|
offset: Number.isFinite(offset) ? offset : 0
|
|
1806
2104
|
};
|
|
@@ -1852,8 +2150,11 @@ var ImageTool = class {
|
|
|
1852
2150
|
return Math.max(0, Math.min(maxRadius, rawCutRadius));
|
|
1853
2151
|
}
|
|
1854
2152
|
getCropShapeHatchPattern(color = "rgba(255, 0, 0, 0.6)") {
|
|
2153
|
+
var _a;
|
|
1855
2154
|
if (typeof document === "undefined") return void 0;
|
|
1856
|
-
|
|
2155
|
+
const sceneScale = ((_a = this.canvasService) == null ? void 0 : _a.getSceneScale()) || 1;
|
|
2156
|
+
const cacheKey = `${color}::${sceneScale.toFixed(6)}`;
|
|
2157
|
+
if (this.cropShapeHatchPattern && this.cropShapeHatchPatternColor === color && this.cropShapeHatchPatternKey === cacheKey) {
|
|
1857
2158
|
return this.cropShapeHatchPattern;
|
|
1858
2159
|
}
|
|
1859
2160
|
const size = 16;
|
|
@@ -1882,11 +2183,21 @@ var ImageTool = class {
|
|
|
1882
2183
|
// @ts-ignore: Fabric Pattern accepts canvas source here.
|
|
1883
2184
|
repetition: "repeat"
|
|
1884
2185
|
});
|
|
2186
|
+
pattern.patternTransform = [
|
|
2187
|
+
1 / sceneScale,
|
|
2188
|
+
0,
|
|
2189
|
+
0,
|
|
2190
|
+
1 / sceneScale,
|
|
2191
|
+
0,
|
|
2192
|
+
0
|
|
2193
|
+
];
|
|
1885
2194
|
this.cropShapeHatchPattern = pattern;
|
|
1886
2195
|
this.cropShapeHatchPatternColor = color;
|
|
2196
|
+
this.cropShapeHatchPatternKey = cacheKey;
|
|
1887
2197
|
return pattern;
|
|
1888
2198
|
}
|
|
1889
2199
|
buildCropShapeOverlaySpecs(frame, sceneGeometry) {
|
|
2200
|
+
var _a, _b;
|
|
1890
2201
|
if (!sceneGeometry) {
|
|
1891
2202
|
this.debug("overlay:shape:skip", { reason: "scene-geometry-missing" });
|
|
1892
2203
|
return [];
|
|
@@ -1896,6 +2207,7 @@ var ImageTool = class {
|
|
|
1896
2207
|
return [];
|
|
1897
2208
|
}
|
|
1898
2209
|
const shape = sceneGeometry.shape;
|
|
2210
|
+
const shapeStyle = sceneGeometry.shapeStyle;
|
|
1899
2211
|
const inset = 0;
|
|
1900
2212
|
const shapeWidth = Math.max(1, frame.width);
|
|
1901
2213
|
const shapeHeight = Math.max(1, frame.height);
|
|
@@ -1905,6 +2217,7 @@ var ImageTool = class {
|
|
|
1905
2217
|
frameWidth: frame.width,
|
|
1906
2218
|
frameHeight: frame.height,
|
|
1907
2219
|
offset: sceneGeometry.offset,
|
|
2220
|
+
shapeStyle,
|
|
1908
2221
|
inset,
|
|
1909
2222
|
shapeWidth,
|
|
1910
2223
|
shapeHeight,
|
|
@@ -1926,6 +2239,7 @@ var ImageTool = class {
|
|
|
1926
2239
|
x: frame.width / 2,
|
|
1927
2240
|
y: frame.height / 2,
|
|
1928
2241
|
features: [],
|
|
2242
|
+
shapeStyle,
|
|
1929
2243
|
canvasWidth: frame.width,
|
|
1930
2244
|
canvasHeight: frame.height
|
|
1931
2245
|
};
|
|
@@ -1943,6 +2257,9 @@ var ImageTool = class {
|
|
|
1943
2257
|
}
|
|
1944
2258
|
const patternFill = this.getCropShapeHatchPattern();
|
|
1945
2259
|
const hatchFill = patternFill || "rgba(255, 0, 0, 0.22)";
|
|
2260
|
+
const shapeBounds = getPathBounds(shapePathData);
|
|
2261
|
+
const hatchBounds = getPathBounds(hatchPathData);
|
|
2262
|
+
const frameRect = this.toLayoutSceneRect(frame);
|
|
1946
2263
|
const hatchPathLength = hatchPathData.length;
|
|
1947
2264
|
const shapePathLength = shapePathData.length;
|
|
1948
2265
|
const specs = [
|
|
@@ -1950,10 +2267,16 @@ var ImageTool = class {
|
|
|
1950
2267
|
id: "image.cropShapeHatch",
|
|
1951
2268
|
type: "path",
|
|
1952
2269
|
data: { id: "image.cropShapeHatch", zIndex: 5 },
|
|
2270
|
+
layout: {
|
|
2271
|
+
reference: "custom",
|
|
2272
|
+
referenceRect: frameRect,
|
|
2273
|
+
alignX: "start",
|
|
2274
|
+
alignY: "start",
|
|
2275
|
+
offsetX: hatchBounds.x,
|
|
2276
|
+
offsetY: hatchBounds.y
|
|
2277
|
+
},
|
|
1953
2278
|
props: {
|
|
1954
2279
|
pathData: hatchPathData,
|
|
1955
|
-
left: frame.left,
|
|
1956
|
-
top: frame.top,
|
|
1957
2280
|
originX: "left",
|
|
1958
2281
|
originY: "top",
|
|
1959
2282
|
fill: hatchFill,
|
|
@@ -1970,15 +2293,21 @@ var ImageTool = class {
|
|
|
1970
2293
|
id: "image.cropShapePath",
|
|
1971
2294
|
type: "path",
|
|
1972
2295
|
data: { id: "image.cropShapePath", zIndex: 6 },
|
|
2296
|
+
layout: {
|
|
2297
|
+
reference: "custom",
|
|
2298
|
+
referenceRect: frameRect,
|
|
2299
|
+
alignX: "start",
|
|
2300
|
+
alignY: "start",
|
|
2301
|
+
offsetX: shapeBounds.x,
|
|
2302
|
+
offsetY: shapeBounds.y
|
|
2303
|
+
},
|
|
1973
2304
|
props: {
|
|
1974
2305
|
pathData: shapePathData,
|
|
1975
|
-
left: frame.left,
|
|
1976
|
-
top: frame.top,
|
|
1977
2306
|
originX: "left",
|
|
1978
2307
|
originY: "top",
|
|
1979
2308
|
fill: "rgba(0,0,0,0)",
|
|
1980
2309
|
stroke: "rgba(255, 0, 0, 0.9)",
|
|
1981
|
-
strokeWidth: 1,
|
|
2310
|
+
strokeWidth: (_b = (_a = this.canvasService) == null ? void 0 : _a.toSceneLength(1)) != null ? _b : 1,
|
|
1982
2311
|
selectable: false,
|
|
1983
2312
|
evented: false,
|
|
1984
2313
|
excludeFromExport: true,
|
|
@@ -1995,6 +2324,8 @@ var ImageTool = class {
|
|
|
1995
2324
|
fillRule: "evenodd",
|
|
1996
2325
|
shapePathLength,
|
|
1997
2326
|
hatchPathLength,
|
|
2327
|
+
shapeBounds,
|
|
2328
|
+
hatchBounds,
|
|
1998
2329
|
hatchFillType: hatchFill && typeof hatchFill === "object" ? "pattern" : "color",
|
|
1999
2330
|
ids: specs.map((spec) => spec.id)
|
|
2000
2331
|
});
|
|
@@ -2057,6 +2388,28 @@ var ImageTool = class {
|
|
|
2057
2388
|
opacity: render.opacity
|
|
2058
2389
|
};
|
|
2059
2390
|
}
|
|
2391
|
+
toScreenObjectProps(props) {
|
|
2392
|
+
if (!this.canvasService) return props;
|
|
2393
|
+
const next = { ...props };
|
|
2394
|
+
if (Number.isFinite(next.left) || Number.isFinite(next.top)) {
|
|
2395
|
+
const mapped = this.canvasService.toScreenPoint({
|
|
2396
|
+
x: Number.isFinite(next.left) ? Number(next.left) : 0,
|
|
2397
|
+
y: Number.isFinite(next.top) ? Number(next.top) : 0
|
|
2398
|
+
});
|
|
2399
|
+
if (Number.isFinite(next.left)) next.left = mapped.x;
|
|
2400
|
+
if (Number.isFinite(next.top)) next.top = mapped.y;
|
|
2401
|
+
}
|
|
2402
|
+
const sceneScale = this.canvasService.getSceneScale();
|
|
2403
|
+
const sx = Number.isFinite(next.scaleX) ? Number(next.scaleX) : 1;
|
|
2404
|
+
const sy = Number.isFinite(next.scaleY) ? Number(next.scaleY) : 1;
|
|
2405
|
+
next.scaleX = sx * sceneScale;
|
|
2406
|
+
next.scaleY = sy * sceneScale;
|
|
2407
|
+
return next;
|
|
2408
|
+
}
|
|
2409
|
+
toSceneObjectScale(value) {
|
|
2410
|
+
if (!this.canvasService) return value;
|
|
2411
|
+
return value / this.canvasService.getSceneScale();
|
|
2412
|
+
}
|
|
2060
2413
|
getCurrentSrc(obj) {
|
|
2061
2414
|
var _a;
|
|
2062
2415
|
if (!obj) return void 0;
|
|
@@ -2106,8 +2459,9 @@ var ImageTool = class {
|
|
|
2106
2459
|
this.rememberSourceSize(render.src, obj);
|
|
2107
2460
|
const sourceSize = this.getSourceSize(render.src, obj);
|
|
2108
2461
|
const props = this.computeCanvasProps(render, sourceSize, frame);
|
|
2462
|
+
const screenProps = this.toScreenObjectProps(props);
|
|
2109
2463
|
obj.set({
|
|
2110
|
-
...
|
|
2464
|
+
...screenProps,
|
|
2111
2465
|
data: {
|
|
2112
2466
|
...obj.data || {},
|
|
2113
2467
|
id: item.id,
|
|
@@ -2173,37 +2527,67 @@ var ImageTool = class {
|
|
|
2173
2527
|
});
|
|
2174
2528
|
return [];
|
|
2175
2529
|
}
|
|
2176
|
-
const
|
|
2177
|
-
const
|
|
2530
|
+
const viewport = this.canvasService.getSceneViewportRect();
|
|
2531
|
+
const canvasW = viewport.width || 0;
|
|
2532
|
+
const canvasH = viewport.height || 0;
|
|
2533
|
+
const canvasLeft = viewport.left || 0;
|
|
2534
|
+
const canvasTop = viewport.top || 0;
|
|
2178
2535
|
const visual = this.getFrameVisualConfig();
|
|
2179
|
-
const
|
|
2180
|
-
|
|
2536
|
+
const strokeWidthScene = this.canvasService.toSceneLength(
|
|
2537
|
+
visual.strokeWidth
|
|
2538
|
+
);
|
|
2539
|
+
const dashLengthScene = this.canvasService.toSceneLength(visual.dashLength);
|
|
2540
|
+
const frameLeft = Math.max(
|
|
2541
|
+
canvasLeft,
|
|
2542
|
+
Math.min(canvasLeft + canvasW, frame.left)
|
|
2543
|
+
);
|
|
2544
|
+
const frameTop = Math.max(
|
|
2545
|
+
canvasTop,
|
|
2546
|
+
Math.min(canvasTop + canvasH, frame.top)
|
|
2547
|
+
);
|
|
2181
2548
|
const frameRight = Math.max(
|
|
2182
2549
|
frameLeft,
|
|
2183
|
-
Math.min(canvasW, frame.left + frame.width)
|
|
2550
|
+
Math.min(canvasLeft + canvasW, frame.left + frame.width)
|
|
2184
2551
|
);
|
|
2185
2552
|
const frameBottom = Math.max(
|
|
2186
2553
|
frameTop,
|
|
2187
|
-
Math.min(canvasH, frame.top + frame.height)
|
|
2554
|
+
Math.min(canvasTop + canvasH, frame.top + frame.height)
|
|
2188
2555
|
);
|
|
2189
2556
|
const visibleFrameH = Math.max(0, frameBottom - frameTop);
|
|
2190
|
-
const topH = frameTop;
|
|
2191
|
-
const bottomH = Math.max(0, canvasH - frameBottom);
|
|
2192
|
-
const leftW = frameLeft;
|
|
2193
|
-
const rightW = Math.max(0, canvasW - frameRight);
|
|
2557
|
+
const topH = Math.max(0, frameTop - canvasTop);
|
|
2558
|
+
const bottomH = Math.max(0, canvasTop + canvasH - frameBottom);
|
|
2559
|
+
const leftW = Math.max(0, frameLeft - canvasLeft);
|
|
2560
|
+
const rightW = Math.max(0, canvasLeft + canvasW - frameRight);
|
|
2561
|
+
const viewportRect = this.toLayoutSceneRect({
|
|
2562
|
+
left: canvasLeft,
|
|
2563
|
+
top: canvasTop,
|
|
2564
|
+
width: canvasW,
|
|
2565
|
+
height: canvasH
|
|
2566
|
+
});
|
|
2567
|
+
const visibleFrameBandRect = this.toLayoutSceneRect({
|
|
2568
|
+
left: canvasLeft,
|
|
2569
|
+
top: frameTop,
|
|
2570
|
+
width: canvasW,
|
|
2571
|
+
height: visibleFrameH
|
|
2572
|
+
});
|
|
2573
|
+
const frameRect = this.toLayoutSceneRect(frame);
|
|
2194
2574
|
const shapeOverlay = this.buildCropShapeOverlaySpecs(frame, sceneGeometry);
|
|
2195
2575
|
const mask = [
|
|
2196
2576
|
{
|
|
2197
2577
|
id: "image.cropMask.top",
|
|
2198
2578
|
type: "rect",
|
|
2199
2579
|
data: { id: "image.cropMask.top", zIndex: 1 },
|
|
2580
|
+
layout: {
|
|
2581
|
+
reference: "custom",
|
|
2582
|
+
referenceRect: viewportRect,
|
|
2583
|
+
alignX: "start",
|
|
2584
|
+
alignY: "start",
|
|
2585
|
+
width: "100%",
|
|
2586
|
+
height: topH
|
|
2587
|
+
},
|
|
2200
2588
|
props: {
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
width: canvasW,
|
|
2204
|
-
height: topH,
|
|
2205
|
-
originX: "center",
|
|
2206
|
-
originY: "center",
|
|
2589
|
+
originX: "left",
|
|
2590
|
+
originY: "top",
|
|
2207
2591
|
fill: visual.outerBackground,
|
|
2208
2592
|
selectable: false,
|
|
2209
2593
|
evented: false
|
|
@@ -2213,13 +2597,17 @@ var ImageTool = class {
|
|
|
2213
2597
|
id: "image.cropMask.bottom",
|
|
2214
2598
|
type: "rect",
|
|
2215
2599
|
data: { id: "image.cropMask.bottom", zIndex: 2 },
|
|
2600
|
+
layout: {
|
|
2601
|
+
reference: "custom",
|
|
2602
|
+
referenceRect: viewportRect,
|
|
2603
|
+
alignX: "start",
|
|
2604
|
+
alignY: "end",
|
|
2605
|
+
width: "100%",
|
|
2606
|
+
height: bottomH
|
|
2607
|
+
},
|
|
2216
2608
|
props: {
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
width: canvasW,
|
|
2220
|
-
height: bottomH,
|
|
2221
|
-
originX: "center",
|
|
2222
|
-
originY: "center",
|
|
2609
|
+
originX: "left",
|
|
2610
|
+
originY: "top",
|
|
2223
2611
|
fill: visual.outerBackground,
|
|
2224
2612
|
selectable: false,
|
|
2225
2613
|
evented: false
|
|
@@ -2229,13 +2617,17 @@ var ImageTool = class {
|
|
|
2229
2617
|
id: "image.cropMask.left",
|
|
2230
2618
|
type: "rect",
|
|
2231
2619
|
data: { id: "image.cropMask.left", zIndex: 3 },
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2620
|
+
layout: {
|
|
2621
|
+
reference: "custom",
|
|
2622
|
+
referenceRect: visibleFrameBandRect,
|
|
2623
|
+
alignX: "start",
|
|
2624
|
+
alignY: "start",
|
|
2235
2625
|
width: leftW,
|
|
2236
|
-
height:
|
|
2237
|
-
|
|
2238
|
-
|
|
2626
|
+
height: "100%"
|
|
2627
|
+
},
|
|
2628
|
+
props: {
|
|
2629
|
+
originX: "left",
|
|
2630
|
+
originY: "top",
|
|
2239
2631
|
fill: visual.outerBackground,
|
|
2240
2632
|
selectable: false,
|
|
2241
2633
|
evented: false
|
|
@@ -2245,13 +2637,17 @@ var ImageTool = class {
|
|
|
2245
2637
|
id: "image.cropMask.right",
|
|
2246
2638
|
type: "rect",
|
|
2247
2639
|
data: { id: "image.cropMask.right", zIndex: 4 },
|
|
2248
|
-
|
|
2249
|
-
|
|
2250
|
-
|
|
2640
|
+
layout: {
|
|
2641
|
+
reference: "custom",
|
|
2642
|
+
referenceRect: visibleFrameBandRect,
|
|
2643
|
+
alignX: "end",
|
|
2644
|
+
alignY: "start",
|
|
2251
2645
|
width: rightW,
|
|
2252
|
-
height:
|
|
2253
|
-
|
|
2254
|
-
|
|
2646
|
+
height: "100%"
|
|
2647
|
+
},
|
|
2648
|
+
props: {
|
|
2649
|
+
originX: "left",
|
|
2650
|
+
originY: "top",
|
|
2255
2651
|
fill: visual.outerBackground,
|
|
2256
2652
|
selectable: false,
|
|
2257
2653
|
evented: false
|
|
@@ -2262,17 +2658,21 @@ var ImageTool = class {
|
|
|
2262
2658
|
id: "image.cropFrame",
|
|
2263
2659
|
type: "rect",
|
|
2264
2660
|
data: { id: "image.cropFrame", zIndex: 7 },
|
|
2661
|
+
layout: {
|
|
2662
|
+
reference: "custom",
|
|
2663
|
+
referenceRect: frameRect,
|
|
2664
|
+
alignX: "start",
|
|
2665
|
+
alignY: "start",
|
|
2666
|
+
width: "100%",
|
|
2667
|
+
height: "100%"
|
|
2668
|
+
},
|
|
2265
2669
|
props: {
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
width: frame.width,
|
|
2269
|
-
height: frame.height,
|
|
2270
|
-
originX: "center",
|
|
2271
|
-
originY: "center",
|
|
2670
|
+
originX: "left",
|
|
2671
|
+
originY: "top",
|
|
2272
2672
|
fill: visual.innerBackground,
|
|
2273
2673
|
stroke: visual.strokeStyle === "hidden" ? "rgba(0,0,0,0)" : visual.strokeColor,
|
|
2274
|
-
strokeWidth: visual.strokeStyle === "hidden" ? 0 :
|
|
2275
|
-
strokeDashArray: visual.strokeStyle === "dashed" ? [
|
|
2674
|
+
strokeWidth: visual.strokeStyle === "hidden" ? 0 : strokeWidthScene,
|
|
2675
|
+
strokeDashArray: visual.strokeStyle === "dashed" ? [dashLengthScene, dashLengthScene] : void 0,
|
|
2276
2676
|
selectable: false,
|
|
2277
2677
|
evented: false
|
|
2278
2678
|
}
|
|
@@ -2323,10 +2723,8 @@ var ImageTool = class {
|
|
|
2323
2723
|
const sceneGeometry = await this.resolveSceneGeometryForOverlay();
|
|
2324
2724
|
if (seq !== this.renderSeq) return;
|
|
2325
2725
|
const overlaySpecs = this.buildOverlaySpecs(frame, sceneGeometry);
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
overlaySpecs
|
|
2329
|
-
);
|
|
2726
|
+
this.overlaySpecs = overlaySpecs;
|
|
2727
|
+
await this.canvasService.flushRenderFromProducers();
|
|
2330
2728
|
this.syncImageZOrder(renderItems);
|
|
2331
2729
|
const overlayCanvasCount = this.getOverlayObjects().length;
|
|
2332
2730
|
this.debug("render:done", {
|
|
@@ -2417,7 +2815,7 @@ var ImageTool = class {
|
|
|
2417
2815
|
const source = this.getSourceSize(render.src, obj);
|
|
2418
2816
|
const frame = this.getFrameRect();
|
|
2419
2817
|
const coverScale = this.getCoverScale(frame, source);
|
|
2420
|
-
const currentScale = obj.scaleX || 1;
|
|
2818
|
+
const currentScale = this.toSceneObjectScale(obj.scaleX || 1);
|
|
2421
2819
|
const zoom = Math.max(0.05, currentScale / coverScale);
|
|
2422
2820
|
const updated = {
|
|
2423
2821
|
scale: Number.isFinite(zoom) ? zoom : 1,
|
|
@@ -2454,12 +2852,13 @@ var ImageTool = class {
|
|
|
2454
2852
|
Math.max(1, area.width) / Math.max(1, source.width),
|
|
2455
2853
|
Math.max(1, area.height) / Math.max(1, source.height)
|
|
2456
2854
|
);
|
|
2457
|
-
const
|
|
2458
|
-
const
|
|
2855
|
+
const viewport = this.canvasService.getSceneViewportRect();
|
|
2856
|
+
const canvasW = viewport.width || 1;
|
|
2857
|
+
const canvasH = viewport.height || 1;
|
|
2459
2858
|
const areaLeftInput = (_a = area.left) != null ? _a : 0.5;
|
|
2460
2859
|
const areaTopInput = (_b = area.top) != null ? _b : 0.5;
|
|
2461
|
-
const areaLeftPx = areaLeftInput <= 1.5 ? areaLeftInput * canvasW : areaLeftInput;
|
|
2462
|
-
const areaTopPx = areaTopInput <= 1.5 ? areaTopInput * canvasH : areaTopInput;
|
|
2860
|
+
const areaLeftPx = areaLeftInput <= 1.5 ? viewport.left + areaLeftInput * canvasW : areaLeftInput;
|
|
2861
|
+
const areaTopPx = areaTopInput <= 1.5 ? viewport.top + areaTopInput * canvasH : areaTopInput;
|
|
2463
2862
|
const updates = {
|
|
2464
2863
|
scale: Math.max(0.05, desiredScale / baseCover),
|
|
2465
2864
|
left: this.clampNormalized(
|
|
@@ -2497,6 +2896,8 @@ var ImageTool = class {
|
|
|
2497
2896
|
this.normalizeItem({
|
|
2498
2897
|
...item,
|
|
2499
2898
|
url,
|
|
2899
|
+
// Keep original source for next image-tool session editing,
|
|
2900
|
+
// and use committedUrl as non-image-tools render source.
|
|
2500
2901
|
sourceUrl,
|
|
2501
2902
|
committedUrl: url
|
|
2502
2903
|
})
|
|
@@ -2522,7 +2923,8 @@ var ImageTool = class {
|
|
|
2522
2923
|
if (!normalizedIds.length) {
|
|
2523
2924
|
throw new Error("image-ids-required");
|
|
2524
2925
|
}
|
|
2525
|
-
const
|
|
2926
|
+
const frameScene = this.getFrameRect();
|
|
2927
|
+
const frame = this.getFrameRectScreen(frameScene);
|
|
2526
2928
|
const multiplier = Math.max(1, (_a = options.multiplier) != null ? _a : 2);
|
|
2527
2929
|
const format = options.format === "jpeg" ? "jpeg" : "png";
|
|
2528
2930
|
const width = Math.max(1, Math.round(frame.width * multiplier));
|
|
@@ -3400,14 +3802,10 @@ var ImageTracer = class {
|
|
|
3400
3802
|
};
|
|
3401
3803
|
}
|
|
3402
3804
|
const baseUnpaddedContours = baseContours.map(
|
|
3403
|
-
(contour) =>
|
|
3404
|
-
|
|
3405
|
-
|
|
3406
|
-
|
|
3407
|
-
})),
|
|
3408
|
-
width,
|
|
3409
|
-
height
|
|
3410
|
-
)
|
|
3805
|
+
(contour) => contour.map((p) => ({
|
|
3806
|
+
x: p.x - padding,
|
|
3807
|
+
y: p.y - padding
|
|
3808
|
+
}))
|
|
3411
3809
|
).filter((contour) => contour.length > 2);
|
|
3412
3810
|
if (!baseUnpaddedContours.length) {
|
|
3413
3811
|
const w = (_h = options.scaleToWidth) != null ? _h : width;
|
|
@@ -3496,13 +3894,46 @@ var ImageTracer = class {
|
|
|
3496
3894
|
this.flattenContours(baseScaledContours)
|
|
3497
3895
|
);
|
|
3498
3896
|
}
|
|
3499
|
-
|
|
3500
|
-
|
|
3501
|
-
|
|
3502
|
-
|
|
3503
|
-
|
|
3504
|
-
|
|
3505
|
-
|
|
3897
|
+
if (expand > 0) {
|
|
3898
|
+
const expectedExpandedBounds = {
|
|
3899
|
+
x: baseBounds.x - expand,
|
|
3900
|
+
y: baseBounds.y - expand,
|
|
3901
|
+
width: baseBounds.width + expand * 2,
|
|
3902
|
+
height: baseBounds.height + expand * 2
|
|
3903
|
+
};
|
|
3904
|
+
if (expectedExpandedBounds.width > 0 && expectedExpandedBounds.height > 0 && globalBounds.width > 0 && globalBounds.height > 0) {
|
|
3905
|
+
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;
|
|
3906
|
+
if (shouldNormalizeExpandBounds) {
|
|
3907
|
+
const beforeNormalize = globalBounds;
|
|
3908
|
+
finalContours = this.translateContours(
|
|
3909
|
+
this.scaleContours(
|
|
3910
|
+
finalContours,
|
|
3911
|
+
expectedExpandedBounds.width,
|
|
3912
|
+
expectedExpandedBounds.height,
|
|
3913
|
+
globalBounds
|
|
3914
|
+
),
|
|
3915
|
+
expectedExpandedBounds.x,
|
|
3916
|
+
expectedExpandedBounds.y
|
|
3917
|
+
);
|
|
3918
|
+
globalBounds = this.boundsFromPoints(
|
|
3919
|
+
this.flattenContours(finalContours)
|
|
3920
|
+
);
|
|
3921
|
+
debugLog("traceWithBounds:expand-normalized", {
|
|
3922
|
+
expand,
|
|
3923
|
+
expectedExpandedBounds,
|
|
3924
|
+
beforeNormalize,
|
|
3925
|
+
afterNormalize: globalBounds
|
|
3926
|
+
});
|
|
3927
|
+
}
|
|
3928
|
+
}
|
|
3929
|
+
}
|
|
3930
|
+
debugLog("traceWithBounds:contours", {
|
|
3931
|
+
baseContourCount: baseContoursRaw.length,
|
|
3932
|
+
baseSelectedCount: baseContours.length,
|
|
3933
|
+
expandedContourCount: expandedContoursRaw.length,
|
|
3934
|
+
expandedSelectedCount: expandedContours.length,
|
|
3935
|
+
baseBounds,
|
|
3936
|
+
expandedBounds: globalBounds,
|
|
3506
3937
|
expandedDeltaX: globalBounds.width - baseBounds.width,
|
|
3507
3938
|
expandedDeltaY: globalBounds.height - baseBounds.height,
|
|
3508
3939
|
expandedMayOverflowImageBounds: expand > 0,
|
|
@@ -3858,13 +4289,13 @@ var ImageTracer = class {
|
|
|
3858
4289
|
(points) => this.scalePoints(points, targetWidth, targetHeight, bounds)
|
|
3859
4290
|
);
|
|
3860
4291
|
}
|
|
3861
|
-
static
|
|
3862
|
-
|
|
3863
|
-
|
|
3864
|
-
|
|
3865
|
-
|
|
3866
|
-
|
|
3867
|
-
|
|
4292
|
+
static translateContours(contours, offsetX, offsetY) {
|
|
4293
|
+
return contours.map(
|
|
4294
|
+
(points) => points.map((p) => ({
|
|
4295
|
+
x: p.x + offsetX,
|
|
4296
|
+
y: p.y + offsetY
|
|
4297
|
+
}))
|
|
4298
|
+
);
|
|
3868
4299
|
}
|
|
3869
4300
|
static pointsToSVG(points) {
|
|
3870
4301
|
if (points.length === 0) return "";
|
|
@@ -3917,6 +4348,7 @@ var ImageTracer = class {
|
|
|
3917
4348
|
|
|
3918
4349
|
// src/extensions/dieline.ts
|
|
3919
4350
|
var IMAGE_OBJECT_LAYER_ID2 = "image.user";
|
|
4351
|
+
var DIELINE_LAYER_ID = "dieline-overlay";
|
|
3920
4352
|
var DielineTool = class {
|
|
3921
4353
|
constructor(options) {
|
|
3922
4354
|
this.id = "pooder.kit.dieline";
|
|
@@ -3924,8 +4356,8 @@ var DielineTool = class {
|
|
|
3924
4356
|
name: "DielineTool"
|
|
3925
4357
|
};
|
|
3926
4358
|
this.state = {
|
|
3927
|
-
|
|
3928
|
-
|
|
4359
|
+
shape: DEFAULT_DIELINE_SHAPE,
|
|
4360
|
+
shapeStyle: { ...DEFAULT_DIELINE_SHAPE_STYLE },
|
|
3929
4361
|
width: 500,
|
|
3930
4362
|
height: 500,
|
|
3931
4363
|
radius: 0,
|
|
@@ -3948,6 +4380,8 @@ var DielineTool = class {
|
|
|
3948
4380
|
showBleedLines: true,
|
|
3949
4381
|
features: []
|
|
3950
4382
|
};
|
|
4383
|
+
this.specs = [];
|
|
4384
|
+
this.renderSeq = 0;
|
|
3951
4385
|
this.onCanvasResized = () => {
|
|
3952
4386
|
this.updateDieline();
|
|
3953
4387
|
};
|
|
@@ -3960,24 +4394,50 @@ var DielineTool = class {
|
|
|
3960
4394
|
Object.assign(this.state.offsetLine, options.offsetLine);
|
|
3961
4395
|
delete options.offsetLine;
|
|
3962
4396
|
}
|
|
4397
|
+
if (options.shapeStyle) {
|
|
4398
|
+
this.state.shapeStyle = normalizeShapeStyle(
|
|
4399
|
+
options.shapeStyle,
|
|
4400
|
+
this.state.shapeStyle
|
|
4401
|
+
);
|
|
4402
|
+
delete options.shapeStyle;
|
|
4403
|
+
}
|
|
3963
4404
|
Object.assign(this.state, options);
|
|
4405
|
+
this.state.shape = normalizeDielineShape(options.shape, this.state.shape);
|
|
3964
4406
|
}
|
|
3965
4407
|
}
|
|
3966
4408
|
activate(context) {
|
|
4409
|
+
var _a;
|
|
3967
4410
|
this.context = context;
|
|
3968
4411
|
this.canvasService = context.services.get("CanvasService");
|
|
3969
4412
|
if (!this.canvasService) {
|
|
3970
4413
|
console.warn("CanvasService not found for DielineTool");
|
|
3971
4414
|
return;
|
|
3972
4415
|
}
|
|
4416
|
+
(_a = this.renderProducerDisposable) == null ? void 0 : _a.dispose();
|
|
4417
|
+
this.renderProducerDisposable = this.canvasService.registerRenderProducer(
|
|
4418
|
+
this.id,
|
|
4419
|
+
() => ({
|
|
4420
|
+
layerSpecs: {
|
|
4421
|
+
[DIELINE_LAYER_ID]: this.specs
|
|
4422
|
+
},
|
|
4423
|
+
replaceLayerIds: [DIELINE_LAYER_ID]
|
|
4424
|
+
}),
|
|
4425
|
+
{ priority: 250 }
|
|
4426
|
+
);
|
|
3973
4427
|
const configService = context.services.get(
|
|
3974
4428
|
"ConfigurationService"
|
|
3975
4429
|
);
|
|
3976
4430
|
if (configService) {
|
|
3977
4431
|
const s = this.state;
|
|
3978
4432
|
const sizeState = readSizeState(configService);
|
|
3979
|
-
s.
|
|
3980
|
-
|
|
4433
|
+
s.shape = normalizeDielineShape(
|
|
4434
|
+
configService.get("dieline.shape", s.shape),
|
|
4435
|
+
s.shape
|
|
4436
|
+
);
|
|
4437
|
+
s.shapeStyle = normalizeShapeStyle(
|
|
4438
|
+
configService.get("dieline.shapeStyle", s.shapeStyle),
|
|
4439
|
+
s.shapeStyle
|
|
4440
|
+
);
|
|
3981
4441
|
s.width = sizeState.actualWidthMm;
|
|
3982
4442
|
s.height = sizeState.actualHeightMm;
|
|
3983
4443
|
s.radius = parseLengthToMm(
|
|
@@ -4026,10 +4486,17 @@ var DielineTool = class {
|
|
|
4026
4486
|
);
|
|
4027
4487
|
s.features = configService.get("dieline.features", s.features);
|
|
4028
4488
|
s.pathData = configService.get("dieline.pathData", s.pathData);
|
|
4489
|
+
const sourceWidth = Number(
|
|
4490
|
+
configService.get("dieline.customSourceWidthPx", 0)
|
|
4491
|
+
);
|
|
4492
|
+
const sourceHeight = Number(
|
|
4493
|
+
configService.get("dieline.customSourceHeightPx", 0)
|
|
4494
|
+
);
|
|
4495
|
+
s.customSourceWidthPx = Number.isFinite(sourceWidth) && sourceWidth > 0 ? sourceWidth : void 0;
|
|
4496
|
+
s.customSourceHeightPx = Number.isFinite(sourceHeight) && sourceHeight > 0 ? sourceHeight : void 0;
|
|
4029
4497
|
configService.onAnyChange((e) => {
|
|
4030
4498
|
if (e.key.startsWith("size.")) {
|
|
4031
4499
|
const nextSize = readSizeState(configService);
|
|
4032
|
-
s.displayUnit = nextSize.unit;
|
|
4033
4500
|
s.width = nextSize.actualWidthMm;
|
|
4034
4501
|
s.height = nextSize.actualHeightMm;
|
|
4035
4502
|
s.padding = nextSize.viewPadding;
|
|
@@ -4040,7 +4507,10 @@ var DielineTool = class {
|
|
|
4040
4507
|
if (e.key.startsWith("dieline.")) {
|
|
4041
4508
|
switch (e.key) {
|
|
4042
4509
|
case "dieline.shape":
|
|
4043
|
-
s.shape = e.value;
|
|
4510
|
+
s.shape = normalizeDielineShape(e.value, s.shape);
|
|
4511
|
+
break;
|
|
4512
|
+
case "dieline.shapeStyle":
|
|
4513
|
+
s.shapeStyle = normalizeShapeStyle(e.value, s.shapeStyle);
|
|
4044
4514
|
break;
|
|
4045
4515
|
case "dieline.radius":
|
|
4046
4516
|
s.radius = parseLengthToMm(e.value, "mm");
|
|
@@ -4084,18 +4554,30 @@ var DielineTool = class {
|
|
|
4084
4554
|
case "dieline.pathData":
|
|
4085
4555
|
s.pathData = e.value;
|
|
4086
4556
|
break;
|
|
4557
|
+
case "dieline.customSourceWidthPx":
|
|
4558
|
+
s.customSourceWidthPx = Number.isFinite(Number(e.value)) && Number(e.value) > 0 ? Number(e.value) : void 0;
|
|
4559
|
+
break;
|
|
4560
|
+
case "dieline.customSourceHeightPx":
|
|
4561
|
+
s.customSourceHeightPx = Number.isFinite(Number(e.value)) && Number(e.value) > 0 ? Number(e.value) : void 0;
|
|
4562
|
+
break;
|
|
4087
4563
|
}
|
|
4088
4564
|
this.updateDieline();
|
|
4089
4565
|
}
|
|
4090
4566
|
});
|
|
4091
4567
|
}
|
|
4092
4568
|
context.eventBus.on("canvas:resized", this.onCanvasResized);
|
|
4093
|
-
this.createLayer();
|
|
4094
4569
|
this.updateDieline();
|
|
4095
4570
|
}
|
|
4096
4571
|
deactivate(context) {
|
|
4572
|
+
var _a;
|
|
4097
4573
|
context.eventBus.off("canvas:resized", this.onCanvasResized);
|
|
4098
|
-
this.
|
|
4574
|
+
this.renderSeq += 1;
|
|
4575
|
+
this.specs = [];
|
|
4576
|
+
(_a = this.renderProducerDisposable) == null ? void 0 : _a.dispose();
|
|
4577
|
+
this.renderProducerDisposable = void 0;
|
|
4578
|
+
if (this.canvasService) {
|
|
4579
|
+
void this.canvasService.flushRenderFromProducers();
|
|
4580
|
+
}
|
|
4099
4581
|
this.canvasService = void 0;
|
|
4100
4582
|
this.context = void 0;
|
|
4101
4583
|
}
|
|
@@ -4118,7 +4600,7 @@ var DielineTool = class {
|
|
|
4118
4600
|
id: "dieline.shape",
|
|
4119
4601
|
type: "select",
|
|
4120
4602
|
label: "Shape",
|
|
4121
|
-
options:
|
|
4603
|
+
options: Array.from(DIELINE_SHAPES),
|
|
4122
4604
|
default: s.shape
|
|
4123
4605
|
},
|
|
4124
4606
|
{
|
|
@@ -4129,6 +4611,12 @@ var DielineTool = class {
|
|
|
4129
4611
|
max: 500,
|
|
4130
4612
|
default: s.radius
|
|
4131
4613
|
},
|
|
4614
|
+
{
|
|
4615
|
+
id: "dieline.shapeStyle",
|
|
4616
|
+
type: "json",
|
|
4617
|
+
label: "Shape Style",
|
|
4618
|
+
default: s.shapeStyle
|
|
4619
|
+
},
|
|
4132
4620
|
{
|
|
4133
4621
|
id: "dieline.showBleedLines",
|
|
4134
4622
|
type: "boolean",
|
|
@@ -4304,34 +4792,6 @@ var DielineTool = class {
|
|
|
4304
4792
|
]
|
|
4305
4793
|
};
|
|
4306
4794
|
}
|
|
4307
|
-
getLayer() {
|
|
4308
|
-
var _a;
|
|
4309
|
-
return (_a = this.canvasService) == null ? void 0 : _a.getLayer("dieline-overlay");
|
|
4310
|
-
}
|
|
4311
|
-
createLayer() {
|
|
4312
|
-
if (!this.canvasService) return;
|
|
4313
|
-
const width = this.canvasService.canvas.width || 800;
|
|
4314
|
-
const height = this.canvasService.canvas.height || 600;
|
|
4315
|
-
const layer = this.canvasService.createLayer("dieline-overlay", {
|
|
4316
|
-
width,
|
|
4317
|
-
height,
|
|
4318
|
-
selectable: false,
|
|
4319
|
-
evented: false
|
|
4320
|
-
});
|
|
4321
|
-
this.canvasService.canvas.bringObjectToFront(layer);
|
|
4322
|
-
const userLayer = this.canvasService.getLayer("user");
|
|
4323
|
-
if (userLayer) {
|
|
4324
|
-
const userIndex = this.canvasService.canvas.getObjects().indexOf(userLayer);
|
|
4325
|
-
this.canvasService.canvas.moveObjectTo(layer, userIndex + 1);
|
|
4326
|
-
}
|
|
4327
|
-
}
|
|
4328
|
-
destroyLayer() {
|
|
4329
|
-
if (!this.canvasService) return;
|
|
4330
|
-
const layer = this.getLayer();
|
|
4331
|
-
if (layer) {
|
|
4332
|
-
this.canvasService.canvas.remove(layer);
|
|
4333
|
-
}
|
|
4334
|
-
}
|
|
4335
4795
|
createHatchPattern(color = "rgba(0, 0, 0, 0.3)") {
|
|
4336
4796
|
if (typeof document === "undefined") {
|
|
4337
4797
|
return void 0;
|
|
@@ -4360,7 +4820,6 @@ var DielineTool = class {
|
|
|
4360
4820
|
}
|
|
4361
4821
|
syncSizeState(configService) {
|
|
4362
4822
|
const sizeState = readSizeState(configService);
|
|
4363
|
-
this.state.displayUnit = sizeState.unit;
|
|
4364
4823
|
this.state.width = sizeState.actualWidthMm;
|
|
4365
4824
|
this.state.height = sizeState.actualHeightMm;
|
|
4366
4825
|
this.state.padding = sizeState.viewPadding;
|
|
@@ -4374,20 +4833,26 @@ var DielineTool = class {
|
|
|
4374
4833
|
return ((_a = obj == null ? void 0 : obj.data) == null ? void 0 : _a.type) === "feature-marker";
|
|
4375
4834
|
}).forEach((obj) => canvas.bringObjectToFront(obj));
|
|
4376
4835
|
}
|
|
4377
|
-
|
|
4836
|
+
ensureLayerStacking() {
|
|
4378
4837
|
if (!this.canvasService) return;
|
|
4379
|
-
const layer = this.getLayer();
|
|
4838
|
+
const layer = this.canvasService.getLayer(DIELINE_LAYER_ID);
|
|
4380
4839
|
if (!layer) return;
|
|
4381
|
-
const
|
|
4382
|
-
if (
|
|
4383
|
-
|
|
4384
|
-
|
|
4385
|
-
|
|
4386
|
-
|
|
4387
|
-
|
|
4388
|
-
|
|
4840
|
+
const userLayer = this.canvasService.getLayer("user");
|
|
4841
|
+
if (userLayer) {
|
|
4842
|
+
const layerIndex = this.canvasService.canvas.getObjects().indexOf(layer);
|
|
4843
|
+
const userIndex = this.canvasService.canvas.getObjects().indexOf(userLayer);
|
|
4844
|
+
if (layerIndex < userIndex) {
|
|
4845
|
+
this.canvasService.canvas.moveObjectTo(layer, userIndex + 1);
|
|
4846
|
+
}
|
|
4847
|
+
return;
|
|
4848
|
+
}
|
|
4849
|
+
this.canvasService.canvas.bringObjectToFront(layer);
|
|
4850
|
+
}
|
|
4851
|
+
buildDielineSpecs(sceneLayout) {
|
|
4852
|
+
var _a, _b;
|
|
4389
4853
|
const {
|
|
4390
4854
|
shape,
|
|
4855
|
+
shapeStyle,
|
|
4391
4856
|
radius,
|
|
4392
4857
|
mainLine,
|
|
4393
4858
|
offsetLine,
|
|
@@ -4396,8 +4861,8 @@ var DielineTool = class {
|
|
|
4396
4861
|
showBleedLines,
|
|
4397
4862
|
features
|
|
4398
4863
|
} = this.state;
|
|
4399
|
-
const canvasW = sceneLayout.canvasWidth || this.canvasService.canvas.width || 800;
|
|
4400
|
-
const canvasH = sceneLayout.canvasHeight || this.canvasService.canvas.height || 600;
|
|
4864
|
+
const canvasW = sceneLayout.canvasWidth || ((_a = this.canvasService) == null ? void 0 : _a.canvas.width) || 800;
|
|
4865
|
+
const canvasH = sceneLayout.canvasHeight || ((_b = this.canvasService) == null ? void 0 : _b.canvas.height) || 600;
|
|
4401
4866
|
const scale = sceneLayout.scale;
|
|
4402
4867
|
const cx = sceneLayout.trimRect.centerX;
|
|
4403
4868
|
const cy = sceneLayout.trimRect.centerY;
|
|
@@ -4408,7 +4873,6 @@ var DielineTool = class {
|
|
|
4408
4873
|
const cutH = sceneLayout.cutRect.height;
|
|
4409
4874
|
const visualOffset = (cutW - visualWidth) / 2;
|
|
4410
4875
|
const cutR = visualRadius === 0 ? 0 : Math.max(0, visualRadius + visualOffset);
|
|
4411
|
-
layer.remove(...layer.getObjects());
|
|
4412
4876
|
const absoluteFeatures = (features || []).map((f) => ({
|
|
4413
4877
|
...f,
|
|
4414
4878
|
x: f.x,
|
|
@@ -4428,19 +4892,30 @@ var DielineTool = class {
|
|
|
4428
4892
|
x: cx,
|
|
4429
4893
|
y: cy,
|
|
4430
4894
|
features: cutFeatures,
|
|
4431
|
-
|
|
4432
|
-
|
|
4433
|
-
|
|
4434
|
-
|
|
4435
|
-
stroke: null,
|
|
4436
|
-
selectable: false,
|
|
4437
|
-
evented: false,
|
|
4438
|
-
originX: "left",
|
|
4439
|
-
originY: "top",
|
|
4440
|
-
left: 0,
|
|
4441
|
-
top: 0
|
|
4895
|
+
shapeStyle,
|
|
4896
|
+
pathData: this.state.pathData,
|
|
4897
|
+
customSourceWidthPx: this.state.customSourceWidthPx,
|
|
4898
|
+
customSourceHeightPx: this.state.customSourceHeightPx
|
|
4442
4899
|
});
|
|
4443
|
-
|
|
4900
|
+
const specs = [
|
|
4901
|
+
{
|
|
4902
|
+
id: "dieline.mask",
|
|
4903
|
+
type: "path",
|
|
4904
|
+
space: "screen",
|
|
4905
|
+
data: { id: "dieline.mask", type: "dieline" },
|
|
4906
|
+
props: {
|
|
4907
|
+
pathData: maskPathData,
|
|
4908
|
+
fill: outsideColor,
|
|
4909
|
+
stroke: null,
|
|
4910
|
+
selectable: false,
|
|
4911
|
+
evented: false,
|
|
4912
|
+
originX: "left",
|
|
4913
|
+
originY: "top",
|
|
4914
|
+
left: 0,
|
|
4915
|
+
top: 0
|
|
4916
|
+
}
|
|
4917
|
+
}
|
|
4918
|
+
];
|
|
4444
4919
|
if (insideColor && insideColor !== "transparent" && insideColor !== "rgba(0,0,0,0)") {
|
|
4445
4920
|
const productPathData = generateDielinePath({
|
|
4446
4921
|
shape,
|
|
@@ -4450,19 +4925,28 @@ var DielineTool = class {
|
|
|
4450
4925
|
x: cx,
|
|
4451
4926
|
y: cy,
|
|
4452
4927
|
features: cutFeatures,
|
|
4928
|
+
shapeStyle,
|
|
4453
4929
|
pathData: this.state.pathData,
|
|
4930
|
+
customSourceWidthPx: this.state.customSourceWidthPx,
|
|
4931
|
+
customSourceHeightPx: this.state.customSourceHeightPx,
|
|
4454
4932
|
canvasWidth: canvasW,
|
|
4455
4933
|
canvasHeight: canvasH
|
|
4456
4934
|
});
|
|
4457
|
-
|
|
4458
|
-
|
|
4459
|
-
|
|
4460
|
-
|
|
4461
|
-
|
|
4462
|
-
|
|
4463
|
-
|
|
4935
|
+
specs.push({
|
|
4936
|
+
id: "dieline.inside",
|
|
4937
|
+
type: "path",
|
|
4938
|
+
space: "screen",
|
|
4939
|
+
data: { id: "dieline.inside", type: "dieline" },
|
|
4940
|
+
props: {
|
|
4941
|
+
pathData: productPathData,
|
|
4942
|
+
fill: insideColor,
|
|
4943
|
+
stroke: null,
|
|
4944
|
+
selectable: false,
|
|
4945
|
+
evented: false,
|
|
4946
|
+
originX: "left",
|
|
4947
|
+
originY: "top"
|
|
4948
|
+
}
|
|
4464
4949
|
});
|
|
4465
|
-
layer.add(insideObj);
|
|
4466
4950
|
}
|
|
4467
4951
|
if (Math.abs(visualOffset) > 1e-4) {
|
|
4468
4952
|
const bleedPathData = generateBleedZonePath(
|
|
@@ -4474,7 +4958,10 @@ var DielineTool = class {
|
|
|
4474
4958
|
x: cx,
|
|
4475
4959
|
y: cy,
|
|
4476
4960
|
features: cutFeatures,
|
|
4961
|
+
shapeStyle,
|
|
4477
4962
|
pathData: this.state.pathData,
|
|
4963
|
+
customSourceWidthPx: this.state.customSourceWidthPx,
|
|
4964
|
+
customSourceHeightPx: this.state.customSourceHeightPx,
|
|
4478
4965
|
canvasWidth: canvasW,
|
|
4479
4966
|
canvasHeight: canvasH
|
|
4480
4967
|
},
|
|
@@ -4486,7 +4973,10 @@ var DielineTool = class {
|
|
|
4486
4973
|
x: cx,
|
|
4487
4974
|
y: cy,
|
|
4488
4975
|
features: cutFeatures,
|
|
4976
|
+
shapeStyle,
|
|
4489
4977
|
pathData: this.state.pathData,
|
|
4978
|
+
customSourceWidthPx: this.state.customSourceWidthPx,
|
|
4979
|
+
customSourceHeightPx: this.state.customSourceHeightPx,
|
|
4490
4980
|
canvasWidth: canvasW,
|
|
4491
4981
|
canvasHeight: canvasH
|
|
4492
4982
|
},
|
|
@@ -4495,16 +4985,22 @@ var DielineTool = class {
|
|
|
4495
4985
|
if (showBleedLines !== false) {
|
|
4496
4986
|
const pattern = this.createHatchPattern(mainLine.color);
|
|
4497
4987
|
if (pattern) {
|
|
4498
|
-
|
|
4499
|
-
|
|
4500
|
-
|
|
4501
|
-
|
|
4502
|
-
|
|
4503
|
-
|
|
4504
|
-
|
|
4505
|
-
|
|
4988
|
+
specs.push({
|
|
4989
|
+
id: "dieline.bleed-zone",
|
|
4990
|
+
type: "path",
|
|
4991
|
+
space: "screen",
|
|
4992
|
+
data: { id: "dieline.bleed-zone", type: "dieline" },
|
|
4993
|
+
props: {
|
|
4994
|
+
pathData: bleedPathData,
|
|
4995
|
+
fill: pattern,
|
|
4996
|
+
stroke: null,
|
|
4997
|
+
selectable: false,
|
|
4998
|
+
evented: false,
|
|
4999
|
+
objectCaching: false,
|
|
5000
|
+
originX: "left",
|
|
5001
|
+
originY: "top"
|
|
5002
|
+
}
|
|
4506
5003
|
});
|
|
4507
|
-
layer.add(bleedObj);
|
|
4508
5004
|
}
|
|
4509
5005
|
}
|
|
4510
5006
|
const offsetPathData = generateDielinePath({
|
|
@@ -4515,21 +5011,30 @@ var DielineTool = class {
|
|
|
4515
5011
|
x: cx,
|
|
4516
5012
|
y: cy,
|
|
4517
5013
|
features: cutFeatures,
|
|
5014
|
+
shapeStyle,
|
|
4518
5015
|
pathData: this.state.pathData,
|
|
5016
|
+
customSourceWidthPx: this.state.customSourceWidthPx,
|
|
5017
|
+
customSourceHeightPx: this.state.customSourceHeightPx,
|
|
4519
5018
|
canvasWidth: canvasW,
|
|
4520
5019
|
canvasHeight: canvasH
|
|
4521
5020
|
});
|
|
4522
|
-
|
|
4523
|
-
|
|
4524
|
-
|
|
4525
|
-
|
|
4526
|
-
|
|
4527
|
-
|
|
4528
|
-
|
|
4529
|
-
|
|
4530
|
-
|
|
5021
|
+
specs.push({
|
|
5022
|
+
id: "dieline.offset-border",
|
|
5023
|
+
type: "path",
|
|
5024
|
+
space: "screen",
|
|
5025
|
+
data: { id: "dieline.offset-border", type: "dieline" },
|
|
5026
|
+
props: {
|
|
5027
|
+
pathData: offsetPathData,
|
|
5028
|
+
fill: null,
|
|
5029
|
+
stroke: offsetLine.style === "hidden" ? null : offsetLine.color,
|
|
5030
|
+
strokeWidth: offsetLine.width,
|
|
5031
|
+
strokeDashArray: offsetLine.style === "dashed" ? [offsetLine.dashLength, offsetLine.dashLength] : void 0,
|
|
5032
|
+
selectable: false,
|
|
5033
|
+
evented: false,
|
|
5034
|
+
originX: "left",
|
|
5035
|
+
originY: "top"
|
|
5036
|
+
}
|
|
4531
5037
|
});
|
|
4532
|
-
layer.add(offsetBorderObj);
|
|
4533
5038
|
}
|
|
4534
5039
|
const borderPathData = generateDielinePath({
|
|
4535
5040
|
shape,
|
|
@@ -4539,37 +5044,59 @@ var DielineTool = class {
|
|
|
4539
5044
|
x: cx,
|
|
4540
5045
|
y: cy,
|
|
4541
5046
|
features: absoluteFeatures,
|
|
5047
|
+
shapeStyle,
|
|
4542
5048
|
pathData: this.state.pathData,
|
|
5049
|
+
customSourceWidthPx: this.state.customSourceWidthPx,
|
|
5050
|
+
customSourceHeightPx: this.state.customSourceHeightPx,
|
|
4543
5051
|
canvasWidth: canvasW,
|
|
4544
5052
|
canvasHeight: canvasH
|
|
4545
5053
|
});
|
|
4546
|
-
|
|
4547
|
-
|
|
4548
|
-
|
|
4549
|
-
|
|
4550
|
-
|
|
4551
|
-
|
|
4552
|
-
|
|
4553
|
-
|
|
4554
|
-
|
|
4555
|
-
|
|
4556
|
-
|
|
4557
|
-
|
|
4558
|
-
|
|
4559
|
-
|
|
4560
|
-
|
|
4561
|
-
if (layerIndex < userIndex) {
|
|
4562
|
-
this.canvasService.canvas.moveObjectTo(layer, userIndex + 1);
|
|
5054
|
+
specs.push({
|
|
5055
|
+
id: "dieline.border",
|
|
5056
|
+
type: "path",
|
|
5057
|
+
space: "screen",
|
|
5058
|
+
data: { id: "dieline.border", type: "dieline" },
|
|
5059
|
+
props: {
|
|
5060
|
+
pathData: borderPathData,
|
|
5061
|
+
fill: "transparent",
|
|
5062
|
+
stroke: mainLine.style === "hidden" ? null : mainLine.color,
|
|
5063
|
+
strokeWidth: mainLine.width,
|
|
5064
|
+
strokeDashArray: mainLine.style === "dashed" ? [mainLine.dashLength, mainLine.dashLength] : void 0,
|
|
5065
|
+
selectable: false,
|
|
5066
|
+
evented: false,
|
|
5067
|
+
originX: "left",
|
|
5068
|
+
originY: "top"
|
|
4563
5069
|
}
|
|
4564
|
-
}
|
|
4565
|
-
|
|
5070
|
+
});
|
|
5071
|
+
return specs;
|
|
5072
|
+
}
|
|
5073
|
+
updateDieline(_emitEvent = true) {
|
|
5074
|
+
void this.updateDielineAsync();
|
|
5075
|
+
}
|
|
5076
|
+
async updateDielineAsync() {
|
|
5077
|
+
if (!this.canvasService) return;
|
|
5078
|
+
const configService = this.getConfigService();
|
|
5079
|
+
if (!configService) return;
|
|
5080
|
+
const seq = ++this.renderSeq;
|
|
5081
|
+
this.syncSizeState(configService);
|
|
5082
|
+
const sceneLayout = computeSceneLayout(
|
|
5083
|
+
this.canvasService,
|
|
5084
|
+
readSizeState(configService)
|
|
5085
|
+
);
|
|
5086
|
+
if (!sceneLayout) {
|
|
5087
|
+
if (seq !== this.renderSeq) return;
|
|
5088
|
+
this.specs = [];
|
|
5089
|
+
await this.canvasService.flushRenderFromProducers();
|
|
5090
|
+
return;
|
|
4566
5091
|
}
|
|
5092
|
+
const nextSpecs = this.buildDielineSpecs(sceneLayout);
|
|
5093
|
+
if (seq !== this.renderSeq) return;
|
|
5094
|
+
this.specs = nextSpecs;
|
|
5095
|
+
await this.canvasService.flushRenderFromProducers();
|
|
5096
|
+
if (seq !== this.renderSeq) return;
|
|
5097
|
+
this.ensureLayerStacking();
|
|
4567
5098
|
this.bringFeatureMarkersToFront();
|
|
4568
|
-
|
|
4569
|
-
if (rulerLayer) {
|
|
4570
|
-
this.canvasService.canvas.bringObjectToFront(rulerLayer);
|
|
4571
|
-
}
|
|
4572
|
-
layer.dirty = true;
|
|
5099
|
+
this.canvasService.bringLayerToFront("ruler-overlay");
|
|
4573
5100
|
this.canvasService.requestRenderAll();
|
|
4574
5101
|
}
|
|
4575
5102
|
getGeometry() {
|
|
@@ -4585,7 +5112,9 @@ var DielineTool = class {
|
|
|
4585
5112
|
return {
|
|
4586
5113
|
...sceneGeometry,
|
|
4587
5114
|
strokeWidth: this.state.mainLine.width,
|
|
4588
|
-
pathData: this.state.pathData
|
|
5115
|
+
pathData: this.state.pathData,
|
|
5116
|
+
customSourceWidthPx: this.state.customSourceWidthPx,
|
|
5117
|
+
customSourceHeightPx: this.state.customSourceHeightPx
|
|
4589
5118
|
};
|
|
4590
5119
|
}
|
|
4591
5120
|
async exportCutImage(options) {
|
|
@@ -4615,7 +5144,7 @@ var DielineTool = class {
|
|
|
4615
5144
|
);
|
|
4616
5145
|
return null;
|
|
4617
5146
|
}
|
|
4618
|
-
const { shape, radius, features, pathData } = this.state;
|
|
5147
|
+
const { shape, shapeStyle, radius, features, pathData } = this.state;
|
|
4619
5148
|
const canvasW = sceneLayout.canvasWidth || this.canvasService.canvas.width || 800;
|
|
4620
5149
|
const canvasH = sceneLayout.canvasHeight || this.canvasService.canvas.height || 600;
|
|
4621
5150
|
const scale = sceneLayout.scale;
|
|
@@ -4643,7 +5172,10 @@ var DielineTool = class {
|
|
|
4643
5172
|
x: cx,
|
|
4644
5173
|
y: cy,
|
|
4645
5174
|
features: cutFeatures,
|
|
5175
|
+
shapeStyle,
|
|
4646
5176
|
pathData,
|
|
5177
|
+
customSourceWidthPx: this.state.customSourceWidthPx,
|
|
5178
|
+
customSourceHeightPx: this.state.customSourceHeightPx,
|
|
4647
5179
|
canvasWidth: canvasW,
|
|
4648
5180
|
canvasHeight: canvasH
|
|
4649
5181
|
});
|
|
@@ -4753,7 +5285,6 @@ var DielineTool = class {
|
|
|
4753
5285
|
|
|
4754
5286
|
// src/extensions/feature.ts
|
|
4755
5287
|
var import_core5 = require("@pooder/core");
|
|
4756
|
-
var import_fabric4 = require("fabric");
|
|
4757
5288
|
|
|
4758
5289
|
// src/extensions/constraints.ts
|
|
4759
5290
|
var ConstraintRegistry = class {
|
|
@@ -4953,6 +5484,10 @@ function completeFeaturesStrict(features, context, update) {
|
|
|
4953
5484
|
}
|
|
4954
5485
|
|
|
4955
5486
|
// src/extensions/feature.ts
|
|
5487
|
+
var FEATURE_OVERLAY_LAYER_ID = "feature-overlay";
|
|
5488
|
+
var FEATURE_STROKE_WIDTH = 2;
|
|
5489
|
+
var DEFAULT_RECT_SIZE = 10;
|
|
5490
|
+
var DEFAULT_CIRCLE_RADIUS = 5;
|
|
4956
5491
|
var FeatureTool = class {
|
|
4957
5492
|
constructor(options) {
|
|
4958
5493
|
this.id = "pooder.kit.feature";
|
|
@@ -4965,6 +5500,8 @@ var FeatureTool = class {
|
|
|
4965
5500
|
this.isFeatureSessionActive = false;
|
|
4966
5501
|
this.sessionOriginalFeatures = null;
|
|
4967
5502
|
this.hasWorkingChanges = false;
|
|
5503
|
+
this.specs = [];
|
|
5504
|
+
this.renderSeq = 0;
|
|
4968
5505
|
this.handleMoving = null;
|
|
4969
5506
|
this.handleModified = null;
|
|
4970
5507
|
this.handleSceneGeometryChange = null;
|
|
@@ -4981,12 +5518,23 @@ var FeatureTool = class {
|
|
|
4981
5518
|
}
|
|
4982
5519
|
}
|
|
4983
5520
|
activate(context) {
|
|
5521
|
+
var _a;
|
|
4984
5522
|
this.context = context;
|
|
4985
5523
|
this.canvasService = context.services.get("CanvasService");
|
|
4986
5524
|
if (!this.canvasService) {
|
|
4987
5525
|
console.warn("CanvasService not found for FeatureTool");
|
|
4988
5526
|
return;
|
|
4989
5527
|
}
|
|
5528
|
+
(_a = this.renderProducerDisposable) == null ? void 0 : _a.dispose();
|
|
5529
|
+
this.renderProducerDisposable = this.canvasService.registerRenderProducer(
|
|
5530
|
+
this.id,
|
|
5531
|
+
() => ({
|
|
5532
|
+
rootLayerSpecs: {
|
|
5533
|
+
[FEATURE_OVERLAY_LAYER_ID]: this.specs
|
|
5534
|
+
}
|
|
5535
|
+
}),
|
|
5536
|
+
{ priority: 350 }
|
|
5537
|
+
);
|
|
4990
5538
|
const configService = context.services.get(
|
|
4991
5539
|
"ConfigurationService"
|
|
4992
5540
|
);
|
|
@@ -5025,21 +5573,7 @@ var FeatureTool = class {
|
|
|
5025
5573
|
this.context = void 0;
|
|
5026
5574
|
}
|
|
5027
5575
|
updateVisibility() {
|
|
5028
|
-
|
|
5029
|
-
const canvas = this.canvasService.canvas;
|
|
5030
|
-
const markers = canvas.getObjects().filter((obj) => {
|
|
5031
|
-
var _a;
|
|
5032
|
-
return ((_a = obj.data) == null ? void 0 : _a.type) === "feature-marker";
|
|
5033
|
-
});
|
|
5034
|
-
markers.forEach((marker) => {
|
|
5035
|
-
marker.set({
|
|
5036
|
-
visible: this.isToolActive,
|
|
5037
|
-
// Or just selectable: false if we want them visible but locked
|
|
5038
|
-
selectable: this.isToolActive,
|
|
5039
|
-
evented: this.isToolActive
|
|
5040
|
-
});
|
|
5041
|
-
});
|
|
5042
|
-
canvas.requestRenderAll();
|
|
5576
|
+
this.redraw();
|
|
5043
5577
|
}
|
|
5044
5578
|
contribute() {
|
|
5045
5579
|
return {
|
|
@@ -5271,8 +5805,7 @@ var FeatureTool = class {
|
|
|
5271
5805
|
if (!changed) return { ok: true };
|
|
5272
5806
|
this.setWorkingFeatures(next);
|
|
5273
5807
|
this.hasWorkingChanges = true;
|
|
5274
|
-
this.redraw();
|
|
5275
|
-
this.enforceConstraints();
|
|
5808
|
+
this.redraw({ enforceConstraints: true });
|
|
5276
5809
|
this.emitWorkingChange();
|
|
5277
5810
|
return { ok: true };
|
|
5278
5811
|
}
|
|
@@ -5320,12 +5853,10 @@ var FeatureTool = class {
|
|
|
5320
5853
|
shape: "rect",
|
|
5321
5854
|
x: 0.5,
|
|
5322
5855
|
y: 0,
|
|
5323
|
-
// Top edge
|
|
5324
5856
|
width: 10,
|
|
5325
5857
|
height: 10,
|
|
5326
5858
|
rotation: 0,
|
|
5327
5859
|
renderBehavior: "edge",
|
|
5328
|
-
// Default constraint: path (snap to edge)
|
|
5329
5860
|
constraints: [{ type: "path" }]
|
|
5330
5861
|
};
|
|
5331
5862
|
this.setWorkingFeatures([...this.workingFeatures || [], newFeature]);
|
|
@@ -5368,7 +5899,7 @@ var FeatureTool = class {
|
|
|
5368
5899
|
this.emitWorkingChange();
|
|
5369
5900
|
return true;
|
|
5370
5901
|
}
|
|
5371
|
-
getGeometryForFeature(geometry,
|
|
5902
|
+
getGeometryForFeature(geometry, _feature) {
|
|
5372
5903
|
return geometry;
|
|
5373
5904
|
}
|
|
5374
5905
|
setup() {
|
|
@@ -5377,8 +5908,7 @@ var FeatureTool = class {
|
|
|
5377
5908
|
if (!this.handleSceneGeometryChange) {
|
|
5378
5909
|
this.handleSceneGeometryChange = (geometry) => {
|
|
5379
5910
|
this.currentGeometry = geometry;
|
|
5380
|
-
this.redraw();
|
|
5381
|
-
this.enforceConstraints();
|
|
5911
|
+
this.redraw({ enforceConstraints: true });
|
|
5382
5912
|
};
|
|
5383
5913
|
this.context.eventBus.on(
|
|
5384
5914
|
"scene:geometry:change",
|
|
@@ -5401,76 +5931,34 @@ var FeatureTool = class {
|
|
|
5401
5931
|
}
|
|
5402
5932
|
if (!this.handleMoving) {
|
|
5403
5933
|
this.handleMoving = (e) => {
|
|
5404
|
-
|
|
5405
|
-
|
|
5406
|
-
|
|
5407
|
-
|
|
5408
|
-
|
|
5409
|
-
|
|
5410
|
-
|
|
5411
|
-
|
|
5412
|
-
|
|
5413
|
-
|
|
5414
|
-
} else {
|
|
5415
|
-
const index = (_d = target.data) == null ? void 0 : _d.index;
|
|
5416
|
-
if (index !== void 0) {
|
|
5417
|
-
feature = this.workingFeatures[index];
|
|
5418
|
-
}
|
|
5419
|
-
}
|
|
5420
|
-
const geometry = this.getGeometryForFeature(
|
|
5421
|
-
this.currentGeometry,
|
|
5934
|
+
const target = this.getDraggableMarkerTarget(e == null ? void 0 : e.target);
|
|
5935
|
+
if (!target || !this.currentGeometry) return;
|
|
5936
|
+
const feature = this.getFeatureForMarker(target);
|
|
5937
|
+
const geometry = this.getGeometryForFeature(this.currentGeometry, feature);
|
|
5938
|
+
const snapped = this.constrainPosition(
|
|
5939
|
+
{
|
|
5940
|
+
x: Number(target.left || 0),
|
|
5941
|
+
y: Number(target.top || 0)
|
|
5942
|
+
},
|
|
5943
|
+
geometry,
|
|
5422
5944
|
feature
|
|
5423
5945
|
);
|
|
5424
|
-
const p = new import_fabric4.Point(target.left, target.top);
|
|
5425
|
-
const markerStrokeWidth = (target.strokeWidth || 2) * (target.scaleX || 1);
|
|
5426
|
-
const minDim = Math.min(
|
|
5427
|
-
target.getScaledWidth(),
|
|
5428
|
-
target.getScaledHeight()
|
|
5429
|
-
);
|
|
5430
|
-
const limit = Math.max(0, minDim / 2 - markerStrokeWidth);
|
|
5431
|
-
const snapped = this.constrainPosition(p, geometry, limit, feature);
|
|
5432
5946
|
target.set({
|
|
5433
5947
|
left: snapped.x,
|
|
5434
5948
|
top: snapped.y
|
|
5435
5949
|
});
|
|
5950
|
+
target.setCoords();
|
|
5951
|
+
this.syncMarkerVisualsByTarget(target, snapped);
|
|
5436
5952
|
};
|
|
5437
5953
|
canvas.on("object:moving", this.handleMoving);
|
|
5438
5954
|
}
|
|
5439
5955
|
if (!this.handleModified) {
|
|
5440
5956
|
this.handleModified = (e) => {
|
|
5441
|
-
var _a
|
|
5442
|
-
const target = e.target;
|
|
5443
|
-
if (!target
|
|
5444
|
-
if ((
|
|
5445
|
-
|
|
5446
|
-
const indices = (_c = groupObj.data) == null ? void 0 : _c.indices;
|
|
5447
|
-
if (!indices) return;
|
|
5448
|
-
const groupCenter = new import_fabric4.Point(groupObj.left, groupObj.top);
|
|
5449
|
-
const newFeatures = [...this.workingFeatures];
|
|
5450
|
-
const { x, y } = this.currentGeometry;
|
|
5451
|
-
groupObj.getObjects().forEach((child, i) => {
|
|
5452
|
-
const originalIndex = indices[i];
|
|
5453
|
-
const feature = this.workingFeatures[originalIndex];
|
|
5454
|
-
const geometry = this.getGeometryForFeature(
|
|
5455
|
-
this.currentGeometry,
|
|
5456
|
-
feature
|
|
5457
|
-
);
|
|
5458
|
-
const { width, height } = geometry;
|
|
5459
|
-
const layoutLeft = x - width / 2;
|
|
5460
|
-
const layoutTop = y - height / 2;
|
|
5461
|
-
const absX = groupCenter.x + (child.left || 0);
|
|
5462
|
-
const absY = groupCenter.y + (child.top || 0);
|
|
5463
|
-
const normalizedX = width > 0 ? (absX - layoutLeft) / width : 0.5;
|
|
5464
|
-
const normalizedY = height > 0 ? (absY - layoutTop) / height : 0.5;
|
|
5465
|
-
newFeatures[originalIndex] = {
|
|
5466
|
-
...newFeatures[originalIndex],
|
|
5467
|
-
x: normalizedX,
|
|
5468
|
-
y: normalizedY
|
|
5469
|
-
};
|
|
5470
|
-
});
|
|
5471
|
-
this.setWorkingFeatures(newFeatures);
|
|
5472
|
-
this.hasWorkingChanges = true;
|
|
5473
|
-
this.emitWorkingChange();
|
|
5957
|
+
var _a;
|
|
5958
|
+
const target = this.getDraggableMarkerTarget(e == null ? void 0 : e.target);
|
|
5959
|
+
if (!target) return;
|
|
5960
|
+
if ((_a = target.data) == null ? void 0 : _a.isGroup) {
|
|
5961
|
+
this.syncGroupFromCanvas(target);
|
|
5474
5962
|
} else {
|
|
5475
5963
|
this.syncFeatureFromCanvas(target);
|
|
5476
5964
|
}
|
|
@@ -5479,6 +5967,7 @@ var FeatureTool = class {
|
|
|
5479
5967
|
}
|
|
5480
5968
|
}
|
|
5481
5969
|
teardown() {
|
|
5970
|
+
var _a;
|
|
5482
5971
|
if (!this.canvasService) return;
|
|
5483
5972
|
const canvas = this.canvasService.canvas;
|
|
5484
5973
|
if (this.handleMoving) {
|
|
@@ -5496,14 +5985,25 @@ var FeatureTool = class {
|
|
|
5496
5985
|
);
|
|
5497
5986
|
this.handleSceneGeometryChange = null;
|
|
5498
5987
|
}
|
|
5499
|
-
|
|
5500
|
-
|
|
5501
|
-
|
|
5502
|
-
|
|
5503
|
-
|
|
5504
|
-
|
|
5988
|
+
this.renderSeq += 1;
|
|
5989
|
+
this.specs = [];
|
|
5990
|
+
(_a = this.renderProducerDisposable) == null ? void 0 : _a.dispose();
|
|
5991
|
+
this.renderProducerDisposable = void 0;
|
|
5992
|
+
void this.canvasService.flushRenderFromProducers();
|
|
5993
|
+
}
|
|
5994
|
+
getDraggableMarkerTarget(target) {
|
|
5995
|
+
var _a, _b;
|
|
5996
|
+
if (!target || ((_a = target.data) == null ? void 0 : _a.type) !== "feature-marker") return null;
|
|
5997
|
+
if (((_b = target.data) == null ? void 0 : _b.markerRole) !== "handle") return null;
|
|
5998
|
+
return target;
|
|
5505
5999
|
}
|
|
5506
|
-
|
|
6000
|
+
getFeatureForMarker(target) {
|
|
6001
|
+
const data = (target == null ? void 0 : target.data) || {};
|
|
6002
|
+
const index = data.isGroup ? this.toFeatureIndex(data.anchorIndex) : this.toFeatureIndex(data.index);
|
|
6003
|
+
if (index === null) return void 0;
|
|
6004
|
+
return this.workingFeatures[index];
|
|
6005
|
+
}
|
|
6006
|
+
constrainPosition(p, geometry, feature) {
|
|
5507
6007
|
var _a;
|
|
5508
6008
|
if (!feature) {
|
|
5509
6009
|
return { x: p.x, y: p.y };
|
|
@@ -5534,231 +6034,374 @@ var FeatureTool = class {
|
|
|
5534
6034
|
y: minY + constrained.y * geometry.height
|
|
5535
6035
|
};
|
|
5536
6036
|
}
|
|
6037
|
+
toNormalizedPoint(point, geometry) {
|
|
6038
|
+
const left = geometry.x - geometry.width / 2;
|
|
6039
|
+
const top = geometry.y - geometry.height / 2;
|
|
6040
|
+
return {
|
|
6041
|
+
x: geometry.width > 0 ? (point.x - left) / geometry.width : 0.5,
|
|
6042
|
+
y: geometry.height > 0 ? (point.y - top) / geometry.height : 0.5
|
|
6043
|
+
};
|
|
6044
|
+
}
|
|
5537
6045
|
syncFeatureFromCanvas(target) {
|
|
5538
6046
|
var _a;
|
|
5539
|
-
if (!this.currentGeometry
|
|
5540
|
-
const index = (_a = target.data) == null ? void 0 : _a.index;
|
|
5541
|
-
if (index ===
|
|
5542
|
-
return;
|
|
6047
|
+
if (!this.currentGeometry) return;
|
|
6048
|
+
const index = this.toFeatureIndex((_a = target.data) == null ? void 0 : _a.index);
|
|
6049
|
+
if (index === null || index >= this.workingFeatures.length) return;
|
|
5543
6050
|
const feature = this.workingFeatures[index];
|
|
5544
6051
|
const geometry = this.getGeometryForFeature(this.currentGeometry, feature);
|
|
5545
|
-
const
|
|
5546
|
-
|
|
5547
|
-
|
|
5548
|
-
|
|
5549
|
-
|
|
6052
|
+
const normalized = this.toNormalizedPoint(
|
|
6053
|
+
{
|
|
6054
|
+
x: Number(target.left || 0),
|
|
6055
|
+
y: Number(target.top || 0)
|
|
6056
|
+
},
|
|
6057
|
+
geometry
|
|
6058
|
+
);
|
|
5550
6059
|
const updatedFeature = {
|
|
5551
6060
|
...feature,
|
|
5552
|
-
x:
|
|
5553
|
-
y:
|
|
5554
|
-
// Could also update rotation if we allowed rotating markers
|
|
6061
|
+
x: normalized.x,
|
|
6062
|
+
y: normalized.y
|
|
5555
6063
|
};
|
|
5556
|
-
const
|
|
5557
|
-
|
|
5558
|
-
this.setWorkingFeatures(
|
|
6064
|
+
const next = [...this.workingFeatures];
|
|
6065
|
+
next[index] = updatedFeature;
|
|
6066
|
+
this.setWorkingFeatures(next);
|
|
5559
6067
|
this.hasWorkingChanges = true;
|
|
5560
6068
|
this.emitWorkingChange();
|
|
5561
6069
|
}
|
|
5562
|
-
|
|
5563
|
-
|
|
5564
|
-
|
|
5565
|
-
const
|
|
5566
|
-
|
|
5567
|
-
|
|
5568
|
-
|
|
6070
|
+
syncGroupFromCanvas(target) {
|
|
6071
|
+
var _a, _b;
|
|
6072
|
+
if (!this.currentGeometry) return;
|
|
6073
|
+
const indices = this.readGroupIndices((_a = target.data) == null ? void 0 : _a.indices);
|
|
6074
|
+
if (indices.length === 0) return;
|
|
6075
|
+
const offsets = this.readGroupMemberOffsets((_b = target.data) == null ? void 0 : _b.memberOffsets, indices);
|
|
6076
|
+
const anchorCenter = {
|
|
6077
|
+
x: Number(target.left || 0),
|
|
6078
|
+
y: Number(target.top || 0)
|
|
6079
|
+
};
|
|
6080
|
+
const next = [...this.workingFeatures];
|
|
6081
|
+
let changed = false;
|
|
6082
|
+
offsets.forEach((entry) => {
|
|
6083
|
+
const index = entry.index;
|
|
6084
|
+
if (index < 0 || index >= next.length) return;
|
|
6085
|
+
const feature = next[index];
|
|
6086
|
+
const geometry = this.getGeometryForFeature(this.currentGeometry, feature);
|
|
6087
|
+
const normalized = this.toNormalizedPoint(
|
|
6088
|
+
{
|
|
6089
|
+
x: anchorCenter.x + entry.dx,
|
|
6090
|
+
y: anchorCenter.y + entry.dy
|
|
6091
|
+
},
|
|
6092
|
+
geometry
|
|
6093
|
+
);
|
|
6094
|
+
if (feature.x !== normalized.x || feature.y !== normalized.y) {
|
|
6095
|
+
next[index] = {
|
|
6096
|
+
...feature,
|
|
6097
|
+
x: normalized.x,
|
|
6098
|
+
y: normalized.y
|
|
6099
|
+
};
|
|
6100
|
+
changed = true;
|
|
6101
|
+
}
|
|
5569
6102
|
});
|
|
5570
|
-
|
|
5571
|
-
|
|
5572
|
-
|
|
5573
|
-
|
|
6103
|
+
if (!changed) return;
|
|
6104
|
+
this.setWorkingFeatures(next);
|
|
6105
|
+
this.hasWorkingChanges = true;
|
|
6106
|
+
this.emitWorkingChange();
|
|
6107
|
+
}
|
|
6108
|
+
redraw(options = {}) {
|
|
6109
|
+
void this.redrawAsync(options);
|
|
6110
|
+
}
|
|
6111
|
+
async redrawAsync(options = {}) {
|
|
6112
|
+
if (!this.canvasService) return;
|
|
6113
|
+
const seq = ++this.renderSeq;
|
|
6114
|
+
this.specs = this.buildFeatureSpecs();
|
|
6115
|
+
if (seq !== this.renderSeq) return;
|
|
6116
|
+
await this.canvasService.flushRenderFromProducers();
|
|
6117
|
+
if (seq !== this.renderSeq) return;
|
|
6118
|
+
this.syncOverlayOrder();
|
|
6119
|
+
if (options.enforceConstraints) {
|
|
6120
|
+
this.enforceConstraints();
|
|
5574
6121
|
}
|
|
5575
|
-
|
|
5576
|
-
|
|
5577
|
-
|
|
6122
|
+
}
|
|
6123
|
+
syncOverlayOrder() {
|
|
6124
|
+
if (!this.canvasService) return;
|
|
6125
|
+
this.canvasService.bringLayerToFront(FEATURE_OVERLAY_LAYER_ID);
|
|
6126
|
+
this.canvasService.bringLayerToFront("ruler-overlay");
|
|
6127
|
+
}
|
|
6128
|
+
buildFeatureSpecs() {
|
|
6129
|
+
if (!this.currentGeometry || this.workingFeatures.length === 0) {
|
|
6130
|
+
return [];
|
|
6131
|
+
}
|
|
6132
|
+
const groups = /* @__PURE__ */ new Map();
|
|
5578
6133
|
const singles = [];
|
|
5579
|
-
this.workingFeatures.forEach((
|
|
5580
|
-
|
|
5581
|
-
|
|
5582
|
-
|
|
5583
|
-
|
|
5584
|
-
|
|
6134
|
+
this.workingFeatures.forEach((feature, index) => {
|
|
6135
|
+
const geometry = this.getGeometryForFeature(this.currentGeometry, feature);
|
|
6136
|
+
const position = resolveFeaturePosition(feature, geometry);
|
|
6137
|
+
const scale = geometry.scale || 1;
|
|
6138
|
+
const marker = {
|
|
6139
|
+
feature,
|
|
6140
|
+
index,
|
|
6141
|
+
position,
|
|
6142
|
+
geometry,
|
|
6143
|
+
scale
|
|
6144
|
+
};
|
|
6145
|
+
if (feature.groupId) {
|
|
6146
|
+
const list = groups.get(feature.groupId) || [];
|
|
6147
|
+
list.push(marker);
|
|
6148
|
+
groups.set(feature.groupId, list);
|
|
6149
|
+
return;
|
|
5585
6150
|
}
|
|
6151
|
+
singles.push(marker);
|
|
6152
|
+
});
|
|
6153
|
+
const specs = [];
|
|
6154
|
+
singles.forEach((marker) => {
|
|
6155
|
+
this.appendMarkerSpecs(specs, marker, {
|
|
6156
|
+
markerRole: "handle",
|
|
6157
|
+
isGroup: false
|
|
6158
|
+
});
|
|
6159
|
+
});
|
|
6160
|
+
groups.forEach((members, groupId) => {
|
|
6161
|
+
if (!members.length) return;
|
|
6162
|
+
const anchor = members[0];
|
|
6163
|
+
const memberOffsets = members.map((member) => ({
|
|
6164
|
+
index: member.index,
|
|
6165
|
+
dx: member.position.x - anchor.position.x,
|
|
6166
|
+
dy: member.position.y - anchor.position.y
|
|
6167
|
+
}));
|
|
6168
|
+
const indices = members.map((member) => member.index);
|
|
6169
|
+
members.filter((member) => member.index !== anchor.index).forEach((member) => {
|
|
6170
|
+
this.appendMarkerSpecs(specs, member, {
|
|
6171
|
+
markerRole: "member",
|
|
6172
|
+
isGroup: false,
|
|
6173
|
+
groupId
|
|
6174
|
+
});
|
|
6175
|
+
});
|
|
6176
|
+
this.appendMarkerSpecs(specs, anchor, {
|
|
6177
|
+
markerRole: "handle",
|
|
6178
|
+
isGroup: true,
|
|
6179
|
+
groupId,
|
|
6180
|
+
indices,
|
|
6181
|
+
anchorIndex: anchor.index,
|
|
6182
|
+
memberOffsets
|
|
6183
|
+
});
|
|
5586
6184
|
});
|
|
5587
|
-
|
|
5588
|
-
|
|
5589
|
-
|
|
5590
|
-
|
|
5591
|
-
|
|
5592
|
-
|
|
5593
|
-
|
|
5594
|
-
|
|
5595
|
-
|
|
5596
|
-
|
|
6185
|
+
return specs;
|
|
6186
|
+
}
|
|
6187
|
+
appendMarkerSpecs(specs, marker, options) {
|
|
6188
|
+
var _a, _b, _c, _d, _e;
|
|
6189
|
+
const { feature, index, position, scale, geometry } = marker;
|
|
6190
|
+
const baseRadius = feature.shape === "circle" ? (_a = feature.radius) != null ? _a : DEFAULT_CIRCLE_RADIUS : (_b = feature.radius) != null ? _b : 0;
|
|
6191
|
+
const baseWidth = feature.shape === "circle" ? baseRadius * 2 : (_c = feature.width) != null ? _c : DEFAULT_RECT_SIZE;
|
|
6192
|
+
const baseHeight = feature.shape === "circle" ? baseRadius * 2 : (_d = feature.height) != null ? _d : DEFAULT_RECT_SIZE;
|
|
6193
|
+
const visualWidth = baseWidth * scale;
|
|
6194
|
+
const visualHeight = baseHeight * scale;
|
|
6195
|
+
const visualRadius = baseRadius * scale;
|
|
6196
|
+
const color = feature.color || (feature.operation === "add" ? "#00FF00" : "#FF0000");
|
|
6197
|
+
const strokeDash = feature.strokeDash || (feature.operation === "subtract" ? [4, 4] : void 0);
|
|
6198
|
+
const interactive = options.markerRole === "handle";
|
|
6199
|
+
const baseData = this.buildMarkerData(marker, options);
|
|
6200
|
+
const commonProps = {
|
|
6201
|
+
visible: this.isToolActive,
|
|
6202
|
+
selectable: interactive && this.isToolActive,
|
|
6203
|
+
evented: interactive && this.isToolActive,
|
|
6204
|
+
hasControls: false,
|
|
6205
|
+
hasBorders: false,
|
|
6206
|
+
hoverCursor: interactive ? "move" : "default",
|
|
6207
|
+
lockRotation: true,
|
|
6208
|
+
lockScalingX: true,
|
|
6209
|
+
lockScalingY: true,
|
|
6210
|
+
fill: "transparent",
|
|
6211
|
+
stroke: color,
|
|
6212
|
+
strokeWidth: FEATURE_STROKE_WIDTH,
|
|
6213
|
+
strokeDashArray: strokeDash,
|
|
6214
|
+
originX: "center",
|
|
6215
|
+
originY: "center",
|
|
6216
|
+
left: position.x,
|
|
6217
|
+
top: position.y,
|
|
6218
|
+
angle: feature.rotation || 0
|
|
6219
|
+
};
|
|
6220
|
+
const markerId = this.markerId(index);
|
|
6221
|
+
if (feature.shape === "rect") {
|
|
6222
|
+
specs.push({
|
|
6223
|
+
id: markerId,
|
|
6224
|
+
type: "rect",
|
|
6225
|
+
space: "screen",
|
|
6226
|
+
data: baseData,
|
|
6227
|
+
props: {
|
|
6228
|
+
...commonProps,
|
|
5597
6229
|
width: visualWidth,
|
|
5598
6230
|
height: visualHeight,
|
|
5599
6231
|
rx: visualRadius,
|
|
5600
|
-
ry: visualRadius
|
|
5601
|
-
|
|
5602
|
-
|
|
5603
|
-
|
|
5604
|
-
|
|
5605
|
-
|
|
5606
|
-
|
|
5607
|
-
|
|
5608
|
-
|
|
5609
|
-
|
|
5610
|
-
|
|
5611
|
-
|
|
5612
|
-
|
|
5613
|
-
|
|
5614
|
-
|
|
5615
|
-
|
|
5616
|
-
|
|
5617
|
-
|
|
5618
|
-
|
|
5619
|
-
|
|
5620
|
-
|
|
5621
|
-
|
|
5622
|
-
|
|
5623
|
-
|
|
5624
|
-
|
|
5625
|
-
|
|
5626
|
-
|
|
5627
|
-
|
|
5628
|
-
|
|
5629
|
-
|
|
5630
|
-
|
|
5631
|
-
|
|
6232
|
+
ry: visualRadius
|
|
6233
|
+
}
|
|
6234
|
+
});
|
|
6235
|
+
} else {
|
|
6236
|
+
specs.push({
|
|
6237
|
+
id: markerId,
|
|
6238
|
+
type: "rect",
|
|
6239
|
+
space: "screen",
|
|
6240
|
+
data: baseData,
|
|
6241
|
+
props: {
|
|
6242
|
+
...commonProps,
|
|
6243
|
+
width: visualWidth,
|
|
6244
|
+
height: visualHeight,
|
|
6245
|
+
rx: visualRadius,
|
|
6246
|
+
ry: visualRadius
|
|
6247
|
+
}
|
|
6248
|
+
});
|
|
6249
|
+
}
|
|
6250
|
+
if (((_e = feature.bridge) == null ? void 0 : _e.type) === "vertical") {
|
|
6251
|
+
const featureTopY = position.y - visualHeight / 2;
|
|
6252
|
+
const dielineTopY = geometry.y - geometry.height / 2;
|
|
6253
|
+
const bridgeHeight = Math.max(0, featureTopY - dielineTopY);
|
|
6254
|
+
if (bridgeHeight <= 1e-3) {
|
|
6255
|
+
return;
|
|
6256
|
+
}
|
|
6257
|
+
specs.push({
|
|
6258
|
+
id: this.bridgeIndicatorId(index),
|
|
6259
|
+
type: "rect",
|
|
6260
|
+
space: "screen",
|
|
6261
|
+
data: {
|
|
6262
|
+
...baseData,
|
|
6263
|
+
markerRole: "indicator",
|
|
6264
|
+
markerOffsetX: 0,
|
|
6265
|
+
markerOffsetY: -visualHeight / 2
|
|
6266
|
+
},
|
|
6267
|
+
props: {
|
|
6268
|
+
visible: this.isToolActive,
|
|
6269
|
+
selectable: false,
|
|
6270
|
+
evented: false,
|
|
6271
|
+
width: visualWidth,
|
|
6272
|
+
height: bridgeHeight,
|
|
6273
|
+
fill: "transparent",
|
|
5632
6274
|
stroke: "#888",
|
|
5633
6275
|
strokeWidth: 1,
|
|
5634
6276
|
strokeDashArray: [2, 2],
|
|
5635
|
-
originX: "center",
|
|
5636
|
-
originY: "bottom",
|
|
5637
|
-
// Anchor at bottom so it extends up
|
|
5638
|
-
left: pos.x,
|
|
5639
|
-
top: pos.y - visualHeight / 2,
|
|
5640
|
-
// Start from top of feature
|
|
5641
6277
|
opacity: 0.5,
|
|
5642
|
-
selectable: false,
|
|
5643
|
-
evented: false
|
|
5644
|
-
});
|
|
5645
|
-
const group = new import_fabric4.Group([bridgeIndicator, shape], {
|
|
5646
6278
|
originX: "center",
|
|
5647
|
-
originY: "
|
|
5648
|
-
left:
|
|
5649
|
-
top:
|
|
6279
|
+
originY: "bottom",
|
|
6280
|
+
left: position.x,
|
|
6281
|
+
top: position.y - visualHeight / 2
|
|
6282
|
+
}
|
|
6283
|
+
});
|
|
6284
|
+
}
|
|
6285
|
+
}
|
|
6286
|
+
buildMarkerData(marker, options) {
|
|
6287
|
+
const data = {
|
|
6288
|
+
type: "feature-marker",
|
|
6289
|
+
index: marker.index,
|
|
6290
|
+
featureId: marker.feature.id,
|
|
6291
|
+
markerRole: options.markerRole,
|
|
6292
|
+
markerOffsetX: 0,
|
|
6293
|
+
markerOffsetY: 0,
|
|
6294
|
+
isGroup: options.isGroup
|
|
6295
|
+
};
|
|
6296
|
+
if (options.groupId) data.groupId = options.groupId;
|
|
6297
|
+
if (options.indices) data.indices = options.indices;
|
|
6298
|
+
if (options.anchorIndex !== void 0) data.anchorIndex = options.anchorIndex;
|
|
6299
|
+
if (options.memberOffsets) data.memberOffsets = options.memberOffsets;
|
|
6300
|
+
return data;
|
|
6301
|
+
}
|
|
6302
|
+
markerId(index) {
|
|
6303
|
+
return `feature.marker.${index}`;
|
|
6304
|
+
}
|
|
6305
|
+
bridgeIndicatorId(index) {
|
|
6306
|
+
return `feature.marker.${index}.bridge`;
|
|
6307
|
+
}
|
|
6308
|
+
toFeatureIndex(value) {
|
|
6309
|
+
const numeric = Number(value);
|
|
6310
|
+
if (!Number.isInteger(numeric) || numeric < 0) return null;
|
|
6311
|
+
return numeric;
|
|
6312
|
+
}
|
|
6313
|
+
readGroupIndices(raw) {
|
|
6314
|
+
if (!Array.isArray(raw)) return [];
|
|
6315
|
+
return raw.map((value) => this.toFeatureIndex(value)).filter((value) => value !== null);
|
|
6316
|
+
}
|
|
6317
|
+
readGroupMemberOffsets(raw, fallbackIndices = []) {
|
|
6318
|
+
if (Array.isArray(raw)) {
|
|
6319
|
+
const parsed = raw.map((entry) => {
|
|
6320
|
+
const index = this.toFeatureIndex(entry == null ? void 0 : entry.index);
|
|
6321
|
+
const dx = Number(entry == null ? void 0 : entry.dx);
|
|
6322
|
+
const dy = Number(entry == null ? void 0 : entry.dy);
|
|
6323
|
+
if (index === null || !Number.isFinite(dx) || !Number.isFinite(dy)) {
|
|
6324
|
+
return null;
|
|
6325
|
+
}
|
|
6326
|
+
return { index, dx, dy };
|
|
6327
|
+
}).filter((value) => !!value);
|
|
6328
|
+
if (parsed.length > 0) return parsed;
|
|
6329
|
+
}
|
|
6330
|
+
return fallbackIndices.map((index) => ({ index, dx: 0, dy: 0 }));
|
|
6331
|
+
}
|
|
6332
|
+
syncMarkerVisualsByTarget(target, center) {
|
|
6333
|
+
var _a, _b, _c, _d, _e, _f;
|
|
6334
|
+
if ((_a = target.data) == null ? void 0 : _a.isGroup) {
|
|
6335
|
+
const indices = this.readGroupIndices((_b = target.data) == null ? void 0 : _b.indices);
|
|
6336
|
+
const offsets = this.readGroupMemberOffsets((_c = target.data) == null ? void 0 : _c.memberOffsets, indices);
|
|
6337
|
+
offsets.forEach((entry) => {
|
|
6338
|
+
this.syncMarkerVisualObjectsToCenter(entry.index, {
|
|
6339
|
+
x: center.x + entry.dx,
|
|
6340
|
+
y: center.y + entry.dy
|
|
5650
6341
|
});
|
|
5651
|
-
|
|
6342
|
+
});
|
|
6343
|
+
(_d = this.canvasService) == null ? void 0 : _d.requestRenderAll();
|
|
6344
|
+
return;
|
|
6345
|
+
}
|
|
6346
|
+
const index = this.toFeatureIndex((_e = target.data) == null ? void 0 : _e.index);
|
|
6347
|
+
if (index === null) return;
|
|
6348
|
+
this.syncMarkerVisualObjectsToCenter(index, center);
|
|
6349
|
+
(_f = this.canvasService) == null ? void 0 : _f.requestRenderAll();
|
|
6350
|
+
}
|
|
6351
|
+
syncMarkerVisualObjectsToCenter(index, center) {
|
|
6352
|
+
if (!this.canvasService) return;
|
|
6353
|
+
const markers = this.canvasService.canvas.getObjects().filter(
|
|
6354
|
+
(obj) => {
|
|
6355
|
+
var _a, _b;
|
|
6356
|
+
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;
|
|
5652
6357
|
}
|
|
5653
|
-
|
|
5654
|
-
|
|
5655
|
-
|
|
5656
|
-
const
|
|
5657
|
-
|
|
5658
|
-
feature
|
|
5659
|
-
);
|
|
5660
|
-
const pos = resolveFeaturePosition(feature, geometry2);
|
|
5661
|
-
const marker = createMarkerShape(feature, pos);
|
|
6358
|
+
);
|
|
6359
|
+
markers.forEach((marker) => {
|
|
6360
|
+
var _a, _b;
|
|
6361
|
+
const offsetX = Number(((_a = marker == null ? void 0 : marker.data) == null ? void 0 : _a.markerOffsetX) || 0);
|
|
6362
|
+
const offsetY = Number(((_b = marker == null ? void 0 : marker.data) == null ? void 0 : _b.markerOffsetY) || 0);
|
|
5662
6363
|
marker.set({
|
|
5663
|
-
|
|
5664
|
-
|
|
5665
|
-
evented: this.isToolActive,
|
|
5666
|
-
hasControls: false,
|
|
5667
|
-
hasBorders: false,
|
|
5668
|
-
hoverCursor: "move",
|
|
5669
|
-
lockRotation: true,
|
|
5670
|
-
lockScalingX: true,
|
|
5671
|
-
lockScalingY: true,
|
|
5672
|
-
data: { type: "feature-marker", index, isGroup: false }
|
|
6364
|
+
left: center.x + offsetX,
|
|
6365
|
+
top: center.y + offsetY
|
|
5673
6366
|
});
|
|
5674
|
-
|
|
5675
|
-
canvas.bringObjectToFront(marker);
|
|
5676
|
-
});
|
|
5677
|
-
Object.keys(groups).forEach((groupId) => {
|
|
5678
|
-
const members = groups[groupId];
|
|
5679
|
-
if (members.length === 0) return;
|
|
5680
|
-
const shapes = members.map(({ feature }) => {
|
|
5681
|
-
const geometry2 = this.getGeometryForFeature(
|
|
5682
|
-
this.currentGeometry,
|
|
5683
|
-
feature
|
|
5684
|
-
);
|
|
5685
|
-
const pos = resolveFeaturePosition(feature, geometry2);
|
|
5686
|
-
return createMarkerShape(feature, pos);
|
|
5687
|
-
});
|
|
5688
|
-
const groupObj = new import_fabric4.Group(shapes, {
|
|
5689
|
-
visible: this.isToolActive,
|
|
5690
|
-
selectable: this.isToolActive,
|
|
5691
|
-
evented: this.isToolActive,
|
|
5692
|
-
hasControls: false,
|
|
5693
|
-
hasBorders: false,
|
|
5694
|
-
hoverCursor: "move",
|
|
5695
|
-
lockRotation: true,
|
|
5696
|
-
lockScalingX: true,
|
|
5697
|
-
lockScalingY: true,
|
|
5698
|
-
subTargetCheck: true,
|
|
5699
|
-
// Allow events to pass through if needed, but we treat as one
|
|
5700
|
-
interactive: false,
|
|
5701
|
-
// Children not interactive
|
|
5702
|
-
// @ts-ignore
|
|
5703
|
-
data: {
|
|
5704
|
-
type: "feature-marker",
|
|
5705
|
-
isGroup: true,
|
|
5706
|
-
groupId,
|
|
5707
|
-
indices: members.map((m) => m.index)
|
|
5708
|
-
}
|
|
5709
|
-
});
|
|
5710
|
-
canvas.add(groupObj);
|
|
5711
|
-
canvas.bringObjectToFront(groupObj);
|
|
6367
|
+
marker.setCoords();
|
|
5712
6368
|
});
|
|
5713
|
-
this.canvasService.requestRenderAll();
|
|
5714
6369
|
}
|
|
5715
6370
|
enforceConstraints() {
|
|
5716
6371
|
if (!this.canvasService || !this.currentGeometry) return;
|
|
5717
|
-
const
|
|
5718
|
-
|
|
5719
|
-
|
|
5720
|
-
|
|
5721
|
-
});
|
|
5722
|
-
markers.forEach((marker) => {
|
|
5723
|
-
var _a, _b, _c;
|
|
5724
|
-
let feature;
|
|
5725
|
-
if ((_a = marker.data) == null ? void 0 : _a.isGroup) {
|
|
5726
|
-
const indices = (_b = marker.data) == null ? void 0 : _b.indices;
|
|
5727
|
-
if (indices && indices.length > 0) {
|
|
5728
|
-
feature = this.workingFeatures[indices[0]];
|
|
5729
|
-
}
|
|
5730
|
-
} else {
|
|
5731
|
-
const index = (_c = marker.data) == null ? void 0 : _c.index;
|
|
5732
|
-
if (index !== void 0) {
|
|
5733
|
-
feature = this.workingFeatures[index];
|
|
5734
|
-
}
|
|
6372
|
+
const handles = this.canvasService.canvas.getObjects().filter(
|
|
6373
|
+
(obj) => {
|
|
6374
|
+
var _a, _b;
|
|
6375
|
+
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";
|
|
5735
6376
|
}
|
|
5736
|
-
|
|
5737
|
-
|
|
5738
|
-
|
|
5739
|
-
);
|
|
5740
|
-
const
|
|
5741
|
-
const minDim = Math.min(
|
|
5742
|
-
marker.getScaledWidth(),
|
|
5743
|
-
marker.getScaledHeight()
|
|
5744
|
-
);
|
|
5745
|
-
const limit = Math.max(0, minDim / 2 - markerStrokeWidth);
|
|
6377
|
+
);
|
|
6378
|
+
handles.forEach((marker) => {
|
|
6379
|
+
const feature = this.getFeatureForMarker(marker);
|
|
6380
|
+
if (!feature) return;
|
|
6381
|
+
const geometry = this.getGeometryForFeature(this.currentGeometry, feature);
|
|
5746
6382
|
const snapped = this.constrainPosition(
|
|
5747
|
-
|
|
6383
|
+
{
|
|
6384
|
+
x: Number(marker.left || 0),
|
|
6385
|
+
y: Number(marker.top || 0)
|
|
6386
|
+
},
|
|
5748
6387
|
geometry,
|
|
5749
|
-
limit,
|
|
5750
6388
|
feature
|
|
5751
6389
|
);
|
|
5752
6390
|
marker.set({ left: snapped.x, top: snapped.y });
|
|
5753
6391
|
marker.setCoords();
|
|
6392
|
+
this.syncMarkerVisualsByTarget(marker, snapped);
|
|
5754
6393
|
});
|
|
5755
|
-
canvas.requestRenderAll();
|
|
6394
|
+
this.canvasService.canvas.requestRenderAll();
|
|
5756
6395
|
}
|
|
5757
6396
|
};
|
|
5758
6397
|
|
|
5759
6398
|
// src/extensions/film.ts
|
|
5760
6399
|
var import_core6 = require("@pooder/core");
|
|
5761
|
-
var
|
|
6400
|
+
var import_fabric4 = require("fabric");
|
|
6401
|
+
var FILM_LAYER_ID = "overlay";
|
|
6402
|
+
var FILM_IMAGE_ID = "film-image";
|
|
6403
|
+
var DEFAULT_WIDTH2 = 800;
|
|
6404
|
+
var DEFAULT_HEIGHT2 = 600;
|
|
5762
6405
|
var FilmTool = class {
|
|
5763
6406
|
constructor(options) {
|
|
5764
6407
|
this.id = "pooder.kit.film";
|
|
@@ -5767,17 +6410,38 @@ var FilmTool = class {
|
|
|
5767
6410
|
};
|
|
5768
6411
|
this.url = "";
|
|
5769
6412
|
this.opacity = 0.5;
|
|
6413
|
+
this.specs = [];
|
|
6414
|
+
this.renderSeq = 0;
|
|
6415
|
+
this.renderImageUrl = "";
|
|
6416
|
+
this.sourceSizeBySrc = /* @__PURE__ */ new Map();
|
|
6417
|
+
this.pendingSizeBySrc = /* @__PURE__ */ new Map();
|
|
6418
|
+
this.onCanvasResized = () => {
|
|
6419
|
+
this.updateFilm();
|
|
6420
|
+
};
|
|
5770
6421
|
if (options) {
|
|
5771
6422
|
Object.assign(this, options);
|
|
5772
6423
|
}
|
|
5773
6424
|
}
|
|
5774
6425
|
activate(context) {
|
|
6426
|
+
var _a;
|
|
5775
6427
|
this.canvasService = context.services.get("CanvasService");
|
|
5776
6428
|
if (!this.canvasService) {
|
|
5777
6429
|
console.warn("CanvasService not found for FilmTool");
|
|
5778
6430
|
return;
|
|
5779
6431
|
}
|
|
5780
|
-
|
|
6432
|
+
(_a = this.renderProducerDisposable) == null ? void 0 : _a.dispose();
|
|
6433
|
+
this.renderProducerDisposable = this.canvasService.registerRenderProducer(
|
|
6434
|
+
this.id,
|
|
6435
|
+
() => ({
|
|
6436
|
+
layerSpecs: {
|
|
6437
|
+
[FILM_LAYER_ID]: this.specs
|
|
6438
|
+
}
|
|
6439
|
+
}),
|
|
6440
|
+
{ priority: 500 }
|
|
6441
|
+
);
|
|
6442
|
+
const configService = context.services.get(
|
|
6443
|
+
"ConfigurationService"
|
|
6444
|
+
);
|
|
5781
6445
|
if (configService) {
|
|
5782
6446
|
this.url = configService.get("film.url", this.url);
|
|
5783
6447
|
this.opacity = configService.get("film.opacity", this.opacity);
|
|
@@ -5794,21 +6458,21 @@ var FilmTool = class {
|
|
|
5794
6458
|
}
|
|
5795
6459
|
});
|
|
5796
6460
|
}
|
|
5797
|
-
this.
|
|
6461
|
+
context.eventBus.on("canvas:resized", this.onCanvasResized);
|
|
5798
6462
|
this.updateFilm();
|
|
5799
6463
|
}
|
|
5800
6464
|
deactivate(context) {
|
|
5801
|
-
|
|
5802
|
-
|
|
5803
|
-
|
|
5804
|
-
|
|
5805
|
-
|
|
5806
|
-
|
|
5807
|
-
|
|
5808
|
-
|
|
5809
|
-
|
|
5810
|
-
|
|
5811
|
-
|
|
6465
|
+
var _a;
|
|
6466
|
+
context.eventBus.off("canvas:resized", this.onCanvasResized);
|
|
6467
|
+
this.renderSeq += 1;
|
|
6468
|
+
this.specs = [];
|
|
6469
|
+
this.renderImageUrl = "";
|
|
6470
|
+
(_a = this.renderProducerDisposable) == null ? void 0 : _a.dispose();
|
|
6471
|
+
this.renderProducerDisposable = void 0;
|
|
6472
|
+
if (!this.canvasService) return;
|
|
6473
|
+
void this.canvasService.flushRenderFromProducers();
|
|
6474
|
+
this.canvasService.requestRenderAll();
|
|
6475
|
+
this.canvasService = void 0;
|
|
5812
6476
|
}
|
|
5813
6477
|
contribute() {
|
|
5814
6478
|
return {
|
|
@@ -5844,73 +6508,108 @@ var FilmTool = class {
|
|
|
5844
6508
|
]
|
|
5845
6509
|
};
|
|
5846
6510
|
}
|
|
5847
|
-
|
|
5848
|
-
|
|
5849
|
-
|
|
5850
|
-
|
|
5851
|
-
|
|
5852
|
-
|
|
5853
|
-
|
|
5854
|
-
|
|
5855
|
-
height,
|
|
5856
|
-
left: 0,
|
|
5857
|
-
top: 0,
|
|
5858
|
-
originX: "left",
|
|
5859
|
-
originY: "top",
|
|
5860
|
-
selectable: false,
|
|
5861
|
-
evented: false,
|
|
5862
|
-
subTargetCheck: false,
|
|
5863
|
-
interactive: false
|
|
5864
|
-
});
|
|
5865
|
-
this.canvasService.canvas.bringObjectToFront(layer);
|
|
5866
|
-
}
|
|
6511
|
+
getViewportSize() {
|
|
6512
|
+
var _a, _b;
|
|
6513
|
+
const width = Number(((_a = this.canvasService) == null ? void 0 : _a.canvas.width) || 0);
|
|
6514
|
+
const height = Number(((_b = this.canvasService) == null ? void 0 : _b.canvas.height) || 0);
|
|
6515
|
+
return {
|
|
6516
|
+
width: width > 0 ? width : DEFAULT_WIDTH2,
|
|
6517
|
+
height: height > 0 ? height : DEFAULT_HEIGHT2
|
|
6518
|
+
};
|
|
5867
6519
|
}
|
|
5868
|
-
|
|
5869
|
-
|
|
5870
|
-
|
|
5871
|
-
|
|
5872
|
-
|
|
5873
|
-
return;
|
|
5874
|
-
}
|
|
5875
|
-
const { url, opacity } = this;
|
|
5876
|
-
if (!url) {
|
|
5877
|
-
const img2 = this.canvasService.getObject("film-image", "overlay");
|
|
5878
|
-
if (img2) {
|
|
5879
|
-
layer.remove(img2);
|
|
5880
|
-
this.canvasService.requestRenderAll();
|
|
5881
|
-
}
|
|
5882
|
-
return;
|
|
6520
|
+
clampOpacity(value) {
|
|
6521
|
+
return Math.max(0, Math.min(1, Number(value)));
|
|
6522
|
+
}
|
|
6523
|
+
buildFilmSpecs(imageUrl, opacity) {
|
|
6524
|
+
if (!imageUrl) {
|
|
6525
|
+
return [];
|
|
5883
6526
|
}
|
|
5884
|
-
const width = this.
|
|
5885
|
-
const
|
|
5886
|
-
|
|
5887
|
-
|
|
5888
|
-
|
|
5889
|
-
|
|
5890
|
-
|
|
5891
|
-
|
|
5892
|
-
|
|
5893
|
-
|
|
5894
|
-
|
|
5895
|
-
|
|
5896
|
-
|
|
5897
|
-
|
|
5898
|
-
|
|
5899
|
-
|
|
6527
|
+
const { width, height } = this.getViewportSize();
|
|
6528
|
+
const sourceSize = this.sourceSizeBySrc.get(imageUrl);
|
|
6529
|
+
const sourceWidth = Math.max(1, Number((sourceSize == null ? void 0 : sourceSize.width) || width));
|
|
6530
|
+
const sourceHeight = Math.max(1, Number((sourceSize == null ? void 0 : sourceSize.height) || height));
|
|
6531
|
+
const coverScale = Math.max(width / sourceWidth, height / sourceHeight);
|
|
6532
|
+
return [
|
|
6533
|
+
{
|
|
6534
|
+
id: FILM_IMAGE_ID,
|
|
6535
|
+
type: "image",
|
|
6536
|
+
src: imageUrl,
|
|
6537
|
+
space: "screen",
|
|
6538
|
+
data: {
|
|
6539
|
+
id: FILM_IMAGE_ID,
|
|
6540
|
+
layerId: FILM_LAYER_ID,
|
|
6541
|
+
type: "film-image"
|
|
6542
|
+
},
|
|
6543
|
+
props: {
|
|
5900
6544
|
left: 0,
|
|
5901
6545
|
top: 0,
|
|
5902
|
-
|
|
6546
|
+
originX: "left",
|
|
6547
|
+
originY: "top",
|
|
6548
|
+
opacity: this.clampOpacity(opacity),
|
|
6549
|
+
scaleX: coverScale,
|
|
6550
|
+
scaleY: coverScale,
|
|
5903
6551
|
selectable: false,
|
|
5904
6552
|
evented: false,
|
|
5905
|
-
|
|
5906
|
-
}
|
|
5907
|
-
|
|
6553
|
+
excludeFromExport: true
|
|
6554
|
+
}
|
|
6555
|
+
}
|
|
6556
|
+
];
|
|
6557
|
+
}
|
|
6558
|
+
async ensureImageSize(src) {
|
|
6559
|
+
if (!src) return null;
|
|
6560
|
+
const cached = this.sourceSizeBySrc.get(src);
|
|
6561
|
+
if (cached) return cached;
|
|
6562
|
+
const pending = this.pendingSizeBySrc.get(src);
|
|
6563
|
+
if (pending) {
|
|
6564
|
+
return pending;
|
|
6565
|
+
}
|
|
6566
|
+
const task = this.loadImageSize(src);
|
|
6567
|
+
this.pendingSizeBySrc.set(src, task);
|
|
6568
|
+
try {
|
|
6569
|
+
return await task;
|
|
6570
|
+
} finally {
|
|
6571
|
+
if (this.pendingSizeBySrc.get(src) === task) {
|
|
6572
|
+
this.pendingSizeBySrc.delete(src);
|
|
6573
|
+
}
|
|
6574
|
+
}
|
|
6575
|
+
}
|
|
6576
|
+
async loadImageSize(src) {
|
|
6577
|
+
try {
|
|
6578
|
+
const image = await import_fabric4.FabricImage.fromURL(src, {
|
|
6579
|
+
crossOrigin: "anonymous"
|
|
6580
|
+
});
|
|
6581
|
+
const width = Number((image == null ? void 0 : image.width) || 0);
|
|
6582
|
+
const height = Number((image == null ? void 0 : image.height) || 0);
|
|
6583
|
+
if (width > 0 && height > 0) {
|
|
6584
|
+
const size = { width, height };
|
|
6585
|
+
this.sourceSizeBySrc.set(src, size);
|
|
6586
|
+
return size;
|
|
5908
6587
|
}
|
|
5909
|
-
this.canvasService.requestRenderAll();
|
|
5910
6588
|
} catch (error) {
|
|
5911
|
-
console.error("[FilmTool] Failed to load film image",
|
|
6589
|
+
console.error("[FilmTool] Failed to load film image", src, error);
|
|
6590
|
+
}
|
|
6591
|
+
return null;
|
|
6592
|
+
}
|
|
6593
|
+
updateFilm() {
|
|
6594
|
+
void this.updateFilmAsync();
|
|
6595
|
+
}
|
|
6596
|
+
async updateFilmAsync() {
|
|
6597
|
+
if (!this.canvasService) return;
|
|
6598
|
+
const seq = ++this.renderSeq;
|
|
6599
|
+
const nextUrl = String(this.url || "").trim();
|
|
6600
|
+
if (!nextUrl) {
|
|
6601
|
+
this.renderImageUrl = "";
|
|
6602
|
+
} else if (nextUrl !== this.renderImageUrl) {
|
|
6603
|
+
const loaded = await this.ensureImageSize(nextUrl);
|
|
6604
|
+
if (seq !== this.renderSeq) return;
|
|
6605
|
+
if (loaded) {
|
|
6606
|
+
this.renderImageUrl = nextUrl;
|
|
6607
|
+
}
|
|
5912
6608
|
}
|
|
5913
|
-
|
|
6609
|
+
this.specs = this.buildFilmSpecs(this.renderImageUrl, this.opacity);
|
|
6610
|
+
await this.canvasService.flushRenderFromProducers();
|
|
6611
|
+
if (seq !== this.renderSeq) return;
|
|
6612
|
+
this.canvasService.bringLayerToFront(FILM_LAYER_ID);
|
|
5914
6613
|
this.canvasService.requestRenderAll();
|
|
5915
6614
|
}
|
|
5916
6615
|
};
|
|
@@ -6007,19 +6706,37 @@ var MirrorTool = class {
|
|
|
6007
6706
|
|
|
6008
6707
|
// src/extensions/ruler.ts
|
|
6009
6708
|
var import_core8 = require("@pooder/core");
|
|
6010
|
-
var
|
|
6709
|
+
var RULER_LAYER_ID = "ruler-overlay";
|
|
6710
|
+
var EXTENSION_LINE_LENGTH = 5;
|
|
6711
|
+
var MIN_ARROW_SIZE = 4;
|
|
6712
|
+
var THICKNESS_TO_STROKE_WIDTH_RATIO = 20;
|
|
6713
|
+
var DEFAULT_THICKNESS = 20;
|
|
6714
|
+
var DEFAULT_GAP = 45;
|
|
6715
|
+
var DEFAULT_FONT_SIZE = 10;
|
|
6716
|
+
var DEFAULT_BACKGROUND_COLOR = "#f0f0f0";
|
|
6717
|
+
var DEFAULT_TEXT_COLOR = "#333333";
|
|
6718
|
+
var DEFAULT_LINE_COLOR = "#999999";
|
|
6719
|
+
var RULER_THICKNESS_MIN = 10;
|
|
6720
|
+
var RULER_THICKNESS_MAX = 100;
|
|
6721
|
+
var RULER_GAP_MIN = 0;
|
|
6722
|
+
var RULER_GAP_MAX = 100;
|
|
6723
|
+
var RULER_FONT_SIZE_MIN = 8;
|
|
6724
|
+
var RULER_FONT_SIZE_MAX = 24;
|
|
6011
6725
|
var RulerTool = class {
|
|
6012
6726
|
constructor(options) {
|
|
6013
6727
|
this.id = "pooder.kit.ruler";
|
|
6014
6728
|
this.metadata = {
|
|
6015
6729
|
name: "RulerTool"
|
|
6016
6730
|
};
|
|
6017
|
-
this.thickness =
|
|
6018
|
-
this.gap =
|
|
6019
|
-
this.backgroundColor =
|
|
6020
|
-
this.textColor =
|
|
6021
|
-
this.lineColor =
|
|
6022
|
-
this.fontSize =
|
|
6731
|
+
this.thickness = DEFAULT_THICKNESS;
|
|
6732
|
+
this.gap = DEFAULT_GAP;
|
|
6733
|
+
this.backgroundColor = DEFAULT_BACKGROUND_COLOR;
|
|
6734
|
+
this.textColor = DEFAULT_TEXT_COLOR;
|
|
6735
|
+
this.lineColor = DEFAULT_LINE_COLOR;
|
|
6736
|
+
this.fontSize = DEFAULT_FONT_SIZE;
|
|
6737
|
+
this.renderSeq = 0;
|
|
6738
|
+
this.numericProps = /* @__PURE__ */ new Set(["thickness", "gap", "fontSize"]);
|
|
6739
|
+
this.specs = [];
|
|
6023
6740
|
this.onCanvasResized = () => {
|
|
6024
6741
|
this.updateRuler();
|
|
6025
6742
|
};
|
|
@@ -6028,50 +6745,73 @@ var RulerTool = class {
|
|
|
6028
6745
|
}
|
|
6029
6746
|
}
|
|
6030
6747
|
activate(context) {
|
|
6748
|
+
var _a;
|
|
6031
6749
|
this.context = context;
|
|
6032
6750
|
this.canvasService = context.services.get("CanvasService");
|
|
6033
6751
|
if (!this.canvasService) {
|
|
6034
|
-
console.warn("CanvasService not found
|
|
6752
|
+
console.warn("[RulerTool] CanvasService not found.");
|
|
6035
6753
|
return;
|
|
6036
6754
|
}
|
|
6755
|
+
(_a = this.renderProducerDisposable) == null ? void 0 : _a.dispose();
|
|
6756
|
+
this.renderProducerDisposable = this.canvasService.registerRenderProducer(
|
|
6757
|
+
this.id,
|
|
6758
|
+
() => ({
|
|
6759
|
+
rootLayerSpecs: {
|
|
6760
|
+
[RULER_LAYER_ID]: this.specs
|
|
6761
|
+
},
|
|
6762
|
+
replaceRootLayerIds: [RULER_LAYER_ID]
|
|
6763
|
+
}),
|
|
6764
|
+
{ priority: 400 }
|
|
6765
|
+
);
|
|
6037
6766
|
const configService = context.services.get(
|
|
6038
6767
|
"ConfigurationService"
|
|
6039
6768
|
);
|
|
6040
6769
|
if (configService) {
|
|
6041
|
-
this.
|
|
6042
|
-
this.gap = configService.get("ruler.gap", this.gap);
|
|
6043
|
-
this.backgroundColor = configService.get(
|
|
6044
|
-
"ruler.backgroundColor",
|
|
6045
|
-
this.backgroundColor
|
|
6046
|
-
);
|
|
6047
|
-
this.textColor = configService.get("ruler.textColor", this.textColor);
|
|
6048
|
-
this.lineColor = configService.get("ruler.lineColor", this.lineColor);
|
|
6049
|
-
this.fontSize = configService.get("ruler.fontSize", this.fontSize);
|
|
6770
|
+
this.syncConfig(configService);
|
|
6050
6771
|
configService.onAnyChange((e) => {
|
|
6051
6772
|
let shouldUpdate = false;
|
|
6052
6773
|
if (e.key.startsWith("ruler.")) {
|
|
6053
6774
|
const prop = e.key.split(".")[1];
|
|
6054
6775
|
if (prop && prop in this) {
|
|
6055
|
-
this
|
|
6776
|
+
if (this.numericProps.has(prop)) {
|
|
6777
|
+
this[prop] = this.toFiniteNumber(
|
|
6778
|
+
e.value,
|
|
6779
|
+
this[prop]
|
|
6780
|
+
);
|
|
6781
|
+
} else {
|
|
6782
|
+
this[prop] = e.value;
|
|
6783
|
+
}
|
|
6056
6784
|
shouldUpdate = true;
|
|
6785
|
+
this.log("config:update", {
|
|
6786
|
+
key: e.key,
|
|
6787
|
+
raw: e.value,
|
|
6788
|
+
normalized: this[prop]
|
|
6789
|
+
});
|
|
6057
6790
|
}
|
|
6058
6791
|
} else if (e.key.startsWith("size.")) {
|
|
6059
6792
|
shouldUpdate = true;
|
|
6793
|
+
this.log("size:update", { key: e.key, value: e.value });
|
|
6060
6794
|
}
|
|
6061
6795
|
if (shouldUpdate) {
|
|
6062
6796
|
this.updateRuler();
|
|
6063
6797
|
}
|
|
6064
6798
|
});
|
|
6065
6799
|
}
|
|
6066
|
-
this.createLayer();
|
|
6067
6800
|
context.eventBus.on("canvas:resized", this.onCanvasResized);
|
|
6068
6801
|
this.updateRuler();
|
|
6069
6802
|
}
|
|
6070
6803
|
deactivate(context) {
|
|
6804
|
+
var _a;
|
|
6071
6805
|
context.eventBus.off("canvas:resized", this.onCanvasResized);
|
|
6072
|
-
this.
|
|
6806
|
+
this.specs = [];
|
|
6807
|
+
(_a = this.renderProducerDisposable) == null ? void 0 : _a.dispose();
|
|
6808
|
+
this.renderProducerDisposable = void 0;
|
|
6809
|
+
if (this.canvasService) {
|
|
6810
|
+
void this.canvasService.flushRenderFromProducers();
|
|
6811
|
+
}
|
|
6073
6812
|
this.canvasService = void 0;
|
|
6074
6813
|
this.context = void 0;
|
|
6814
|
+
this.renderSeq = 0;
|
|
6075
6815
|
}
|
|
6076
6816
|
contribute() {
|
|
6077
6817
|
return {
|
|
@@ -6080,43 +6820,43 @@ var RulerTool = class {
|
|
|
6080
6820
|
id: "ruler.thickness",
|
|
6081
6821
|
type: "number",
|
|
6082
6822
|
label: "Thickness",
|
|
6083
|
-
min:
|
|
6084
|
-
max:
|
|
6085
|
-
default:
|
|
6823
|
+
min: RULER_THICKNESS_MIN,
|
|
6824
|
+
max: RULER_THICKNESS_MAX,
|
|
6825
|
+
default: DEFAULT_THICKNESS
|
|
6086
6826
|
},
|
|
6087
6827
|
{
|
|
6088
6828
|
id: "ruler.gap",
|
|
6089
6829
|
type: "number",
|
|
6090
6830
|
label: "Gap",
|
|
6091
|
-
min:
|
|
6092
|
-
max:
|
|
6093
|
-
default:
|
|
6831
|
+
min: RULER_GAP_MIN,
|
|
6832
|
+
max: RULER_GAP_MAX,
|
|
6833
|
+
default: DEFAULT_GAP
|
|
6094
6834
|
},
|
|
6095
6835
|
{
|
|
6096
6836
|
id: "ruler.backgroundColor",
|
|
6097
6837
|
type: "color",
|
|
6098
6838
|
label: "Background Color",
|
|
6099
|
-
default:
|
|
6839
|
+
default: DEFAULT_BACKGROUND_COLOR
|
|
6100
6840
|
},
|
|
6101
6841
|
{
|
|
6102
6842
|
id: "ruler.textColor",
|
|
6103
6843
|
type: "color",
|
|
6104
6844
|
label: "Text Color",
|
|
6105
|
-
default:
|
|
6845
|
+
default: DEFAULT_TEXT_COLOR
|
|
6106
6846
|
},
|
|
6107
6847
|
{
|
|
6108
6848
|
id: "ruler.lineColor",
|
|
6109
6849
|
type: "color",
|
|
6110
6850
|
label: "Line Color",
|
|
6111
|
-
default:
|
|
6851
|
+
default: DEFAULT_LINE_COLOR
|
|
6112
6852
|
},
|
|
6113
6853
|
{
|
|
6114
6854
|
id: "ruler.fontSize",
|
|
6115
6855
|
type: "number",
|
|
6116
6856
|
label: "Font Size",
|
|
6117
|
-
min:
|
|
6118
|
-
max:
|
|
6119
|
-
default:
|
|
6857
|
+
min: RULER_FONT_SIZE_MIN,
|
|
6858
|
+
max: RULER_FONT_SIZE_MAX,
|
|
6859
|
+
default: DEFAULT_FONT_SIZE
|
|
6120
6860
|
}
|
|
6121
6861
|
],
|
|
6122
6862
|
[import_core8.ContributionPointIds.COMMANDS]: [
|
|
@@ -6129,12 +6869,23 @@ var RulerTool = class {
|
|
|
6129
6869
|
textColor: this.textColor,
|
|
6130
6870
|
lineColor: this.lineColor,
|
|
6131
6871
|
fontSize: this.fontSize,
|
|
6132
|
-
thickness: this.thickness
|
|
6872
|
+
thickness: this.thickness,
|
|
6873
|
+
gap: this.gap
|
|
6133
6874
|
};
|
|
6134
6875
|
const newState = { ...oldState, ...theme };
|
|
6135
|
-
if (JSON.stringify(newState) === JSON.stringify(oldState))
|
|
6876
|
+
if (JSON.stringify(newState) === JSON.stringify(oldState)) {
|
|
6136
6877
|
return true;
|
|
6878
|
+
}
|
|
6137
6879
|
Object.assign(this, newState);
|
|
6880
|
+
this.thickness = this.toFiniteNumber(
|
|
6881
|
+
this.thickness,
|
|
6882
|
+
DEFAULT_THICKNESS
|
|
6883
|
+
);
|
|
6884
|
+
this.gap = this.toFiniteNumber(this.gap, DEFAULT_GAP);
|
|
6885
|
+
this.fontSize = this.toFiniteNumber(
|
|
6886
|
+
this.fontSize,
|
|
6887
|
+
DEFAULT_FONT_SIZE
|
|
6888
|
+
);
|
|
6138
6889
|
this.updateRuler();
|
|
6139
6890
|
return true;
|
|
6140
6891
|
}
|
|
@@ -6142,225 +6893,367 @@ var RulerTool = class {
|
|
|
6142
6893
|
]
|
|
6143
6894
|
};
|
|
6144
6895
|
}
|
|
6145
|
-
|
|
6146
|
-
|
|
6147
|
-
|
|
6896
|
+
log(step, payload) {
|
|
6897
|
+
if (payload) {
|
|
6898
|
+
console.debug(`[RulerTool] ${step}`, payload);
|
|
6899
|
+
return;
|
|
6900
|
+
}
|
|
6901
|
+
console.debug(`[RulerTool] ${step}`);
|
|
6148
6902
|
}
|
|
6149
|
-
|
|
6150
|
-
|
|
6151
|
-
|
|
6152
|
-
|
|
6153
|
-
|
|
6154
|
-
|
|
6155
|
-
|
|
6156
|
-
|
|
6157
|
-
|
|
6158
|
-
|
|
6159
|
-
|
|
6160
|
-
|
|
6161
|
-
|
|
6162
|
-
|
|
6903
|
+
syncConfig(configService) {
|
|
6904
|
+
this.thickness = this.toFiniteNumber(
|
|
6905
|
+
configService.get("ruler.thickness", this.thickness),
|
|
6906
|
+
DEFAULT_THICKNESS
|
|
6907
|
+
);
|
|
6908
|
+
this.gap = Math.max(
|
|
6909
|
+
0,
|
|
6910
|
+
this.toFiniteNumber(
|
|
6911
|
+
configService.get("ruler.gap", this.gap),
|
|
6912
|
+
DEFAULT_GAP
|
|
6913
|
+
)
|
|
6914
|
+
);
|
|
6915
|
+
this.backgroundColor = configService.get(
|
|
6916
|
+
"ruler.backgroundColor",
|
|
6917
|
+
this.backgroundColor
|
|
6918
|
+
);
|
|
6919
|
+
this.textColor = configService.get("ruler.textColor", this.textColor);
|
|
6920
|
+
this.lineColor = configService.get("ruler.lineColor", this.lineColor);
|
|
6921
|
+
this.fontSize = this.toFiniteNumber(
|
|
6922
|
+
configService.get("ruler.fontSize", this.fontSize),
|
|
6923
|
+
DEFAULT_FONT_SIZE
|
|
6924
|
+
);
|
|
6925
|
+
this.log("config:loaded", {
|
|
6926
|
+
thickness: this.thickness,
|
|
6927
|
+
gap: this.gap,
|
|
6928
|
+
fontSize: this.fontSize,
|
|
6929
|
+
backgroundColor: this.backgroundColor,
|
|
6930
|
+
textColor: this.textColor,
|
|
6931
|
+
lineColor: this.lineColor
|
|
6163
6932
|
});
|
|
6164
|
-
canvas.bringObjectToFront(layer);
|
|
6165
6933
|
}
|
|
6166
|
-
|
|
6167
|
-
|
|
6168
|
-
|
|
6169
|
-
if (layer) {
|
|
6170
|
-
this.canvasService.canvas.remove(layer);
|
|
6171
|
-
}
|
|
6934
|
+
toFiniteNumber(value, fallback) {
|
|
6935
|
+
const numeric = Number(value);
|
|
6936
|
+
return Number.isFinite(numeric) ? numeric : fallback;
|
|
6172
6937
|
}
|
|
6173
|
-
|
|
6174
|
-
|
|
6175
|
-
|
|
6176
|
-
|
|
6177
|
-
|
|
6178
|
-
|
|
6179
|
-
|
|
6180
|
-
|
|
6181
|
-
|
|
6182
|
-
|
|
6183
|
-
const
|
|
6184
|
-
|
|
6185
|
-
|
|
6186
|
-
|
|
6187
|
-
|
|
6188
|
-
|
|
6189
|
-
|
|
6190
|
-
|
|
6191
|
-
|
|
6192
|
-
|
|
6193
|
-
|
|
6938
|
+
toSceneDisplayLength(value) {
|
|
6939
|
+
if (!this.canvasService) return value;
|
|
6940
|
+
return this.canvasService.toSceneLength(value);
|
|
6941
|
+
}
|
|
6942
|
+
formatLengthMm(valueMm, unit) {
|
|
6943
|
+
const converted = fromMm(valueMm, unit);
|
|
6944
|
+
const fractionDigits = unit === "in" ? 3 : 2;
|
|
6945
|
+
return Number(converted.toFixed(fractionDigits)).toString();
|
|
6946
|
+
}
|
|
6947
|
+
buildLinePath(start, end) {
|
|
6948
|
+
const dx = end.x - start.x;
|
|
6949
|
+
const dy = end.y - start.y;
|
|
6950
|
+
return `M 0 0 L ${dx} ${dy}`;
|
|
6951
|
+
}
|
|
6952
|
+
buildStartArrowPath(size) {
|
|
6953
|
+
return `M 0 0 L ${size} ${-size / 2} L ${size} ${size / 2} Z`;
|
|
6954
|
+
}
|
|
6955
|
+
buildEndArrowPath(size) {
|
|
6956
|
+
return `M 0 0 L ${-size} ${-size / 2} L ${-size} ${size / 2} Z`;
|
|
6957
|
+
}
|
|
6958
|
+
createPathSpec(id, pathData, position, options) {
|
|
6959
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
6960
|
+
return {
|
|
6961
|
+
id,
|
|
6962
|
+
type: "path",
|
|
6963
|
+
data: {
|
|
6964
|
+
id,
|
|
6965
|
+
type: "ruler"
|
|
6966
|
+
},
|
|
6967
|
+
props: {
|
|
6968
|
+
pathData,
|
|
6969
|
+
left: position.x,
|
|
6970
|
+
top: position.y,
|
|
6971
|
+
originX: (_a = options.originX) != null ? _a : "left",
|
|
6972
|
+
originY: (_b = options.originY) != null ? _b : "top",
|
|
6973
|
+
angle: (_c = options.angle) != null ? _c : 0,
|
|
6974
|
+
stroke: (_d = options.stroke) != null ? _d : null,
|
|
6975
|
+
fill: (_e = options.fill) != null ? _e : null,
|
|
6976
|
+
strokeWidth: (_f = options.strokeWidth) != null ? _f : 1,
|
|
6977
|
+
strokeLineCap: (_g = options.strokeLineCap) != null ? _g : "butt",
|
|
6978
|
+
selectable: false,
|
|
6979
|
+
evented: false,
|
|
6980
|
+
excludeFromExport: true
|
|
6981
|
+
}
|
|
6982
|
+
};
|
|
6983
|
+
}
|
|
6984
|
+
createTextSpec(id, text, position, angle = 0) {
|
|
6985
|
+
return {
|
|
6986
|
+
id,
|
|
6987
|
+
type: "text",
|
|
6988
|
+
data: {
|
|
6989
|
+
id,
|
|
6990
|
+
type: "ruler"
|
|
6991
|
+
},
|
|
6992
|
+
props: {
|
|
6993
|
+
text,
|
|
6994
|
+
left: position.x,
|
|
6995
|
+
top: position.y,
|
|
6996
|
+
angle,
|
|
6997
|
+
fontSize: this.toSceneDisplayLength(this.fontSize),
|
|
6998
|
+
fill: this.textColor,
|
|
6999
|
+
fontFamily: "Arial",
|
|
7000
|
+
originX: "center",
|
|
6194
7001
|
originY: "center",
|
|
6195
|
-
|
|
7002
|
+
backgroundColor: this.backgroundColor,
|
|
6196
7003
|
selectable: false,
|
|
6197
|
-
evented: false
|
|
7004
|
+
evented: false,
|
|
7005
|
+
excludeFromExport: true
|
|
6198
7006
|
}
|
|
7007
|
+
};
|
|
7008
|
+
}
|
|
7009
|
+
buildRulerSpecs(input) {
|
|
7010
|
+
const { left, top, right, bottom, widthLabel, heightLabel } = input;
|
|
7011
|
+
const gap = Math.max(
|
|
7012
|
+
0,
|
|
7013
|
+
this.toSceneDisplayLength(this.toFiniteNumber(this.gap, DEFAULT_GAP))
|
|
7014
|
+
);
|
|
7015
|
+
const topY = top - gap;
|
|
7016
|
+
const leftX = left - gap;
|
|
7017
|
+
const arrowSize = Math.max(
|
|
7018
|
+
this.toSceneDisplayLength(MIN_ARROW_SIZE),
|
|
7019
|
+
this.toSceneDisplayLength(this.thickness * 0.3)
|
|
7020
|
+
);
|
|
7021
|
+
const strokeWidth = Math.max(
|
|
7022
|
+
this.toSceneDisplayLength(1),
|
|
7023
|
+
this.toSceneDisplayLength(
|
|
7024
|
+
this.thickness / THICKNESS_TO_STROKE_WIDTH_RATIO
|
|
7025
|
+
)
|
|
7026
|
+
);
|
|
7027
|
+
const extensionLength = this.toSceneDisplayLength(EXTENSION_LINE_LENGTH);
|
|
7028
|
+
const topLineAngleDeg = 0;
|
|
7029
|
+
const leftLineAngleDeg = 90;
|
|
7030
|
+
const topMidX = left + (right - left) / 2;
|
|
7031
|
+
const leftMidY = top + (bottom - top) / 2;
|
|
7032
|
+
const topLineStartX = Math.min(left + arrowSize, topMidX);
|
|
7033
|
+
const topLineEndX = Math.max(right - arrowSize, topMidX);
|
|
7034
|
+
const leftLineStartY = Math.min(top + arrowSize, leftMidY);
|
|
7035
|
+
const leftLineEndY = Math.max(bottom - arrowSize, leftMidY);
|
|
7036
|
+
const specs = [];
|
|
7037
|
+
specs.push(
|
|
7038
|
+
this.createPathSpec(
|
|
7039
|
+
"ruler.top.line",
|
|
7040
|
+
this.buildLinePath(
|
|
7041
|
+
{ x: topLineStartX, y: topY },
|
|
7042
|
+
{ x: topLineEndX, y: topY }
|
|
7043
|
+
),
|
|
7044
|
+
{ x: topLineStartX, y: topY },
|
|
7045
|
+
{
|
|
7046
|
+
stroke: this.lineColor,
|
|
7047
|
+
strokeWidth,
|
|
7048
|
+
strokeLineCap: "butt"
|
|
7049
|
+
}
|
|
7050
|
+
),
|
|
7051
|
+
this.createPathSpec(
|
|
7052
|
+
"ruler.top.arrow.start",
|
|
7053
|
+
this.buildStartArrowPath(arrowSize),
|
|
7054
|
+
{ x: left, y: topY },
|
|
7055
|
+
{
|
|
7056
|
+
fill: this.lineColor,
|
|
7057
|
+
stroke: this.lineColor,
|
|
7058
|
+
strokeWidth: this.toSceneDisplayLength(1),
|
|
7059
|
+
originX: "left",
|
|
7060
|
+
originY: "center",
|
|
7061
|
+
angle: topLineAngleDeg
|
|
7062
|
+
}
|
|
7063
|
+
),
|
|
7064
|
+
this.createPathSpec(
|
|
7065
|
+
"ruler.top.arrow.end",
|
|
7066
|
+
this.buildEndArrowPath(arrowSize),
|
|
7067
|
+
{ x: right, y: topY },
|
|
7068
|
+
{
|
|
7069
|
+
fill: this.lineColor,
|
|
7070
|
+
stroke: this.lineColor,
|
|
7071
|
+
strokeWidth: this.toSceneDisplayLength(1),
|
|
7072
|
+
originX: "right",
|
|
7073
|
+
originY: "center",
|
|
7074
|
+
angle: topLineAngleDeg
|
|
7075
|
+
}
|
|
7076
|
+
),
|
|
7077
|
+
this.createPathSpec(
|
|
7078
|
+
"ruler.top.ext.start",
|
|
7079
|
+
this.buildLinePath(
|
|
7080
|
+
{ x: left, y: topY - extensionLength },
|
|
7081
|
+
{ x: left, y: topY + extensionLength }
|
|
7082
|
+
),
|
|
7083
|
+
{ x: left, y: topY - extensionLength },
|
|
7084
|
+
{
|
|
7085
|
+
stroke: this.lineColor,
|
|
7086
|
+
strokeWidth: this.toSceneDisplayLength(1)
|
|
7087
|
+
}
|
|
7088
|
+
),
|
|
7089
|
+
this.createPathSpec(
|
|
7090
|
+
"ruler.top.ext.end",
|
|
7091
|
+
this.buildLinePath(
|
|
7092
|
+
{ x: right, y: topY - extensionLength },
|
|
7093
|
+
{ x: right, y: topY + extensionLength }
|
|
7094
|
+
),
|
|
7095
|
+
{ x: right, y: topY - extensionLength },
|
|
7096
|
+
{
|
|
7097
|
+
stroke: this.lineColor,
|
|
7098
|
+
strokeWidth: this.toSceneDisplayLength(1)
|
|
7099
|
+
}
|
|
7100
|
+
),
|
|
7101
|
+
this.createTextSpec("ruler.top.label", widthLabel, {
|
|
7102
|
+
x: left + (right - left) / 2,
|
|
7103
|
+
y: topY
|
|
7104
|
+
})
|
|
6199
7105
|
);
|
|
6200
|
-
|
|
6201
|
-
|
|
6202
|
-
|
|
6203
|
-
|
|
6204
|
-
|
|
6205
|
-
|
|
6206
|
-
|
|
6207
|
-
|
|
6208
|
-
|
|
6209
|
-
|
|
6210
|
-
|
|
6211
|
-
|
|
6212
|
-
|
|
6213
|
-
|
|
6214
|
-
|
|
6215
|
-
|
|
7106
|
+
specs.push(
|
|
7107
|
+
this.createPathSpec(
|
|
7108
|
+
"ruler.left.line",
|
|
7109
|
+
this.buildLinePath(
|
|
7110
|
+
{ x: leftX, y: leftLineStartY },
|
|
7111
|
+
{ x: leftX, y: leftLineEndY }
|
|
7112
|
+
),
|
|
7113
|
+
{ x: leftX, y: leftLineStartY },
|
|
7114
|
+
{
|
|
7115
|
+
stroke: this.lineColor,
|
|
7116
|
+
strokeWidth,
|
|
7117
|
+
strokeLineCap: "butt"
|
|
7118
|
+
}
|
|
7119
|
+
),
|
|
7120
|
+
this.createPathSpec(
|
|
7121
|
+
"ruler.left.arrow.start",
|
|
7122
|
+
this.buildStartArrowPath(arrowSize),
|
|
7123
|
+
{ x: leftX, y: top },
|
|
7124
|
+
{
|
|
7125
|
+
fill: this.lineColor,
|
|
7126
|
+
stroke: this.lineColor,
|
|
7127
|
+
strokeWidth: this.toSceneDisplayLength(1),
|
|
7128
|
+
originX: "left",
|
|
7129
|
+
originY: "center",
|
|
7130
|
+
angle: leftLineAngleDeg
|
|
7131
|
+
}
|
|
7132
|
+
),
|
|
7133
|
+
this.createPathSpec(
|
|
7134
|
+
"ruler.left.arrow.end",
|
|
7135
|
+
this.buildEndArrowPath(arrowSize),
|
|
7136
|
+
{ x: leftX, y: bottom },
|
|
7137
|
+
{
|
|
7138
|
+
fill: this.lineColor,
|
|
7139
|
+
stroke: this.lineColor,
|
|
7140
|
+
strokeWidth: this.toSceneDisplayLength(1),
|
|
7141
|
+
originX: "right",
|
|
7142
|
+
originY: "center",
|
|
7143
|
+
angle: leftLineAngleDeg
|
|
7144
|
+
}
|
|
7145
|
+
),
|
|
7146
|
+
this.createPathSpec(
|
|
7147
|
+
"ruler.left.ext.start",
|
|
7148
|
+
this.buildLinePath(
|
|
7149
|
+
{ x: leftX - extensionLength, y: top },
|
|
7150
|
+
{ x: leftX + extensionLength, y: top }
|
|
7151
|
+
),
|
|
7152
|
+
{ x: leftX - extensionLength, y: top },
|
|
7153
|
+
{
|
|
7154
|
+
stroke: this.lineColor,
|
|
7155
|
+
strokeWidth: this.toSceneDisplayLength(1)
|
|
7156
|
+
}
|
|
7157
|
+
),
|
|
7158
|
+
this.createPathSpec(
|
|
7159
|
+
"ruler.left.ext.end",
|
|
7160
|
+
this.buildLinePath(
|
|
7161
|
+
{ x: leftX - extensionLength, y: bottom },
|
|
7162
|
+
{ x: leftX + extensionLength, y: bottom }
|
|
7163
|
+
),
|
|
7164
|
+
{ x: leftX - extensionLength, y: bottom },
|
|
7165
|
+
{
|
|
7166
|
+
stroke: this.lineColor,
|
|
7167
|
+
strokeWidth: this.toSceneDisplayLength(1)
|
|
7168
|
+
}
|
|
7169
|
+
),
|
|
7170
|
+
this.createTextSpec(
|
|
7171
|
+
"ruler.left.label",
|
|
7172
|
+
heightLabel,
|
|
7173
|
+
{
|
|
7174
|
+
x: leftX,
|
|
7175
|
+
y: top + (bottom - top) / 2
|
|
7176
|
+
},
|
|
7177
|
+
-90
|
|
7178
|
+
)
|
|
6216
7179
|
);
|
|
6217
|
-
return
|
|
6218
|
-
selectable: false,
|
|
6219
|
-
evented: false
|
|
6220
|
-
});
|
|
7180
|
+
return specs;
|
|
6221
7181
|
}
|
|
6222
7182
|
updateRuler() {
|
|
6223
|
-
|
|
7183
|
+
void this.updateRulerAsync();
|
|
7184
|
+
}
|
|
7185
|
+
async updateRulerAsync() {
|
|
7186
|
+
var _a, _b;
|
|
6224
7187
|
if (!this.canvasService) return;
|
|
6225
|
-
const layer = this.getLayer();
|
|
6226
|
-
if (!layer) return;
|
|
6227
|
-
layer.remove(...layer.getObjects());
|
|
6228
|
-
const { backgroundColor, lineColor, textColor, fontSize } = this;
|
|
6229
7188
|
const configService = (_a = this.context) == null ? void 0 : _a.services.get(
|
|
6230
7189
|
"ConfigurationService"
|
|
6231
7190
|
);
|
|
6232
7191
|
if (!configService) return;
|
|
7192
|
+
const seq = ++this.renderSeq;
|
|
6233
7193
|
const sizeState = readSizeState(configService);
|
|
6234
7194
|
const layout = computeSceneLayout(this.canvasService, sizeState);
|
|
6235
|
-
|
|
6236
|
-
|
|
6237
|
-
|
|
6238
|
-
|
|
6239
|
-
|
|
6240
|
-
|
|
6241
|
-
|
|
6242
|
-
|
|
6243
|
-
const rulerRight = rulerRect.left + rulerRect.width;
|
|
6244
|
-
const rulerBottom = rulerRect.top + rulerRect.height;
|
|
6245
|
-
const displayWidthMm = useCutAsRuler ? layout.cutWidthMm : layout.trimWidthMm;
|
|
6246
|
-
const displayHeightMm = useCutAsRuler ? layout.cutHeightMm : layout.trimHeightMm;
|
|
6247
|
-
const displayUnit = sizeState.unit;
|
|
6248
|
-
const topRulerY = rulerTop - gap;
|
|
6249
|
-
const topRulerXStart = rulerLeft;
|
|
6250
|
-
const topRulerXEnd = rulerRight;
|
|
6251
|
-
const leftRulerX = rulerLeft - gap;
|
|
6252
|
-
const leftRulerYStart = rulerTop;
|
|
6253
|
-
const leftRulerYEnd = rulerBottom;
|
|
6254
|
-
const topDimLine = this.createArrowLine(
|
|
6255
|
-
topRulerXStart,
|
|
6256
|
-
topRulerY,
|
|
6257
|
-
topRulerXEnd,
|
|
6258
|
-
topRulerY,
|
|
6259
|
-
lineColor
|
|
6260
|
-
);
|
|
6261
|
-
layer.add(topDimLine);
|
|
6262
|
-
const extLen = 5;
|
|
6263
|
-
layer.add(
|
|
6264
|
-
new import_fabric6.Line(
|
|
6265
|
-
[
|
|
6266
|
-
topRulerXStart,
|
|
6267
|
-
topRulerY - extLen,
|
|
6268
|
-
topRulerXStart,
|
|
6269
|
-
topRulerY + extLen
|
|
6270
|
-
],
|
|
6271
|
-
{
|
|
6272
|
-
stroke: lineColor,
|
|
6273
|
-
strokeWidth: 1,
|
|
6274
|
-
selectable: false,
|
|
6275
|
-
evented: false
|
|
6276
|
-
}
|
|
6277
|
-
)
|
|
6278
|
-
);
|
|
6279
|
-
layer.add(
|
|
6280
|
-
new import_fabric6.Line(
|
|
6281
|
-
[topRulerXEnd, topRulerY - extLen, topRulerXEnd, topRulerY + extLen],
|
|
6282
|
-
{
|
|
6283
|
-
stroke: lineColor,
|
|
6284
|
-
strokeWidth: 1,
|
|
6285
|
-
selectable: false,
|
|
6286
|
-
evented: false
|
|
6287
|
-
}
|
|
6288
|
-
)
|
|
6289
|
-
);
|
|
6290
|
-
const widthStr = formatMm(displayWidthMm, displayUnit);
|
|
6291
|
-
const topTextContent = `${widthStr} ${displayUnit}`;
|
|
6292
|
-
const topText = new import_fabric6.Text(topTextContent, {
|
|
6293
|
-
left: topRulerXStart + (rulerRight - rulerLeft) / 2,
|
|
6294
|
-
top: topRulerY,
|
|
6295
|
-
fontSize,
|
|
6296
|
-
fill: textColor,
|
|
6297
|
-
fontFamily: "Arial",
|
|
6298
|
-
originX: "center",
|
|
6299
|
-
originY: "center",
|
|
6300
|
-
backgroundColor,
|
|
6301
|
-
// Background mask for readability
|
|
6302
|
-
selectable: false,
|
|
6303
|
-
evented: false
|
|
7195
|
+
this.log("render:start", {
|
|
7196
|
+
seq,
|
|
7197
|
+
unit: sizeState.unit,
|
|
7198
|
+
gap: this.gap,
|
|
7199
|
+
thickness: this.thickness,
|
|
7200
|
+
fontSize: this.fontSize,
|
|
7201
|
+
hasLayout: !!layout,
|
|
7202
|
+
scale: (_b = layout == null ? void 0 : layout.scale) != null ? _b : null
|
|
6304
7203
|
});
|
|
6305
|
-
|
|
6306
|
-
|
|
6307
|
-
|
|
6308
|
-
|
|
6309
|
-
|
|
6310
|
-
|
|
6311
|
-
|
|
6312
|
-
);
|
|
6313
|
-
|
|
6314
|
-
|
|
6315
|
-
|
|
6316
|
-
|
|
6317
|
-
|
|
6318
|
-
|
|
6319
|
-
leftRulerX + extLen,
|
|
6320
|
-
leftRulerYStart
|
|
6321
|
-
],
|
|
6322
|
-
{
|
|
6323
|
-
stroke: lineColor,
|
|
6324
|
-
strokeWidth: 1,
|
|
6325
|
-
selectable: false,
|
|
6326
|
-
evented: false
|
|
6327
|
-
}
|
|
6328
|
-
)
|
|
6329
|
-
);
|
|
6330
|
-
layer.add(
|
|
6331
|
-
new import_fabric6.Line(
|
|
6332
|
-
[
|
|
6333
|
-
leftRulerX - extLen,
|
|
6334
|
-
leftRulerYEnd,
|
|
6335
|
-
leftRulerX + extLen,
|
|
6336
|
-
leftRulerYEnd
|
|
6337
|
-
],
|
|
6338
|
-
{
|
|
6339
|
-
stroke: lineColor,
|
|
6340
|
-
strokeWidth: 1,
|
|
6341
|
-
selectable: false,
|
|
6342
|
-
evented: false
|
|
6343
|
-
}
|
|
6344
|
-
)
|
|
6345
|
-
);
|
|
6346
|
-
const heightStr = formatMm(displayHeightMm, displayUnit);
|
|
6347
|
-
const leftTextContent = `${heightStr} ${displayUnit}`;
|
|
6348
|
-
const leftText = new import_fabric6.Text(leftTextContent, {
|
|
6349
|
-
left: leftRulerX,
|
|
6350
|
-
top: leftRulerYStart + (rulerBottom - rulerTop) / 2,
|
|
6351
|
-
angle: -90,
|
|
6352
|
-
fontSize,
|
|
6353
|
-
fill: textColor,
|
|
6354
|
-
fontFamily: "Arial",
|
|
6355
|
-
originX: "center",
|
|
6356
|
-
originY: "center",
|
|
6357
|
-
backgroundColor,
|
|
6358
|
-
selectable: false,
|
|
6359
|
-
evented: false
|
|
7204
|
+
if (!layout || layout.scale <= 0) {
|
|
7205
|
+
if (seq !== this.renderSeq) return;
|
|
7206
|
+
this.log("render:skip", { seq, reason: "invalid-layout" });
|
|
7207
|
+
this.specs = [];
|
|
7208
|
+
await this.canvasService.flushRenderFromProducers();
|
|
7209
|
+
return;
|
|
7210
|
+
}
|
|
7211
|
+
const geometry = buildSceneGeometry(configService, layout);
|
|
7212
|
+
if (geometry.unit !== "px") {
|
|
7213
|
+
console.warn("[RulerTool] Unexpected geometry unit.", geometry.unit);
|
|
7214
|
+
}
|
|
7215
|
+
const centerScene = this.canvasService.toScenePoint({
|
|
7216
|
+
x: geometry.x,
|
|
7217
|
+
y: geometry.y
|
|
6360
7218
|
});
|
|
6361
|
-
|
|
6362
|
-
this.canvasService.
|
|
6363
|
-
|
|
7219
|
+
const widthScene = this.canvasService.toSceneLength(geometry.width);
|
|
7220
|
+
const heightScene = this.canvasService.toSceneLength(geometry.height);
|
|
7221
|
+
const rulerLeft = centerScene.x - widthScene / 2;
|
|
7222
|
+
const rulerTop = centerScene.y - heightScene / 2;
|
|
7223
|
+
const rulerRight = rulerLeft + widthScene;
|
|
7224
|
+
const rulerBottom = rulerTop + heightScene;
|
|
7225
|
+
const widthMm = widthScene;
|
|
7226
|
+
const heightMm = heightScene;
|
|
7227
|
+
const unit = sizeState.unit;
|
|
7228
|
+
const widthLabel = `${this.formatLengthMm(widthMm, unit)} ${unit}`;
|
|
7229
|
+
const heightLabel = `${this.formatLengthMm(heightMm, unit)} ${unit}`;
|
|
7230
|
+
const specs = this.buildRulerSpecs({
|
|
7231
|
+
left: rulerLeft,
|
|
7232
|
+
top: rulerTop,
|
|
7233
|
+
right: rulerRight,
|
|
7234
|
+
bottom: rulerBottom,
|
|
7235
|
+
widthLabel,
|
|
7236
|
+
heightLabel
|
|
7237
|
+
});
|
|
7238
|
+
this.log("render:geometry", {
|
|
7239
|
+
seq,
|
|
7240
|
+
left: rulerLeft,
|
|
7241
|
+
top: rulerTop,
|
|
7242
|
+
right: rulerRight,
|
|
7243
|
+
bottom: rulerBottom,
|
|
7244
|
+
widthScene,
|
|
7245
|
+
heightScene,
|
|
7246
|
+
widthMm,
|
|
7247
|
+
heightMm,
|
|
7248
|
+
specCount: specs.length
|
|
7249
|
+
});
|
|
7250
|
+
if (seq !== this.renderSeq) return;
|
|
7251
|
+
this.specs = specs;
|
|
7252
|
+
await this.canvasService.flushRenderFromProducers();
|
|
7253
|
+
if (seq !== this.renderSeq) return;
|
|
7254
|
+
this.canvasService.bringLayerToFront(RULER_LAYER_ID);
|
|
7255
|
+
this.canvasService.requestRenderAll();
|
|
7256
|
+
this.log("render:done", { seq });
|
|
6364
7257
|
}
|
|
6365
7258
|
};
|
|
6366
7259
|
|
|
@@ -6397,6 +7290,9 @@ var WhiteInkTool = class {
|
|
|
6397
7290
|
this.printWithWhiteInk = true;
|
|
6398
7291
|
this.previewImageVisible = true;
|
|
6399
7292
|
this.renderSeq = 0;
|
|
7293
|
+
this.whiteSpecs = [];
|
|
7294
|
+
this.coverSpecs = [];
|
|
7295
|
+
this.overlaySpecs = [];
|
|
6400
7296
|
this.onToolActivated = (event) => {
|
|
6401
7297
|
const before = this.isToolActive;
|
|
6402
7298
|
this.syncToolActiveFromWorkbench(event.id);
|
|
@@ -6434,12 +7330,25 @@ var WhiteInkTool = class {
|
|
|
6434
7330
|
};
|
|
6435
7331
|
}
|
|
6436
7332
|
activate(context) {
|
|
7333
|
+
var _a;
|
|
6437
7334
|
this.context = context;
|
|
6438
7335
|
this.canvasService = context.services.get("CanvasService");
|
|
6439
7336
|
if (!this.canvasService) {
|
|
6440
7337
|
console.warn("CanvasService not found for WhiteInkTool");
|
|
6441
7338
|
return;
|
|
6442
7339
|
}
|
|
7340
|
+
(_a = this.renderProducerDisposable) == null ? void 0 : _a.dispose();
|
|
7341
|
+
this.renderProducerDisposable = this.canvasService.registerRenderProducer(
|
|
7342
|
+
this.id,
|
|
7343
|
+
() => ({
|
|
7344
|
+
rootLayerSpecs: {
|
|
7345
|
+
[WHITE_INK_OBJECT_LAYER_ID]: this.whiteSpecs,
|
|
7346
|
+
[WHITE_INK_COVER_LAYER_ID]: this.coverSpecs,
|
|
7347
|
+
[WHITE_INK_OVERLAY_LAYER_ID]: this.overlaySpecs
|
|
7348
|
+
}
|
|
7349
|
+
}),
|
|
7350
|
+
{ priority: 260 }
|
|
7351
|
+
);
|
|
6443
7352
|
context.eventBus.on("tool:activated", this.onToolActivated);
|
|
6444
7353
|
context.eventBus.on("scene:layout:change", this.onSceneLayoutChanged);
|
|
6445
7354
|
context.eventBus.on("object:added", this.onObjectAdded);
|
|
@@ -6505,7 +7414,7 @@ var WhiteInkTool = class {
|
|
|
6505
7414
|
this.updateWhiteInks();
|
|
6506
7415
|
}
|
|
6507
7416
|
deactivate(context) {
|
|
6508
|
-
var _a;
|
|
7417
|
+
var _a, _b;
|
|
6509
7418
|
context.eventBus.off("tool:activated", this.onToolActivated);
|
|
6510
7419
|
context.eventBus.off("scene:layout:change", this.onSceneLayoutChanged);
|
|
6511
7420
|
context.eventBus.off("object:added", this.onObjectAdded);
|
|
@@ -6516,6 +7425,11 @@ var WhiteInkTool = class {
|
|
|
6516
7425
|
this.dirtyTrackerDisposable = void 0;
|
|
6517
7426
|
this.clearRenderedWhiteInks();
|
|
6518
7427
|
this.applyImageVisibilityForWhiteInk(false);
|
|
7428
|
+
(_b = this.renderProducerDisposable) == null ? void 0 : _b.dispose();
|
|
7429
|
+
this.renderProducerDisposable = void 0;
|
|
7430
|
+
if (this.canvasService) {
|
|
7431
|
+
void this.canvasService.flushRenderFromProducers();
|
|
7432
|
+
}
|
|
6519
7433
|
this.canvasService = void 0;
|
|
6520
7434
|
this.context = void 0;
|
|
6521
7435
|
}
|
|
@@ -6938,11 +7852,20 @@ var WhiteInkTool = class {
|
|
|
6938
7852
|
if (!layout) {
|
|
6939
7853
|
return { left: 0, top: 0, width: 0, height: 0 };
|
|
6940
7854
|
}
|
|
6941
|
-
return {
|
|
7855
|
+
return this.canvasService.toSceneRect({
|
|
6942
7856
|
left: layout.cutRect.left,
|
|
6943
7857
|
top: layout.cutRect.top,
|
|
6944
7858
|
width: layout.cutRect.width,
|
|
6945
7859
|
height: layout.cutRect.height
|
|
7860
|
+
});
|
|
7861
|
+
}
|
|
7862
|
+
toLayoutSceneRect(rect) {
|
|
7863
|
+
return {
|
|
7864
|
+
left: rect.left,
|
|
7865
|
+
top: rect.top,
|
|
7866
|
+
width: rect.width,
|
|
7867
|
+
height: rect.height,
|
|
7868
|
+
space: "scene"
|
|
6946
7869
|
};
|
|
6947
7870
|
}
|
|
6948
7871
|
getImageObjects() {
|
|
@@ -6965,7 +7888,7 @@ var WhiteInkTool = class {
|
|
|
6965
7888
|
return (_a = obj == null ? void 0 : obj._originalElement) == null ? void 0 : _a.src;
|
|
6966
7889
|
}
|
|
6967
7890
|
getImageSnapshot(obj) {
|
|
6968
|
-
var _a;
|
|
7891
|
+
var _a, _b;
|
|
6969
7892
|
if (!obj) return null;
|
|
6970
7893
|
const src = this.getCurrentSrc(obj);
|
|
6971
7894
|
if (!src) return null;
|
|
@@ -6973,14 +7896,18 @@ var WhiteInkTool = class {
|
|
|
6973
7896
|
const width = Number((obj == null ? void 0 : obj.width) || 0);
|
|
6974
7897
|
const height = Number((obj == null ? void 0 : obj.height) || 0);
|
|
6975
7898
|
this.rememberSourceSize(src, { width, height });
|
|
7899
|
+
const sceneScale = ((_a = this.canvasService) == null ? void 0 : _a.getSceneScale()) || 1;
|
|
7900
|
+
const leftScreen = Number.isFinite(obj == null ? void 0 : obj.left) ? Number(obj.left) : 0;
|
|
7901
|
+
const topScreen = Number.isFinite(obj == null ? void 0 : obj.top) ? Number(obj.top) : 0;
|
|
7902
|
+
const scenePoint = this.canvasService ? this.canvasService.toScenePoint({ x: leftScreen, y: topScreen }) : { x: leftScreen, y: topScreen };
|
|
6976
7903
|
return {
|
|
6977
|
-
id: String(((
|
|
7904
|
+
id: String(((_b = obj == null ? void 0 : obj.data) == null ? void 0 : _b.id) || "image"),
|
|
6978
7905
|
src,
|
|
6979
7906
|
element,
|
|
6980
|
-
left:
|
|
6981
|
-
top:
|
|
6982
|
-
scaleX: Number.isFinite(obj == null ? void 0 : obj.scaleX) ? Number(obj.scaleX) : 1,
|
|
6983
|
-
scaleY: Number.isFinite(obj == null ? void 0 : obj.scaleY) ? Number(obj.scaleY) : 1,
|
|
7907
|
+
left: scenePoint.x,
|
|
7908
|
+
top: scenePoint.y,
|
|
7909
|
+
scaleX: (Number.isFinite(obj == null ? void 0 : obj.scaleX) ? Number(obj.scaleX) : 1) / sceneScale,
|
|
7910
|
+
scaleY: (Number.isFinite(obj == null ? void 0 : obj.scaleY) ? Number(obj.scaleY) : 1) / sceneScale,
|
|
6984
7911
|
angle: Number.isFinite(obj == null ? void 0 : obj.angle) ? Number(obj.angle) : 0,
|
|
6985
7912
|
originX: typeof (obj == null ? void 0 : obj.originX) === "string" ? obj.originX : "center",
|
|
6986
7913
|
originY: typeof (obj == null ? void 0 : obj.originY) === "string" ? obj.originY : "center",
|
|
@@ -7155,8 +8082,11 @@ var WhiteInkTool = class {
|
|
|
7155
8082
|
var _a, _b;
|
|
7156
8083
|
if (!this.isToolActive || !this.canvasService) return [];
|
|
7157
8084
|
if (frame.width <= 0 || frame.height <= 0) return [];
|
|
7158
|
-
const
|
|
7159
|
-
const
|
|
8085
|
+
const viewport = this.canvasService.getSceneViewportRect();
|
|
8086
|
+
const canvasW = viewport.width || 0;
|
|
8087
|
+
const canvasH = viewport.height || 0;
|
|
8088
|
+
const canvasLeft = viewport.left || 0;
|
|
8089
|
+
const canvasTop = viewport.top || 0;
|
|
7160
8090
|
const strokeColor = this.getConfig("image.frame.strokeColor", "#808080") || "#808080";
|
|
7161
8091
|
const strokeWidthRaw = Number(
|
|
7162
8092
|
(_a = this.getConfig("image.frame.strokeWidth", 2)) != null ? _a : 2
|
|
@@ -7168,21 +8098,42 @@ var WhiteInkTool = class {
|
|
|
7168
8098
|
const innerBackground = this.getConfig("image.frame.innerBackground", "rgba(0,0,0,0)") || "rgba(0,0,0,0)";
|
|
7169
8099
|
const strokeWidth = Number.isFinite(strokeWidthRaw) ? Math.max(0, strokeWidthRaw) : 2;
|
|
7170
8100
|
const dashLength = Number.isFinite(dashLengthRaw) ? Math.max(1, dashLengthRaw) : 8;
|
|
7171
|
-
const
|
|
7172
|
-
const
|
|
8101
|
+
const strokeWidthScene = this.canvasService.toSceneLength(strokeWidth);
|
|
8102
|
+
const dashLengthScene = this.canvasService.toSceneLength(dashLength);
|
|
8103
|
+
const frameLeft = Math.max(
|
|
8104
|
+
canvasLeft,
|
|
8105
|
+
Math.min(canvasLeft + canvasW, frame.left)
|
|
8106
|
+
);
|
|
8107
|
+
const frameTop = Math.max(
|
|
8108
|
+
canvasTop,
|
|
8109
|
+
Math.min(canvasTop + canvasH, frame.top)
|
|
8110
|
+
);
|
|
7173
8111
|
const frameRight = Math.max(
|
|
7174
8112
|
frameLeft,
|
|
7175
|
-
Math.min(canvasW, frame.left + frame.width)
|
|
8113
|
+
Math.min(canvasLeft + canvasW, frame.left + frame.width)
|
|
7176
8114
|
);
|
|
7177
8115
|
const frameBottom = Math.max(
|
|
7178
8116
|
frameTop,
|
|
7179
|
-
Math.min(canvasH, frame.top + frame.height)
|
|
8117
|
+
Math.min(canvasTop + canvasH, frame.top + frame.height)
|
|
7180
8118
|
);
|
|
7181
8119
|
const visibleFrameH = Math.max(0, frameBottom - frameTop);
|
|
7182
|
-
const topH = frameTop;
|
|
7183
|
-
const bottomH = Math.max(0, canvasH - frameBottom);
|
|
7184
|
-
const leftW = frameLeft;
|
|
7185
|
-
const rightW = Math.max(0, canvasW - frameRight);
|
|
8120
|
+
const topH = Math.max(0, frameTop - canvasTop);
|
|
8121
|
+
const bottomH = Math.max(0, canvasTop + canvasH - frameBottom);
|
|
8122
|
+
const leftW = Math.max(0, frameLeft - canvasLeft);
|
|
8123
|
+
const rightW = Math.max(0, canvasLeft + canvasW - frameRight);
|
|
8124
|
+
const viewportRect = this.toLayoutSceneRect({
|
|
8125
|
+
left: canvasLeft,
|
|
8126
|
+
top: canvasTop,
|
|
8127
|
+
width: canvasW,
|
|
8128
|
+
height: canvasH
|
|
8129
|
+
});
|
|
8130
|
+
const visibleFrameBandRect = this.toLayoutSceneRect({
|
|
8131
|
+
left: canvasLeft,
|
|
8132
|
+
top: frameTop,
|
|
8133
|
+
width: canvasW,
|
|
8134
|
+
height: visibleFrameH
|
|
8135
|
+
});
|
|
8136
|
+
const frameRect = this.toLayoutSceneRect(frame);
|
|
7186
8137
|
const maskSpecs = [
|
|
7187
8138
|
{
|
|
7188
8139
|
id: "white-ink.cropMask.top",
|
|
@@ -7192,13 +8143,17 @@ var WhiteInkTool = class {
|
|
|
7192
8143
|
layerId: WHITE_INK_OVERLAY_LAYER_ID,
|
|
7193
8144
|
type: "white-ink-mask"
|
|
7194
8145
|
},
|
|
8146
|
+
layout: {
|
|
8147
|
+
reference: "custom",
|
|
8148
|
+
referenceRect: viewportRect,
|
|
8149
|
+
alignX: "start",
|
|
8150
|
+
alignY: "start",
|
|
8151
|
+
width: "100%",
|
|
8152
|
+
height: topH
|
|
8153
|
+
},
|
|
7195
8154
|
props: {
|
|
7196
|
-
|
|
7197
|
-
|
|
7198
|
-
width: canvasW,
|
|
7199
|
-
height: topH,
|
|
7200
|
-
originX: "center",
|
|
7201
|
-
originY: "center",
|
|
8155
|
+
originX: "left",
|
|
8156
|
+
originY: "top",
|
|
7202
8157
|
fill: outerBackground,
|
|
7203
8158
|
selectable: false,
|
|
7204
8159
|
evented: false,
|
|
@@ -7213,13 +8168,17 @@ var WhiteInkTool = class {
|
|
|
7213
8168
|
layerId: WHITE_INK_OVERLAY_LAYER_ID,
|
|
7214
8169
|
type: "white-ink-mask"
|
|
7215
8170
|
},
|
|
8171
|
+
layout: {
|
|
8172
|
+
reference: "custom",
|
|
8173
|
+
referenceRect: viewportRect,
|
|
8174
|
+
alignX: "start",
|
|
8175
|
+
alignY: "end",
|
|
8176
|
+
width: "100%",
|
|
8177
|
+
height: bottomH
|
|
8178
|
+
},
|
|
7216
8179
|
props: {
|
|
7217
|
-
|
|
7218
|
-
|
|
7219
|
-
width: canvasW,
|
|
7220
|
-
height: bottomH,
|
|
7221
|
-
originX: "center",
|
|
7222
|
-
originY: "center",
|
|
8180
|
+
originX: "left",
|
|
8181
|
+
originY: "top",
|
|
7223
8182
|
fill: outerBackground,
|
|
7224
8183
|
selectable: false,
|
|
7225
8184
|
evented: false,
|
|
@@ -7234,13 +8193,17 @@ var WhiteInkTool = class {
|
|
|
7234
8193
|
layerId: WHITE_INK_OVERLAY_LAYER_ID,
|
|
7235
8194
|
type: "white-ink-mask"
|
|
7236
8195
|
},
|
|
7237
|
-
|
|
7238
|
-
|
|
7239
|
-
|
|
8196
|
+
layout: {
|
|
8197
|
+
reference: "custom",
|
|
8198
|
+
referenceRect: visibleFrameBandRect,
|
|
8199
|
+
alignX: "start",
|
|
8200
|
+
alignY: "start",
|
|
7240
8201
|
width: leftW,
|
|
7241
|
-
height:
|
|
7242
|
-
|
|
7243
|
-
|
|
8202
|
+
height: "100%"
|
|
8203
|
+
},
|
|
8204
|
+
props: {
|
|
8205
|
+
originX: "left",
|
|
8206
|
+
originY: "top",
|
|
7244
8207
|
fill: outerBackground,
|
|
7245
8208
|
selectable: false,
|
|
7246
8209
|
evented: false,
|
|
@@ -7255,13 +8218,17 @@ var WhiteInkTool = class {
|
|
|
7255
8218
|
layerId: WHITE_INK_OVERLAY_LAYER_ID,
|
|
7256
8219
|
type: "white-ink-mask"
|
|
7257
8220
|
},
|
|
7258
|
-
|
|
7259
|
-
|
|
7260
|
-
|
|
8221
|
+
layout: {
|
|
8222
|
+
reference: "custom",
|
|
8223
|
+
referenceRect: visibleFrameBandRect,
|
|
8224
|
+
alignX: "end",
|
|
8225
|
+
alignY: "start",
|
|
7261
8226
|
width: rightW,
|
|
7262
|
-
height:
|
|
7263
|
-
|
|
7264
|
-
|
|
8227
|
+
height: "100%"
|
|
8228
|
+
},
|
|
8229
|
+
props: {
|
|
8230
|
+
originX: "left",
|
|
8231
|
+
originY: "top",
|
|
7265
8232
|
fill: outerBackground,
|
|
7266
8233
|
selectable: false,
|
|
7267
8234
|
evented: false,
|
|
@@ -7279,17 +8246,21 @@ var WhiteInkTool = class {
|
|
|
7279
8246
|
layerId: WHITE_INK_OVERLAY_LAYER_ID,
|
|
7280
8247
|
type: "white-ink-frame"
|
|
7281
8248
|
},
|
|
8249
|
+
layout: {
|
|
8250
|
+
reference: "custom",
|
|
8251
|
+
referenceRect: frameRect,
|
|
8252
|
+
alignX: "start",
|
|
8253
|
+
alignY: "start",
|
|
8254
|
+
width: "100%",
|
|
8255
|
+
height: "100%"
|
|
8256
|
+
},
|
|
7282
8257
|
props: {
|
|
7283
|
-
|
|
7284
|
-
|
|
7285
|
-
width: frame.width,
|
|
7286
|
-
height: frame.height,
|
|
7287
|
-
originX: "center",
|
|
7288
|
-
originY: "center",
|
|
8258
|
+
originX: "left",
|
|
8259
|
+
originY: "top",
|
|
7289
8260
|
fill: innerBackground,
|
|
7290
8261
|
stroke: strokeColor,
|
|
7291
|
-
strokeWidth,
|
|
7292
|
-
strokeDashArray: [
|
|
8262
|
+
strokeWidth: strokeWidthScene,
|
|
8263
|
+
strokeDashArray: [dashLengthScene, dashLengthScene],
|
|
7293
8264
|
selectable: false,
|
|
7294
8265
|
evented: false,
|
|
7295
8266
|
excludeFromExport: true
|
|
@@ -7365,50 +8336,30 @@ var WhiteInkTool = class {
|
|
|
7365
8336
|
}
|
|
7366
8337
|
).filter((index) => index >= 0);
|
|
7367
8338
|
let whiteInsertIndex = imageIndexes.length ? Math.min(...imageIndexes) : this.resolveDefaultInsertIndex(currentObjects);
|
|
7368
|
-
|
|
7369
|
-
canvas.moveObjectTo(obj, whiteInsertIndex);
|
|
7370
|
-
whiteInsertIndex += 1;
|
|
7371
|
-
});
|
|
7372
|
-
const afterWhiteObjects = canvas.getObjects();
|
|
7373
|
-
const afterImageIndexes = afterWhiteObjects.map(
|
|
7374
|
-
(obj, index) => {
|
|
7375
|
-
var _a;
|
|
7376
|
-
return ((_a = obj == null ? void 0 : obj.data) == null ? void 0 : _a.layerId) === IMAGE_OBJECT_LAYER_ID3 ? index : -1;
|
|
7377
|
-
}
|
|
7378
|
-
).filter((index) => index >= 0);
|
|
7379
|
-
let coverInsertIndex = afterImageIndexes.length ? Math.max(...afterImageIndexes) + 1 : whiteInsertIndex;
|
|
8339
|
+
let coverInsertIndex = whiteInsertIndex;
|
|
7380
8340
|
coverObjects.forEach((obj) => {
|
|
7381
8341
|
canvas.moveObjectTo(obj, coverInsertIndex);
|
|
7382
8342
|
coverInsertIndex += 1;
|
|
7383
8343
|
});
|
|
8344
|
+
whiteInsertIndex = coverInsertIndex;
|
|
8345
|
+
whiteObjects.forEach((obj) => {
|
|
8346
|
+
canvas.moveObjectTo(obj, whiteInsertIndex);
|
|
8347
|
+
whiteInsertIndex += 1;
|
|
8348
|
+
});
|
|
7384
8349
|
frameObjects.forEach((obj) => canvas.bringObjectToFront(obj));
|
|
7385
8350
|
canvas.getObjects().filter((obj) => {
|
|
7386
8351
|
var _a;
|
|
7387
8352
|
return ((_a = obj == null ? void 0 : obj.data) == null ? void 0 : _a.layerId) === IMAGE_OVERLAY_LAYER_ID2;
|
|
7388
8353
|
}).forEach((obj) => canvas.bringObjectToFront(obj));
|
|
7389
|
-
|
|
7390
|
-
|
|
7391
|
-
canvas.bringObjectToFront(dielineOverlay);
|
|
7392
|
-
}
|
|
7393
|
-
const rulerOverlay = this.canvasService.getLayer("ruler-overlay");
|
|
7394
|
-
if (rulerOverlay) {
|
|
7395
|
-
canvas.bringObjectToFront(rulerOverlay);
|
|
7396
|
-
}
|
|
8354
|
+
this.canvasService.bringLayerToFront("dieline-overlay");
|
|
8355
|
+
this.canvasService.bringLayerToFront("ruler-overlay");
|
|
7397
8356
|
}
|
|
7398
8357
|
clearRenderedWhiteInks() {
|
|
7399
8358
|
if (!this.canvasService) return;
|
|
7400
|
-
|
|
7401
|
-
|
|
7402
|
-
|
|
7403
|
-
);
|
|
7404
|
-
void this.canvasService.applyObjectSpecsToRootLayer(
|
|
7405
|
-
WHITE_INK_COVER_LAYER_ID,
|
|
7406
|
-
[]
|
|
7407
|
-
);
|
|
7408
|
-
void this.canvasService.applyObjectSpecsToRootLayer(
|
|
7409
|
-
WHITE_INK_OVERLAY_LAYER_ID,
|
|
7410
|
-
[]
|
|
7411
|
-
);
|
|
8359
|
+
this.whiteSpecs = [];
|
|
8360
|
+
this.coverSpecs = [];
|
|
8361
|
+
this.overlaySpecs = [];
|
|
8362
|
+
this.canvasService.requestRenderFromProducers();
|
|
7412
8363
|
}
|
|
7413
8364
|
purgeSourceCaches(item) {
|
|
7414
8365
|
const sourceUrl = this.resolveSourceUrl(item);
|
|
@@ -7475,20 +8426,12 @@ var WhiteInkTool = class {
|
|
|
7475
8426
|
}
|
|
7476
8427
|
}
|
|
7477
8428
|
}
|
|
7478
|
-
|
|
7479
|
-
WHITE_INK_OBJECT_LAYER_ID,
|
|
7480
|
-
whiteSpecs
|
|
7481
|
-
);
|
|
8429
|
+
this.whiteSpecs = whiteSpecs;
|
|
7482
8430
|
if (seq !== this.renderSeq) return;
|
|
7483
|
-
|
|
7484
|
-
WHITE_INK_COVER_LAYER_ID,
|
|
7485
|
-
coverSpecs
|
|
7486
|
-
);
|
|
8431
|
+
this.coverSpecs = coverSpecs;
|
|
7487
8432
|
if (seq !== this.renderSeq) return;
|
|
7488
|
-
|
|
7489
|
-
|
|
7490
|
-
frameSpecs
|
|
7491
|
-
);
|
|
8433
|
+
this.overlaySpecs = frameSpecs;
|
|
8434
|
+
await this.canvasService.flushRenderFromProducers();
|
|
7492
8435
|
if (seq !== this.renderSeq) return;
|
|
7493
8436
|
this.syncZOrder();
|
|
7494
8437
|
this.canvasService.requestRenderAll();
|
|
@@ -7718,23 +8661,16 @@ var SceneVisibilityService = class {
|
|
|
7718
8661
|
const dielineLayer = this.canvasService.getLayer("dieline-overlay");
|
|
7719
8662
|
if (dielineLayer) {
|
|
7720
8663
|
const visible = !HIDDEN_DIELINE_TOOLS.has(this.activeToolId || "");
|
|
7721
|
-
|
|
7722
|
-
dielineLayer.set({ visible });
|
|
7723
|
-
}
|
|
7724
|
-
}
|
|
7725
|
-
const rulerLayer = this.canvasService.getLayer("ruler-overlay");
|
|
7726
|
-
if (rulerLayer) {
|
|
7727
|
-
const visible = !HIDDEN_RULER_TOOLS.has(this.activeToolId || "");
|
|
7728
|
-
if (rulerLayer.visible !== visible) {
|
|
7729
|
-
rulerLayer.set({ visible });
|
|
7730
|
-
}
|
|
8664
|
+
this.canvasService.setLayerVisibility("dieline-overlay", visible);
|
|
7731
8665
|
}
|
|
8666
|
+
const rulerVisible = !HIDDEN_RULER_TOOLS.has(this.activeToolId || "");
|
|
8667
|
+
this.canvasService.setLayerVisibility("ruler-overlay", rulerVisible);
|
|
7732
8668
|
this.canvasService.requestRenderAll();
|
|
7733
8669
|
}
|
|
7734
8670
|
};
|
|
7735
8671
|
|
|
7736
8672
|
// src/services/CanvasService.ts
|
|
7737
|
-
var
|
|
8673
|
+
var import_fabric5 = require("fabric");
|
|
7738
8674
|
|
|
7739
8675
|
// src/services/ViewportSystem.ts
|
|
7740
8676
|
var ViewportSystem = class {
|
|
@@ -7812,10 +8748,17 @@ var ViewportSystem = class {
|
|
|
7812
8748
|
// src/services/CanvasService.ts
|
|
7813
8749
|
var CanvasService = class {
|
|
7814
8750
|
constructor(el, options) {
|
|
7815
|
-
|
|
8751
|
+
this.renderProducers = /* @__PURE__ */ new Map();
|
|
8752
|
+
this.producerOrder = 0;
|
|
8753
|
+
this.producerFlushRequested = false;
|
|
8754
|
+
this.producerLoopPending = false;
|
|
8755
|
+
this.producerLoopPromise = null;
|
|
8756
|
+
this.managedProducerLayerIds = /* @__PURE__ */ new Set();
|
|
8757
|
+
this.managedProducerRootLayerIds = /* @__PURE__ */ new Set();
|
|
8758
|
+
if (el instanceof import_fabric5.Canvas) {
|
|
7816
8759
|
this.canvas = el;
|
|
7817
8760
|
} else {
|
|
7818
|
-
this.canvas = new
|
|
8761
|
+
this.canvas = new import_fabric5.Canvas(el, {
|
|
7819
8762
|
preserveObjectStacking: true,
|
|
7820
8763
|
...options
|
|
7821
8764
|
});
|
|
@@ -7844,8 +8787,156 @@ var CanvasService = class {
|
|
|
7844
8787
|
this.canvas.on("object:removed", forward("object:removed"));
|
|
7845
8788
|
}
|
|
7846
8789
|
dispose() {
|
|
8790
|
+
this.renderProducers.clear();
|
|
8791
|
+
this.managedProducerLayerIds.clear();
|
|
8792
|
+
this.managedProducerRootLayerIds.clear();
|
|
8793
|
+
this.producerFlushRequested = false;
|
|
7847
8794
|
this.canvas.dispose();
|
|
7848
8795
|
}
|
|
8796
|
+
registerRenderProducer(toolId, producer, options = {}) {
|
|
8797
|
+
const normalizedToolId = String(toolId || "").trim();
|
|
8798
|
+
if (!normalizedToolId) {
|
|
8799
|
+
throw new Error(
|
|
8800
|
+
"[CanvasService] registerRenderProducer requires a toolId."
|
|
8801
|
+
);
|
|
8802
|
+
}
|
|
8803
|
+
if (typeof producer !== "function") {
|
|
8804
|
+
throw new Error(
|
|
8805
|
+
`[CanvasService] registerRenderProducer("${normalizedToolId}") requires a producer function.`
|
|
8806
|
+
);
|
|
8807
|
+
}
|
|
8808
|
+
const entry = {
|
|
8809
|
+
toolId: normalizedToolId,
|
|
8810
|
+
producer,
|
|
8811
|
+
priority: Number.isFinite(options.priority) ? Number(options.priority) : 0,
|
|
8812
|
+
order: this.producerOrder++
|
|
8813
|
+
};
|
|
8814
|
+
this.renderProducers.set(normalizedToolId, entry);
|
|
8815
|
+
this.requestRenderFromProducers();
|
|
8816
|
+
return {
|
|
8817
|
+
dispose: () => {
|
|
8818
|
+
this.unregisterRenderProducer(normalizedToolId);
|
|
8819
|
+
}
|
|
8820
|
+
};
|
|
8821
|
+
}
|
|
8822
|
+
unregisterRenderProducer(toolId) {
|
|
8823
|
+
const normalizedToolId = String(toolId || "").trim();
|
|
8824
|
+
if (!normalizedToolId) return false;
|
|
8825
|
+
const removed = this.renderProducers.delete(normalizedToolId);
|
|
8826
|
+
if (removed) {
|
|
8827
|
+
this.requestRenderFromProducers();
|
|
8828
|
+
}
|
|
8829
|
+
return removed;
|
|
8830
|
+
}
|
|
8831
|
+
requestRenderFromProducers() {
|
|
8832
|
+
this.producerFlushRequested = true;
|
|
8833
|
+
this.scheduleProducerLoop();
|
|
8834
|
+
}
|
|
8835
|
+
async flushRenderFromProducers() {
|
|
8836
|
+
this.requestRenderFromProducers();
|
|
8837
|
+
if (this.producerLoopPromise) {
|
|
8838
|
+
await this.producerLoopPromise;
|
|
8839
|
+
}
|
|
8840
|
+
}
|
|
8841
|
+
scheduleProducerLoop() {
|
|
8842
|
+
if (this.producerLoopPending) return;
|
|
8843
|
+
this.producerLoopPending = true;
|
|
8844
|
+
this.producerLoopPromise = Promise.resolve().then(() => this.runProducerLoop()).catch((error) => {
|
|
8845
|
+
console.error("[CanvasService] render producer loop failed.", error);
|
|
8846
|
+
}).finally(() => {
|
|
8847
|
+
this.producerLoopPending = false;
|
|
8848
|
+
if (this.producerFlushRequested) {
|
|
8849
|
+
this.scheduleProducerLoop();
|
|
8850
|
+
}
|
|
8851
|
+
});
|
|
8852
|
+
}
|
|
8853
|
+
async runProducerLoop() {
|
|
8854
|
+
while (this.producerFlushRequested) {
|
|
8855
|
+
this.producerFlushRequested = false;
|
|
8856
|
+
await this.collectAndApplyProducerSpecs();
|
|
8857
|
+
}
|
|
8858
|
+
}
|
|
8859
|
+
sortedRenderProducerEntries() {
|
|
8860
|
+
return Array.from(this.renderProducers.values()).sort((a, b) => {
|
|
8861
|
+
if (a.priority !== b.priority) {
|
|
8862
|
+
return a.priority - b.priority;
|
|
8863
|
+
}
|
|
8864
|
+
if (a.order !== b.order) {
|
|
8865
|
+
return a.order - b.order;
|
|
8866
|
+
}
|
|
8867
|
+
return a.toolId.localeCompare(b.toolId);
|
|
8868
|
+
});
|
|
8869
|
+
}
|
|
8870
|
+
appendLayerSpecMap(map, source) {
|
|
8871
|
+
if (!source) return;
|
|
8872
|
+
Object.entries(source).forEach(([layerId, specs]) => {
|
|
8873
|
+
if (!Array.isArray(specs)) return;
|
|
8874
|
+
const list = map.get(layerId) || [];
|
|
8875
|
+
list.push(...specs);
|
|
8876
|
+
map.set(layerId, list);
|
|
8877
|
+
});
|
|
8878
|
+
}
|
|
8879
|
+
async collectAndApplyProducerSpecs() {
|
|
8880
|
+
const groupLayerSpecs = /* @__PURE__ */ new Map();
|
|
8881
|
+
const rootLayerSpecs = /* @__PURE__ */ new Map();
|
|
8882
|
+
const replaceLayerIds = /* @__PURE__ */ new Set();
|
|
8883
|
+
const replaceRootLayerIds = /* @__PURE__ */ new Set();
|
|
8884
|
+
const entries = this.sortedRenderProducerEntries();
|
|
8885
|
+
for (const entry of entries) {
|
|
8886
|
+
try {
|
|
8887
|
+
const result = await entry.producer();
|
|
8888
|
+
if (!result) continue;
|
|
8889
|
+
this.appendLayerSpecMap(groupLayerSpecs, result.layerSpecs);
|
|
8890
|
+
this.appendLayerSpecMap(rootLayerSpecs, result.rootLayerSpecs);
|
|
8891
|
+
if (Array.isArray(result.replaceLayerIds)) {
|
|
8892
|
+
result.replaceLayerIds.forEach((layerId) => {
|
|
8893
|
+
if (layerId) replaceLayerIds.add(layerId);
|
|
8894
|
+
});
|
|
8895
|
+
}
|
|
8896
|
+
if (Array.isArray(result.replaceRootLayerIds)) {
|
|
8897
|
+
result.replaceRootLayerIds.forEach((layerId) => {
|
|
8898
|
+
if (layerId) replaceRootLayerIds.add(layerId);
|
|
8899
|
+
});
|
|
8900
|
+
}
|
|
8901
|
+
} catch (error) {
|
|
8902
|
+
console.error(
|
|
8903
|
+
`[CanvasService] render producer "${entry.toolId}" failed.`,
|
|
8904
|
+
error
|
|
8905
|
+
);
|
|
8906
|
+
}
|
|
8907
|
+
}
|
|
8908
|
+
const nextLayerIds = new Set(groupLayerSpecs.keys());
|
|
8909
|
+
const nextRootLayerIds = new Set(rootLayerSpecs.keys());
|
|
8910
|
+
for (const [layerId, specs] of groupLayerSpecs.entries()) {
|
|
8911
|
+
if (replaceLayerIds.has(layerId)) {
|
|
8912
|
+
const layer = this.getLayer(layerId);
|
|
8913
|
+
if (layer) {
|
|
8914
|
+
layer.getObjects().forEach((obj) => layer.remove(obj));
|
|
8915
|
+
}
|
|
8916
|
+
}
|
|
8917
|
+
await this.applyObjectSpecsToLayer(layerId, specs, { render: false });
|
|
8918
|
+
}
|
|
8919
|
+
for (const layerId of this.managedProducerLayerIds) {
|
|
8920
|
+
if (nextLayerIds.has(layerId)) continue;
|
|
8921
|
+
const layer = this.getLayer(layerId);
|
|
8922
|
+
if (!layer) continue;
|
|
8923
|
+
await this.applyObjectSpecsToContainer(layer, [], { render: false });
|
|
8924
|
+
}
|
|
8925
|
+
for (const [layerId, specs] of rootLayerSpecs.entries()) {
|
|
8926
|
+
if (replaceRootLayerIds.has(layerId)) {
|
|
8927
|
+
const existing = this.getRootLayerObjects(layerId);
|
|
8928
|
+
existing.forEach((obj) => this.canvas.remove(obj));
|
|
8929
|
+
}
|
|
8930
|
+
await this.applyObjectSpecsToRootLayer(layerId, specs, { render: false });
|
|
8931
|
+
}
|
|
8932
|
+
for (const layerId of this.managedProducerRootLayerIds) {
|
|
8933
|
+
if (nextRootLayerIds.has(layerId)) continue;
|
|
8934
|
+
await this.applyObjectSpecsToRootLayer(layerId, [], { render: false });
|
|
8935
|
+
}
|
|
8936
|
+
this.managedProducerLayerIds = nextLayerIds;
|
|
8937
|
+
this.managedProducerRootLayerIds = nextRootLayerIds;
|
|
8938
|
+
this.requestRenderAll();
|
|
8939
|
+
}
|
|
7849
8940
|
/**
|
|
7850
8941
|
* Get a layer (Group) by its ID.
|
|
7851
8942
|
* We assume layers are Groups directly on the canvas with a data.id property.
|
|
@@ -7868,7 +8959,7 @@ var CanvasService = class {
|
|
|
7868
8959
|
...options,
|
|
7869
8960
|
data: { ...options.data, id }
|
|
7870
8961
|
};
|
|
7871
|
-
layer = new
|
|
8962
|
+
layer = new import_fabric5.Group([], defaultOptions);
|
|
7872
8963
|
this.canvas.add(layer);
|
|
7873
8964
|
}
|
|
7874
8965
|
return layer;
|
|
@@ -7900,13 +8991,206 @@ var CanvasService = class {
|
|
|
7900
8991
|
(_a = this.eventBus) == null ? void 0 : _a.emit("canvas:resized", { width, height });
|
|
7901
8992
|
this.requestRenderAll();
|
|
7902
8993
|
}
|
|
8994
|
+
getSceneScale() {
|
|
8995
|
+
const scale = Number(this.viewport.scale);
|
|
8996
|
+
return Number.isFinite(scale) && scale > 0 ? scale : 1;
|
|
8997
|
+
}
|
|
8998
|
+
getSceneOffset() {
|
|
8999
|
+
const offset = this.viewport.offset;
|
|
9000
|
+
const x = Number(offset.x);
|
|
9001
|
+
const y = Number(offset.y);
|
|
9002
|
+
return {
|
|
9003
|
+
x: Number.isFinite(x) ? x : 0,
|
|
9004
|
+
y: Number.isFinite(y) ? y : 0
|
|
9005
|
+
};
|
|
9006
|
+
}
|
|
9007
|
+
toScreenPoint(point) {
|
|
9008
|
+
const scale = this.getSceneScale();
|
|
9009
|
+
const offset = this.getSceneOffset();
|
|
9010
|
+
return {
|
|
9011
|
+
x: point.x * scale + offset.x,
|
|
9012
|
+
y: point.y * scale + offset.y
|
|
9013
|
+
};
|
|
9014
|
+
}
|
|
9015
|
+
toScenePoint(point) {
|
|
9016
|
+
const scale = this.getSceneScale();
|
|
9017
|
+
const offset = this.getSceneOffset();
|
|
9018
|
+
return {
|
|
9019
|
+
x: (point.x - offset.x) / scale,
|
|
9020
|
+
y: (point.y - offset.y) / scale
|
|
9021
|
+
};
|
|
9022
|
+
}
|
|
9023
|
+
toScreenLength(value) {
|
|
9024
|
+
return value * this.getSceneScale();
|
|
9025
|
+
}
|
|
9026
|
+
toSceneLength(value) {
|
|
9027
|
+
return value / this.getSceneScale();
|
|
9028
|
+
}
|
|
9029
|
+
toScreenRect(rect) {
|
|
9030
|
+
const start = this.toScreenPoint({ x: rect.left, y: rect.top });
|
|
9031
|
+
return {
|
|
9032
|
+
left: start.x,
|
|
9033
|
+
top: start.y,
|
|
9034
|
+
width: this.toScreenLength(rect.width),
|
|
9035
|
+
height: this.toScreenLength(rect.height)
|
|
9036
|
+
};
|
|
9037
|
+
}
|
|
9038
|
+
toSceneRect(rect) {
|
|
9039
|
+
const start = this.toScenePoint({ x: rect.left, y: rect.top });
|
|
9040
|
+
return {
|
|
9041
|
+
left: start.x,
|
|
9042
|
+
top: start.y,
|
|
9043
|
+
width: this.toSceneLength(rect.width),
|
|
9044
|
+
height: this.toSceneLength(rect.height)
|
|
9045
|
+
};
|
|
9046
|
+
}
|
|
9047
|
+
getSceneViewportRect() {
|
|
9048
|
+
const width = Number(this.canvas.width || 0);
|
|
9049
|
+
const height = Number(this.canvas.height || 0);
|
|
9050
|
+
return this.toSceneRect({ left: 0, top: 0, width, height });
|
|
9051
|
+
}
|
|
9052
|
+
getScreenViewportRect() {
|
|
9053
|
+
return {
|
|
9054
|
+
left: 0,
|
|
9055
|
+
top: 0,
|
|
9056
|
+
width: Number(this.canvas.width || 0),
|
|
9057
|
+
height: Number(this.canvas.height || 0)
|
|
9058
|
+
};
|
|
9059
|
+
}
|
|
9060
|
+
toSpaceRect(rect, from, to) {
|
|
9061
|
+
if (from === to) return { ...rect };
|
|
9062
|
+
if (from === "scene") {
|
|
9063
|
+
return this.toScreenRect(rect);
|
|
9064
|
+
}
|
|
9065
|
+
return this.toSceneRect(rect);
|
|
9066
|
+
}
|
|
9067
|
+
resolveLayoutLength(value, base) {
|
|
9068
|
+
if (typeof value === "number") {
|
|
9069
|
+
return Number.isFinite(value) ? value : void 0;
|
|
9070
|
+
}
|
|
9071
|
+
if (typeof value !== "string") {
|
|
9072
|
+
return void 0;
|
|
9073
|
+
}
|
|
9074
|
+
const raw = value.trim();
|
|
9075
|
+
if (!raw) return void 0;
|
|
9076
|
+
if (raw.endsWith("%")) {
|
|
9077
|
+
const percent = parseFloat(raw.slice(0, -1));
|
|
9078
|
+
if (!Number.isFinite(percent)) return void 0;
|
|
9079
|
+
return base * percent / 100;
|
|
9080
|
+
}
|
|
9081
|
+
const parsed = parseFloat(raw);
|
|
9082
|
+
return Number.isFinite(parsed) ? parsed : void 0;
|
|
9083
|
+
}
|
|
9084
|
+
resolveLayoutInsets(inset, reference) {
|
|
9085
|
+
var _a, _b, _c, _d, _e;
|
|
9086
|
+
if (typeof inset === "number" || typeof inset === "string") {
|
|
9087
|
+
const all = (_a = this.resolveLayoutLength(
|
|
9088
|
+
inset,
|
|
9089
|
+
Math.min(reference.width, reference.height)
|
|
9090
|
+
)) != null ? _a : 0;
|
|
9091
|
+
return { top: all, right: all, bottom: all, left: all };
|
|
9092
|
+
}
|
|
9093
|
+
const source = inset || {};
|
|
9094
|
+
const top = (_b = this.resolveLayoutLength(source.top, reference.height)) != null ? _b : 0;
|
|
9095
|
+
const right = (_c = this.resolveLayoutLength(source.right, reference.width)) != null ? _c : 0;
|
|
9096
|
+
const bottom = (_d = this.resolveLayoutLength(source.bottom, reference.height)) != null ? _d : 0;
|
|
9097
|
+
const left = (_e = this.resolveLayoutLength(source.left, reference.width)) != null ? _e : 0;
|
|
9098
|
+
return { top, right, bottom, left };
|
|
9099
|
+
}
|
|
9100
|
+
resolveLayoutReferenceRect(layout, space) {
|
|
9101
|
+
if (layout.referenceRect) {
|
|
9102
|
+
const sourceSpace = layout.referenceRect.space || space;
|
|
9103
|
+
return this.toSpaceRect(layout.referenceRect, sourceSpace, space);
|
|
9104
|
+
}
|
|
9105
|
+
const reference = layout.reference || "sceneViewport";
|
|
9106
|
+
if (reference === "screenViewport") {
|
|
9107
|
+
const screenRect = this.getScreenViewportRect();
|
|
9108
|
+
return space === "screen" ? screenRect : this.toSceneRect(screenRect);
|
|
9109
|
+
}
|
|
9110
|
+
const sceneRect = this.getSceneViewportRect();
|
|
9111
|
+
return space === "scene" ? sceneRect : this.toScreenRect(sceneRect);
|
|
9112
|
+
}
|
|
9113
|
+
alignFactor(value) {
|
|
9114
|
+
if (value === "end") return 1;
|
|
9115
|
+
if (value === "center") return 0.5;
|
|
9116
|
+
return 0;
|
|
9117
|
+
}
|
|
9118
|
+
normalizeOriginX(value) {
|
|
9119
|
+
if (value === "center") return "center";
|
|
9120
|
+
if (value === "right") return "right";
|
|
9121
|
+
return "left";
|
|
9122
|
+
}
|
|
9123
|
+
normalizeOriginY(value) {
|
|
9124
|
+
if (value === "center") return "center";
|
|
9125
|
+
if (value === "bottom") return "bottom";
|
|
9126
|
+
return "top";
|
|
9127
|
+
}
|
|
9128
|
+
originFactor(value) {
|
|
9129
|
+
if (value === "center") return 0.5;
|
|
9130
|
+
if (value === "right" || value === "bottom") return 1;
|
|
9131
|
+
return 0;
|
|
9132
|
+
}
|
|
9133
|
+
resolveLayoutProps(spec, props) {
|
|
9134
|
+
var _a, _b, _c, _d;
|
|
9135
|
+
const layout = spec.layout;
|
|
9136
|
+
if (!layout) {
|
|
9137
|
+
return { ...props };
|
|
9138
|
+
}
|
|
9139
|
+
const space = spec.space || "scene";
|
|
9140
|
+
const reference = this.resolveLayoutReferenceRect(layout, space);
|
|
9141
|
+
const inset = this.resolveLayoutInsets(layout.inset, reference);
|
|
9142
|
+
const area = {
|
|
9143
|
+
left: reference.left + inset.left,
|
|
9144
|
+
top: reference.top + inset.top,
|
|
9145
|
+
width: Math.max(0, reference.width - inset.left - inset.right),
|
|
9146
|
+
height: Math.max(0, reference.height - inset.top - inset.bottom)
|
|
9147
|
+
};
|
|
9148
|
+
const next = { ...props };
|
|
9149
|
+
const width = (_a = this.resolveLayoutLength(layout.width, area.width)) != null ? _a : Number.isFinite(next.width) ? Number(next.width) : void 0;
|
|
9150
|
+
const height = (_b = this.resolveLayoutLength(layout.height, area.height)) != null ? _b : Number.isFinite(next.height) ? Number(next.height) : void 0;
|
|
9151
|
+
if (width !== void 0) next.width = width;
|
|
9152
|
+
if (height !== void 0) next.height = height;
|
|
9153
|
+
const alignX = this.alignFactor(layout.alignX);
|
|
9154
|
+
const alignY = this.alignFactor(layout.alignY);
|
|
9155
|
+
const offsetX = (_c = this.resolveLayoutLength(layout.offsetX, area.width)) != null ? _c : 0;
|
|
9156
|
+
const offsetY = (_d = this.resolveLayoutLength(layout.offsetY, area.height)) != null ? _d : 0;
|
|
9157
|
+
const objectWidth = Number.isFinite(next.width) ? Number(next.width) : 0;
|
|
9158
|
+
const objectHeight = Number.isFinite(next.height) ? Number(next.height) : 0;
|
|
9159
|
+
const objectLeft = area.left + (area.width - objectWidth) * alignX + offsetX;
|
|
9160
|
+
const objectTop = area.top + (area.height - objectHeight) * alignY + offsetY;
|
|
9161
|
+
const originX = this.normalizeOriginX(next.originX);
|
|
9162
|
+
const originY = this.normalizeOriginY(next.originY);
|
|
9163
|
+
next.left = objectLeft + objectWidth * this.originFactor(originX);
|
|
9164
|
+
next.top = objectTop + objectHeight * this.originFactor(originY);
|
|
9165
|
+
return next;
|
|
9166
|
+
}
|
|
9167
|
+
setLayerVisibility(layerId, visible) {
|
|
9168
|
+
const layer = this.getLayer(layerId);
|
|
9169
|
+
if (layer) {
|
|
9170
|
+
layer.set({ visible });
|
|
9171
|
+
}
|
|
9172
|
+
const objects = this.getRootLayerObjects(layerId);
|
|
9173
|
+
objects.forEach((obj) => {
|
|
9174
|
+
var _a, _b;
|
|
9175
|
+
(_a = obj.set) == null ? void 0 : _a.call(obj, { visible });
|
|
9176
|
+
(_b = obj.setCoords) == null ? void 0 : _b.call(obj);
|
|
9177
|
+
});
|
|
9178
|
+
}
|
|
9179
|
+
bringLayerToFront(layerId) {
|
|
9180
|
+
const layer = this.getLayer(layerId);
|
|
9181
|
+
if (layer) {
|
|
9182
|
+
this.canvas.bringObjectToFront(layer);
|
|
9183
|
+
}
|
|
9184
|
+
const objects = this.getRootLayerObjects(layerId);
|
|
9185
|
+
objects.forEach((obj) => this.canvas.bringObjectToFront(obj));
|
|
9186
|
+
}
|
|
7903
9187
|
async applyLayerSpec(spec) {
|
|
7904
9188
|
const layer = this.createLayer(spec.id, spec.props || {});
|
|
7905
9189
|
await this.applyObjectSpecsToContainer(layer, spec.objects);
|
|
7906
9190
|
}
|
|
7907
|
-
async applyObjectSpecsToLayer(layerId, objects) {
|
|
9191
|
+
async applyObjectSpecsToLayer(layerId, objects, options = {}) {
|
|
7908
9192
|
const layer = this.createLayer(layerId, {});
|
|
7909
|
-
await this.applyObjectSpecsToContainer(layer, objects);
|
|
9193
|
+
await this.applyObjectSpecsToContainer(layer, objects, options);
|
|
7910
9194
|
}
|
|
7911
9195
|
getRootLayerObjects(layerId) {
|
|
7912
9196
|
return this.canvas.getObjects().filter((obj) => {
|
|
@@ -7914,7 +9198,7 @@ var CanvasService = class {
|
|
|
7914
9198
|
return ((_a = obj == null ? void 0 : obj.data) == null ? void 0 : _a.layerId) === layerId;
|
|
7915
9199
|
});
|
|
7916
9200
|
}
|
|
7917
|
-
async applyObjectSpecsToRootLayer(layerId, specs) {
|
|
9201
|
+
async applyObjectSpecsToRootLayer(layerId, specs, options = {}) {
|
|
7918
9202
|
const desiredIds = new Set(specs.map((s) => s.id));
|
|
7919
9203
|
const existing = this.getRootLayerObjects(layerId);
|
|
7920
9204
|
existing.forEach((obj) => {
|
|
@@ -7948,9 +9232,11 @@ var CanvasService = class {
|
|
|
7948
9232
|
}
|
|
7949
9233
|
this.patchFabricObject(current, spec, { layerId });
|
|
7950
9234
|
}
|
|
7951
|
-
|
|
9235
|
+
if (options.render !== false) {
|
|
9236
|
+
this.requestRenderAll();
|
|
9237
|
+
}
|
|
7952
9238
|
}
|
|
7953
|
-
async applyObjectSpecsToContainer(container, specs) {
|
|
9239
|
+
async applyObjectSpecsToContainer(container, specs, options = {}) {
|
|
7954
9240
|
const desiredIds = new Set(specs.map((s) => s.id));
|
|
7955
9241
|
const existing = container.getObjects();
|
|
7956
9242
|
existing.forEach((obj) => {
|
|
@@ -7986,7 +9272,9 @@ var CanvasService = class {
|
|
|
7986
9272
|
this.moveObjectInContainer(container, current, index);
|
|
7987
9273
|
}
|
|
7988
9274
|
container.dirty = true;
|
|
7989
|
-
|
|
9275
|
+
if (options.render !== false) {
|
|
9276
|
+
this.requestRenderAll();
|
|
9277
|
+
}
|
|
7990
9278
|
}
|
|
7991
9279
|
patchFabricObject(obj, spec, extraData) {
|
|
7992
9280
|
const nextData = {
|
|
@@ -7995,9 +9283,33 @@ var CanvasService = class {
|
|
|
7995
9283
|
...extraData || {},
|
|
7996
9284
|
id: spec.id
|
|
7997
9285
|
};
|
|
7998
|
-
|
|
9286
|
+
const props = this.resolveFabricProps(spec, spec.props || {});
|
|
9287
|
+
obj.set({ ...props, data: nextData });
|
|
7999
9288
|
obj.setCoords();
|
|
8000
9289
|
}
|
|
9290
|
+
resolveFabricProps(spec, props) {
|
|
9291
|
+
const space = spec.space || "scene";
|
|
9292
|
+
const next = this.resolveLayoutProps(spec, props);
|
|
9293
|
+
if (space === "screen") {
|
|
9294
|
+
return next;
|
|
9295
|
+
}
|
|
9296
|
+
const hasLeft = Number.isFinite(next.left);
|
|
9297
|
+
const hasTop = Number.isFinite(next.top);
|
|
9298
|
+
if (hasLeft || hasTop) {
|
|
9299
|
+
const mapped = this.toScreenPoint({
|
|
9300
|
+
x: hasLeft ? Number(next.left) : 0,
|
|
9301
|
+
y: hasTop ? Number(next.top) : 0
|
|
9302
|
+
});
|
|
9303
|
+
if (hasLeft) next.left = mapped.x;
|
|
9304
|
+
if (hasTop) next.top = mapped.y;
|
|
9305
|
+
}
|
|
9306
|
+
const rawScaleX = Number.isFinite(next.scaleX) ? Number(next.scaleX) : 1;
|
|
9307
|
+
const rawScaleY = Number.isFinite(next.scaleY) ? Number(next.scaleY) : 1;
|
|
9308
|
+
const sceneScale = this.getSceneScale();
|
|
9309
|
+
next.scaleX = rawScaleX * sceneScale;
|
|
9310
|
+
next.scaleY = rawScaleY * sceneScale;
|
|
9311
|
+
return next;
|
|
9312
|
+
}
|
|
8001
9313
|
moveObjectInContainer(container, obj, index) {
|
|
8002
9314
|
if (!obj) return;
|
|
8003
9315
|
const moveObjectTo = container.moveObjectTo;
|
|
@@ -8017,10 +9329,11 @@ var CanvasService = class {
|
|
|
8017
9329
|
}
|
|
8018
9330
|
}
|
|
8019
9331
|
async createFabricObject(spec) {
|
|
8020
|
-
var _a, _b;
|
|
9332
|
+
var _a, _b, _c, _d;
|
|
8021
9333
|
if (spec.type === "rect") {
|
|
8022
|
-
const
|
|
8023
|
-
|
|
9334
|
+
const props = this.resolveFabricProps(spec, spec.props || {});
|
|
9335
|
+
const rect = new import_fabric5.Rect({
|
|
9336
|
+
...props,
|
|
8024
9337
|
data: { ...spec.data || {}, id: spec.id }
|
|
8025
9338
|
});
|
|
8026
9339
|
rect.setCoords();
|
|
@@ -8029,8 +9342,9 @@ var CanvasService = class {
|
|
|
8029
9342
|
if (spec.type === "path") {
|
|
8030
9343
|
const pathData = ((_a = spec.props) == null ? void 0 : _a.path) || ((_b = spec.props) == null ? void 0 : _b.pathData);
|
|
8031
9344
|
if (!pathData) return void 0;
|
|
8032
|
-
const
|
|
8033
|
-
|
|
9345
|
+
const props = this.resolveFabricProps(spec, spec.props || {});
|
|
9346
|
+
const path = new import_fabric5.Path(pathData, {
|
|
9347
|
+
...props,
|
|
8034
9348
|
data: { ...spec.data || {}, id: spec.id }
|
|
8035
9349
|
});
|
|
8036
9350
|
path.setCoords();
|
|
@@ -8038,14 +9352,25 @@ var CanvasService = class {
|
|
|
8038
9352
|
}
|
|
8039
9353
|
if (spec.type === "image") {
|
|
8040
9354
|
if (!spec.src) return void 0;
|
|
8041
|
-
const image = await
|
|
9355
|
+
const image = await import_fabric5.Image.fromURL(spec.src, { crossOrigin: "anonymous" });
|
|
9356
|
+
const props = this.resolveFabricProps(spec, spec.props || {});
|
|
8042
9357
|
image.set({
|
|
8043
|
-
...
|
|
9358
|
+
...props,
|
|
8044
9359
|
data: { ...spec.data || {}, id: spec.id }
|
|
8045
9360
|
});
|
|
8046
9361
|
image.setCoords();
|
|
8047
9362
|
return image;
|
|
8048
9363
|
}
|
|
9364
|
+
if (spec.type === "text") {
|
|
9365
|
+
const content = String((_d = (_c = spec.props) == null ? void 0 : _c.text) != null ? _d : "");
|
|
9366
|
+
const props = this.resolveFabricProps(spec, spec.props || {});
|
|
9367
|
+
const text = new import_fabric5.Text(content, {
|
|
9368
|
+
...props,
|
|
9369
|
+
data: { ...spec.data || {}, id: spec.id }
|
|
9370
|
+
});
|
|
9371
|
+
text.setCoords();
|
|
9372
|
+
return text;
|
|
9373
|
+
}
|
|
8049
9374
|
return void 0;
|
|
8050
9375
|
}
|
|
8051
9376
|
};
|