leaflet-tual 0.0.0 → 0.1.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.
@@ -0,0 +1,559 @@
1
+ import L from 'leaflet';
2
+
3
+ type GeoPoint = {
4
+ lat: number;
5
+ lng: number;
6
+ };
7
+ type ScreenPoint = {
8
+ x: number;
9
+ y: number;
10
+ };
11
+ type ArrowStyle = 'linear' | 'curved' | 'bi' | 'elbow' | 's-curve';
12
+ type ShapeKind = 'square' | 'circle' | 'star' | 'actor' | 'triangle' | 'diamond' | 'hexagon' | 'marker';
13
+ type CanvasTool = 'select' | 'freedraw' | 'arrow-linear' | 'arrow-curved' | 'arrow-bi' | 'arrow-elbow' | 'arrow-s-curve' | 'shape' | 'ruler' | 'note' | 'text';
14
+ type ToolbarToolGroupId = 'select' | 'freedraw' | 'arrow' | 'shape' | 'ruler' | 'note' | 'text';
15
+ type ArrowHeadStyle = 'triangle' | 'open' | 'both' | 'none';
16
+ interface ArrowItem {
17
+ id: string;
18
+ type: 'arrow';
19
+ arrowStyle: ArrowStyle;
20
+ start: GeoPoint;
21
+ end: GeoPoint;
22
+ controlPoint?: GeoPoint;
23
+ color: string;
24
+ strokeWidth: number;
25
+ dashed?: boolean;
26
+ headStyle?: ArrowHeadStyle;
27
+ label?: string;
28
+ labelMode?: boolean;
29
+ hasLabelMode?: boolean;
30
+ createdAt: number;
31
+ }
32
+ interface FreeDrawItem {
33
+ id: string;
34
+ type: 'freedraw';
35
+ points: GeoPoint[];
36
+ color: string;
37
+ strokeWidth: number;
38
+ dashed?: boolean;
39
+ createdAt: number;
40
+ }
41
+ interface ShapeItem {
42
+ id: string;
43
+ type: 'shape';
44
+ shape: ShapeKind;
45
+ start: GeoPoint;
46
+ end: GeoPoint;
47
+ color: string;
48
+ fillColor?: string;
49
+ filled?: boolean;
50
+ strokeWidth: number;
51
+ dashed?: boolean;
52
+ label?: string;
53
+ labelMode?: boolean;
54
+ hasLabelMode?: boolean;
55
+ createdAt: number;
56
+ }
57
+ type NoteCollapseState = 'expanded' | 'collapsed' | 'compact';
58
+ interface NoteItem {
59
+ id: string;
60
+ type: 'note';
61
+ position: GeoPoint;
62
+ title?: string;
63
+ text: string;
64
+ backgroundColor: string;
65
+ textColor: string;
66
+ width?: number;
67
+ height?: number;
68
+ minimized?: boolean | 'compact';
69
+ collapseState?: NoteCollapseState;
70
+ createdAt: number;
71
+ }
72
+ interface TextItem {
73
+ id: string;
74
+ type: 'text';
75
+ position: GeoPoint;
76
+ text: string;
77
+ color: string;
78
+ initialFontSize?: number;
79
+ baseZoom?: number;
80
+ fontWeight?: 'normal' | 'bold';
81
+ backgroundColor?: string;
82
+ createdAt: number;
83
+ }
84
+ interface RulerItem {
85
+ id: string;
86
+ type: 'ruler';
87
+ start: GeoPoint;
88
+ end: GeoPoint;
89
+ color: string;
90
+ strokeWidth: number;
91
+ dashed?: boolean;
92
+ label?: string;
93
+ unit?: 'metric' | 'imperial';
94
+ createdAt: number;
95
+ }
96
+ type CanvasItem = ArrowItem | FreeDrawItem | ShapeItem | NoteItem | TextItem | RulerItem;
97
+
98
+ type ToolbarPosition = 'top' | 'bottom' | 'left' | 'right' | 'top-center' | 'bottom-center' | 'left-center' | 'right-center';
99
+ type ToolbarOrientation = 'horizontal' | 'vertical';
100
+ interface CanvasLabels {
101
+ select?: string;
102
+ freedraw?: string;
103
+ arrowGroup?: string;
104
+ arrowLinear?: string;
105
+ arrowCurved?: string;
106
+ arrowBi?: string;
107
+ arrowElbow?: string;
108
+ arrowSCurve?: string;
109
+ shapesGroup?: string;
110
+ shapesModalTitle?: string;
111
+ shapeSquare?: string;
112
+ shapeCircle?: string;
113
+ shapeStar?: string;
114
+ shapeActor?: string;
115
+ shapeTriangle?: string;
116
+ shapeDiamond?: string;
117
+ shapeHexagon?: string;
118
+ shapeMarker?: string;
119
+ ruler?: string;
120
+ note?: string;
121
+ text?: string;
122
+ undo?: string;
123
+ redo?: string;
124
+ delete?: string;
125
+ clear?: string;
126
+ color?: string;
127
+ width?: string;
128
+ dashed?: string;
129
+ filled?: string;
130
+ arrowStylePrefix?: string;
131
+ arrowLabelPlaceholder?: string;
132
+ shapeLabelPlaceholder?: string;
133
+ noteTheme?: string;
134
+ noteDefaultTitle?: string;
135
+ noteTitlePlaceholder?: string;
136
+ noteTextPlaceholder?: string;
137
+ noteExpand?: string;
138
+ noteCollapse?: string;
139
+ noteCompact?: string;
140
+ noteDelete?: string;
141
+ noteResize?: string;
142
+ fontSize?: string;
143
+ textPlaceholder?: string;
144
+ textEmptyFallback?: string;
145
+ textEdit?: string;
146
+ textDone?: string;
147
+ textBold?: string;
148
+ textDecreaseSize?: string;
149
+ textIncreaseSize?: string;
150
+ textDelete?: string;
151
+ collapseToolbar?: string;
152
+ expandToolbar?: string;
153
+ }
154
+ interface CanvasAnnotationTheme {
155
+ selectionGlowColor?: string;
156
+ selectionGlowWidth?: number;
157
+ guideLineDash?: readonly number[];
158
+ guideLineColor?: string;
159
+ guideLineWidth?: number;
160
+ endpointHandleColor?: string;
161
+ controlHandleColor?: string;
162
+ handleFillColor?: string;
163
+ handleRadius?: number;
164
+ handleStrokeWidth?: number;
165
+ shadowColor?: string;
166
+ shadowBlur?: number;
167
+ shadowOffsetY?: number;
168
+ labelBackgroundColor?: string;
169
+ labelTextColor?: string;
170
+ labelFont?: string;
171
+ labelBorderColor?: string;
172
+ labelBorderWidth?: number;
173
+ labelBorderRadius?: number;
174
+ labelPaddingX?: number;
175
+ labelPaddingY?: number;
176
+ labelShadowColor?: string;
177
+ labelShadowBlur?: number;
178
+ shapeDefaultFillOpacity?: number;
179
+ shapeBorderRadius?: number;
180
+ labelMinShapeSize?: number;
181
+ labelMaxTextWidth?: number;
182
+ fitLabelsToShape?: boolean;
183
+ }
184
+ type ArrowRenderTheme = CanvasAnnotationTheme;
185
+ interface LeafletCanvasClassNames {
186
+ overlay?: string;
187
+ canvas?: string;
188
+ drawingSurface?: string;
189
+ itemsContainer?: string;
190
+ toolbar?: string;
191
+ toolbarPrimary?: string;
192
+ toolbarSecondary?: string;
193
+ toolButton?: string;
194
+ toolButtonActive?: string;
195
+ arrowGroupWrapper?: string;
196
+ arrowDropdownMenu?: string;
197
+ arrowDropdownItem?: string;
198
+ arrowDropdownItemActive?: string;
199
+ shapesGroupWrapper?: string;
200
+ shapesModal?: string;
201
+ shapesModalHeader?: string;
202
+ shapesModalGrid?: string;
203
+ shapesModalItem?: string;
204
+ shapesModalItemActive?: string;
205
+ toolbarDivider?: string;
206
+ toolbarCollapseButton?: string;
207
+ toolbarCollapsed?: string;
208
+ actionButton?: string;
209
+ actionButtonDisabled?: string;
210
+ deleteButton?: string;
211
+ swatchButton?: string;
212
+ swatchButtonActive?: string;
213
+ toolbarInput?: string;
214
+ toolbarSelect?: string;
215
+ noteCard?: string;
216
+ noteCardSelected?: string;
217
+ noteCollapsed?: string;
218
+ noteCompact?: string;
219
+ noteHeader?: string;
220
+ noteTitleInput?: string;
221
+ noteHeaderActions?: string;
222
+ noteHeaderButton?: string;
223
+ noteDeleteButton?: string;
224
+ noteBody?: string;
225
+ noteTextarea?: string;
226
+ noteResizeHandle?: string;
227
+ textWrapper?: string;
228
+ textWrapperSelected?: string;
229
+ textCompact?: string;
230
+ textControls?: string;
231
+ textControlButton?: string;
232
+ textControlButtonActive?: string;
233
+ textInput?: string;
234
+ textDisplay?: string;
235
+ }
236
+
237
+ interface DraftArrowState {
238
+ arrowStyle: ArrowStyle;
239
+ startGeo: GeoPoint;
240
+ currentGeo: GeoPoint;
241
+ }
242
+ interface DraftShapeState {
243
+ shape: ShapeKind;
244
+ startGeo: GeoPoint;
245
+ currentGeo: GeoPoint;
246
+ }
247
+ interface DraftRulerState {
248
+ startGeo: GeoPoint;
249
+ currentGeo: GeoPoint;
250
+ }
251
+ interface CanvasOverlayOptions {
252
+ interactive?: boolean;
253
+ readOnly?: boolean;
254
+ zIndex?: number;
255
+ defaultColor?: string;
256
+ defaultStrokeWidth?: number;
257
+ defaultNoteColor?: string;
258
+ defaultFontSize?: number;
259
+ defaultShape?: ShapeKind;
260
+ }
261
+ interface UseLeafletCanvasOptions extends CanvasOverlayOptions {
262
+ initialItems?: CanvasItem[];
263
+ items?: CanvasItem[];
264
+ maxHistory?: number;
265
+ onItemsChange?: (items: CanvasItem[]) => void;
266
+ onChange?: (items: CanvasItem[]) => void;
267
+ onChangeComplete?: (items: CanvasItem[], targetItem?: CanvasItem | null) => void;
268
+ onItemsChangeComplete?: (items: CanvasItem[], targetItem?: CanvasItem | null) => void;
269
+ onEditEnd?: (items: CanvasItem[], targetItem?: CanvasItem | null) => void;
270
+ onEditComplete?: (items: CanvasItem[], targetItem?: CanvasItem | null) => void;
271
+ onItemSelect?: (item: CanvasItem | null) => void;
272
+ onItemCreate?: (item: CanvasItem) => void;
273
+ onItemChange?: (item: CanvasItem) => void;
274
+ onItemDelete?: (id: string) => void;
275
+ onItemChangeComplete?: (item: CanvasItem) => void;
276
+ initialTool?: CanvasTool;
277
+ onToolChange?: (tool: CanvasTool) => void;
278
+ }
279
+ type LeafletCanvasOptions = UseLeafletCanvasOptions;
280
+ interface LeafletCanvasController {
281
+ items: CanvasItem[];
282
+ activeTool: CanvasTool;
283
+ setActiveTool: (tool: CanvasTool) => void;
284
+ readOnly: boolean;
285
+ setReadOnly: (readOnly: boolean) => void;
286
+ activeShape: ShapeKind;
287
+ setActiveShape: (shape: ShapeKind) => void;
288
+ shapeFilled: boolean;
289
+ setShapeFilled: (filled: boolean) => void;
290
+ selectedId: string | null;
291
+ setSelectedId: (id: string | null) => void;
292
+ selectedItem: CanvasItem | null;
293
+ isEditingLabel?: boolean;
294
+ setEditingLabel?: (editing: boolean) => void;
295
+ labelEditMode?: boolean;
296
+ setLabelEditMode?: (editing: boolean) => void;
297
+ activeColor: string;
298
+ setActiveColor: (color: string) => void;
299
+ strokeWidth: number;
300
+ setStrokeWidth: (width: number) => void;
301
+ dashed: boolean;
302
+ setDashed: (dashed: boolean) => void;
303
+ noteColor: string;
304
+ setNoteColor: (color: string) => void;
305
+ fontSize: number;
306
+ setFontSize: (size: number) => void;
307
+ fontWeight: 'normal' | 'bold';
308
+ setFontWeight: (weight: 'normal' | 'bold') => void;
309
+ addItem: (item: CanvasItem) => void;
310
+ updateItem: (id: string, patch: Partial<CanvasItem>) => void;
311
+ removeItem: (id: string) => void;
312
+ deleteSelected: () => void;
313
+ clearAll: () => void;
314
+ clear: () => void;
315
+ deleteItem: (id: string) => void;
316
+ setTool: (tool: CanvasTool) => void;
317
+ selectItem: (id: string | null) => void;
318
+ undo: () => void;
319
+ redo: () => void;
320
+ canUndo: boolean;
321
+ canRedo: boolean;
322
+ notifyChangeComplete: (targetItem?: CanvasItem | null) => void;
323
+ exportJSON: () => string;
324
+ importJSON: (json: string) => boolean;
325
+ }
326
+
327
+ declare const TOOL_TO_ARROW_STYLE: Record<string, ArrowStyle | undefined>;
328
+ declare const STROKE_COLORS: readonly ["#000000", "#4b5563", "#2563eb", "#dc2626", "#16a34a", "#d97706", "#9333ea", "#0891b2"];
329
+ interface NoteColorTheme {
330
+ name: string;
331
+ bg: string;
332
+ border: string;
333
+ header: string;
334
+ text: string;
335
+ }
336
+ declare const NOTE_COLOR_THEMES: readonly NoteColorTheme[];
337
+ declare const DEFAULT_STROKE_COLOR = "#000000";
338
+ declare const DEFAULT_STROKE_WIDTH = 2;
339
+ declare const DEFAULT_STROKE_WIDTH_OPTIONS: readonly number[];
340
+ declare const STROKE_WIDTH_OPTIONS: readonly number[];
341
+ declare const DEFAULT_NOTE_BG = "#fef9c3";
342
+ declare const DEFAULT_NOTE_TEXT = "#422006";
343
+ declare const DEFAULT_FONT_SIZE = 16;
344
+ declare const DEFAULT_FONT_SIZE_OPTIONS: readonly number[];
345
+ declare const FONT_SIZE_OPTIONS: readonly number[];
346
+ /**
347
+ * Super simple unified annotation default theme matching basic HTML element appearance.
348
+ */
349
+ declare const DEFAULT_ANNOTATION_THEME: Readonly<CanvasAnnotationTheme>;
350
+
351
+ declare function createId(prefix?: string): string;
352
+ declare function geoToScreen(map: L.Map, point: GeoPoint): ScreenPoint;
353
+ declare function screenToGeo(map: L.Map, point: ScreenPoint): GeoPoint;
354
+ declare function constrainToAspectRatio(anchor: ScreenPoint, target: ScreenPoint, aspectRatio?: number): ScreenPoint;
355
+ declare function constrainAngleTo45Degrees(anchor: ScreenPoint, target: ScreenPoint): ScreenPoint;
356
+ declare function computeDefaultControlGeoPoint(start: GeoPoint, end: GeoPoint, curvature?: number): GeoPoint;
357
+ declare function getQuadraticBezierPoint(p0: ScreenPoint, p1: ScreenPoint, p2: ScreenPoint, t: number): ScreenPoint;
358
+ declare function getQuadraticEndAngle(p0: ScreenPoint, p1: ScreenPoint, p2: ScreenPoint): number;
359
+ declare function distanceToSegment(p: ScreenPoint, v: ScreenPoint, w: ScreenPoint): number;
360
+ declare function distanceToQuadraticBezier(p: ScreenPoint, p0: ScreenPoint, p1: ScreenPoint, p2: ScreenPoint, steps?: number): number;
361
+ declare function getMapDimensions(map: L.Map | null | undefined): {
362
+ width: number;
363
+ height: number;
364
+ } | null;
365
+ declare function truncateCanvasText(ctx: CanvasRenderingContext2D, text: string, maxWidth: number): string;
366
+ declare function calculateZoomFontSize(initialFontSize: number | undefined, currentZoom: number | null, baseZoom?: number, options?: {
367
+ min?: number;
368
+ max?: number;
369
+ scaleFactor?: number;
370
+ }): number;
371
+ declare function calculateGeodesicDistance(p1: GeoPoint, p2: GeoPoint): number;
372
+ declare function formatRealWorldDistance(meters: number, unit?: 'metric' | 'imperial'): string;
373
+ declare function calculateLineDistance(points: GeoPoint[]): number;
374
+
375
+ declare function drawCanvasHandle(ctx: CanvasRenderingContext2D, pt: ScreenPoint, strokeColor: string, fillColor: string, radius: number, strokeWidth?: number): void;
376
+ declare function drawCanvasLabelPill(ctx: CanvasRenderingContext2D, label: string, midX: number, midY: number, strokeColor: string, maxAllowedBoxWidth: number, theme?: CanvasAnnotationTheme): void;
377
+
378
+ type ArrowHandleType = 'start' | 'end' | 'control';
379
+ interface ProjectedArrow {
380
+ start: ScreenPoint;
381
+ end: ScreenPoint;
382
+ control: ScreenPoint;
383
+ }
384
+ declare function projectArrow(map: L.Map, arrow: ArrowItem): ProjectedArrow;
385
+ declare function renderArrowOnCanvas(ctx: CanvasRenderingContext2D, projected: ProjectedArrow, arrow: Pick<ArrowItem, 'arrowStyle' | 'color' | 'strokeWidth' | 'dashed' | 'headStyle' | 'label'>, options?: {
386
+ isSelected?: boolean;
387
+ isPreview?: boolean;
388
+ theme?: ArrowRenderTheme;
389
+ }): void;
390
+ declare function hitTestArrowHandle(point: ScreenPoint, projected: ProjectedArrow, arrow: ArrowItem, tolerance?: number): ArrowHandleType | null;
391
+ declare function hitTestArrow(point: ScreenPoint, projected: ProjectedArrow, arrow: ArrowItem, tolerance?: number): boolean;
392
+
393
+ declare function drawArrowHead(ctx: CanvasRenderingContext2D, tip: ScreenPoint, angle: number, size: number, color: string, filled?: boolean): void;
394
+ declare function traceArrowPath(ctx: CanvasRenderingContext2D, projected: ProjectedArrow, arrowStyle: ArrowItem['arrowStyle']): void;
395
+
396
+ declare function projectFreeDraw(map: L.Map, item: Pick<FreeDrawItem, 'points'>): ScreenPoint[];
397
+ declare function renderFreeDrawOnCanvas(ctx: CanvasRenderingContext2D, screenPoints: ScreenPoint[], item: Pick<FreeDrawItem, 'color' | 'strokeWidth' | 'dashed'>, options?: {
398
+ isSelected?: boolean;
399
+ isPreview?: boolean;
400
+ theme?: CanvasAnnotationTheme;
401
+ }): void;
402
+ declare function hitTestFreeDraw(point: ScreenPoint, screenPoints: ScreenPoint[], item: FreeDrawItem, tolerance?: number): boolean;
403
+
404
+ type ShapeHandleType = 'start' | 'end';
405
+ interface ProjectedShape {
406
+ start: ScreenPoint;
407
+ end: ScreenPoint;
408
+ minX: number;
409
+ minY: number;
410
+ maxX: number;
411
+ maxY: number;
412
+ width: number;
413
+ height: number;
414
+ cx: number;
415
+ cy: number;
416
+ }
417
+ declare function projectShape(map: L.Map, shape: ShapeItem): ProjectedShape;
418
+ declare function renderShapeOnCanvas(ctx: CanvasRenderingContext2D, projected: ProjectedShape, shape: Pick<ShapeItem, 'shape' | 'color' | 'fillColor' | 'filled' | 'strokeWidth' | 'dashed' | 'label'>, options?: {
419
+ isSelected?: boolean;
420
+ isPreview?: boolean;
421
+ theme?: CanvasAnnotationTheme;
422
+ }): void;
423
+ declare function hitTestShapeHandle(point: ScreenPoint, projected: ProjectedShape, tolerance?: number): ShapeHandleType | null;
424
+ declare function hitTestShape(point: ScreenPoint, projected: ProjectedShape, tolerance?: number): boolean;
425
+
426
+ declare function tracePolygonShape(ctx: CanvasRenderingContext2D, proj: ProjectedShape, kind: ShapeKind, theme?: CanvasAnnotationTheme): void;
427
+
428
+ type RulerHandleType = 'start' | 'end';
429
+ interface ProjectedRuler {
430
+ start: ScreenPoint;
431
+ end: ScreenPoint;
432
+ mid: ScreenPoint;
433
+ lengthPx: number;
434
+ angle: number;
435
+ }
436
+ declare function projectRuler(map: L.Map, ruler: Pick<RulerItem, 'start' | 'end'>): ProjectedRuler;
437
+ declare function renderRulerOnCanvas(ctx: CanvasRenderingContext2D, projected: ProjectedRuler, ruler: Pick<RulerItem, 'start' | 'end' | 'color' | 'strokeWidth' | 'dashed' | 'label' | 'unit'>, options?: {
438
+ isSelected?: boolean;
439
+ isPreview?: boolean;
440
+ theme?: CanvasAnnotationTheme;
441
+ }): void;
442
+ declare function hitTestRulerHandle(point: ScreenPoint, projected: ProjectedRuler, tolerance?: number): RulerHandleType | null;
443
+ declare function hitTestRuler(point: ScreenPoint, projected: ProjectedRuler, ruler: RulerItem, tolerance?: number): boolean;
444
+
445
+ interface ResolvedNoteTheme {
446
+ name: string;
447
+ bg: string;
448
+ border: string;
449
+ header: string;
450
+ text: string;
451
+ }
452
+ declare function resolveNoteTheme(backgroundColor: string): ResolvedNoteTheme;
453
+ declare function clampNotePosition(map: L.Map, screenPos: ScreenPoint, item: NoteItem, isCompact: boolean, isDragging: boolean, clampToViewport?: boolean): ScreenPoint;
454
+
455
+ declare function clampTextPosition(map: L.Map, screenPos: ScreenPoint, item: TextItem, dynamicFontSize: number, isCompact: boolean, isDragging: boolean, clampToViewport?: boolean): ScreenPoint;
456
+
457
+ declare function startFreeDrawDrag(map: L.Map, mapContainer: HTMLElement, pt: ScreenPoint, geo: GeoPoint, activeColor: string, strokeWidth: number, dashed: boolean, draftFreeDrawRef: {
458
+ current: {
459
+ screenPoints: ScreenPoint[];
460
+ geoPoints: GeoPoint[];
461
+ } | null;
462
+ }, rafIdRef: {
463
+ current: number | null;
464
+ }, paintCanvas: () => void, addItem: (item: FreeDrawItem) => void, setActiveTool: (tool: 'select') => void): void;
465
+
466
+ declare function createDraftNote(geo: GeoPoint, noteColor: string, defaultTitle?: string): NoteItem;
467
+ declare function createDraftText(geo: GeoPoint, activeColor: string, fontSize: number, fontWeight: 'normal' | 'bold', currentZoom: number): TextItem;
468
+
469
+ declare function startShapeDrag(map: L.Map, mapContainer: HTMLElement, startScreen: ScreenPoint, startGeo: GeoPoint, activeShape: ShapeKind, activeColor: string, shapeFilled: boolean, strokeWidth: number, dashed: boolean, setDraftShape: (draft: DraftShapeState | null) => void, addItem: (item: ShapeItem) => void, setActiveTool: (tool: 'select') => void): void;
470
+ declare function buildArrowItem(arrowStyle: ArrowStyle, startGeo: GeoPoint, endGeo: GeoPoint, activeColor: string, strokeWidth: number, dashed: boolean): ArrowItem;
471
+ declare function startArrowDrag(map: L.Map, mapContainer: HTMLElement, startScreen: ScreenPoint, startGeo: GeoPoint, arrowStyle: ArrowStyle, activeColor: string, strokeWidth: number, dashed: boolean, setDraftArrow: (draft: DraftArrowState | null) => void, addItem: (item: ArrowItem) => void, setActiveTool: (tool: 'select') => void): void;
472
+ declare function buildRulerItem(startGeo: GeoPoint, endGeo: GeoPoint, activeColor: string, strokeWidth: number, dashed: boolean): RulerItem;
473
+ declare function startRulerDrag(map: L.Map, mapContainer: HTMLElement, startScreen: ScreenPoint, startGeo: GeoPoint, activeColor: string, strokeWidth: number, dashed: boolean, setDraftRuler: (draft: DraftRulerState | null) => void, addItem: (item: RulerItem) => void, setActiveTool: (tool: 'select') => void): void;
474
+
475
+ declare function startArrowHandleDrag(map: L.Map, arrow: ArrowItem, projected: ProjectedArrow, handle: ArrowHandleType, getLocalPoint: (e: PointerEvent) => ScreenPoint, updateItem: (id: string, patch: Partial<ArrowItem>) => void): void;
476
+ declare function startShapeHandleDrag(map: L.Map, shape: ShapeItem, projected: ProjectedShape, handle: ShapeHandleType, getLocalPoint: (e: PointerEvent) => ScreenPoint, updateItem: (id: string, patch: Partial<ShapeItem>) => void): void;
477
+ declare function startArrowBodyDrag(map: L.Map, arrow: ArrowItem, projected: ProjectedArrow, originPt: ScreenPoint, getLocalPoint: (e: PointerEvent) => ScreenPoint, updateItem: (id: string, patch: Partial<ArrowItem>) => void): void;
478
+ declare function startShapeBodyDrag(map: L.Map, shape: ShapeItem, projected: ProjectedShape, originPt: ScreenPoint, getLocalPoint: (e: PointerEvent) => ScreenPoint, updateItem: (id: string, patch: Partial<ShapeItem>) => void): void;
479
+ declare function startFreeDrawBodyDrag(map: L.Map, fd: FreeDrawItem, initialScreenPts: ScreenPoint[], originPt: ScreenPoint, getLocalPoint: (e: PointerEvent) => ScreenPoint, updateItem: (id: string, patch: Partial<FreeDrawItem>) => void): void;
480
+ declare function startRulerHandleDrag(map: L.Map, ruler: RulerItem, projected: ProjectedRuler, handle: RulerHandleType, getLocalPoint: (e: PointerEvent) => ScreenPoint, updateItem: (id: string, patch: Partial<RulerItem>) => void): void;
481
+ declare function startRulerBodyDrag(map: L.Map, ruler: RulerItem, projected: ProjectedRuler, originPt: ScreenPoint, getLocalPoint: (e: PointerEvent) => ScreenPoint, updateItem: (id: string, patch: Partial<RulerItem>) => void): void;
482
+
483
+ interface PaintLeafletCanvasOptions {
484
+ map: L.Map | null;
485
+ canvas: HTMLCanvasElement | null;
486
+ width: number;
487
+ height: number;
488
+ arrowItems: ArrowItem[];
489
+ shapeItems: ShapeItem[];
490
+ freeDrawItems: FreeDrawItem[];
491
+ rulerItems: RulerItem[];
492
+ selectedId: string | null;
493
+ draftShape: DraftShapeState | null;
494
+ draftArrow: DraftArrowState | null;
495
+ draftRuler?: DraftRulerState | null;
496
+ draftFreeDraw?: {
497
+ screenPoints: ScreenPoint[];
498
+ geoPoints: GeoPoint[];
499
+ } | null;
500
+ activeColor: string;
501
+ strokeWidth: number;
502
+ dashed: boolean;
503
+ shapeFilled: boolean;
504
+ annotationTheme?: CanvasAnnotationTheme;
505
+ arrowTheme?: ArrowRenderTheme;
506
+ isReadOnly: boolean;
507
+ }
508
+ declare function paintLeafletCanvas({ map, canvas, width, height, arrowItems, shapeItems, freeDrawItems, rulerItems, selectedId, draftShape, draftArrow, draftRuler, draftFreeDraw, activeColor, strokeWidth, dashed, shapeFilled, annotationTheme, arrowTheme, isReadOnly, }: PaintLeafletCanvasOptions): void;
509
+
510
+ interface MapViewportDimensions {
511
+ width: number;
512
+ height: number;
513
+ }
514
+ declare function bindLeafletSync(map: L.Map, onSync: (dimensions: MapViewportDimensions) => void): () => void;
515
+ declare function bindBlockMapDblClick(map: L.Map): () => void;
516
+
517
+ interface LeafletCanvasStore extends LeafletCanvasController {
518
+ subscribe: (listener: (controller: LeafletCanvasController) => void) => () => void;
519
+ getState: () => LeafletCanvasController;
520
+ destroy: () => void;
521
+ }
522
+ declare function createLeafletCanvasController(options?: UseLeafletCanvasOptions): LeafletCanvasStore;
523
+ declare const createLeafletTualController: typeof createLeafletCanvasController;
524
+
525
+ interface CreateLeafletCanvasOptions extends UseLeafletCanvasOptions {
526
+ controller?: LeafletCanvasStore;
527
+ annotationTheme?: CanvasAnnotationTheme;
528
+ arrowTheme?: ArrowRenderTheme;
529
+ labels?: CanvasLabels;
530
+ }
531
+ interface LeafletCanvasInstance {
532
+ controller: LeafletCanvasStore;
533
+ container: HTMLDivElement;
534
+ canvas: HTMLCanvasElement;
535
+ repaint: () => void;
536
+ destroy: () => void;
537
+ }
538
+ declare function createLeafletCanvas(map: L.Map, options?: CreateLeafletCanvasOptions): LeafletCanvasInstance;
539
+ declare const createLeafletTual: typeof createLeafletCanvas;
540
+
541
+ /**
542
+ * leaflet-tual — core (framework-agnostic)
543
+ *
544
+ * Interactive canvas and annotation toolkit for Leaflet maps — draw vector
545
+ * arrows, geometric shapes, freehand sketches, rulers, sticky notes, and text
546
+ * overlays that stay geographically synchronized with Leaflet across panning
547
+ * and zooming.
548
+ *
549
+ * This module is the entire framework-agnostic public surface. It has zero
550
+ * dependency on React or any UI framework, so it can be used directly from
551
+ * vanilla JavaScript, TypeScript, Vue, Svelte, Angular, or a plain `<script>` tag.
552
+ *
553
+ * React users: see `leaflet-tual/react` for `<LeafletCanvas>`, `<CanvasToolbar>`,
554
+ * `useLeafletCanvas`, and `useLeafletSync`.
555
+ */
556
+
557
+ declare const VERSION: string;
558
+
559
+ export { type ArrowHandleType, type ArrowHeadStyle, type ArrowItem, type ArrowRenderTheme, type ArrowStyle, type CanvasAnnotationTheme, type CanvasItem, type CanvasLabels, type CanvasOverlayOptions, type CanvasTool, type CreateLeafletCanvasOptions, DEFAULT_ANNOTATION_THEME, DEFAULT_FONT_SIZE, DEFAULT_FONT_SIZE_OPTIONS, DEFAULT_NOTE_BG, DEFAULT_NOTE_TEXT, DEFAULT_STROKE_COLOR, DEFAULT_STROKE_WIDTH, DEFAULT_STROKE_WIDTH_OPTIONS, type DraftArrowState, type DraftRulerState, type DraftShapeState, FONT_SIZE_OPTIONS, type FreeDrawItem, type GeoPoint, type LeafletCanvasClassNames, type LeafletCanvasController, type LeafletCanvasInstance, type LeafletCanvasOptions, type LeafletCanvasStore, type MapViewportDimensions, NOTE_COLOR_THEMES, type NoteCollapseState, type NoteColorTheme, type NoteItem, type PaintLeafletCanvasOptions, type ProjectedArrow, type ProjectedRuler, type ProjectedShape, type ResolvedNoteTheme, type RulerHandleType, type RulerItem, STROKE_COLORS, STROKE_WIDTH_OPTIONS, type ScreenPoint, type ShapeHandleType, type ShapeItem, type ShapeKind, TOOL_TO_ARROW_STYLE, type TextItem, type ToolbarOrientation, type ToolbarPosition, type ToolbarToolGroupId, type UseLeafletCanvasOptions, VERSION, bindBlockMapDblClick, bindLeafletSync, buildArrowItem, buildRulerItem, calculateGeodesicDistance, calculateLineDistance, calculateZoomFontSize, clampNotePosition, clampTextPosition, computeDefaultControlGeoPoint, constrainAngleTo45Degrees, constrainToAspectRatio, createDraftNote, createDraftText, createId, createLeafletCanvas, createLeafletCanvasController, createLeafletTual, createLeafletTualController, distanceToQuadraticBezier, distanceToSegment, drawArrowHead, drawCanvasHandle, drawCanvasLabelPill, formatRealWorldDistance, geoToScreen, getMapDimensions, getQuadraticBezierPoint, getQuadraticEndAngle, hitTestArrow, hitTestArrowHandle, hitTestFreeDraw, hitTestRuler, hitTestRulerHandle, hitTestShape, hitTestShapeHandle, paintLeafletCanvas, projectArrow, projectFreeDraw, projectRuler, projectShape, renderArrowOnCanvas, renderFreeDrawOnCanvas, renderRulerOnCanvas, renderShapeOnCanvas, resolveNoteTheme, screenToGeo, startArrowBodyDrag, startArrowDrag, startArrowHandleDrag, startFreeDrawBodyDrag, startFreeDrawDrag, startRulerBodyDrag, startRulerDrag, startRulerHandleDrag, startShapeBodyDrag, startShapeDrag, startShapeHandleDrag, traceArrowPath, tracePolygonShape, truncateCanvasText };
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ var Me={name:"leaflet-tual",version:"0.1.0",description:"Framework-agnostic interactive canvas and annotation toolkit for Leaflet maps \u2014 draw arrows, shapes, freehand sketches, rulers, notes, and text pinned to geo-coordinates. Optional React bindings.",type:"module",sideEffects:!1,main:"./dist/index.cjs",module:"./dist/index.js",types:"./dist/index.d.ts",exports:{".":{types:"./dist/index.d.ts",import:{types:"./dist/index.d.ts",default:"./dist/index.js"},require:{types:"./dist/index.d.cts",default:"./dist/index.cjs"},default:"./dist/index.js"},"./core":{types:"./dist/index.d.ts",import:{types:"./dist/index.d.ts",default:"./dist/index.js"},require:{types:"./dist/index.d.cts",default:"./dist/index.cjs"},default:"./dist/index.js"},"./react":{types:"./dist/react.d.ts",import:{types:"./dist/react.d.ts",default:"./dist/react.js"},require:{types:"./dist/react.d.cts",default:"./dist/react.cjs"},default:"./dist/react.js"},"./package.json":"./package.json"},files:["dist","README.md"],author:"Yusuf Arslan",license:"MIT",repository:{type:"git",url:"git+https://github.com/yusufarsln98/leaflet-tual.git",directory:"packages/leaflet-tual"},bugs:{url:"https://github.com/yusufarsln98/leaflet-tual/issues"},publishConfig:{access:"public",registry:"https://registry.npmjs.org/"},keywords:["leaflet","leaflet-tual","tual","tuval","canvas","annotation","map-tools","arrows","notes","gis","overlay","framework-agnostic","vanilla-js","react","react-leaflet"],scripts:{build:"tsup",dev:"tsup --watch",lint:"eslint src --ext ts,tsx",typecheck:"tsc --noEmit",format:'prettier --write "src/**/*.{ts,tsx}"',"format:check":'prettier --check "src/**/*.{ts,tsx}"',test:"vitest run","test:watch":"vitest",version:"changeset version",release:"npm run build && changeset publish"},peerDependencies:{leaflet:"^1.9.0",react:"^18.0.0 || ^19.0.0","react-dom":"^18.0.0 || ^19.0.0","react-leaflet":"^4.0.0 || ^5.0.0"},peerDependenciesMeta:{react:{optional:!0},"react-dom":{optional:!0},"react-leaflet":{optional:!0}},devDependencies:{"@changesets/cli":"^2.27.1","@testing-library/dom":"^10.4.0","@testing-library/react":"^16.2.0","@types/leaflet":"^1.9.16","@types/node":"^22.13.0","@types/react":"^19.0.0","@types/react-dom":"^19.0.0",eslint:"^9.20.0","eslint-plugin-react-hooks":"^5.1.0",jsdom:"^26.0.0",leaflet:"^1.9.4",prettier:"^3.5.0",react:"^19.0.0","react-dom":"^19.0.0","react-leaflet":"^5.0.0",tsup:"^8.5.1",typescript:"^5.7.0","typescript-eslint":"^8.24.0",vitest:"^3.0.0"}};var Ie={"arrow-linear":"linear","arrow-curved":"curved","arrow-bi":"bi","arrow-elbow":"elbow","arrow-s-curve":"s-curve"},ft=["#000000","#4b5563","#2563eb","#dc2626","#16a34a","#d97706","#9333ea","#0891b2"],q=[{name:"Amber",bg:"#fef9c3",border:"#fde047",header:"#fef08a",text:"#422006"},{name:"Sky",bg:"#e0f2fe",border:"#7dd3fc",header:"#bae6fd",text:"#0c4a6e"},{name:"Emerald",bg:"#dcfce7",border:"#86efac",header:"#bbf7d0",text:"#064e3b"},{name:"Rose",bg:"#ffe4e6",border:"#fda4af",header:"#fecdd3",text:"#881337"},{name:"Violet",bg:"#f3e8ff",border:"#d8b4fe",header:"#e9d5ff",text:"#3b0764"},{name:"Dark Slate",bg:"#1e293b",border:"#334155",header:"#0f172a",text:"#f8fafc"},{name:"Midnight",bg:"#111827",border:"#374151",header:"#030712",text:"#f9fafb"}],De="#000000",Ae=2,st=[1,2,3,4,5,6,8,10,12],ht=st,Ee="#fef9c3",mt="#422006",Re=16,lt=[10,12,14,16,18,20,24,28,32,36,40,48],yt=lt,pt={selectionGlowColor:"rgba(0, 0, 0, 0.2)",selectionGlowWidth:6,guideLineDash:[4,4],guideLineColor:"rgba(100, 100, 100, 0.6)",guideLineWidth:1.2,endpointHandleColor:"#4f4f4f",controlHandleColor:"#4f4f4f",handleFillColor:"#ffffff",handleRadius:5,handleStrokeWidth:2,shadowColor:"rgba(0, 0, 0, 0.2)",shadowBlur:3,shadowOffsetY:1.5,labelBackgroundColor:"#ffffff",labelTextColor:"#000000",labelFont:"12px system-ui, -apple-system, sans-serif",labelBorderWidth:1,labelBorderRadius:2,labelPaddingX:6,labelPaddingY:18,shapeDefaultFillOpacity:.16,shapeBorderRadius:0};var ke=0;function K(e="rlc"){ke+=1;let t=Math.random().toString(36).slice(2,8);return`${e}-${Date.now().toString(36)}-${ke}-${t}`}function W(e,t){let n=e.latLngToContainerPoint([t.lat,t.lng]);return{x:n.x,y:n.y}}function L(e,t){let n=e.containerPointToLatLng([t.x,t.y]);return{lat:n.lat,lng:n.lng}}function oe(e,t,n=1){let o=n>0?n:1,r=t.x-e.x,a=t.y-e.y,s=Math.abs(r),l=Math.abs(a),i=r>=0?1:-1,d=a>=0?1:-1;return s/o>=l?{x:e.x+i*s,y:e.y+d*(s/o)}:{x:e.x+i*(l*o),y:e.y+d*l}}function B(e,t){let n=t.x-e.x,o=t.y-e.y,r=Math.hypot(n,o);if(r===0)return t;let a=Math.atan2(o,n),s=Math.PI/4,l=Math.round(a/s)*s;return{x:e.x+Math.cos(l)*r,y:e.y+Math.sin(l)*r}}function se(e,t,n=.25){let o=(e.lat+t.lat)/2,r=(e.lng+t.lng)/2,a=t.lat-e.lat,s=t.lng-e.lng;return{lat:o+s*n,lng:r-a*n}}function ye(e,t,n,o){let r=1-o;return{x:r*r*e.x+2*r*o*t.x+o*o*n.x,y:r*r*e.y+2*r*o*t.y+o*o*n.y}}function le(e,t,n){let o=n.x-t.x,r=n.y-t.y;return Math.hypot(o,r)<.001?Math.atan2(n.y-e.y,n.x-e.x):Math.atan2(r,o)}function j(e,t,n){let o=(n.x-t.x)**2+(n.y-t.y)**2;if(o===0)return Math.hypot(e.x-t.x,e.y-t.y);let r=((e.x-t.x)*(n.x-t.x)+(e.y-t.y)*(n.y-t.y))/o;r=Math.max(0,Math.min(1,r));let a=t.x+r*(n.x-t.x),s=t.y+r*(n.y-t.y);return Math.hypot(e.x-a,e.y-s)}function Oe(e,t,n,o,r=24){let a=1/0,s=t;for(let l=1;l<=r;l+=1){let i=ye(t,n,o,l/r),d=j(e,s,i);d<a&&(a=d),s=i}return a}function de(e){if(!e)return null;try{let t=e.getSize?.();if(t&&t.x>0&&t.y>0)return{width:t.x,height:t.y}}catch{}try{let t=e.getContainer?.()?.getBoundingClientRect?.();if(t&&t.width>0&&t.height>0)return{width:t.width,height:t.height}}catch{}return null}function We(e,t,n){if(!t||n<=0)return"";if(e.measureText(t).width<=n)return t;let o="\u2026";if(e.measureText(o).width>=n)return"";let r=0,a=t.length,s="";for(;r<=a;){let l=Math.floor((r+a)/2),i=t.slice(0,l)+o;e.measureText(i).width<=n?(s=i,r=l+1):a=l-1}return s||o}function St(e=16,t,n=14,o){if(t===null||typeof t!="number")return e;let r=o?.scaleFactor??1.22,a=o?.min??9,s=o?.max??72,l=e*Math.pow(r,t-n);return Math.round(Math.max(a,Math.min(s,l)))}function pe(e,t){let o=(t.lat-e.lat)*Math.PI/180,r=(t.lng-e.lng)*Math.PI/180,a=e.lat*Math.PI/180,s=t.lat*Math.PI/180,l=Math.sin(o/2),i=Math.sin(r/2),d=l*l+Math.cos(a)*Math.cos(s)*i*i;return 6371e3*(2*Math.atan2(Math.sqrt(d),Math.sqrt(1-d)))}function Fe(e,t="metric"){if(t==="imperial"){let o=e*3.28084;if(o<1e3)return`${Math.round(o)} ft`;let r=o/5280;return`${r>=10?r.toFixed(1):r.toFixed(2)} mi`}if(e<1e3)return`${Math.round(e)} m`;let n=e/1e3;return`${n>=10?n.toFixed(1):n.toFixed(2)} km`}function wt(e){let t=0;for(let n=0;n<e.length-1;n+=1)t+=pe(e[n],e[n+1]);return t}function X(e,t,n,o,r,a=2){e.save(),e.beginPath(),e.arc(t.x,t.y,r,0,Math.PI*2),e.fillStyle=o,e.fill(),e.lineWidth=a,e.strokeStyle=n,e.stroke(),e.restore()}function ee(e,t,n,o,r,a,s){e.save(),e.font=s?.labelFont??"12px system-ui, -apple-system, sans-serif";let l=s?.labelPaddingX??6,i=Math.max(10,a-l*2),d=We(e,t,i);if(d){let u=e.measureText(d),p=Math.round(u.width+l*2),h=s?.labelPaddingY??18,m=Math.round(n-p/2),f=Math.round(o-h/2),y=s?.labelBorderRadius??2;s?.labelShadowColor&&(e.shadowColor=s.labelShadowColor,e.shadowBlur=s.labelShadowBlur??3),e.fillStyle=s?.labelBackgroundColor??"#ffffff",e.strokeStyle=s?.labelBorderColor??r,e.lineWidth=s?.labelBorderWidth??1,e.beginPath(),typeof e.roundRect=="function"?e.roundRect(m,f,p,h,y):e.rect(m,f,p,h),e.fill(),e.stroke(),e.fillStyle=s?.labelTextColor??"#000000",e.textAlign="center",e.textBaseline="middle",e.fillText(d,n,o)}e.restore()}function ge(e,t,n,o,r,a=!0){let s=Math.PI/6.5,l=t.x-o*Math.cos(n-s),i=t.y-o*Math.sin(n-s),d=t.x-o*Math.cos(n+s),u=t.y-o*Math.sin(n+s);e.save(),e.setLineDash([]),e.beginPath(),e.moveTo(t.x,t.y),e.lineTo(l,i),a?(e.lineTo(d,u),e.closePath(),e.fillStyle=r,e.fill()):(e.moveTo(t.x,t.y),e.lineTo(d,u),e.strokeStyle=r,e.lineWidth=Math.max(2,o/4.5),e.lineCap="round",e.stroke()),e.restore()}function Se(e,t,n){let{start:o,end:r,control:a}=t;if(e.moveTo(o.x,o.y),n==="curved")e.quadraticCurveTo(a.x,a.y,r.x,r.y);else if(n==="elbow")e.lineTo(a.x,o.y),e.lineTo(a.x,r.y),e.lineTo(r.x,r.y);else if(n==="s-curve"){let s=r.x-o.x,l=r.y-o.y;e.bezierCurveTo(o.x+s*.5,o.y,o.x+s*.5,o.y+l,r.x,r.y)}else e.lineTo(r.x,r.y)}function te(e,t){let n=W(e,t.start),o=W(e,t.end),r=t.arrowStyle==="curved"||t.arrowStyle==="s-curve",a=t.controlPoint?t.controlPoint:r?se(t.start,t.end):{lat:(t.start.lat+t.end.lat)/2,lng:(t.start.lng+t.end.lng)/2},s=W(e,a);return{start:n,end:o,control:s}}function we(e,t,n,o={}){let{start:r,end:a,control:s}=t,l=Math.hypot(a.x-r.x,a.y-r.y);if(l<2)return;let i=o.theme,d=Math.max(12,n.strokeWidth*3.8),u=Math.atan2(a.y-r.y,a.x-r.x),p=Math.atan2(r.y-a.y,r.x-a.x);if(n.arrowStyle==="curved")u=le(r,s,a),p=le(a,s,r);else if(n.arrowStyle==="elbow"){let f=a.x-s.x,y=a.y-r.y;u=Math.abs(f)>1?Math.atan2(0,f):Math.atan2(y,0);let w=r.x-s.x;p=Math.abs(w)>1?Math.atan2(0,w):Math.atan2(-y,0)}else if(n.arrowStyle==="s-curve"){let f=a.x-r.x;u=le(r,{x:r.x+f*.5,y:a.y},a)}e.save(),o.isPreview&&(e.globalAlpha=.85),o.isSelected&&(e.save(),e.beginPath(),Se(e,t,n.arrowStyle),e.strokeStyle=i?.selectionGlowColor??"rgba(0, 0, 0, 0.2)",e.lineWidth=n.strokeWidth+(i?.selectionGlowWidth??6),e.lineCap="round",e.lineJoin="round",e.stroke(),e.restore()),e.save(),e.shadowColor=i?.shadowColor??"rgba(0, 0, 0, 0.2)",e.shadowBlur=i?.shadowBlur??3,e.shadowOffsetY=i?.shadowOffsetY??1.5,e.beginPath(),Se(e,t,n.arrowStyle),e.strokeStyle=n.color,e.lineWidth=n.strokeWidth,e.lineCap="round",e.lineJoin="round";let h=!!(n.dashed||n.arrowStyle==="dashed");e.setLineDash(h?[n.strokeWidth*3,n.strokeWidth*2]:[]),e.stroke();let m=n.headStyle??(n.arrowStyle==="bi"?"both":"triangle");if(m!=="none"&&(ge(e,a,u,d,n.color,m!=="open"),m==="both"&&ge(e,r,p,d,n.color,!0)),e.restore(),n.label){let f=typeof i?.labelMinShapeSize=="number"?i.labelMinShapeSize:24;if(f<=0||l>=f){let y=n.arrowStyle==="curved"?ye(r,s,a,.5):n.arrowStyle==="elbow"?{x:s.x,y:(r.y+a.y)/2}:{x:(r.x+a.x)/2,y:(r.y+a.y)/2},w=i?.fitLabelsToShape!==!1,b=i?.labelMaxTextWidth??(w?Math.max(48,Math.min(280,l*1.6)):1/0);ee(e,n.label,Math.round(y.x),Math.round(y.y),n.color,b,i)}}if(o.isSelected){let f=i?.handleRadius??5,y=i?.handleFillColor??"#ffffff",w=i?.endpointHandleColor??"#4f4f4f",b=i?.controlHandleColor??"#767676",M=i?.handleStrokeWidth??2;(n.arrowStyle==="curved"||n.arrowStyle==="elbow")&&(e.save(),e.beginPath(),e.setLineDash(i?.guideLineDash?[...i.guideLineDash]:[4,4]),e.moveTo(r.x,r.y),e.lineTo(s.x,s.y),e.lineTo(a.x,a.y),e.strokeStyle=i?.guideLineColor??"rgba(100, 100, 100, 0.6)",e.lineWidth=i?.guideLineWidth??1.2,e.stroke(),e.restore(),X(e,s,b,y,f+.5,M)),X(e,r,w,y,f,M),X(e,a,w,y,f,M)}e.restore()}function He(e,t,n,o=11){return Math.hypot(e.x-t.end.x,e.y-t.end.y)<=o?"end":Math.hypot(e.x-t.start.x,e.y-t.start.y)<=o?"start":(n.arrowStyle==="curved"||n.arrowStyle==="elbow")&&Math.hypot(e.x-t.control.x,e.y-t.control.y)<=o?"control":null}function _e(e,t,n,o=9){let r=Math.max(o,n.strokeWidth/2+6);if(n.arrowStyle==="curved")return Oe(e,t.start,t.control,t.end)<=r;if(n.arrowStyle==="elbow"){let a={x:t.control.x,y:t.start.y},s={x:t.control.x,y:t.end.y};return j(e,t.start,a)<=r||j(e,a,s)<=r||j(e,s,t.end)<=r}return j(e,t.start,t.end)<=r}function ce(e,t){return t.points.map(n=>W(e,n))}function Be(e,t){if(t.length===0)return;if(e.moveTo(t[0].x,t[0].y),t.length===1){e.lineTo(t[0].x+.5,t[0].y+.5);return}if(t.length===2){e.lineTo(t[1].x,t[1].y);return}for(let o=1;o<t.length-1;o+=1){let r=(t[o].x+t[o+1].x)/2,a=(t[o].y+t[o+1].y)/2;e.quadraticCurveTo(t[o].x,t[o].y,r,a)}let n=t[t.length-1];e.lineTo(n.x,n.y)}function ve(e,t,n,o={}){if(t.length===0)return;let r=o.theme;e.save(),o.isPreview&&(e.globalAlpha=.9),o.isSelected&&(e.save(),e.beginPath(),Be(e,t),e.strokeStyle=r?.selectionGlowColor??"rgba(0, 0, 0, 0.2)",e.lineWidth=n.strokeWidth+(r?.selectionGlowWidth??6),e.lineCap="round",e.lineJoin="round",e.stroke(),e.restore()),e.save(),e.shadowColor=r?.shadowColor??"rgba(0, 0, 0, 0.2)",e.shadowBlur=r?.shadowBlur??3,e.shadowOffsetY=r?.shadowOffsetY??1,e.beginPath(),Be(e,t),e.strokeStyle=n.color,e.lineWidth=n.strokeWidth,e.lineCap="round",e.lineJoin="round",n.dashed?e.setLineDash([n.strokeWidth*3,n.strokeWidth*2]):e.setLineDash([]),e.stroke(),e.restore(),e.restore()}function Ge(e,t,n,o=9){if(t.length===0)return!1;let r=Math.max(o,n.strokeWidth/2+6);if(t.length===1)return Math.hypot(e.x-t[0].x,e.y-t[0].y)<=r;let a=1/0,s=1/0,l=-1/0,i=-1/0;for(let d=0;d<t.length;d+=1){let u=t[d];u.x<a&&(a=u.x),u.y<s&&(s=u.y),u.x>l&&(l=u.x),u.y>i&&(i=u.y)}if(e.x<a-r||e.x>l+r||e.y<s-r||e.y>i+r)return!1;for(let d=0;d<t.length-1;d+=1)if(j(e,t[d],t[d+1])<=r)return!0;return!1}function be(e,t,n,o){let{minX:r,minY:a,maxX:s,maxY:l,width:i,height:d,cx:u,cy:p}=t;if(n==="square"){let h=o?.shapeBorderRadius??0;h>0&&typeof e.roundRect=="function"?e.roundRect(r,a,i,d,h):e.rect(r,a,i,d);return}if(n==="circle"){e.ellipse(u,p,i/2,d/2,0,0,Math.PI*2);return}if(n==="triangle"){e.moveTo(u,a),e.lineTo(s,l),e.lineTo(r,l),e.closePath();return}if(n==="diamond"){e.moveTo(u,a),e.lineTo(s,p),e.lineTo(u,l),e.lineTo(r,p),e.closePath();return}if(n==="hexagon"){let h=i/2,m=d/2;for(let f=0;f<6;f+=1){let y=Math.PI/3*f-Math.PI/6,w=u+h*Math.cos(y),b=p+m*Math.sin(y);f===0?e.moveTo(w,b):e.lineTo(w,b)}e.closePath();return}if(n==="star"){let m=i/2,f=d/2,y=m*.42,w=f*.42;for(let b=0;b<10;b+=1){let M=b%2===0?m:y,x=b%2===0?f:w,A=b*Math.PI/5-Math.PI/2,F=u+M*Math.cos(A),O=p+x*Math.sin(A);b===0?e.moveTo(F,O):e.lineTo(F,O)}e.closePath();return}if(n==="marker"||n==="cloud"){let h=i/2,m=d*.36,f=a+m;e.moveTo(u,l),e.bezierCurveTo(r+i*.05,a+d*.7,r,a+d*.5,r,f),e.ellipse(u,f,h,m,0,Math.PI,0,!1),e.bezierCurveTo(s,a+d*.5,s-i*.05,a+d*.7,u,l),e.closePath();let y=h*.35,w=m*.35;y>=2.5&&w>=2.5&&(e.moveTo(u+y,f),e.ellipse(u,f,y,w,0,Math.PI*2,0,!0),e.closePath());return}if(n==="actor"){let h=Math.min(i,d)*.16,m=a+h+d*.04,f=m+h,y=a+d*.64,w=a+d*.42,b=i*.36,M=i*.32;e.moveTo(u+h,m),e.arc(u,m,h,0,Math.PI*2),e.closePath(),e.moveTo(u,f),e.lineTo(u,y),e.moveTo(u-b,w),e.lineTo(u+b,w),e.moveTo(u,y),e.lineTo(u-M,l),e.moveTo(u,y),e.lineTo(u+M,l)}}function ne(e,t){let n=W(e,t.start),o=W(e,t.end),r=Math.min(n.x,o.x),a=Math.min(n.y,o.y),s=Math.max(n.x,o.x),l=Math.max(n.y,o.y),i=Math.max(4,s-r),d=Math.max(4,l-a);return{start:n,end:o,minX:r,minY:a,maxX:s,maxY:l,width:i,height:d,cx:r+i/2,cy:a+d/2}}function Pe(e,t,n,o={}){if(t.width<4&&t.height<4)return;let r=o.theme;if(e.save(),o.isPreview&&(e.globalAlpha=.85),o.isSelected&&(e.save(),e.beginPath(),be(e,t,n.shape,r),e.strokeStyle=r?.selectionGlowColor??"rgba(0, 0, 0, 0.2)",e.lineWidth=n.strokeWidth+(r?.selectionGlowWidth??6),e.lineCap="round",e.lineJoin="round",e.stroke(),e.restore()),e.save(),e.shadowColor=r?.shadowColor??"rgba(0, 0, 0, 0.2)",e.shadowBlur=r?.shadowBlur??3,e.shadowOffsetY=r?.shadowOffsetY??1.5,e.beginPath(),be(e,t,n.shape,r),n.filled){let a=r?.shapeDefaultFillOpacity??.16,s=Math.round(Math.min(1,Math.max(0,a))*255).toString(16).padStart(2,"0");e.fillStyle=n.fillColor??`${n.color}${s}`,e.fill()}if(e.strokeStyle=n.color,e.lineWidth=n.strokeWidth,e.lineCap="round",e.lineJoin="round",e.setLineDash(n.dashed?[n.strokeWidth*3,n.strokeWidth*2]:[]),e.stroke(),e.restore(),n.label){let a=typeof r?.labelMinShapeSize=="number"?r.labelMinShapeSize:18;if(a<=0||Math.max(t.width,t.height)>=a&&t.width>=8&&t.height>=8){let s=n.shape==="actor"?t.maxY+14:t.cy,l=r?.fitLabelsToShape!==!1,i=r?.labelMaxTextWidth??(l?Math.max(48,Math.min(280,t.width*2.2)):1/0);ee(e,n.label,Math.round(t.cx),Math.round(s),n.color,i,r)}}if(o.isSelected){let a=r?.handleRadius??5,s=r?.handleFillColor??"#ffffff",l=r?.endpointHandleColor??"#4f4f4f",i=r?.handleStrokeWidth??2;e.save(),e.setLineDash(r?.guideLineDash?[...r.guideLineDash]:[4,4]),e.strokeStyle=r?.guideLineColor??"rgba(100, 100, 100, 0.6)",e.lineWidth=r?.guideLineWidth??1.2,e.strokeRect(t.minX,t.minY,t.width,t.height),e.restore(),X(e,t.start,l,s,a,i),X(e,t.end,l,s,a,i)}e.restore()}function Ne(e,t,n=11){return Math.hypot(e.x-t.end.x,e.y-t.end.y)<=n?"end":Math.hypot(e.x-t.start.x,e.y-t.start.y)<=n?"start":null}function Ye(e,t,n=8){return e.x>=t.minX-n&&e.x<=t.maxX+n&&e.y>=t.minY-n&&e.y<=t.maxY+n}function re(e,t){let n=W(e,t.start),o=W(e,t.end),r={x:(n.x+o.x)/2,y:(n.y+o.y)/2},a=Math.hypot(o.x-n.x,o.y-n.y),s=Math.atan2(o.y-n.y,o.x-n.x);return{start:n,end:o,mid:r,lengthPx:a,angle:s}}function xe(e,t,n,o={}){let{start:r,end:a,mid:s,lengthPx:l,angle:i}=t;if(l<2)return;let d=o.theme;e.save(),o.isPreview&&(e.globalAlpha=.9),o.isSelected&&(e.save(),e.beginPath(),e.moveTo(r.x,r.y),e.lineTo(a.x,a.y),e.strokeStyle=d?.selectionGlowColor??"rgba(0, 0, 0, 0.2)",e.lineWidth=n.strokeWidth+(d?.selectionGlowWidth??6),e.lineCap="round",e.stroke(),e.restore()),e.save(),e.shadowColor=d?.shadowColor??"rgba(0, 0, 0, 0.2)",e.shadowBlur=d?.shadowBlur??3,e.shadowOffsetY=d?.shadowOffsetY??1.5,e.beginPath(),e.moveTo(r.x,r.y),e.lineTo(a.x,a.y),e.strokeStyle=n.color,e.lineWidth=n.strokeWidth,e.lineCap="round",n.dashed?e.setLineDash([n.strokeWidth*3,n.strokeWidth*2]):e.setLineDash([]),e.stroke();let u=i+Math.PI/2,p=Math.max(7,n.strokeWidth*3.2),h=Math.cos(u)*p,m=Math.sin(u)*p;e.beginPath(),e.setLineDash([]),e.moveTo(r.x-h,r.y-m),e.lineTo(r.x+h,r.y+m),e.moveTo(a.x-h,a.y-m),e.lineTo(a.x+h,a.y+m),e.stroke(),e.restore();let f=pe(n.start,n.end),y=n.label?n.label:Fe(f,n.unit);if(y){let w=d?.fitLabelsToShape!==!1,b=d?.labelMaxTextWidth??(w?Math.max(50,Math.min(300,l*1.5)):1/0);ee(e,y,Math.round(s.x),Math.round(s.y),n.color,b,d)}if(o.isSelected){let w=d?.handleRadius??5,b=d?.handleFillColor??"#ffffff",M=d?.endpointHandleColor??"#4f4f4f",x=d?.handleStrokeWidth??2;X(e,r,M,b,w,x),X(e,a,M,b,w,x)}e.restore()}function je(e,t,n=11){return Math.hypot(e.x-t.end.x,e.y-t.end.y)<=n?"end":Math.hypot(e.x-t.start.x,e.y-t.start.y)<=n?"start":null}function Xe(e,t,n,o=9){let r=Math.max(o,n.strokeWidth/2+6);return j(e,t.start,t.end)<=r}function Gt(e){let t=q.find(o=>o.bg===e);if(t)return t;let n=e?.startsWith("#")&&e.length===7&&parseInt(e.slice(1),16)<8947848||e==="#111827"||e==="#1e293b"||e==="#0f172a";return{name:"Custom",bg:e,border:n?"rgba(255, 255, 255, 0.16)":"rgba(0, 0, 0, 0.12)",header:n?"rgba(255, 255, 255, 0.08)":"rgba(0, 0, 0, 0.06)",text:n?"#f8fafc":"#0f172a"}}function Nt(e,t,n,o,r,a=!0){let s=a!==!1?de(e):null;if(!s||r||!(t.x>=-120&&t.x<=s.width+120&&t.y>=-120&&t.y<=s.height+120))return t;let i=o?95:n.width??230,d=o?22:n.height??100,u=8,p=16+u,h=Math.max(p,s.width-i+16-u),m=12+u,f=Math.max(m,s.height-d+12-u);return{x:Math.max(p,Math.min(h,t.x)),y:Math.max(m,Math.min(f,t.y))}}function Xt(e,t,n,o,r,a,s=!0){let l=s!==!1?de(e):null;if(!l||a||!(t.x>=-100&&t.x<=l.width+100&&t.y>=-100&&t.y<=l.height+100))return t;let d=r?35:Math.max(24,(n.text||"Text").length*o/3.6),u=r?11:o/2+4,p=8,h=d+p,m=Math.max(h,l.width-d-p),f=u+p,y=Math.max(f,l.height-u-p);return{x:Math.max(h,Math.min(m,t.x)),y:Math.max(f,Math.min(y,t.y))}}function Te(e,t,n,o,r,a,s,l,i,d,u,p){l.current={screenPoints:[n],geoPoints:[o]},e.dragging.disable(),d();let h=f=>{if(!l.current)return;let y=t.getBoundingClientRect(),w={x:f.clientX-y.left,y:f.clientY-y.top},b=l.current.screenPoints,M=b[b.length-1];Math.hypot(w.x-M.x,w.y-M.y)<2.5||(b.push(w),l.current.geoPoints.push(L(e,w)),i.current===null&&(i.current=window.requestAnimationFrame(()=>{i.current=null,d()})))},m=f=>{window.removeEventListener("pointermove",h),window.removeEventListener("pointerup",m),e.dragging.enable(),i.current!==null&&(window.cancelAnimationFrame(i.current),i.current=null);let y=l.current;l.current=null,y&&y.geoPoints.length>=1?(u({id:K("freedraw"),type:"freedraw",points:y.geoPoints,color:r,strokeWidth:a,dashed:s,createdAt:Date.now()}),f.shiftKey||p("select")):d()};window.addEventListener("pointermove",h),window.addEventListener("pointerup",m)}function ze(e,t,n="Field Note"){let o=q.find(r=>r.bg===t)??q[0];return{id:K("note"),type:"note",position:e,title:n,text:"",backgroundColor:o.bg,textColor:o.text,width:230,createdAt:Date.now()}}function Ke(e,t,n,o,r){return{id:K("text"),type:"text",position:e,text:"",color:t,initialFontSize:n,baseZoom:r,fontWeight:o,createdAt:Date.now()}}function Ue(e,t,n,o,r,a,s,l,i,d,u,p){d({shape:r,startGeo:o,currentGeo:o}),e.dragging.disable();let h=f=>{let y=t.getBoundingClientRect(),w={x:f.clientX-y.left,y:f.clientY-y.top},b=f.shiftKey?oe(n,w,1):w;d({shape:r,startGeo:o,currentGeo:L(e,b)})},m=f=>{window.removeEventListener("pointermove",h),window.removeEventListener("pointerup",m),e.dragging.enable();let y=t.getBoundingClientRect(),w={x:f.clientX-y.left,y:f.clientY-y.top},b=f.shiftKey?oe(n,w,1):w,M=Math.hypot(w.x-n.x,w.y-n.y),x=M>=10?o:L(e,{x:n.x-45,y:n.y-45}),A=M>=10?L(e,b):L(e,{x:n.x+45,y:n.y+45});u({id:K("shape"),type:"shape",shape:r,start:x,end:A,color:a,filled:s,strokeWidth:l,dashed:i,createdAt:Date.now()}),d(null),p("select")};window.addEventListener("pointermove",h),window.addEventListener("pointerup",m)}function Ce(e,t,n,o,r,a){return{id:K("arrow"),type:"arrow",arrowStyle:e,start:t,end:n,controlPoint:e==="curved"?se(t,n):e==="elbow"?{lat:(t.lat+n.lat)/2,lng:(t.lng+n.lng)/2}:void 0,color:o,strokeWidth:r,dashed:a,headStyle:e==="bi"?"both":"triangle",createdAt:Date.now()}}function Je(e,t,n,o,r,a,s,l,i,d,u){i({arrowStyle:r,startGeo:o,currentGeo:o}),e.dragging.disable();let p=m=>{let f=t.getBoundingClientRect(),y={x:m.clientX-f.left,y:m.clientY-f.top},w=m.shiftKey?B(n,y):y;i({arrowStyle:r,startGeo:o,currentGeo:L(e,w)})},h=m=>{window.removeEventListener("pointermove",p),window.removeEventListener("pointerup",h),e.dragging.enable();let f=t.getBoundingClientRect(),y={x:m.clientX-f.left,y:m.clientY-f.top},w=m.shiftKey?B(n,y):y;Math.hypot(y.x-n.x,y.y-n.y)>=8&&(d(Ce(r,o,L(e,w),a,s,l)),i(null),u("select"))};window.addEventListener("pointermove",p),window.addEventListener("pointerup",h)}function dt(e,t,n,o,r){return{id:K("ruler"),type:"ruler",start:e,end:t,color:n,strokeWidth:o,dashed:r,unit:"metric",createdAt:Date.now()}}function $e(e,t,n,o,r,a,s,l,i,d){l({startGeo:o,currentGeo:o}),e.dragging.disable();let u=h=>{let m=t.getBoundingClientRect(),f={x:h.clientX-m.left,y:h.clientY-m.top},y=h.shiftKey?B(n,f):f;l({startGeo:o,currentGeo:L(e,y)})},p=h=>{window.removeEventListener("pointermove",u),window.removeEventListener("pointerup",p),e.dragging.enable();let m=t.getBoundingClientRect(),f={x:h.clientX-m.left,y:h.clientY-m.top},y=h.shiftKey?B(n,f):f;Math.hypot(f.x-n.x,f.y-n.y)>=8&&(i(dt(o,L(e,y),r,a,s)),l(null),d("select"))};window.addEventListener("pointermove",u),window.addEventListener("pointerup",p)}function Z(e,t){e.dragging.disable();let n=()=>{e.dragging.enable(),window.removeEventListener("pointermove",t),window.removeEventListener("pointerup",n)};window.addEventListener("pointermove",t),window.addEventListener("pointerup",n)}function qe(e,t,n,o,r,a){Z(e,s=>{let l=r(s),i=s.shiftKey;if(o==="start"){let d=i?B(n.end,l):l;a(t.id,{start:L(e,d)})}else if(o==="end"){let d=i?B(n.start,l):l;a(t.id,{end:L(e,d)})}else o==="control"&&a(t.id,{controlPoint:L(e,l)})})}function Ze(e,t,n,o,r,a){let s=o==="start"?n.end:n.start,l=n.width>4&&n.height>4?n.width/n.height:1;Z(e,i=>{let d=r(i),u=i.shiftKey?oe(s,d,l):d,p=L(e,u);a(t.id,o==="start"?{start:p}:{end:p})})}function Ve(e,t,n,o,r,a){let s=n.start,l=n.end,i=n.control,d=!!t.controlPoint;Z(e,u=>{let p=r(u),h=p.x-o.x,m=p.y-o.y,f={start:L(e,{x:s.x+h,y:s.y+m}),end:L(e,{x:l.x+h,y:l.y+m})};(t.arrowStyle==="curved"||t.arrowStyle==="elbow")&&d&&(f.controlPoint=L(e,{x:i.x+h,y:i.y+m})),a(t.id,f)})}function Qe(e,t,n,o,r,a){let s=n.start,l=n.end;Z(e,i=>{let d=r(i),u=d.x-o.x,p=d.y-o.y;a(t.id,{start:L(e,{x:s.x+u,y:s.y+p}),end:L(e,{x:l.x+u,y:l.y+p})})})}function et(e,t,n,o,r,a){Z(e,s=>{let l=r(s),i=l.x-o.x,d=l.y-o.y;a(t.id,{points:n.map(u=>L(e,{x:u.x+i,y:u.y+d}))})})}function tt(e,t,n,o,r,a){Z(e,s=>{let l=r(s),i=s.shiftKey;if(o==="start"){let d=i?B(n.end,l):l;a(t.id,{start:L(e,d)})}else if(o==="end"){let d=i?B(n.start,l):l;a(t.id,{end:L(e,d)})}})}function nt(e,t,n,o,r,a){let s=n.start,l=n.end;Z(e,i=>{let d=r(i),u=d.x-o.x,p=d.y-o.y;a(t.id,{start:L(e,{x:s.x+u,y:s.y+p}),end:L(e,{x:l.x+u,y:l.y+p})})})}function rt({map:e,canvas:t,width:n,height:o,arrowItems:r,shapeItems:a,freeDrawItems:s,rulerItems:l,selectedId:i,draftShape:d,draftArrow:u,draftRuler:p,draftFreeDraw:h,activeColor:m,strokeWidth:f,dashed:y,shapeFilled:w,annotationTheme:b,arrowTheme:M,isReadOnly:x}){if(!e||!t||n===0||o===0)return;let A=b??M,F=typeof window<"u"&&window.devicePixelRatio||1,O=Math.round(n*F),Y=Math.round(o*F);t.width!==O&&(t.width=O),t.height!==Y&&(t.height=Y);let C=t.getContext("2d");if(C){C.save(),typeof C.scale=="function"&&C.scale(F,F),C.clearRect(0,0,n,o);for(let P of s){let E=ce(e,P);ve(C,E,P,{isSelected:!x&&P.id===i,theme:A})}for(let P of a){let E=ne(e,P);Pe(C,E,P,{isSelected:!x&&P.id===i,theme:A})}for(let P of r){let E=te(e,P);we(C,E,P,{isSelected:!x&&P.id===i,theme:A})}for(let P of l){let E=re(e,P);xe(C,E,P,{isSelected:!x&&P.id===i,theme:A})}if(!x&&h&&h.screenPoints.length>0&&ve(C,h.screenPoints,{color:m,strokeWidth:f,dashed:y},{isPreview:!0,theme:A}),!x&&d){let P={id:"draft-shape",type:"shape",shape:d.shape,start:d.startGeo,end:d.currentGeo,color:m,filled:w,strokeWidth:f,dashed:y,createdAt:0},E=ne(e,P);Pe(C,E,P,{isPreview:!0,isSelected:!0,theme:A})}if(!x&&u){let P={id:"draft-arrow",type:"arrow",arrowStyle:u.arrowStyle,start:u.startGeo,end:u.currentGeo,color:m,strokeWidth:f,dashed:y,createdAt:0},E=te(e,P);we(C,E,P,{isPreview:!0,isSelected:!0,theme:A})}if(!x&&p){let P={id:"draft-ruler",type:"ruler",start:p.startGeo,end:p.currentGeo,color:m,strokeWidth:f,dashed:y,unit:"metric",createdAt:0},E=re(e,P);xe(C,E,P,{isPreview:!0,isSelected:!0,theme:A})}C.restore()}}function ot(e,t){let n=()=>{let o=e.getSize();t({width:o.x,height:o.y})};return n(),e.on("move",n),e.on("zoom",n),e.on("zoomanim",n),e.on("viewreset",n),e.on("resize",n),()=>{e.off("move",n),e.off("zoom",n),e.off("zoomanim",n),e.off("viewreset",n),e.off("resize",n)}}function it(e){let t=e.getContainer();if(!t)return()=>{};let n=r=>{let a=r.target;if(!a?.closest?.("[data-rlc-overlay], input, textarea, select, button, .rlc-overlay"))return;let s=Object.prototype.hasOwnProperty.call(a,"_leaflet_disable_events"),l=a._leaflet_disable_events;a._leaflet_disable_events=!0;let i=!!e.doubleClickZoom?.enabled?.();i&&e.doubleClickZoom.disable(),setTimeout(()=>{s?a._leaflet_disable_events=l:delete a._leaflet_disable_events,i&&e.doubleClickZoom.enable()},0)},o=r=>{if(r.target?.closest?.("textarea, input, select, button, [data-rlc-note-resize], .rlc-note-resize-handle")&&e.dragging?.enabled?.()){e.dragging.disable();let s=()=>{e.dragging.enable(),window.removeEventListener("mouseup",s,!0),window.removeEventListener("touchend",s,!0),window.removeEventListener("pointerup",s,!0)};window.addEventListener("mouseup",s,{capture:!0,once:!0}),window.addEventListener("touchend",s,{capture:!0,once:!0}),window.addEventListener("pointerup",s,{capture:!0,once:!0})}};return t.addEventListener("dblclick",n,!0),t.addEventListener("mousedown",o,!0),t.addEventListener("touchstart",o,!0),()=>{t.removeEventListener("dblclick",n,!0),t.removeEventListener("mousedown",o,!0),t.removeEventListener("touchstart",o,!0)}}function Le(e={}){let t=Math.max(0,(e.maxHistory??50)-1),n=[],o=e.items??e.initialItems??[],r=[],a=o,s=e.initialTool??"select",l=!!(e.readOnly??!1),i=null,d=!1,u=e.defaultShape??"square",p=!0,h=e.defaultColor??De,m=e.defaultStrokeWidth??Ae,f=!1,y=e.defaultNoteColor??Ee,w=e.defaultFontSize??Re,b="bold",M=new Set,x=()=>{for(let c of M)c(T)},A=c=>{e.onItemsChange?.(c),e.onChange?.(c)},F=(c,g)=>{e.onItemsChangeComplete?.(c,g),e.onChangeComplete?.(c,g),e.onEditEnd?.(c,g),e.onEditComplete?.(c,g),g&&e.onItemChangeComplete?.(g)},O=c=>{let g=c(o);return o=g,A(g),x(),g},Y=c=>{if(o===a)return;let g=a;a=o,n=[...n,g].slice(-t),r=[],F(o,c),x()},C=c=>{if(i!==c){let g=i;i=c,d=!1,g!==null&&c===null&&Y(),e.onItemSelect?.(o.find(R=>R.id===c)??null),x()}},P=c=>{l&&c!=="select"||(s=c,e.onToolChange?.(c),x())},E=c=>{l=!!c,l&&s!=="select"&&(s="select"),x()},G=(c,g)=>{i&&O(R=>R.map(z=>z.id===i&&c(z)?g(z):z))},ie=c=>{l||(u=c,G(g=>g.type==="shape",g=>({...g,shape:c})),x())},ae=c=>{l||(p=c,G(g=>g.type==="shape",g=>({...g,filled:c})),x())},ue=c=>{l||(h=c,G(g=>g.type!=="note",g=>({...g,color:c})),x())},fe=c=>{l||(m=c,G(g=>g.type==="arrow"||g.type==="freedraw"||g.type==="shape"||g.type==="ruler",g=>({...g,strokeWidth:c})),x())},he=c=>{l||(f=c,G(g=>g.type==="arrow"||g.type==="freedraw"||g.type==="shape"||g.type==="ruler",g=>({...g,dashed:c})),x())},S=c=>{if(l)return;y=c;let g=q.find(R=>R.bg===c);G(R=>R.type==="note",R=>({...R,backgroundColor:c,textColor:g?.text??R.textColor})),x()},I=c=>{l||(w=c,G(g=>g.type==="text",g=>({...g,initialFontSize:c})),x())},D=c=>{l||(b=c,G(g=>g.type==="text",g=>({...g,fontWeight:c})),x())},k=c=>{d=c,x()},U=c=>{l||(O(g=>[...g,c]),C(c.id),e.onItemCreate?.(c))},J=(c,g)=>{if(l){let z=Object.keys(g);if(z.length!==1||z[0]!=="minimized")return}let R;O(z=>z.map(me=>me.id===c?(R={...me,...g},R):me)),R&&e.onItemChange?.(R)},H=c=>{l||(O(g=>g.filter(R=>R.id!==c)),i===c&&C(null),e.onItemDelete?.(c),Y())},N=()=>{!l&&i&&H(i)},_=()=>{l||(O(()=>[]),C(null),Y())},T={get items(){return o},get activeTool(){return s},setActiveTool:P,get readOnly(){return l},setReadOnly:E,get activeShape(){return u},setActiveShape:ie,get shapeFilled(){return p},setShapeFilled:ae,get selectedId(){return i},setSelectedId:C,get selectedItem(){return o.find(c=>c.id===i)??null},get isEditingLabel(){return d},setEditingLabel:k,get labelEditMode(){return d},setLabelEditMode:k,get activeColor(){return h},setActiveColor:ue,get strokeWidth(){return m},setStrokeWidth:fe,get dashed(){return f},setDashed:he,get noteColor(){return y},setNoteColor:S,get fontSize(){return w},setFontSize:I,get fontWeight(){return b},setFontWeight:D,addItem:U,updateItem:J,removeItem:H,deleteSelected:N,clearAll:_,clear:_,deleteItem:H,setTool:P,selectItem:C,undo:()=>{if(l||n.length===0)return;let c=n[n.length-1];r=[o,...r],n=n.slice(0,-1),o=c,a=c,A(c),F(c,null),x()},redo:()=>{if(l||r.length===0)return;let c=r[0];n=[...n,o],r=r.slice(1),o=c,a=c,A(c),F(c,null),x()},get canUndo(){return!l&&n.length>0},get canRedo(){return!l&&r.length>0},notifyChangeComplete:Y,exportJSON:()=>JSON.stringify(o,null,2),importJSON:c=>{if(l)return!1;try{let g=JSON.parse(c);return Array.isArray(g)?(O(()=>g),C(null),Y(),!0):!1}catch{return!1}},subscribe(c){return M.add(c),()=>{M.delete(c)}},getState(){return T},destroy(){M.clear()}};return T}var rn=Le;function ct(e,t={}){let{controller:n,annotationTheme:o,arrowTheme:r,labels:a,zIndex:s=650,...l}=t,i=n??Le(l),d=e.getContainer(),u=document.createElement("div");u.setAttribute("data-rlc-overlay","true"),u.style.position="absolute",u.style.inset="0",u.style.pointerEvents="none",u.style.zIndex=String(s),u.style.overflow="hidden";let p=document.createElement("canvas");p.style.position="absolute",p.style.top="0",p.style.left="0",p.style.pointerEvents="none";let h=document.createElement("div");h.style.position="absolute",h.style.inset="0",h.style.pointerEvents="none",u.appendChild(p),u.appendChild(h),d.appendChild(u);let m={width:0,height:0},f=null,y=null,w=null,b={current:null},M={current:null},x=S=>{f=S,C()},A=S=>{y=S,C()},F=S=>{w=S,C()},O=()=>{b.current=null,M.current!==null&&typeof window<"u"&&(window.cancelAnimationFrame(M.current),M.current=null)},Y=()=>{let S=!i.readOnly&&i.activeTool!=="select";h.style.pointerEvents=S?"auto":"none",h.style.cursor=S?"crosshair":"default",p.style.width=`${m.width}px`,p.style.height=`${m.height}px`},C=()=>{Y();let S=i.items;rt({map:e,canvas:p,width:m.width,height:m.height,arrowItems:S.filter(I=>I.type==="arrow"),shapeItems:S.filter(I=>I.type==="shape"),freeDrawItems:S.filter(I=>I.type==="freedraw"),rulerItems:S.filter(I=>I.type==="ruler"),selectedId:i.selectedId,draftShape:y,draftArrow:f,draftRuler:w,draftFreeDraw:b.current,activeColor:i.activeColor,strokeWidth:i.strokeWidth,dashed:i.dashed,shapeFilled:i.shapeFilled,annotationTheme:o,arrowTheme:r,isReadOnly:i.readOnly})},P=S=>{let I=d.getBoundingClientRect();return{x:S.clientX-I.left,y:S.clientY-I.top}},E=S=>{if(S.button!==0||i.readOnly)return;S.stopPropagation(),S.preventDefault();let I=P(S),D=L(e,I),{activeTool:k,activeShape:U,shapeFilled:J,activeColor:H,strokeWidth:N,dashed:_,noteColor:$,fontSize:V,fontWeight:Q}=i;if(k==="freedraw"){Te(e,d,I,D,H,N,_,b,M,C,i.addItem,i.setActiveTool);return}if(k==="shape"){Ue(e,d,I,D,U,H,J,N,_,A,i.addItem,i.setActiveTool);return}if(k==="note"){i.addItem(ze(D,$,a?.noteDefaultTitle??"Field Note")),i.setActiveTool("select");return}if(k==="text"){i.addItem(Ke(D,H,V,Q,e.getZoom?.()??14)),i.setActiveTool("select");return}if(k==="ruler"){$e(e,d,I,D,H,N,_,F,i.addItem,i.setActiveTool);return}let v=Ie[k];if(v)if(!f)Je(e,d,I,D,v,H,N,_,x,i.addItem,i.setActiveTool);else{let T=W(e,f.startGeo),c=S.shiftKey?B(T,I):I;Math.hypot(c.x-T.x,c.y-T.y)>=4&&i.addItem(Ce(f.arrowStyle,f.startGeo,L(e,c),H,N,_)),x(null),i.setActiveTool("select")}},G=S=>{if(!f)return;let I=P(S),D=W(e,f.startGeo),k=S.shiftKey?B(D,I):I;x({...f,currentGeo:L(e,k)})},ie=S=>{if(S.button!==0||i.readOnly||i.activeTool!=="select"||S.target?.closest("[data-rlc-toolbar], [data-rlc-note], [data-rlc-text], .leaflet-control"))return;let D=P(S),k=i.items,U=k.filter(v=>v.type==="arrow"),J=k.filter(v=>v.type==="shape"),H=k.filter(v=>v.type==="freedraw"),N=k.filter(v=>v.type==="ruler"),_=i.selectedId,$=U.find(v=>v.id===_);if($){let v=te(e,$),T=He(D,v,$);if(T){S.stopPropagation(),S.preventDefault(),qe(e,$,v,T,P,i.updateItem);return}}let V=J.find(v=>v.id===_);if(V){let v=ne(e,V),T=Ne(D,v);if(T){S.stopPropagation(),S.preventDefault(),Ze(e,V,v,T,P,i.updateItem);return}}let Q=N.find(v=>v.id===_);if(Q){let v=re(e,Q),T=je(D,v);if(T){S.stopPropagation(),S.preventDefault(),tt(e,Q,v,T,P,i.updateItem);return}}for(let v=U.length-1;v>=0;v-=1){let T=U[v],c=te(e,T);if(_e(D,c,T)){S.stopPropagation(),S.preventDefault(),i.setSelectedId(T.id),Ve(e,T,c,D,P,i.updateItem);return}}for(let v=J.length-1;v>=0;v-=1){let T=J[v],c=ne(e,T);if(Ye(D,c)){S.stopPropagation(),S.preventDefault(),i.setSelectedId(T.id),Qe(e,T,c,D,P,i.updateItem);return}}for(let v=H.length-1;v>=0;v-=1){let T=H[v],c=ce(e,T);if(Ge(D,c,T)){S.stopPropagation(),S.preventDefault(),i.setSelectedId(T.id),et(e,T,c,D,P,i.updateItem);return}}for(let v=N.length-1;v>=0;v-=1){let T=N[v],c=re(e,T);if(Xe(D,c,T)){S.stopPropagation(),S.preventDefault(),i.setSelectedId(T.id),nt(e,T,c,D,P,i.updateItem);return}}_&&(i.setSelectedId(null),i.notifyChangeComplete())},ae=S=>{if(i.readOnly)return;let I=S.target;I&&(I.tagName==="INPUT"||I.tagName==="TEXTAREA"||I.isContentEditable)||(S.key==="Escape"?(f=null,y=null,w=null,O(),i.setSelectedId(null),i.setActiveTool("select"),i.notifyChangeComplete(),C()):(S.key==="Delete"||S.key==="Backspace")&&i.selectedId&&(S.preventDefault(),i.deleteSelected()))};h.addEventListener("pointerdown",E),h.addEventListener("pointermove",G),d.addEventListener("pointerdown",ie,{capture:!0}),typeof window<"u"&&window.addEventListener("keydown",ae);let ue=ot(e,S=>{m=S,C()}),fe=it(e),he=i.subscribe(()=>{C()});return C(),{controller:i,container:u,canvas:p,repaint:C,destroy(){h.removeEventListener("pointerdown",E),h.removeEventListener("pointermove",G),d.removeEventListener("pointerdown",ie,{capture:!0}),typeof window<"u"&&window.removeEventListener("keydown",ae),O(),ue(),fe(),he(),n||i.destroy(),u.remove()}}}var hn=ct;var pn=Me.version;export{pt as DEFAULT_ANNOTATION_THEME,Re as DEFAULT_FONT_SIZE,lt as DEFAULT_FONT_SIZE_OPTIONS,Ee as DEFAULT_NOTE_BG,mt as DEFAULT_NOTE_TEXT,De as DEFAULT_STROKE_COLOR,Ae as DEFAULT_STROKE_WIDTH,st as DEFAULT_STROKE_WIDTH_OPTIONS,yt as FONT_SIZE_OPTIONS,q as NOTE_COLOR_THEMES,ft as STROKE_COLORS,ht as STROKE_WIDTH_OPTIONS,Ie as TOOL_TO_ARROW_STYLE,pn as VERSION,it as bindBlockMapDblClick,ot as bindLeafletSync,Ce as buildArrowItem,dt as buildRulerItem,pe as calculateGeodesicDistance,wt as calculateLineDistance,St as calculateZoomFontSize,Nt as clampNotePosition,Xt as clampTextPosition,se as computeDefaultControlGeoPoint,B as constrainAngleTo45Degrees,oe as constrainToAspectRatio,ze as createDraftNote,Ke as createDraftText,K as createId,ct as createLeafletCanvas,Le as createLeafletCanvasController,hn as createLeafletTual,rn as createLeafletTualController,Oe as distanceToQuadraticBezier,j as distanceToSegment,ge as drawArrowHead,X as drawCanvasHandle,ee as drawCanvasLabelPill,Fe as formatRealWorldDistance,W as geoToScreen,de as getMapDimensions,ye as getQuadraticBezierPoint,le as getQuadraticEndAngle,_e as hitTestArrow,He as hitTestArrowHandle,Ge as hitTestFreeDraw,Xe as hitTestRuler,je as hitTestRulerHandle,Ye as hitTestShape,Ne as hitTestShapeHandle,rt as paintLeafletCanvas,te as projectArrow,ce as projectFreeDraw,re as projectRuler,ne as projectShape,we as renderArrowOnCanvas,ve as renderFreeDrawOnCanvas,xe as renderRulerOnCanvas,Pe as renderShapeOnCanvas,Gt as resolveNoteTheme,L as screenToGeo,Ve as startArrowBodyDrag,Je as startArrowDrag,qe as startArrowHandleDrag,et as startFreeDrawBodyDrag,Te as startFreeDrawDrag,nt as startRulerBodyDrag,$e as startRulerDrag,tt as startRulerHandleDrag,Qe as startShapeBodyDrag,Ue as startShapeDrag,Ze as startShapeHandleDrag,Se as traceArrowPath,be as tracePolygonShape,We as truncateCanvasText};
2
+ //# sourceMappingURL=index.js.map