@orbat-mapper/tactical-draw 0.8.1 → 0.9.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.
@@ -1,6 +1,106 @@
1
1
  import { PatternId } from "@orbat-mapper/control-measures";
2
2
  import { Feature, Position } from "geojson";
3
3
 
4
+ //#region src/pin-presentation.d.ts
5
+ /** View preferences, never part of an authored PointSymbol snapshot. */
6
+ interface PinPresentation {
7
+ enabled: boolean;
8
+ mode: "screen" | "world";
9
+ liftPixels: number;
10
+ heightMeters: number;
11
+ sizePixels: number;
12
+ occlusion: "none" | "terrain";
13
+ stem: {
14
+ color: string;
15
+ width: number;
16
+ opacity: number;
17
+ };
18
+ dot: {
19
+ color: string;
20
+ radius: number;
21
+ opacity: number;
22
+ };
23
+ halo: {
24
+ color: string;
25
+ width: number;
26
+ opacity: number;
27
+ };
28
+ symbolHalo: {
29
+ color: string;
30
+ width: number;
31
+ opacity: number;
32
+ };
33
+ plate: {
34
+ enabled: boolean;
35
+ color: string;
36
+ borderColor: string;
37
+ borderWidth: number;
38
+ padding: number;
39
+ radius: number;
40
+ opacity: number;
41
+ };
42
+ }
43
+ type PinPresentationPatch = Partial<Omit<PinPresentation, "stem" | "dot" | "halo" | "symbolHalo" | "plate">> & {
44
+ stem?: Partial<PinPresentation["stem"]>;
45
+ dot?: Partial<PinPresentation["dot"]>;
46
+ halo?: Partial<PinPresentation["halo"]>;
47
+ symbolHalo?: Partial<PinPresentation["symbolHalo"]>;
48
+ plate?: Partial<PinPresentation["plate"]>;
49
+ };
50
+ /** Per-unit appearance and dimensions; spatial rules belong to the view. */
51
+ type PinOverridePatch = Omit<PinPresentationPatch, "mode" | "occlusion">;
52
+ interface PinPresentationState {
53
+ defaults: PinPresentationPatch;
54
+ overrides: Record<string, PinOverridePatch>;
55
+ }
56
+ type PinPresentationStatus = "supported" | "unsupported" | "loading" | "waiting-for-elevation" | "unavailable";
57
+ interface PinPresentationCapability {
58
+ status: PinPresentationStatus;
59
+ reason?: string;
60
+ }
61
+ interface PinPresentationStatusEvent extends PinPresentationCapability {
62
+ graphicIds: readonly string[];
63
+ }
64
+ /** Render payload for one atomic graphic; shared icon resources retain HQ staff. */
65
+ interface PinRender {
66
+ id: string;
67
+ position: Position;
68
+ resource: IconResource;
69
+ octagonSize: number;
70
+ presentation: PinPresentation;
71
+ opacity: number;
72
+ /** Absolute clockwise bearing in radians, independent of billboard orientation. */
73
+ direction?: number;
74
+ /** Selection chrome only, on the host highlight/handles surface. */
75
+ highlightOnly?: boolean;
76
+ }
77
+ interface PinFootprint {
78
+ ground: PixelCoordinate;
79
+ attachment: PixelCoordinate;
80
+ min: PixelCoordinate;
81
+ max: PixelCoordinate;
82
+ }
83
+ declare const DEFAULT_PIN_PRESENTATION: Readonly<PinPresentation>;
84
+ /**
85
+ * Whether `value` is an acceptable number for the pin setting named `key`.
86
+ * Exported so a host's input handling can reject a value with the same rules
87
+ * the store enforces, rather than re-encoding the bounds and drifting from it.
88
+ */
89
+ declare function isValidPinNumber(key: string, value: unknown): value is number;
90
+ declare function resolvePinPresentation(...patches: readonly PinPresentationPatch[]): PinPresentation;
91
+ /** Replacing patches makes omitted override properties inherit again. */
92
+ declare class PinPresentationStore {
93
+ private state;
94
+ private readonly emitter;
95
+ getState(): PinPresentationState;
96
+ resolve(id: string): PinPresentation;
97
+ replace(state: PinPresentationState): void;
98
+ setDefaults(patch: PinPresentationPatch): void;
99
+ setOverride(id: string, patch: PinOverridePatch): void;
100
+ resetOverride(id: string): void;
101
+ onChange(listener: (state: PinPresentationState) => void): () => void;
102
+ }
103
+ //#endregion
4
104
  //#region src/gestures/types.d.ts
