@orbat-mapper/tactical-draw 0.2.0-alpha.22 → 0.2.0-alpha.23
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 +59 -1
- package/dist/index.mjs +300 -44
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -1184,6 +1184,55 @@ interface DrawSession {
|
|
|
1184
1184
|
onSettled(handler: (reason: SettleReason) => void): () => void;
|
|
1185
1185
|
}
|
|
1186
1186
|
//#endregion
|
|
1187
|
+
//#region src/tactical-draw/snapping.d.ts
|
|
1188
|
+
type SnapInteraction = "draw" | "reshape" | "translate" | "label-drag";
|
|
1189
|
+
interface SnapCandidateRequest {
|
|
1190
|
+
coordinate: Position;
|
|
1191
|
+
pixel: PixelCoordinate;
|
|
1192
|
+
interaction: SnapInteraction;
|
|
1193
|
+
graphicId?: string;
|
|
1194
|
+
controlPointIndex?: number;
|
|
1195
|
+
originalEvent?: unknown;
|
|
1196
|
+
}
|
|
1197
|
+
interface SnapCandidate {
|
|
1198
|
+
id: string;
|
|
1199
|
+
coordinate: Position;
|
|
1200
|
+
kind: string;
|
|
1201
|
+
graphicId?: string;
|
|
1202
|
+
controlPointIndex?: number;
|
|
1203
|
+
priority?: number;
|
|
1204
|
+
}
|
|
1205
|
+
type SnapCandidateProvider = (request: SnapCandidateRequest) => readonly SnapCandidate[];
|
|
1206
|
+
interface SnapResult {
|
|
1207
|
+
coordinate: Position;
|
|
1208
|
+
pixel: PixelCoordinate;
|
|
1209
|
+
candidate: SnapCandidate;
|
|
1210
|
+
distancePixels: number;
|
|
1211
|
+
}
|
|
1212
|
+
interface GraphicGeometrySnappingOptions {
|
|
1213
|
+
/** Snap to the nearest point along generated linework and polygon boundaries. Default `true`. */
|
|
1214
|
+
edges?: boolean;
|
|
1215
|
+
/** Snap to generated geometry vertices. Default `false`. */
|
|
1216
|
+
vertices?: boolean;
|
|
1217
|
+
}
|
|
1218
|
+
interface SnappingOptions {
|
|
1219
|
+
enabled?: boolean;
|
|
1220
|
+
tolerancePixels?: number;
|
|
1221
|
+
sources?: {
|
|
1222
|
+
graphics?: boolean;
|
|
1223
|
+
/**
|
|
1224
|
+
* Snap to generated control-measure geometry. `true` enables edges with
|
|
1225
|
+
* vertices disabled; pass an object to select either candidate type.
|
|
1226
|
+
* Text/label point features and the active graphic are excluded.
|
|
1227
|
+
*/
|
|
1228
|
+
graphicGeometry?: boolean | GraphicGeometrySnappingOptions;
|
|
1229
|
+
external?: SnapCandidateProvider;
|
|
1230
|
+
};
|
|
1231
|
+
bypass?: (originalEvent: unknown) => boolean;
|
|
1232
|
+
/** Called for each resolution attempt; `null` clears a host-rendered indicator. */
|
|
1233
|
+
onSnap?: (result: SnapResult | null) => void;
|
|
1234
|
+
}
|
|
1235
|
+
//#endregion
|
|
1187
1236
|
//#region src/tactical-draw/point-symbol-draw-controller.d.ts
|
|
1188
1237
|
type DrawPointSymbolDraft = Pick<PointSymbol, "kind" | "sidc"> & Partial<Omit<PointSymbol, "kind" | "sidc">>;
|
|
1189
1238
|
//#endregion
|
|
@@ -1234,6 +1283,8 @@ interface TacticalDrawOptions {
|
|
|
1234
1283
|
* the draw API itself are deferred (PRD #40 user-story-5 note).
|
|
1235
1284
|
*/
|
|
1236
1285
|
generateId?: () => string;
|
|
1286
|
+
/** Optional engine-level snapping for draw and edit interactions. */
|
|
1287
|
+
snapping?: SnappingOptions;
|
|
1237
1288
|
}
|
|
1238
1289
|
interface EditOptions {
|
|
1239
1290
|
signal?: AbortSignal;
|
|
@@ -1382,6 +1433,8 @@ declare class TacticalDraw {
|
|
|
1382
1433
|
private readonly defaultInteractionStyle;
|
|
1383
1434
|
private readonly generateId;
|
|
1384
1435
|
private readonly pointSymbols;
|
|
1436
|
+
private snappingOptions;
|
|
1437
|
+
private readonly resolveSnap;
|
|
1385
1438
|
private destroyed;
|
|
1386
1439
|
private hasRendered;
|
|
1387
1440
|
private readonly activeInteraction;
|
|
@@ -1432,7 +1485,12 @@ declare class TacticalDraw {
|
|
|
1432
1485
|
* surrounding collection state.
|
|
1433
1486
|
*/
|
|
1434
1487
|
private lastRenderedMeasures;
|
|
1488
|
+
private snapGeometryFeatures;
|
|
1435
1489
|
constructor(adapter: MapAdapter, options?: TacticalDrawOptions);
|
|
1490
|
+
/** Replace snapping configuration without recreating the map adapter or façade. */
|
|
1491
|
+
setSnappingOptions(options?: SnappingOptions): void;
|
|
1492
|
+
/** Clear transient host affordances when snapping or its interaction ends. */
|
|
1493
|
+
private clearSnapResult;
|
|
1436
1494
|
/**
|
|
1437
1495
|
* Render `measures` into features and write them to the graphics layer.
|
|
1438
1496
|
* Routes every measure through [[renderMeasureForAdapter]] so pixel sizing is
|
|
@@ -1820,4 +1878,4 @@ declare function nearestWorldCopyLng(lng: number, refLng: number): number;
|
|
|
1820
1878
|
/** `nearestWorldCopyLng` applied to a lon/lat position. */
|
|
1821
1879
|
declare function nearestWorldCopyPosition(position: Position, refLng: number): Position;
|
|
1822
1880
|
//#endregion
|
|
1823
|
-
export { BaseMapAdapter, type CombinedAbort, DEFAULT_LABEL_SIZE_PIXELS, DEFAULT_TEXT_SIZE_MAX_PIXELS, DEFAULT_TEXT_SIZE_MIN_PIXELS, type DrawMeasureDraft, type DrawOptions, type DrawPointSymbolDraft, type DrawSession, type EditChangeEvent, type EditManyOptions, type EditMode, type EditOptions, type EditPointerDriver, type EditSession, type FeatureOps, type Graphic, type GraphicEditChangeEvent, type GraphicEditSession, type GraphicRender, type GraphicSnapshot, type GraphicTransformChangeEvent, type GraphicTransformSession, type GuideStyle, type HandleStyle, type IconResource, type InteractionHit, type InteractionStyle, type LayerId, type MapAdapter, type MapCursor, type MapEvent, type MapEventHandler, type NativeEventEntry, type PickEvent, type PickHandler, type PickOptions, type PixelCoordinate, type PointSymbol, type PointSymbolAnchor, type PointSymbolCapability, PointSymbolCapabilityRequiredError, type PointSymbolColors, type PointSymbolFootprint, type PointSymbolGraphicModifiers, type PointSymbolRender, type PointSymbolSize, type PointSymbolStyle, type PointerCallback, PointerCallbackHub, type PointerEventInfo, type SessionChangeSource, type SessionHistory, type SessionHistoryState, 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, clonePointSymbol, coerceHandleStyle, combineWithHostSignal, getSizeAnchor, hitTestFeature, hitTestIconFeature, ignoreAbort, isPointSymbol, isTacticalDrawAbortError, nearestWorldCopyLng, nearestWorldCopyPosition, pickHitTolerance, pointSymbolFootprint, resolveGroundTextSizePixels, tryControlMeasureIdFromFeature };
|
|
1881
|
+
export { BaseMapAdapter, type CombinedAbort, DEFAULT_LABEL_SIZE_PIXELS, DEFAULT_TEXT_SIZE_MAX_PIXELS, DEFAULT_TEXT_SIZE_MIN_PIXELS, type DrawMeasureDraft, type DrawOptions, type DrawPointSymbolDraft, type DrawSession, type EditChangeEvent, type EditManyOptions, type EditMode, type EditOptions, type EditPointerDriver, type EditSession, type FeatureOps, type Graphic, type GraphicEditChangeEvent, type GraphicEditSession, type GraphicGeometrySnappingOptions, type GraphicRender, type GraphicSnapshot, type GraphicTransformChangeEvent, type GraphicTransformSession, type GuideStyle, type HandleStyle, type IconResource, type InteractionHit, type InteractionStyle, type LayerId, type MapAdapter, type MapCursor, type MapEvent, type MapEventHandler, type NativeEventEntry, type PickEvent, type PickHandler, type PickOptions, type PixelCoordinate, type PointSymbol, type PointSymbolAnchor, type PointSymbolCapability, PointSymbolCapabilityRequiredError, type PointSymbolColors, type PointSymbolFootprint, type PointSymbolGraphicModifiers, type PointSymbolRender, type PointSymbolSize, type PointSymbolStyle, type PointerCallback, PointerCallbackHub, type PointerEventInfo, type SessionChangeSource, type SessionHistory, type SessionHistoryState, type SettleReason, type SizeAnchor, type SnapCandidate, type SnapCandidateProvider, type SnapCandidateRequest, type SnapInteraction, type SnapResult, type SnappingOptions, 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, clonePointSymbol, coerceHandleStyle, combineWithHostSignal, getSizeAnchor, hitTestFeature, hitTestIconFeature, ignoreAbort, isPointSymbol, isTacticalDrawAbortError, nearestWorldCopyLng, nearestWorldCopyPosition, pickHitTolerance, pointSymbolFootprint, resolveGroundTextSizePixels, tryControlMeasureIdFromFeature };
|
package/dist/index.mjs
CHANGED
|
@@ -298,21 +298,24 @@ function resolveGroundTextSizePixels(textSizeMeters, resolution, text) {
|
|
|
298
298
|
}
|
|
299
299
|
//#endregion
|
|
300
300
|
//#region src/gestures/hit-test.ts
|
|
301
|
-
/**
|
|
302
|
-
function
|
|
303
|
-
const a = toPixel(p1);
|
|
304
|
-
const b = toPixel(p2);
|
|
305
|
-
if (!a || !b) return null;
|
|
301
|
+
/** Clamped parameter t ∈ [0, 1] of `pixel` projected onto the segment a→b in pixel space, or null for a zero-length segment. */
|
|
302
|
+
function clampedSegmentParameter(pixel, a, b) {
|
|
306
303
|
const dx = b[0] - a[0];
|
|
307
304
|
const dy = b[1] - a[1];
|
|
308
305
|
const lengthSq = dx * dx + dy * dy;
|
|
309
306
|
if (lengthSq === 0) return null;
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
const
|
|
307
|
+
const t = ((pixel[0] - a[0]) * dx + (pixel[1] - a[1]) * dy) / lengthSq;
|
|
308
|
+
return Math.max(0, Math.min(1, t));
|
|
309
|
+
}
|
|
310
|
+
/** 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. */
|
|
311
|
+
function pixelDistanceToSegment(pixel, p1, p2, toPixel) {
|
|
312
|
+
const a = toPixel(p1);
|
|
313
|
+
const b = toPixel(p2);
|
|
314
|
+
if (!a || !b) return null;
|
|
315
|
+
const t = clampedSegmentParameter(pixel, a, b);
|
|
316
|
+
if (t === null) return null;
|
|
317
|
+
const ddx = pixel[0] - (a[0] + t * (b[0] - a[0]));
|
|
318
|
+
const ddy = pixel[1] - (a[1] + t * (b[1] - a[1]));
|
|
316
319
|
return Math.sqrt(ddx * ddx + ddy * ddy);
|
|
317
320
|
}
|
|
318
321
|
/** Even-odd point-in-ring test in pixel space. */
|
|
@@ -1013,6 +1016,188 @@ function buildGuideFeatures(points, isAreaKind, trailingFixedSlots = 0) {
|
|
|
1013
1016
|
return features;
|
|
1014
1017
|
}
|
|
1015
1018
|
//#endregion
|
|
1019
|
+
//#region src/tactical-draw/snapping.ts
|
|
1020
|
+
/** Resolve a draw-interaction map event through `snap`, falling back to the event coordinate. */
|
|
1021
|
+
function snappedDrawPosition(snap, event) {
|
|
1022
|
+
return snap?.({
|
|
1023
|
+
coordinate: event.coordinate,
|
|
1024
|
+
pixel: event.pixel,
|
|
1025
|
+
interaction: "draw",
|
|
1026
|
+
originalEvent: event.originalEvent
|
|
1027
|
+
})?.coordinate ?? event.coordinate;
|
|
1028
|
+
}
|
|
1029
|
+
const DEFAULT_TOLERANCE_PIXELS = 12;
|
|
1030
|
+
function graphicCandidates(graphics) {
|
|
1031
|
+
const candidates = [];
|
|
1032
|
+
for (const graphic of graphics) {
|
|
1033
|
+
if (isPointSymbol(graphic)) {
|
|
1034
|
+
candidates.push({
|
|
1035
|
+
id: `${graphic.id}:anchor`,
|
|
1036
|
+
coordinate: graphic.position,
|
|
1037
|
+
kind: "anchor",
|
|
1038
|
+
graphicId: graphic.id
|
|
1039
|
+
});
|
|
1040
|
+
continue;
|
|
1041
|
+
}
|
|
1042
|
+
graphic.controlPoints.forEach((coordinate, controlPointIndex) => {
|
|
1043
|
+
candidates.push({
|
|
1044
|
+
id: `${graphic.id}:control-point:${controlPointIndex}`,
|
|
1045
|
+
coordinate,
|
|
1046
|
+
kind: "control-point",
|
|
1047
|
+
graphicId: graphic.id,
|
|
1048
|
+
controlPointIndex
|
|
1049
|
+
});
|
|
1050
|
+
});
|
|
1051
|
+
}
|
|
1052
|
+
return candidates;
|
|
1053
|
+
}
|
|
1054
|
+
function isSelfCandidate(candidate, request) {
|
|
1055
|
+
if (request.graphicId === void 0 || candidate.graphicId !== request.graphicId) return false;
|
|
1056
|
+
if (request.interaction === "reshape" && request.controlPointIndex !== void 0) return candidate.controlPointIndex === void 0 || candidate.controlPointIndex === request.controlPointIndex;
|
|
1057
|
+
return true;
|
|
1058
|
+
}
|
|
1059
|
+
function isLabelFeature(feature) {
|
|
1060
|
+
const properties = feature.properties;
|
|
1061
|
+
return properties?.part === "label" || typeof properties?.labelPlacementKey === "string" || typeof properties?.text === "string";
|
|
1062
|
+
}
|
|
1063
|
+
function collectGeometryPaths(geometry, featureId, graphicId, out) {
|
|
1064
|
+
const add = (positions, suffix) => {
|
|
1065
|
+
if (positions.length > 0) out.push({
|
|
1066
|
+
id: `${featureId}:${suffix}`,
|
|
1067
|
+
graphicId,
|
|
1068
|
+
positions
|
|
1069
|
+
});
|
|
1070
|
+
};
|
|
1071
|
+
switch (geometry.type) {
|
|
1072
|
+
case "LineString":
|
|
1073
|
+
add(geometry.coordinates, "line");
|
|
1074
|
+
break;
|
|
1075
|
+
case "MultiLineString":
|
|
1076
|
+
geometry.coordinates.forEach((line, index) => add(line, `line:${index}`));
|
|
1077
|
+
break;
|
|
1078
|
+
case "Polygon":
|
|
1079
|
+
geometry.coordinates.forEach((ring, index) => add(ring, `ring:${index}`));
|
|
1080
|
+
break;
|
|
1081
|
+
case "MultiPolygon":
|
|
1082
|
+
geometry.coordinates.forEach((polygon, polygonIndex) => polygon.forEach((ring, ringIndex) => add(ring, `ring:${polygonIndex}:${ringIndex}`)));
|
|
1083
|
+
break;
|
|
1084
|
+
case "GeometryCollection":
|
|
1085
|
+
geometry.geometries.forEach((child, index) => collectGeometryPaths(child, `${featureId}:geometry:${index}`, graphicId, out));
|
|
1086
|
+
break;
|
|
1087
|
+
case "Point":
|
|
1088
|
+
case "MultiPoint": break;
|
|
1089
|
+
}
|
|
1090
|
+
}
|
|
1091
|
+
function indexGeometryFeatures(features) {
|
|
1092
|
+
const paths = [];
|
|
1093
|
+
features.forEach((feature, index) => {
|
|
1094
|
+
if (!feature.geometry || isLabelFeature(feature)) return;
|
|
1095
|
+
const graphicId = tryControlMeasureIdFromFeature(feature);
|
|
1096
|
+
if (!graphicId) return;
|
|
1097
|
+
const featureId = typeof feature.id === "string" ? feature.id : `${graphicId}:feature:${index}`;
|
|
1098
|
+
collectGeometryPaths(feature.geometry, featureId, graphicId, paths);
|
|
1099
|
+
});
|
|
1100
|
+
return paths;
|
|
1101
|
+
}
|
|
1102
|
+
function interpolatePosition(a, b, t) {
|
|
1103
|
+
const dimensions = Math.min(a.length, b.length);
|
|
1104
|
+
const position = [];
|
|
1105
|
+
for (let index = 0; index < dimensions; index += 1) position.push(a[index] + (b[index] - a[index]) * t);
|
|
1106
|
+
return position;
|
|
1107
|
+
}
|
|
1108
|
+
function generatedGeometryCandidates(adapter, paths, request, options) {
|
|
1109
|
+
const resolved = options === true ? {} : options;
|
|
1110
|
+
const edges = resolved.edges ?? true;
|
|
1111
|
+
const vertices = resolved.vertices ?? false;
|
|
1112
|
+
const candidates = [];
|
|
1113
|
+
for (const path of paths) {
|
|
1114
|
+
if (vertices) path.positions.forEach((coordinate, index) => {
|
|
1115
|
+
candidates.push({
|
|
1116
|
+
id: `${path.id}:vertex:${index}`,
|
|
1117
|
+
coordinate,
|
|
1118
|
+
kind: "graphic-vertex",
|
|
1119
|
+
graphicId: path.graphicId
|
|
1120
|
+
});
|
|
1121
|
+
});
|
|
1122
|
+
if (!edges) continue;
|
|
1123
|
+
for (let index = 1; index < path.positions.length; index += 1) {
|
|
1124
|
+
const a = path.positions[index - 1];
|
|
1125
|
+
const b = path.positions[index];
|
|
1126
|
+
const aPixel = adapter.getPixelFromCoordinate(a);
|
|
1127
|
+
const bPixel = adapter.getPixelFromCoordinate(b);
|
|
1128
|
+
if (!aPixel || !bPixel) continue;
|
|
1129
|
+
const t = clampedSegmentParameter(request.pixel, aPixel, bPixel) ?? 0;
|
|
1130
|
+
candidates.push({
|
|
1131
|
+
id: `${path.id}:edge:${index - 1}`,
|
|
1132
|
+
coordinate: interpolatePosition(a, b, t),
|
|
1133
|
+
kind: "graphic-edge",
|
|
1134
|
+
graphicId: path.graphicId
|
|
1135
|
+
});
|
|
1136
|
+
}
|
|
1137
|
+
}
|
|
1138
|
+
return candidates;
|
|
1139
|
+
}
|
|
1140
|
+
function createSnapResolver(adapter, getGraphics, getGeometryFeatures, getOptions) {
|
|
1141
|
+
let indexedGraphics;
|
|
1142
|
+
let indexedCandidates = [];
|
|
1143
|
+
let indexedFeatures;
|
|
1144
|
+
let indexedGeometryPaths = [];
|
|
1145
|
+
const builtInCandidates = () => {
|
|
1146
|
+
const graphics = getGraphics();
|
|
1147
|
+
if (graphics !== indexedGraphics) {
|
|
1148
|
+
indexedGraphics = graphics;
|
|
1149
|
+
indexedCandidates = graphicCandidates(graphics);
|
|
1150
|
+
}
|
|
1151
|
+
return indexedCandidates;
|
|
1152
|
+
};
|
|
1153
|
+
const geometryPaths = () => {
|
|
1154
|
+
const features = getGeometryFeatures();
|
|
1155
|
+
if (features !== indexedFeatures) {
|
|
1156
|
+
indexedFeatures = features;
|
|
1157
|
+
indexedGeometryPaths = indexGeometryFeatures(features);
|
|
1158
|
+
}
|
|
1159
|
+
return indexedGeometryPaths;
|
|
1160
|
+
};
|
|
1161
|
+
return (request) => {
|
|
1162
|
+
const options = getOptions();
|
|
1163
|
+
const clear = () => options?.onSnap?.(null);
|
|
1164
|
+
if (!options?.enabled || options.bypass?.(request.originalEvent)) {
|
|
1165
|
+
clear();
|
|
1166
|
+
return null;
|
|
1167
|
+
}
|
|
1168
|
+
const tolerance = options.tolerancePixels ?? DEFAULT_TOLERANCE_PIXELS;
|
|
1169
|
+
if (!Number.isFinite(tolerance) || tolerance < 0) {
|
|
1170
|
+
clear();
|
|
1171
|
+
return null;
|
|
1172
|
+
}
|
|
1173
|
+
const candidateLists = [];
|
|
1174
|
+
if (options.sources?.graphics !== false) candidateLists.push(builtInCandidates());
|
|
1175
|
+
const graphicGeometry = options.sources?.graphicGeometry;
|
|
1176
|
+
if (graphicGeometry) candidateLists.push(generatedGeometryCandidates(adapter, geometryPaths(), request, graphicGeometry));
|
|
1177
|
+
const external = options.sources?.external?.(request);
|
|
1178
|
+
if (external) candidateLists.push(external);
|
|
1179
|
+
let best = null;
|
|
1180
|
+
for (const list of candidateLists) for (const candidate of list) {
|
|
1181
|
+
if (isSelfCandidate(candidate, request)) continue;
|
|
1182
|
+
const pixel = adapter.getPixelFromCoordinate(candidate.coordinate);
|
|
1183
|
+
if (!pixel) continue;
|
|
1184
|
+
const distancePixels = Math.hypot(pixel[0] - request.pixel[0], pixel[1] - request.pixel[1]);
|
|
1185
|
+
if (distancePixels > tolerance) continue;
|
|
1186
|
+
const priority = candidate.priority ?? 0;
|
|
1187
|
+
const bestPriority = best?.candidate.priority ?? 0;
|
|
1188
|
+
if (best && (distancePixels > best.distancePixels || distancePixels === best.distancePixels && priority <= bestPriority)) continue;
|
|
1189
|
+
best = {
|
|
1190
|
+
coordinate: [...candidate.coordinate],
|
|
1191
|
+
pixel: [...pixel],
|
|
1192
|
+
candidate,
|
|
1193
|
+
distancePixels
|
|
1194
|
+
};
|
|
1195
|
+
}
|
|
1196
|
+
options.onSnap?.(best);
|
|
1197
|
+
return best;
|
|
1198
|
+
};
|
|
1199
|
+
}
|
|
1200
|
+
//#endregion
|
|
1016
1201
|
//#region src/tactical-draw/draw-controller.ts
|
|
1017
1202
|
const PREVIEW_CM_ID$1 = "__td_preview__";
|
|
1018
1203
|
const PREVIEW_CURSOR$1 = "crosshair";
|
|
@@ -1030,7 +1215,7 @@ const PREVIEW_CURSOR$1 = "crosshair";
|
|
|
1030
1215
|
* kinds need no host UI.
|
|
1031
1216
|
*/
|
|
1032
1217
|
function runFixedLengthDraw(options) {
|
|
1033
|
-
const { adapter, kind, previewLayer, guideLayer, graphicsStyle, generateId, signal, measureOptions, measureStyle, measureProperties, measureTextAmplifiers, guide: guideOpt, sizeAnchor, onSettled } = options;
|
|
1218
|
+
const { adapter, kind, previewLayer, guideLayer, graphicsStyle, generateId, signal, measureOptions, measureStyle, measureProperties, measureTextAmplifiers, guide: guideOpt, sizeAnchor, onSettled, snap } = options;
|
|
1034
1219
|
const metadata = getControlMeasureMetadata(kind);
|
|
1035
1220
|
const rule = metadata.rule;
|
|
1036
1221
|
const min = metadata.minCoordinates;
|
|
@@ -1048,7 +1233,7 @@ function runFixedLengthDraw(options) {
|
|
|
1048
1233
|
const savedCursor = "";
|
|
1049
1234
|
const handleClick = (event) => {
|
|
1050
1235
|
if (ctx.settled) return;
|
|
1051
|
-
committed.push(event
|
|
1236
|
+
committed.push(snappedDrawPosition(snap, event));
|
|
1052
1237
|
rubberBand = void 0;
|
|
1053
1238
|
if (committed.length >= required) {
|
|
1054
1239
|
ctx.commit(buildSnapshot);
|
|
@@ -1059,7 +1244,7 @@ function runFixedLengthDraw(options) {
|
|
|
1059
1244
|
const handlePointerMove = (event) => {
|
|
1060
1245
|
if (ctx.settled) return;
|
|
1061
1246
|
if (committed.length === 0) return;
|
|
1062
|
-
rubberBand = event
|
|
1247
|
+
rubberBand = snappedDrawPosition(snap, event);
|
|
1063
1248
|
renderPreview();
|
|
1064
1249
|
};
|
|
1065
1250
|
function renderPreview() {
|
|
@@ -1285,7 +1470,7 @@ const PREVIEW_CURSOR = "crosshair";
|
|
|
1285
1470
|
* added point again" as additional gesture-level commit triggers.
|
|
1286
1471
|
*/
|
|
1287
1472
|
function runVariableLengthDraw(options) {
|
|
1288
|
-
const { adapter, kind, previewLayer, guideLayer, graphicsStyle, generateId, signal, onSession, seed, measureOptions, measureStyle, measureProperties, measureTextAmplifiers, guide: guideOpt, sizeAnchor, onSettled } = options;
|
|
1473
|
+
const { adapter, kind, previewLayer, guideLayer, graphicsStyle, generateId, signal, onSession, seed, measureOptions, measureStyle, measureProperties, measureTextAmplifiers, guide: guideOpt, sizeAnchor, onSettled, snap } = options;
|
|
1289
1474
|
const metadata = getControlMeasureMetadata(kind);
|
|
1290
1475
|
if (typeof metadata.minCoordinates !== "number") throw new Error(`runVariableLengthDraw: kind "${kind}" has no minCoordinates metadata`);
|
|
1291
1476
|
const min = metadata.minCoordinates;
|
|
@@ -1392,7 +1577,7 @@ function runVariableLengthDraw(options) {
|
|
|
1392
1577
|
}
|
|
1393
1578
|
const handleClick = (event) => {
|
|
1394
1579
|
if (ctx.settled) return;
|
|
1395
|
-
const pos = roundControlPoint(event
|
|
1580
|
+
const pos = roundControlPoint(snappedDrawPosition(snap, event));
|
|
1396
1581
|
const lastSpineIdx = committed.length - 1 - trailingFixed;
|
|
1397
1582
|
const finishIndices = closedRing && lastSpineIdx > 0 ? [lastSpineIdx, 0] : [lastSpineIdx];
|
|
1398
1583
|
for (let i = 0; i < committed.length; i++) if (positionsEqual(pos, committed[i])) {
|
|
@@ -1433,7 +1618,7 @@ function runVariableLengthDraw(options) {
|
|
|
1433
1618
|
const handlePointerMove = (event) => {
|
|
1434
1619
|
if (ctx.settled) return;
|
|
1435
1620
|
if (committed.length === 0) return;
|
|
1436
|
-
rubberBand = event
|
|
1621
|
+
rubberBand = snappedDrawPosition(snap, event);
|
|
1437
1622
|
renderPreview();
|
|
1438
1623
|
};
|
|
1439
1624
|
function renderPreview() {
|
|
@@ -2435,7 +2620,7 @@ function mergeAmplifierPlacementField(existing, incoming) {
|
|
|
2435
2620
|
* - close / abort / signal / preempt / destroy paths
|
|
2436
2621
|
*/
|
|
2437
2622
|
function runEdit(opts) {
|
|
2438
|
-
const { adapter, measure, graphicsLayer, previewLayer, guideLayer, handlesLayer, graphicsStyle, signal, closeOnClickAway = true, modes: initialModes, interactionStyle, onSession, handleIdPrefix, guide: guideOpt, restoreOriginalToGraphics, wasOnGraphicsLayer, onSettled, onClickAwayGraphicsPick } = opts;
|
|
2623
|
+
const { adapter, measure, graphicsLayer, previewLayer, guideLayer, handlesLayer, graphicsStyle, signal, closeOnClickAway = true, modes: initialModes, interactionStyle, onSession, handleIdPrefix, guide: guideOpt, restoreOriginalToGraphics, wasOnGraphicsLayer, onSettled, onClickAwayGraphicsPick, snap } = opts;
|
|
2439
2624
|
const renderOpts = graphicsStyle ? { graphicsStyle } : void 0;
|
|
2440
2625
|
let sizeAnchor = opts.sizeAnchor ?? "ground";
|
|
2441
2626
|
const metadata = getControlMeasureMetadata(measure.kind);
|
|
@@ -3169,6 +3354,38 @@ function runEdit(opts) {
|
|
|
3169
3354
|
}
|
|
3170
3355
|
};
|
|
3171
3356
|
let activeDrag = null;
|
|
3357
|
+
function snappedPixel(pixel, info, interaction, controlPointIndex) {
|
|
3358
|
+
if (!snap) return pixel;
|
|
3359
|
+
return snap({
|
|
3360
|
+
coordinate: driver.fromPixel(pixel),
|
|
3361
|
+
pixel,
|
|
3362
|
+
interaction,
|
|
3363
|
+
graphicId: measure.id,
|
|
3364
|
+
controlPointIndex,
|
|
3365
|
+
originalEvent: info?.native
|
|
3366
|
+
})?.pixel ?? pixel;
|
|
3367
|
+
}
|
|
3368
|
+
function translatedBoxPixel(pixel, info, drag) {
|
|
3369
|
+
if (!snap || drag.fsm.kind !== "body") return pixel;
|
|
3370
|
+
const first = drag.preDragPoints[0];
|
|
3371
|
+
if (!first) return pixel;
|
|
3372
|
+
const cursor = driver.fromPixel(pixel);
|
|
3373
|
+
const origin = driver.fromPixel(drag.downPixel);
|
|
3374
|
+
const anchor = [...first];
|
|
3375
|
+
anchor[0] = first[0] + cursor[0] - origin[0];
|
|
3376
|
+
anchor[1] = first[1] + cursor[1] - origin[1];
|
|
3377
|
+
const anchorPixel = driver.toPixel(anchor);
|
|
3378
|
+
if (!anchorPixel) return pixel;
|
|
3379
|
+
const result = snap({
|
|
3380
|
+
coordinate: anchor,
|
|
3381
|
+
pixel: anchorPixel,
|
|
3382
|
+
interaction: "translate",
|
|
3383
|
+
graphicId: measure.id,
|
|
3384
|
+
originalEvent: info?.native
|
|
3385
|
+
});
|
|
3386
|
+
if (!result) return pixel;
|
|
3387
|
+
return [pixel[0] + result.pixel[0] - anchorPixel[0], pixel[1] + result.pixel[1] - anchorPixel[1]];
|
|
3388
|
+
}
|
|
3172
3389
|
/**
|
|
3173
3390
|
* A live label *move* drag: direct label grab, the floating grip, or a body
|
|
3174
3391
|
* grab inside the selected label's transform box (ADR-0017 box machinery
|
|
@@ -3370,7 +3587,8 @@ function runEdit(opts) {
|
|
|
3370
3587
|
});
|
|
3371
3588
|
activeDrag = {
|
|
3372
3589
|
fsm,
|
|
3373
|
-
preDragPoints
|
|
3590
|
+
preDragPoints,
|
|
3591
|
+
controlPointIndex: hit.kind === "midpoint" ? hit.index + 1 : hit.index
|
|
3374
3592
|
};
|
|
3375
3593
|
if (fsm.kind === "midpoint") {
|
|
3376
3594
|
workingPoints.splice(0, workingPoints.length, ...initialPoints);
|
|
@@ -3415,17 +3633,19 @@ function runEdit(opts) {
|
|
|
3415
3633
|
}
|
|
3416
3634
|
}
|
|
3417
3635
|
};
|
|
3418
|
-
function paintDragSnapshot(pixel) {
|
|
3636
|
+
function paintDragSnapshot(pixel, info) {
|
|
3419
3637
|
if (!activeDrag) return;
|
|
3420
|
-
const
|
|
3638
|
+
const resolvedPixel = snappedPixel(pixel, info, "reshape", activeDrag.controlPointIndex);
|
|
3639
|
+
const snapshot = activeDrag.fsm.move(resolvedPixel);
|
|
3421
3640
|
workingPoints.splice(0, workingPoints.length, ...snapshot.points);
|
|
3422
3641
|
renderPreview();
|
|
3423
3642
|
renderHandlesLayer();
|
|
3424
3643
|
recomputeDirty();
|
|
3425
3644
|
}
|
|
3426
|
-
function paintBoxDragSnapshot(pixel, constrainRotation = false) {
|
|
3645
|
+
function paintBoxDragSnapshot(pixel, info, constrainRotation = false) {
|
|
3427
3646
|
if (!activeBoxDrag) return;
|
|
3428
|
-
const
|
|
3647
|
+
const resolvedPixel = translatedBoxPixel(pixel, info, activeBoxDrag);
|
|
3648
|
+
const snapshot = activeBoxDrag.fsm.move(resolvedPixel, { constrainRotation });
|
|
3429
3649
|
activeBoxDrag.lastSnapshot = snapshot;
|
|
3430
3650
|
workingPoints.splice(0, workingPoints.length, ...snapshot.points);
|
|
3431
3651
|
workingAmplifierPlacements = transformAmplifierPlacements(activeBoxDrag.preDragAmplifierPlacements, activeBoxDrag.preDragBox, snapshot.box, driver);
|
|
@@ -3468,8 +3688,8 @@ function runEdit(opts) {
|
|
|
3468
3688
|
};
|
|
3469
3689
|
renderPreview();
|
|
3470
3690
|
renderHandlesLayer();
|
|
3471
|
-
} else if (activeDrag) paintDragSnapshot(pixel);
|
|
3472
|
-
else if (activeBoxDrag) paintBoxDragSnapshot(pixel, info?.shiftKey);
|
|
3691
|
+
} else if (activeDrag) paintDragSnapshot(pixel, info);
|
|
3692
|
+
else if (activeBoxDrag) paintBoxDragSnapshot(pixel, info, info?.shiftKey);
|
|
3473
3693
|
};
|
|
3474
3694
|
/** Reset drag-in-flight bookkeeping shared by every "gesture ended" path. */
|
|
3475
3695
|
function endDragBookkeeping() {
|
|
@@ -3516,10 +3736,10 @@ function runEdit(opts) {
|
|
|
3516
3736
|
driver.setDragPanEnabled(true);
|
|
3517
3737
|
return;
|
|
3518
3738
|
}
|
|
3519
|
-
const { fsm, preDragPoints } = activeDrag;
|
|
3739
|
+
const { fsm, preDragPoints, controlPointIndex } = activeDrag;
|
|
3520
3740
|
activeDrag = null;
|
|
3521
3741
|
driver.setDragPanEnabled(true);
|
|
3522
|
-
const next = fsm.end(pixel);
|
|
3742
|
+
const next = fsm.end(snappedPixel(pixel, info, "reshape", controlPointIndex));
|
|
3523
3743
|
replaceWorkingPoints(preDragPoints);
|
|
3524
3744
|
commitGesture(next);
|
|
3525
3745
|
return;
|
|
@@ -3545,7 +3765,12 @@ function runEdit(opts) {
|
|
|
3545
3765
|
bodyClickPending = true;
|
|
3546
3766
|
return;
|
|
3547
3767
|
}
|
|
3548
|
-
const
|
|
3768
|
+
const finalPixel = translatedBoxPixel(pixel, info, {
|
|
3769
|
+
fsm,
|
|
3770
|
+
preDragPoints,
|
|
3771
|
+
downPixel
|
|
3772
|
+
});
|
|
3773
|
+
const finalSnapshot = fsm.move(finalPixel, { constrainRotation: info?.shiftKey });
|
|
3549
3774
|
replaceWorkingPoints(preDragPoints);
|
|
3550
3775
|
workingAmplifierPlacements = preDragAmplifierPlacements;
|
|
3551
3776
|
if (fsm.kind === "rotate") boxAngle += finalSnapshot.box.angle - preDragBox.angle;
|
|
@@ -4798,7 +5023,7 @@ var PointSymbolCapabilityRequiredError = class extends Error {
|
|
|
4798
5023
|
//#region src/tactical-draw/point-symbol-draw-controller.ts
|
|
4799
5024
|
const PREVIEW_ID = "__td_point_symbol_preview__";
|
|
4800
5025
|
function runPointSymbolDraw(options) {
|
|
4801
|
-
const { adapter, capability, draft, previewLayer, generateId, signal, onSettled } = options;
|
|
5026
|
+
const { adapter, capability, draft, previewLayer, generateId, signal, onSettled, snap } = options;
|
|
4802
5027
|
let latestPosition = draft.position;
|
|
4803
5028
|
let ctx;
|
|
4804
5029
|
const savedCursor = "";
|
|
@@ -4818,13 +5043,13 @@ function runPointSymbolDraw(options) {
|
|
|
4818
5043
|
ctx.writeLayer(previewLayer, [plan.feature]);
|
|
4819
5044
|
};
|
|
4820
5045
|
const handlePointerMove = (event) => {
|
|
4821
|
-
latestPosition = event
|
|
5046
|
+
latestPosition = snappedDrawPosition(snap, event);
|
|
4822
5047
|
renderPreview();
|
|
4823
5048
|
};
|
|
4824
5049
|
const handleClick = (event) => {
|
|
4825
|
-
latestPosition = event
|
|
5050
|
+
latestPosition = snappedDrawPosition(snap, event);
|
|
4826
5051
|
ctx.commit(() => {
|
|
4827
|
-
const graphic = build(draft.id ?? generateId(),
|
|
5052
|
+
const graphic = build(draft.id ?? generateId(), latestPosition);
|
|
4828
5053
|
return {
|
|
4829
5054
|
graphic: clonePointSymbol(graphic),
|
|
4830
5055
|
render: capability.render(graphic)
|
|
@@ -4871,7 +5096,7 @@ function symbolBox(adapter, capability, symbol, padding = 0) {
|
|
|
4871
5096
|
};
|
|
4872
5097
|
}
|
|
4873
5098
|
function runPointSymbolEdit(opts) {
|
|
4874
|
-
const { adapter, capability, symbol, graphicsLayer, previewLayer, handlesLayer, signal, closeOnClickAway = true, interactionStyle, onSession, handleIdPrefix, restoreOriginalToGraphics, wasOnGraphicsLayer, onSettled, onClickAwayGraphicsPick } = opts;
|
|
5099
|
+
const { adapter, capability, symbol, graphicsLayer, previewLayer, handlesLayer, signal, closeOnClickAway = true, interactionStyle, onSession, handleIdPrefix, restoreOriginalToGraphics, wasOnGraphicsLayer, onSettled, onClickAwayGraphicsPick, snap } = opts;
|
|
4875
5100
|
let modes = normalisePointModes(opts.modes);
|
|
4876
5101
|
let working = clonePointSymbol(symbol);
|
|
4877
5102
|
let dirty = false;
|
|
@@ -5021,13 +5246,22 @@ function runPointSymbolEdit(opts) {
|
|
|
5021
5246
|
};
|
|
5022
5247
|
driver.setDragPanEnabled(false);
|
|
5023
5248
|
};
|
|
5024
|
-
const transformed = (pixel,
|
|
5249
|
+
const transformed = (pixel, info) => {
|
|
5025
5250
|
if (!drag) return null;
|
|
5026
5251
|
const next = clonePointSymbol(drag.start);
|
|
5027
|
-
if (drag.kind === "body")
|
|
5028
|
-
|
|
5252
|
+
if (drag.kind === "body") {
|
|
5253
|
+
const unsnappedPosition = driver.fromPixel([drag.anchor[0] + pixel[0] - drag.down[0], drag.anchor[1] + pixel[1] - drag.down[1]]);
|
|
5254
|
+
const anchorPixel = driver.toPixel(unsnappedPosition) ?? pixel;
|
|
5255
|
+
next.position = (snap?.({
|
|
5256
|
+
coordinate: unsnappedPosition,
|
|
5257
|
+
pixel: anchorPixel,
|
|
5258
|
+
interaction: "translate",
|
|
5259
|
+
graphicId: symbol.id,
|
|
5260
|
+
originalEvent: info?.native
|
|
5261
|
+
}))?.coordinate ?? unsnappedPosition;
|
|
5262
|
+
} else if (drag.kind === "rotate") {
|
|
5029
5263
|
const rotation = drag.start.rotation + pointerAngle(pixel, drag.anchor) - drag.startPointerAngle;
|
|
5030
|
-
next.rotation = normalizeRotation(
|
|
5264
|
+
next.rotation = normalizeRotation(info?.shiftKey ? constrainRotation(rotation) : rotation);
|
|
5031
5265
|
} else {
|
|
5032
5266
|
const distance = Math.hypot(pixel[0] - drag.anchor[0], pixel[1] - drag.anchor[1]);
|
|
5033
5267
|
next.size.value = Math.max(.1, drag.start.size.value * (distance / drag.startDistance));
|
|
@@ -5035,7 +5269,7 @@ function runPointSymbolEdit(opts) {
|
|
|
5035
5269
|
return next;
|
|
5036
5270
|
};
|
|
5037
5271
|
const onMove = (pixel, info) => {
|
|
5038
|
-
const next = transformed(pixel, info
|
|
5272
|
+
const next = transformed(pixel, info);
|
|
5039
5273
|
if (!next) return;
|
|
5040
5274
|
working = next;
|
|
5041
5275
|
render();
|
|
@@ -5043,7 +5277,7 @@ function runPointSymbolEdit(opts) {
|
|
|
5043
5277
|
const onUp = (pixel, info) => {
|
|
5044
5278
|
if (!drag) return;
|
|
5045
5279
|
const currentDrag = drag;
|
|
5046
|
-
const next = transformed(pixel, info
|
|
5280
|
+
const next = transformed(pixel, info);
|
|
5047
5281
|
drag = null;
|
|
5048
5282
|
suppressClickAway = true;
|
|
5049
5283
|
driver.setDragPanEnabled(true);
|
|
@@ -5140,6 +5374,8 @@ var TacticalDraw = class {
|
|
|
5140
5374
|
defaultInteractionStyle;
|
|
5141
5375
|
generateId;
|
|
5142
5376
|
pointSymbols;
|
|
5377
|
+
snappingOptions;
|
|
5378
|
+
resolveSnap;
|
|
5143
5379
|
destroyed = false;
|
|
5144
5380
|
hasRendered = false;
|
|
5145
5381
|
activeInteraction = new ActiveInteractionTracker();
|
|
@@ -5190,12 +5426,15 @@ var TacticalDraw = class {
|
|
|
5190
5426
|
* surrounding collection state.
|
|
5191
5427
|
*/
|
|
5192
5428
|
lastRenderedMeasures = [];
|
|
5429
|
+
snapGeometryFeatures = [];
|
|
5193
5430
|
constructor(adapter, options) {
|
|
5194
5431
|
this.adapter = adapter;
|
|
5195
5432
|
this.graphicsStyle = resolveStyleHints(BUILT_IN_GRAPHICS_STYLE, options?.graphicsStyle, void 0);
|
|
5196
5433
|
this.defaultInteractionStyle = options?.interactionStyle;
|
|
5197
5434
|
this.generateId = options?.generateId ?? (() => `td-${++this.idCounter}`);
|
|
5198
5435
|
this.pointSymbols = options?.pointSymbols;
|
|
5436
|
+
this.snappingOptions = options?.snapping;
|
|
5437
|
+
this.resolveSnap = createSnapResolver(adapter, () => this.lastRenderedMeasures, () => this.snapGeometryFeatures, () => this.snappingOptions);
|
|
5199
5438
|
const owned = /* @__PURE__ */ new Set();
|
|
5200
5439
|
const provided = options?.layers ?? {};
|
|
5201
5440
|
this.graphicsLayer = resolveSlot(adapter, provided.graphics, owned);
|
|
@@ -5209,6 +5448,16 @@ var TacticalDraw = class {
|
|
|
5209
5448
|
this.adapter.setLayerStyle(this.guideLayer, guideToStyleOptions(this.baseGuideStyle()));
|
|
5210
5449
|
this.adapter.onViewChange(this.handleViewChange);
|
|
5211
5450
|
}
|
|
5451
|
+
/** Replace snapping configuration without recreating the map adapter or façade. */
|
|
5452
|
+
setSnappingOptions(options) {
|
|
5453
|
+
this.assertAlive();
|
|
5454
|
+
this.clearSnapResult();
|
|
5455
|
+
this.snappingOptions = options;
|
|
5456
|
+
}
|
|
5457
|
+
/** Clear transient host affordances when snapping or its interaction ends. */
|
|
5458
|
+
clearSnapResult() {
|
|
5459
|
+
this.snappingOptions?.onSnap?.(null);
|
|
5460
|
+
}
|
|
5212
5461
|
/**
|
|
5213
5462
|
* Render `measures` into features and write them to the graphics layer.
|
|
5214
5463
|
* Routes every measure through [[renderMeasureForAdapter]] so pixel sizing is
|
|
@@ -5231,6 +5480,7 @@ var TacticalDraw = class {
|
|
|
5231
5480
|
}
|
|
5232
5481
|
this.adapter.reconcileLayerIconResources(this.graphicsLayer, [...resources.values()]);
|
|
5233
5482
|
this.adapter.updateLayerFeatures(this.graphicsLayer, features);
|
|
5483
|
+
this.snapGeometryFeatures = features;
|
|
5234
5484
|
}
|
|
5235
5485
|
/**
|
|
5236
5486
|
* Re-render the graphics layer on a view (zoom) change so pixel-denominated
|
|
@@ -5391,6 +5641,7 @@ var TacticalDraw = class {
|
|
|
5391
5641
|
};
|
|
5392
5642
|
const onSettled = () => {
|
|
5393
5643
|
clearSlot();
|
|
5644
|
+
this.clearSnapResult();
|
|
5394
5645
|
if (extraSettle) extraSettle();
|
|
5395
5646
|
};
|
|
5396
5647
|
this.activeInteraction.begin();
|
|
@@ -5444,7 +5695,8 @@ var TacticalDraw = class {
|
|
|
5444
5695
|
previewLayer: this.previewLayer,
|
|
5445
5696
|
generateId: this.generateId,
|
|
5446
5697
|
signal: options?.signal,
|
|
5447
|
-
onSettled
|
|
5698
|
+
onSettled,
|
|
5699
|
+
snap: this.resolveSnap
|
|
5448
5700
|
}), null);
|
|
5449
5701
|
}
|
|
5450
5702
|
const measureDraft = draft;
|
|
@@ -5476,7 +5728,8 @@ var TacticalDraw = class {
|
|
|
5476
5728
|
measureTextAmplifiers: measureDraft.textAmplifiers,
|
|
5477
5729
|
guide: options?.guide,
|
|
5478
5730
|
sizeAnchor: options?.sizeAnchor,
|
|
5479
|
-
onSettled
|
|
5731
|
+
onSettled,
|
|
5732
|
+
snap: this.resolveSnap
|
|
5480
5733
|
}) : runVariableLengthDraw({
|
|
5481
5734
|
adapter: this.adapter,
|
|
5482
5735
|
kind,
|
|
@@ -5493,7 +5746,8 @@ var TacticalDraw = class {
|
|
|
5493
5746
|
measureTextAmplifiers: measureDraft.textAmplifiers,
|
|
5494
5747
|
guide: options?.guide,
|
|
5495
5748
|
sizeAnchor: options?.sizeAnchor,
|
|
5496
|
-
onSettled
|
|
5749
|
+
onSettled,
|
|
5750
|
+
snap: this.resolveSnap
|
|
5497
5751
|
}), null, extraSettle);
|
|
5498
5752
|
}
|
|
5499
5753
|
edit(measure, options) {
|
|
@@ -5522,7 +5776,8 @@ var TacticalDraw = class {
|
|
|
5522
5776
|
restoreOriginalToGraphics,
|
|
5523
5777
|
wasOnGraphicsLayer,
|
|
5524
5778
|
onSettled,
|
|
5525
|
-
onClickAwayGraphicsPick: (event) => this.dispatchHostPick(this.graphicsLayer, event)
|
|
5779
|
+
onClickAwayGraphicsPick: (event) => this.dispatchHostPick(this.graphicsLayer, event),
|
|
5780
|
+
snap: this.resolveSnap
|
|
5526
5781
|
}), (handle) => {
|
|
5527
5782
|
this.activeEdit = handle;
|
|
5528
5783
|
return () => {
|
|
@@ -5562,7 +5817,8 @@ var TacticalDraw = class {
|
|
|
5562
5817
|
restoreOriginalToGraphics,
|
|
5563
5818
|
wasOnGraphicsLayer,
|
|
5564
5819
|
onSettled,
|
|
5565
|
-
onClickAwayGraphicsPick
|
|
5820
|
+
onClickAwayGraphicsPick,
|
|
5821
|
+
snap: this.resolveSnap
|
|
5566
5822
|
}), (handle) => {
|
|
5567
5823
|
this.activeEdit = handle;
|
|
5568
5824
|
return () => {
|
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.23",
|
|
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",
|