@sindicum/libre-draw 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.
- package/LICENSE +21 -0
- package/README.md +149 -0
- package/dist/LibreDraw.d.ts +359 -0
- package/dist/core/EventBus.d.ts +37 -0
- package/dist/core/FeatureStore.d.ts +68 -0
- package/dist/core/HistoryManager.d.ts +47 -0
- package/dist/core/ModeManager.d.ts +44 -0
- package/dist/core/errors.d.ts +6 -0
- package/dist/index.d.ts +7 -0
- package/dist/input/InputHandler.d.ts +29 -0
- package/dist/input/KeyboardInput.d.ts +31 -0
- package/dist/input/MouseInput.d.ts +41 -0
- package/dist/input/TouchInput.d.ts +58 -0
- package/dist/libre-draw.cjs +2 -0
- package/dist/libre-draw.cjs.map +1 -0
- package/dist/libre-draw.js +2116 -0
- package/dist/libre-draw.js.map +1 -0
- package/dist/modes/DrawMode.d.ts +70 -0
- package/dist/modes/IdleMode.d.ts +16 -0
- package/dist/modes/Mode.d.ts +26 -0
- package/dist/modes/SelectMode.d.ts +158 -0
- package/dist/rendering/RenderManager.d.ts +80 -0
- package/dist/rendering/SourceManager.d.ts +52 -0
- package/dist/types/events.d.ts +43 -0
- package/dist/types/features.d.ts +80 -0
- package/dist/types/index.d.ts +5 -0
- package/dist/types/input.d.ts +23 -0
- package/dist/types/options.d.ts +30 -0
- package/dist/ui/Toolbar.d.ts +59 -0
- package/dist/ui/ToolbarButton.d.ts +53 -0
- package/dist/ui/icons/delete.d.ts +4 -0
- package/dist/ui/icons/draw.d.ts +4 -0
- package/dist/ui/icons/redo.d.ts +4 -0
- package/dist/ui/icons/select.d.ts +4 -0
- package/dist/ui/icons/undo.d.ts +4 -0
- package/dist/validation/geojson.d.ts +20 -0
- package/dist/validation/intersection.d.ts +28 -0
- package/package.json +76 -0
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { Mode } from '../modes/Mode';
|
|
2
|
+
/**
|
|
3
|
+
* The available drawing modes.
|
|
4
|
+
*/
|
|
5
|
+
export type ModeName = 'idle' | 'draw' | 'select';
|
|
6
|
+
/**
|
|
7
|
+
* Manages the active drawing mode and handles transitions between modes.
|
|
8
|
+
*
|
|
9
|
+
* When switching modes, the current mode is deactivated and the new mode
|
|
10
|
+
* is activated. A callback is invoked on mode changes so the LibreDraw
|
|
11
|
+
* facade can emit the appropriate event.
|
|
12
|
+
*/
|
|
13
|
+
export declare class ModeManager {
|
|
14
|
+
private modes;
|
|
15
|
+
private currentModeName;
|
|
16
|
+
private onModeChange?;
|
|
17
|
+
/**
|
|
18
|
+
* Register a mode implementation.
|
|
19
|
+
* @param name - The mode name.
|
|
20
|
+
* @param mode - The mode implementation.
|
|
21
|
+
*/
|
|
22
|
+
registerMode(name: ModeName, mode: Mode): void;
|
|
23
|
+
/**
|
|
24
|
+
* Set a callback to be invoked on mode changes.
|
|
25
|
+
* @param callback - The callback receiving (newMode, previousMode).
|
|
26
|
+
*/
|
|
27
|
+
setOnModeChange(callback: (mode: ModeName, previousMode: ModeName) => void): void;
|
|
28
|
+
/**
|
|
29
|
+
* Switch to a new mode.
|
|
30
|
+
* Deactivates the current mode and activates the new one.
|
|
31
|
+
* @param name - The mode to switch to.
|
|
32
|
+
*/
|
|
33
|
+
setMode(name: ModeName): void;
|
|
34
|
+
/**
|
|
35
|
+
* Get the current mode name.
|
|
36
|
+
* @returns The active mode name.
|
|
37
|
+
*/
|
|
38
|
+
getMode(): ModeName;
|
|
39
|
+
/**
|
|
40
|
+
* Get the current mode implementation.
|
|
41
|
+
* @returns The active Mode object, or undefined.
|
|
42
|
+
*/
|
|
43
|
+
getCurrentMode(): Mode | undefined;
|
|
44
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { LibreDraw } from './LibreDraw';
|
|
2
|
+
export type { Position, PolygonGeometry, FeatureProperties, LibreDrawFeature, ActionType, Action, } from './types';
|
|
3
|
+
export type { LibreDrawEventMap, CreateEvent, UpdateEvent, DeleteEvent, SelectionChangeEvent, ModeChangeEvent, } from './types';
|
|
4
|
+
export type { LibreDrawOptions, ToolbarOptions, ToolbarPosition, ToolbarControls, } from './types';
|
|
5
|
+
export type { NormalizedInputEvent, InputType, } from './types';
|
|
6
|
+
export type { ModeName } from './core/ModeManager';
|
|
7
|
+
export { LibreDrawError } from './core/errors';
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { Map as MaplibreMap } from 'maplibre-gl';
|
|
2
|
+
import type { Mode } from '../modes/Mode';
|
|
3
|
+
/**
|
|
4
|
+
* Callback to retrieve the currently active mode.
|
|
5
|
+
*/
|
|
6
|
+
export type GetActiveModeCallback = () => Mode | undefined;
|
|
7
|
+
/**
|
|
8
|
+
* Orchestrates all input handlers (mouse, touch, keyboard) and
|
|
9
|
+
* dispatches events to the currently active drawing mode.
|
|
10
|
+
*/
|
|
11
|
+
export declare class InputHandler {
|
|
12
|
+
private mouseInput;
|
|
13
|
+
private touchInput;
|
|
14
|
+
private keyboardInput;
|
|
15
|
+
private getActiveMode;
|
|
16
|
+
constructor(map: MaplibreMap, getActiveMode: GetActiveModeCallback);
|
|
17
|
+
/**
|
|
18
|
+
* Enable all input handlers.
|
|
19
|
+
*/
|
|
20
|
+
enable(): void;
|
|
21
|
+
/**
|
|
22
|
+
* Disable all input handlers.
|
|
23
|
+
*/
|
|
24
|
+
disable(): void;
|
|
25
|
+
/**
|
|
26
|
+
* Destroy all input handlers and remove event listeners.
|
|
27
|
+
*/
|
|
28
|
+
destroy(): void;
|
|
29
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Callback for keyboard key events.
|
|
3
|
+
*/
|
|
4
|
+
export interface KeyboardInputCallbacks {
|
|
5
|
+
onKeyDown(key: string, event: KeyboardEvent): void;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Handles keyboard input events for the drawing interface.
|
|
9
|
+
*
|
|
10
|
+
* Listens for key events on the document and dispatches
|
|
11
|
+
* relevant keys (Escape, Delete, Backspace) to the active mode.
|
|
12
|
+
*/
|
|
13
|
+
export declare class KeyboardInput {
|
|
14
|
+
private callbacks;
|
|
15
|
+
/** The set of keys that this handler cares about. */
|
|
16
|
+
private static readonly RELEVANT_KEYS;
|
|
17
|
+
private handleKeyDown;
|
|
18
|
+
constructor(callbacks: KeyboardInputCallbacks);
|
|
19
|
+
/**
|
|
20
|
+
* Start listening for keyboard events.
|
|
21
|
+
*/
|
|
22
|
+
enable(): void;
|
|
23
|
+
/**
|
|
24
|
+
* Stop listening for keyboard events.
|
|
25
|
+
*/
|
|
26
|
+
disable(): void;
|
|
27
|
+
/**
|
|
28
|
+
* Destroy the keyboard input handler and remove all listeners.
|
|
29
|
+
*/
|
|
30
|
+
destroy(): void;
|
|
31
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { Map as MaplibreMap } from 'maplibre-gl';
|
|
2
|
+
import type { NormalizedInputEvent } from '../types/input';
|
|
3
|
+
/**
|
|
4
|
+
* Callbacks that MouseInput dispatches to.
|
|
5
|
+
*/
|
|
6
|
+
export interface MouseInputCallbacks {
|
|
7
|
+
onPointerDown(event: NormalizedInputEvent): void;
|
|
8
|
+
onPointerMove(event: NormalizedInputEvent): void;
|
|
9
|
+
onPointerUp(event: NormalizedInputEvent): void;
|
|
10
|
+
onDoubleClick(event: NormalizedInputEvent): void;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Handles mouse input events on the map canvas and converts them
|
|
14
|
+
* to normalized input events.
|
|
15
|
+
*/
|
|
16
|
+
export declare class MouseInput {
|
|
17
|
+
private map;
|
|
18
|
+
private callbacks;
|
|
19
|
+
private canvas;
|
|
20
|
+
private handleMouseDown;
|
|
21
|
+
private handleMouseMove;
|
|
22
|
+
private handleMouseUp;
|
|
23
|
+
private handleDblClick;
|
|
24
|
+
constructor(map: MaplibreMap, callbacks: MouseInputCallbacks);
|
|
25
|
+
/**
|
|
26
|
+
* Start listening for mouse events on the map canvas.
|
|
27
|
+
*/
|
|
28
|
+
enable(): void;
|
|
29
|
+
/**
|
|
30
|
+
* Stop listening for mouse events.
|
|
31
|
+
*/
|
|
32
|
+
disable(): void;
|
|
33
|
+
/**
|
|
34
|
+
* Destroy the mouse input handler and remove all listeners.
|
|
35
|
+
*/
|
|
36
|
+
destroy(): void;
|
|
37
|
+
/**
|
|
38
|
+
* Convert a raw MouseEvent into a NormalizedInputEvent.
|
|
39
|
+
*/
|
|
40
|
+
private normalize;
|
|
41
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import type { Map as MaplibreMap } from 'maplibre-gl';
|
|
2
|
+
import type { NormalizedInputEvent } from '../types/input';
|
|
3
|
+
/**
|
|
4
|
+
* Callbacks that TouchInput dispatches to.
|
|
5
|
+
*/
|
|
6
|
+
export interface TouchInputCallbacks {
|
|
7
|
+
onPointerDown(event: NormalizedInputEvent): void;
|
|
8
|
+
onPointerMove(event: NormalizedInputEvent): void;
|
|
9
|
+
onPointerUp(event: NormalizedInputEvent): void;
|
|
10
|
+
onDoubleClick(event: NormalizedInputEvent): void;
|
|
11
|
+
onLongPress(event: NormalizedInputEvent): void;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Handles touch input events on the map canvas.
|
|
15
|
+
*
|
|
16
|
+
* Provides gesture detection for:
|
|
17
|
+
* - Double tap (within 300ms)
|
|
18
|
+
* - Long press (hold for 500ms)
|
|
19
|
+
* - Pinch detection (2+ fingers, passes through to map)
|
|
20
|
+
*/
|
|
21
|
+
export declare class TouchInput {
|
|
22
|
+
private map;
|
|
23
|
+
private callbacks;
|
|
24
|
+
private canvas;
|
|
25
|
+
private lastTapTime;
|
|
26
|
+
private longPressTimer;
|
|
27
|
+
private touchStartPos;
|
|
28
|
+
private isPinching;
|
|
29
|
+
private handleTouchStart;
|
|
30
|
+
private handleTouchMove;
|
|
31
|
+
private handleTouchEnd;
|
|
32
|
+
constructor(map: MaplibreMap, callbacks: TouchInputCallbacks);
|
|
33
|
+
/**
|
|
34
|
+
* Start listening for touch events on the map canvas.
|
|
35
|
+
*/
|
|
36
|
+
enable(): void;
|
|
37
|
+
/**
|
|
38
|
+
* Stop listening for touch events.
|
|
39
|
+
*/
|
|
40
|
+
disable(): void;
|
|
41
|
+
/**
|
|
42
|
+
* Destroy the touch input handler and remove all listeners.
|
|
43
|
+
*/
|
|
44
|
+
destroy(): void;
|
|
45
|
+
/**
|
|
46
|
+
* Cancel the long press detection timer.
|
|
47
|
+
*/
|
|
48
|
+
private cancelLongPress;
|
|
49
|
+
/**
|
|
50
|
+
* Convert a TouchEvent into a NormalizedInputEvent using the first touch.
|
|
51
|
+
*/
|
|
52
|
+
private normalize;
|
|
53
|
+
/**
|
|
54
|
+
* Convert a TouchEvent into a NormalizedInputEvent using changedTouches
|
|
55
|
+
* (for touchend events where touches array is empty).
|
|
56
|
+
*/
|
|
57
|
+
private normalizeChangedTouch;
|
|
58
|
+
}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});class ue{constructor(e){this.feature=e,this.type="create"}apply(e){e.add(this.feature)}revert(e){e.remove(this.feature.id)}}class ${constructor(e,t,s){this.id=e,this.oldFeature=t,this.newFeature=s,this.type="update"}apply(e){e.update(this.id,this.newFeature)}revert(e){e.update(this.id,this.oldFeature)}}class oe{constructor(e){this.feature=e,this.type="delete"}apply(e){e.remove(this.feature.id)}revert(e){e.add(this.feature)}}class ge{constructor(){this.listeners=new Map}on(e,t){let s=this.listeners.get(e);s||(s=new Set,this.listeners.set(e,s)),s.add(t)}off(e,t){const s=this.listeners.get(e);s&&s.delete(t)}emit(e,t){const s=this.listeners.get(e);if(s)for(const i of s)i(t)}removeAllListeners(){this.listeners.clear()}}class R{constructor(){this.features=new Map}add(e){const t=e.id||crypto.randomUUID(),s={...e,id:t};return this.features.set(t,s),s}update(e,t){this.features.has(e)&&this.features.set(e,{...t,id:e})}remove(e){const t=this.features.get(e);return t&&this.features.delete(e),t}getAll(){return Array.from(this.features.values())}getById(e){return this.features.get(e)}clear(){this.features.clear()}setAll(e){this.features.clear();for(const t of e){const s=t.id||crypto.randomUUID();this.features.set(s,{...t,id:s})}}toGeoJSON(){return{type:"FeatureCollection",features:this.getAll()}}static cloneFeature(e){return{id:e.id,type:"Feature",geometry:{type:"Polygon",coordinates:e.geometry.coordinates.map(t=>t.map(s=>[...s]))},properties:{...e.properties}}}}class fe{constructor(e=100){this.undoStack=[],this.redoStack=[],this.limit=e}push(e){this.undoStack.push(e),this.redoStack=[],this.undoStack.length>this.limit&&this.undoStack.shift()}undo(e){const t=this.undoStack.pop();return t?(t.revert(e),this.redoStack.push(t),!0):!1}redo(e){const t=this.redoStack.pop();return t?(t.apply(e),this.undoStack.push(t),!0):!1}canUndo(){return this.undoStack.length>0}canRedo(){return this.redoStack.length>0}clear(){this.undoStack=[],this.redoStack=[]}}class pe{constructor(){this.modes=new Map,this.currentModeName="idle"}registerMode(e,t){this.modes.set(e,t)}setOnModeChange(e){this.onModeChange=e}setMode(e){if(e===this.currentModeName)return;const t=this.currentModeName,s=this.modes.get(this.currentModeName);s&&s.deactivate(),this.currentModeName=e;const i=this.modes.get(e);i&&i.activate(),this.onModeChange&&this.onModeChange(e,t)}getMode(){return this.currentModeName}getCurrentMode(){return this.modes.get(this.currentModeName)}}class v extends Error{constructor(e){super(e),this.name="LibreDrawError"}}function z(r,e,t){const s=(e[1]-r[1])*(t[0]-e[0])-(e[0]-r[0])*(t[1]-e[1]);return Math.abs(s)<1e-10?0:s>0?1:2}function j(r,e,t){return e[0]<=Math.max(r[0],t[0])&&e[0]>=Math.min(r[0],t[0])&&e[1]<=Math.max(r[1],t[1])&&e[1]>=Math.min(r[1],t[1])}function X(r,e){return Math.abs(r[0]-e[0])<1e-10&&Math.abs(r[1]-e[1])<1e-10}function q(r,e,t,s){if(X(r,t)||X(r,s)||X(e,t)||X(e,s))return!1;const i=z(r,e,t),n=z(r,e,s),o=z(t,s,r),l=z(t,s,e);return!!(i!==n&&o!==l||i===0&&j(r,t,e)||n===0&&j(r,s,e)||o===0&&j(t,r,s)||l===0&&j(t,e,s))}function ae(r){const e=r.length-1;if(e<3)return!1;for(let t=0;t<e;t++)for(let s=t+2;s<e;s++)if(!(t===0&&s===e-1)&&q(r[t],r[t+1],r[s],r[s+1]))return!0;return!1}function ye(r,e){if(r.length<2)return!1;const t=r[r.length-1];for(let s=0;s<r.length-2;s++)if(q(t,e,r[s],r[s+1]))return!0;return!1}function J(r){if(r.length<3)return!1;const e=r[0],t=r[r.length-1];for(let s=1;s<r.length-2;s++)if(q(t,e,r[s],r[s+1]))return!0;return!1}function me(r,e){return r[0]===e[0]&&r[1]===e[1]}function be(r){const[e,t]=r;if(typeof e!="number"||typeof t!="number")throw new v(`Invalid coordinate: expected [number, number], got [${typeof e}, ${typeof t}]`);if(e<-180||e>180)throw new v(`Invalid longitude: ${e}. Must be between -180 and 180.`);if(t<-90||t>90)throw new v(`Invalid latitude: ${t}. Must be between -90 and 90.`)}function ve(r){if(!Array.isArray(r))throw new v("Ring must be an array of positions.");if(r.length<4)throw new v(`Ring must have at least 4 positions (got ${r.length}). A valid polygon ring requires 3 unique vertices plus a closing vertex.`);const e=r[0],t=r[r.length-1];if(!me(e,t))throw new v("Ring is not closed. The first and last positions must be identical.");for(const s of r){if(!Array.isArray(s)||s.length<2)throw new v("Each position in a ring must be an array of at least 2 numbers.");be(s)}if(ae(r))throw new v("Ring has self-intersections. Polygon edges must not cross each other.")}function le(r){if(r==null||typeof r!="object")throw new v("Feature must be a non-null object.");const e=r;if(e.type!=="Feature")throw new v(`Feature.type must be "Feature", got "${String(e.type)}".`);if(e.geometry===null||e.geometry===void 0||typeof e.geometry!="object")throw new v("Feature.geometry must be a non-null object.");const t=e.geometry;if(t.type!=="Polygon")throw new v(`Feature.geometry.type must be "Polygon", got "${String(t.type)}".`);if(!Array.isArray(t.coordinates))throw new v("Feature.geometry.coordinates must be an array.");const s=t.coordinates;if(s.length===0)throw new v("Polygon must have at least one ring (outer ring).");for(const i of s)ve(i);return r}function Ee(r){if(r==null||typeof r!="object")throw new v("GeoJSON must be a non-null object.");const e=r;if(e.type!=="FeatureCollection")throw new v(`GeoJSON.type must be "FeatureCollection", got "${String(e.type)}".`);if(!Array.isArray(e.features))throw new v("GeoJSON.features must be an array.");const t=r,s=[];for(let i=0;i<t.features.length;i++)try{s.push(le(t.features[i]))}catch(n){throw n instanceof v?new v(`Invalid feature at index ${i}: ${n.message}`):n}return{type:"FeatureCollection",features:s}}class Ie{activate(){}deactivate(){}onPointerDown(e){}onPointerMove(e){}onPointerUp(e){}onDoubleClick(e){}onLongPress(e){}onKeyDown(e,t){}}const we=10,W=3;class Se{constructor(e){this.vertices=[],this.isActive=!1,this.callbacks=e}activate(){this.isActive=!0,this.vertices=[]}deactivate(){this.isActive=!1,this.vertices=[],this.callbacks.clearPreview()}onPointerDown(e){if(!this.isActive)return;const t=[e.lngLat.lng,e.lngLat.lat];if(this.vertices.length>=W){const s=this.vertices[0],i=this.callbacks.getScreenPoint({lng:s[0],lat:s[1]}),n=e.point.x-i.x,o=e.point.y-i.y;if(Math.sqrt(n*n+o*o)<=we){if(J(this.vertices))return;this.finalizePolygon();return}}ye(this.vertices,t)||(this.vertices.push(t),this.updatePreview(e))}onPointerMove(e){!this.isActive||this.vertices.length===0||this.updatePreview(e)}onPointerUp(e){}onDoubleClick(e){this.isActive&&(this.vertices.length>W&&this.vertices.pop(),this.vertices.length>=W&&(J(this.vertices)||this.finalizePolygon()),e.originalEvent.preventDefault(),e.originalEvent.stopPropagation())}onLongPress(e){this.isActive&&this.vertices.length>0&&(this.vertices.pop(),this.vertices.length===0?this.callbacks.clearPreview():this.callbacks.renderPreview(this.buildPreviewCoordinates()))}onKeyDown(e,t){this.isActive&&e==="Escape"&&this.cancelDrawing()}buildPreviewCoordinates(e){const t=[...this.vertices];return e&&t.push(e),t.length>0&&t.push([...t[0]]),t}updatePreview(e){const t=[e.lngLat.lng,e.lngLat.lat],s=this.buildPreviewCoordinates(t);this.callbacks.renderPreview(s)}finalizePolygon(){if(this.vertices.length<W)return;const e=[...this.vertices,[...this.vertices[0]]],t={id:crypto.randomUUID(),type:"Feature",geometry:{type:"Polygon",coordinates:[e]},properties:{}},s=this.callbacks.addFeatureToStore(t),i=new ue(s);this.callbacks.pushToHistory(i),this.callbacks.emitEvent("create",{feature:s}),this.callbacks.renderFeatures(),this.vertices=[],this.callbacks.clearPreview()}cancelDrawing(){this.vertices=[],this.callbacks.clearPreview()}}const N=11102230246251565e-32,F=134217729,Te=(3+8*N)*N;function Y(r,e,t,s,i){let n,o,l,h,d=e[0],u=s[0],a=0,c=0;u>d==u>-d?(n=d,d=e[++a]):(n=u,u=s[++c]);let g=0;if(a<r&&c<t)for(u>d==u>-d?(o=d+n,l=n-(o-d),d=e[++a]):(o=u+n,l=n-(o-u),u=s[++c]),n=o,l!==0&&(i[g++]=l);a<r&&c<t;)u>d==u>-d?(o=n+d,h=o-n,l=n-(o-h)+(d-h),d=e[++a]):(o=n+u,h=o-n,l=n-(o-h)+(u-h),u=s[++c]),n=o,l!==0&&(i[g++]=l);for(;a<r;)o=n+d,h=o-n,l=n-(o-h)+(d-h),d=e[++a],n=o,l!==0&&(i[g++]=l);for(;c<t;)o=n+u,h=o-n,l=n-(o-h)+(u-h),u=s[++c],n=o,l!==0&&(i[g++]=l);return(n!==0||g===0)&&(i[g++]=n),g}function Me(r,e){let t=e[0];for(let s=1;s<r;s++)t+=e[s];return t}function H(r){return new Float64Array(r)}const Pe=(3+16*N)*N,ke=(2+12*N)*N,Fe=(9+64*N)*N*N,O=H(4),Q=H(8),Z=H(12),ee=H(16),D=H(4);function De(r,e,t,s,i,n,o){let l,h,d,u,a,c,g,y,p,m,f,b,T,I,M,P,C,k;const L=r-i,x=t-i,V=e-n,A=s-n;I=L*A,c=F*L,g=c-(c-L),y=L-g,c=F*A,p=c-(c-A),m=A-p,M=y*m-(I-g*p-y*p-g*m),P=V*x,c=F*V,g=c-(c-V),y=V-g,c=F*x,p=c-(c-x),m=x-p,C=y*m-(P-g*p-y*p-g*m),f=M-C,a=M-f,O[0]=M-(f+a)+(a-C),b=I+f,a=b-I,T=I-(b-a)+(f-a),f=T-P,a=T-f,O[1]=T-(f+a)+(a-P),k=b+f,a=k-b,O[2]=b-(k-a)+(f-a),O[3]=k;let _=Me(4,O),U=ke*o;if(_>=U||-_>=U||(a=r-L,l=r-(L+a)+(a-i),a=t-x,d=t-(x+a)+(a-i),a=e-V,h=e-(V+a)+(a-n),a=s-A,u=s-(A+a)+(a-n),l===0&&h===0&&d===0&&u===0)||(U=Fe*o+Te*Math.abs(_),_+=L*u+A*l-(V*d+x*h),_>=U||-_>=U))return _;I=l*A,c=F*l,g=c-(c-l),y=l-g,c=F*A,p=c-(c-A),m=A-p,M=y*m-(I-g*p-y*p-g*m),P=h*x,c=F*h,g=c-(c-h),y=h-g,c=F*x,p=c-(c-x),m=x-p,C=y*m-(P-g*p-y*p-g*m),f=M-C,a=M-f,D[0]=M-(f+a)+(a-C),b=I+f,a=b-I,T=I-(b-a)+(f-a),f=T-P,a=T-f,D[1]=T-(f+a)+(a-P),k=b+f,a=k-b,D[2]=b-(k-a)+(f-a),D[3]=k;const ce=Y(4,O,4,D,Q);I=L*u,c=F*L,g=c-(c-L),y=L-g,c=F*u,p=c-(c-u),m=u-p,M=y*m-(I-g*p-y*p-g*m),P=V*d,c=F*V,g=c-(c-V),y=V-g,c=F*d,p=c-(c-d),m=d-p,C=y*m-(P-g*p-y*p-g*m),f=M-C,a=M-f,D[0]=M-(f+a)+(a-C),b=I+f,a=b-I,T=I-(b-a)+(f-a),f=T-P,a=T-f,D[1]=T-(f+a)+(a-P),k=b+f,a=k-b,D[2]=b-(k-a)+(f-a),D[3]=k;const he=Y(ce,Q,4,D,Z);I=l*u,c=F*l,g=c-(c-l),y=l-g,c=F*u,p=c-(c-u),m=u-p,M=y*m-(I-g*p-y*p-g*m),P=h*d,c=F*h,g=c-(c-h),y=h-g,c=F*d,p=c-(c-d),m=d-p,C=y*m-(P-g*p-y*p-g*m),f=M-C,a=M-f,D[0]=M-(f+a)+(a-C),b=I+f,a=b-I,T=I-(b-a)+(f-a),f=T-P,a=T-f,D[1]=T-(f+a)+(a-P),k=b+f,a=k-b,D[2]=b-(k-a)+(f-a),D[3]=k;const de=Y(he,Z,4,D,ee);return ee[de-1]}function Ce(r,e,t,s,i,n){const o=(e-n)*(t-i),l=(r-i)*(s-n),h=o-l,d=Math.abs(o+l);return Math.abs(h)>=Pe*d?h:-De(r,e,t,s,i,n,d)}function Le(r,e){var t,s,i=0,n,o,l,h,d,u,a,c=r[0],g=r[1],y=e.length;for(t=0;t<y;t++){s=0;var p=e[t],m=p.length-1;if(u=p[0],u[0]!==p[m][0]&&u[1]!==p[m][1])throw new Error("First and last coordinates in a ring must be the same");for(o=u[0]-c,l=u[1]-g,s;s<m;s++){if(a=p[s+1],h=a[0]-c,d=a[1]-g,l===0&&d===0){if(h<=0&&o>=0||o<=0&&h>=0)return 0}else if(d>=0&&l<=0||d<=0&&l>=0){if(n=Ce(o,h,l,d,0,0),n===0)return 0;(n>0&&d>0&&l<=0||n<0&&d<=0&&l>0)&&i++}u=a,l=d,o=h}}return i%2!==0}function xe(r,e,t={}){const s={type:"Feature"};return(t.id===0||t.id)&&(s.id=t.id),t.bbox&&(s.bbox=t.bbox),s.properties={},s.geometry=r,s}function te(r,e,t={}){if(!r)throw new Error("coordinates is required");if(!Array.isArray(r))throw new Error("coordinates must be an Array");if(r.length<2)throw new Error("coordinates must be at least 2 numbers long");if(!se(r[0])||!se(r[1]))throw new Error("coordinates must contain numbers");return xe({type:"Point",coordinates:r},e,t)}function se(r){return!isNaN(r)&&r!==null&&!Array.isArray(r)}function Ve(r){if(!r)throw new Error("coord is required");if(!Array.isArray(r)){if(r.type==="Feature"&&r.geometry!==null&&r.geometry.type==="Point")return[...r.geometry.coordinates];if(r.type==="Point")return[...r.coordinates]}if(Array.isArray(r)&&r.length>=2&&!Array.isArray(r[0])&&!Array.isArray(r[1]))return[...r];throw new Error("coord must be GeoJSON Point or an Array of numbers")}function Ae(r){return r.type==="Feature"?r.geometry:r}function _e(r,e,t={}){if(!r)throw new Error("point is required");if(!e)throw new Error("polygon is required");const s=Ve(r),i=Ae(e),n=i.type,o=e.bbox;let l=i.coordinates;if(o&&Re(s,o)===!1)return!1;n==="Polygon"&&(l=[l]);let h=!1;for(var d=0;d<l.length;++d){const u=Le(s,l[d]);if(u===0)return!t.ignoreBoundary;u&&(h=!0)}return h}function Re(r,e){return e[0]<=r[0]&&e[1]<=r[1]&&e[2]>=r[0]&&e[3]>=r[1]}var ie=_e;const re=10,Ne=24,ne=3;class Oe{constructor(e,t){this.selectedIds=new Set,this.isActive=!1,this.dragging=!1,this.dragVertexIndex=-1,this.dragStartFeature=null,this.draggingPolygon=!1,this.dragPolygonStartLngLat=null,this.highlightedVertexIndex=-1,this.callbacks=e,this.onSelectionChange=t}activate(){this.isActive=!0}deactivate(){this.isActive=!1,this.highlightedVertexIndex=-1,this.endDrag(),this.selectedIds.size>0&&(this.selectedIds.clear(),this.callbacks.clearVertices(),this.notifySelectionChange())}getSelectedIds(){return Array.from(this.selectedIds)}selectFeature(e){if(!this.isActive)return!1;const t=this.callbacks.getFeatureById(e);return t?(this.highlightedVertexIndex=-1,this.endDrag(),this.selectedIds.clear(),this.selectedIds.add(e),this.showVertexHandles(t),this.notifySelectionChange(),this.callbacks.renderFeatures(),!0):!1}clearSelection(){this.isActive&&this.selectedIds.size!==0&&(this.highlightedVertexIndex=-1,this.endDrag(),this.selectedIds.clear(),this.callbacks.clearVertices(),this.notifySelectionChange(),this.callbacks.renderFeatures())}onPointerDown(e){if(!this.isActive)return;const t=this.getFirstSelectedId();if(t){const o=this.callbacks.getFeatureById(t);if(o){const l=this.getVertices(o),h=this.getThreshold(e),d=this.findNearestVertex(l,e.point,h);if(d>=0){this.startDrag(o,d);return}const u=this.computeMidpoints(l),a=this.findNearestPoint(u,e.point,h);if(a>=0){const g=R.cloneFeature(o),y=this.insertVertex(o,a+1,u[a]);this.callbacks.updateFeatureInStore(t,y),this.showVertexHandles(y),this.startDrag(y,a+1),this.dragStartFeature=g;return}const c=te([e.lngLat.lng,e.lngLat.lat]);if(ie(c,o.geometry)){this.startPolygonDrag(o,e.lngLat);return}}}this.highlightedVertexIndex=-1;const s=te([e.lngLat.lng,e.lngLat.lat]),i=this.callbacks.getAllFeatures();let n;for(let o=i.length-1;o>=0;o--){const l=i[o],h=l.geometry;if(ie(s,h)){n=l;break}}n?this.selectedIds.has(n.id)?(this.selectedIds.delete(n.id),this.callbacks.clearVertices()):(this.selectedIds.clear(),this.selectedIds.add(n.id),this.showVertexHandles(n)):(this.selectedIds.clear(),this.callbacks.clearVertices()),this.notifySelectionChange(),this.callbacks.renderFeatures()}onPointerMove(e){if(!this.isActive)return;if(this.dragging){const l=this.getFirstSelectedId();if(!l)return;const h=this.callbacks.getFeatureById(l);if(!h)return;const d=[e.lngLat.lng,e.lngLat.lat],u=this.moveVertex(h,this.dragVertexIndex,d);if(ae(u.geometry.coordinates[0]))return;this.callbacks.updateFeatureInStore(l,u),this.callbacks.renderFeatures(),this.showVertexHandles(u);return}if(this.draggingPolygon){const l=this.getFirstSelectedId();if(!l||!this.dragStartFeature||!this.dragPolygonStartLngLat)return;const h=e.lngLat.lng-this.dragPolygonStartLngLat.lng,d=e.lngLat.lat-this.dragPolygonStartLngLat.lat,u=this.movePolygon(this.dragStartFeature,h,d);this.callbacks.updateFeatureInStore(l,u),this.callbacks.renderFeatures(),this.showVertexHandles(u);return}const t=this.getFirstSelectedId();if(!t)return;const s=this.callbacks.getFeatureById(t);if(!s)return;const i=this.getVertices(s),n=this.getThreshold(e),o=this.findNearestVertex(i,e.point,n);o!==this.highlightedVertexIndex&&(this.highlightedVertexIndex=o,this.showVertexHandles(s))}onPointerUp(e){if(!this.isActive||!this.dragging&&!this.draggingPolygon)return;const t=this.getFirstSelectedId();if(!t||!this.dragStartFeature){this.endDrag();return}const s=this.callbacks.getFeatureById(t);if(s){const i=new $(t,this.dragStartFeature,R.cloneFeature(s));this.callbacks.pushToHistory(i),this.callbacks.emitEvent("update",{feature:s,oldFeature:this.dragStartFeature})}this.endDrag()}onDoubleClick(e){if(!this.isActive)return;const t=this.getFirstSelectedId();if(!t)return;const s=this.callbacks.getFeatureById(t);if(!s)return;const i=this.getVertices(s),n=this.getThreshold(e),o=this.findNearestVertex(i,e.point,n);if(o>=0&&i.length>ne){const l=R.cloneFeature(s),h=this.removeVertex(s,o);this.callbacks.updateFeatureInStore(t,h);const d=new $(t,l,R.cloneFeature(h));this.callbacks.pushToHistory(d),this.callbacks.emitEvent("update",{feature:h,oldFeature:l}),this.callbacks.renderFeatures(),this.showVertexHandles(h),e.originalEvent.preventDefault(),e.originalEvent.stopPropagation()}}onLongPress(e){if(!this.isActive)return;const t=this.getFirstSelectedId();if(!t)return;const s=this.callbacks.getFeatureById(t);if(!s)return;const i=this.getVertices(s),n=this.getThreshold(e),o=this.findNearestVertex(i,e.point,n);if(o>=0&&i.length>ne){const l=R.cloneFeature(s),h=this.removeVertex(s,o);this.callbacks.updateFeatureInStore(t,h);const d=new $(t,l,R.cloneFeature(h));this.callbacks.pushToHistory(d),this.callbacks.emitEvent("update",{feature:h,oldFeature:l}),this.callbacks.renderFeatures(),this.showVertexHandles(h)}}onKeyDown(e,t){this.isActive&&(e==="Delete"||e==="Backspace")&&this.deleteSelected()}getThreshold(e){return e.inputType==="touch"?Ne:re}getVertices(e){const t=e.geometry.coordinates[0];return t.slice(0,t.length-1)}findNearestVertex(e,t,s){return this.findNearestPoint(e,t,s)}findNearestPoint(e,t,s=re){let i=1/0,n=-1;for(let o=0;o<e.length;o++){const l=this.callbacks.getScreenPoint({lng:e[o][0],lat:e[o][1]}),h=t.x-l.x,d=t.y-l.y,u=Math.sqrt(h*h+d*d);u<=s&&u<i&&(i=u,n=o)}return n}computeMidpoints(e){const t=[];for(let s=0;s<e.length;s++){const i=(s+1)%e.length;t.push([(e[s][0]+e[i][0])/2,(e[s][1]+e[i][1])/2])}return t}startDrag(e,t){this.dragging=!0,this.dragVertexIndex=t,this.dragStartFeature=R.cloneFeature(e),this.callbacks.setDragPan(!1)}startPolygonDrag(e,t){this.draggingPolygon=!0,this.dragPolygonStartLngLat=t,this.dragStartFeature=R.cloneFeature(e),this.callbacks.setDragPan(!1)}endDrag(){(this.dragging||this.draggingPolygon)&&this.callbacks.setDragPan(!0),this.dragging=!1,this.dragVertexIndex=-1,this.dragStartFeature=null,this.draggingPolygon=!1,this.dragPolygonStartLngLat=null,this.highlightedVertexIndex=-1}moveVertex(e,t,s){const i=[...e.geometry.coordinates[0]];return i[t]=s,t===0&&(i[i.length-1]=s),t===i.length-1&&(i[0]=s),{...e,geometry:{type:"Polygon",coordinates:[i]}}}movePolygon(e,t,s){const i=e.geometry.coordinates[0].map(n=>[n[0]+t,n[1]+s]);return{...e,geometry:{type:"Polygon",coordinates:[i]}}}insertVertex(e,t,s){const i=[...e.geometry.coordinates[0]];return i.splice(t,0,s),{...e,geometry:{type:"Polygon",coordinates:[i]}}}removeVertex(e,t){const i=this.getVertices(e).filter((o,l)=>l!==t),n=[...i,[...i[0]]];return{...e,geometry:{type:"Polygon",coordinates:[n]}}}refreshVertexHandles(){if(!this.isActive)return;const e=this.getFirstSelectedId();if(!e)return;const t=this.callbacks.getFeatureById(e);t?this.showVertexHandles(t):(this.selectedIds.delete(e),this.callbacks.clearVertices(),this.notifySelectionChange())}showVertexHandles(e){const t=this.getVertices(e),s=this.computeMidpoints(t);this.callbacks.renderVertices(e.id,t,s,this.highlightedVertexIndex>=0?this.highlightedVertexIndex:void 0)}getFirstSelectedId(){return this.selectedIds.values().next().value}deleteSelected(){if(this.selectedIds.size===0)return;const e=Array.from(this.selectedIds);for(const t of e){const s=this.callbacks.getFeatureById(t);if(s){this.callbacks.removeFeatureFromStore(t);const i=new oe(s);this.callbacks.pushToHistory(i),this.callbacks.emitEvent("delete",{feature:s})}}this.selectedIds.clear(),this.callbacks.clearVertices(),this.notifySelectionChange(),this.callbacks.renderFeatures()}notifySelectionChange(){const e=this.getSelectedIds();this.callbacks.emitEvent("selectionchange",{selectedIds:e}),this.onSelectionChange&&this.onSelectionChange(e)}}class Ue{constructor(e,t){this.handleMouseDown=s=>{this.callbacks.onPointerDown(this.normalize(s))},this.handleMouseMove=s=>{this.callbacks.onPointerMove(this.normalize(s))},this.handleMouseUp=s=>{this.callbacks.onPointerUp(this.normalize(s))},this.handleDblClick=s=>{this.callbacks.onDoubleClick(this.normalize(s))},this.map=e,this.callbacks=t,this.canvas=e.getCanvasContainer()}enable(){this.canvas.addEventListener("mousedown",this.handleMouseDown),this.canvas.addEventListener("mousemove",this.handleMouseMove),this.canvas.addEventListener("mouseup",this.handleMouseUp),this.canvas.addEventListener("dblclick",this.handleDblClick)}disable(){this.canvas.removeEventListener("mousedown",this.handleMouseDown),this.canvas.removeEventListener("mousemove",this.handleMouseMove),this.canvas.removeEventListener("mouseup",this.handleMouseUp),this.canvas.removeEventListener("dblclick",this.handleDblClick)}destroy(){this.disable()}normalize(e){const t=this.canvas.getBoundingClientRect(),s=e.clientX-t.left,i=e.clientY-t.top,n=this.map.unproject([s,i]);return{lngLat:{lng:n.lng,lat:n.lat},point:{x:s,y:i},originalEvent:e,inputType:"mouse"}}}const Be=300,He=500,ze=15;class je{constructor(e,t){this.lastTapTime=0,this.longPressTimer=null,this.touchStartPos=null,this.isPinching=!1,this.handleTouchStart=s=>{if(s.touches.length>=2){this.isPinching=!0,this.cancelLongPress();return}this.isPinching=!1;const i=this.normalize(s);this.touchStartPos={x:i.point.x,y:i.point.y},this.cancelLongPress(),this.longPressTimer=setTimeout(()=>{this.touchStartPos&&(this.callbacks.onLongPress(i),this.touchStartPos=null)},He),this.callbacks.onPointerDown(i)},this.handleTouchMove=s=>{if(this.isPinching||s.touches.length>=2){this.cancelLongPress();return}const i=this.normalize(s);if(this.touchStartPos){const n=i.point.x-this.touchStartPos.x,o=i.point.y-this.touchStartPos.y;Math.sqrt(n*n+o*o)>ze&&this.cancelLongPress()}this.callbacks.onPointerMove(i)},this.handleTouchEnd=s=>{if(this.cancelLongPress(),this.isPinching){s.touches.length===0&&(this.isPinching=!1);return}if(s.changedTouches.length===0)return;const i=this.normalizeChangedTouch(s),n=Date.now();n-this.lastTapTime<Be?(this.callbacks.onDoubleClick(i),this.lastTapTime=0):this.lastTapTime=n,this.touchStartPos&&(this.callbacks.onPointerUp(i),this.touchStartPos=null)},this.map=e,this.callbacks=t,this.canvas=e.getCanvasContainer()}enable(){this.canvas.addEventListener("touchstart",this.handleTouchStart,{passive:!1}),this.canvas.addEventListener("touchmove",this.handleTouchMove,{passive:!1}),this.canvas.addEventListener("touchend",this.handleTouchEnd)}disable(){this.canvas.removeEventListener("touchstart",this.handleTouchStart),this.canvas.removeEventListener("touchmove",this.handleTouchMove),this.canvas.removeEventListener("touchend",this.handleTouchEnd),this.cancelLongPress()}destroy(){this.disable()}cancelLongPress(){this.longPressTimer!==null&&(clearTimeout(this.longPressTimer),this.longPressTimer=null)}normalize(e){const t=e.touches[0],s=this.canvas.getBoundingClientRect(),i=t.clientX-s.left,n=t.clientY-s.top,o=this.map.unproject([i,n]);return{lngLat:{lng:o.lng,lat:o.lat},point:{x:i,y:n},originalEvent:e,inputType:"touch"}}normalizeChangedTouch(e){const t=e.changedTouches[0],s=this.canvas.getBoundingClientRect(),i=t.clientX-s.left,n=t.clientY-s.top,o=this.map.unproject([i,n]);return{lngLat:{lng:o.lng,lat:o.lat},point:{x:i,y:n},originalEvent:e,inputType:"touch"}}}const K=class K{constructor(e){this.handleKeyDown=t=>{K.RELEVANT_KEYS.has(t.key)&&this.callbacks.onKeyDown(t.key,t)},this.callbacks=e}enable(){document.addEventListener("keydown",this.handleKeyDown)}disable(){document.removeEventListener("keydown",this.handleKeyDown)}destroy(){this.disable()}};K.RELEVANT_KEYS=new Set(["Escape","Delete","Backspace"]);let G=K;class Xe{constructor(e,t){this.getActiveMode=t;const s={onPointerDown:i=>{var n;(n=this.getActiveMode())==null||n.onPointerDown(i)},onPointerMove:i=>{var n;(n=this.getActiveMode())==null||n.onPointerMove(i)},onPointerUp:i=>{var n;(n=this.getActiveMode())==null||n.onPointerUp(i)},onDoubleClick:i=>{var n;(n=this.getActiveMode())==null||n.onDoubleClick(i)},onLongPress:i=>{var n;(n=this.getActiveMode())==null||n.onLongPress(i)}};this.mouseInput=new Ue(e,s),this.touchInput=new je(e,s),this.keyboardInput=new G({onKeyDown:(i,n)=>{var o;(o=this.getActiveMode())==null||o.onKeyDown(i,n)}})}enable(){this.mouseInput.enable(),this.touchInput.enable(),this.keyboardInput.enable()}disable(){this.mouseInput.disable(),this.touchInput.disable(),this.keyboardInput.disable()}destroy(){this.mouseInput.destroy(),this.touchInput.destroy(),this.keyboardInput.destroy()}}const E={FEATURES:"libre-draw-features",PREVIEW:"libre-draw-preview",EDIT_VERTICES:"libre-draw-edit-vertices"},B={type:"FeatureCollection",features:[]};class We{constructor(e){this.initialized=!1,this.map=e}initialize(){this.initialized||(this.map.getSource(E.FEATURES)||this.map.addSource(E.FEATURES,{type:"geojson",data:B}),this.map.getSource(E.PREVIEW)||this.map.addSource(E.PREVIEW,{type:"geojson",data:B}),this.map.getSource(E.EDIT_VERTICES)||this.map.addSource(E.EDIT_VERTICES,{type:"geojson",data:B}),this.initialized=!0)}updateFeatures(e){const t=this.map.getSource(E.FEATURES);t&&t.setData(e)}updatePreview(e){const t=this.map.getSource(E.PREVIEW);t&&t.setData(e)}clearPreview(){this.updatePreview(B)}updateEditVertices(e){const t=this.map.getSource(E.EDIT_VERTICES);t&&t.setData(e)}clearEditVertices(){this.updateEditVertices(B)}destroy(){this.map.getSource(E.FEATURES)&&this.map.removeSource(E.FEATURES),this.map.getSource(E.PREVIEW)&&this.map.removeSource(E.PREVIEW),this.map.getSource(E.EDIT_VERTICES)&&this.map.removeSource(E.EDIT_VERTICES),this.initialized=!1}}const S={FILL:"libre-draw-fill",OUTLINE:"libre-draw-outline",VERTICES:"libre-draw-vertices",PREVIEW:"libre-draw-preview",EDIT_VERTICES:"libre-draw-edit-vertices",EDIT_MIDPOINTS:"libre-draw-edit-midpoints"},w={FILL:"#3bb2d0",FILL_OPACITY:.2,FILL_SELECTED:"#fbb03b",FILL_SELECTED_OPACITY:.4,OUTLINE:"#3bb2d0",OUTLINE_WIDTH:2,OUTLINE_SELECTED:"#fbb03b",VERTEX_COLOR:"#ffffff",VERTEX_STROKE:"#3bb2d0",VERTEX_RADIUS:4,PREVIEW_OUTLINE:"#3bb2d0",PREVIEW_OUTLINE_DASH:[2,2],EDIT_VERTEX_COLOR:"#ffffff",EDIT_VERTEX_STROKE:"#3bb2d0",EDIT_VERTEX_RADIUS:5,EDIT_VERTEX_STROKE_WIDTH:2,MIDPOINT_COLOR:"#3bb2d0",MIDPOINT_OPACITY:.5,MIDPOINT_RADIUS:3};class Ke{constructor(e,t){this.selectedIds=new Set,this.pendingRender=!1,this.pendingFeatures=null,this.initialized=!1,this.map=e,this.sourceManager=t}initialize(){this.initialized||(this.sourceManager.initialize(),this.map.getLayer(S.FILL)||this.map.addLayer({id:S.FILL,type:"fill",source:E.FEATURES,paint:{"fill-color":["case",["boolean",["get","_selected"],!1],w.FILL_SELECTED,w.FILL],"fill-opacity":["case",["boolean",["get","_selected"],!1],w.FILL_SELECTED_OPACITY,w.FILL_OPACITY]}}),this.map.getLayer(S.OUTLINE)||this.map.addLayer({id:S.OUTLINE,type:"line",source:E.FEATURES,paint:{"line-color":["case",["boolean",["get","_selected"],!1],w.OUTLINE_SELECTED,w.OUTLINE],"line-width":w.OUTLINE_WIDTH}}),this.map.getLayer(S.VERTICES)||this.map.addLayer({id:S.VERTICES,type:"circle",source:E.FEATURES,filter:["==","$type","Point"],paint:{"circle-radius":w.VERTEX_RADIUS,"circle-color":w.VERTEX_COLOR,"circle-stroke-color":w.VERTEX_STROKE,"circle-stroke-width":2}}),this.map.getLayer(S.PREVIEW)||this.map.addLayer({id:S.PREVIEW,type:"line",source:E.PREVIEW,paint:{"line-color":w.PREVIEW_OUTLINE,"line-width":2,"line-dasharray":w.PREVIEW_OUTLINE_DASH}}),this.map.getLayer(S.EDIT_MIDPOINTS)||this.map.addLayer({id:S.EDIT_MIDPOINTS,type:"circle",source:E.EDIT_VERTICES,filter:["==",["get","_type"],"midpoint"],paint:{"circle-radius":w.MIDPOINT_RADIUS,"circle-color":w.MIDPOINT_COLOR,"circle-opacity":w.MIDPOINT_OPACITY}}),this.map.getLayer(S.EDIT_VERTICES)||this.map.addLayer({id:S.EDIT_VERTICES,type:"circle",source:E.EDIT_VERTICES,filter:["==",["get","_type"],"vertex"],paint:{"circle-radius":["case",["boolean",["get","_highlighted"],!1],7,w.EDIT_VERTEX_RADIUS],"circle-color":["case",["boolean",["get","_highlighted"],!1],"#ff4444",w.EDIT_VERTEX_COLOR],"circle-stroke-color":["case",["boolean",["get","_highlighted"],!1],"#cc0000",w.EDIT_VERTEX_STROKE],"circle-stroke-width":w.EDIT_VERTEX_STROKE_WIDTH}}),this.initialized=!0)}render(e){this.pendingFeatures=e,this.pendingRender||(this.pendingRender=!0,requestAnimationFrame(()=>{this.performRender(),this.pendingRender=!1}))}renderPreview(e){if(e.length<2){this.clearPreview();return}const t=e.map(i=>[i[0],i[1]]),s={type:"FeatureCollection",features:[{type:"Feature",properties:{},geometry:{type:"LineString",coordinates:t}}]};this.sourceManager.updatePreview(s)}clearPreview(){this.sourceManager.clearPreview()}renderVertices(e,t,s){const i=[];for(let n=0;n<e.length;n++){const o=e[n];i.push({type:"Feature",properties:{_type:"vertex",_highlighted:n===s},geometry:{type:"Point",coordinates:[o[0],o[1]]}})}for(const n of t)i.push({type:"Feature",properties:{_type:"midpoint"},geometry:{type:"Point",coordinates:[n[0],n[1]]}});this.sourceManager.updateEditVertices({type:"FeatureCollection",features:i})}clearVertices(){this.sourceManager.clearEditVertices()}setSelectedIds(e){this.selectedIds=new Set(e)}destroy(){const e=[S.EDIT_VERTICES,S.EDIT_MIDPOINTS,S.PREVIEW,S.VERTICES,S.OUTLINE,S.FILL];for(const t of e)this.map.getLayer(t)&&this.map.removeLayer(t);this.sourceManager.destroy(),this.initialized=!1}performRender(){if(!this.pendingFeatures)return;const t={type:"FeatureCollection",features:this.pendingFeatures.map(s=>({type:"Feature",id:s.id,properties:{...s.properties,_id:s.id,_selected:this.selectedIds.has(s.id)},geometry:s.geometry}))};this.sourceManager.updateFeatures(t),this.pendingFeatures=null}}class $e{constructor(e){this.options=e,this.element=document.createElement("button"),this.element.type="button",this.element.title=e.title,this.element.setAttribute("aria-label",e.title),this.element.dataset.libreDrawButton=e.id,this.applyStyles(),this.iconContainer=document.createElement("span"),this.iconContainer.style.display="flex",this.iconContainer.style.alignItems="center",this.iconContainer.style.justifyContent="center",this.setIcon(e.icon),this.element.appendChild(this.iconContainer),this.element.addEventListener("click",t=>{t.preventDefault(),t.stopPropagation(),this.element.disabled||e.onClick()})}getElement(){return this.element}setActive(e){e?(this.element.style.backgroundColor="#3bb2d0",this.element.style.color="#ffffff"):(this.element.style.backgroundColor="#ffffff",this.element.style.color="#333333"),this.element.setAttribute("aria-pressed",String(e))}setDisabled(e){this.element.disabled=e,this.element.style.opacity=e?"0.4":"1",this.element.style.cursor=e?"not-allowed":"pointer"}destroy(){this.element.remove()}setIcon(e){const i=new DOMParser().parseFromString(e,"image/svg+xml").documentElement;for(;this.iconContainer.firstChild;)this.iconContainer.removeChild(this.iconContainer.firstChild);this.iconContainer.appendChild(document.importNode(i,!0))}applyStyles(){const e=this.element.style;e.display="flex",e.alignItems="center",e.justifyContent="center",e.width="44px",e.height="44px",e.padding="0",e.margin="0",e.border="1px solid #ddd",e.borderRadius="4px",e.backgroundColor="#ffffff",e.color="#333333",e.cursor="pointer",e.outline="none",e.transition="background-color 0.15s, color 0.15s",e.boxSizing="border-box"}}const Ye='<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 2l8.5 6.2-3.2 9.8H6.7L3.5 8.2z"/></svg>',Ge='<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 3l7.07 16.97 2.51-7.39 7.39-2.51L3 3z"/><path d="M13 13l6 6"/></svg>',qe='<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="3 6 5 6 21 6"/><path d="M19 6v14a2 2 0 01-2 2H7a2 2 0 01-2-2V6m3 0V4a2 2 0 012-2h4a2 2 0 012 2v2"/><line x1="10" y1="11" x2="10" y2="17"/><line x1="14" y1="11" x2="14" y2="17"/></svg>',Je='<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="9 14 4 9 9 4"/><path d="M20 20v-7a4 4 0 00-4-4H4"/></svg>',Qe='<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="15 14 20 9 15 4"/><path d="M4 20v-7a4 4 0 014-4h12"/></svg>',Ze={draw:!0,select:!0,delete:!0,undo:!0,redo:!0};class et{constructor(e,t,s={}){this.buttons=new Map,this.map=e,this.callbacks=t,this.options=s,this.container=document.createElement("div"),this.container.className="libre-draw-toolbar",this.applyContainerStyles(),this.createButtons(),this.mount()}setActiveMode(e){const t=this.buttons.get("draw"),s=this.buttons.get("select");t&&t.setActive(e==="draw"),s&&s.setActive(e==="select")}setHistoryState(e,t){const s=this.buttons.get("undo"),i=this.buttons.get("redo");s&&s.setDisabled(!e),i&&i.setDisabled(!t)}destroy(){for(const e of this.buttons.values())e.destroy();this.buttons.clear(),this.container.remove()}createButtons(){const e={...Ze,...this.options.controls};e.draw&&this.addButton("draw",Ye,"Draw polygon",()=>{this.callbacks.onDrawClick()},!0),e.select&&this.addButton("select",Ge,"Select feature",()=>{this.callbacks.onSelectClick()},!0),e.delete&&this.addButton("delete",qe,"Delete selected",()=>{this.callbacks.onDeleteClick()}),e.undo&&this.addButton("undo",Je,"Undo",()=>{this.callbacks.onUndoClick()}),e.redo&&this.addButton("redo",Qe,"Redo",()=>{this.callbacks.onRedoClick()})}addButton(e,t,s,i,n){const o=new $e({id:e,icon:t,title:s,onClick:i,isToggle:n});this.buttons.set(e,o),this.container.appendChild(o.getElement())}mount(){const e=this.options.position||"top-right",t=this.map.getContainer(),s=t.querySelector(`.maplibregl-ctrl-${e}`);s?s.appendChild(this.container):t.appendChild(this.container)}applyContainerStyles(){const e=this.container.style;e.display="flex",e.flexDirection="column",e.gap="4px",e.padding="4px",e.backgroundColor="rgba(255, 255, 255, 0.9)",e.borderRadius="4px",e.boxShadow="0 1px 4px rgba(0, 0, 0, 0.3)",e.zIndex="1",e.pointerEvents="auto"}}class tt{constructor(e,t={}){this.toolbar=null,this.destroyed=!1,this.map=e,this.eventBus=new ge,this.featureStore=new R,this.historyManager=new fe(t.historyLimit??100),this.modeManager=new pe,this.sourceManager=new We(e),this.renderManager=new Ke(e,this.sourceManager);const s=new Se({addFeatureToStore:i=>this.featureStore.add(i),pushToHistory:i=>{this.historyManager.push(i),this.updateToolbarHistoryState()},emitEvent:(i,n)=>this.eventBus.emit(i,n),renderPreview:i=>this.renderManager.renderPreview(i),clearPreview:()=>this.renderManager.clearPreview(),renderFeatures:()=>this.renderAllFeatures(),getScreenPoint:i=>{const n=e.project([i.lng,i.lat]);return{x:n.x,y:n.y}}});if(this.selectMode=new Oe({removeFeatureFromStore:i=>this.featureStore.remove(i),pushToHistory:i=>{this.historyManager.push(i),this.updateToolbarHistoryState()},emitEvent:(i,n)=>this.eventBus.emit(i,n),renderFeatures:()=>this.renderAllFeatures(),getFeatureById:i=>this.featureStore.getById(i),getAllFeatures:()=>this.featureStore.getAll(),getScreenPoint:i=>{const n=e.project([i.lng,i.lat]);return{x:n.x,y:n.y}},updateFeatureInStore:(i,n)=>this.featureStore.update(i,n),renderVertices:(i,n,o,l)=>this.renderManager.renderVertices(n,o,l),clearVertices:()=>this.renderManager.clearVertices(),setDragPan:i=>{i?e.dragPan.enable():e.dragPan.disable()}},i=>{this.renderManager.setSelectedIds(i)}),this.modeManager.registerMode("idle",new Ie),this.modeManager.registerMode("draw",s),this.modeManager.registerMode("select",this.selectMode),this.modeManager.setOnModeChange((i,n)=>{this.eventBus.emit("modechange",{mode:i,previousMode:n}),this.toolbar&&this.toolbar.setActiveMode(i),i==="draw"?(e.dragPan.disable(),e.doubleClickZoom.disable()):i==="select"?e.doubleClickZoom.disable():(e.dragPan.enable(),e.doubleClickZoom.enable())}),this.inputHandler=new Xe(e,()=>this.modeManager.getCurrentMode()),t.toolbar!==!1&&t.toolbar!==void 0){const i=typeof t.toolbar=="object"?t.toolbar:{};this.createToolbar(i)}e.isStyleLoaded()?this.initialize():e.once("load",()=>{this.initialize()})}setMode(e){this.assertNotDestroyed(),this.modeManager.setMode(e)}getMode(){return this.assertNotDestroyed(),this.modeManager.getMode()}getFeatures(){return this.assertNotDestroyed(),this.featureStore.getAll()}setFeatures(e){this.assertNotDestroyed();const t=Ee(e);this.featureStore.setAll(t.features),this.historyManager.clear(),this.renderAllFeatures(),this.updateToolbarHistoryState()}addFeatures(e){this.assertNotDestroyed();for(const t of e){const s=le(t);this.featureStore.add(s)}this.renderAllFeatures()}getSelectedFeatureIds(){return this.assertNotDestroyed(),this.selectMode.getSelectedIds()}getFeatureById(e){return this.assertNotDestroyed(),this.featureStore.getById(e)}deleteFeature(e){this.assertNotDestroyed();const t=this.featureStore.getById(e);if(!t)return;this.selectMode.getSelectedIds().includes(e)&&this.selectMode.clearSelection(),this.featureStore.remove(e);const i=new oe(t);return this.historyManager.push(i),this.eventBus.emit("delete",{feature:t}),this.renderAllFeatures(),this.updateToolbarHistoryState(),t}selectFeature(e){if(this.assertNotDestroyed(),!this.featureStore.getById(e))throw new v(`Feature not found: ${e}`);this.modeManager.getMode()!=="select"&&this.modeManager.setMode("select"),this.selectMode.selectFeature(e)}clearSelection(){this.assertNotDestroyed(),this.selectMode.clearSelection()}undo(){this.assertNotDestroyed();const e=this.historyManager.undo(this.featureStore);return e&&(this.renderAllFeatures(),this.selectMode.refreshVertexHandles(),this.updateToolbarHistoryState()),e}redo(){this.assertNotDestroyed();const e=this.historyManager.redo(this.featureStore);return e&&(this.renderAllFeatures(),this.selectMode.refreshVertexHandles(),this.updateToolbarHistoryState()),e}on(e,t){this.assertNotDestroyed(),this.eventBus.on(e,t)}off(e,t){this.assertNotDestroyed(),this.eventBus.off(e,t)}destroy(){this.destroyed||(this.destroyed=!0,this.modeManager.setMode("idle"),this.inputHandler.destroy(),this.renderManager.destroy(),this.eventBus.removeAllListeners(),this.historyManager.clear(),this.featureStore.clear(),this.toolbar&&(this.toolbar.destroy(),this.toolbar=null))}initialize(){this.destroyed||(this.renderManager.initialize(),this.inputHandler.enable())}renderAllFeatures(){const e=this.featureStore.getAll();this.renderManager.render(e)}createToolbar(e){this.toolbar=new et(this.map,{onDrawClick:()=>{const t=this.modeManager.getMode();this.modeManager.setMode(t==="draw"?"idle":"draw")},onSelectClick:()=>{const t=this.modeManager.getMode();this.modeManager.setMode(t==="select"?"idle":"select")},onDeleteClick:()=>{if(this.modeManager.getMode()==="select"){const t=this.selectMode.getSelectedIds();for(const s of t)this.deleteFeature(s)}},onUndoClick:()=>{this.undo()},onRedoClick:()=>{this.redo()}},e),this.toolbar.setActiveMode(this.modeManager.getMode()),this.toolbar.setHistoryState(this.historyManager.canUndo(),this.historyManager.canRedo())}updateToolbarHistoryState(){this.toolbar&&this.toolbar.setHistoryState(this.historyManager.canUndo(),this.historyManager.canRedo())}assertNotDestroyed(){if(this.destroyed)throw new v("This LibreDraw instance has been destroyed.")}}exports.LibreDraw=tt;exports.LibreDrawError=v;
|
|
2
|
+
//# sourceMappingURL=libre-draw.cjs.map
|