@orbat-mapper/tactical-draw 0.9.0 → 0.9.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/dist/index.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { A as PinOverridePatch, B as resolvePinPresentation, C as makeFillPatternImage, D as PointerEventInfo, E as PointerCallback, F as PinPresentationStatus, I as PinPresentationStatusEvent, L as PinPresentationStore, M as PinPresentationCapability, N as PinPresentationPatch, O as DEFAULT_PIN_PRESENTATION, P as PinPresentationState, R as PinRender, S as isMinePattern, T as EditPointerDriver, _ as HatchPattern, a as LayerId, b as fillPatternImageDimension, c as MapEvent, d as PickHandler, f as PickOptions, g as HATCH_PATTERNS, h as TextStyleOptions, i as ImageOverlayResource, j as PinPresentation, k as PinFootprint, l as MapEventHandler, m as StyleOptions, n as HandleStyle, o as MapAdapter, p as PixelCoordinate, r as IconResource, s as MapCursor, t as FeatureGroup, u as PickEvent, v as MINE_PATTERN_TILE_SIZE, w as parseColor, x as fillPatternImageId, y as Rgba, z as isValidPinNumber } from "./map-adapter-azR_hVjj.mjs";
1
+ import { A as PinOverridePatch, B as resolvePinPresentation, C as makeFillPatternImage, D as PointerEventInfo, E as PointerCallback, F as PinPresentationStatus, I as PinPresentationStatusEvent, L as PinPresentationStore, M as PinPresentationCapability, N as PinPresentationPatch, O as DEFAULT_PIN_PRESENTATION, P as PinPresentationState, R as PinRender, S as isMinePattern, T as EditPointerDriver, _ as HatchPattern, a as LayerId, b as fillPatternImageDimension, c as MapEvent, d as PickHandler, f as PickOptions, g as HATCH_PATTERNS, h as TextStyleOptions, i as ImageOverlayResource, j as PinPresentation, k as PinFootprint, l as MapEventHandler, m as StyleOptions, n as HandleStyle, o as MapAdapter, p as PixelCoordinate, r as IconResource, s as MapCursor, t as FeatureGroup, u as PickEvent, v as MINE_PATTERN_TILE_SIZE, w as parseColor, x as fillPatternImageId, y as Rgba, z as isValidPinNumber } from "./map-adapter-DY-iZRcb.mjs";
2
2
  import { AmplifierPlacement, AmplifierPlacements, ControlMeasure, ControlMeasureKind, ControlMeasureRender, ControlMeasureStyle, SymbolColors, TextAmplifiers } from "@orbat-mapper/control-measures";
3
3
  import { Feature, Position } from "geojson";
4
4
 
