@orbat-mapper/tactical-draw 0.9.2 → 0.10.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.
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-
|
|
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-2Cmj-tem.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
|
|
|
@@ -1662,6 +1662,12 @@ declare class TacticalDraw {
|
|
|
1662
1662
|
private transformCounter;
|
|
1663
1663
|
/** Snapshot of the host's latest authoritative Graphic membership and order. */
|
|
1664
1664
|
private lastRenderedMeasures;
|
|
1665
|
+
/**
|
|
1666
|
+
* Id index over {@link lastRenderedMeasures}, rebuilt alongside it so
|
|
1667
|
+
* per-id lookups (e.g. {@link renderHighlights}) are O(1) instead of an
|
|
1668
|
+
* O(document) linear scan on every highlighted id, every frame.
|
|
1669
|
+
*/
|
|
1670
|
+
private lastRenderedMeasuresById;
|
|
1665
1671
|
/** Whether any last-rendered graphic reads the whole camera, not just scale. */
|
|
1666
1672
|
private lastRenderedHasViewDependent;
|
|
1667
1673
|
private snapGeometryFeatures;
|
|
@@ -1703,6 +1709,15 @@ declare class TacticalDraw {
|
|
|
1703
1709
|
* that removes outlines when the set transitions to empty.
|
|
1704
1710
|
*/
|
|
1705
1711
|
private hasHighlightOutlines;
|
|
1712
|
+
/**
|
|
1713
|
+
* Coalesces bursts of {@link setHighlightedGraphics} (e.g. hover across a
|
|
1714
|
+
* list of rows) into at most one {@link renderHighlights} per animation
|
|
1715
|
+
* frame. Every other caller — `render()`, view-change, session start /
|
|
1716
|
+
* settle — needs highlight state updated synchronously and in step with
|
|
1717
|
+
* its own write, so those call {@link flushHighlights} instead, which
|
|
1718
|
+
* cancels any pending coalesced frame before rendering immediately.
|
|
1719
|
+
*/
|
|
1720
|
+
private readonly highlightCoalescer;
|
|
1706
1721
|
constructor(adapter: MapAdapter, options?: TacticalDrawOptions);
|
|
1707
1722
|
setPinPresentation(defaults: PinPresentationPatch): void;
|
|
1708
1723
|
setPinOverride(id: string, patch: PinOverridePatch): void;
|
|
@@ -1830,6 +1845,14 @@ declare class TacticalDraw {
|
|
|
1830
1845
|
* "locked selection" chrome.
|
|
1831
1846
|
*/
|
|
1832
1847
|
setHighlightedGraphics(ids: readonly string[]): void;
|
|
1848
|
+
/**
|
|
1849
|
+
* Cancel any pending coalesced highlight frame and re-project highlights
|
|
1850
|
+
* immediately. Used by every caller other than `setHighlightedGraphics`
|
|
1851
|
+
* (`render()`, view-change, session start / settle) so their own
|
|
1852
|
+
* synchronous effects and the highlight layer update together, with no
|
|
1853
|
+
* frame of lag and no stale coalesced call left to fire afterwards.
|
|
1854
|
+
*/
|
|
1855
|
+
private flushHighlights;
|
|
1833
1856
|
/**
|
|
1834
1857
|
* Project the current {@link highlightedIds} into one outline `LineString`
|
|
1835
1858
|
* per graphic and reconcile them onto the highlight layer. Idempotent and
|
package/dist/index.mjs
CHANGED
|
@@ -1091,7 +1091,8 @@ function validateOverride(patch) {
|
|
|
1091
1091
|
for (const key of [
|
|
1092
1092
|
"mode",
|
|
1093
1093
|
"occlusion",
|
|
1094
|
-
"prioritizePins"
|
|
1094
|
+
"prioritizePins",
|
|
1095
|
+
"depthSort"
|
|
1095
1096
|
]) if (Object.hasOwn(patch, key)) throw new TypeError(`Pin setting ${key} is view-wide only`);
|
|
1096
1097
|
}
|
|
1097
1098
|
const DEFAULT_PIN_PRESENTATION = Object.freeze({
|
|
@@ -1102,6 +1103,7 @@ const DEFAULT_PIN_PRESENTATION = Object.freeze({
|
|
|
1102
1103
|
sizePixels: 32,
|
|
1103
1104
|
occlusion: "none",
|
|
1104
1105
|
prioritizePins: true,
|
|
1106
|
+
depthSort: true,
|
|
1105
1107
|
stem: Object.freeze({
|
|
1106
1108
|
color: "#172033",
|
|
1107
1109
|
width: 2,
|
|
@@ -7642,6 +7644,12 @@ var TacticalDraw = class {
|
|
|
7642
7644
|
transformCounter = 0;
|
|
7643
7645
|
/** Snapshot of the host's latest authoritative Graphic membership and order. */
|
|
7644
7646
|
lastRenderedMeasures = [];
|
|
7647
|
+
/**
|
|
7648
|
+
* Id index over {@link lastRenderedMeasures}, rebuilt alongside it so
|
|
7649
|
+
* per-id lookups (e.g. {@link renderHighlights}) are O(1) instead of an
|
|
7650
|
+
* O(document) linear scan on every highlighted id, every frame.
|
|
7651
|
+
*/
|
|
7652
|
+
lastRenderedMeasuresById = /* @__PURE__ */ new Map();
|
|
7645
7653
|
/** Whether any last-rendered graphic reads the whole camera, not just scale. */
|
|
7646
7654
|
lastRenderedHasViewDependent = false;
|
|
7647
7655
|
snapGeometryFeatures = [];
|
|
@@ -7683,6 +7691,15 @@ var TacticalDraw = class {
|
|
|
7683
7691
|
* that removes outlines when the set transitions to empty.
|
|
7684
7692
|
*/
|
|
7685
7693
|
hasHighlightOutlines = false;
|
|
7694
|
+
/**
|
|
7695
|
+
* Coalesces bursts of {@link setHighlightedGraphics} (e.g. hover across a
|
|
7696
|
+
* list of rows) into at most one {@link renderHighlights} per animation
|
|
7697
|
+
* frame. Every other caller — `render()`, view-change, session start /
|
|
7698
|
+
* settle — needs highlight state updated synchronously and in step with
|
|
7699
|
+
* its own write, so those call {@link flushHighlights} instead, which
|
|
7700
|
+
* cancels any pending coalesced frame before rendering immediately.
|
|
7701
|
+
*/
|
|
7702
|
+
highlightCoalescer = createFrameCoalescer(() => this.renderHighlights());
|
|
7686
7703
|
constructor(adapter, options) {
|
|
7687
7704
|
this.adapter = adapter;
|
|
7688
7705
|
this.offsetDragModifier = options?.offsetDragModifier ?? false;
|
|
@@ -7715,7 +7732,7 @@ var TacticalDraw = class {
|
|
|
7715
7732
|
this.invalidateGraphicGroupCache(false);
|
|
7716
7733
|
this.refreshActiveEditPresentation();
|
|
7717
7734
|
this.reconcileGraphicsStack();
|
|
7718
|
-
this.
|
|
7735
|
+
this.flushHighlights();
|
|
7719
7736
|
});
|
|
7720
7737
|
}
|
|
7721
7738
|
setPinPresentation(defaults) {
|
|
@@ -7949,7 +7966,7 @@ var TacticalDraw = class {
|
|
|
7949
7966
|
const resolutionChanged = !Object.is(resolution, this.lastViewResolution);
|
|
7950
7967
|
this.lastViewResolution = resolution;
|
|
7951
7968
|
if (!this.hasRendered) return;
|
|
7952
|
-
this.
|
|
7969
|
+
this.flushHighlights();
|
|
7953
7970
|
const nativePointSymbolScaling = this.adapter.scalesGroundPointSymbolsNatively === true;
|
|
7954
7971
|
if (!resolutionChanged && !this.lastRenderedHasViewDependent) return;
|
|
7955
7972
|
const excluded = this.graphicsStackExcludedIds();
|
|
@@ -8038,6 +8055,7 @@ var TacticalDraw = class {
|
|
|
8038
8055
|
}
|
|
8039
8056
|
}
|
|
8040
8057
|
this.lastRenderedMeasures = measures.slice();
|
|
8058
|
+
this.lastRenderedMeasuresById = new Map(this.lastRenderedMeasures.map((g) => [g.id, g]));
|
|
8041
8059
|
this.lastRenderedHasViewDependent = this.lastRenderedMeasures.some((g) => !this.renderGraphicGroup(g).pin && graphicViewDependence(g, this.adapter.scalesGroundPointSymbolsNatively === true) === "view");
|
|
8042
8060
|
this.graphicStack.acknowledgeHostRender(measures);
|
|
8043
8061
|
if (activeEdit && "syncHostMembership" in activeEdit && measures.some((graphic) => graphic.id === activeEdit.measureId && graphic.kind === activeEdit.graphicKind)) activeEdit.syncHostMembership(true);
|
|
@@ -8056,7 +8074,7 @@ var TacticalDraw = class {
|
|
|
8056
8074
|
});
|
|
8057
8075
|
else if (this.activeInteraction.isStarting) this.activeInteraction.cancel("removed");
|
|
8058
8076
|
}
|
|
8059
|
-
this.
|
|
8077
|
+
this.flushHighlights();
|
|
8060
8078
|
}
|
|
8061
8079
|
/**
|
|
8062
8080
|
* Replace the passive selection-highlight set with `ids`. Declarative and
|
|
@@ -8071,6 +8089,17 @@ var TacticalDraw = class {
|
|
|
8071
8089
|
setHighlightedGraphics(ids) {
|
|
8072
8090
|
this.assertAlive();
|
|
8073
8091
|
this.highlightedIds = ids.slice();
|
|
8092
|
+
this.highlightCoalescer.schedule();
|
|
8093
|
+
}
|
|
8094
|
+
/**
|
|
8095
|
+
* Cancel any pending coalesced highlight frame and re-project highlights
|
|
8096
|
+
* immediately. Used by every caller other than `setHighlightedGraphics`
|
|
8097
|
+
* (`render()`, view-change, session start / settle) so their own
|
|
8098
|
+
* synchronous effects and the highlight layer update together, with no
|
|
8099
|
+
* frame of lag and no stale coalesced call left to fire afterwards.
|
|
8100
|
+
*/
|
|
8101
|
+
flushHighlights() {
|
|
8102
|
+
this.highlightCoalescer.cancel();
|
|
8074
8103
|
this.renderHighlights();
|
|
8075
8104
|
}
|
|
8076
8105
|
/**
|
|
@@ -8096,7 +8125,7 @@ var TacticalDraw = class {
|
|
|
8096
8125
|
const pinGroups = [];
|
|
8097
8126
|
for (const id of this.highlightedIds) {
|
|
8098
8127
|
if (excluded.has(id)) continue;
|
|
8099
|
-
const graphic = this.
|
|
8128
|
+
const graphic = this.lastRenderedMeasuresById.get(id);
|
|
8100
8129
|
if (!graphic) continue;
|
|
8101
8130
|
if (isPointSymbol(graphic)) {
|
|
8102
8131
|
const pin = this.renderGraphicGroup(graphic).pin;
|
|
@@ -8149,16 +8178,13 @@ var TacticalDraw = class {
|
|
|
8149
8178
|
if (!this.images) return null;
|
|
8150
8179
|
return imageFootprint(graphic, renderImageForAdapter(this.adapter, this.images, graphic).render, this.adapter)?.box ?? null;
|
|
8151
8180
|
}
|
|
8152
|
-
const
|
|
8153
|
-
|
|
8154
|
-
symbolColors: this.symbolColors
|
|
8155
|
-
});
|
|
8156
|
-
if (graphic.kind === "text") return fitTextFootprintFromFeatures(render.features, (lonLat) => this.adapter.getPixelFromCoordinate(lonLat), {
|
|
8181
|
+
const features = this.renderGraphicGroup(graphic).features;
|
|
8182
|
+
if (graphic.kind === "text") return fitTextFootprintFromFeatures(features, (lonLat) => this.adapter.getPixelFromCoordinate(lonLat), {
|
|
8157
8183
|
resolution: this.adapter.getResolution(),
|
|
8158
8184
|
bearing
|
|
8159
8185
|
});
|
|
8160
8186
|
const positions = [];
|
|
8161
|
-
for (const feature of
|
|
8187
|
+
for (const feature of features) if (feature.geometry) collectFeaturePositions(feature.geometry, positions);
|
|
8162
8188
|
const pixels = [];
|
|
8163
8189
|
for (const position of positions) {
|
|
8164
8190
|
const pixel = this.adapter.getPixelFromCoordinate(position);
|
|
@@ -8219,7 +8245,7 @@ var TacticalDraw = class {
|
|
|
8219
8245
|
clearSlot();
|
|
8220
8246
|
this.clearSnapResult();
|
|
8221
8247
|
if (extraSettle) extraSettle();
|
|
8222
|
-
this.
|
|
8248
|
+
this.flushHighlights();
|
|
8223
8249
|
};
|
|
8224
8250
|
this.activeInteraction.begin();
|
|
8225
8251
|
try {
|
|
@@ -8233,7 +8259,7 @@ var TacticalDraw = class {
|
|
|
8233
8259
|
this.activeInteraction.set(handle);
|
|
8234
8260
|
if (activate && !handle.settled) {
|
|
8235
8261
|
deactivate = activate(handle) ?? null;
|
|
8236
|
-
this.
|
|
8262
|
+
this.flushHighlights();
|
|
8237
8263
|
}
|
|
8238
8264
|
}
|
|
8239
8265
|
handle.promise.then(clearSlot, clearSlot);
|
|
@@ -8780,6 +8806,7 @@ var TacticalDraw = class {
|
|
|
8780
8806
|
this.unsubscribePins();
|
|
8781
8807
|
if (this.destroyed) return;
|
|
8782
8808
|
this.destroyed = true;
|
|
8809
|
+
this.highlightCoalescer.cancel();
|
|
8783
8810
|
if (this.activeInteraction.isActive) {
|
|
8784
8811
|
this.activeEdit = null;
|
|
8785
8812
|
this.activeTransform = null;
|
|
@@ -11,6 +11,8 @@ interface PinPresentation {
|
|
|
11
11
|
sizePixels: number;
|
|
12
12
|
occlusion: "none" | "terrain";
|
|
13
13
|
prioritizePins: boolean;
|
|
14
|
+
/** Paint whole pins far to near by camera depth; ties retain layer order. Default on. */
|
|
15
|
+
depthSort: boolean;
|
|
14
16
|
stem: {
|
|
15
17
|
color: string;
|
|
16
18
|
width: number;
|
|
@@ -49,7 +51,7 @@ type PinPresentationPatch = Partial<Omit<PinPresentation, "stem" | "dot" | "halo
|
|
|
49
51
|
plate?: Partial<PinPresentation["plate"]>;
|
|
50
52
|
};
|
|
51
53
|
/** Per-unit appearance and dimensions; spatial rules belong to the view. */
|
|
52
|
-
type PinOverridePatch = Omit<PinPresentationPatch, "mode" | "occlusion" | "prioritizePins">;
|
|
54
|
+
type PinOverridePatch = Omit<PinPresentationPatch, "mode" | "occlusion" | "prioritizePins" | "depthSort">;
|
|
53
55
|
interface PinPresentationState {
|
|
54
56
|
defaults: PinPresentationPatch;
|
|
55
57
|
overrides: Record<string, PinOverridePatch>;
|
package/dist/testing.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as LayerId, o as MapAdapter, p as PixelCoordinate } from "./map-adapter-
|
|
1
|
+
import { a as LayerId, o as MapAdapter, p as PixelCoordinate } from "./map-adapter-2Cmj-tem.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.
|
|
3
|
+
"version": "0.10.1",
|
|
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",
|