@pooder/kit 3.2.0 → 3.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 +3 -2
- package/dist/index.d.ts +3 -2
- package/dist/index.js +387 -158
- package/dist/index.mjs +388 -159
- package/package.json +1 -1
- package/src/dieline.ts +10 -0
- package/src/geometry.ts +37 -11
- package/src/hole.ts +79 -29
- package/src/image.ts +122 -124
- package/src/tracer.ts +278 -164
package/package.json
CHANGED
package/src/dieline.ts
CHANGED
|
@@ -493,6 +493,8 @@ export class DielineTool implements Extension {
|
|
|
493
493
|
y: cy,
|
|
494
494
|
holes: absoluteHoles,
|
|
495
495
|
pathData: this.pathData,
|
|
496
|
+
canvasWidth: canvasW,
|
|
497
|
+
canvasHeight: canvasH,
|
|
496
498
|
});
|
|
497
499
|
|
|
498
500
|
const insideObj = new Path(productPathData, {
|
|
@@ -518,6 +520,8 @@ export class DielineTool implements Extension {
|
|
|
518
520
|
y: cy,
|
|
519
521
|
holes: absoluteHoles,
|
|
520
522
|
pathData: this.pathData,
|
|
523
|
+
canvasWidth: canvasW,
|
|
524
|
+
canvasHeight: canvasH,
|
|
521
525
|
},
|
|
522
526
|
visualOffset,
|
|
523
527
|
);
|
|
@@ -549,6 +553,8 @@ export class DielineTool implements Extension {
|
|
|
549
553
|
y: cy,
|
|
550
554
|
holes: absoluteHoles,
|
|
551
555
|
pathData: this.pathData,
|
|
556
|
+
canvasWidth: canvasW,
|
|
557
|
+
canvasHeight: canvasH,
|
|
552
558
|
});
|
|
553
559
|
|
|
554
560
|
const offsetBorderObj = new Path(offsetPathData, {
|
|
@@ -577,6 +583,8 @@ export class DielineTool implements Extension {
|
|
|
577
583
|
y: cy,
|
|
578
584
|
holes: absoluteHoles,
|
|
579
585
|
pathData: this.pathData,
|
|
586
|
+
canvasWidth: canvasW,
|
|
587
|
+
canvasHeight: canvasH,
|
|
580
588
|
});
|
|
581
589
|
|
|
582
590
|
const borderObj = new Path(borderPathData, {
|
|
@@ -730,6 +738,8 @@ export class DielineTool implements Extension {
|
|
|
730
738
|
y: cy,
|
|
731
739
|
holes: absoluteHoles,
|
|
732
740
|
pathData: this.pathData,
|
|
741
|
+
canvasWidth: canvasW,
|
|
742
|
+
canvasHeight: canvasH,
|
|
733
743
|
});
|
|
734
744
|
|
|
735
745
|
// 2. Prepare for Export
|
package/src/geometry.ts
CHANGED
|
@@ -14,6 +14,7 @@ export type PositionAnchor =
|
|
|
14
14
|
export interface HoleData {
|
|
15
15
|
x?: number;
|
|
16
16
|
y?: number;
|
|
17
|
+
shape?: "circle" | "square";
|
|
17
18
|
anchor?: PositionAnchor;
|
|
18
19
|
offsetX?: number;
|
|
19
20
|
offsetY?: number;
|
|
@@ -103,6 +104,8 @@ export interface GeometryOptions {
|
|
|
103
104
|
y: number;
|
|
104
105
|
holes: Array<HoleData>;
|
|
105
106
|
pathData?: string;
|
|
107
|
+
canvasWidth?: number;
|
|
108
|
+
canvasHeight?: number;
|
|
106
109
|
}
|
|
107
110
|
|
|
108
111
|
export interface MaskGeometryOptions extends GeometryOptions {
|
|
@@ -287,21 +290,41 @@ function getDielineShape(options: GeometryOptions): paper.PathItem {
|
|
|
287
290
|
let cutsPath: paper.PathItem | null = null;
|
|
288
291
|
|
|
289
292
|
holes.forEach((hole) => {
|
|
293
|
+
const center = new paper.Point(hole.x!, hole.y!);
|
|
294
|
+
|
|
290
295
|
// Create Lug (Outer Radius)
|
|
291
|
-
const lug =
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
296
|
+
const lug =
|
|
297
|
+
hole.shape === "square"
|
|
298
|
+
? new paper.Path.Rectangle({
|
|
299
|
+
point: [
|
|
300
|
+
center.x - hole.outerRadius,
|
|
301
|
+
center.y - hole.outerRadius,
|
|
302
|
+
],
|
|
303
|
+
size: [hole.outerRadius * 2, hole.outerRadius * 2],
|
|
304
|
+
})
|
|
305
|
+
: new paper.Path.Circle({
|
|
306
|
+
center: center,
|
|
307
|
+
radius: hole.outerRadius,
|
|
308
|
+
});
|
|
295
309
|
|
|
296
310
|
// REMOVED: Intersects check. We want to process all holes defined in config.
|
|
297
311
|
// If a hole is completely outside, it might form an island, but that's better than missing it.
|
|
298
312
|
// Users can remove the hole if they don't want it.
|
|
299
313
|
|
|
300
314
|
// Create Cut (Inner Radius)
|
|
301
|
-
const cut =
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
315
|
+
const cut =
|
|
316
|
+
hole.shape === "square"
|
|
317
|
+
? new paper.Path.Rectangle({
|
|
318
|
+
point: [
|
|
319
|
+
center.x - hole.innerRadius,
|
|
320
|
+
center.y - hole.innerRadius,
|
|
321
|
+
],
|
|
322
|
+
size: [hole.innerRadius * 2, hole.innerRadius * 2],
|
|
323
|
+
})
|
|
324
|
+
: new paper.Path.Circle({
|
|
325
|
+
center: center,
|
|
326
|
+
radius: hole.innerRadius,
|
|
327
|
+
});
|
|
305
328
|
|
|
306
329
|
// Union Lugs
|
|
307
330
|
if (!lugsPath) {
|
|
@@ -373,7 +396,9 @@ function getDielineShape(options: GeometryOptions): paper.PathItem {
|
|
|
373
396
|
* Logic: (BaseShape UNION IntersectingLugs) SUBTRACT Cuts
|
|
374
397
|
*/
|
|
375
398
|
export function generateDielinePath(options: GeometryOptions): string {
|
|
376
|
-
|
|
399
|
+
const paperWidth = options.canvasWidth || options.width * 2 || 2000;
|
|
400
|
+
const paperHeight = options.canvasHeight || options.height * 2 || 2000;
|
|
401
|
+
ensurePaper(paperWidth, paperHeight);
|
|
377
402
|
paper.project.activeLayer.removeChildren();
|
|
378
403
|
|
|
379
404
|
const mainShape = getDielineShape(options);
|
|
@@ -423,8 +448,9 @@ export function generateBleedZonePath(
|
|
|
423
448
|
offset: number,
|
|
424
449
|
): string {
|
|
425
450
|
// Ensure canvas is large enough
|
|
426
|
-
const
|
|
427
|
-
|
|
451
|
+
const paperWidth = options.canvasWidth || options.width * 2 || 2000;
|
|
452
|
+
const paperHeight = options.canvasHeight || options.height * 2 || 2000;
|
|
453
|
+
ensurePaper(paperWidth, paperHeight);
|
|
428
454
|
paper.project.activeLayer.removeChildren();
|
|
429
455
|
|
|
430
456
|
// 1. Original Shape
|
package/src/hole.ts
CHANGED
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
ConfigurationContribution,
|
|
7
7
|
ConfigurationService,
|
|
8
8
|
} from "@pooder/core";
|
|
9
|
-
import { Circle, Group, Point } from "fabric";
|
|
9
|
+
import { Circle, Group, Point, Rect } from "fabric";
|
|
10
10
|
import CanvasService from "./CanvasService";
|
|
11
11
|
import { DielineGeometry } from "./dieline";
|
|
12
12
|
import {
|
|
@@ -179,10 +179,12 @@ export class HoleTool implements Extension {
|
|
|
179
179
|
const lastHole = currentHoles[currentHoles.length - 1];
|
|
180
180
|
const innerRadius = lastHole?.innerRadius ?? 15;
|
|
181
181
|
const outerRadius = lastHole?.outerRadius ?? 25;
|
|
182
|
+
const shape = lastHole?.shape ?? "circle";
|
|
182
183
|
|
|
183
184
|
const newHole = {
|
|
184
185
|
x: normalizedX,
|
|
185
186
|
y: normalizedY,
|
|
187
|
+
shape,
|
|
186
188
|
innerRadius,
|
|
187
189
|
outerRadius,
|
|
188
190
|
};
|
|
@@ -216,6 +218,7 @@ export class HoleTool implements Extension {
|
|
|
216
218
|
if (!this.handleDielineChange) {
|
|
217
219
|
this.handleDielineChange = (geometry: DielineGeometry) => {
|
|
218
220
|
this.currentGeometry = geometry;
|
|
221
|
+
this.redraw();
|
|
219
222
|
const changed = this.enforceConstraints();
|
|
220
223
|
// Only sync if constraints actually moved something
|
|
221
224
|
if (changed) {
|
|
@@ -367,21 +370,38 @@ export class HoleTool implements Extension {
|
|
|
367
370
|
if (!this.canvasService) return;
|
|
368
371
|
const objects = this.canvasService.canvas
|
|
369
372
|
.getObjects()
|
|
370
|
-
.filter(
|
|
373
|
+
.filter(
|
|
374
|
+
(obj: any) =>
|
|
375
|
+
obj.data?.type === "hole-marker" || obj.name === "hole-marker",
|
|
376
|
+
);
|
|
377
|
+
|
|
378
|
+
// If we have markers but no state, or mismatch, we should be careful.
|
|
379
|
+
// However, if we just dragged one, we expect them to match.
|
|
380
|
+
if (objects.length === 0 && this.holes.length > 0) {
|
|
381
|
+
console.warn("HoleTool: No markers found on canvas to sync from");
|
|
382
|
+
return;
|
|
383
|
+
}
|
|
371
384
|
|
|
372
|
-
// Sort objects by index
|
|
385
|
+
// Sort objects by index to match this.holes order
|
|
373
386
|
objects.sort(
|
|
374
|
-
(a: any, b: any) => (a.data?.index ?? 0) - (b.data?.index ?? 0)
|
|
387
|
+
(a: any, b: any) => (a.data?.index ?? 0) - (b.data?.index ?? 0),
|
|
375
388
|
);
|
|
376
389
|
|
|
377
390
|
// Update holes based on canvas positions
|
|
378
|
-
// We need to preserve original hole properties (radii, anchor)
|
|
379
|
-
// If a hole has an anchor, we update offsetX/Y instead of x/y
|
|
380
391
|
const newHoles = objects.map((obj, i) => {
|
|
381
392
|
const original = this.holes[i];
|
|
382
393
|
const newAbsX = obj.left!;
|
|
383
394
|
const newAbsY = obj.top!;
|
|
384
395
|
|
|
396
|
+
// Validate coordinates to prevent NaN issues
|
|
397
|
+
if (isNaN(newAbsX) || isNaN(newAbsY)) {
|
|
398
|
+
console.error("HoleTool: Invalid marker coordinates", {
|
|
399
|
+
newAbsX,
|
|
400
|
+
newAbsY,
|
|
401
|
+
});
|
|
402
|
+
return original;
|
|
403
|
+
}
|
|
404
|
+
|
|
385
405
|
// Get current scale to denormalize offsets
|
|
386
406
|
const scale = this.currentGeometry?.scale || 1;
|
|
387
407
|
const unit = this.currentGeometry?.unit || "mm";
|
|
@@ -435,7 +455,7 @@ export class HoleTool implements Extension {
|
|
|
435
455
|
by = bottom;
|
|
436
456
|
break;
|
|
437
457
|
}
|
|
438
|
-
|
|
458
|
+
|
|
439
459
|
return {
|
|
440
460
|
...original,
|
|
441
461
|
// Denormalize offset back to physical units (mm)
|
|
@@ -444,11 +464,14 @@ export class HoleTool implements Extension {
|
|
|
444
464
|
// Clear direct coordinates if we use anchor
|
|
445
465
|
x: undefined,
|
|
446
466
|
y: undefined,
|
|
467
|
+
// Ensure other properties are preserved
|
|
468
|
+
innerRadius: original.innerRadius,
|
|
469
|
+
outerRadius: original.outerRadius,
|
|
470
|
+
shape: original.shape || "circle",
|
|
447
471
|
};
|
|
448
472
|
}
|
|
449
473
|
|
|
450
474
|
// If no anchor, use normalized coordinates relative to Dieline Geometry
|
|
451
|
-
// normalized = (absolute - (center - width/2)) / width
|
|
452
475
|
let normalizedX = 0.5;
|
|
453
476
|
let normalizedY = 0.5;
|
|
454
477
|
|
|
@@ -459,19 +482,23 @@ export class HoleTool implements Extension {
|
|
|
459
482
|
normalizedX = width > 0 ? (newAbsX - left) / width : 0.5;
|
|
460
483
|
normalizedY = height > 0 ? (newAbsY - top) / height : 0.5;
|
|
461
484
|
} else {
|
|
462
|
-
// Fallback to Canvas normalization
|
|
485
|
+
// Fallback to Canvas normalization
|
|
463
486
|
const { width, height } = this.canvasService!.canvas;
|
|
464
487
|
normalizedX = Coordinate.toNormalized(newAbsX, width || 800);
|
|
465
488
|
normalizedY = Coordinate.toNormalized(newAbsY, height || 600);
|
|
466
489
|
}
|
|
467
|
-
|
|
490
|
+
|
|
468
491
|
return {
|
|
469
492
|
...original,
|
|
470
493
|
x: normalizedX,
|
|
471
494
|
y: normalizedY,
|
|
472
|
-
//
|
|
495
|
+
// Clear offsets if we are using direct normalized coordinates
|
|
496
|
+
offsetX: undefined,
|
|
497
|
+
offsetY: undefined,
|
|
498
|
+
// Ensure other properties are preserved
|
|
473
499
|
innerRadius: original?.innerRadius ?? 15,
|
|
474
500
|
outerRadius: original?.outerRadius ?? 25,
|
|
501
|
+
shape: original?.shape || "circle",
|
|
475
502
|
};
|
|
476
503
|
});
|
|
477
504
|
|
|
@@ -544,26 +571,49 @@ export class HoleTool implements Extension {
|
|
|
544
571
|
{ width: geometry.width, height: geometry.height } // Use geometry dims instead of canvas
|
|
545
572
|
);
|
|
546
573
|
|
|
547
|
-
const
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
574
|
+
const isSquare = hole.shape === "square";
|
|
575
|
+
|
|
576
|
+
const innerMarker = isSquare
|
|
577
|
+
? new Rect({
|
|
578
|
+
width: visualInnerRadius * 2,
|
|
579
|
+
height: visualInnerRadius * 2,
|
|
580
|
+
fill: "transparent",
|
|
581
|
+
stroke: "red",
|
|
582
|
+
strokeWidth: 2,
|
|
583
|
+
originX: "center",
|
|
584
|
+
originY: "center",
|
|
585
|
+
})
|
|
586
|
+
: new Circle({
|
|
587
|
+
radius: visualInnerRadius,
|
|
588
|
+
fill: "transparent",
|
|
589
|
+
stroke: "red",
|
|
590
|
+
strokeWidth: 2,
|
|
591
|
+
originX: "center",
|
|
592
|
+
originY: "center",
|
|
593
|
+
});
|
|
555
594
|
|
|
556
|
-
const
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
595
|
+
const outerMarker = isSquare
|
|
596
|
+
? new Rect({
|
|
597
|
+
width: visualOuterRadius * 2,
|
|
598
|
+
height: visualOuterRadius * 2,
|
|
599
|
+
fill: "transparent",
|
|
600
|
+
stroke: "#666",
|
|
601
|
+
strokeWidth: 1,
|
|
602
|
+
strokeDashArray: [5, 5],
|
|
603
|
+
originX: "center",
|
|
604
|
+
originY: "center",
|
|
605
|
+
})
|
|
606
|
+
: new Circle({
|
|
607
|
+
radius: visualOuterRadius,
|
|
608
|
+
fill: "transparent",
|
|
609
|
+
stroke: "#666",
|
|
610
|
+
strokeWidth: 1,
|
|
611
|
+
strokeDashArray: [5, 5],
|
|
612
|
+
originX: "center",
|
|
613
|
+
originY: "center",
|
|
614
|
+
});
|
|
565
615
|
|
|
566
|
-
const holeGroup = new Group([
|
|
616
|
+
const holeGroup = new Group([outerMarker, innerMarker], {
|
|
567
617
|
left: pos.x,
|
|
568
618
|
top: pos.y,
|
|
569
619
|
originX: "center",
|