@orbat-mapper/tactical-draw 0.2.0-alpha.20 → 0.2.0-alpha.21

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 (2) hide show
  1. package/dist/index.mjs +55 -35
  2. package/package.json +1 -1
package/dist/index.mjs CHANGED
@@ -2088,6 +2088,34 @@ function boxToHandles(box, fromPixel) {
2088
2088
  return handles;
2089
2089
  }
2090
2090
  /**
2091
+ * The group's outline style: the resolved `boxOutline` plus `[4, 4]` dash so
2092
+ * the group reads as dashed per the reference design — unless the host
2093
+ * explicitly set their own `strokeDash`, which wins. Shared by
2094
+ * `transform-controller.ts` and `graphic-transform-controller.ts` so their
2095
+ * group boxes can't drift apart (member outlines stay solid).
2096
+ */
2097
+ function groupOutlineStyle(base) {
2098
+ if (base?.strokeDash !== void 0) return base;
2099
+ return {
2100
+ ...base ?? {},
2101
+ strokeDash: [4, 4]
2102
+ };
2103
+ }
2104
+ /**
2105
+ * Build the per-member outline features for a group transform — one closed
2106
+ * `LineString` per `[memberId, box]` pair, id'd
2107
+ * `${handleIdPrefix}:member-outline:{memberId}` and styled with the plain
2108
+ * (solid) `boxOutline`. Shared by `transform-controller.ts` and
2109
+ * `graphic-transform-controller.ts` so member outlines can't drift between
2110
+ * the measures-only and mixed-graphic group transforms — only the group box
2111
+ * gets the dashed default (`groupOutlineStyle`).
2112
+ */
2113
+ function memberOutlineFeatures(members, fromPixel, handleIdPrefix, style) {
2114
+ const features = [];
2115
+ for (const [memberId, box] of members) features.push(boxOutlineFeature(box, fromPixel, `${handleIdPrefix}:member-outline:${memberId}`, style));
2116
+ return features;
2117
+ }
2118
+ /**
2091
2119
  * Build the closed `LineString` outline feature for `box`, styled from
2092
2120
  * `style` (delivered per-feature via `properties.style`, as the adapters
2093
2121
  * already honor for line features). `featureId` is the caller's stable id —
@@ -3692,32 +3720,15 @@ function runGroupTransform(opts) {
3692
3720
  else refitBoxes();
3693
3721
  renderHandlesLayer();
3694
3722
  }
3695
- /**
3696
- * The group's outline style: the resolved `boxOutline` plus `[4, 4]` dash
3697
- * so the group reads as dashed per the reference design — unless the host
3698
- * explicitly set their own `strokeDash`, which wins.
3699
- */
3700
- function groupOutlineStyle() {
3701
- const base = interactionStyle?.boxOutline;
3702
- if (base?.strokeDash !== void 0) return base;
3703
- return {
3704
- ...base ?? {},
3705
- strokeDash: [4, 4]
3706
- };
3707
- }
3708
3723
  function renderHandlesLayer() {
3709
3724
  if (ctx.settled) return;
3710
3725
  const features = [];
3711
3726
  const liveGroupBox = activeBoxDrag ? activeBoxDrag.lastSnapshot.box : groupBox;
3712
3727
  if (liveGroupBox) {
3713
- features.push(boxOutlineFeature(liveGroupBox, dragProjection.fromPixel, `${handleIdPrefix}:box-outline`, groupOutlineStyle()));
3728
+ features.push(boxOutlineFeature(liveGroupBox, dragProjection.fromPixel, `${handleIdPrefix}:box-outline`, groupOutlineStyle(interactionStyle?.boxOutline)));
3714
3729
  features.push(...toFeatures(boxToHandles(liveGroupBox, dragProjection.fromPixel), handleIdPrefix, interactionStyle));
3715
3730
  }
3716
- for (const member of members) {
3717
- const memberBox = member.box;
3718
- if (!memberBox) continue;
3719
- features.push(boxOutlineFeature(memberBox, dragProjection.fromPixel, `${handleIdPrefix}:member-outline:${member.measure.id}`, interactionStyle?.boxOutline));
3720
- }
3731
+ features.push(...memberOutlineFeatures(members.flatMap((member) => member.box ? [[member.measure.id, member.box]] : []), dragProjection.fromPixel, handleIdPrefix, interactionStyle?.boxOutline));
3721
3732
  ctx.writeLayer(handlesLayer, features);
3722
3733
  }
