@pooder/kit 6.1.2 → 6.2.1

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.
Files changed (30) hide show
  1. package/.test-dist/src/extensions/background/BackgroundTool.js +177 -5
  2. package/.test-dist/src/extensions/constraintUtils.js +44 -0
  3. package/.test-dist/src/extensions/dieline/DielineTool.js +52 -409
  4. package/.test-dist/src/extensions/dieline/featureResolution.js +29 -0
  5. package/.test-dist/src/extensions/dieline/model.js +83 -0
  6. package/.test-dist/src/extensions/dieline/renderBuilder.js +227 -0
  7. package/.test-dist/src/extensions/feature/FeatureTool.js +156 -45
  8. package/.test-dist/src/extensions/featureCoordinates.js +21 -0
  9. package/.test-dist/src/extensions/featurePlacement.js +46 -0
  10. package/.test-dist/src/extensions/image/ImageTool.js +281 -25
  11. package/.test-dist/src/extensions/ruler/RulerTool.js +24 -1
  12. package/.test-dist/src/shared/constants/layers.js +3 -1
  13. package/.test-dist/tests/run.js +25 -0
  14. package/CHANGELOG.md +12 -0
  15. package/dist/index.d.mts +47 -13
  16. package/dist/index.d.ts +47 -13
  17. package/dist/index.js +1325 -977
  18. package/dist/index.mjs +1311 -966
  19. package/package.json +1 -1
  20. package/src/extensions/background/BackgroundTool.ts +264 -4
  21. package/src/extensions/dieline/DielineTool.ts +67 -548
  22. package/src/extensions/dieline/model.ts +165 -1
  23. package/src/extensions/dieline/renderBuilder.ts +301 -0
  24. package/src/extensions/feature/FeatureTool.ts +190 -47
  25. package/src/extensions/featureCoordinates.ts +35 -0
  26. package/src/extensions/featurePlacement.ts +118 -0
  27. package/src/extensions/image/ImageTool.ts +139 -157
  28. package/src/extensions/ruler/RulerTool.ts +24 -2
  29. package/src/shared/constants/layers.ts +2 -0
  30. package/tests/run.ts +37 -0