5
105
  interface PointerEventInfo {
6
106
  /** Per-event hit-tolerance override (e.g. larger for touch). */
@@ -64,6 +164,12 @@ declare const HATCH_PATTERNS: readonly HatchPattern[];
64
164
  declare const MINE_PATTERN_TILE_SIZE: number;
65
165
  /** True for the mine-pictogram family — a screen-space glyph texture rather than a repeating hatch. */
66
166
  declare function isMinePattern(pattern: HatchPattern): pattern is MinePattern;
167
+ interface Rgba {
168
+ r: number;
169
+ g: number;
170
+ b: number;
171
+ a: number;
172
+ }
67
173
  /**
68
174
  * Stable id for a rasterized tile, keyed by pattern and color. Adapters use
69
175
  * this as the image-registry key (MapLibre `addImage` id, OpenLayers pattern
@@ -80,6 +186,15 @@ declare function fillPatternImageId(color: string, pattern: HatchPattern): strin
80
186
  * power-of-two guarantee.
81
187
  */
82
188
  declare function fillPatternImageDimension(pixelRatio: number): number;
189
+ /**
190
+ * Parse a hex (`#rgb`, `#rgba`, `#rrggbb`, `#rrggbbaa`) or `rgb()`/`rgba()`
191
+ * color string into normalized channels, alpha in `[0, 1]`. Unparseable input
192
+ * falls back to opaque black rather than throwing, since a mis-themed fill
193
+ * should still render *something*. Shared by every renderer that needs CSS
194
+ * colors as numbers — hatch fills here, billboard pins in the MapLibre
195
+ * adapter — so the accepted syntax stays identical across them.
196
+ */
197
+ declare function parseColor(color: string): Rgba;
83
198
  /** The mine-pictogram members of {@link HatchPattern}, derived so the family stays in one place. */
84
199
  type MinePattern = Extract<HatchPattern, `mine-${string}`>;
85
200
  /** Coverage from the canonical command interpreter, exposed only for focused conformance tests. */
@@ -205,6 +320,8 @@ interface ImageOverlayResource {
205
320
  * stack position.
206
321
  */
207
322
  interface FeatureGroup {
323
+ /** Optional view-only point-symbol presentation; ordinary features are the fallback. */
324
+ pin?: PinRender;
208
325
  id: string;
209
326
  features: readonly Feature[];
210
327
  iconResources: readonly IconResource[];
@@ -242,6 +359,12 @@ interface PickOptions {
242
359
  signal?: AbortSignal;
243
360
  }
244
361
  interface MapAdapter {
362
+ onPinPresentationStatusChange?(handler: (event: PinPresentationStatusEvent) => void): () => void;
363
+ getPinPresentationCapability?(graphicId?: string): PinPresentationCapability;
364
+ getPinFootprint?(graphicId: string): PinFootprint | null;
365
+ pickPin?(graphicId: string, pixel: PixelCoordinate, tolerance: number): boolean;
366
+ /** Invert a pinned attachment for a location drag, preserving pointer grab. */
367
+ movePinFromPixel?(graphicId: string, attachment: PixelCoordinate): Position | null;
245
368
  /**
246
369
  * Add a vector layer to the map.
247
370
  * @returns unique layer ID
@@ -389,4 +512,4 @@ interface MapAdapter {
389
512
  getLayerFeatures(layerId: LayerId): readonly Feature[];
390
513
  }
391
514
  //#endregion
392
- export { EditPointerDriver as C, makeFillPatternImage as S, PointerEventInfo as T, HatchPattern as _, LayerId as a, fillPatternImageId as b, MapEvent as c, PickHandler as d, PickOptions as f, HATCH_PATTERNS as g, TextStyleOptions as h, ImageOverlayResource as i, MapEventHandler as l, StyleOptions as m, HandleStyle as n, MapAdapter as o, PixelCoordinate as p, IconResource as r, MapCursor as s, FeatureGroup as t, PickEvent as u, MINE_PATTERN_TILE_SIZE as v, PointerCallback as w, isMinePattern as x, fillPatternImageDimension as y };
515
+ export { PinOverridePatch as A, resolvePinPresentation as B, makeFillPatternImage as C, PointerEventInfo as D, PointerCallback as E, PinPresentationStatus as F, PinPresentationStatusEvent as I, PinPresentationStore as L, PinPresentationCapability as M, PinPresentationPatch as N, DEFAULT_PIN_PRESENTATION as O, PinPresentationState as P, PinRender as R, isMinePattern as S, EditPointerDriver as T, HatchPattern as _, LayerId as a, fillPatternImageDimension as b, MapEvent as c, PickHandler as d, PickOptions as f, HATCH_PATTERNS as g, TextStyleOptions as h, ImageOverlayResource as i, PinPresentation as j, PinFootprint as k, MapEventHandler as l, StyleOptions as m, HandleStyle as n, MapAdapter as o, PixelCoordinate as p, IconResource as r, MapCursor as s, FeatureGroup as t, PickEvent as u, MINE_PATTERN_TILE_SIZE as v, parseColor as w, fillPatternImageId as x, Rgba as y, isValidPinNumber as z };
@@ -1,4 +1,4 @@
1
- import { a as LayerId, o as MapAdapter, p as PixelCoordinate } from "./map-adapter-CyVIAoPf.mjs";
1
+ import { a as LayerId, o as MapAdapter, p as PixelCoordinate } from "./map-adapter-azR_hVjj.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.8.1",
3
+ "version": "0.9.0",
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",
@@ -39,7 +39,7 @@
39
39
  "access": "public"
40
40
  },
41
41
  "dependencies": {
42
- "@orbat-mapper/control-measures": "^0.25.0"
42
+ "@orbat-mapper/control-measures": "^0.27.0"
43
43
  },
44
44
  "peerDependencies": {
45
45
  "vitest": ">=4.0.0"