3723
3734
  /**
@@ -4273,23 +4284,31 @@ function runGraphicTransform(opts) {
4273
4284
  const features = [];
4274
4285
  const resources = /* @__PURE__ */ new Map();
4275
4286
  const pixels = [];
4276
- for (const graphic of working) if (isPointSymbol(graphic)) {
4277
- const plan = renderPointSymbolForAdapter(adapter, capability, graphic);
4278
- resources.set(plan.resource.id, plan.resource);
4279
- features.push(plan.feature);
4280
- const footprint = pointSymbolFootprint(graphic, plan.render, adapter);
4281
- if (footprint) pixels.push(...footprint.corners);
4282
- } else {
4283
- const rendered = renderMeasureForAdapter(adapter, graphic, renderOpts);
4284
- features.push(...rendered.features);
4285
- for (const feature of rendered.features) {
4286
- const positions = [];
4287
- if (feature.geometry) collectFeaturePositions(feature.geometry, positions);
4288
- for (const position of positions) {
4289
- const pixel = driver.toPixel(position);
4290
- if (pixel) pixels.push(pixel);
4287
+ const memberBoxes = [];
4288
+ const angle = drag ? drag.liveBox.angle : boxAngle;
4289
+ for (const graphic of working) {
4290
+ const graphicPixels = [];
4291
+ if (isPointSymbol(graphic)) {
4292
+ const plan = renderPointSymbolForAdapter(adapter, capability, graphic);
4293
+ resources.set(plan.resource.id, plan.resource);
4294
+ features.push(plan.feature);
4295
+ const footprint = pointSymbolFootprint(graphic, plan.render, adapter);
4296
+ if (footprint) graphicPixels.push(...footprint.corners);
4297
+ } else {
4298
+ const rendered = renderMeasureForAdapter(adapter, graphic, renderOpts);
4299
+ features.push(...rendered.features);
4300
+ for (const feature of rendered.features) {
4301
+ const positions = [];
4302
+ if (feature.geometry) collectFeaturePositions(feature.geometry, positions);
4303
+ for (const position of positions) {
4304
+ const pixel = driver.toPixel(position);
4305
+ if (pixel) graphicPixels.push(pixel);
4306
+ }
4291
4307
  }
4292
4308
  }
4309
+ pixels.push(...graphicPixels);
4310
+ const memberBox = fitTransformBox(graphicPixels, angle, interactionStyle?.boxPadding);
4311
+ if (memberBox) memberBoxes.push([graphic.id, memberBox]);
4293
4312
  }
4294
4313
  adapter.reconcileLayerIconResources(previewLayer, [...resources.values()]);
4295
4314
  ctx.writeLayer(previewLayer, features);
@@ -4297,9 +4316,10 @@ function runGraphicTransform(opts) {
4297
4316
  const liveBox = drag?.liveBox ?? box;
4298
4317
  const handles = [];
4299
4318
  if (liveBox) {
4300
- handles.push(boxOutlineFeature(liveBox, (pixel) => driver.fromPixel(pixel), `${handleIdPrefix}:box-outline`, interactionStyle?.boxOutline));
4319
+ handles.push(boxOutlineFeature(liveBox, (pixel) => driver.fromPixel(pixel), `${handleIdPrefix}:box-outline`, groupOutlineStyle(interactionStyle?.boxOutline)));
4301
4320
  handles.push(...toFeatures(boxToHandles(liveBox, (pixel) => driver.fromPixel(pixel)), handleIdPrefix, interactionStyle));
4302
4321
  }
4322
+ handles.push(...memberOutlineFeatures(memberBoxes, (pixel) => driver.fromPixel(pixel), handleIdPrefix, interactionStyle?.boxOutline));
4303
4323
  ctx.writeLayer(handlesLayer, handles);
4304
4324
  }
4305
4325
  function anchorPoints(source) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@orbat-mapper/tactical-draw",
3
- "version": "0.2.0-alpha.20",
3
+ "version": "0.2.0-alpha.21",
4
4
  "description": "Engine-agnostic draw/edit core for tactical control measures (MIL-STD-2525 / APP-6). The MapAdapter ABI and bring-your-own-engine entry point for the tactical-draw package family.",
5
5
  "license": "MIT",
6
6
  "author": "Orbat Mapper",