@@ -0,0 +1,227 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.buildDielineRenderBundle = buildDielineRenderBundle;
4
+ const geometry_1 = require("../geometry");
5
+ const featurePlacement_1 = require("../featurePlacement");
6
+ const layers_1 = require("../../shared/constants/layers");
7
+ const DEFAULT_IDS = {
8
+ inside: "dieline.inside",
9
+ bleedZone: "dieline.bleed-zone",
10
+ offsetBorder: "dieline.offset-border",
11
+ border: "dieline.border",
12
+ clip: "dieline.clip.image",
13
+ clipSource: "dieline.effect.clip-path",
14
+ };
15
+ function buildDielineRenderBundle(options) {
16
+ const ids = { ...DEFAULT_IDS, ...(options.ids || {}) };
17
+ const { state, sceneLayout, canvasWidth, canvasHeight, hasImages, createHatchPattern, includeImageClipEffect = true, clipTargetPassIds = [layers_1.IMAGE_OBJECT_LAYER_ID], clipVisibility, } = options;
18
+ const { shape, shapeStyle, radius, mainLine, offsetLine, insideColor } = state;
19
+ const scale = sceneLayout.scale;
20
+ const cx = sceneLayout.trimRect.centerX;
21
+ const cy = sceneLayout.trimRect.centerY;
22
+ const visualWidth = sceneLayout.trimRect.width;
23
+ const visualHeight = sceneLayout.trimRect.height;
24
+ const visualRadius = radius * scale;
25
+ const cutW = sceneLayout.cutRect.width;
26
+ const cutH = sceneLayout.cutRect.height;
27
+ const visualOffset = (cutW - visualWidth) / 2;
28
+ const cutR = visualRadius === 0 ? 0 : Math.max(0, visualRadius + visualOffset);
29
+ const placements = (0, featurePlacement_1.resolveFeaturePlacements)(state.features || [], {
30
+ shape,
31
+ shapeStyle,
32
+ pathData: state.pathData,
33
+ customSourceWidthPx: state.customSourceWidthPx,
34
+ customSourceHeightPx: state.customSourceHeightPx,
35
+ canvasWidth,
36
+ canvasHeight,
37
+ x: cx,
38
+ y: cy,
39
+ width: visualWidth,
40
+ height: visualHeight,
41
+ radius: visualRadius,
42
+ scale,
43
+ });
44
+ const absoluteFeatures = (0, featurePlacement_1.projectPlacedFeatures)(placements, {
45
+ x: cx,
46
+ y: cy,
47
+ width: visualWidth,
48
+ height: visualHeight,
49
+ }, scale);
50
+ const cutFeatures = (0, featurePlacement_1.projectPlacedFeatures)(placements.filter((placement) => !placement.feature.skipCut), {
51
+ x: cx,
52
+ y: cy,
53
+ width: cutW,
54
+ height: cutH,
55
+ }, scale);
56
+ const common = {
57
+ shape,
58
+ shapeStyle,
59
+ pathData: state.pathData,
60
+ customSourceWidthPx: state.customSourceWidthPx,
61
+ customSourceHeightPx: state.customSourceHeightPx,
62
+ canvasWidth,
63
+ canvasHeight,
64
+ };
65
+ const specs = [];
66
+ if (insideColor &&
67
+ insideColor !== "transparent" &&
68
+ insideColor !== "rgba(0,0,0,0)" &&
69
+ !hasImages) {
70
+ specs.push({
71
+ id: ids.inside,
72
+ type: "path",
73
+ space: "screen",
74
+ data: { id: ids.inside, type: "dieline" },
75
+ props: {
76
+ pathData: (0, geometry_1.generateDielinePath)({
77
+ ...common,
78
+ width: cutW,
79
+ height: cutH,
80
+ radius: cutR,
81
+ x: cx,
82
+ y: cy,
83
+ features: cutFeatures,
84
+ }),
85
+ fill: insideColor,
86
+ stroke: null,
87
+ selectable: false,
88
+ evented: false,
89
+ originX: "left",
90
+ originY: "top",
91
+ },
92
+ });
93
+ }
94
+ if (Math.abs(visualOffset) > 0.0001) {
95
+ const trimPathInput = {
96
+ ...common,
97
+ width: visualWidth,
98
+ height: visualHeight,
99
+ radius: visualRadius,
100
+ x: cx,
101
+ y: cy,
102
+ features: cutFeatures,
103
+ };
104
+ const cutPathInput = {
105
+ ...common,
106
+ width: cutW,
107
+ height: cutH,
108
+ radius: cutR,
109
+ x: cx,
110
+ y: cy,
111
+ features: cutFeatures,
112
+ };
113
+ if (state.showBleedLines !== false) {
114
+ const pattern = createHatchPattern?.(mainLine.color);
115
+ if (pattern) {
116
+ specs.push({
117
+ id: ids.bleedZone,
118
+ type: "path",
119
+ space: "screen",
120
+ data: { id: ids.bleedZone, type: "dieline" },
121
+ props: {
122
+ pathData: (0, geometry_1.generateBleedZonePath)(trimPathInput, cutPathInput, visualOffset),
123
+ fill: pattern,
124
+ stroke: null,
125
+ selectable: false,
126
+ evented: false,
127
+ objectCaching: false,
128
+ originX: "left",
129
+ originY: "top",
130
+ },
131
+ });
132
+ }
133
+ }
134
+ specs.push({
135
+ id: ids.offsetBorder,
136
+ type: "path",
137
+ space: "screen",
138
+ data: { id: ids.offsetBorder, type: "dieline" },
139
+ props: {
140
+ pathData: (0, geometry_1.generateDielinePath)(cutPathInput),
141
+ fill: null,
142
+ stroke: offsetLine.style === "hidden" ? null : offsetLine.color,
143
+ strokeWidth: offsetLine.width,
144
+ strokeDashArray: offsetLine.style === "dashed"
145
+ ? [offsetLine.dashLength, offsetLine.dashLength]
146
+ : undefined,
147
+ selectable: false,
148
+ evented: false,
149
+ originX: "left",
150
+ originY: "top",
151
+ },
152
+ });
153
+ }
154
+ specs.push({
155
+ id: ids.border,
156
+ type: "path",
157
+ space: "screen",
158
+ data: { id: ids.border, type: "dieline" },
159
+ props: {
160
+ pathData: (0, geometry_1.generateDielinePath)({
161
+ ...common,
162
+ width: visualWidth,
163
+ height: visualHeight,
164
+ radius: visualRadius,
165
+ x: cx,
166
+ y: cy,
167
+ features: absoluteFeatures,
168
+ }),
169
+ fill: "transparent",
170
+ stroke: mainLine.style === "hidden" ? null : mainLine.color,
171
+ strokeWidth: mainLine.width,
172
+ strokeDashArray: mainLine.style === "dashed"
173
+ ? [mainLine.dashLength, mainLine.dashLength]
174
+ : undefined,
175
+ selectable: false,
176
+ evented: false,
177
+ originX: "left",
178
+ originY: "top",
179
+ },
180
+ });
181
+ if (!includeImageClipEffect) {
182
+ return { specs, effects: [] };
183
+ }
184
+ const clipPathData = (0, geometry_1.generateDielinePath)({
185
+ ...common,
186
+ width: cutW,
187
+ height: cutH,
188
+ radius: cutR,
189
+ x: cx,
190
+ y: cy,
191
+ features: cutFeatures,
192
+ });
193
+ if (!clipPathData) {
194
+ return { specs, effects: [] };
195
+ }
196
+ return {
197
+ specs,
198
+ effects: [
199
+ {
200
+ type: "clipPath",
201
+ id: ids.clip,
202
+ visibility: clipVisibility,
203
+ targetPassIds: clipTargetPassIds,
204
+ source: {
205
+ id: ids.clipSource,
206
+ type: "path",
207
+ space: "screen",
208
+ data: {
209
+ id: ids.clipSource,
210
+ type: "dieline-effect",
211
+ effect: "clipPath",
212
+ },
213
+ props: {
214
+ pathData: clipPathData,
215
+ fill: "#000000",
216
+ stroke: null,
217
+ originX: "left",
218
+ originY: "top",
219
+ selectable: false,
220
+ evented: false,
221
+ excludeFromExport: true,
222
+ },
223
+ },
224
+ },
225
+ ],
226
+ };
227
+ }
@@ -2,13 +2,16 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.FeatureTool = void 0;
4
4
  const core_1 = require("@pooder/core");
