@orbat-mapper/tactical-draw 0.2.0-alpha.13 → 0.2.0-alpha.15
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 +33 -4
- package/dist/index.mjs +111 -44
- package/package.json +2 -2
package/dist/index.d.mts
CHANGED
|
@@ -57,9 +57,12 @@ interface StyleOptions {
|
|
|
57
57
|
/**
|
|
58
58
|
* Text (label) style for a layer. When `labelProperty` is set, adapters also
|
|
59
59
|
* read per-feature label properties: `rotation` (radians, rendered as
|
|
60
|
-
* `π − rotation`), `
|
|
61
|
-
* (ADR-
|
|
62
|
-
* `"end"` = text ends there; absent = centered).
|
|
60
|
+
* `π − rotation`), the size anchor's `textSizeMeters` (ground) or
|
|
61
|
+
* `textSizePixels` (screen) (ADR-0028), and `textAnchor` (`"start"` = text
|
|
62
|
+
* begins at the label point, `"end"` = text ends there; absent = centered).
|
|
63
|
+
* A ground-anchored label renders at
|
|
64
|
+
* `clamp(textSizeMeters / resolution, textSizeMinPixels, textSizeMaxPixels)`;
|
|
65
|
+
* a screen-anchored one at a constant `textSizePixels`, unclamped.
|
|
63
66
|
*/
|
|
64
67
|
interface TextStyleOptions {
|
|
65
68
|
text?: string;
|
|
@@ -69,6 +72,18 @@ interface TextStyleOptions {
|
|
|
69
72
|
strokeColor?: string;
|
|
70
73
|
strokeWidth?: number;
|
|
71
74
|
rotation?: number;
|
|
75
|
+
/**
|
|
76
|
+
* Lower edge of the ground-anchored label clamp band (ADR-0028): text never
|
|
77
|
+
* renders below this pixel size, however far the view zooms out.
|
|
78
|
+
* @default 8
|
|
79
|
+
*/
|
|
80
|
+
textSizeMinPixels?: number;
|
|
81
|
+
/**
|
|
82
|
+
* Upper edge of the ground-anchored label clamp band (ADR-0028): text never
|
|
83
|
+
* renders above this pixel size, however far the view zooms in.
|
|
84
|
+
* @default 24
|
|
85
|
+
*/
|
|
86
|
+
textSizeMaxPixels?: number;
|
|
72
87
|
}
|
|
73
88
|
/**
|
|
74
89
|
* Per-feature style for edit handles (vertex / midpoint / translate / rotate).
|
|
@@ -333,6 +348,20 @@ declare function bindAbortable(signal: AbortSignal | undefined, attach: () => ()
|
|
|
333
348
|
* when missing or shaped wrong so callers fall through to the layer style.
|
|
334
349
|
*/
|
|
335
350
|
declare function coerceHandleStyle(raw: unknown): HandleStyle | undefined;
|
|
351
|
+
/** Default lower edge of the ground-anchored label clamp band (ADR-0028). */
|
|
352
|
+
declare const DEFAULT_TEXT_SIZE_MIN_PIXELS = 8;
|
|
353
|
+
/** Default upper edge of the ground-anchored label clamp band (ADR-0028). */
|
|
354
|
+
declare const DEFAULT_TEXT_SIZE_MAX_PIXELS = 24;
|
|
355
|
+
/**
|
|
356
|
+
* Rendered pixel size of a ground-anchored label (ADR-0028):
|
|
357
|
+
* `textSizeMeters / resolution`, clamped to the layer's text-style band.
|
|
358
|
+
* Within the band the text scales with its graphic; past either edge it pins
|
|
359
|
+
* to the bound, so zooming out never yields unreadable smudges and zooming in
|
|
360
|
+
* never yields screen-covering text. Shared by the adapters that resolve text
|
|
361
|
+
* size in code (OpenLayers, Leaflet); the MapLibre adapter evaluates the same
|
|
362
|
+
* clamp inside its per-zoom-stop style expression.
|
|
363
|
+
*/
|
|
364
|
+
declare function resolveGroundTextSizePixels(textSizeMeters: number, resolution: number, text?: Pick<TextStyleOptions, "textSizeMinPixels" | "textSizeMaxPixels">): number;
|
|
336
365
|
//#endregion
|
|
337
366
|
//#region src/gestures/hit-test.d.ts
|
|
338
367
|
type ToPixel = (lonLat: Position) => PixelCoordinate | null;
|
|
@@ -1487,4 +1516,4 @@ declare function nearestWorldCopyLng(lng: number, refLng: number): number;
|
|
|
1487
1516
|
/** `nearestWorldCopyLng` applied to a lon/lat position. */
|
|
1488
1517
|
declare function nearestWorldCopyPosition(position: Position, refLng: number): Position;
|
|
1489
1518
|
//#endregion
|
|
1490
|
-
export { BaseMapAdapter, type CombinedAbort, type DrawMeasureDraft, type DrawOptions, type DrawSession, type EditChangeEvent, type EditManyOptions, type EditMode, type EditOptions, type EditPointerDriver, type EditSession, type FeatureOps, type GuideStyle, type HandleStyle, type InteractionStyle, type LayerId, type MapAdapter, type MapCursor, type MapEvent, type MapEventHandler, type NativeEventEntry, type PickEvent, type PickHandler, type PickOptions, type PixelCoordinate, type PointerCallback, PointerCallbackHub, type PointerEventInfo, type SettleReason, type SizeAnchor, type StyleOptions, TOUCH_HIT_TOLERANCE_PX, TacticalDraw, TacticalDrawAbortError, type TacticalDrawAbortReason, TacticalDrawDestroyedError, type TacticalDrawLayerOptions, type TacticalDrawOptions, type TextStyleOptions, type ToPixel, type TransformBox, type TransformChangeEvent, type TransformSession, bindAbortable, coerceHandleStyle, combineWithHostSignal, getSizeAnchor, hitTestFeature, ignoreAbort, isTacticalDrawAbortError, nearestWorldCopyLng, nearestWorldCopyPosition, pickHitTolerance, tryControlMeasureIdFromFeature };
|
|
1519
|
+
export { BaseMapAdapter, type CombinedAbort, DEFAULT_TEXT_SIZE_MAX_PIXELS, DEFAULT_TEXT_SIZE_MIN_PIXELS, type DrawMeasureDraft, type DrawOptions, type DrawSession, type EditChangeEvent, type EditManyOptions, type EditMode, type EditOptions, type EditPointerDriver, type EditSession, type FeatureOps, type GuideStyle, type HandleStyle, type InteractionStyle, type LayerId, type MapAdapter, type MapCursor, type MapEvent, type MapEventHandler, type NativeEventEntry, type PickEvent, type PickHandler, type PickOptions, type PixelCoordinate, type PointerCallback, PointerCallbackHub, type PointerEventInfo, type SettleReason, type SizeAnchor, type StyleOptions, TOUCH_HIT_TOLERANCE_PX, TacticalDraw, TacticalDrawAbortError, type TacticalDrawAbortReason, TacticalDrawDestroyedError, type TacticalDrawLayerOptions, type TacticalDrawOptions, type TextStyleOptions, type ToPixel, type TransformBox, type TransformChangeEvent, type TransformSession, bindAbortable, coerceHandleStyle, combineWithHostSignal, getSizeAnchor, hitTestFeature, ignoreAbort, isTacticalDrawAbortError, nearestWorldCopyLng, nearestWorldCopyPosition, pickHitTolerance, resolveGroundTextSizePixels, tryControlMeasureIdFromFeature };
|
package/dist/index.mjs
CHANGED
|
@@ -232,6 +232,24 @@ function coerceHandleStyle(raw) {
|
|
|
232
232
|
if (!raw || typeof raw !== "object") return void 0;
|
|
233
233
|
return raw;
|
|
234
234
|
}
|
|
235
|
+
/** Default lower edge of the ground-anchored label clamp band (ADR-0028). */
|
|
236
|
+
const DEFAULT_TEXT_SIZE_MIN_PIXELS = 8;
|
|
237
|
+
/** Default upper edge of the ground-anchored label clamp band (ADR-0028). */
|
|
238
|
+
const DEFAULT_TEXT_SIZE_MAX_PIXELS = 24;
|
|
239
|
+
/**
|
|
240
|
+
* Rendered pixel size of a ground-anchored label (ADR-0028):
|
|
241
|
+
* `textSizeMeters / resolution`, clamped to the layer's text-style band.
|
|
242
|
+
* Within the band the text scales with its graphic; past either edge it pins
|
|
243
|
+
* to the bound, so zooming out never yields unreadable smudges and zooming in
|
|
244
|
+
* never yields screen-covering text. Shared by the adapters that resolve text
|
|
245
|
+
* size in code (OpenLayers, Leaflet); the MapLibre adapter evaluates the same
|
|
246
|
+
* clamp inside its per-zoom-stop style expression.
|
|
247
|
+
*/
|
|
248
|
+
function resolveGroundTextSizePixels(textSizeMeters, resolution, text) {
|
|
249
|
+
const min = text?.textSizeMinPixels ?? 8;
|
|
250
|
+
const max = text?.textSizeMaxPixels ?? 24;
|
|
251
|
+
return Math.min(max, Math.max(min, textSizeMeters / resolution));
|
|
252
|
+
}
|
|
235
253
|
//#endregion
|
|
236
254
|
//#region src/gestures/hit-test.ts
|
|
237
255
|
/** Squared distance from `pixel` to the segment p1→p2 in pixel space, or null if either endpoint fails to project or the segment has zero length. */
|
|
@@ -504,11 +522,14 @@ function combineWithHostSignal(hostSignal) {
|
|
|
504
522
|
};
|
|
505
523
|
}
|
|
506
524
|
/**
|
|
507
|
-
* Per-kind pixel-denominated size option and the meter option it
|
|
508
|
-
* the single source of which option makes a measure
|
|
509
|
-
*
|
|
510
|
-
*
|
|
511
|
-
*
|
|
525
|
+
* Per-kind pixel-denominated *geometry* size option and the meter option it
|
|
526
|
+
* bakes into — the single source of which geometry option makes a measure
|
|
527
|
+
* screen-anchored. Label sizing is not listed here: every `capturesLabelSize`
|
|
528
|
+
* kind carries the shared `labelSizePixels` → `labelSize` pair implicitly
|
|
529
|
+
* (ADR-0028) — see [[sizeOptionSpecs]]. Both the resolution gate
|
|
530
|
+
* ([[measureUsesAdapterResolution]]) and the bake ([[bakePixelSizeToGround]])
|
|
531
|
+
* derive from this table, so a new pixel-sized kind is one entry here
|
|
532
|
+
* (ADR-0020).
|
|
512
533
|
*/
|
|
513
534
|
const PIXEL_SIZE_OPTIONS = {
|
|
514
535
|
boundary: {
|
|
@@ -523,6 +544,14 @@ const PIXEL_SIZE_OPTIONS = {
|
|
|
523
544
|
pixels: "echelonSizePixels",
|
|
524
545
|
meters: "echelonSize"
|
|
525
546
|
},
|
|
547
|
+
"base-camp": {
|
|
548
|
+
pixels: "echelonSizePixels",
|
|
549
|
+
meters: "echelonSize"
|
|
550
|
+
},
|
|
551
|
+
"guerrilla-base": {
|
|
552
|
+
pixels: "echelonSizePixels",
|
|
553
|
+
meters: "echelonSize"
|
|
554
|
+
},
|
|
526
555
|
flot: {
|
|
527
556
|
pixels: "radiusPixels",
|
|
528
557
|
meters: "radius"
|
|
@@ -548,34 +577,52 @@ const PIXEL_SIZE_OPTIONS = {
|
|
|
548
577
|
meters: "toothHeight"
|
|
549
578
|
}
|
|
550
579
|
};
|
|
580
|
+
/** The shared label-size pair every `capturesLabelSize` kind carries (ADR-0028). */
|
|
581
|
+
const LABEL_SIZE_SPEC = {
|
|
582
|
+
pixels: "labelSizePixels",
|
|
583
|
+
meters: "labelSize"
|
|
584
|
+
};
|
|
585
|
+
/**
|
|
586
|
+
* Every pixel/meter size-option pair `kind` can carry: its geometry entry from
|
|
587
|
+
* [[PIXEL_SIZE_OPTIONS]] (if any) plus the shared label pair when the kind
|
|
588
|
+
* captures a label size — a kind like Boundary can carry both anchor-bearing
|
|
589
|
+
* dimensions at once (echelon glyph + labels).
|
|
590
|
+
*/
|
|
591
|
+
function sizeOptionSpecs(kind) {
|
|
592
|
+
const specs = [];
|
|
593
|
+
const geometry = PIXEL_SIZE_OPTIONS[kind];
|
|
594
|
+
if (geometry) specs.push(geometry);
|
|
595
|
+
if (getControlMeasureMetadata(kind).capturesLabelSize) specs.push(LABEL_SIZE_SPEC);
|
|
596
|
+
return specs;
|
|
597
|
+
}
|
|
551
598
|
/**
|
|
552
599
|
* Whether `measure` carries a pixel-denominated size option whose resolution
|
|
553
600
|
* to meters depends on the live map (`metersPerPixel`) — i.e. it is
|
|
554
601
|
* *screen-anchored*. Used both to inject the override
|
|
555
602
|
* ([[withAdapterMeasureOptions]]) and to let zoom-driven re-renders skip
|
|
556
|
-
* measures whose
|
|
603
|
+
* measures whose render is resolution-independent. Accepts the minimal
|
|
557
604
|
* `{ kind, options }` shape so in-flight draw/edit handlers can gate against
|
|
558
605
|
* working options without materialising a full measure.
|
|
559
606
|
*/
|
|
560
607
|
function measureUsesAdapterResolution(measure) {
|
|
561
|
-
const
|
|
562
|
-
|
|
563
|
-
return measure.options?.[spec.pixels] !== void 0;
|
|
608
|
+
const options = measure.options;
|
|
609
|
+
return sizeOptionSpecs(measure.kind).some((spec) => options?.[spec.pixels] !== void 0);
|
|
564
610
|
}
|
|
565
611
|
/**
|
|
566
612
|
* Whether rendering `measure` through [[renderMeasureForAdapter]] reads live
|
|
567
613
|
* adapter view state — either a pixel-denominated size
|
|
568
614
|
* ([[measureUsesAdapterResolution]]) or draw-time label sizing that
|
|
569
|
-
* [[withCommittedAdapterMeasureOptions]] would still
|
|
570
|
-
* `capturesLabelSize` kind not yet carrying
|
|
571
|
-
*
|
|
572
|
-
*
|
|
573
|
-
*
|
|
615
|
+
* [[withCommittedAdapterMeasureOptions]] would still stamp (a
|
|
616
|
+
* `capturesLabelSize` kind not yet carrying any label size). The view-change
|
|
617
|
+
* rerender gates key off this so such measures rescale live; committed
|
|
618
|
+
* ground-anchored measures carry `labelSize` meters, stay zoom-independent,
|
|
619
|
+
* and keep skipping the rebuild.
|
|
574
620
|
*/
|
|
575
621
|
function measureRendersFromViewState(measure) {
|
|
576
622
|
if (measureUsesAdapterResolution(measure)) return true;
|
|
577
623
|
if (!getControlMeasureMetadata(measure.kind).capturesLabelSize) return false;
|
|
578
|
-
|
|
624
|
+
const options = measure.options;
|
|
625
|
+
return typeof options?.labelSizePixels !== "number" && typeof options?.labelSize !== "number";
|
|
579
626
|
}
|
|
580
627
|
/**
|
|
581
628
|
* The [[SizeAnchor]] a measure currently encodes (ADR-0020): `screen` when it
|
|
@@ -597,16 +644,15 @@ function getSizeAnchor(measure) {
|
|
|
597
644
|
* carries no pixel size or the adapter has no usable resolution.
|
|
598
645
|
*/
|
|
599
646
|
function bakePixelSizeToGround(measure, adapter) {
|
|
600
|
-
const spec = PIXEL_SIZE_OPTIONS[measure.kind];
|
|
601
|
-
if (!spec) return measure;
|
|
602
647
|
const options = measure.options ?? {};
|
|
603
|
-
const
|
|
604
|
-
if (
|
|
648
|
+
const specs = sizeOptionSpecs(measure.kind).filter((spec) => typeof options[spec.pixels] === "number");
|
|
649
|
+
if (specs.length === 0) return measure;
|
|
605
650
|
const mpp = adapter.getResolution();
|
|
606
651
|
if (mpp === void 0 || mpp <= 0) return measure;
|
|
652
|
+
const pixelKeys = new Set(specs.map((spec) => spec.pixels));
|
|
607
653
|
const rest = {};
|
|
608
|
-
for (const [key, value] of Object.entries(options)) if (key
|
|
609
|
-
rest[spec.meters] = pixels * mpp;
|
|
654
|
+
for (const [key, value] of Object.entries(options)) if (!pixelKeys.has(key) && key !== "metersPerPixel") rest[key] = value;
|
|
655
|
+
for (const spec of specs) rest[spec.meters] = options[spec.pixels] * mpp;
|
|
610
656
|
return {
|
|
611
657
|
...measure,
|
|
612
658
|
options: rest
|
|
@@ -632,24 +678,24 @@ function withAdapterMeasureOptions(measure, adapter) {
|
|
|
632
678
|
};
|
|
633
679
|
}
|
|
634
680
|
/**
|
|
635
|
-
*
|
|
636
|
-
*
|
|
637
|
-
*
|
|
638
|
-
*
|
|
639
|
-
*
|
|
681
|
+
* Stamp the draw-time default label size, in its screen-anchored
|
|
682
|
+
* (`labelSizePixels`) form, onto a `capturesLabelSize` measure that carries no
|
|
683
|
+
* label size of its own (ADR-0028). The pixel form keeps the in-flight
|
|
684
|
+
* preview screen-anchored through the gesture; the commit's default `ground`
|
|
685
|
+
* anchor then bakes it to `labelSize` meters via [[bakePixelSizeToGround]],
|
|
686
|
+
* while a `screen` commit persists the pixels. No-op once either label-size
|
|
687
|
+
* option is present (e.g. already committed), so it's safe to call on every
|
|
688
|
+
* render as well as on commit itself — see [[renderMeasureForAdapter]].
|
|
640
689
|
*/
|
|
641
|
-
function withCommittedAdapterMeasureOptions(measure
|
|
690
|
+
function withCommittedAdapterMeasureOptions(measure) {
|
|
642
691
|
if (!getControlMeasureMetadata(measure.kind).capturesLabelSize) return measure;
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
const resolution = adapter.getResolution();
|
|
692
|
+
const options = measure.options;
|
|
693
|
+
if (typeof options?.labelSizePixels === "number" || typeof options?.labelSize === "number") return measure;
|
|
646
694
|
return {
|
|
647
695
|
...measure,
|
|
648
696
|
options: {
|
|
649
697
|
...measure.options,
|
|
650
|
-
labelSizePixels: 14
|
|
651
|
-
...zoom !== void 0 ? { labelSizeZoom: zoom } : {},
|
|
652
|
-
...resolution !== void 0 && resolution > 0 ? { labelSizeResolution: resolution } : {}
|
|
698
|
+
labelSizePixels: 14
|
|
653
699
|
}
|
|
654
700
|
};
|
|
655
701
|
}
|
|
@@ -668,7 +714,7 @@ function withCommittedAdapterMeasureOptions(measure, adapter) {
|
|
|
668
714
|
* directly to produce the value they persist).
|
|
669
715
|
*/
|
|
670
716
|
function renderMeasureForAdapter(adapter, measure, opts) {
|
|
671
|
-
return renderControlMeasure(withAdapterMeasureOptions(withCommittedAdapterMeasureOptions(measure
|
|
717
|
+
return renderControlMeasure(withAdapterMeasureOptions(withCommittedAdapterMeasureOptions(measure), adapter), opts);
|
|
672
718
|
}
|
|
673
719
|
//#endregion
|
|
674
720
|
//#region src/tactical-draw/run-interaction.ts
|
|
@@ -963,7 +1009,7 @@ function runFixedLengthDraw(options) {
|
|
|
963
1009
|
...measureStyle !== void 0 ? { style: measureStyle } : {},
|
|
964
1010
|
...measureProperties !== void 0 ? { properties: measureProperties } : {},
|
|
965
1011
|
...measureTextAmplifiers !== void 0 ? { textAmplifiers: measureTextAmplifiers } : {}
|
|
966
|
-
}
|
|
1012
|
+
});
|
|
967
1013
|
const measure = sizeAnchor === "screen" ? captured : bakePixelSizeToGround(captured, adapter);
|
|
968
1014
|
return {
|
|
969
1015
|
measure: cloneControlMeasure(measure),
|
|
@@ -1335,7 +1381,7 @@ function runVariableLengthDraw(options) {
|
|
|
1335
1381
|
...measureStyle !== void 0 ? { style: measureStyle } : {},
|
|
1336
1382
|
...measureProperties !== void 0 ? { properties: measureProperties } : {},
|
|
1337
1383
|
...measureTextAmplifiers !== void 0 ? { textAmplifiers: measureTextAmplifiers } : {}
|
|
1338
|
-
}
|
|
1384
|
+
});
|
|
1339
1385
|
const measure = sizeAnchor === "screen" ? built : bakePixelSizeToGround(built, adapter);
|
|
1340
1386
|
return {
|
|
1341
1387
|
measure: cloneControlMeasure(measure),
|
|
@@ -1989,9 +2035,11 @@ const HANDLE_HIT_TOLERANCE_PX$1 = 12;
|
|
|
1989
2035
|
* A body drag (drag-anywhere-inside-the-box translate) whose release pixel
|
|
1990
2036
|
* lands within this many pixels of the down pixel is treated as a plain
|
|
1991
2037
|
* click, not a gesture: it is not committed (geometry restored, no
|
|
1992
|
-
* `EditChangeEvent`, `dirty` untouched)
|
|
1993
|
-
* suppressed so the click doesn't
|
|
1994
|
-
*
|
|
2038
|
+
* `EditChangeEvent`, `dirty` untouched). The click-away's *empty-map* close is
|
|
2039
|
+
* suppressed so the click doesn't end the edit, but a pick on another
|
|
2040
|
+
* graphics-layer measure inside the box still closes-then-selects it.
|
|
2041
|
+
* Corner/rotate drags commit even at zero movement (matches the pre-ADR-0017
|
|
2042
|
+
* translate/rotate seams).
|
|
1995
2043
|
*/
|
|
1996
2044
|
const CLICK_SLOP_PX$1 = 3;
|
|
1997
2045
|
const ALLOWED_EDIT_MODES = new Set([
|
|
@@ -2037,6 +2085,15 @@ function runEdit(opts) {
|
|
|
2037
2085
|
*/
|
|
2038
2086
|
let suppressClickAway = false;
|
|
2039
2087
|
/**
|
|
2088
|
+
* Set when a zero-movement body drag (a plain click inside the transform
|
|
2089
|
+
* box) released this pointer cycle. Unlike {@link suppressClickAway} it only
|
|
2090
|
+
* suppresses the *empty-map* close in `handleClick` — a stashed pick on
|
|
2091
|
+
* another graphics-layer measure still closes-then-re-dispatches, so
|
|
2092
|
+
* measures sitting inside a large box stay selectable. Consumed by the next
|
|
2093
|
+
* `handleClick`.
|
|
2094
|
+
*/
|
|
2095
|
+
let bodyClickPending = false;
|
|
2096
|
+
/**
|
|
2040
2097
|
* Mutable style snapshot. Initialised from the edit-start input; replaced
|
|
2041
2098
|
* when the façade routes an external style change to us via
|
|
2042
2099
|
* `notifyExternalMeasure`. `EditSession.measure` stays the immutable
|
|
@@ -2722,7 +2779,7 @@ function runEdit(opts) {
|
|
|
2722
2779
|
renderHandlesLayer();
|
|
2723
2780
|
recomputeDirty();
|
|
2724
2781
|
endDragBookkeeping();
|
|
2725
|
-
|
|
2782
|
+
bodyClickPending = true;
|
|
2726
2783
|
return;
|
|
2727
2784
|
}
|
|
2728
2785
|
const finalSnapshot = fsm.move(pixel);
|
|
@@ -2748,21 +2805,25 @@ function runEdit(opts) {
|
|
|
2748
2805
|
const localPreview = pickPreview;
|
|
2749
2806
|
const localHandles = pickHandles;
|
|
2750
2807
|
const localGraphics = pickGraphics;
|
|
2808
|
+
const wasBodyClick = bodyClickPending;
|
|
2751
2809
|
pickPreview = void 0;
|
|
2752
2810
|
pickHandles = void 0;
|
|
2753
2811
|
pickGraphics = void 0;
|
|
2812
|
+
bodyClickPending = false;
|
|
2754
2813
|
if (ctx.settled) return;
|
|
2755
2814
|
if (!closeOnClickAway) return;
|
|
2756
2815
|
if (suppressClickAway) {
|
|
2757
2816
|
suppressClickAway = false;
|
|
2758
2817
|
return;
|
|
2759
2818
|
}
|
|
2760
|
-
if (
|
|
2819
|
+
if (localHandles) return;
|
|
2761
2820
|
if (localGraphics && localGraphics.id !== measure.id) {
|
|
2762
2821
|
ctx.commit(rebuildRendered);
|
|
2763
2822
|
if (onClickAwayGraphicsPick) onClickAwayGraphicsPick(localGraphics);
|
|
2764
2823
|
return;
|
|
2765
2824
|
}
|
|
2825
|
+
if (localPreview) return;
|
|
2826
|
+
if (wasBodyClick) return;
|
|
2766
2827
|
ctx.commit(rebuildRendered);
|
|
2767
2828
|
};
|
|
2768
2829
|
const core = runInteraction({
|
|
@@ -2969,6 +3030,8 @@ function runGroupTransform(opts) {
|
|
|
2969
3030
|
let dragInFlight = false;
|
|
2970
3031
|
/** Same click-away suppression role as `edit-controller.ts`'s flag of the same name. */
|
|
2971
3032
|
let suppressClickAway = false;
|
|
3033
|
+
/** Same body-click role as `edit-controller.ts`'s flag of the same name. */
|
|
3034
|
+
let bodyClickPending = false;
|
|
2972
3035
|
const changeListeners = /* @__PURE__ */ new Set();
|
|
2973
3036
|
const commitEmitter = createCommitEmitter("TransformSession.onCommit listener errors");
|
|
2974
3037
|
const settleEmitter = createSettleEmitter("TransformSession.onSettled listener errors");
|
|
@@ -3402,7 +3465,7 @@ function runGroupTransform(opts) {
|
|
|
3402
3465
|
renderHandlesLayer();
|
|
3403
3466
|
recomputeDirty();
|
|
3404
3467
|
dragInFlight = false;
|
|
3405
|
-
|
|
3468
|
+
bodyClickPending = true;
|
|
3406
3469
|
return;
|
|
3407
3470
|
}
|
|
3408
3471
|
const finalSnapshot = fsm.move(pixel);
|
|
@@ -3426,22 +3489,26 @@ function runGroupTransform(opts) {
|
|
|
3426
3489
|
const localPreview = pickPreview;
|
|
3427
3490
|
const localHandles = pickHandles;
|
|
3428
3491
|
const localGraphics = pickGraphics;
|
|
3492
|
+
const wasBodyClick = bodyClickPending;
|
|
3429
3493
|
pickPreview = void 0;
|
|
3430
3494
|
pickHandles = void 0;
|
|
3431
3495
|
pickGraphics = void 0;
|
|
3496
|
+
bodyClickPending = false;
|
|
3432
3497
|
if (ctx.settled) return;
|
|
3433
3498
|
if (!closeOnClickAway) return;
|
|
3434
3499
|
if (suppressClickAway) {
|
|
3435
3500
|
suppressClickAway = false;
|
|
3436
3501
|
return;
|
|
3437
3502
|
}
|
|
3438
|
-
if (
|
|
3503
|
+
if (localHandles) return;
|
|
3439
3504
|
const isMember = localGraphics ? members.some((m) => m.measure.id === localGraphics.id) : false;
|
|
3440
3505
|
if (localGraphics && !isMember) {
|
|
3441
3506
|
commitClose();
|
|
3442
3507
|
if (onClickAwayGraphicsPick) onClickAwayGraphicsPick(localGraphics);
|
|
3443
3508
|
return;
|
|
3444
3509
|
}
|
|
3510
|
+
if (localPreview) return;
|
|
3511
|
+
if (wasBodyClick) return;
|
|
3445
3512
|
commitClose();
|
|
3446
3513
|
};
|
|
3447
3514
|
const core = runInteraction({
|
|
@@ -4336,4 +4403,4 @@ function nearestWorldCopyPosition(position, refLng) {
|
|
|
4336
4403
|
return [nearestWorldCopyLng(position[0], refLng), ...position.slice(1)];
|
|
4337
4404
|
}
|
|
4338
4405
|
//#endregion
|
|
4339
|
-
export { BaseMapAdapter, PointerCallbackHub, TOUCH_HIT_TOLERANCE_PX, TacticalDraw, TacticalDrawAbortError, TacticalDrawDestroyedError, bindAbortable, coerceHandleStyle, combineWithHostSignal, getSizeAnchor, hitTestFeature, ignoreAbort, isTacticalDrawAbortError, nearestWorldCopyLng, nearestWorldCopyPosition, pickHitTolerance, tryControlMeasureIdFromFeature };
|
|
4406
|
+
export { BaseMapAdapter, DEFAULT_TEXT_SIZE_MAX_PIXELS, DEFAULT_TEXT_SIZE_MIN_PIXELS, PointerCallbackHub, TOUCH_HIT_TOLERANCE_PX, TacticalDraw, TacticalDrawAbortError, TacticalDrawDestroyedError, bindAbortable, coerceHandleStyle, combineWithHostSignal, getSizeAnchor, hitTestFeature, ignoreAbort, isTacticalDrawAbortError, nearestWorldCopyLng, nearestWorldCopyPosition, pickHitTolerance, resolveGroundTextSizePixels, tryControlMeasureIdFromFeature };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@orbat-mapper/tactical-draw",
|
|
3
|
-
"version": "0.2.0-alpha.
|
|
3
|
+
"version": "0.2.0-alpha.15",
|
|
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",
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"access": "public"
|
|
39
39
|
},
|
|
40
40
|
"dependencies": {
|
|
41
|
-
"@orbat-mapper/control-measures": "^0.2.0-alpha.
|
|
41
|
+
"@orbat-mapper/control-measures": "^0.2.0-alpha.11"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
44
|
"@arethetypeswrong/core": "^0.18.3",
|