leaflet-tual 0.0.0 → 1.0.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.
- package/README.md +256 -0
- package/dist/index.cjs +2 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +557 -0
- package/dist/index.d.ts +557 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/dist/react.cjs +4 -0
- package/dist/react.cjs.map +1 -0
- package/dist/react.d.cts +820 -0
- package/dist/react.d.ts +820 -0
- package/dist/react.js +4 -0
- package/dist/react.js.map +1 -0
- package/package.json +124 -6
- package/index.js +0 -1
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,557 @@
|
|
|
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 TualTool = '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 TualItem = 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 TualLabels {
|
|
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 TualAnnotationTheme {
|
|
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 = TualAnnotationTheme;
|
|
185
|
+
interface LeafletTualClassNames {
|
|
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 TualOverlayOptions {
|
|
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 UseLeafletTualOptions extends TualOverlayOptions {
|
|
262
|
+
initialItems?: TualItem[];
|
|
263
|
+
items?: TualItem[];
|
|
264
|
+
maxHistory?: number;
|
|
265
|
+
onItemsChange?: (items: TualItem[]) => void;
|
|
266
|
+
onChange?: (items: TualItem[]) => void;
|
|
267
|
+
onChangeComplete?: (items: TualItem[], targetItem?: TualItem | null) => void;
|
|
268
|
+
onItemsChangeComplete?: (items: TualItem[], targetItem?: TualItem | null) => void;
|
|
269
|
+
onEditEnd?: (items: TualItem[], targetItem?: TualItem | null) => void;
|
|
270
|
+
onEditComplete?: (items: TualItem[], targetItem?: TualItem | null) => void;
|
|
271
|
+
onItemSelect?: (item: TualItem | null) => void;
|
|
272
|
+
onItemCreate?: (item: TualItem) => void;
|
|
273
|
+
onItemChange?: (item: TualItem) => void;
|
|
274
|
+
onItemDelete?: (id: string) => void;
|
|
275
|
+
onItemChangeComplete?: (item: TualItem) => void;
|
|
276
|
+
initialTool?: TualTool;
|
|
277
|
+
onToolChange?: (tool: TualTool) => void;
|
|
278
|
+
}
|
|
279
|
+
type LeafletTualOptions = UseLeafletTualOptions;
|
|
280
|
+
interface LeafletTualController {
|
|
281
|
+
items: TualItem[];
|
|
282
|
+
activeTool: TualTool;
|
|
283
|
+
setActiveTool: (tool: TualTool) => 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: TualItem | 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: TualItem) => void;
|
|
310
|
+
updateItem: (id: string, patch: Partial<TualItem>) => void;
|
|
311
|
+
removeItem: (id: string) => void;
|
|
312
|
+
deleteSelected: () => void;
|
|
313
|
+
clearAll: () => void;
|
|
314
|
+
clear: () => void;
|
|
315
|
+
deleteItem: (id: string) => void;
|
|
316
|
+
setTool: (tool: TualTool) => void;
|
|
317
|
+
selectItem: (id: string | null) => void;
|
|
318
|
+
undo: () => void;
|
|
319
|
+
redo: () => void;
|
|
320
|
+
canUndo: boolean;
|
|
321
|
+
canRedo: boolean;
|
|
322
|
+
notifyChangeComplete: (targetItem?: TualItem | 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<TualAnnotationTheme>;
|
|
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 truncateTualText(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 drawTualHandle(ctx: CanvasRenderingContext2D, pt: ScreenPoint, strokeColor: string, fillColor: string, radius: number, strokeWidth?: number): void;
|
|
376
|
+
declare function drawTualLabelPill(ctx: CanvasRenderingContext2D, label: string, midX: number, midY: number, strokeColor: string, maxAllowedBoxWidth: number, theme?: TualAnnotationTheme): 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?: TualAnnotationTheme;
|
|
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?: TualAnnotationTheme;
|
|
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?: TualAnnotationTheme): 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?: TualAnnotationTheme;
|
|
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 PaintLeafletTualOptions {
|
|
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?: TualAnnotationTheme;
|
|
505
|
+
arrowTheme?: ArrowRenderTheme;
|
|
506
|
+
isReadOnly: boolean;
|
|
507
|
+
}
|
|
508
|
+
declare function paintLeafletTual({ map, canvas, width, height, arrowItems, shapeItems, freeDrawItems, rulerItems, selectedId, draftShape, draftArrow, draftRuler, draftFreeDraw, activeColor, strokeWidth, dashed, shapeFilled, annotationTheme, arrowTheme, isReadOnly, }: PaintLeafletTualOptions): 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 LeafletTualStore extends LeafletTualController {
|
|
518
|
+
subscribe: (listener: (controller: LeafletTualController) => void) => () => void;
|
|
519
|
+
getState: () => LeafletTualController;
|
|
520
|
+
destroy: () => void;
|
|
521
|
+
}
|
|
522
|
+
declare function createLeafletTualController(options?: UseLeafletTualOptions): LeafletTualStore;
|
|
523
|
+
|
|
524
|
+
interface CreateLeafletTualOptions extends UseLeafletTualOptions {
|
|
525
|
+
controller?: LeafletTualStore;
|
|
526
|
+
annotationTheme?: TualAnnotationTheme;
|
|
527
|
+
arrowTheme?: ArrowRenderTheme;
|
|
528
|
+
labels?: TualLabels;
|
|
529
|
+
}
|
|
530
|
+
interface LeafletTualInstance {
|
|
531
|
+
controller: LeafletTualStore;
|
|
532
|
+
container: HTMLDivElement;
|
|
533
|
+
canvas: HTMLCanvasElement;
|
|
534
|
+
repaint: () => void;
|
|
535
|
+
destroy: () => void;
|
|
536
|
+
}
|
|
537
|
+
declare function createLeafletTual(map: L.Map, options?: CreateLeafletTualOptions): LeafletTualInstance;
|
|
538
|
+
|
|
539
|
+
/**
|
|
540
|
+
* leaflet-tual — core (framework-agnostic)
|
|
541
|
+
*
|
|
542
|
+
* Interactive canvas and annotation toolkit for Leaflet maps — draw vector
|
|
543
|
+
* arrows, geometric shapes, freehand sketches, rulers, sticky notes, and text
|
|
544
|
+
* overlays that stay geographically synchronized with Leaflet across panning
|
|
545
|
+
* and zooming.
|
|
546
|
+
*
|
|
547
|
+
* This module is the entire framework-agnostic public surface. It has zero
|
|
548
|
+
* dependency on React or any UI framework, so it can be used directly from
|
|
549
|
+
* vanilla JavaScript, TypeScript, Vue, Svelte, Angular, or a plain `<script>` tag.
|
|
550
|
+
*
|
|
551
|
+
* React users: see `leaflet-tual/react` for `<LeafletTual>`, `<TualToolbar>`,
|
|
552
|
+
* `useLeafletTual`, and `useLeafletSync`.
|
|
553
|
+
*/
|
|
554
|
+
|
|
555
|
+
declare const VERSION: string;
|
|
556
|
+
|
|
557
|
+
export { type ArrowHandleType, type ArrowHeadStyle, type ArrowItem, type ArrowRenderTheme, type ArrowStyle, type CreateLeafletTualOptions, 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 LeafletTualClassNames, type LeafletTualController, type LeafletTualInstance, type LeafletTualOptions, type LeafletTualStore, type MapViewportDimensions, NOTE_COLOR_THEMES, type NoteCollapseState, type NoteColorTheme, type NoteItem, type PaintLeafletTualOptions, 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 TualAnnotationTheme, type TualItem, type TualLabels, type TualOverlayOptions, type TualTool, type UseLeafletTualOptions, VERSION, bindBlockMapDblClick, bindLeafletSync, buildArrowItem, buildRulerItem, calculateGeodesicDistance, calculateLineDistance, calculateZoomFontSize, clampNotePosition, clampTextPosition, computeDefaultControlGeoPoint, constrainAngleTo45Degrees, constrainToAspectRatio, createDraftNote, createDraftText, createId, createLeafletTual, createLeafletTualController, distanceToQuadraticBezier, distanceToSegment, drawArrowHead, drawTualHandle, drawTualLabelPill, formatRealWorldDistance, geoToScreen, getMapDimensions, getQuadraticBezierPoint, getQuadraticEndAngle, hitTestArrow, hitTestArrowHandle, hitTestFreeDraw, hitTestRuler, hitTestRulerHandle, hitTestShape, hitTestShapeHandle, paintLeafletTual, projectArrow, projectFreeDraw, projectRuler, projectShape, renderArrowOnCanvas, renderFreeDrawOnCanvas, renderRulerOnCanvas, renderShapeOnCanvas, resolveNoteTheme, screenToGeo, startArrowBodyDrag, startArrowDrag, startArrowHandleDrag, startFreeDrawBodyDrag, startFreeDrawDrag, startRulerBodyDrag, startRulerDrag, startRulerHandleDrag, startShapeBodyDrag, startShapeDrag, startShapeHandleDrag, traceArrowPath, tracePolygonShape, truncateTualText };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
var Le={name:"leaflet-tual",version:"1.0.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"},ut=["#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",Ce=2,lt=[1,2,3,4,5,6,8,10,12],ft=lt,Ae="#fef9c3",ht="#422006",Ee=16,st=[10,12,14,16,18,20,24,28,32,36,40,48],mt=st,yt={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 Re=0;function K(e="rlc"){Re+=1;let t=Math.random().toString(36).slice(2,8);return`${e}-${Date.now().toString(36)}-${Re}-${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 re(e,t,n=1){let r=n>0?n:1,o=t.x-e.x,a=t.y-e.y,l=Math.abs(o),s=Math.abs(a),i=o>=0?1:-1,d=a>=0?1:-1;return l/r>=s?{x:e.x+i*l,y:e.y+d*(l/r)}:{x:e.x+i*(s*r),y:e.y+d*s}}function B(e,t){let n=t.x-e.x,r=t.y-e.y,o=Math.hypot(n,r);if(o===0)return t;let a=Math.atan2(r,n),l=Math.PI/4,s=Math.round(a/l)*l;return{x:e.x+Math.cos(s)*o,y:e.y+Math.sin(s)*o}}function le(e,t,n=.25){let r=(e.lat+t.lat)/2,o=(e.lng+t.lng)/2,a=t.lat-e.lat,l=t.lng-e.lng;return{lat:r+l*n,lng:o-a*n}}function ye(e,t,n,r){let o=1-r;return{x:o*o*e.x+2*o*r*t.x+r*r*n.x,y:o*o*e.y+2*o*r*t.y+r*r*n.y}}function se(e,t,n){let r=n.x-t.x,o=n.y-t.y;return Math.hypot(r,o)<.001?Math.atan2(n.y-e.y,n.x-e.x):Math.atan2(o,r)}function j(e,t,n){let r=(n.x-t.x)**2+(n.y-t.y)**2;if(r===0)return Math.hypot(e.x-t.x,e.y-t.y);let o=((e.x-t.x)*(n.x-t.x)+(e.y-t.y)*(n.y-t.y))/r;o=Math.max(0,Math.min(1,o));let a=t.x+o*(n.x-t.x),l=t.y+o*(n.y-t.y);return Math.hypot(e.x-a,e.y-l)}function ke(e,t,n,r,o=24){let a=1/0,l=t;for(let s=1;s<=o;s+=1){let i=ye(t,n,r,s/o),d=j(e,l,i);d<a&&(a=d),l=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 Oe(e,t,n){if(!t||n<=0)return"";if(e.measureText(t).width<=n)return t;let r="\u2026";if(e.measureText(r).width>=n)return"";let o=0,a=t.length,l="";for(;o<=a;){let s=Math.floor((o+a)/2),i=t.slice(0,s)+r;e.measureText(i).width<=n?(l=i,o=s+1):a=s-1}return l||r}function gt(e=16,t,n=14,r){if(t===null||typeof t!="number")return e;let o=r?.scaleFactor??1.22,a=r?.min??9,l=r?.max??72,s=e*Math.pow(o,t-n);return Math.round(Math.max(a,Math.min(l,s)))}function pe(e,t){let r=(t.lat-e.lat)*Math.PI/180,o=(t.lng-e.lng)*Math.PI/180,a=e.lat*Math.PI/180,l=t.lat*Math.PI/180,s=Math.sin(r/2),i=Math.sin(o/2),d=s*s+Math.cos(a)*Math.cos(l)*i*i;return 6371e3*(2*Math.atan2(Math.sqrt(d),Math.sqrt(1-d)))}function We(e,t="metric"){if(t==="imperial"){let r=e*3.28084;if(r<1e3)return`${Math.round(r)} ft`;let o=r/5280;return`${o>=10?o.toFixed(1):o.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 St(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,r,o,a=2){e.save(),e.beginPath(),e.arc(t.x,t.y,o,0,Math.PI*2),e.fillStyle=r,e.fill(),e.lineWidth=a,e.strokeStyle=n,e.stroke(),e.restore()}function ee(e,t,n,r,o,a,l){e.save(),e.font=l?.labelFont??"12px system-ui, -apple-system, sans-serif";let s=l?.labelPaddingX??6,i=Math.max(10,a-s*2),d=Oe(e,t,i);if(d){let u=e.measureText(d),p=Math.round(u.width+s*2),h=l?.labelPaddingY??18,m=Math.round(n-p/2),f=Math.round(r-h/2),y=l?.labelBorderRadius??2;l?.labelShadowColor&&(e.shadowColor=l.labelShadowColor,e.shadowBlur=l.labelShadowBlur??3),e.fillStyle=l?.labelBackgroundColor??"#ffffff",e.strokeStyle=l?.labelBorderColor??o,e.lineWidth=l?.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=l?.labelTextColor??"#000000",e.textAlign="center",e.textBaseline="middle",e.fillText(d,n,r)}e.restore()}function ge(e,t,n,r,o,a=!0){let l=Math.PI/6.5,s=t.x-r*Math.cos(n-l),i=t.y-r*Math.sin(n-l),d=t.x-r*Math.cos(n+l),u=t.y-r*Math.sin(n+l);e.save(),e.setLineDash([]),e.beginPath(),e.moveTo(t.x,t.y),e.lineTo(s,i),a?(e.lineTo(d,u),e.closePath(),e.fillStyle=o,e.fill()):(e.moveTo(t.x,t.y),e.lineTo(d,u),e.strokeStyle=o,e.lineWidth=Math.max(2,r/4.5),e.lineCap="round",e.stroke()),e.restore()}function Se(e,t,n){let{start:r,end:o,control:a}=t;if(e.moveTo(r.x,r.y),n==="curved")e.quadraticCurveTo(a.x,a.y,o.x,o.y);else if(n==="elbow")e.lineTo(a.x,r.y),e.lineTo(a.x,o.y),e.lineTo(o.x,o.y);else if(n==="s-curve"){let l=o.x-r.x,s=o.y-r.y;e.bezierCurveTo(r.x+l*.5,r.y,r.x+l*.5,r.y+s,o.x,o.y)}else e.lineTo(o.x,o.y)}function te(e,t){let n=W(e,t.start),r=W(e,t.end),o=t.arrowStyle==="curved"||t.arrowStyle==="s-curve",a=t.controlPoint?t.controlPoint:o?le(t.start,t.end):{lat:(t.start.lat+t.end.lat)/2,lng:(t.start.lng+t.end.lng)/2},l=W(e,a);return{start:n,end:r,control:l}}function we(e,t,n,r={}){let{start:o,end:a,control:l}=t,s=Math.hypot(a.x-o.x,a.y-o.y);if(s<2)return;let i=r.theme,d=Math.max(12,n.strokeWidth*3.8),u=Math.atan2(a.y-o.y,a.x-o.x),p=Math.atan2(o.y-a.y,o.x-a.x);if(n.arrowStyle==="curved")u=se(o,l,a),p=se(a,l,o);else if(n.arrowStyle==="elbow"){let f=a.x-l.x,y=a.y-o.y;u=Math.abs(f)>1?Math.atan2(0,f):Math.atan2(y,0);let w=o.x-l.x;p=Math.abs(w)>1?Math.atan2(0,w):Math.atan2(-y,0)}else if(n.arrowStyle==="s-curve"){let f=a.x-o.x;u=se(o,{x:o.x+f*.5,y:a.y},a)}e.save(),r.isPreview&&(e.globalAlpha=.85),r.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,o,p,d,n.color,!0)),e.restore(),n.label){let f=typeof i?.labelMinShapeSize=="number"?i.labelMinShapeSize:24;if(f<=0||s>=f){let y=n.arrowStyle==="curved"?ye(o,l,a,.5):n.arrowStyle==="elbow"?{x:l.x,y:(o.y+a.y)/2}:{x:(o.x+a.x)/2,y:(o.y+a.y)/2},w=i?.fitLabelsToShape!==!1,b=i?.labelMaxTextWidth??(w?Math.max(48,Math.min(280,s*1.6)):1/0);ee(e,n.label,Math.round(y.x),Math.round(y.y),n.color,b,i)}}if(r.isSelected){let f=i?.handleRadius??5,y=i?.handleFillColor??"#ffffff",w=i?.endpointHandleColor??"#4f4f4f",b=i?.controlHandleColor??"#767676",I=i?.handleStrokeWidth??2;(n.arrowStyle==="curved"||n.arrowStyle==="elbow")&&(e.save(),e.beginPath(),e.setLineDash(i?.guideLineDash?[...i.guideLineDash]:[4,4]),e.moveTo(o.x,o.y),e.lineTo(l.x,l.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,l,b,y,f+.5,I)),X(e,o,w,y,f,I),X(e,a,w,y,f,I)}e.restore()}function Fe(e,t,n,r=11){return Math.hypot(e.x-t.end.x,e.y-t.end.y)<=r?"end":Math.hypot(e.x-t.start.x,e.y-t.start.y)<=r?"start":(n.arrowStyle==="curved"||n.arrowStyle==="elbow")&&Math.hypot(e.x-t.control.x,e.y-t.control.y)<=r?"control":null}function He(e,t,n,r=9){let o=Math.max(r,n.strokeWidth/2+6);if(n.arrowStyle==="curved")return ke(e,t.start,t.control,t.end)<=o;if(n.arrowStyle==="elbow"){let a={x:t.control.x,y:t.start.y},l={x:t.control.x,y:t.end.y};return j(e,t.start,a)<=o||j(e,a,l)<=o||j(e,l,t.end)<=o}return j(e,t.start,t.end)<=o}function ce(e,t){return t.points.map(n=>W(e,n))}function _e(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 r=1;r<t.length-1;r+=1){let o=(t[r].x+t[r+1].x)/2,a=(t[r].y+t[r+1].y)/2;e.quadraticCurveTo(t[r].x,t[r].y,o,a)}let n=t[t.length-1];e.lineTo(n.x,n.y)}function Te(e,t,n,r={}){if(t.length===0)return;let o=r.theme;e.save(),r.isPreview&&(e.globalAlpha=.9),r.isSelected&&(e.save(),e.beginPath(),_e(e,t),e.strokeStyle=o?.selectionGlowColor??"rgba(0, 0, 0, 0.2)",e.lineWidth=n.strokeWidth+(o?.selectionGlowWidth??6),e.lineCap="round",e.lineJoin="round",e.stroke(),e.restore()),e.save(),e.shadowColor=o?.shadowColor??"rgba(0, 0, 0, 0.2)",e.shadowBlur=o?.shadowBlur??3,e.shadowOffsetY=o?.shadowOffsetY??1,e.beginPath(),_e(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 Be(e,t,n,r=9){if(t.length===0)return!1;let o=Math.max(r,n.strokeWidth/2+6);if(t.length===1)return Math.hypot(e.x-t[0].x,e.y-t[0].y)<=o;let a=1/0,l=1/0,s=-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<l&&(l=u.y),u.x>s&&(s=u.x),u.y>i&&(i=u.y)}if(e.x<a-o||e.x>s+o||e.y<l-o||e.y>i+o)return!1;for(let d=0;d<t.length-1;d+=1)if(j(e,t[d],t[d+1])<=o)return!0;return!1}function be(e,t,n,r){let{minX:o,minY:a,maxX:l,maxY:s,width:i,height:d,cx:u,cy:p}=t;if(n==="square"){let h=r?.shapeBorderRadius??0;h>0&&typeof e.roundRect=="function"?e.roundRect(o,a,i,d,h):e.rect(o,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(l,s),e.lineTo(o,s),e.closePath();return}if(n==="diamond"){e.moveTo(u,a),e.lineTo(l,p),e.lineTo(u,s),e.lineTo(o,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 I=b%2===0?m:y,x=b%2===0?f:w,A=b*Math.PI/5-Math.PI/2,F=u+I*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,s),e.bezierCurveTo(o+i*.05,a+d*.7,o,a+d*.5,o,f),e.ellipse(u,f,h,m,0,Math.PI,0,!1),e.bezierCurveTo(l,a+d*.5,l-i*.05,a+d*.7,u,s),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,I=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-I,s),e.moveTo(u,y),e.lineTo(u+I,s)}}function ne(e,t){let n=W(e,t.start),r=W(e,t.end),o=Math.min(n.x,r.x),a=Math.min(n.y,r.y),l=Math.max(n.x,r.x),s=Math.max(n.y,r.y),i=Math.max(4,l-o),d=Math.max(4,s-a);return{start:n,end:r,minX:o,minY:a,maxX:l,maxY:s,width:i,height:d,cx:o+i/2,cy:a+d/2}}function Pe(e,t,n,r={}){if(t.width<4&&t.height<4)return;let o=r.theme;if(e.save(),r.isPreview&&(e.globalAlpha=.85),r.isSelected&&(e.save(),e.beginPath(),be(e,t,n.shape,o),e.strokeStyle=o?.selectionGlowColor??"rgba(0, 0, 0, 0.2)",e.lineWidth=n.strokeWidth+(o?.selectionGlowWidth??6),e.lineCap="round",e.lineJoin="round",e.stroke(),e.restore()),e.save(),e.shadowColor=o?.shadowColor??"rgba(0, 0, 0, 0.2)",e.shadowBlur=o?.shadowBlur??3,e.shadowOffsetY=o?.shadowOffsetY??1.5,e.beginPath(),be(e,t,n.shape,o),n.filled){let a=o?.shapeDefaultFillOpacity??.16,l=Math.round(Math.min(1,Math.max(0,a))*255).toString(16).padStart(2,"0");e.fillStyle=n.fillColor??`${n.color}${l}`,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 o?.labelMinShapeSize=="number"?o.labelMinShapeSize:18;if(a<=0||Math.max(t.width,t.height)>=a&&t.width>=8&&t.height>=8){let l=n.shape==="actor"?t.maxY+14:t.cy,s=o?.fitLabelsToShape!==!1,i=o?.labelMaxTextWidth??(s?Math.max(48,Math.min(280,t.width*2.2)):1/0);ee(e,n.label,Math.round(t.cx),Math.round(l),n.color,i,o)}}if(r.isSelected){let a=o?.handleRadius??5,l=o?.handleFillColor??"#ffffff",s=o?.endpointHandleColor??"#4f4f4f",i=o?.handleStrokeWidth??2;e.save(),e.setLineDash(o?.guideLineDash?[...o.guideLineDash]:[4,4]),e.strokeStyle=o?.guideLineColor??"rgba(100, 100, 100, 0.6)",e.lineWidth=o?.guideLineWidth??1.2,e.strokeRect(t.minX,t.minY,t.width,t.height),e.restore(),X(e,t.start,s,l,a,i),X(e,t.end,s,l,a,i)}e.restore()}function Ge(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 Ne(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 oe(e,t){let n=W(e,t.start),r=W(e,t.end),o={x:(n.x+r.x)/2,y:(n.y+r.y)/2},a=Math.hypot(r.x-n.x,r.y-n.y),l=Math.atan2(r.y-n.y,r.x-n.x);return{start:n,end:r,mid:o,lengthPx:a,angle:l}}function xe(e,t,n,r={}){let{start:o,end:a,mid:l,lengthPx:s,angle:i}=t;if(s<2)return;let d=r.theme;e.save(),r.isPreview&&(e.globalAlpha=.9),r.isSelected&&(e.save(),e.beginPath(),e.moveTo(o.x,o.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(o.x,o.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(o.x-h,o.y-m),e.lineTo(o.x+h,o.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:We(f,n.unit);if(y){let w=d?.fitLabelsToShape!==!1,b=d?.labelMaxTextWidth??(w?Math.max(50,Math.min(300,s*1.5)):1/0);ee(e,y,Math.round(l.x),Math.round(l.y),n.color,b,d)}if(r.isSelected){let w=d?.handleRadius??5,b=d?.handleFillColor??"#ffffff",I=d?.endpointHandleColor??"#4f4f4f",x=d?.handleStrokeWidth??2;X(e,o,I,b,w,x),X(e,a,I,b,w,x)}e.restore()}function Ye(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 je(e,t,n,r=9){let o=Math.max(r,n.strokeWidth/2+6);return j(e,t.start,t.end)<=o}function Bt(e){let t=q.find(r=>r.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 Gt(e,t,n,r,o,a=!0){let l=a!==!1?de(e):null;if(!l||o||!(t.x>=-120&&t.x<=l.width+120&&t.y>=-120&&t.y<=l.height+120))return t;let i=r?95:n.width??230,d=r?22:n.height??100,u=8,p=16+u,h=Math.max(p,l.width-i+16-u),m=12+u,f=Math.max(m,l.height-d+12-u);return{x:Math.max(p,Math.min(h,t.x)),y:Math.max(m,Math.min(f,t.y))}}function jt(e,t,n,r,o,a,l=!0){let s=l!==!1?de(e):null;if(!s||a||!(t.x>=-100&&t.x<=s.width+100&&t.y>=-100&&t.y<=s.height+100))return t;let d=o?35:Math.max(24,(n.text||"Text").length*r/3.6),u=o?11:r/2+4,p=8,h=d+p,m=Math.max(h,s.width-d-p),f=u+p,y=Math.max(f,s.height-u-p);return{x:Math.max(h,Math.min(m,t.x)),y:Math.max(f,Math.min(y,t.y))}}function ve(e,t,n,r,o,a,l,s,i,d,u,p){s.current={screenPoints:[n],geoPoints:[r]},e.dragging.disable(),d();let h=f=>{if(!s.current)return;let y=t.getBoundingClientRect(),w={x:f.clientX-y.left,y:f.clientY-y.top},b=s.current.screenPoints,I=b[b.length-1];Math.hypot(w.x-I.x,w.y-I.y)<2.5||(b.push(w),s.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=s.current;s.current=null,y&&y.geoPoints.length>=1?(u({id:K("freedraw"),type:"freedraw",points:y.geoPoints,color:o,strokeWidth:a,dashed:l,createdAt:Date.now()}),f.shiftKey||p("select")):d()};window.addEventListener("pointermove",h),window.addEventListener("pointerup",m)}function Xe(e,t,n="Field Note"){let r=q.find(o=>o.bg===t)??q[0];return{id:K("note"),type:"note",position:e,title:n,text:"",backgroundColor:r.bg,textColor:r.text,width:230,createdAt:Date.now()}}function ze(e,t,n,r,o){return{id:K("text"),type:"text",position:e,text:"",color:t,initialFontSize:n,baseZoom:o,fontWeight:r,createdAt:Date.now()}}function Ke(e,t,n,r,o,a,l,s,i,d,u,p){d({shape:o,startGeo:r,currentGeo:r}),e.dragging.disable();let h=f=>{let y=t.getBoundingClientRect(),w={x:f.clientX-y.left,y:f.clientY-y.top},b=f.shiftKey?re(n,w,1):w;d({shape:o,startGeo:r,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?re(n,w,1):w,I=Math.hypot(w.x-n.x,w.y-n.y),x=I>=10?r:L(e,{x:n.x-45,y:n.y-45}),A=I>=10?L(e,b):L(e,{x:n.x+45,y:n.y+45});u({id:K("shape"),type:"shape",shape:o,start:x,end:A,color:a,filled:l,strokeWidth:s,dashed:i,createdAt:Date.now()}),d(null),p("select")};window.addEventListener("pointermove",h),window.addEventListener("pointerup",m)}function Me(e,t,n,r,o,a){return{id:K("arrow"),type:"arrow",arrowStyle:e,start:t,end:n,controlPoint:e==="curved"?le(t,n):e==="elbow"?{lat:(t.lat+n.lat)/2,lng:(t.lng+n.lng)/2}:void 0,color:r,strokeWidth:o,dashed:a,headStyle:e==="bi"?"both":"triangle",createdAt:Date.now()}}function Ue(e,t,n,r,o,a,l,s,i,d,u){i({arrowStyle:o,startGeo:r,currentGeo:r}),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:o,startGeo:r,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(Me(o,r,L(e,w),a,l,s)),i(null),u("select"))};window.addEventListener("pointermove",p),window.addEventListener("pointerup",h)}function dt(e,t,n,r,o){return{id:K("ruler"),type:"ruler",start:e,end:t,color:n,strokeWidth:r,dashed:o,unit:"metric",createdAt:Date.now()}}function Je(e,t,n,r,o,a,l,s,i,d){s({startGeo:r,currentGeo:r}),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;s({startGeo:r,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(r,L(e,y),o,a,l)),s(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 $e(e,t,n,r,o,a){Z(e,l=>{let s=o(l),i=l.shiftKey;if(r==="start"){let d=i?B(n.end,s):s;a(t.id,{start:L(e,d)})}else if(r==="end"){let d=i?B(n.start,s):s;a(t.id,{end:L(e,d)})}else r==="control"&&a(t.id,{controlPoint:L(e,s)})})}function qe(e,t,n,r,o,a){let l=r==="start"?n.end:n.start,s=n.width>4&&n.height>4?n.width/n.height:1;Z(e,i=>{let d=o(i),u=i.shiftKey?re(l,d,s):d,p=L(e,u);a(t.id,r==="start"?{start:p}:{end:p})})}function Ze(e,t,n,r,o,a){let l=n.start,s=n.end,i=n.control,d=!!t.controlPoint;Z(e,u=>{let p=o(u),h=p.x-r.x,m=p.y-r.y,f={start:L(e,{x:l.x+h,y:l.y+m}),end:L(e,{x:s.x+h,y:s.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 Ve(e,t,n,r,o,a){let l=n.start,s=n.end;Z(e,i=>{let d=o(i),u=d.x-r.x,p=d.y-r.y;a(t.id,{start:L(e,{x:l.x+u,y:l.y+p}),end:L(e,{x:s.x+u,y:s.y+p})})})}function Qe(e,t,n,r,o,a){Z(e,l=>{let s=o(l),i=s.x-r.x,d=s.y-r.y;a(t.id,{points:n.map(u=>L(e,{x:u.x+i,y:u.y+d}))})})}function et(e,t,n,r,o,a){Z(e,l=>{let s=o(l),i=l.shiftKey;if(r==="start"){let d=i?B(n.end,s):s;a(t.id,{start:L(e,d)})}else if(r==="end"){let d=i?B(n.start,s):s;a(t.id,{end:L(e,d)})}})}function tt(e,t,n,r,o,a){let l=n.start,s=n.end;Z(e,i=>{let d=o(i),u=d.x-r.x,p=d.y-r.y;a(t.id,{start:L(e,{x:l.x+u,y:l.y+p}),end:L(e,{x:s.x+u,y:s.y+p})})})}function nt({map:e,canvas:t,width:n,height:r,arrowItems:o,shapeItems:a,freeDrawItems:l,rulerItems:s,selectedId:i,draftShape:d,draftArrow:u,draftRuler:p,draftFreeDraw:h,activeColor:m,strokeWidth:f,dashed:y,shapeFilled:w,annotationTheme:b,arrowTheme:I,isReadOnly:x}){if(!e||!t||n===0||r===0)return;let A=b??I,F=typeof window<"u"&&window.devicePixelRatio||1,O=Math.round(n*F),Y=Math.round(r*F);t.width!==O&&(t.width=O),t.height!==Y&&(t.height=Y);let M=t.getContext("2d");if(M){M.save(),typeof M.scale=="function"&&M.scale(F,F),M.clearRect(0,0,n,r);for(let P of l){let E=ce(e,P);Te(M,E,P,{isSelected:!x&&P.id===i,theme:A})}for(let P of a){let E=ne(e,P);Pe(M,E,P,{isSelected:!x&&P.id===i,theme:A})}for(let P of o){let E=te(e,P);we(M,E,P,{isSelected:!x&&P.id===i,theme:A})}for(let P of s){let E=oe(e,P);xe(M,E,P,{isSelected:!x&&P.id===i,theme:A})}if(!x&&h&&h.screenPoints.length>0&&Te(M,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(M,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(M,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=oe(e,P);xe(M,E,P,{isPreview:!0,isSelected:!0,theme:A})}M.restore()}}function ot(e,t){let n=()=>{let r=e.getSize();t({width:r.x,height:r.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 rt(e){let t=e.getContainer();if(!t)return()=>{};let n=o=>{let a=o.target;if(!a?.closest?.("[data-tual-overlay], input, textarea, select, button, .rlc-overlay"))return;let l=Object.prototype.hasOwnProperty.call(a,"_leaflet_disable_events"),s=a._leaflet_disable_events;a._leaflet_disable_events=!0;let i=!!e.doubleClickZoom?.enabled?.();i&&e.doubleClickZoom.disable(),setTimeout(()=>{l?a._leaflet_disable_events=s:delete a._leaflet_disable_events,i&&e.doubleClickZoom.enable()},0)},r=o=>{if(o.target?.closest?.("textarea, input, select, button, [data-tual-note-resize], .rlc-note-resize-handle")&&e.dragging?.enabled?.()){e.dragging.disable();let l=()=>{e.dragging.enable(),window.removeEventListener("mouseup",l,!0),window.removeEventListener("touchend",l,!0),window.removeEventListener("pointerup",l,!0)};window.addEventListener("mouseup",l,{capture:!0,once:!0}),window.addEventListener("touchend",l,{capture:!0,once:!0}),window.addEventListener("pointerup",l,{capture:!0,once:!0})}};return t.addEventListener("dblclick",n,!0),t.addEventListener("mousedown",r,!0),t.addEventListener("touchstart",r,!0),()=>{t.removeEventListener("dblclick",n,!0),t.removeEventListener("mousedown",r,!0),t.removeEventListener("touchstart",r,!0)}}function it(e={}){let t=Math.max(0,(e.maxHistory??50)-1),n=[],r=e.items??e.initialItems??[],o=[],a=r,l=e.initialTool??"select",s=!!(e.readOnly??!1),i=null,d=!1,u=e.defaultShape??"square",p=!0,h=e.defaultColor??De,m=e.defaultStrokeWidth??Ce,f=!1,y=e.defaultNoteColor??Ae,w=e.defaultFontSize??Ee,b="bold",I=new Set,x=()=>{for(let c of I)c(v)},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(r);return r=g,A(g),x(),g},Y=c=>{if(r===a)return;let g=a;a=r,n=[...n,g].slice(-t),o=[],F(r,c),x()},M=c=>{if(i!==c){let g=i;i=c,d=!1,g!==null&&c===null&&Y(),e.onItemSelect?.(r.find(R=>R.id===c)??null),x()}},P=c=>{s&&c!=="select"||(l=c,e.onToolChange?.(c),x())},E=c=>{s=!!c,s&&l!=="select"&&(l="select"),x()},G=(c,g)=>{i&&O(R=>R.map(z=>z.id===i&&c(z)?g(z):z))},ie=c=>{s||(u=c,G(g=>g.type==="shape",g=>({...g,shape:c})),x())},ae=c=>{s||(p=c,G(g=>g.type==="shape",g=>({...g,filled:c})),x())},ue=c=>{s||(h=c,G(g=>g.type!=="note",g=>({...g,color:c})),x())},fe=c=>{s||(m=c,G(g=>g.type==="arrow"||g.type==="freedraw"||g.type==="shape"||g.type==="ruler",g=>({...g,strokeWidth:c})),x())},he=c=>{s||(f=c,G(g=>g.type==="arrow"||g.type==="freedraw"||g.type==="shape"||g.type==="ruler",g=>({...g,dashed:c})),x())},S=c=>{if(s)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()},D=c=>{s||(w=c,G(g=>g.type==="text",g=>({...g,initialFontSize:c})),x())},C=c=>{s||(b=c,G(g=>g.type==="text",g=>({...g,fontWeight:c})),x())},k=c=>{d=c,x()},U=c=>{s||(O(g=>[...g,c]),M(c.id),e.onItemCreate?.(c))},J=(c,g)=>{if(s){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=>{s||(O(g=>g.filter(R=>R.id!==c)),i===c&&M(null),e.onItemDelete?.(c),Y())},N=()=>{!s&&i&&H(i)},_=()=>{s||(O(()=>[]),M(null),Y())},v={get items(){return r},get activeTool(){return l},setActiveTool:P,get readOnly(){return s},setReadOnly:E,get activeShape(){return u},setActiveShape:ie,get shapeFilled(){return p},setShapeFilled:ae,get selectedId(){return i},setSelectedId:M,get selectedItem(){return r.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:D,get fontWeight(){return b},setFontWeight:C,addItem:U,updateItem:J,removeItem:H,deleteSelected:N,clearAll:_,clear:_,deleteItem:H,setTool:P,selectItem:M,undo:()=>{if(s||n.length===0)return;let c=n[n.length-1];o=[r,...o],n=n.slice(0,-1),r=c,a=c,A(c),F(c,null),x()},redo:()=>{if(s||o.length===0)return;let c=o[0];n=[...n,r],o=o.slice(1),r=c,a=c,A(c),F(c,null),x()},get canUndo(){return!s&&n.length>0},get canRedo(){return!s&&o.length>0},notifyChangeComplete:Y,exportJSON:()=>JSON.stringify(r,null,2),importJSON:c=>{if(s)return!1;try{let g=JSON.parse(c);return Array.isArray(g)?(O(()=>g),M(null),Y(),!0):!1}catch{return!1}},subscribe(c){return I.add(c),()=>{I.delete(c)}},getState(){return v},destroy(){I.clear()}};return v}function un(e,t={}){let{controller:n,annotationTheme:r,arrowTheme:o,labels:a,zIndex:l=650,...s}=t,i=n??it(s),d=e.getContainer(),u=document.createElement("div");u.setAttribute("data-tual-overlay","true"),u.style.position="absolute",u.style.inset="0",u.style.pointerEvents="none",u.style.zIndex=String(l),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},I={current:null},x=S=>{f=S,M()},A=S=>{y=S,M()},F=S=>{w=S,M()},O=()=>{b.current=null,I.current!==null&&typeof window<"u"&&(window.cancelAnimationFrame(I.current),I.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`},M=()=>{Y();let S=i.items;nt({map:e,canvas:p,width:m.width,height:m.height,arrowItems:S.filter(D=>D.type==="arrow"),shapeItems:S.filter(D=>D.type==="shape"),freeDrawItems:S.filter(D=>D.type==="freedraw"),rulerItems:S.filter(D=>D.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:r,arrowTheme:o,isReadOnly:i.readOnly})},P=S=>{let D=d.getBoundingClientRect();return{x:S.clientX-D.left,y:S.clientY-D.top}},E=S=>{if(S.button!==0||i.readOnly)return;S.stopPropagation(),S.preventDefault();let D=P(S),C=L(e,D),{activeTool:k,activeShape:U,shapeFilled:J,activeColor:H,strokeWidth:N,dashed:_,noteColor:$,fontSize:V,fontWeight:Q}=i;if(k==="freedraw"){ve(e,d,D,C,H,N,_,b,I,M,i.addItem,i.setActiveTool);return}if(k==="shape"){Ke(e,d,D,C,U,H,J,N,_,A,i.addItem,i.setActiveTool);return}if(k==="note"){i.addItem(Xe(C,$,a?.noteDefaultTitle??"Field Note")),i.setActiveTool("select");return}if(k==="text"){i.addItem(ze(C,H,V,Q,e.getZoom?.()??14)),i.setActiveTool("select");return}if(k==="ruler"){Je(e,d,D,C,H,N,_,F,i.addItem,i.setActiveTool);return}let T=Ie[k];if(T)if(!f)Ue(e,d,D,C,T,H,N,_,x,i.addItem,i.setActiveTool);else{let v=W(e,f.startGeo),c=S.shiftKey?B(v,D):D;Math.hypot(c.x-v.x,c.y-v.y)>=4&&i.addItem(Me(f.arrowStyle,f.startGeo,L(e,c),H,N,_)),x(null),i.setActiveTool("select")}},G=S=>{if(!f)return;let D=P(S),C=W(e,f.startGeo),k=S.shiftKey?B(C,D):D;x({...f,currentGeo:L(e,k)})},ie=S=>{if(S.button!==0||i.readOnly||i.activeTool!=="select"||S.target?.closest("[data-tual-toolbar], [data-tual-note], [data-tual-text], .leaflet-control"))return;let C=P(S),k=i.items,U=k.filter(T=>T.type==="arrow"),J=k.filter(T=>T.type==="shape"),H=k.filter(T=>T.type==="freedraw"),N=k.filter(T=>T.type==="ruler"),_=i.selectedId,$=U.find(T=>T.id===_);if($){let T=te(e,$),v=Fe(C,T,$);if(v){S.stopPropagation(),S.preventDefault(),$e(e,$,T,v,P,i.updateItem);return}}let V=J.find(T=>T.id===_);if(V){let T=ne(e,V),v=Ge(C,T);if(v){S.stopPropagation(),S.preventDefault(),qe(e,V,T,v,P,i.updateItem);return}}let Q=N.find(T=>T.id===_);if(Q){let T=oe(e,Q),v=Ye(C,T);if(v){S.stopPropagation(),S.preventDefault(),et(e,Q,T,v,P,i.updateItem);return}}for(let T=U.length-1;T>=0;T-=1){let v=U[T],c=te(e,v);if(He(C,c,v)){S.stopPropagation(),S.preventDefault(),i.setSelectedId(v.id),Ze(e,v,c,C,P,i.updateItem);return}}for(let T=J.length-1;T>=0;T-=1){let v=J[T],c=ne(e,v);if(Ne(C,c)){S.stopPropagation(),S.preventDefault(),i.setSelectedId(v.id),Ve(e,v,c,C,P,i.updateItem);return}}for(let T=H.length-1;T>=0;T-=1){let v=H[T],c=ce(e,v);if(Be(C,c,v)){S.stopPropagation(),S.preventDefault(),i.setSelectedId(v.id),Qe(e,v,c,C,P,i.updateItem);return}}for(let T=N.length-1;T>=0;T-=1){let v=N[T],c=oe(e,v);if(je(C,c,v)){S.stopPropagation(),S.preventDefault(),i.setSelectedId(v.id),tt(e,v,c,C,P,i.updateItem);return}}_&&(i.setSelectedId(null),i.notifyChangeComplete())},ae=S=>{if(i.readOnly)return;let D=S.target;D&&(D.tagName==="INPUT"||D.tagName==="TEXTAREA"||D.isContentEditable)||(S.key==="Escape"?(f=null,y=null,w=null,O(),i.setSelectedId(null),i.setActiveTool("select"),i.notifyChangeComplete(),M()):(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,M()}),fe=rt(e),he=i.subscribe(()=>{M()});return M(),{controller:i,container:u,canvas:p,repaint:M,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 mn=Le.version;export{yt as DEFAULT_ANNOTATION_THEME,Ee as DEFAULT_FONT_SIZE,st as DEFAULT_FONT_SIZE_OPTIONS,Ae as DEFAULT_NOTE_BG,ht as DEFAULT_NOTE_TEXT,De as DEFAULT_STROKE_COLOR,Ce as DEFAULT_STROKE_WIDTH,lt as DEFAULT_STROKE_WIDTH_OPTIONS,mt as FONT_SIZE_OPTIONS,q as NOTE_COLOR_THEMES,ut as STROKE_COLORS,ft as STROKE_WIDTH_OPTIONS,Ie as TOOL_TO_ARROW_STYLE,mn as VERSION,rt as bindBlockMapDblClick,ot as bindLeafletSync,Me as buildArrowItem,dt as buildRulerItem,pe as calculateGeodesicDistance,St as calculateLineDistance,gt as calculateZoomFontSize,Gt as clampNotePosition,jt as clampTextPosition,le as computeDefaultControlGeoPoint,B as constrainAngleTo45Degrees,re as constrainToAspectRatio,Xe as createDraftNote,ze as createDraftText,K as createId,un as createLeafletTual,it as createLeafletTualController,ke as distanceToQuadraticBezier,j as distanceToSegment,ge as drawArrowHead,X as drawTualHandle,ee as drawTualLabelPill,We as formatRealWorldDistance,W as geoToScreen,de as getMapDimensions,ye as getQuadraticBezierPoint,se as getQuadraticEndAngle,He as hitTestArrow,Fe as hitTestArrowHandle,Be as hitTestFreeDraw,je as hitTestRuler,Ye as hitTestRulerHandle,Ne as hitTestShape,Ge as hitTestShapeHandle,nt as paintLeafletTual,te as projectArrow,ce as projectFreeDraw,oe as projectRuler,ne as projectShape,we as renderArrowOnCanvas,Te as renderFreeDrawOnCanvas,xe as renderRulerOnCanvas,Pe as renderShapeOnCanvas,Bt as resolveNoteTheme,L as screenToGeo,Ze as startArrowBodyDrag,Ue as startArrowDrag,$e as startArrowHandleDrag,Qe as startFreeDrawBodyDrag,ve as startFreeDrawDrag,tt as startRulerBodyDrag,Je as startRulerDrag,et as startRulerHandleDrag,Ve as startShapeBodyDrag,Ke as startShapeDrag,qe as startShapeHandleDrag,Se as traceArrowPath,be as tracePolygonShape,Oe as truncateTualText};
|
|
2
|
+
//# sourceMappingURL=index.js.map
|