@pooder/kit 6.2.0 → 6.2.2
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/.test-dist/src/extensions/dieline/DielineTool.js +22 -9
- package/.test-dist/src/extensions/dieline/renderBuilder.js +47 -14
- package/.test-dist/src/extensions/feature/FeatureTool.js +20 -3
- package/.test-dist/src/extensions/featureCoordinates.js +21 -0
- package/.test-dist/src/extensions/featurePlacement.js +46 -0
- package/.test-dist/src/extensions/image/ImageTool.js +46 -348
- package/.test-dist/src/extensions/image/sessionOverlay.js +148 -0
- package/.test-dist/src/extensions/ruler/RulerTool.js +25 -2
- package/.test-dist/tests/run.js +25 -0
- package/CHANGELOG.md +12 -0
- package/dist/index.d.mts +4 -5
- package/dist/index.d.ts +4 -5
- package/dist/index.js +1506 -1494
- package/dist/index.mjs +1506 -1494
- package/package.json +1 -1
- package/src/extensions/dieline/DielineTool.ts +29 -9
- package/src/extensions/dieline/renderBuilder.ts +65 -17
- package/src/extensions/feature/FeatureTool.ts +23 -3
- package/src/extensions/featureCoordinates.ts +35 -0
- package/src/extensions/featurePlacement.ts +118 -0
- package/src/extensions/image/ImageTool.ts +57 -412
- package/src/extensions/image/sessionOverlay.ts +206 -0
- package/src/extensions/ruler/RulerTool.ts +24 -2
- package/tests/run.ts +37 -0
|
@@ -14,24 +14,15 @@ import {
|
|
|
14
14
|
Point,
|
|
15
15
|
controlsUtils,
|
|
16
16
|
} from "fabric";
|
|
17
|
-
import {
|
|
18
|
-
CanvasService,
|
|
19
|
-
RenderLayoutRect,
|
|
20
|
-
RenderObjectSpec,
|
|
21
|
-
} from "../../services";
|
|
22
|
-
import { isDielineShape, normalizeShapeStyle } from "../dielineShape";
|
|
23
|
-
import type { DielineShape, DielineShapeStyle } from "../dielineShape";
|
|
24
|
-
import { generateDielinePath, getPathBounds } from "../geometry";
|
|
17
|
+
import { CanvasService, RenderObjectSpec } from "../../services";
|
|
25
18
|
import {
|
|
26
19
|
buildSceneGeometry,
|
|
27
20
|
computeSceneLayout,
|
|
28
21
|
readSizeState,
|
|
22
|
+
type SceneGeometrySnapshot,
|
|
23
|
+
type SceneLayoutSnapshot,
|
|
29
24
|
} from "../../shared/scene/sceneLayoutModel";
|
|
30
|
-
import {
|
|
31
|
-
type FrameRect,
|
|
32
|
-
resolveCutFrameRect,
|
|
33
|
-
toLayoutSceneRect as toSceneLayoutRect,
|
|
34
|
-
} from "../../shared/scene/frame";
|
|
25
|
+
import { type FrameRect, resolveCutFrameRect } from "../../shared/scene/frame";
|
|
35
26
|
import {
|
|
36
27
|
createSourceSizeCache,
|
|
37
28
|
getCoverScale as getCoverScaleFromRect,
|
|
@@ -48,6 +39,7 @@ import {
|
|
|
48
39
|
} from "../../shared/constants/layers";
|
|
49
40
|
import { createImageCommands } from "./commands";
|
|
50
41
|
import { createImageConfigurations } from "./config";
|
|
42
|
+
import { buildImageSessionOverlaySpecs } from "./sessionOverlay";
|
|
51
43
|
|
|
52
44
|
export interface ImageItem {
|
|
53
45
|
id: string;
|
|
@@ -91,13 +83,9 @@ interface ImageControlVisualConfig {
|
|
|
91
83
|
padding: number;
|
|
92
84
|
}
|
|
93
85
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
shape: DielineShape;
|
|
98
|
-
shapeStyle: DielineShapeStyle;
|
|
99
|
-
radius: number;
|
|
100
|
-
offset: number;
|
|
86
|
+
interface ImageSessionOverlayState {
|
|
87
|
+
layout: SceneLayoutSnapshot;
|
|
88
|
+
geometry: SceneGeometrySnapshot;
|
|
101
89
|
}
|
|
102
90
|
|
|
103
91
|
interface UpsertImageOptions {
|
|
@@ -663,10 +651,21 @@ export class ImageTool implements Extension {
|
|
|
663
651
|
}
|
|
664
652
|
}
|
|
665
653
|
|
|
654
|
+
private clearSnapGuideContext() {
|
|
655
|
+
const topContext = this.canvasService?.canvas.contextTop;
|
|
656
|
+
if (!this.canvasService || !topContext) return;
|
|
657
|
+
this.canvasService.canvas.clearContext(topContext);
|
|
658
|
+
}
|
|
659
|
+
|
|
666
660
|
private clearSnapPreview() {
|
|
661
|
+
const shouldClearCanvas =
|
|
662
|
+
this.hasRenderedSnapGuides || !!this.activeSnapX || !!this.activeSnapY;
|
|
667
663
|
this.activeSnapX = null;
|
|
668
664
|
this.activeSnapY = null;
|
|
669
665
|
this.hasRenderedSnapGuides = false;
|
|
666
|
+
if (shouldClearCanvas) {
|
|
667
|
+
this.clearSnapGuideContext();
|
|
668
|
+
}
|
|
670
669
|
this.canvasService?.requestRenderAll();
|
|
671
670
|
}
|
|
672
671
|
|
|
@@ -1166,10 +1165,6 @@ export class ImageTool implements Extension {
|
|
|
1166
1165
|
return this.canvasService.toScreenRect(frame || this.getFrameRect());
|
|
1167
1166
|
}
|
|
1168
1167
|
|
|
1169
|
-
private toLayoutSceneRect(rect: FrameRect): RenderLayoutRect {
|
|
1170
|
-
return toSceneLayoutRect(rect);
|
|
1171
|
-
}
|
|
1172
|
-
|
|
1173
1168
|
private async resolveDefaultFitArea(): Promise<DielineFitArea | null> {
|
|
1174
1169
|
if (!this.canvasService) return null;
|
|
1175
1170
|
const frame = this.getFrameRect();
|
|
@@ -1319,94 +1314,42 @@ export class ImageTool implements Extension {
|
|
|
1319
1314
|
};
|
|
1320
1315
|
}
|
|
1321
1316
|
|
|
1322
|
-
private
|
|
1323
|
-
|
|
1324
|
-
if (!isDielineShape(shape)) {
|
|
1317
|
+
private resolveSessionOverlayState(): ImageSessionOverlayState | null {
|
|
1318
|
+
if (!this.canvasService || !this.context) {
|
|
1325
1319
|
return null;
|
|
1326
1320
|
}
|
|
1327
|
-
|
|
1328
|
-
const radiusRaw = Number(raw?.radius);
|
|
1329
|
-
const offsetRaw = Number(raw?.offset);
|
|
1330
|
-
const unit = typeof raw?.unit === "string" ? raw.unit : "px";
|
|
1331
|
-
const radius =
|
|
1332
|
-
unit === "scene" || !this.canvasService
|
|
1333
|
-
? radiusRaw
|
|
1334
|
-
: this.canvasService.toSceneLength(radiusRaw);
|
|
1335
|
-
const offset =
|
|
1336
|
-
unit === "scene" || !this.canvasService
|
|
1337
|
-
? offsetRaw
|
|
1338
|
-
: this.canvasService.toSceneLength(offsetRaw);
|
|
1339
|
-
return {
|
|
1340
|
-
shape,
|
|
1341
|
-
shapeStyle: normalizeShapeStyle(raw?.shapeStyle),
|
|
1342
|
-
radius: Number.isFinite(radius) ? radius : 0,
|
|
1343
|
-
offset: Number.isFinite(offset) ? offset : 0,
|
|
1344
|
-
};
|
|
1345
|
-
}
|
|
1346
|
-
|
|
1347
|
-
private async resolveSceneGeometryForOverlay(): Promise<SceneGeometryLike | null> {
|
|
1348
|
-
if (!this.context) return null;
|
|
1349
|
-
const commandService = this.context.services.get<any>("CommandService");
|
|
1350
|
-
if (commandService) {
|
|
1351
|
-
try {
|
|
1352
|
-
const raw = await Promise.resolve(
|
|
1353
|
-
commandService.executeCommand("getSceneGeometry"),
|
|
1354
|
-
);
|
|
1355
|
-
const geometry = this.toSceneGeometryLike(raw);
|
|
1356
|
-
if (geometry) {
|
|
1357
|
-
this.debug("overlay:sceneGeometry:command", geometry);
|
|
1358
|
-
return geometry;
|
|
1359
|
-
}
|
|
1360
|
-
this.debug("overlay:sceneGeometry:command:invalid", { raw });
|
|
1361
|
-
} catch (error) {
|
|
1362
|
-
this.debug("overlay:sceneGeometry:command:error", {
|
|
1363
|
-
error: error instanceof Error ? error.message : String(error),
|
|
1364
|
-
});
|
|
1365
|
-
}
|
|
1366
|
-
}
|
|
1367
|
-
|
|
1368
|
-
if (!this.canvasService) return null;
|
|
1369
1321
|
const configService = this.context.services.get<ConfigurationService>(
|
|
1370
1322
|
"ConfigurationService",
|
|
1371
1323
|
);
|
|
1372
|
-
if (!configService)
|
|
1373
|
-
|
|
1374
|
-
const sizeState = readSizeState(configService);
|
|
1375
|
-
const layout = computeSceneLayout(this.canvasService, sizeState);
|
|
1376
|
-
if (!layout) {
|
|
1377
|
-
this.debug("overlay:sceneGeometry:fallback:missing-layout");
|
|
1324
|
+
if (!configService) {
|
|
1378
1325
|
return null;
|
|
1379
1326
|
}
|
|
1380
1327
|
|
|
1381
|
-
const
|
|
1382
|
-
|
|
1328
|
+
const layout = computeSceneLayout(
|
|
1329
|
+
this.canvasService,
|
|
1330
|
+
readSizeState(configService),
|
|
1383
1331
|
);
|
|
1384
|
-
if (
|
|
1385
|
-
this.debug("overlay:
|
|
1332
|
+
if (!layout) {
|
|
1333
|
+
this.debug("overlay:layout:missing");
|
|
1334
|
+
return null;
|
|
1386
1335
|
}
|
|
1387
|
-
return geometry;
|
|
1388
|
-
}
|
|
1389
1336
|
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
:
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
visualRadius === 0 ? 0 : Math.max(0, visualRadius + visualOffset);
|
|
1400
|
-
const maxRadius = Math.max(0, Math.min(frame.width, frame.height) / 2);
|
|
1401
|
-
return Math.max(0, Math.min(maxRadius, rawCutRadius));
|
|
1337
|
+
const geometry = buildSceneGeometry(configService, layout);
|
|
1338
|
+
this.debug("overlay:state:resolved", {
|
|
1339
|
+
cutRect: layout.cutRect,
|
|
1340
|
+
shape: geometry.shape,
|
|
1341
|
+
shapeStyle: geometry.shapeStyle,
|
|
1342
|
+
radius: geometry.radius,
|
|
1343
|
+
offset: geometry.offset,
|
|
1344
|
+
});
|
|
1345
|
+
return { layout, geometry };
|
|
1402
1346
|
}
|
|
1403
1347
|
|
|
1404
1348
|
private getCropShapeHatchPattern(
|
|
1405
1349
|
color = "rgba(255, 0, 0, 0.6)",
|
|
1406
1350
|
): Pattern | undefined {
|
|
1407
1351
|
if (typeof document === "undefined") return undefined;
|
|
1408
|
-
const
|
|
1409
|
-
const cacheKey = `${color}::${sceneScale.toFixed(6)}`;
|
|
1352
|
+
const cacheKey = color;
|
|
1410
1353
|
if (
|
|
1411
1354
|
this.cropShapeHatchPattern &&
|
|
1412
1355
|
this.cropShapeHatchPatternColor === color &&
|
|
@@ -1443,152 +1386,12 @@ export class ImageTool implements Extension {
|
|
|
1443
1386
|
// @ts-ignore: Fabric Pattern accepts canvas source here.
|
|
1444
1387
|
repetition: "repeat",
|
|
1445
1388
|
});
|
|
1446
|
-
// Scene specs are scaled to screen by CanvasService; keep hatch density in screen pixels.
|
|
1447
|
-
(pattern as any).patternTransform = [
|
|
1448
|
-
1 / sceneScale,
|
|
1449
|
-
0,
|
|
1450
|
-
0,
|
|
1451
|
-
1 / sceneScale,
|
|
1452
|
-
0,
|
|
1453
|
-
0,
|
|
1454
|
-
];
|
|
1455
1389
|
this.cropShapeHatchPattern = pattern;
|
|
1456
1390
|
this.cropShapeHatchPatternColor = color;
|
|
1457
1391
|
this.cropShapeHatchPatternKey = cacheKey;
|
|
1458
1392
|
return pattern;
|
|
1459
1393
|
}
|
|
1460
1394
|
|
|
1461
|
-
private buildCropShapeOverlaySpecs(
|
|
1462
|
-
frame: FrameRect,
|
|
1463
|
-
sceneGeometry: SceneGeometryLike | null,
|
|
1464
|
-
): RenderObjectSpec[] {
|
|
1465
|
-
if (!sceneGeometry) {
|
|
1466
|
-
this.debug("overlay:shape:skip", { reason: "scene-geometry-missing" });
|
|
1467
|
-
return [];
|
|
1468
|
-
}
|
|
1469
|
-
if (sceneGeometry.shape === "custom") {
|
|
1470
|
-
this.debug("overlay:shape:skip", { reason: "shape-custom" });
|
|
1471
|
-
return [];
|
|
1472
|
-
}
|
|
1473
|
-
|
|
1474
|
-
const shape = sceneGeometry.shape as ShapeOverlayShape;
|
|
1475
|
-
const shapeStyle = sceneGeometry.shapeStyle;
|
|
1476
|
-
const inset = 0;
|
|
1477
|
-
const shapeWidth = Math.max(1, frame.width);
|
|
1478
|
-
const shapeHeight = Math.max(1, frame.height);
|
|
1479
|
-
const radius = this.resolveCutShapeRadius(sceneGeometry, frame);
|
|
1480
|
-
|
|
1481
|
-
this.debug("overlay:shape:geometry", {
|
|
1482
|
-
shape,
|
|
1483
|
-
frameWidth: frame.width,
|
|
1484
|
-
frameHeight: frame.height,
|
|
1485
|
-
offset: sceneGeometry.offset,
|
|
1486
|
-
shapeStyle,
|
|
1487
|
-
inset,
|
|
1488
|
-
shapeWidth,
|
|
1489
|
-
shapeHeight,
|
|
1490
|
-
baseRadius: sceneGeometry.radius,
|
|
1491
|
-
radius,
|
|
1492
|
-
});
|
|
1493
|
-
|
|
1494
|
-
const isSameAsFrame =
|
|
1495
|
-
Math.abs(shapeWidth - frame.width) <= 0.0001 &&
|
|
1496
|
-
Math.abs(shapeHeight - frame.height) <= 0.0001;
|
|
1497
|
-
if (shape === "rect" && radius <= 0.0001 && isSameAsFrame) {
|
|
1498
|
-
this.debug("overlay:shape:skip", {
|
|
1499
|
-
reason: "shape-rect-no-radius",
|
|
1500
|
-
});
|
|
1501
|
-
return [];
|
|
1502
|
-
}
|
|
1503
|
-
|
|
1504
|
-
const baseOptions = {
|
|
1505
|
-
shape,
|
|
1506
|
-
width: shapeWidth,
|
|
1507
|
-
height: shapeHeight,
|
|
1508
|
-
radius,
|
|
1509
|
-
x: frame.width / 2,
|
|
1510
|
-
y: frame.height / 2,
|
|
1511
|
-
features: [],
|
|
1512
|
-
shapeStyle,
|
|
1513
|
-
canvasWidth: frame.width,
|
|
1514
|
-
canvasHeight: frame.height,
|
|
1515
|
-
};
|
|
1516
|
-
|
|
1517
|
-
try {
|
|
1518
|
-
const shapePathData = generateDielinePath(baseOptions);
|
|
1519
|
-
const outerRectPathData = `M 0 0 L ${frame.width} 0 L ${frame.width} ${frame.height} L 0 ${frame.height} Z`;
|
|
1520
|
-
const hatchPathData = `${outerRectPathData} ${shapePathData}`;
|
|
1521
|
-
if (!shapePathData || !hatchPathData) {
|
|
1522
|
-
this.debug("overlay:shape:skip", {
|
|
1523
|
-
reason: "path-generation-empty",
|
|
1524
|
-
shape,
|
|
1525
|
-
radius,
|
|
1526
|
-
});
|
|
1527
|
-
return [];
|
|
1528
|
-
}
|
|
1529
|
-
|
|
1530
|
-
const patternFill = this.getCropShapeHatchPattern();
|
|
1531
|
-
const hatchFill = patternFill || "rgba(255, 0, 0, 0.22)";
|
|
1532
|
-
const shapeBounds = getPathBounds(shapePathData);
|
|
1533
|
-
const hatchBounds = getPathBounds(hatchPathData);
|
|
1534
|
-
const frameRect = this.toLayoutSceneRect(frame);
|
|
1535
|
-
const hatchPathLength = hatchPathData.length;
|
|
1536
|
-
const shapePathLength = shapePathData.length;
|
|
1537
|
-
const specs: RenderObjectSpec[] = [
|
|
1538
|
-
{
|
|
1539
|
-
id: "image.cropShapeHatch",
|
|
1540
|
-
type: "path",
|
|
1541
|
-
data: { id: "image.cropShapeHatch", zIndex: 5 },
|
|
1542
|
-
layout: {
|
|
1543
|
-
reference: "custom",
|
|
1544
|
-
referenceRect: frameRect,
|
|
1545
|
-
alignX: "start",
|
|
1546
|
-
alignY: "start",
|
|
1547
|
-
offsetX: hatchBounds.x,
|
|
1548
|
-
offsetY: hatchBounds.y,
|
|
1549
|
-
},
|
|
1550
|
-
props: {
|
|
1551
|
-
pathData: hatchPathData,
|
|
1552
|
-
originX: "left",
|
|
1553
|
-
originY: "top",
|
|
1554
|
-
fill: hatchFill,
|
|
1555
|
-
opacity: patternFill ? 1 : 0.8,
|
|
1556
|
-
stroke: "rgba(255, 0, 0, 0.9)",
|
|
1557
|
-
strokeWidth: this.canvasService?.toSceneLength(1) ?? 1,
|
|
1558
|
-
fillRule: "evenodd",
|
|
1559
|
-
selectable: false,
|
|
1560
|
-
evented: false,
|
|
1561
|
-
excludeFromExport: true,
|
|
1562
|
-
objectCaching: false,
|
|
1563
|
-
},
|
|
1564
|
-
},
|
|
1565
|
-
];
|
|
1566
|
-
this.debug("overlay:shape:built", {
|
|
1567
|
-
shape,
|
|
1568
|
-
radius,
|
|
1569
|
-
inset,
|
|
1570
|
-
shapeWidth,
|
|
1571
|
-
shapeHeight,
|
|
1572
|
-
fillRule: "evenodd",
|
|
1573
|
-
shapePathLength,
|
|
1574
|
-
hatchPathLength,
|
|
1575
|
-
shapeBounds,
|
|
1576
|
-
hatchBounds,
|
|
1577
|
-
hatchFillType:
|
|
1578
|
-
hatchFill && typeof hatchFill === "object" ? "pattern" : "color",
|
|
1579
|
-
ids: specs.map((spec) => spec.id),
|
|
1580
|
-
});
|
|
1581
|
-
return specs;
|
|
1582
|
-
} catch (error) {
|
|
1583
|
-
this.debug("overlay:shape:error", {
|
|
1584
|
-
shape,
|
|
1585
|
-
radius,
|
|
1586
|
-
error: error instanceof Error ? error.message : String(error),
|
|
1587
|
-
});
|
|
1588
|
-
return [];
|
|
1589
|
-
}
|
|
1590
|
-
}
|
|
1591
|
-
|
|
1592
1395
|
private resolveRenderImageState(item: ImageItem): RenderImageState {
|
|
1593
1396
|
const active = this.isToolActive;
|
|
1594
1397
|
const sourceUrl = item.sourceUrl || item.url;
|
|
@@ -1689,19 +1492,13 @@ export class ImageTool implements Extension {
|
|
|
1689
1492
|
}
|
|
1690
1493
|
|
|
1691
1494
|
private buildOverlaySpecs(
|
|
1692
|
-
|
|
1693
|
-
sceneGeometry: SceneGeometryLike | null,
|
|
1495
|
+
overlayState: ImageSessionOverlayState | null,
|
|
1694
1496
|
): RenderObjectSpec[] {
|
|
1695
1497
|
const visible = this.isImageEditingVisible();
|
|
1696
|
-
if (
|
|
1697
|
-
!visible ||
|
|
1698
|
-
frame.width <= 0 ||
|
|
1699
|
-
frame.height <= 0 ||
|
|
1700
|
-
!this.canvasService
|
|
1701
|
-
) {
|
|
1498
|
+
if (!visible || !overlayState || !this.canvasService) {
|
|
1702
1499
|
this.debug("overlay:hidden", {
|
|
1703
1500
|
visible,
|
|
1704
|
-
|
|
1501
|
+
cutRect: overlayState?.layout.cutRect,
|
|
1705
1502
|
isToolActive: this.isToolActive,
|
|
1706
1503
|
isImageSelectionActive: this.isImageSelectionActive,
|
|
1707
1504
|
focusedImageId: this.focusedImageId,
|
|
@@ -1709,174 +1506,23 @@ export class ImageTool implements Extension {
|
|
|
1709
1506
|
return [];
|
|
1710
1507
|
}
|
|
1711
1508
|
|
|
1712
|
-
const viewport = this.canvasService.
|
|
1713
|
-
const canvasW = viewport.width || 0;
|
|
1714
|
-
const canvasH = viewport.height || 0;
|
|
1715
|
-
const canvasLeft = viewport.left || 0;
|
|
1716
|
-
const canvasTop = viewport.top || 0;
|
|
1509
|
+
const viewport = this.canvasService.getScreenViewportRect();
|
|
1717
1510
|
const visual = this.getFrameVisualConfig();
|
|
1718
|
-
const
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
canvasLeft,
|
|
1725
|
-
Math.min(canvasLeft + canvasW, frame.left),
|
|
1726
|
-
);
|
|
1727
|
-
const frameTop = Math.max(
|
|
1728
|
-
canvasTop,
|
|
1729
|
-
Math.min(canvasTop + canvasH, frame.top),
|
|
1730
|
-
);
|
|
1731
|
-
const frameRight = Math.max(
|
|
1732
|
-
frameLeft,
|
|
1733
|
-
Math.min(canvasLeft + canvasW, frame.left + frame.width),
|
|
1734
|
-
);
|
|
1735
|
-
const frameBottom = Math.max(
|
|
1736
|
-
frameTop,
|
|
1737
|
-
Math.min(canvasTop + canvasH, frame.top + frame.height),
|
|
1738
|
-
);
|
|
1739
|
-
const visibleFrameH = Math.max(0, frameBottom - frameTop);
|
|
1740
|
-
|
|
1741
|
-
const topH = Math.max(0, frameTop - canvasTop);
|
|
1742
|
-
const bottomH = Math.max(0, canvasTop + canvasH - frameBottom);
|
|
1743
|
-
const leftW = Math.max(0, frameLeft - canvasLeft);
|
|
1744
|
-
const rightW = Math.max(0, canvasLeft + canvasW - frameRight);
|
|
1745
|
-
const viewportRect = this.toLayoutSceneRect({
|
|
1746
|
-
left: canvasLeft,
|
|
1747
|
-
top: canvasTop,
|
|
1748
|
-
width: canvasW,
|
|
1749
|
-
height: canvasH,
|
|
1750
|
-
});
|
|
1751
|
-
const visibleFrameBandRect = this.toLayoutSceneRect({
|
|
1752
|
-
left: canvasLeft,
|
|
1753
|
-
top: frameTop,
|
|
1754
|
-
width: canvasW,
|
|
1755
|
-
height: visibleFrameH,
|
|
1756
|
-
});
|
|
1757
|
-
const frameRect = this.toLayoutSceneRect(frame);
|
|
1758
|
-
const shapeOverlay = this.buildCropShapeOverlaySpecs(frame, sceneGeometry);
|
|
1759
|
-
|
|
1760
|
-
const mask: RenderObjectSpec[] = [
|
|
1761
|
-
{
|
|
1762
|
-
id: "image.cropMask.top",
|
|
1763
|
-
type: "rect",
|
|
1764
|
-
data: { id: "image.cropMask.top", zIndex: 1 },
|
|
1765
|
-
layout: {
|
|
1766
|
-
reference: "custom",
|
|
1767
|
-
referenceRect: viewportRect,
|
|
1768
|
-
alignX: "start",
|
|
1769
|
-
alignY: "start",
|
|
1770
|
-
width: "100%",
|
|
1771
|
-
height: topH,
|
|
1772
|
-
},
|
|
1773
|
-
props: {
|
|
1774
|
-
originX: "left",
|
|
1775
|
-
originY: "top",
|
|
1776
|
-
fill: visual.outerBackground,
|
|
1777
|
-
selectable: false,
|
|
1778
|
-
evented: false,
|
|
1779
|
-
},
|
|
1511
|
+
const specs = buildImageSessionOverlaySpecs({
|
|
1512
|
+
viewport: {
|
|
1513
|
+
left: viewport.left,
|
|
1514
|
+
top: viewport.top,
|
|
1515
|
+
width: viewport.width,
|
|
1516
|
+
height: viewport.height,
|
|
1780
1517
|
},
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
reference: "custom",
|
|
1787
|
-
referenceRect: viewportRect,
|
|
1788
|
-
alignX: "start",
|
|
1789
|
-
alignY: "end",
|
|
1790
|
-
width: "100%",
|
|
1791
|
-
height: bottomH,
|
|
1792
|
-
},
|
|
1793
|
-
props: {
|
|
1794
|
-
originX: "left",
|
|
1795
|
-
originY: "top",
|
|
1796
|
-
fill: visual.outerBackground,
|
|
1797
|
-
selectable: false,
|
|
1798
|
-
evented: false,
|
|
1799
|
-
},
|
|
1800
|
-
},
|
|
1801
|
-
{
|
|
1802
|
-
id: "image.cropMask.left",
|
|
1803
|
-
type: "rect",
|
|
1804
|
-
data: { id: "image.cropMask.left", zIndex: 3 },
|
|
1805
|
-
layout: {
|
|
1806
|
-
reference: "custom",
|
|
1807
|
-
referenceRect: visibleFrameBandRect,
|
|
1808
|
-
alignX: "start",
|
|
1809
|
-
alignY: "start",
|
|
1810
|
-
width: leftW,
|
|
1811
|
-
height: "100%",
|
|
1812
|
-
},
|
|
1813
|
-
props: {
|
|
1814
|
-
originX: "left",
|
|
1815
|
-
originY: "top",
|
|
1816
|
-
fill: visual.outerBackground,
|
|
1817
|
-
selectable: false,
|
|
1818
|
-
evented: false,
|
|
1819
|
-
},
|
|
1820
|
-
},
|
|
1821
|
-
{
|
|
1822
|
-
id: "image.cropMask.right",
|
|
1823
|
-
type: "rect",
|
|
1824
|
-
data: { id: "image.cropMask.right", zIndex: 4 },
|
|
1825
|
-
layout: {
|
|
1826
|
-
reference: "custom",
|
|
1827
|
-
referenceRect: visibleFrameBandRect,
|
|
1828
|
-
alignX: "end",
|
|
1829
|
-
alignY: "start",
|
|
1830
|
-
width: rightW,
|
|
1831
|
-
height: "100%",
|
|
1832
|
-
},
|
|
1833
|
-
props: {
|
|
1834
|
-
originX: "left",
|
|
1835
|
-
originY: "top",
|
|
1836
|
-
fill: visual.outerBackground,
|
|
1837
|
-
selectable: false,
|
|
1838
|
-
evented: false,
|
|
1839
|
-
},
|
|
1840
|
-
},
|
|
1841
|
-
];
|
|
1842
|
-
|
|
1843
|
-
const frameSpec: RenderObjectSpec = {
|
|
1844
|
-
id: "image.cropFrame",
|
|
1845
|
-
type: "rect",
|
|
1846
|
-
data: { id: "image.cropFrame", zIndex: 7 },
|
|
1847
|
-
layout: {
|
|
1848
|
-
reference: "custom",
|
|
1849
|
-
referenceRect: frameRect,
|
|
1850
|
-
alignX: "start",
|
|
1851
|
-
alignY: "start",
|
|
1852
|
-
width: "100%",
|
|
1853
|
-
height: "100%",
|
|
1854
|
-
},
|
|
1855
|
-
props: {
|
|
1856
|
-
originX: "left",
|
|
1857
|
-
originY: "top",
|
|
1858
|
-
fill: visual.innerBackground,
|
|
1859
|
-
stroke:
|
|
1860
|
-
visual.strokeStyle === "hidden"
|
|
1861
|
-
? "rgba(0,0,0,0)"
|
|
1862
|
-
: visual.strokeColor,
|
|
1863
|
-
strokeWidth: visual.strokeStyle === "hidden" ? 0 : strokeWidthScene,
|
|
1864
|
-
strokeDashArray:
|
|
1865
|
-
visual.strokeStyle === "dashed"
|
|
1866
|
-
? [dashLengthScene, dashLengthScene]
|
|
1867
|
-
: undefined,
|
|
1868
|
-
selectable: false,
|
|
1869
|
-
evented: false,
|
|
1870
|
-
},
|
|
1871
|
-
};
|
|
1872
|
-
|
|
1873
|
-
const specs =
|
|
1874
|
-
shapeOverlay.length > 0
|
|
1875
|
-
? [...mask, ...shapeOverlay]
|
|
1876
|
-
: [...mask, ...shapeOverlay, frameSpec];
|
|
1518
|
+
layout: overlayState.layout,
|
|
1519
|
+
geometry: overlayState.geometry,
|
|
1520
|
+
visual,
|
|
1521
|
+
hatchPattern: this.getCropShapeHatchPattern(),
|
|
1522
|
+
});
|
|
1877
1523
|
this.debug("overlay:built", {
|
|
1878
|
-
|
|
1879
|
-
shape:
|
|
1524
|
+
cutRect: overlayState.layout.cutRect,
|
|
1525
|
+
shape: overlayState.geometry.shape,
|
|
1880
1526
|
overlayIds: specs.map((spec) => ({
|
|
1881
1527
|
id: spec.id,
|
|
1882
1528
|
zIndex: spec.data?.zIndex,
|
|
@@ -1907,11 +1553,10 @@ export class ImageTool implements Extension {
|
|
|
1907
1553
|
const imageSpecs = await this.buildImageSpecs(renderItems, frame);
|
|
1908
1554
|
if (seq !== this.renderSeq) return;
|
|
1909
1555
|
|
|
1910
|
-
const
|
|
1911
|
-
if (seq !== this.renderSeq) return;
|
|
1556
|
+
const overlayState = this.resolveSessionOverlayState();
|
|
1912
1557
|
|
|
1913
1558
|
this.imageSpecs = imageSpecs;
|
|
1914
|
-
this.overlaySpecs = this.buildOverlaySpecs(
|
|
1559
|
+
this.overlaySpecs = this.buildOverlaySpecs(overlayState);
|
|
1915
1560
|
await this.canvasService.flushRenderFromProducers();
|
|
1916
1561
|
if (seq !== this.renderSeq) return;
|
|
1917
1562
|
this.refreshImageObjectInteractionState();
|