package/dist/index.mjs CHANGED
@@ -1088,7 +1088,11 @@ function createCommitEmitter(listenerErrorsMessage) {
1088
1088
  //#endregion
1089
1089
  //#region src/pin-presentation.ts
1090
1090
  function validateOverride(patch) {
1091
- for (const key of ["mode", "occlusion"]) if (Object.hasOwn(patch, key)) throw new TypeError(`Pin setting ${key} is view-wide only`);
1091
+ for (const key of [
1092
+ "mode",
1093
+ "occlusion",
1094
+ "prioritizePins"
1095
+ ]) if (Object.hasOwn(patch, key)) throw new TypeError(`Pin setting ${key} is view-wide only`);
1092
1096
  }
1093
1097
  const DEFAULT_PIN_PRESENTATION = Object.freeze({
1094
1098
  enabled: false,
@@ -1097,6 +1101,7 @@ const DEFAULT_PIN_PRESENTATION = Object.freeze({
1097
1101
  heightMeters: 250,
1098
1102
  sizePixels: 32,
1099
1103
  occlusion: "none",
1104
+ prioritizePins: true,
1100
1105
  stem: Object.freeze({
1101
1106
  color: "#172033",
1102
1107
  width: 2,
@@ -6062,6 +6067,15 @@ function runGroupTransform(opts) {
6062
6067
  }
6063
6068
  return pixels;
6064
6069
  }
6070
+ /** An axis-aligned {@link TransformBox} spanning a min/max pixel extent. */
6071
+ function boxFromPixelBounds(min, max) {
6072
+ return {
6073
+ center: [(min[0] + max[0]) / 2, (min[1] + max[1]) / 2],
6074
+ halfWidth: (max[0] - min[0]) / 2,
6075
+ halfHeight: (max[1] - min[1]) / 2,
6076
+ angle: 0
6077
+ };
6078
+ }
6065
6079
  /** The rotated-text footprint corners for a Text member's rendered feature, or `null`. */
6066
6080
  function textFootprintCorners(features) {
6067
6081
  const box = fitTextFootprintFromFeatures(features, driver.toPixel, {
@@ -6127,6 +6141,7 @@ function runGroupTransform(opts) {
6127
6141
  let features;
6128
6142
  let iconResources = [];
6129
6143
  let imageOverlays;
6144
+ let pinGroup;
6130
6145
  let boxPixels = [];
6131
6146
  if (isImageMember(member)) {
6132
6147
  const image = buildWorkingImage(member);
@@ -6138,11 +6153,23 @@ function runGroupTransform(opts) {
6138
6153
  } else try {
6139
6154
  if (isPointSymbolMember(member)) {
6140
6155
  const symbol = buildWorkingPointSymbol(member);
6141
- const plan = renderPointSymbolForAdapter(adapter, capability, symbol);
6142
- iconResources = [plan.resource];
6143
- features = plan.features;
6144
- const footprint = pointSymbolFootprint(symbol, plan.render, adapter);
6145
- if (footprint) boxPixels = footprint.corners;
6156
+ pinGroup = opts.renderPin?.(symbol);
6157
+ if (pinGroup?.pin) {
6158
+ features = pinGroup.features;
6159
+ iconResources = pinGroup.iconResources;
6160
+ const pinFootprint = adapter.getPinFootprint?.(symbol.id);
6161
+ if (pinFootprint) boxPixels = boxCorners(boxFromPixelBounds(pinFootprint.min, pinFootprint.max));
6162
+ else {
6163
+ const footprint = pointSymbolFootprint(symbol, renderPointSymbolForAdapter(adapter, capability, symbol).render, adapter);
6164
+ if (footprint) boxPixels = footprint.corners;
6165
+ }
6166
+ } else {
6167
+ const plan = renderPointSymbolForAdapter(adapter, capability, symbol);
6168
+ iconResources = [plan.resource];
6169
+ features = plan.features;
6170
+ const footprint = pointSymbolFootprint(symbol, plan.render, adapter);
6171
+ if (footprint) boxPixels = footprint.corners;
6172
+ }
6146
6173
  } else {
6147
6174
  const working = workingGraphicFor(i);
6148
6175
  features = renderMeasureForAdapter(adapter, working, renderOpts).features;
@@ -6153,16 +6180,11 @@ function runGroupTransform(opts) {
6153
6180
  boxPixels = [];
6154
6181
  }
6155
6182
  member.lastBoxPixels = boxPixels;
6156
- if (member.usesGraphicStack) workingGroups.push({
6157
- id: member.graphic.id,
6158
- features,
6159
- iconResources,
6160
- ...imageOverlays ? { imageOverlays } : {}
6161
- });
6162
- else previewGroups.push({
6183
+ (member.usesGraphicStack ? workingGroups : previewGroups).push({
6163
6184
  id: member.graphic.id,
6164
6185
  features,
6165
6186
  iconResources,
6187
+ ...pinGroup?.pin ? { pin: pinGroup.pin } : {},
6166
6188
  ...imageOverlays ? { imageOverlays } : {}
6167
6189
  });
6168
6190
  });
@@ -6983,6 +7005,13 @@ function runPointSymbolEdit(opts) {
6983
7005
  }
6984
7006
  };
6985
7007
  const pointerAngle = (pixel, anchor) => Math.atan2(pixel[1] - anchor[1], pixel[0] - anchor[0]);
7008
+ const snapTranslate = (position, fallbackPixel, info) => snap?.({
7009
+ coordinate: position,
7010
+ pixel: driver.toPixel(position) ?? fallbackPixel,
7011
+ interaction: "translate",
7012
+ graphicId: symbol.id,
7013
+ originalEvent: info?.native
7014
+ })?.coordinate ?? position;
6986
7015
  const onDown = (pixel, info) => {
6987
7016
  if (pinEditing && opts.canRenderPin?.() && !ctx.settled) {
6988
7017
  const footprint = adapter.getPinFootprint?.(working.id);
@@ -7031,11 +7060,13 @@ function runPointSymbolEdit(opts) {
7031
7060
  };
7032
7061
  const transformed = (pixel, info) => {
7033
7062
  if (pinDrag) {
7034
- const position = adapter.movePinFromPixel?.(working.id, [pinDrag.attachment[0] + pixel[0] - pinDrag.down[0], pinDrag.attachment[1] + pixel[1] - pinDrag.down[1]]);
7035
- return position ? {
7063
+ const attachment = [pinDrag.attachment[0] + pixel[0] - pinDrag.down[0], pinDrag.attachment[1] + pixel[1] - pinDrag.down[1]];
7064
+ const position = adapter.movePinFromPixel?.(working.id, attachment);
7065
+ if (!position) return null;
7066
+ return {
7036
7067
  ...clonePointSymbol(pinDrag.start),
7037
- position
7038
- } : null;
7068
+ position: snapTranslate(position, attachment, info)
7069
+ };
7039
7070
  }
7040
7071
  if (!drag) return null;
7041
7072
  let next = clonePointSymbol(drag.start);
@@ -7061,15 +7092,7 @@ function runPointSymbolEdit(opts) {
7061
7092
  return next;
7062
7093
  }
7063
7094
  if (drag.kind === "body" || drag.kind === "location") {
7064
- const unsnappedPosition = driver.fromPixel([drag.anchor[0] + pixel[0] - drag.down[0], drag.anchor[1] + pixel[1] - drag.down[1]]);
7065
- const anchorPixel = driver.toPixel(unsnappedPosition) ?? pixel;
7066
- const position = (snap?.({
7067
- coordinate: unsnappedPosition,
7068
- pixel: anchorPixel,
7069
- interaction: "translate",
7070
- graphicId: symbol.id,
7071
- originalEvent: info?.native
7072
- }))?.coordinate ?? unsnappedPosition;
7095
+ const position = snapTranslate(driver.fromPixel([drag.anchor[0] + pixel[0] - drag.down[0], drag.anchor[1] + pixel[1] - drag.down[1]]), pixel, info);
7073
7096
  if (drag.kind === "location") return movePointSymbolLocation(next, intrinsic, adapter, position);
7074
7097
  next.position = position;
7075
7098
  if (next.offset?.placement.mode === "ground") {
@@ -8484,6 +8507,7 @@ var TacticalDraw = class {
8484
8507
  adapter: this.adapter,
8485
8508
  capability: this.pointSymbols,
8486
8509
  imageCapability: this.images,
8510
+ ...this.pointSymbols ? { renderPin: (symbol) => this.buildGraphicGroup(symbol) } : {},
8487
8511
  graphics: measures,
8488
8512
  graphicsLayer: this.graphicsLayer,
8489
8513
  previewLayer: this.previewLayer,
@@ -10,6 +10,7 @@ interface PinPresentation {
10
10
  heightMeters: number;
11
11
  sizePixels: number;
12
12
  occlusion: "none" | "terrain";
13
+ prioritizePins: boolean;
13
14
  stem: {
14
15
  color: string;
15
16
  width: number;
@@ -48,7 +49,7 @@ type PinPresentationPatch = Partial<Omit<PinPresentation, "stem" | "dot" | "halo
48
49
  plate?: Partial<PinPresentation["plate"]>;
49
50
  };
50
51
  /** Per-unit appearance and dimensions; spatial rules belong to the view. */
51
- type PinOverridePatch = Omit<PinPresentationPatch, "mode" | "occlusion">;
52
+ type PinOverridePatch = Omit<PinPresentationPatch, "mode" | "occlusion" | "prioritizePins">;
52
53
  interface PinPresentationState {
53
54
  defaults: PinPresentationPatch;
54
55
  overrides: Record<string, PinOverridePatch>;
@@ -1,4 +1,4 @@
1
- import { a as LayerId, o as MapAdapter, p as PixelCoordinate } from "./map-adapter-azR_hVjj.mjs";
1
+ import { a as LayerId, o as MapAdapter, p as PixelCoordinate } from "./map-adapter-DY-iZRcb.mjs";
2
2
  import { Feature } from "geojson";
3
3
 
4
4
  //#region src/testing/feature-group-conformance.d.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@orbat-mapper/tactical-draw",
3
- "version": "0.9.0",
3
+ "version": "0.9.2",
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",