5
- const geometry_1 = require("../geometry");
5
+ const fabric_1 = require("fabric");
6
6
  const constraints_1 = require("../constraints");
7
7
  const featureComplete_1 = require("../featureComplete");
8
+ const featurePlacement_1 = require("../featurePlacement");
8
9
  const sceneLayoutModel_1 = require("../../shared/scene/sceneLayoutModel");
9
10
  const layers_1 = require("../../shared/constants/layers");
10
11
  const subscriptions_1 = require("../../shared/runtime/subscriptions");
11
12
  const sessionState_1 = require("../../shared/runtime/sessionState");
13
+ const renderBuilder_1 = require("../dieline/renderBuilder");
14
+ const model_1 = require("../dieline/model");
12
15
  const FEATURE_STROKE_WIDTH = 2;
13
16
  const DEFAULT_RECT_SIZE = 10;
14
17
  const DEFAULT_CIRCLE_RADIUS = 5;
@@ -24,7 +27,9 @@ class FeatureTool {
24
27
  this.isFeatureSessionActive = false;
25
28
  this.sessionOriginalFeatures = null;
26
29
  this.hasWorkingChanges = false;
27
- this.specs = [];
30
+ this.markerSpecs = [];
31
+ this.sessionDielineSpecs = [];
32
+ this.sessionDielineEffects = [];
28
33
  this.renderSeq = 0;
29
34
  this.subscriptions = new subscriptions_1.SubscriptionBag();
30
35
  this.handleMoving = null;
@@ -34,7 +39,7 @@ class FeatureTool {
34
39
  this.onToolActivated = (event) => {
35
40
  this.isToolActive = event.id === this.id;
36
41
  if (!this.isToolActive) {
37
- this.restoreSessionFeaturesToConfig();
42
+ this.suspendFeatureSession();
38
43
  }
39
44
  this.updateVisibility();
40
45
  };
@@ -51,16 +56,35 @@ class FeatureTool {
51
56
  return;
52
57
  }
53
58
  this.renderProducerDisposable?.dispose();
54
- this.renderProducerDisposable = this.canvasService.registerRenderProducer(this.id, () => ({
55
- passes: [
59
+ this.renderProducerDisposable = this.canvasService.registerRenderProducer(this.id, () => {
60
+ const passes = [
56
61
  {
57
62
  id: layers_1.FEATURE_OVERLAY_LAYER_ID,
58
63
  stack: 880,
59
64
  order: 0,
60
- objects: this.specs,
65
+ replace: true,
66
+ objects: this.markerSpecs,
61
67
  },
62
- ],
63
- }), { priority: 350 });
68
+ ];
69
+ if (this.isSessionVisible()) {
70
+ passes.push({
71
+ id: layers_1.DIELINE_LAYER_ID,
72
+ stack: 700,
73
+ order: 0,
74
+ replace: false,
75
+ visibility: { op: "const", value: false },
76
+ objects: [],
77
+ }, {
78
+ id: layers_1.FEATURE_DIELINE_LAYER_ID,
79
+ stack: 705,
80
+ order: 0,
81
+ replace: true,
82
+ effects: this.sessionDielineEffects,
83
+ objects: this.sessionDielineSpecs,
84
+ });
85
+ }
86
+ return { passes };
87
+ }, { priority: 350 });
64
88
  const configService = context.services.get("ConfigurationService");
65
89
  if (configService) {
66
90
  const features = (configService.get("dieline.features", []) ||
@@ -71,13 +95,22 @@ class FeatureTool {
71
95
  if (this.isUpdatingConfig)
72
96
  return;
73
97
  if (e.key === "dieline.features") {
74
- if (this.isFeatureSessionActive)
98
+ if (this.isFeatureSessionActive && this.hasFeatureSessionDraft()) {
75
99
  return;
100
+ }
101
+ if (this.hasFeatureSessionDraft()) {
102
+ this.clearFeatureSessionState();
103
+ }
76
104
  const next = (e.value || []);
77
105
  this.workingFeatures = this.cloneFeatures(next);
78
106
  this.hasWorkingChanges = false;
79
107
  this.redraw();
80
108
  this.emitWorkingChange();
109
+ return;
110
+ }
111
+ if (e.key.startsWith("size.") || e.key.startsWith("dieline.")) {
112
+ void this.refreshGeometry();
113
+ this.redraw({ enforceConstraints: true });
81
114
  }
82
115
  });
83
116
  }
@@ -88,7 +121,8 @@ class FeatureTool {
88
121
  }
89
122
  deactivate(context) {
90
123
  this.subscriptions.disposeAll();
91
- this.restoreSessionFeaturesToConfig();
124
+ this.restoreCommittedFeaturesToConfig();
125
+ this.clearFeatureSessionState();
92
126
  this.dirtyTrackerDisposable?.dispose();
93
127
  this.dirtyTrackerDisposable = undefined;
94
128
  this.teardown();
@@ -98,6 +132,9 @@ class FeatureTool {
98
132
  updateVisibility() {
99
133
  this.redraw();
100
134
  }
135
+ isSessionVisible() {
136
+ return this.isToolActive && this.isFeatureSessionActive;
137
+ }
101
138
  contribute() {
102
139
  return {
103
140
  [core_1.ContributionPointIds.TOOLS]: [
@@ -124,15 +161,16 @@ class FeatureTool {
124
161
  if (this.isFeatureSessionActive) {
125
162
  return { ok: true };
126
163
  }
127
- const original = this.getCommittedFeatures();
128
- this.sessionOriginalFeatures = this.cloneFeatures(original);
164
+ if (!this.hasFeatureSessionDraft()) {
165
+ const original = this.getCommittedFeatures();
166
+ this.sessionOriginalFeatures = this.cloneFeatures(original);
167
+ this.setWorkingFeatures(this.cloneFeatures(original));
168
+ this.hasWorkingChanges = false;
169
+ }
129
170
  this.isFeatureSessionActive = true;
130
171
  await this.refreshGeometry();
131
- this.setWorkingFeatures(this.cloneFeatures(original));
132
- this.hasWorkingChanges = false;
133
172
  this.redraw();
134
173
  this.emitWorkingChange();
135
- this.updateCommittedFeatures([]);
136
174
  return { ok: true };
137
175
  },
138
176
  },
@@ -168,25 +206,6 @@ class FeatureTool {
168
206
  return true;
169
207
  },
170
208
  },
171
- {
172
- command: "getWorkingFeatures",
173
- title: "Get Working Features",
174
- handler: () => {
175
- return this.cloneFeatures(this.workingFeatures);
176
- },
177
- },
178
- {
179
- command: "setWorkingFeatures",
180
- title: "Set Working Features",
181
- handler: async (features) => {
182
- await this.refreshGeometry();
183
- this.setWorkingFeatures(this.cloneFeatures(features || []));
184
- this.hasWorkingChanges = true;
185
- this.redraw();
186
- this.emitWorkingChange();
187
- return { ok: true };
188
- },
189
- },
190
209
  {
191
210
  command: "rollbackFeatureSession",
192
211
  title: "Rollback Feature Session",
@@ -251,16 +270,24 @@ class FeatureTool {
251
270
  this.isUpdatingConfig = false;
252
271
  }
253
272
  }
273
+ hasFeatureSessionDraft() {
274
+ return Array.isArray(this.sessionOriginalFeatures);
275
+ }
254
276
  clearFeatureSessionState() {
255
277
  this.isFeatureSessionActive = false;
256
278
  this.sessionOriginalFeatures = null;
257
279
  }
258
- restoreSessionFeaturesToConfig() {
259
- if (!this.isFeatureSessionActive)
280
+ restoreCommittedFeaturesToConfig() {
281
+ if (!this.hasFeatureSessionDraft())
260
282
  return;
261
283
  const original = this.cloneFeatures(this.sessionOriginalFeatures || this.getCommittedFeatures());
262
284
  this.updateCommittedFeatures(original);
263
- this.clearFeatureSessionState();
285
+ }
286
+ suspendFeatureSession() {
287
+ if (!this.isFeatureSessionActive)
288
+ return;
289
+ this.restoreCommittedFeaturesToConfig();
290
+ this.isFeatureSessionActive = false;
264
291
  }
265
292
  emitWorkingChange() {
266
293
  this.context?.eventBus.emit("feature:working:change", {
@@ -281,9 +308,7 @@ class FeatureTool {
281
308
  catch (e) { }
282
309
  }
283
310
  async resetWorkingFeaturesFromSource() {
284
- const next = this.cloneFeatures(this.isFeatureSessionActive && this.sessionOriginalFeatures
285
- ? this.sessionOriginalFeatures
286
- : this.getCommittedFeatures());
311
+ const next = this.cloneFeatures(this.sessionOriginalFeatures || this.getCommittedFeatures());
287
312
  await this.refreshGeometry();
288
313
  this.setWorkingFeatures(next);
289
314
  this.hasWorkingChanges = false;
@@ -493,11 +518,35 @@ class FeatureTool {
493
518
  this.handleSceneGeometryChange = null;
494
519
  }
495
520
  this.renderSeq += 1;
496
- this.specs = [];
521
+ this.markerSpecs = [];
522
+ this.sessionDielineSpecs = [];
523
+ this.sessionDielineEffects = [];
497
524
  this.renderProducerDisposable?.dispose();
498
525
  this.renderProducerDisposable = undefined;
499
526
  void this.canvasService.flushRenderFromProducers();
500
527
  }
528
+ createHatchPattern(color = "rgba(0, 0, 0, 0.3)") {
529
+ if (typeof document === "undefined") {
530
+ return undefined;
531
+ }
532
+ const size = 20;
533
+ const canvas = document.createElement("canvas");
534
+ canvas.width = size;
535
+ canvas.height = size;
536
+ const ctx = canvas.getContext("2d");
537
+ if (ctx) {
538
+ ctx.clearRect(0, 0, size, size);
539
+ ctx.strokeStyle = color;
540
+ ctx.lineWidth = 1;
541
+ ctx.beginPath();
542
+ ctx.moveTo(0, size);
543
+ ctx.lineTo(size, 0);
544
+ ctx.stroke();
545
+ }
546
+ return new fabric_1.Pattern({
547
+ source: canvas,
548
+ });
549
+ }
501
550
  getDraggableMarkerTarget(target) {
502
551
  if (!this.isFeatureSessionActive || !this.isToolActive)
503
552
  return null;
@@ -567,6 +616,7 @@ class FeatureTool {
567
616
  next[index] = updatedFeature;
568
617
  this.setWorkingFeatures(next);
569
618
  this.hasWorkingChanges = true;
619
+ this.redraw();
570
620
  this.emitWorkingChange();
571
621
  }
572
622
  syncGroupFromCanvas(target) {
@@ -605,6 +655,7 @@ class FeatureTool {
605
655
  return;
606
656
  this.setWorkingFeatures(next);
607
657
  this.hasWorkingChanges = true;
658
+ this.redraw();
608
659
  this.emitWorkingChange();
609
660
  }
610
661
  redraw(options = {}) {
@@ -614,7 +665,10 @@ class FeatureTool {
614
665
  if (!this.canvasService)
615
666
  return;
616
667
  const seq = ++this.renderSeq;
617
- this.specs = this.buildFeatureSpecs();
668
+ this.markerSpecs = this.buildMarkerSpecs();
669
+ const sessionRender = this.buildSessionDielineRender();
670
+ this.sessionDielineSpecs = sessionRender.specs;
671
+ this.sessionDielineEffects = sessionRender.effects;
618
672
  if (seq !== this.renderSeq)
619
673
  return;
620
674
  await this.canvasService.flushRenderFromProducers();
@@ -624,7 +678,47 @@ class FeatureTool {
624
678
  this.enforceConstraints();
625
679
  }
626
680
  }
627
- buildFeatureSpecs() {
681
+ buildSessionDielineRender() {
682
+ if (!this.isSessionVisible() || !this.canvasService) {
683
+ return { specs: [], effects: [] };
684
+ }
685
+ const configService = this.getConfigService();
686
+ if (!configService) {
687
+ return { specs: [], effects: [] };
688
+ }
689
+ const sceneLayout = (0, sceneLayoutModel_1.computeSceneLayout)(this.canvasService, (0, sceneLayoutModel_1.readSizeState)(configService));
690
+ if (!sceneLayout) {
691
+ return { specs: [], effects: [] };
692
+ }
693
+ const state = (0, model_1.readDielineState)(configService);
694
+ state.features = this.cloneFeatures(this.workingFeatures);
695
+ return (0, renderBuilder_1.buildDielineRenderBundle)({
696
+ state,
697
+ sceneLayout,
698
+ canvasWidth: sceneLayout.canvasWidth || this.canvasService.canvas.width || 800,
699
+ canvasHeight: sceneLayout.canvasHeight || this.canvasService.canvas.height || 600,
700
+ hasImages: this.hasImageItems(),
701
+ createHatchPattern: (color) => this.createHatchPattern(color),
702
+ clipTargetPassIds: [layers_1.IMAGE_OBJECT_LAYER_ID],
703
+ clipVisibility: { op: "const", value: true },
704
+ ids: {
705
+ inside: "feature.session.dieline.inside",
706
+ bleedZone: "feature.session.dieline.bleed-zone",
707
+ offsetBorder: "feature.session.dieline.offset-border",
708
+ border: "feature.session.dieline.border",
709
+ clip: "feature.session.dieline.clip.image",
710
+ clipSource: "feature.session.dieline.effect.clip-path",
711
+ },
712
+ });
713
+ }
714
+ hasImageItems() {
715
+ const configService = this.getConfigService();
716
+ if (!configService)
717
+ return false;
718
+ const items = configService.get("image.items", []);
719
+ return Array.isArray(items) && items.length > 0;
720
+ }
721
+ buildMarkerSpecs() {
628
722
  if (!this.isFeatureSessionActive ||
629
723
  !this.currentGeometry ||
630
724
  this.workingFeatures.length === 0) {
@@ -632,9 +726,26 @@ class FeatureTool {
632
726
  }
633
727
  const groups = new Map();
634
728
  const singles = [];
635
- this.workingFeatures.forEach((feature, index) => {
729
+ const placements = (0, featurePlacement_1.resolveFeaturePlacements)(this.workingFeatures, {
730
+ shape: this.currentGeometry.shape,
731
+ shapeStyle: this.currentGeometry.shapeStyle,
732
+ pathData: this.currentGeometry.pathData,
733
+ customSourceWidthPx: this.currentGeometry.customSourceWidthPx,
734
+ customSourceHeightPx: this.currentGeometry.customSourceHeightPx,
735
+ x: this.currentGeometry.x,
736
+ y: this.currentGeometry.y,
737
+ width: this.currentGeometry.width,
738
+ height: this.currentGeometry.height,
739
+ radius: this.currentGeometry.radius,
740
+ scale: this.currentGeometry.scale || 1,
741
+ });
742
+ placements.forEach((placement, index) => {
743
+ const feature = placement.feature;
636
744
  const geometry = this.getGeometryForFeature(this.currentGeometry, feature);
637
- const position = (0, geometry_1.resolveFeaturePosition)(feature, geometry);
745
+ const position = {
746
+ x: placement.centerX,
747
+ y: placement.centerY,
748
+ };
638
749
  const scale = geometry.scale || 1;
639
750
  const marker = {
640
751
  feature,
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.resolveFeaturePosition = resolveFeaturePosition;
4
+ exports.normalizePointInGeometry = normalizePointInGeometry;
5
+ function resolveFeaturePosition(feature, geometry) {
6
+ const { x, y, width, height } = geometry;
7
+ const left = x - width / 2;
8
+ const top = y - height / 2;
9
+ return {
10
+ x: left + feature.x * width,
11
+ y: top + feature.y * height,
12
+ };
13
+ }
14
+ function normalizePointInGeometry(point, geometry) {
15
+ const left = geometry.x - geometry.width / 2;
16
+ const top = geometry.y - geometry.height / 2;
17
+ return {
18
+ x: geometry.width > 0 ? (point.x - left) / geometry.width : 0.5,
19
+ y: geometry.height > 0 ? (point.y - top) / geometry.height : 0.5,
20
+ };
21
+ }
@@ -0,0 +1,46 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.resolveFeaturePlacements = resolveFeaturePlacements;
4
+ exports.projectPlacedFeatures = projectPlacedFeatures;
5
+ const constraints_1 = require("./constraints");
6
+ const featureCoordinates_1 = require("./featureCoordinates");
7
+ function scaleFeatureForRender(feature, scale, x, y) {
8
+ return {
9
+ ...feature,
10
+ x,
11
+ y,
12
+ width: feature.width !== undefined ? feature.width * scale : undefined,
13
+ height: feature.height !== undefined ? feature.height * scale : undefined,
14
+ radius: feature.radius !== undefined ? feature.radius * scale : undefined,
15
+ };
16
+ }
17
+ function resolveFeaturePlacements(features, geometry) {
18
+ const dielineWidth = geometry.scale > 0 ? geometry.width / geometry.scale : geometry.width;
19
+ const dielineHeight = geometry.scale > 0 ? geometry.height / geometry.scale : geometry.height;
20
+ return (features || []).map((feature) => {
21
+ const activeConstraints = feature.constraints?.filter((constraint) => !constraint.validateOnly);
22
+ const constrained = constraints_1.ConstraintRegistry.apply(feature.x, feature.y, feature, {
23
+ dielineWidth,
24
+ dielineHeight,
25
+ geometry,
26
+ }, activeConstraints);
27
+ const center = (0, featureCoordinates_1.resolveFeaturePosition)({
28
+ ...feature,
29
+ x: constrained.x,
30
+ y: constrained.y,
31
+ }, geometry);
32
+ return {
33
+ feature,
34
+ normalizedX: constrained.x,
35
+ normalizedY: constrained.y,
36
+ centerX: center.x,
37
+ centerY: center.y,
38
+ };
39
+ });
40
+ }
41
+ function projectPlacedFeatures(placements, geometry, scale) {
42
+ return placements.map((placement) => {
43
+ const normalized = (0, featureCoordinates_1.normalizePointInGeometry)({ x: placement.centerX, y: placement.centerY }, geometry);
44
+ return scaleFeatureForRender(placement.feature, scale, normalized.x, normalized.y);
45
+ });
46
+ }