leaflet-polydraw
Version:
Advanced Leaflet plugin for freehand polygon drawing, with smart merging and powerful editing tools. Compatible with both Leaflet v1.x and v2.x.
249 lines • 9.29 kB
TypeScript
import * as L from 'leaflet';
import { TurfHelper } from '../turf-helper';
import { PolygonInformationService } from '../polygon-information.service';
import type { Feature, Polygon, MultiPolygon } from 'geojson';
import type { PolydrawConfig, PolydrawPolygon, HistoryAction, LayerInteraction, PolygonStyleOverrides } from '../types/polydraw-interfaces';
import { ModeManager } from './mode-manager';
import { EventManager, PolydrawEvent, PolydrawEventCallback } from './event-manager';
import { PolygonInteractionManager } from './polygon-interaction-manager';
import type { LayerManager } from './layer-manager';
export interface MutationResult {
success: boolean;
featureGroups?: L.FeatureGroup[];
error?: string;
}
interface AddPolygonOptions {
simplify?: boolean;
noMerge?: boolean;
mergeEditableOnly?: boolean;
dynamicTolerance?: boolean;
visualOptimizationLevel?: number;
originalOptimizationLevel?: number;
skipKinkProcessing?: boolean;
targetLayerId?: string;
layerColor?: string;
featureId?: string;
featureMetadata?: Record<string, unknown>;
sourceFeatureIds?: string[];
featureInteractionOverride?: LayerInteraction;
featureStyleOverrides?: PolygonStyleOverrides;
featureCreatedAt?: string;
featureLastModified?: string;
}
export interface MutationManagerDependencies {
turfHelper: TurfHelper;
polygonInformation: PolygonInformationService;
map: L.Map;
config: PolydrawConfig;
modeManager: ModeManager;
eventManager: EventManager;
getFeatureGroups: () => L.FeatureGroup[];
saveHistoryState?: (action: HistoryAction) => void;
layerManager?: LayerManager;
}
/**
* PolygonMutationManager acts as a facade that coordinates between specialized managers.
* It maintains the arrayOfFeatureGroups as the single source of truth and delegates
* operations to the appropriate specialized managers.
*/
export declare class PolygonMutationManager {
private turfHelper;
private map;
private config;
private eventManager;
private getFeatureGroups;
private saveHistoryState?;
private layerManager?;
private geometryManager;
private interactionManager;
private readonly onDrawCancel;
private readonly onPolygonUpdated;
private readonly onMenuAction;
private readonly onCheckIntersection;
private readonly onSubtract;
private readonly onPolygonDeleted;
constructor(dependencies: MutationManagerDependencies);
/**
* Initialize the three specialized managers
*/
private initializeSpecializedManagers;
/**
* Set up event forwarding from specialized managers to facade
*/
private setupEventForwarding;
dispose(): void;
/**
* Handle polygon modification from interaction manager
*/
private handlePolygonModified;
/**
* Handle menu actions from interaction manager
*/
private handleMenuAction;
/**
* Handle polygon menu action execution
*/
private executePolygonMenuAction;
private normalizeMenuActionResult;
private isPolygonFeature;
private getBoundsForMenuAction;
/**
* Get the polygon interaction manager (for testing)
*/
get polygonInteractionManager(): PolygonInteractionManager;
/**
* Add event listener
*/
on<T extends PolydrawEvent>(event: T, callback: PolydrawEventCallback<T>): void;
/**
* Emit event to all listeners
*/
private emit;
/**
* Add a polygon with optional merging logic
*/
addPolygon(latlngs: Feature<Polygon | MultiPolygon>, options?: AddPolygonOptions): Promise<MutationResult>;
private addPolygonWithMergeHandling;
private preparePolygonsForAddition;
/**
* Subtract a polygon from existing polygons
*/
subtractPolygon(latlngs: Feature<Polygon | MultiPolygon>, options?: AddPolygonOptions): Promise<MutationResult>;
/**
* Create and add a polygon layer with all markers and interactions
*/
private addPolygonLayer;
/**
* Merge a polygon with existing intersecting polygons
*/
private mergePolygon;
/**
* Union multiple polygons together using geometry manager
*/
private unionPolygons;
/**
* Determine if intelligent merging should be allowed for a polygon
* This checks if the polygon actually intersects with existing polygons
*/
private shouldAllowIntelligentMerge;
/**
* Check if a polygon is completely inside a hole of an existing polygon
* This prevents incorrect merging when drawing polygons inside holes
*/
private isPolygonInsideExistingHole;
/**
* Normalize polygon coordinates to handle complex nested structures
* This fixes the bug where markers are missing when drawing polygons inside holes
*/
private normalizePolygonCoordinates;
/**
* Create a polygon from GeoJSON feature
*/
private isPositionArrayofArrays;
private isPosition;
/**
* Create a polygon from GeoJSON feature
*/
private getPolygon;
private normalizeSinglePolygonFeature;
/**
* Internal method to add feature group to array
*/
private addFeatureGroupInternal;
/**
* Internal method to remove feature group from array and map
*/
private removeFeatureGroupInternal;
/**
* Get complete polygon GeoJSON including holes from a feature group
*/
private getCompletePolygonFromFeatureGroup;
private getOptimizationMetadataFromFeatureGroup;
private getFeatureMetadataStateFromFeatureGroup;
private collectSourceFeatureIds;
private resolvePrimaryFeatureMetadata;
private resolvePrimaryFeatureInteractionOverride;
private resolvePrimaryFeatureStyleOverrides;
private cloneFeatureMetadata;
private cloneStyleOverrides;
private featureHasHoles;
private setFeatureGroupMetadata;
/**
* Update marker draggable state
*/
updateMarkerDraggableState(): void;
/**
* Update all markers for edge deletion visual feedback
*/
updateAllMarkersForEdgeDeletion(showFeedback: boolean): void;
/**
* Set modifier key held state
*/
setModifierKeyHeld(isHeld: boolean): void;
/**
* Check if two polygons intersect (delegates to geometry manager)
*/
checkPolygonIntersection(polygon1: Feature<Polygon | MultiPolygon>, polygon2: Feature<Polygon | MultiPolygon>): boolean;
/**
* Get polygon center (delegates to geometry manager)
*/
getPolygonCenter(polygon: Feature<Polygon | MultiPolygon>): {
lat: number;
lng: number;
} | null;
/**
* Get bounding box from polygon (delegates to geometry manager)
*/
getBoundingBox(polygon: Feature<Polygon | MultiPolygon>): {
minLat: number;
maxLat: number;
minLng: number;
maxLng: number;
} | null;
addMarker(latlngs: L.LatLngLiteral[], featureGroup: L.FeatureGroup, options?: {
optimizationLevel?: number;
originalOptimizationLevel?: number;
}): void;
addHoleMarker(latlngs: L.LatLngLiteral[], featureGroup: L.FeatureGroup): void;
addEdgeClickListeners(polygon: L.Polygon, featureGroup: L.FeatureGroup): void;
enablePolygonDragging(polygon: PolydrawPolygon, latlngs: Feature<Polygon | MultiPolygon>): void;
getMarkerIndex(latlngs: L.LatLngLiteral[], position: L.LatLngLiteral): number;
ensureMarkerSeparation(polygonLength: number, markers: {
menu?: {
index?: number;
};
delete?: {
index?: number;
};
info?: {
index?: number;
};
}): {
menu: number;
delete: number;
info: number;
};
findAlternativeMarkerPosition(polygonLength: number, originalIndex: number, usedIndices: Set<number>): number;
createDivIcon(processedClasses: string[]): L.DivIcon;
getLatLngInfoString(latlng: L.LatLngLiteral): string;
generateMenuMarkerPopup(latLngs: L.LatLngLiteral[], featureGroup: L.FeatureGroup): HTMLDivElement;
getPolygonGeoJSONFromFeatureGroup(featureGroup: L.FeatureGroup): Feature<Polygon | MultiPolygon>;
getTotalPolygonPerimeter(polygonGeoJSON: Feature<Polygon | MultiPolygon>): number;
generateInfoMarkerPopup(area: number, perimeter: number): HTMLDivElement;
onMarkerHoverForEdgeDeletion(marker: L.Marker, isHovering: boolean): void;
highlightEdgeOnHover(edgePolyline: L.Polyline, isHovering: boolean): void;
onEdgeClick(e: L.LeafletMouseEvent, edgePolyline: L.Polyline): void;
removeFeatureGroup(featureGroup: L.FeatureGroup): void;
/**
* Clean up all resources associated with a feature group
* This method ensures proper cleanup of event listeners and associated resources
*/
cleanupFeatureGroup(featureGroup: L.FeatureGroup): void;
onPolygonMouseMove(e: L.LeafletMouseEvent): void;
onPolygonMouseUp(e: L.LeafletMouseEvent): void;
updatePolygonAfterDrag(polygon: L.Polygon): void;
setSubtractVisualMode(polygon: L.Polygon, enabled: boolean): void;
performModifierSubtract(draggedGeoJSON: Feature<Polygon | MultiPolygon>, originalFeatureGroup: L.FeatureGroup): void;
}
export {};
//# sourceMappingURL=polygon-mutation-manager.d.ts.map