leaflet-polydraw 0.9.1 → 0.9.3

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.
@@ -7,18 +7,19 @@ const touchSupport = true;
7
7
  const mergePolygons = true;
8
8
  const kinks$1 = false;
9
9
  const modes = { "draw": true, "subtract": true, "deleteAll": true, "p2p": true, "attachElbow": true, "dragElbow": true, "dragPolygons": true, "edgeDeletion": true };
10
- const dragPolygons = { "realTimeUpdate": false, "showDragHandle": false, "opacity": 0.7, "dragCursor": "move", "hoverCursor": "grab", "markerBehavior": "hide", "markerAnimationDuration": 200, "autoMergeOnIntersect": true, "autoHoleOnContained": false, "dragInteractionBehavior": "auto", "modifierSubtract": { "enabled": true, "keys": { "windows": "ctrlKey", "mac": "metaKey", "linux": "ctrlKey" }, "subtractColor": "#D9460F", "hideMarkersOnDrag": true } };
11
- const edgeDeletion = { "enabled": true, "modifierKey": "auto", "hoverColor": "#D9460F", "confirmDeletion": false, "minVertices": 3 };
12
- const markers = { "deleteMarker": true, "infoMarker": true, "menuMarker": true, "coordsTitle": true, "zIndexOffset": 0, "markerIcon": { "styleClasses": ["polygon-marker"], "zIndexOffset": null }, "holeIcon": { "styleClasses": ["polygon-marker", "hole"], "zIndexOffset": null }, "markerInfoIcon": { "position": 3, "showArea": true, "showPerimeter": true, "useMetrics": true, "usePerimeterMinValue": false, "areaLabel": "Area", "perimeterLabel": "Perimeter", "values": { "min": { "metric": "50", "imperial": "100" }, "unknown": { "metric": "-", "imperial": "-" } }, "units": { "unknownUnit": "", "metric": { "onlyMetrics": true, "perimeter": { "m": "m", "km": "km" }, "area": { "m2": "m²", "km2": "km²", "daa": "daa", "ha": "ha" } }, "imperial": { "perimeter": { "feet": "ft", "yards": "yd", "miles": "mi" }, "area": { "feet2": "ft²", "yards2": "yd²", "acres": "ac", "miles2": "mi²" } } }, "styleClasses": ["polygon-marker", "info"], "zIndexOffset": 1e4 }, "markerMenuIcon": { "position": 7, "styleClasses": ["polygon-marker", "menu"], "zIndexOffset": 1e4 }, "markerDeleteIcon": { "position": 5, "styleClasses": ["polygon-marker", "delete"], "zIndexOffset": 1e4 }, "visualOptimization": { "sharpAngleThreshold": 30, "thresholdBoundingBox": 0.05, "thresholdDistance": 0.05, "useDistance": true, "useBoundingBox": false, "useAngles": false } };
13
- const polyLineOptions = { "color": "#50622b", "opacity": 1, "smoothFactor": 0, "noClip": true, "clickable": false, "weight": 2 };
14
- const subtractLineOptions = { "color": "#50622b", "opacity": 1, "smoothFactor": 0, "noClip": true, "clickable": false, "weight": 2 };
15
- const polygonOptions = { "smoothFactor": 0.3, "color": "#50622b", "fillColor": "#b4cd8a", "noClip": true };
16
- const holeOptions = { "color": "#aa0000", "fillColor": "#ffcccc", "weight": 2, "opacity": 1, "fillOpacity": 0.5 };
10
+ const dragPolygons = { "realTimeUpdate": false, "showDragHandle": false, "opacity": 0.7, "dragCursor": "move", "hoverCursor": "grab", "markerBehavior": "hide", "markerAnimationDuration": 200, "autoMergeOnIntersect": true, "autoHoleOnContained": false, "dragInteractionBehavior": "auto", "modifierSubtract": { "enabled": true, "keys": { "windows": "ctrlKey", "mac": "metaKey", "linux": "ctrlKey" }, "hideMarkersOnDrag": true } };
11
+ const edgeDeletion = { "enabled": true, "keys": { "windows": "ctrlKey", "mac": "metaKey", "linux": "ctrlKey" }, "confirmDeletion": false, "minVertices": 3 };
12
+ const markers = { "deleteMarker": true, "infoMarker": true, "menuMarker": true, "coordsTitle": true, "zIndexOffset": 0, "markerIcon": { "styleClasses": ["polygon-marker"], "zIndexOffset": null }, "holeIcon": { "styleClasses": ["polygon-marker", "hole"], "zIndexOffset": null }, "markerInfoIcon": { "position": 3, "showArea": true, "showPerimeter": true, "useMetrics": true, "usePerimeterMinValue": false, "areaLabel": "Area", "perimeterLabel": "Perimeter", "values": { "min": { "metric": "50", "imperial": "100" }, "unknown": { "metric": "-", "imperial": "-" } }, "units": { "unknownUnit": "", "metric": { "onlyMetrics": true, "perimeter": { "m": "m", "km": "km" }, "area": { "m2": "m²", "km2": "km²", "daa": "daa", "ha": "ha" } }, "imperial": { "perimeter": { "feet": "ft", "yards": "yd", "miles": "mi" }, "area": { "feet2": "ft²", "yards2": "yd²", "acres": "ac", "miles2": "mi²" } } }, "styleClasses": ["polygon-marker", "info"], "zIndexOffset": 1e4 }, "markerMenuIcon": { "position": 7, "styleClasses": ["polygon-marker", "menu"], "zIndexOffset": 1e4 }, "markerDeleteIcon": { "position": 5, "styleClasses": ["polygon-marker", "delete"], "zIndexOffset": 1e4 }, "holeMarkers": { "menuMarker": false, "deleteMarker": true, "infoMarker": false }, "visualOptimization": { "sharpAngleThreshold": 30, "thresholdBoundingBox": 0.05, "thresholdDistance": 0.05, "useDistance": true, "useBoundingBox": false, "useAngles": false } };
13
+ const polyLineOptions = { "opacity": 1, "smoothFactor": 0, "noClip": true, "clickable": false, "weight": 2 };
14
+ const subtractLineOptions = { "opacity": 1, "smoothFactor": 0, "noClip": true, "clickable": false, "weight": 2 };
15
+ const polygonOptions = { "smoothFactor": 0.3, "noClip": true };
16
+ const holeOptions = { "weight": 2, "opacity": 1, "fillOpacity": 0.5 };
17
17
  const polygonCreation = { "method": "concaveman", "simplification": { "mode": "simple", "tolerance": 1e-5, "highQuality": false } };
18
18
  const simplification = { "simplifyTolerance": { "tolerance": 1e-4, "highQuality": false, "mutate": false }, "dynamicMode": { "fractionGuard": 0.9, "multipiler": 2 } };
19
19
  const menuOperations = { "simplify": { "processHoles": true }, "doubleElbows": { "processHoles": true }, "bbox": { "processHoles": true } };
20
20
  const boundingBox = { "addMidPointMarkers": true };
21
21
  const bezier$1 = { "resolution": 1e4, "sharpness": 0.75 };
22
+ const colors = { "dragPolygons": { "subtract": "#D9460F" }, "p2p": { "closingMarker": "#4CAF50" }, "edgeHover": "#7a9441", "edgeDeletion": { "hover": "#D9460F" }, "polyline": "#50622b", "subtractLine": "#50622b", "polygon": { "border": "#50622b", "fill": "#b4cd8a" }, "hole": { "border": "#aa0000", "fill": "#ffcccc" }, "styles": { "controlButton": { "backgroundColor": "#fff", "color": "#000" }, "controlButtonHover": { "backgroundColor": "#f4f4f4" }, "controlButtonActive": { "backgroundColor": "rgb(128, 218, 255)", "color": "#fff" }, "indicatorActive": { "backgroundColor": "#ffcc00" }, "p2pMarker": { "backgroundColor": "#fff", "borderColor": "#50622b" } } };
22
23
  const defaultConfig = {
23
24
  touchSupport,
24
25
  mergePolygons,
@@ -35,7 +36,8 @@ const defaultConfig = {
35
36
  simplification,
36
37
  menuOperations,
37
38
  boundingBox,
38
- bezier: bezier$1
39
+ bezier: bezier$1,
40
+ colors
39
41
  };
40
42
  var DrawMode = /* @__PURE__ */ ((DrawMode2) => {
41
43
  DrawMode2[DrawMode2["Off"] = 0] = "Off";
@@ -190,7 +192,7 @@ function degreesToRadians(degrees2) {
190
192
  function isNumber(num) {
191
193
  return !isNaN(num) && num !== null && !Array.isArray(num);
192
194
  }
193
- function isObject(input) {
195
+ function isObject$1(input) {
194
196
  return input !== null && typeof input === "object" && !Array.isArray(input);
195
197
  }
196
198
  function getCoord(coord) {
@@ -1498,6 +1500,161 @@ function coordsToLine(coords, properties) {
1498
1500
  }
1499
1501
  return lineString(coords[0], properties);
1500
1502
  }
1503
+ var __defProp$1 = Object.defineProperty;
1504
+ var __name = (target, value) => __defProp$1(target, "name", { value, configurable: true });
1505
+ var _GeojsonEquality = class _GeojsonEquality2 {
1506
+ constructor(opts) {
1507
+ this.direction = false;
1508
+ this.compareProperties = true;
1509
+ var _a2, _b2, _c;
1510
+ this.precision = 10 ** -((_a2 = opts == null ? void 0 : opts.precision) != null ? _a2 : 17);
1511
+ this.direction = (_b2 = opts == null ? void 0 : opts.direction) != null ? _b2 : false;
1512
+ this.compareProperties = (_c = opts == null ? void 0 : opts.compareProperties) != null ? _c : true;
1513
+ }
1514
+ compare(g1, g2) {
1515
+ if (g1.type !== g2.type) {
1516
+ return false;
1517
+ }
1518
+ if (!sameLength(g1, g2)) {
1519
+ return false;
1520
+ }
1521
+ switch (g1.type) {
1522
+ case "Point":
1523
+ return this.compareCoord(g1.coordinates, g2.coordinates);
1524
+ case "LineString":
1525
+ return this.compareLine(g1.coordinates, g2.coordinates);
1526
+ case "Polygon":
1527
+ return this.comparePolygon(g1, g2);
1528
+ case "GeometryCollection":
1529
+ return this.compareGeometryCollection(g1, g2);
1530
+ case "Feature":
1531
+ return this.compareFeature(g1, g2);
1532
+ case "FeatureCollection":
1533
+ return this.compareFeatureCollection(g1, g2);
1534
+ default:
1535
+ if (g1.type.startsWith("Multi")) {
1536
+ const g1s = explode$1(g1);
1537
+ const g2s = explode$1(
1538
+ g2
1539
+ );
1540
+ return g1s.every(
1541
+ (g1part) => g2s.some((g2part) => this.compare(g1part, g2part))
1542
+ );
1543
+ }
1544
+ }
1545
+ return false;
1546
+ }
1547
+ compareCoord(c1, c2) {
1548
+ return c1.length === c2.length && c1.every((c, i) => Math.abs(c - c2[i]) < this.precision);
1549
+ }
1550
+ compareLine(path1, path2, ind = 0, isPoly = false) {
1551
+ if (!sameLength(path1, path2)) {
1552
+ return false;
1553
+ }
1554
+ const p1 = path1;
1555
+ let p2 = path2;
1556
+ if (isPoly && !this.compareCoord(p1[0], p2[0])) {
1557
+ const startIndex = this.fixStartIndex(p2, p1);
1558
+ if (!startIndex) {
1559
+ return false;
1560
+ } else {
1561
+ p2 = startIndex;
1562
+ }
1563
+ }
1564
+ const sameDirection = this.compareCoord(p1[ind], p2[ind]);
1565
+ if (this.direction || sameDirection) {
1566
+ return this.comparePath(p1, p2);
1567
+ } else {
1568
+ if (this.compareCoord(p1[ind], p2[p2.length - (1 + ind)])) {
1569
+ return this.comparePath(p1.slice().reverse(), p2);
1570
+ }
1571
+ return false;
1572
+ }
1573
+ }
1574
+ fixStartIndex(sourcePath, targetPath) {
1575
+ let correctPath, ind = -1;
1576
+ for (let i = 0; i < sourcePath.length; i++) {
1577
+ if (this.compareCoord(sourcePath[i], targetPath[0])) {
1578
+ ind = i;
1579
+ break;
1580
+ }
1581
+ }
1582
+ if (ind >= 0) {
1583
+ correctPath = [].concat(
1584
+ sourcePath.slice(ind, sourcePath.length),
1585
+ sourcePath.slice(1, ind + 1)
1586
+ );
1587
+ }
1588
+ return correctPath;
1589
+ }
1590
+ comparePath(p1, p2) {
1591
+ return p1.every((c, i) => this.compareCoord(c, p2[i]));
1592
+ }
1593
+ comparePolygon(g1, g2) {
1594
+ if (this.compareLine(g1.coordinates[0], g2.coordinates[0], 1, true)) {
1595
+ const holes1 = g1.coordinates.slice(1, g1.coordinates.length);
1596
+ const holes2 = g2.coordinates.slice(1, g2.coordinates.length);
1597
+ return holes1.every(
1598
+ (h1) => holes2.some((h2) => this.compareLine(h1, h2, 1, true))
1599
+ );
1600
+ }
1601
+ return false;
1602
+ }
1603
+ compareGeometryCollection(g1, g2) {
1604
+ return sameLength(g1.geometries, g2.geometries) && this.compareBBox(g1, g2) && g1.geometries.every((g, i) => this.compare(g, g2.geometries[i]));
1605
+ }
1606
+ compareFeature(g1, g2) {
1607
+ return g1.id === g2.id && (this.compareProperties ? equal(g1.properties, g2.properties) : true) && this.compareBBox(g1, g2) && this.compare(g1.geometry, g2.geometry);
1608
+ }
1609
+ compareFeatureCollection(g1, g2) {
1610
+ return sameLength(g1.features, g2.features) && this.compareBBox(g1, g2) && g1.features.every((f, i) => this.compare(f, g2.features[i]));
1611
+ }
1612
+ compareBBox(g1, g2) {
1613
+ return Boolean(!g1.bbox && !g2.bbox) || (g1.bbox && g2.bbox ? this.compareCoord(g1.bbox, g2.bbox) : false);
1614
+ }
1615
+ };
1616
+ __name(_GeojsonEquality, "GeojsonEquality");
1617
+ var GeojsonEquality = _GeojsonEquality;
1618
+ function sameLength(g1, g2) {
1619
+ return g1.coordinates ? g1.coordinates.length === g2.coordinates.length : g1.length === g2.length;
1620
+ }
1621
+ __name(sameLength, "sameLength");
1622
+ function explode$1(g) {
1623
+ return g.coordinates.map((part) => ({
1624
+ type: g.type.replace("Multi", ""),
1625
+ coordinates: part
1626
+ }));
1627
+ }
1628
+ __name(explode$1, "explode");
1629
+ function geojsonEquality(g1, g2, opts) {
1630
+ const eq = new GeojsonEquality(opts);
1631
+ return eq.compare(g1, g2);
1632
+ }
1633
+ __name(geojsonEquality, "geojsonEquality");
1634
+ function equal(object1, object2) {
1635
+ if (object1 === null && object2 === null) {
1636
+ return true;
1637
+ }
1638
+ if (object1 === null || object2 === null) {
1639
+ return false;
1640
+ }
1641
+ const objKeys1 = Object.keys(object1);
1642
+ const objKeys2 = Object.keys(object2);
1643
+ if (objKeys1.length !== objKeys2.length) return false;
1644
+ for (var key of objKeys1) {
1645
+ const value1 = object1[key];
1646
+ const value2 = object2[key];
1647
+ const isObjects = isObject(value1) && isObject(value2);
1648
+ if (isObjects && !equal(value1, value2) || !isObjects && value1 !== value2) {
1649
+ return false;
1650
+ }
1651
+ }
1652
+ return true;
1653
+ }
1654
+ __name(equal, "equal");
1655
+ var isObject = /* @__PURE__ */ __name((object) => {
1656
+ return object != null && typeof object === "object";
1657
+ }, "isObject");
1501
1658
  function cleanCoords(geojson, options = {}) {
1502
1659
  var mutate = typeof options === "object" ? options.mutate : options;
1503
1660
  if (!geojson) throw new Error("geojson is required");
@@ -1611,6 +1768,19 @@ function isPointOnLineSegment(start, end, point2) {
1611
1768
  return dxl > 0 ? startX <= x && x <= endX : endX <= x && x <= startX;
1612
1769
  else return dyl > 0 ? startY <= y && y <= endY : endY <= y && y <= startY;
1613
1770
  }
1771
+ function booleanEqual(feature1, feature2, options = {}) {
1772
+ let precision2 = options.precision;
1773
+ precision2 = precision2 === void 0 || precision2 === null || isNaN(precision2) ? 6 : precision2;
1774
+ if (typeof precision2 !== "number" || !(precision2 >= 0)) {
1775
+ throw new Error("precision must be a positive number");
1776
+ }
1777
+ const type1 = getGeom(feature1).type;
1778
+ const type2 = getGeom(feature2).type;
1779
+ if (type1 !== type2) return false;
1780
+ return geojsonEquality(cleanCoords(feature1), cleanCoords(feature2), {
1781
+ precision: precision2
1782
+ });
1783
+ }
1614
1784
  function quickselect(arr, k, left, right, compare2) {
1615
1785
  quickselectStep(arr, k, left || 0, right || arr.length - 1, compare2 || defaultCompare$1);
1616
1786
  }
@@ -15011,7 +15181,7 @@ function simplify(points, tolerance, highestQuality) {
15011
15181
  function simplify2(geojson, options = {}) {
15012
15182
  var _a2, _b2, _c;
15013
15183
  options = options != null ? options : {};
15014
- if (!isObject(options)) throw new Error("options is invalid");
15184
+ if (!isObject$1(options)) throw new Error("options is invalid");
15015
15185
  const tolerance = (_a2 = options.tolerance) != null ? _a2 : 1;
15016
15186
  const highQuality = (_b2 = options.highQuality) != null ? _b2 : false;
15017
15187
  const mutate = (_c = options.mutate) != null ? _c : false;
@@ -15878,22 +16048,16 @@ class TurfHelper {
15878
16048
  } catch (error) {
15879
16049
  }
15880
16050
  try {
15881
- const coords1 = getCoords(polygon2);
15882
- const coords2 = getCoords(latlngs);
15883
- for (const ring2 of coords2) {
15884
- for (const coord of ring2[0]) {
15885
- const point$1 = point(coord);
15886
- if (booleanPointInPolygon(point$1, polygon2)) {
15887
- return true;
15888
- }
16051
+ const points1 = explode(polygon2);
16052
+ const points2 = explode(latlngs);
16053
+ for (const point2 of points2.features) {
16054
+ if (booleanPointInPolygon(point2, polygon2)) {
16055
+ return true;
15889
16056
  }
15890
16057
  }
15891
- for (const ring1 of coords1) {
15892
- for (const coord of ring1[0]) {
15893
- const point$1 = point(coord);
15894
- if (booleanPointInPolygon(point$1, latlngs)) {
15895
- return true;
15896
- }
16058
+ for (const point2 of points1.features) {
16059
+ if (booleanPointInPolygon(point2, latlngs)) {
16060
+ return true;
15897
16061
  }
15898
16062
  }
15899
16063
  } catch (error) {
@@ -15984,12 +16148,47 @@ class TurfHelper {
15984
16148
  return true;
15985
16149
  }
15986
16150
  }
16151
+ /**
16152
+ * Normalize various point-like inputs into a GeoJSON Feature<Point>.
16153
+ * Supports GeoJSON Feature<Point>, Turf Position [lng, lat], and Leaflet LatLngLiteral.
16154
+ */
16155
+ toPointFeature(point$1) {
16156
+ var _a2, _b2;
16157
+ if ((point$1 == null ? void 0 : point$1.type) === "Feature" && ((_a2 = point$1.geometry) == null ? void 0 : _a2.type) === "Point") {
16158
+ return point$1;
16159
+ }
16160
+ if (Array.isArray(point$1) && point$1.length >= 2 && typeof point$1[0] === "number" && typeof point$1[1] === "number") {
16161
+ return point(point$1);
16162
+ }
16163
+ if (typeof (point$1 == null ? void 0 : point$1.lat) === "number" && typeof (point$1 == null ? void 0 : point$1.lng) === "number") {
16164
+ const p = point$1;
16165
+ return point([p.lng, p.lat]);
16166
+ }
16167
+ if (((_b2 = point$1 == null ? void 0 : point$1.geometry) == null ? void 0 : _b2.coordinates) && Array.isArray(point$1.geometry.coordinates)) {
16168
+ return point(point$1.geometry.coordinates);
16169
+ }
16170
+ throw new Error("Unsupported point format provided to toPointFeature");
16171
+ }
16172
+ /**
16173
+ * Check if a point lies within a polygon.
16174
+ * Accepts Feature<Point>, Turf Position [lng, lat], or Leaflet LatLngLiteral.
16175
+ * This normalization prevents noisy console warnings in tests.
16176
+ */
16177
+ isPointInsidePolygon(point2, polygon2) {
16178
+ try {
16179
+ const pointFeature = this.toPointFeature(point2);
16180
+ return booleanPointInPolygon(pointFeature, polygon2);
16181
+ } catch (error) {
16182
+ return false;
16183
+ }
16184
+ }
15987
16185
  /**
15988
16186
  * Checks if two polygons are equal.
15989
16187
  * @param polygon1 First polygon.
15990
16188
  * @param polygon2 Second polygon.
15991
16189
  */
15992
16190
  equalPolygons(polygon1, polygon2) {
16191
+ return booleanEqual(polygon1, polygon2);
15993
16192
  }
15994
16193
  convertToBoundingBoxPolygon(polygon2) {
15995
16194
  const bbox$1 = bbox(polygon2.geometry);
@@ -16000,37 +16199,31 @@ class TurfHelper {
16000
16199
  const multi = multiPolygon([poly.geometry.coordinates]);
16001
16200
  return multi;
16002
16201
  }
16003
- injectPointToPolygon(polygon2, point2) {
16202
+ injectPointToPolygon(polygon2, point2, ringIndex) {
16004
16203
  const newPoly = JSON.parse(JSON.stringify(polygon2));
16204
+ let targetRing;
16005
16205
  if (newPoly.geometry.type === "MultiPolygon") {
16006
- const coordinates = newPoly.geometry.coordinates[0][0];
16007
- let minDistance = Infinity;
16008
- let insertIndex = 0;
16009
- for (let i = 0; i < coordinates.length - 1; i++) {
16010
- const edgeStart = coordinates[i];
16011
- const edgeEnd = coordinates[i + 1];
16012
- const distance2 = this.distanceToLineSegment(point2, edgeStart, edgeEnd);
16013
- if (distance2 < minDistance) {
16014
- minDistance = distance2;
16015
- insertIndex = i + 1;
16016
- }
16017
- }
16018
- coordinates.splice(insertIndex, 0, point2);
16206
+ targetRing = newPoly.geometry.coordinates[0][ringIndex];
16019
16207
  } else if (newPoly.geometry.type === "Polygon") {
16020
- const coordinates = newPoly.geometry.coordinates[0];
16021
- let minDistance = Infinity;
16022
- let insertIndex = 0;
16023
- for (let i = 0; i < coordinates.length - 1; i++) {
16024
- const edgeStart = coordinates[i];
16025
- const edgeEnd = coordinates[i + 1];
16026
- const distance2 = this.distanceToLineSegment(point2, edgeStart, edgeEnd);
16027
- if (distance2 < minDistance) {
16028
- minDistance = distance2;
16029
- insertIndex = i + 1;
16030
- }
16208
+ targetRing = newPoly.geometry.coordinates[ringIndex];
16209
+ } else {
16210
+ return newPoly;
16211
+ }
16212
+ if (!targetRing) {
16213
+ return newPoly;
16214
+ }
16215
+ let minDistance = Infinity;
16216
+ let insertIndex = 0;
16217
+ for (let i = 0; i < targetRing.length - 1; i++) {
16218
+ const edgeStart = targetRing[i];
16219
+ const edgeEnd = targetRing[i + 1];
16220
+ const distance2 = this.distanceToLineSegment(point2, edgeStart, edgeEnd);
16221
+ if (distance2 < minDistance) {
16222
+ minDistance = distance2;
16223
+ insertIndex = i + 1;
16031
16224
  }
16032
- coordinates.splice(insertIndex, 0, point2);
16033
16225
  }
16226
+ targetRing.splice(insertIndex, 0, point2);
16034
16227
  return newPoly;
16035
16228
  }
16036
16229
  distanceToLineSegment(point2, lineStart, lineEnd) {
@@ -17285,11 +17478,10 @@ class EventManager {
17285
17478
  * @param callback - The callback to execute when the event is emitted.
17286
17479
  */
17287
17480
  on(event, callback) {
17288
- var _a2;
17289
17481
  if (!this.eventListeners.has(event)) {
17290
17482
  this.eventListeners.set(event, []);
17291
17483
  }
17292
- (_a2 = this.eventListeners.get(event)) == null ? void 0 : _a2.push(callback);
17484
+ this.eventListeners.get(event).push(callback);
17293
17485
  }
17294
17486
  /**
17295
17487
  * Unregister an event listener.
@@ -17297,13 +17489,11 @@ class EventManager {
17297
17489
  * @param callback - The specific callback to remove.
17298
17490
  */
17299
17491
  off(event, callback) {
17300
- if (this.eventListeners.has(event)) {
17301
- const listeners = this.eventListeners.get(event);
17302
- if (listeners) {
17303
- const index = listeners.indexOf(callback);
17304
- if (index > -1) {
17305
- listeners.splice(index, 1);
17306
- }
17492
+ const listeners = this.eventListeners.get(event);
17493
+ if (listeners) {
17494
+ const index = listeners.indexOf(callback);
17495
+ if (index > -1) {
17496
+ listeners.splice(index, 1);
17307
17497
  }
17308
17498
  }
17309
17499
  }
@@ -17315,7 +17505,9 @@ class EventManager {
17315
17505
  emit(event, data) {
17316
17506
  var _a2;
17317
17507
  if (this.eventListeners.has(event)) {
17318
- (_a2 = this.eventListeners.get(event)) == null ? void 0 : _a2.forEach((callback) => callback(data));
17508
+ (_a2 = this.eventListeners.get(event)) == null ? void 0 : _a2.forEach((callback) => {
17509
+ callback(data);
17510
+ });
17319
17511
  }
17320
17512
  }
17321
17513
  }
@@ -17514,6 +17706,7 @@ class PolygonDrawManager {
17514
17706
  // Point-to-Point drawing state
17515
17707
  __publicField(this, "p2pMarkers", []);
17516
17708
  __publicField(this, "isModifierKeyHeld", false);
17709
+ __publicField(this, "markerModifierHandlers", /* @__PURE__ */ new WeakMap());
17517
17710
  this.turfHelper = dependencies.turfHelper;
17518
17711
  this.map = dependencies.map;
17519
17712
  this.config = dependencies.config;
@@ -17543,7 +17736,7 @@ class PolygonDrawManager {
17543
17736
  if (!tracerGeoJSON || !tracerGeoJSON.geometry || !tracerGeoJSON.geometry.coordinates || tracerGeoJSON.geometry.coordinates.length < 3) {
17544
17737
  return {
17545
17738
  success: false,
17546
- error: "Not enough points to form a valid polygon"
17739
+ error: "Not enough points to form a valid polygon. Event: " + JSON.stringify(event)
17547
17740
  };
17548
17741
  }
17549
17742
  let geoPos;
@@ -17552,13 +17745,13 @@ class PolygonDrawManager {
17552
17745
  } catch (error) {
17553
17746
  return {
17554
17747
  success: false,
17555
- error: error instanceof Error ? error.message : "Failed to create polygon from trace"
17748
+ error: (error instanceof Error ? error.message : "Failed to create polygon from trace") + ". Event: " + JSON.stringify(event)
17556
17749
  };
17557
17750
  }
17558
17751
  if (!geoPos || !geoPos.geometry || !geoPos.geometry.coordinates || geoPos.geometry.coordinates.length === 0) {
17559
17752
  return {
17560
17753
  success: false,
17561
- error: "Invalid polygon created from trace"
17754
+ error: "Invalid polygon created from trace. Event: " + JSON.stringify(event)
17562
17755
  };
17563
17756
  }
17564
17757
  this.eventManager.emit("polydraw:polygon:created", {
@@ -17624,8 +17817,8 @@ class PolygonDrawManager {
17624
17817
  if (this.p2pMarkers.length >= 3) {
17625
17818
  const element = pointMarker.getElement();
17626
17819
  if (element) {
17627
- element.style.backgroundColor = "#4CAF50";
17628
- element.style.borderColor = "#4CAF50";
17820
+ element.style.backgroundColor = this.config.colors.p2p.closingMarker;
17821
+ element.style.borderColor = this.config.colors.p2p.closingMarker;
17629
17822
  element.style.cursor = "pointer";
17630
17823
  element.title = "Click to close polygon";
17631
17824
  }
@@ -17749,7 +17942,7 @@ class PolygonDrawManager {
17749
17942
  if (this.p2pMarkers.length >= 2) {
17750
17943
  try {
17751
17944
  this.tracer.setStyle({
17752
- color: this.config.polyLineOptions.color,
17945
+ color: this.config.colors.polyline,
17753
17946
  dashArray: "5, 5"
17754
17947
  });
17755
17948
  } catch (error) {
@@ -17819,8 +18012,8 @@ class PolygonDrawManager {
17819
18012
  if (this.p2pMarkers.length >= 3) {
17820
18013
  const element2 = firstMarker.getElement();
17821
18014
  if (element2) {
17822
- element2.style.backgroundColor = "#4CAF50";
17823
- element2.style.borderColor = "#4CAF50";
18015
+ element2.style.backgroundColor = this.config.colors.p2p.closingMarker;
18016
+ element2.style.borderColor = this.config.colors.p2p.closingMarker;
17824
18017
  element2.style.cursor = "pointer";
17825
18018
  element2.title = "Click to close polygon";
17826
18019
  }
@@ -17871,7 +18064,7 @@ class PolygonDrawManager {
17871
18064
  }
17872
18065
  }
17873
18066
  };
17874
- marker._polydrawModifierHandler = checkModifierAndUpdate;
18067
+ this.markerModifierHandlers.set(marker, checkModifierAndUpdate);
17875
18068
  document.addEventListener("keydown", checkModifierAndUpdate);
17876
18069
  document.addEventListener("keyup", checkModifierAndUpdate);
17877
18070
  element.addEventListener("mousemove", checkModifierAndUpdate);
@@ -17882,12 +18075,12 @@ class PolygonDrawManager {
17882
18075
  container.style.cursor = "";
17883
18076
  } catch (error) {
17884
18077
  }
17885
- const handler = marker._polydrawModifierHandler;
18078
+ const handler = this.markerModifierHandlers.get(marker);
17886
18079
  if (handler) {
17887
18080
  document.removeEventListener("keydown", handler);
17888
18081
  document.removeEventListener("keyup", handler);
17889
18082
  element.removeEventListener("mousemove", handler);
17890
- delete marker._polydrawModifierHandler;
18083
+ this.markerModifierHandlers.delete(marker);
17891
18084
  }
17892
18085
  }
17893
18086
  }
@@ -17938,7 +18131,7 @@ class PolygonGeometryManager {
17938
18131
  geometry: { type: "Point", coordinates: coord },
17939
18132
  properties: {}
17940
18133
  };
17941
- if (this.turfHelper.isPolygonCompletelyWithin(point2, polygon1)) {
18134
+ if (this.turfHelper.isPointInsidePolygon(point2, polygon1)) {
17942
18135
  return true;
17943
18136
  }
17944
18137
  }
@@ -17950,7 +18143,7 @@ class PolygonGeometryManager {
17950
18143
  geometry: { type: "Point", coordinates: coord },
17951
18144
  properties: {}
17952
18145
  };
17953
- if (this.turfHelper.isPolygonCompletelyWithin(point2, polygon2)) {
18146
+ if (this.turfHelper.isPointInsidePolygon(point2, polygon2)) {
17954
18147
  return true;
17955
18148
  }
17956
18149
  }
@@ -17966,19 +18159,8 @@ class PolygonGeometryManager {
17966
18159
  try {
17967
18160
  let result = newPolygon;
17968
18161
  for (const polygon2 of polygons) {
17969
- const shouldCreateDonut = this.shouldCreateDonutPolygon(result, polygon2);
17970
- if (shouldCreateDonut) {
17971
- const donutPolygon = this.createDonutPolygon(result, polygon2);
17972
- if (donutPolygon) {
17973
- result = donutPolygon;
17974
- } else {
17975
- const union3 = this.turfHelper.union(result, polygon2);
17976
- result = union3;
17977
- }
17978
- } else {
17979
- const union3 = this.turfHelper.union(result, polygon2);
17980
- result = union3;
17981
- }
18162
+ const union3 = this.turfHelper.union(result, polygon2);
18163
+ result = union3;
17982
18164
  }
17983
18165
  return {
17984
18166
  success: true,
@@ -18289,93 +18471,6 @@ class PolygonGeometryManager {
18289
18471
  return null;
18290
18472
  }
18291
18473
  }
18292
- /**
18293
- * Determine if two polygons should create a donut instead of a regular union
18294
- */
18295
- shouldCreateDonutPolygon(polygon1, polygon2) {
18296
- try {
18297
- return false;
18298
- } catch (error) {
18299
- console.warn("Error in shouldCreateDonutPolygon:", error.message);
18300
- return false;
18301
- }
18302
- }
18303
- /**
18304
- * Create a donut polygon from two intersecting polygons
18305
- */
18306
- createDonutPolygon(polygon1, polygon2) {
18307
- try {
18308
- const area1 = this.turfHelper.getPolygonArea(polygon1);
18309
- const area2 = this.turfHelper.getPolygonArea(polygon2);
18310
- let outerPolygon;
18311
- let innerPolygon;
18312
- if (area1 > area2) {
18313
- outerPolygon = polygon1;
18314
- innerPolygon = polygon2;
18315
- } else {
18316
- outerPolygon = polygon2;
18317
- innerPolygon = polygon1;
18318
- }
18319
- const innerWithinOuter = this.turfHelper.isPolygonCompletelyWithin(
18320
- innerPolygon,
18321
- outerPolygon
18322
- );
18323
- if (innerWithinOuter) {
18324
- return this.createDonutFromContainment(outerPolygon, innerPolygon);
18325
- } else {
18326
- return this.createDonutFromIntersection(outerPolygon, innerPolygon);
18327
- }
18328
- } catch (error) {
18329
- console.warn("Error in createDonutPolygon:", error.message);
18330
- return null;
18331
- }
18332
- }
18333
- /**
18334
- * Create donut when one polygon is completely within another
18335
- */
18336
- createDonutFromContainment(outerPolygon, innerPolygon) {
18337
- try {
18338
- const outerCoords = this.turfHelper.getCoords(outerPolygon);
18339
- const innerCoords = this.turfHelper.getCoords(innerPolygon);
18340
- const donutCoords = [
18341
- outerCoords[0][0],
18342
- // Outer ring
18343
- innerCoords[0][0]
18344
- // Inner ring as hole
18345
- ];
18346
- return {
18347
- type: "Feature",
18348
- geometry: {
18349
- type: "Polygon",
18350
- coordinates: donutCoords
18351
- },
18352
- properties: {}
18353
- };
18354
- } catch (error) {
18355
- console.warn("Error in createDonutFromContainment:", error.message);
18356
- return null;
18357
- }
18358
- }
18359
- /**
18360
- * Create donut from intersecting polygons (C-to-O scenario)
18361
- */
18362
- createDonutFromIntersection(polygon1, polygon2) {
18363
- try {
18364
- const union3 = this.turfHelper.union(polygon1, polygon2);
18365
- if (!union3) {
18366
- return null;
18367
- }
18368
- const intersection3 = this.turfHelper.getIntersection(polygon1, polygon2);
18369
- if (!intersection3) {
18370
- return union3;
18371
- }
18372
- const donut = this.turfHelper.polygonDifference(union3, intersection3);
18373
- return donut;
18374
- } catch (error) {
18375
- console.warn("Error in createDonutFromIntersection:", error.message);
18376
- return null;
18377
- }
18378
- }
18379
18474
  }
18380
18475
  class IconFactory {
18381
18476
  /**
@@ -18390,6 +18485,8 @@ class IconFactory {
18390
18485
  }
18391
18486
  class PolygonInteractionManager {
18392
18487
  constructor(dependencies, featureGroupAccess) {
18488
+ __publicField(this, "markerFeatureGroupMap", /* @__PURE__ */ new WeakMap());
18489
+ __publicField(this, "markerModifierHandlers", /* @__PURE__ */ new WeakMap());
18393
18490
  __publicField(this, "_activeMarker", null);
18394
18491
  __publicField(this, "isDraggingMarker", false);
18395
18492
  __publicField(this, "turfHelper");
@@ -18413,7 +18510,7 @@ class PolygonInteractionManager {
18413
18510
  const polygon2 = this.currentDragPolygon;
18414
18511
  const dragData = polygon2._polydrawDragData;
18415
18512
  const eventToCheck = e.originalEvent && "metaKey" in e.originalEvent ? e.originalEvent : e;
18416
- const currentModifierState = this.detectModifierKey(eventToCheck);
18513
+ const currentModifierState = this.detectDragSubtractModifierKey(eventToCheck);
18417
18514
  if (currentModifierState !== this.currentModifierDragMode) {
18418
18515
  this.handleModifierToggleDuringDrag(eventToCheck);
18419
18516
  }
@@ -18458,8 +18555,8 @@ class PolygonInteractionManager {
18458
18555
  if (!this.isModifierKeyHeld) return;
18459
18556
  const element = e.target;
18460
18557
  if (element) {
18461
- element.style.backgroundColor = "#D9460F";
18462
- element.style.borderColor = "#D9460F";
18558
+ element.style.backgroundColor = this.config.colors.edgeDeletion.hover;
18559
+ element.style.borderColor = this.config.colors.edgeDeletion.hover;
18463
18560
  element.classList.add("edge-deletion-hover");
18464
18561
  }
18465
18562
  });
@@ -18519,7 +18616,7 @@ class PolygonInteractionManager {
18519
18616
  zIndexOffset: this.config.markers.markerIcon.zIndexOffset ?? this.config.markers.zIndexOffset
18520
18617
  });
18521
18618
  featureGroup.addLayer(marker).addTo(this.map);
18522
- marker._polydrawFeatureGroup = featureGroup;
18619
+ this.markerFeatureGroupMap.set(marker, featureGroup);
18523
18620
  marker.on("add", () => {
18524
18621
  const el2 = marker.getElement();
18525
18622
  if (el2) el2.style.pointerEvents = "auto";
@@ -18536,7 +18633,7 @@ class PolygonInteractionManager {
18536
18633
  this._activeMarker = marker;
18537
18634
  });
18538
18635
  marker.on("dragend", (e) => {
18539
- const fg = marker._polydrawFeatureGroup;
18636
+ const fg = this.markerFeatureGroupMap.get(marker);
18540
18637
  if (this.modeManager.canPerformAction("markerDrag") && fg) {
18541
18638
  this.markerDragEnd(fg);
18542
18639
  }
@@ -18560,7 +18657,7 @@ class PolygonInteractionManager {
18560
18657
  e.stopPropagation();
18561
18658
  marker.fire("click");
18562
18659
  if (this.isDraggingMarker && !isSpecialMarker) {
18563
- const fg = marker._polydrawFeatureGroup;
18660
+ const fg = this.markerFeatureGroupMap.get(marker);
18564
18661
  if (this.modeManager.canPerformAction("markerDrag") && fg) {
18565
18662
  this.markerDragEnd(fg);
18566
18663
  }
@@ -18660,12 +18757,11 @@ class PolygonInteractionManager {
18660
18757
  this._activeMarker = marker;
18661
18758
  });
18662
18759
  marker.on("click", (e) => {
18663
- var _a2;
18664
18760
  if (this.modeManager.isInOffMode()) {
18665
- if (this.isModifierKeyPressed(e.originalEvent)) {
18666
- const poly = (_a2 = featureGroup.getLayers().find((layer) => layer instanceof L.Polygon)) == null ? void 0 : _a2.toGeoJSON();
18667
- if (poly) {
18668
- this.elbowClicked(e, poly);
18761
+ if (this.isEdgeDeletionModifierKeyPressed(e.originalEvent)) {
18762
+ const polygonLayer = featureGroup.getLayers().find((layer) => layer instanceof L.Polygon);
18763
+ if (polygonLayer) {
18764
+ this.elbowClicked(e, polygonLayer, marker.getLatLng());
18669
18765
  }
18670
18766
  } else {
18671
18767
  if (i === deleteMarkerIdx && this.config.markers.deleteMarker) {
@@ -18686,88 +18782,291 @@ class PolygonInteractionManager {
18686
18782
  }
18687
18783
  }
18688
18784
  /**
18689
- * Add hole markers to a polygon feature group
18785
+ * Add hole markers to a polygon feature group, with configurable special markers.
18690
18786
  */
18691
18787
  addHoleMarkers(latlngs, featureGroup) {
18788
+ var _a2, _b2, _c;
18789
+ const holeMenuEnabled = ((_a2 = this.config.markers.holeMarkers) == null ? void 0 : _a2.menuMarker) ?? false;
18790
+ const holeDeleteEnabled = ((_b2 = this.config.markers.holeMarkers) == null ? void 0 : _b2.deleteMarker) ?? false;
18791
+ const holeInfoEnabled = ((_c = this.config.markers.holeMarkers) == null ? void 0 : _c.infoMarker) ?? false;
18792
+ let menuMarkerIdx = this.getMarkerIndex(latlngs, this.config.markers.markerMenuIcon.position);
18793
+ let deleteMarkerIdx = this.getMarkerIndex(
18794
+ latlngs,
18795
+ this.config.markers.markerDeleteIcon.position
18796
+ );
18797
+ let infoMarkerIdx = this.getMarkerIndex(latlngs, this.config.markers.markerInfoIcon.position);
18798
+ const separatedIndices = this.ensureMarkerSeparation(latlngs.length, {
18799
+ menu: { index: menuMarkerIdx, enabled: holeMenuEnabled },
18800
+ delete: { index: deleteMarkerIdx, enabled: holeDeleteEnabled },
18801
+ info: { index: infoMarkerIdx, enabled: holeInfoEnabled }
18802
+ });
18803
+ menuMarkerIdx = separatedIndices.menu;
18804
+ deleteMarkerIdx = separatedIndices.delete;
18805
+ infoMarkerIdx = separatedIndices.info;
18692
18806
  latlngs.forEach((latlng, i) => {
18693
- const iconClasses = this.config.markers.holeIcon.styleClasses;
18807
+ let iconClasses = this.config.markers.holeIcon.styleClasses;
18808
+ if (i === menuMarkerIdx && holeMenuEnabled) {
18809
+ iconClasses = this.config.markers.markerMenuIcon.styleClasses;
18810
+ }
18811
+ if (i === deleteMarkerIdx && holeDeleteEnabled) {
18812
+ iconClasses = this.config.markers.markerDeleteIcon.styleClasses;
18813
+ }
18814
+ if (i === infoMarkerIdx && holeInfoEnabled) {
18815
+ iconClasses = this.config.markers.markerInfoIcon.styleClasses;
18816
+ }
18694
18817
  const processedClasses = Array.isArray(iconClasses) ? iconClasses : [iconClasses];
18818
+ const isSpecialMarker = i === menuMarkerIdx && holeMenuEnabled || i === deleteMarkerIdx && holeDeleteEnabled || i === infoMarkerIdx && holeInfoEnabled;
18695
18819
  const marker = new L.Marker(latlng, {
18696
18820
  icon: this.createDivIcon(processedClasses),
18697
- draggable: true,
18698
- title: this.getLatLngInfoString(latlng),
18821
+ draggable: this.config.modes.dragElbow,
18822
+ title: this.config.markers.coordsTitle ? this.getLatLngInfoString(latlng) : "",
18699
18823
  zIndexOffset: this.config.markers.holeIcon.zIndexOffset ?? this.config.markers.zIndexOffset
18700
18824
  });
18701
18825
  featureGroup.addLayer(marker).addTo(this.map);
18826
+ this.markerFeatureGroupMap.set(marker, featureGroup);
18702
18827
  marker.on("add", () => {
18703
- const el = marker.getElement();
18704
- if (el) el.style.pointerEvents = "auto";
18828
+ const el2 = marker.getElement();
18829
+ if (el2) el2.style.pointerEvents = "auto";
18705
18830
  });
18706
18831
  marker.on("click", (e) => {
18707
- var _a2, _b2;
18708
- (_b2 = (_a2 = e.originalEvent) == null ? void 0 : _a2.stopPropagation) == null ? void 0 : _b2.call(_a2);
18709
- L.DomEvent.stopPropagation(e);
18710
- });
18711
- marker.on("dragend", (e) => {
18712
- L.DomEvent.stopPropagation(e);
18832
+ var _a3, _b3;
18833
+ if (this.isDraggingMarker) {
18834
+ (_b3 = (_a3 = e.originalEvent) == null ? void 0 : _a3.stopPropagation) == null ? void 0 : _b3.call(_a3);
18835
+ L.DomEvent.stopPropagation(e);
18836
+ }
18713
18837
  });
18714
- marker.on("drag", (e) => {
18715
- this.markerDrag(featureGroup);
18838
+ marker.on("dragstart", () => {
18839
+ this.isDraggingMarker = true;
18840
+ this._activeMarker = marker;
18716
18841
  });
18717
18842
  marker.on("dragend", (e) => {
18718
- this.markerDragEnd(featureGroup);
18843
+ const fg = this.markerFeatureGroupMap.get(marker);
18844
+ if (this.modeManager.canPerformAction("markerDrag") && fg) {
18845
+ this.markerDragEnd(fg);
18846
+ }
18847
+ this._activeMarker = null;
18848
+ L.DomEvent.stopPropagation(e);
18849
+ setTimeout(() => {
18850
+ this.isDraggingMarker = false;
18851
+ }, 10);
18719
18852
  });
18720
- });
18721
- }
18722
- /**
18723
- * Add edge click listeners to a polygon
18724
- */
18725
- addEdgeClickListeners(polygon2, featureGroup) {
18726
- const rawLatLngs = polygon2.getLatLngs();
18727
- let processedRings;
18728
- if (Array.isArray(rawLatLngs) && rawLatLngs.length > 0) {
18729
- if (Array.isArray(rawLatLngs[0])) {
18730
- if (Array.isArray(rawLatLngs[0][0]) && rawLatLngs[0][0].length > 0) {
18731
- const firstCoord = rawLatLngs[0][0][0];
18732
- if (firstCoord && typeof firstCoord === "object" && "lat" in firstCoord) {
18733
- processedRings = rawLatLngs[0];
18734
- } else {
18735
- processedRings = rawLatLngs[0];
18853
+ const el = marker.getElement();
18854
+ if (el) {
18855
+ el.addEventListener(
18856
+ "touchstart",
18857
+ (e) => {
18858
+ e.stopPropagation();
18859
+ },
18860
+ { passive: true }
18861
+ );
18862
+ el.addEventListener("touchend", (e) => {
18863
+ e.preventDefault();
18864
+ e.stopPropagation();
18865
+ marker.fire("click");
18866
+ if (this.isDraggingMarker && !isSpecialMarker) {
18867
+ const fg = this.markerFeatureGroupMap.get(marker);
18868
+ if (this.modeManager.canPerformAction("markerDrag") && fg) {
18869
+ this.markerDragEnd(fg);
18870
+ }
18736
18871
  }
18737
- } else if (rawLatLngs[0][0] && typeof rawLatLngs[0][0] === "object" && "lat" in rawLatLngs[0][0]) {
18738
- processedRings = rawLatLngs;
18739
- } else {
18740
- processedRings = rawLatLngs[0];
18741
- }
18742
- } else if (rawLatLngs[0] && typeof rawLatLngs[0] === "object" && "lat" in rawLatLngs[0]) {
18743
- processedRings = [rawLatLngs];
18744
- } else {
18745
- processedRings = [rawLatLngs];
18872
+ this._activeMarker = null;
18873
+ });
18746
18874
  }
18747
- } else {
18748
- return;
18749
- }
18750
- processedRings.forEach((ring, ringIndex) => {
18751
- for (let i = 0; i < ring.length; i++) {
18752
- const edgeStart = ring[i];
18753
- const edgeEnd = ring[(i + 1) % ring.length];
18754
- if (edgeStart.lat === edgeEnd.lat && edgeStart.lng === edgeEnd.lng) {
18755
- continue;
18875
+ if (i === menuMarkerIdx || i === deleteMarkerIdx || i === infoMarkerIdx) {
18876
+ const element = marker.getElement();
18877
+ if (element) {
18878
+ element.style.zIndex = "10000";
18756
18879
  }
18757
- const edgePolyline = L.polyline([edgeStart, edgeEnd], {
18758
- color: "transparent",
18759
- weight: 10,
18760
- opacity: 0,
18761
- interactive: true
18762
- });
18763
- edgePolyline._polydrawEdgeInfo = {
18764
- ringIndex,
18765
- edgeIndex: i,
18766
- startPoint: edgeStart,
18767
- endPoint: edgeEnd,
18768
- parentPolygon: polygon2,
18769
- parentFeatureGroup: featureGroup
18770
- };
18880
+ }
18881
+ if (this.config.modes.dragElbow) {
18882
+ const createDragHandler = (fg) => () => {
18883
+ if (this.modeManager.canPerformAction("markerDrag")) {
18884
+ this.markerDrag(fg);
18885
+ }
18886
+ };
18887
+ marker.on("drag", createDragHandler(featureGroup));
18888
+ }
18889
+ if (i === menuMarkerIdx && holeMenuEnabled) {
18890
+ marker.options.zIndexOffset = this.config.markers.markerMenuIcon.zIndexOffset ?? this.config.markers.zIndexOffset;
18891
+ marker.on("click", () => {
18892
+ const ring = latlngs.map((pt) => [pt.lng, pt.lat]);
18893
+ ring.push(ring[0]);
18894
+ const holePolygon = {
18895
+ type: "Feature",
18896
+ properties: {},
18897
+ geometry: {
18898
+ type: "Polygon",
18899
+ coordinates: [ring]
18900
+ }
18901
+ };
18902
+ const centerOfMass2 = PolygonUtil.getCenterOfMass(holePolygon);
18903
+ const menuPopup = this.generateMenuMarkerPopup(latlngs, featureGroup);
18904
+ menuPopup.setLatLng(centerOfMass2).openOn(this.map);
18905
+ });
18906
+ marker.on("popupopen", (e) => {
18907
+ const popup = e.popup;
18908
+ const popupContent = popup.getElement();
18909
+ if (!popupContent) return;
18910
+ setTimeout(() => {
18911
+ const mapContainer = this.map.getContainer();
18912
+ const mapBounds = mapContainer.getBoundingClientRect();
18913
+ const popupBounds = popupContent.getBoundingClientRect();
18914
+ if (popupBounds.left < mapBounds.left) {
18915
+ popupContent.style.transform = `translateX(${mapBounds.left - popupBounds.left}px)`;
18916
+ } else if (popupBounds.right > mapBounds.right) {
18917
+ popupContent.style.transform = `translateX(${mapBounds.right - popupBounds.right}px)`;
18918
+ }
18919
+ }, 0);
18920
+ const container = this.map.getContainer();
18921
+ if (container) {
18922
+ container.style.touchAction = "manipulation";
18923
+ }
18924
+ });
18925
+ marker.on("popupclose", () => {
18926
+ const container = this.map.getContainer();
18927
+ if (container) {
18928
+ container.style.touchAction = "";
18929
+ }
18930
+ });
18931
+ }
18932
+ if (i === infoMarkerIdx && holeInfoEnabled) {
18933
+ const ring = latlngs.map((latlng2) => [latlng2.lng, latlng2.lat]);
18934
+ ring.push(ring[0]);
18935
+ const holePolygon = {
18936
+ type: "Feature",
18937
+ properties: {},
18938
+ geometry: {
18939
+ type: "Polygon",
18940
+ coordinates: [ring]
18941
+ }
18942
+ };
18943
+ const area2 = this.turfHelper.getPolygonArea(holePolygon);
18944
+ const perimeter = this.turfHelper.getPolygonPerimeter(holePolygon) * 1e3;
18945
+ marker.options.zIndexOffset = this.config.markers.markerInfoIcon.zIndexOffset ?? this.config.markers.zIndexOffset;
18946
+ marker.on("click", () => {
18947
+ const infoPopup = this.generateInfoMarkerPopup(area2, perimeter);
18948
+ infoPopup.setLatLng(latlng).openOn(this.map);
18949
+ });
18950
+ }
18951
+ marker.on("mousedown", (e) => {
18952
+ if (!this.modeManager.isInOffMode()) {
18953
+ L.DomEvent.stopPropagation(e);
18954
+ this.map.fire("mousedown", e);
18955
+ }
18956
+ this._activeMarker = marker;
18957
+ });
18958
+ marker.on("click", (e) => {
18959
+ if (this.modeManager.isInOffMode()) {
18960
+ if (this.isEdgeDeletionModifierKeyPressed(e.originalEvent)) {
18961
+ const polygonLayer = featureGroup.getLayers().find((layer) => layer instanceof L.Polygon);
18962
+ if (polygonLayer) {
18963
+ this.elbowClicked(e, polygonLayer, marker.getLatLng());
18964
+ }
18965
+ } else {
18966
+ if (i === deleteMarkerIdx && holeDeleteEnabled) {
18967
+ this.map.closePopup();
18968
+ const parentPolygon = featureGroup.getLayers().find((layer) => layer instanceof L.Polygon);
18969
+ if (parentPolygon) {
18970
+ const rawLatLngs = parentPolygon.getLatLngs();
18971
+ let rings = [];
18972
+ if (Array.isArray(rawLatLngs) && rawLatLngs.length > 0) {
18973
+ if (Array.isArray(rawLatLngs[0])) {
18974
+ const first = rawLatLngs[0];
18975
+ if (Array.isArray(first) && Array.isArray(first[0])) {
18976
+ rings = rawLatLngs[0];
18977
+ } else {
18978
+ rings = rawLatLngs;
18979
+ }
18980
+ } else {
18981
+ rings = [rawLatLngs];
18982
+ }
18983
+ }
18984
+ const target = marker.getLatLng();
18985
+ let holeIndex = -1;
18986
+ for (let r = 1; r < rings.length; r++) {
18987
+ if (rings[r].some((p) => p.lat === target.lat && p.lng === target.lng)) {
18988
+ holeIndex = r;
18989
+ break;
18990
+ }
18991
+ }
18992
+ if (holeIndex > 0) {
18993
+ const newRings = rings.filter((_, idx) => idx !== holeIndex);
18994
+ const coords = newRings.map((ring) => {
18995
+ const arr = ring.map((ll) => [ll.lng, ll.lat]);
18996
+ if (arr.length > 0) {
18997
+ const firstPt = arr[0];
18998
+ const lastPt = arr[arr.length - 1];
18999
+ if (firstPt[0] !== lastPt[0] || firstPt[1] !== lastPt[1]) {
19000
+ arr.push([firstPt[0], firstPt[1]]);
19001
+ }
19002
+ }
19003
+ return arr;
19004
+ });
19005
+ const newPolygon = this.turfHelper.getMultiPolygon([coords]);
19006
+ this.removeFeatureGroup(featureGroup);
19007
+ this.eventManager.emit("polydraw:polygon:updated", {
19008
+ operation: "removeHole",
19009
+ polygon: newPolygon
19010
+ });
19011
+ }
19012
+ }
19013
+ }
19014
+ }
19015
+ }
19016
+ });
19017
+ marker.on("mouseover", () => this.onMarkerHoverForEdgeDeletion(marker, true));
19018
+ marker.on("mouseout", () => this.onMarkerHoverForEdgeDeletion(marker, false));
19019
+ });
19020
+ }
19021
+ /**
19022
+ * Add edge click listeners to a polygon
19023
+ */
19024
+ addEdgeClickListeners(polygon2, featureGroup) {
19025
+ const rawLatLngs = polygon2.getLatLngs();
19026
+ let processedRings;
19027
+ if (Array.isArray(rawLatLngs) && rawLatLngs.length > 0) {
19028
+ if (Array.isArray(rawLatLngs[0])) {
19029
+ if (Array.isArray(rawLatLngs[0][0]) && rawLatLngs[0][0].length > 0) {
19030
+ const firstCoord = rawLatLngs[0][0][0];
19031
+ if (firstCoord && typeof firstCoord === "object" && "lat" in firstCoord) {
19032
+ processedRings = rawLatLngs[0];
19033
+ } else {
19034
+ processedRings = rawLatLngs[0];
19035
+ }
19036
+ } else if (rawLatLngs[0][0] && typeof rawLatLngs[0][0] === "object" && "lat" in rawLatLngs[0][0]) {
19037
+ processedRings = rawLatLngs;
19038
+ } else {
19039
+ processedRings = rawLatLngs[0];
19040
+ }
19041
+ } else if (rawLatLngs[0] && typeof rawLatLngs[0] === "object" && "lat" in rawLatLngs[0]) {
19042
+ processedRings = [rawLatLngs];
19043
+ } else {
19044
+ processedRings = [rawLatLngs];
19045
+ }
19046
+ } else {
19047
+ return;
19048
+ }
19049
+ processedRings.forEach((ring, ringIndex) => {
19050
+ for (let i = 0; i < ring.length; i++) {
19051
+ const edgeStart = ring[i];
19052
+ const edgeEnd = ring[(i + 1) % ring.length];
19053
+ if (edgeStart.lat === edgeEnd.lat && edgeStart.lng === edgeEnd.lng) {
19054
+ continue;
19055
+ }
19056
+ const edgePolyline = L.polyline([edgeStart, edgeEnd], {
19057
+ color: "transparent",
19058
+ weight: 10,
19059
+ opacity: 0,
19060
+ interactive: true
19061
+ });
19062
+ edgePolyline._polydrawEdgeInfo = {
19063
+ ringIndex,
19064
+ edgeIndex: i,
19065
+ startPoint: edgeStart,
19066
+ endPoint: edgeEnd,
19067
+ parentPolygon: polygon2,
19068
+ parentFeatureGroup: featureGroup
19069
+ };
18771
19070
  edgePolyline.on("click", (e) => {
18772
19071
  this.onEdgeClick(e, edgePolyline);
18773
19072
  });
@@ -18801,9 +19100,9 @@ class PolygonInteractionManager {
18801
19100
  if (!this.modeManager.canPerformAction("polygonDrag")) {
18802
19101
  return;
18803
19102
  }
18804
- L.DomEvent.stopPropagation(e);
18805
- L.DomEvent.preventDefault(e);
18806
- const isModifierPressed = this.detectModifierKey(e.originalEvent || e);
19103
+ L.DomEvent.stopPropagation(e.originalEvent);
19104
+ L.DomEvent.preventDefault(e.originalEvent);
19105
+ const isModifierPressed = this.detectDragSubtractModifierKey(e.originalEvent);
18807
19106
  this.currentModifierDragMode = isModifierPressed;
18808
19107
  this.isModifierKeyHeld = isModifierPressed;
18809
19108
  polygon2._polydrawDragData.isDragging = true;
@@ -18919,10 +19218,11 @@ class PolygonInteractionManager {
18919
19218
  }
18920
19219
  const poly = parentPolygon.toGeoJSON();
18921
19220
  if (poly.geometry.type === "MultiPolygon" || poly.geometry.type === "Polygon") {
18922
- const newPolygon = this.turfHelper.injectPointToPolygon(poly, [
18923
- newPoint.lng,
18924
- newPoint.lat
18925
- ]);
19221
+ const newPolygon = this.turfHelper.injectPointToPolygon(
19222
+ poly,
19223
+ [newPoint.lng, newPoint.lat],
19224
+ edgeInfo.ringIndex
19225
+ );
18926
19226
  if (newPolygon) {
18927
19227
  const polydrawPolygon = parentPolygon;
18928
19228
  const optimizationLevel = polydrawPolygon._polydrawOptimizationLevel || 0;
@@ -18942,7 +19242,7 @@ class PolygonInteractionManager {
18942
19242
  highlightEdgeOnHover(edgePolyline, isHovering) {
18943
19243
  if (isHovering) {
18944
19244
  edgePolyline.setStyle({
18945
- color: "#7a9441",
19245
+ color: this.config.colors.edgeHover,
18946
19246
  weight: 4,
18947
19247
  opacity: 1
18948
19248
  });
@@ -18954,49 +19254,79 @@ class PolygonInteractionManager {
18954
19254
  });
18955
19255
  }
18956
19256
  }
18957
- elbowClicked(e, poly) {
18958
- if (!this.config.modes.edgeDeletion) {
18959
- return;
18960
- }
18961
- if (!this.isModifierKeyPressed(e.originalEvent)) {
19257
+ elbowClicked(e, polygonLayer, forcedLatLng) {
19258
+ if (!this.config.modes.edgeDeletion) return;
19259
+ if (!this.isEdgeDeletionModifierKeyPressed(e.originalEvent)) return;
19260
+ const clickedLatLng = forcedLatLng ?? e.latlng;
19261
+ const rawLatLngs = polygonLayer.getLatLngs();
19262
+ let rings = [];
19263
+ if (Array.isArray(rawLatLngs) && rawLatLngs.length > 0) {
19264
+ if (Array.isArray(rawLatLngs[0])) {
19265
+ const first = rawLatLngs[0];
19266
+ if (Array.isArray(first) && Array.isArray(first[0])) {
19267
+ rings = rawLatLngs[0];
19268
+ } else {
19269
+ rings = rawLatLngs;
19270
+ }
19271
+ } else {
19272
+ rings = [rawLatLngs];
19273
+ }
19274
+ } else {
18962
19275
  return;
18963
19276
  }
18964
- const clickedLatLng = e.latlng;
18965
- const allRings = poly.geometry.coordinates[0];
18966
19277
  let targetRingIndex = -1;
18967
19278
  let targetVertexIndex = -1;
18968
- for (let ringIndex = 0; ringIndex < allRings.length; ringIndex++) {
18969
- const ring = allRings[ringIndex];
18970
- const vertexIndex = ring.findIndex(
18971
- (coord) => Math.abs(coord[1] - clickedLatLng.lat) < 1e-4 && Math.abs(coord[0] - clickedLatLng.lng) < 1e-4
18972
- );
18973
- if (vertexIndex !== -1) {
18974
- targetRingIndex = ringIndex;
18975
- targetVertexIndex = vertexIndex;
18976
- break;
19279
+ for (let r = 0; r < rings.length; r++) {
19280
+ const ring = rings[r];
19281
+ for (let v = 0; v < ring.length; v++) {
19282
+ const p = ring[v];
19283
+ if (p.lat === clickedLatLng.lat && p.lng === clickedLatLng.lng) {
19284
+ targetRingIndex = r;
19285
+ targetVertexIndex = v;
19286
+ break;
19287
+ }
18977
19288
  }
19289
+ if (targetRingIndex !== -1) break;
18978
19290
  }
18979
19291
  if (targetRingIndex === -1 || targetVertexIndex === -1) {
18980
19292
  return;
18981
19293
  }
18982
- const targetRing = allRings[targetRingIndex];
18983
- if (targetRing.length <= 4) {
19294
+ const targetRing = rings[targetRingIndex];
19295
+ if (targetRing.length <= 3) {
18984
19296
  return;
18985
19297
  }
18986
- const newAllRings = allRings.map((ring, ringIndex) => {
18987
- if (ringIndex === targetRingIndex) {
18988
- const newRing = [...ring];
18989
- newRing.splice(targetVertexIndex, 1);
18990
- return newRing;
18991
- } else {
18992
- return [...ring];
19298
+ const newRings = rings.map((ring, idx) => {
19299
+ if (idx !== targetRingIndex) return ring.slice();
19300
+ const nr = ring.slice();
19301
+ nr.splice(targetVertexIndex, 1);
19302
+ return nr;
19303
+ });
19304
+ const coords = newRings.map((ring) => {
19305
+ const arr = ring.map((ll) => [ll.lng, ll.lat]);
19306
+ if (arr.length > 0) {
19307
+ const first = arr[0];
19308
+ const last = arr[arr.length - 1];
19309
+ if (first[0] !== last[0] || first[1] !== last[1]) {
19310
+ arr.push([first[0], first[1]]);
19311
+ }
18993
19312
  }
19313
+ return arr;
18994
19314
  });
18995
- const currentFeatureGroup = this.findFeatureGroupForPoly(poly);
19315
+ let currentFeatureGroup = null;
19316
+ for (const fg of this.getFeatureGroups()) {
19317
+ let found = false;
19318
+ fg.eachLayer((layer) => {
19319
+ if (layer === polygonLayer) found = true;
19320
+ });
19321
+ if (found) {
19322
+ currentFeatureGroup = fg;
19323
+ break;
19324
+ }
19325
+ }
18996
19326
  if (currentFeatureGroup) {
18997
19327
  this.removeFeatureGroup(currentFeatureGroup);
18998
19328
  }
18999
- const newPolygon = this.turfHelper.getMultiPolygon([newAllRings]);
19329
+ const newPolygon = this.turfHelper.getMultiPolygon([coords]);
19000
19330
  this.eventManager.emit("polydraw:polygon:updated", {
19001
19331
  operation: "removeVertex",
19002
19332
  polygon: newPolygon
@@ -19007,7 +19337,7 @@ class PolygonInteractionManager {
19007
19337
  const featureCollection2 = featureGroup.toGeoJSON();
19008
19338
  if (featureCollection2 && featureCollection2.features && featureCollection2.features[0]) {
19009
19339
  const feature2 = featureCollection2.features[0];
19010
- if (JSON.stringify(feature2.geometry.coordinates) === JSON.stringify(poly.geometry.coordinates)) {
19340
+ if (this.turfHelper.equalPolygons(feature2, poly)) {
19011
19341
  return featureGroup;
19012
19342
  }
19013
19343
  }
@@ -19022,10 +19352,11 @@ class PolygonInteractionManager {
19022
19352
  const newPos = [];
19023
19353
  let testarray = [];
19024
19354
  let hole = [];
19025
- const layerLength = featureGroup.getLayers();
19026
- const posarrays = layerLength[0].getLatLngs();
19355
+ const layers = featureGroup.getLayers();
19356
+ const polygonLayer = layers.find((l) => l instanceof L.Polygon);
19357
+ const posarrays = polygonLayer.getLatLngs();
19027
19358
  let length2 = 0;
19028
- const markers2 = layerLength.filter((layer) => layer instanceof L.Marker);
19359
+ const markers2 = layers.filter((layer) => layer instanceof L.Marker);
19029
19360
  if (posarrays.length > 1) {
19030
19361
  for (let index = 0; index < posarrays.length; index++) {
19031
19362
  testarray = [];
@@ -19050,7 +19381,7 @@ class PolygonInteractionManager {
19050
19381
  }
19051
19382
  newPos.push(hole);
19052
19383
  } else {
19053
- length2 += posarrays[index - 1][0].length;
19384
+ length2 += posarrays[index - 1].length;
19054
19385
  for (let j = length2; j < posarrays[index][0].length + length2; j++) {
19055
19386
  if (markers2[j]) {
19056
19387
  testarray.push(markers2[j].getLatLng());
@@ -19091,7 +19422,7 @@ class PolygonInteractionManager {
19091
19422
  }
19092
19423
  newPos.push(hole);
19093
19424
  }
19094
- layerLength[0].setLatLngs(newPos);
19425
+ polygonLayer.setLatLngs(newPos);
19095
19426
  }
19096
19427
  async markerDragEnd(featureGroup) {
19097
19428
  this.polygonInformation.deletePolygonInformationStorage();
@@ -19100,7 +19431,7 @@ class PolygonInteractionManager {
19100
19431
  return;
19101
19432
  }
19102
19433
  this.removeFeatureGroup(featureGroup);
19103
- if (featureCollection2.features[0].geometry.coordinates.length > 1) {
19434
+ if (featureCollection2.features[0].geometry.type === "MultiPolygon") {
19104
19435
  for (const element of featureCollection2.features[0].geometry.coordinates) {
19105
19436
  const feature2 = this.turfHelper.getMultiPolygon([element]);
19106
19437
  if (this.turfHelper.hasKinks(feature2)) {
@@ -19121,9 +19452,9 @@ class PolygonInteractionManager {
19121
19452
  }
19122
19453
  }
19123
19454
  } else {
19124
- const feature2 = this.turfHelper.getMultiPolygon(
19455
+ const feature2 = this.turfHelper.getMultiPolygon([
19125
19456
  featureCollection2.features[0].geometry.coordinates
19126
- );
19457
+ ]);
19127
19458
  if (this.turfHelper.hasKinks(feature2)) {
19128
19459
  const unkink = this.turfHelper.getKinks(feature2);
19129
19460
  for (const polygon2 of unkink) {
@@ -19132,11 +19463,6 @@ class PolygonInteractionManager {
19132
19463
  polygon: this.turfHelper.getTurfPolygon(polygon2),
19133
19464
  allowMerge: true
19134
19465
  });
19135
- this.eventManager.emit("polydraw:polygon:updated", {
19136
- operation: "markerDrag",
19137
- polygon: this.turfHelper.getTurfPolygon(polygon2),
19138
- allowMerge: true
19139
- });
19140
19466
  }
19141
19467
  } else {
19142
19468
  this.eventManager.emit("polydraw:polygon:updated", {
@@ -19144,11 +19470,6 @@ class PolygonInteractionManager {
19144
19470
  polygon: feature2,
19145
19471
  allowMerge: true
19146
19472
  });
19147
- this.eventManager.emit("polydraw:polygon:updated", {
19148
- operation: "markerDrag",
19149
- polygon: feature2,
19150
- allowMerge: true
19151
- });
19152
19473
  }
19153
19474
  }
19154
19475
  this.polygonInformation.createPolygonInformationStorage(this.getFeatureGroups());
@@ -19156,17 +19477,11 @@ class PolygonInteractionManager {
19156
19477
  offsetPolygonCoordinates(latLngs, offsetLat, offsetLng) {
19157
19478
  if (!latLngs) return latLngs;
19158
19479
  if (Array.isArray(latLngs[0])) {
19159
- return latLngs.map((ring) => this.offsetPolygonCoordinates(ring, offsetLat, offsetLng));
19160
- } else if (latLngs.lat !== void 0 && latLngs.lng !== void 0) {
19161
- return {
19162
- lat: latLngs.lat + offsetLat,
19163
- lng: latLngs.lng + offsetLng
19164
- };
19165
- } else {
19166
19480
  return latLngs.map(
19167
- (coord) => this.offsetPolygonCoordinates(coord, offsetLat, offsetLng)
19481
+ (ring) => this.offsetPolygonCoordinates(ring, offsetLat, offsetLng)
19168
19482
  );
19169
19483
  }
19484
+ return latLngs.map((p) => L.latLng(p.lat + offsetLat, p.lng + offsetLng));
19170
19485
  }
19171
19486
  updateMarkersAndHoleLinesDuringDrag(polygon2, offsetLat, offsetLng) {
19172
19487
  try {
@@ -19195,7 +19510,8 @@ class PolygonInteractionManager {
19195
19510
  if (layer instanceof L.Marker) {
19196
19511
  polygon2._polydrawOriginalMarkerPositions.set(layer, layer.getLatLng());
19197
19512
  } else if (layer instanceof L.Polyline && !(layer instanceof L.Polygon)) {
19198
- polygon2._polydrawOriginalHoleLinePositions.set(layer, layer.getLatLngs());
19513
+ const latLngs = layer.getLatLngs();
19514
+ polygon2._polydrawOriginalHoleLinePositions.set(layer, latLngs);
19199
19515
  }
19200
19516
  });
19201
19517
  }
@@ -19212,10 +19528,16 @@ class PolygonInteractionManager {
19212
19528
  } else if (layer instanceof L.Polyline && !(layer instanceof L.Polygon)) {
19213
19529
  const originalPositions = polygon2._polydrawOriginalHoleLinePositions.get(layer);
19214
19530
  if (originalPositions) {
19215
- const newLatLngs = originalPositions.map((latlng) => ({
19216
- lat: latlng.lat + offsetLat,
19217
- lng: latlng.lng + offsetLng
19218
- }));
19531
+ let newLatLngs;
19532
+ if (Array.isArray(originalPositions[0])) {
19533
+ newLatLngs = originalPositions.map(
19534
+ (ring) => ring.map((latlng) => L.latLng(latlng.lat + offsetLat, latlng.lng + offsetLng))
19535
+ );
19536
+ } else {
19537
+ newLatLngs = originalPositions.map(
19538
+ (latlng) => L.latLng(latlng.lat + offsetLat, latlng.lng + offsetLng)
19539
+ );
19540
+ }
19219
19541
  layer.setLatLngs(newLatLngs);
19220
19542
  }
19221
19543
  }
@@ -19256,7 +19578,17 @@ class PolygonInteractionManager {
19256
19578
  } catch (error) {
19257
19579
  }
19258
19580
  }
19259
- detectModifierKey(event) {
19581
+ getDragSubtractModifierKey() {
19582
+ const { keys } = this.config.dragPolygons.modifierSubtract;
19583
+ const userAgent = navigator.userAgent.toLowerCase();
19584
+ const isMac = userAgent.includes("mac");
19585
+ const isWindows = userAgent.includes("windows");
19586
+ if (isMac && keys.mac) return keys.mac;
19587
+ if (isWindows && keys.windows) return keys.windows;
19588
+ if (keys.linux) return keys.linux;
19589
+ return isMac ? "metaKey" : "ctrlKey";
19590
+ }
19591
+ detectDragSubtractModifierKey(event) {
19260
19592
  var _a2, _b2;
19261
19593
  if (!((_b2 = (_a2 = this.config.dragPolygons) == null ? void 0 : _a2.modifierSubtract) == null ? void 0 : _b2.enabled)) {
19262
19594
  return false;
@@ -19264,13 +19596,8 @@ class PolygonInteractionManager {
19264
19596
  if (isTouchDevice()) {
19265
19597
  return false;
19266
19598
  }
19267
- const userAgent = navigator.userAgent.toLowerCase();
19268
- const isMac = userAgent.includes("mac");
19269
- if (isMac) {
19270
- return event.metaKey;
19271
- } else {
19272
- return event.ctrlKey;
19273
- }
19599
+ const modifierKey = this.getDragSubtractModifierKey();
19600
+ return !!event[modifierKey];
19274
19601
  }
19275
19602
  setSubtractVisualMode(polygon2, enabled) {
19276
19603
  if (!polygon2 || !polygon2.setStyle) {
@@ -19279,11 +19606,11 @@ class PolygonInteractionManager {
19279
19606
  try {
19280
19607
  if (enabled) {
19281
19608
  polygon2.setStyle({
19282
- color: this.config.dragPolygons.modifierSubtract.subtractColor
19609
+ color: this.config.colors.dragPolygons.subtract
19283
19610
  });
19284
19611
  } else {
19285
19612
  polygon2.setStyle({
19286
- color: this.config.polygonOptions.color
19613
+ color: this.config.colors.polygon.border
19287
19614
  });
19288
19615
  }
19289
19616
  this.updateMarkerColorsForSubtractMode(polygon2, enabled);
@@ -19316,8 +19643,8 @@ class PolygonInteractionManager {
19316
19643
  element.style.display = "none";
19317
19644
  element.classList.add("subtract-mode-hidden");
19318
19645
  } else {
19319
- element.style.backgroundColor = this.config.dragPolygons.modifierSubtract.subtractColor;
19320
- element.style.borderColor = this.config.dragPolygons.modifierSubtract.subtractColor;
19646
+ element.style.backgroundColor = this.config.colors.dragPolygons.subtract;
19647
+ element.style.borderColor = this.config.colors.dragPolygons.subtract;
19321
19648
  element.classList.add("subtract-mode");
19322
19649
  }
19323
19650
  } else {
@@ -19337,7 +19664,7 @@ class PolygonInteractionManager {
19337
19664
  }
19338
19665
  }
19339
19666
  handleModifierToggleDuringDrag(event) {
19340
- const isModifierPressed = this.detectModifierKey(event);
19667
+ const isModifierPressed = this.detectDragSubtractModifierKey(event);
19341
19668
  this.currentModifierDragMode = isModifierPressed;
19342
19669
  this.isModifierKeyHeld = isModifierPressed;
19343
19670
  if (this.currentDragPolygon) {
@@ -19367,8 +19694,11 @@ class PolygonInteractionManager {
19367
19694
  const existingPolygon = this.turfHelper.getTurfPolygon(firstFeature);
19368
19695
  try {
19369
19696
  const intersection3 = this.turfHelper.getIntersection(existingPolygon, draggedPolygon);
19370
- if (intersection3 && intersection3.geometry && intersection3.geometry.coordinates.length > 0) {
19371
- intersectingFeatureGroups.push(featureGroup);
19697
+ if (intersection3 && intersection3.geometry && "coordinates" in intersection3.geometry) {
19698
+ const coords = intersection3.geometry.coordinates;
19699
+ if (coords.length > 0) {
19700
+ intersectingFeatureGroups.push(featureGroup);
19701
+ }
19372
19702
  }
19373
19703
  } catch (intersectError) {
19374
19704
  try {
@@ -19428,28 +19758,39 @@ class PolygonInteractionManager {
19428
19758
  boundingBoxesOverlap(bbox1, bbox2) {
19429
19759
  return !(bbox1[2] < bbox2[0] || bbox2[2] < bbox1[0] || bbox1[3] < bbox2[1] || bbox2[3] < bbox1[1]);
19430
19760
  }
19431
- isModifierKeyPressed(event) {
19761
+ isDragSubtractModifierKeyPressed(event) {
19432
19762
  if (isTouchDevice()) {
19433
19763
  return false;
19434
19764
  }
19765
+ const modifierKey = this.getDragSubtractModifierKey();
19766
+ return !!event[modifierKey];
19767
+ }
19768
+ getEdgeDeletionModifierKey() {
19769
+ const { keys } = this.config.edgeDeletion;
19435
19770
  const userAgent = navigator.userAgent.toLowerCase();
19436
19771
  const isMac = userAgent.includes("mac");
19437
- if (isMac) {
19438
- return event.metaKey;
19439
- } else {
19440
- return event.ctrlKey;
19772
+ const isWindows = userAgent.includes("windows");
19773
+ if (isMac && keys.mac) return keys.mac;
19774
+ if (isWindows && keys.windows) return keys.windows;
19775
+ if (keys.linux) return keys.linux;
19776
+ return isMac ? "metaKey" : "ctrlKey";
19777
+ }
19778
+ isEdgeDeletionModifierKeyPressed(event) {
19779
+ if (isTouchDevice()) {
19780
+ return false;
19441
19781
  }
19782
+ const modifierKey = this.getEdgeDeletionModifierKey();
19783
+ return !!event[modifierKey];
19442
19784
  }
19443
19785
  onMarkerHoverForEdgeDeletion(marker, isHovering) {
19444
19786
  const element = marker.getElement();
19445
19787
  if (!element) return;
19446
19788
  if (isHovering) {
19447
19789
  const checkModifierAndUpdate = (e) => {
19448
- var _a2, _b2, _c, _d;
19449
- const isModifierPressed = this.detectModifierKey(e);
19790
+ const isModifierPressed = this.isEdgeDeletionModifierKeyPressed(e);
19450
19791
  if (isModifierPressed) {
19451
- element.style.backgroundColor = ((_b2 = (_a2 = this.config.dragPolygons) == null ? void 0 : _a2.modifierSubtract) == null ? void 0 : _b2.subtractColor) || "#D9460F";
19452
- element.style.borderColor = ((_d = (_c = this.config.dragPolygons) == null ? void 0 : _c.modifierSubtract) == null ? void 0 : _d.subtractColor) || "#D9460F";
19792
+ element.style.backgroundColor = this.config.colors.edgeDeletion.hover;
19793
+ element.style.borderColor = this.config.colors.edgeDeletion.hover;
19453
19794
  element.classList.add("edge-deletion-hover");
19454
19795
  try {
19455
19796
  const container = this.map.getContainer();
@@ -19469,7 +19810,7 @@ class PolygonInteractionManager {
19469
19810
  };
19470
19811
  const initialEvent = new MouseEvent("mouseover");
19471
19812
  checkModifierAndUpdate(initialEvent);
19472
- marker._polydrawModifierHandler = checkModifierAndUpdate;
19813
+ this.markerModifierHandlers.set(marker, checkModifierAndUpdate);
19473
19814
  document.addEventListener("keydown", checkModifierAndUpdate);
19474
19815
  document.addEventListener("keyup", checkModifierAndUpdate);
19475
19816
  element.addEventListener("mousemove", checkModifierAndUpdate);
@@ -19482,12 +19823,12 @@ class PolygonInteractionManager {
19482
19823
  container.style.cursor = "";
19483
19824
  } catch (error) {
19484
19825
  }
19485
- const handler = marker._polydrawModifierHandler;
19826
+ const handler = this.markerModifierHandlers.get(marker);
19486
19827
  if (handler) {
19487
19828
  document.removeEventListener("keydown", handler);
19488
19829
  document.removeEventListener("keyup", handler);
19489
19830
  element.removeEventListener("mousemove", handler);
19490
- delete marker._polydrawModifierHandler;
19831
+ this.markerModifierHandlers.delete(marker);
19491
19832
  }
19492
19833
  }
19493
19834
  }
@@ -19507,7 +19848,10 @@ class PolygonInteractionManager {
19507
19848
  };
19508
19849
  const targetPoint = this.turfHelper.getCoord(latLngPoint);
19509
19850
  const fc = this.turfHelper.getFeaturePointCollection(latlngs);
19510
- const nearestPointIdx = this.turfHelper.getNearestPointIndex(targetPoint, fc);
19851
+ const nearestPointIdx = this.turfHelper.getNearestPointIndex(
19852
+ targetPoint,
19853
+ fc
19854
+ );
19511
19855
  return nearestPointIdx;
19512
19856
  }
19513
19857
  ensureMarkerSeparation(polygonLength, markers2) {
@@ -19722,7 +20066,11 @@ class PolygonInteractionManager {
19722
20066
  }
19723
20067
  return polygon2.toGeoJSON();
19724
20068
  } catch (error) {
19725
- console.warn("Error getting polygon GeoJSON from feature group:", error.message);
20069
+ if (error instanceof Error) {
20070
+ console.warn("Error getting polygon GeoJSON from feature group:", error.message);
20071
+ } else {
20072
+ console.warn("Error getting polygon GeoJSON from feature group:", error);
20073
+ }
19726
20074
  return {
19727
20075
  type: "Feature",
19728
20076
  geometry: {
@@ -19780,7 +20128,11 @@ class PolygonInteractionManager {
19780
20128
  }
19781
20129
  return totalPerimeter * 1e3;
19782
20130
  } catch (error) {
19783
- console.warn("Error calculating total polygon perimeter:", error.message);
20131
+ if (error instanceof Error) {
20132
+ console.warn("Error calculating total polygon perimeter:", error.message);
20133
+ } else {
20134
+ console.warn("Error calculating total polygon perimeter:", error);
20135
+ }
19784
20136
  return this.turfHelper.getPolygonPerimeter(polygonGeoJSON) * 1e3;
19785
20137
  }
19786
20138
  }
@@ -19901,7 +20253,7 @@ class PolygonMutationManager {
19901
20253
  this.subtractPolygon(data.subtractPolygon);
19902
20254
  });
19903
20255
  this.eventManager.on("polydraw:polygon:deleted", () => {
19904
- this.emit("polygonDeleted");
20256
+ this.emit("polygonDeleted", void 0);
19905
20257
  });
19906
20258
  }
19907
20259
  /**
@@ -19920,11 +20272,10 @@ class PolygonMutationManager {
19920
20272
  * Handle menu actions from interaction manager
19921
20273
  */
19922
20274
  async handleMenuAction(data) {
19923
- const { action, latLngs, featureGroup } = data;
19924
- const completePolygonGeoJSON = this.getCompletePolygonFromFeatureGroup(featureGroup);
19925
- this.removeFeatureGroupInternal(featureGroup);
20275
+ const completePolygonGeoJSON = this.getCompletePolygonFromFeatureGroup(data.featureGroup);
20276
+ this.removeFeatureGroupInternal(data.featureGroup);
19926
20277
  let result;
19927
- switch (action) {
20278
+ switch (data.action) {
19928
20279
  case "simplify": {
19929
20280
  result = this.geometryManager.simplifyPolygon(completePolygonGeoJSON);
19930
20281
  break;
@@ -19970,7 +20321,8 @@ class PolygonMutationManager {
19970
20321
  * Add a polygon with optional merging logic
19971
20322
  */
19972
20323
  async addPolygon(latlngs, options = {}) {
19973
- const { simplify: simplify3 = true, noMerge = false } = options;
20324
+ const { noMerge = false } = options;
20325
+ const { simplify: simplify3 = true } = options;
19974
20326
  try {
19975
20327
  if (this.config.mergePolygons && !noMerge && this.getFeatureGroups().length > 0 && !this.config.kinks) {
19976
20328
  return await this.mergePolygon(latlngs, options);
@@ -20095,9 +20447,11 @@ class PolygonMutationManager {
20095
20447
  this.interactionManager.addMarkers(polyElement, featureGroup);
20096
20448
  } else {
20097
20449
  const holePolyline = L.polyline(polyElement, {
20098
- color: this.config.holeOptions.color,
20450
+ color: this.config.colors.hole.border,
20099
20451
  weight: this.config.holeOptions.weight || 2,
20100
- opacity: this.config.holeOptions.opacity || 1
20452
+ opacity: this.config.holeOptions.opacity || 1,
20453
+ fillColor: this.config.colors.hole.fill,
20454
+ fillOpacity: this.config.holeOptions.fillOpacity || 0.5
20101
20455
  });
20102
20456
  featureGroup.addLayer(holePolyline);
20103
20457
  this.interactionManager.addHoleMarkers(polyElement, featureGroup);
@@ -20148,18 +20502,23 @@ class PolygonMutationManager {
20148
20502
  if (!firstFeature.geometry || !firstFeature.geometry.coordinates) {
20149
20503
  return;
20150
20504
  }
20151
- if (firstFeature.geometry.coordinates.length > 1) {
20152
- firstFeature.geometry.coordinates.forEach((element) => {
20153
- try {
20154
- const feature2 = this.turfHelper.getMultiPolygon([element]);
20155
- polyIntersection = this.geometryManager.checkPolygonIntersection(feature2, latlngs);
20156
- if (polyIntersection) {
20157
- intersectingFeatureGroups.push(featureGroup);
20158
- polygonFeature.push(feature2);
20505
+ if (this.isPositionArrayofArrays(firstFeature.geometry.coordinates)) {
20506
+ firstFeature.geometry.coordinates.forEach(
20507
+ (element) => {
20508
+ try {
20509
+ const feature2 = this.turfHelper.getMultiPolygon([element]);
20510
+ polyIntersection = this.geometryManager.checkPolygonIntersection(
20511
+ feature2,
20512
+ latlngs
20513
+ );
20514
+ if (polyIntersection) {
20515
+ intersectingFeatureGroups.push(featureGroup);
20516
+ polygonFeature.push(feature2);
20517
+ }
20518
+ } catch (error) {
20159
20519
  }
20160
- } catch (error) {
20161
20520
  }
20162
- });
20521
+ );
20163
20522
  } else {
20164
20523
  try {
20165
20524
  const feature2 = this.turfHelper.getTurfPolygon(firstFeature);
@@ -20221,12 +20580,31 @@ class PolygonMutationManager {
20221
20580
  };
20222
20581
  }
20223
20582
  }
20583
+ /**
20584
+ * Create a polygon from GeoJSON feature
20585
+ */
20586
+ isPositionArrayofArrays(arr) {
20587
+ if (!Array.isArray(arr) || arr.length === 0) return false;
20588
+ const first = arr[0];
20589
+ if (!Array.isArray(first) || first.length === 0) return false;
20590
+ const second = first[0];
20591
+ if (!Array.isArray(second) || second.length === 0) return false;
20592
+ const leaf = second[0];
20593
+ return this.isPosition(leaf);
20594
+ }
20595
+ isPosition(val) {
20596
+ return Array.isArray(val) && val.length >= 2 && val.every((n) => typeof n === "number");
20597
+ }
20224
20598
  /**
20225
20599
  * Create a polygon from GeoJSON feature
20226
20600
  */
20227
20601
  getPolygon(latlngs) {
20228
20602
  const polygon2 = L.GeoJSON.geometryToLayer(latlngs);
20229
- polygon2.setStyle(this.config.polygonOptions);
20603
+ polygon2.setStyle({
20604
+ ...this.config.polygonOptions,
20605
+ color: this.config.colors.polygon.border,
20606
+ fillColor: this.config.colors.polygon.fill
20607
+ });
20230
20608
  polygon2._polydrawUniqueId = L.Util.stamp(polygon2) + "_" + Date.now();
20231
20609
  delete polygon2._polydrawDragData;
20232
20610
  delete polygon2._polydrawOriginalLatLngs;
@@ -20424,9 +20802,9 @@ class PolygonMutationManager {
20424
20802
  ensureMarkerSeparation(polygonLength, markers2) {
20425
20803
  var _a2, _b2, _c;
20426
20804
  return {
20427
- menu: ((_a2 = markers2.menu) == null ? void 0 : _a2.index) || 0,
20428
- delete: ((_b2 = markers2.delete) == null ? void 0 : _b2.index) || 1,
20429
- info: ((_c = markers2.info) == null ? void 0 : _c.index) || 2
20805
+ menu: ((_a2 = markers2.menu) == null ? void 0 : _a2.index) ?? 0,
20806
+ delete: ((_b2 = markers2.delete) == null ? void 0 : _b2.index) ?? 1,
20807
+ info: ((_c = markers2.info) == null ? void 0 : _c.index) ?? 2
20430
20808
  };
20431
20809
  }
20432
20810
  findAlternativeMarkerPosition(polygonLength, originalIndex, usedIndices) {
@@ -20534,6 +20912,21 @@ class PolygonMutationManager {
20534
20912
  }
20535
20913
  }
20536
20914
  }
20915
+ function injectDynamicStyles(config) {
20916
+ const style = document.createElement("style");
20917
+ style.innerHTML = `
20918
+ .leaflet-control a { background-color: ${config.colors.styles.controlButton.backgroundColor}; color: ${config.colors.styles.controlButton.color}; display: flex; align-items: center; justify-content: center; }
20919
+ .leaflet-control a:hover { background-color: ${config.colors.styles.controlButtonHover.backgroundColor}; }
20920
+ .leaflet-control a.active { background-color: ${config.colors.styles.controlButtonActive.backgroundColor}; color: ${config.colors.styles.controlButtonActive.color}; }
20921
+ .polydraw-indicator-active { background-color: ${config.colors.styles.indicatorActive.backgroundColor} !important; }
20922
+ .crosshair-cursor-enabled { cursor: crosshair !important; }
20923
+ .crosshair-cursor-enabled * { cursor: crosshair !important; }
20924
+ .leaflet-polydraw-p2p-marker { background-color: ${config.colors.styles.p2pMarker.backgroundColor}; border: 2px solid ${config.colors.styles.p2pMarker.borderColor}; border-radius: 50%; box-sizing: border-box; }
20925
+ .leaflet-polydraw-p2p-first-marker { position: relative; }
20926
+ .leaflet-polydraw-p2p-first-marker:hover { transform: scale(1.5); transition: all 0.2s ease; }
20927
+ `;
20928
+ document.head.appendChild(style);
20929
+ }
20537
20930
  class Polydraw extends L.Control {
20538
20931
  constructor(options) {
20539
20932
  super(options);
@@ -20558,133 +20951,38 @@ class Polydraw extends L.Control {
20558
20951
  __publicField(this, "_boundTouchEnd");
20559
20952
  __publicField(this, "_boundTouchStart");
20560
20953
  /**
20561
- * Handle marker hover when modifier key is held - event handler version
20954
+ * Updates map interactions based on the current drawing mode.
20562
20955
  */
20563
- __publicField(this, "onMarkerHoverForEdgeDeletionEvent", (e) => {
20564
- if (!this.isModifierKeyHeld) return;
20565
- const element = e.target;
20566
- if (element) {
20567
- element.style.backgroundColor = "#D9460F";
20568
- element.style.borderColor = "#D9460F";
20569
- element.classList.add("edge-deletion-hover");
20956
+ __publicField(this, "_handleActivateToggle", () => {
20957
+ const container = this.getContainer();
20958
+ if (!container) return;
20959
+ const activate = container.querySelector(".icon-activate");
20960
+ if (L.DomUtil.hasClass(activate, "active")) {
20961
+ L.DomUtil.removeClass(activate, "active");
20962
+ if (this.subContainer) {
20963
+ this.subContainer.style.maxHeight = "0px";
20964
+ }
20965
+ } else {
20966
+ L.DomUtil.addClass(activate, "active");
20967
+ if (this.subContainer) {
20968
+ this.subContainer.style.maxHeight = "250px";
20969
+ }
20570
20970
  }
20971
+ this.updateActivateButtonIndicator();
20571
20972
  });
20572
- /**
20573
- * Handle marker leave when modifier key is held - event handler version
20574
- */
20575
- __publicField(this, "onMarkerLeaveForEdgeDeletionEvent", (e) => {
20576
- const element = e.target;
20577
- if (element) {
20578
- element.style.backgroundColor = "";
20579
- element.style.borderColor = "";
20580
- element.classList.remove("edge-deletion-hover");
20973
+ __publicField(this, "_handleDrawClick", (e) => {
20974
+ if (e) {
20975
+ e.preventDefault();
20976
+ e.stopPropagation();
20581
20977
  }
20582
- });
20583
- this.config = defaultConfig;
20584
- if (options == null ? void 0 : options.configPath) {
20585
- this.loadExternalConfig(options.configPath, options == null ? void 0 : options.config);
20586
- } else {
20587
- this.config = { ...defaultConfig, ...(options == null ? void 0 : options.config) || {} };
20588
- this.initializeComponents();
20589
- }
20590
- }
20591
- async loadExternalConfig(configPath, inlineConfig) {
20592
- try {
20593
- const response = await fetch(configPath);
20594
- if (!response.ok) {
20595
- throw new Error(
20596
- `Failed to load config from ${configPath}: ${response.status} ${response.statusText}`
20597
- );
20598
- }
20599
- const externalConfig = await response.json();
20600
- this.config = {
20601
- ...defaultConfig,
20602
- ...externalConfig,
20603
- ...inlineConfig || {}
20604
- };
20605
- this.initializeComponents();
20606
- } catch (error) {
20607
- console.warn(
20608
- "Failed to load external config, falling back to default + inline config:",
20609
- error
20610
- );
20611
- this.config = { ...defaultConfig, ...inlineConfig || {} };
20612
- this.initializeComponents();
20613
- }
20614
- }
20615
- initializeComponents() {
20616
- this.turfHelper = new TurfHelper(this.config);
20617
- this.mapStateService = new MapStateService();
20618
- this.eventManager = new EventManager();
20619
- this.polygonInformation = new PolygonInformationService(this.mapStateService);
20620
- this.modeManager = new ModeManager(this.config, this.eventManager);
20621
- this.polygonInformation.onPolygonInfoUpdated((_k) => {
20622
- this.updateActivateButtonIndicator();
20623
- });
20624
- this._boundKeyDownHandler = this.handleKeyDown.bind(this);
20625
- this.polygonMutationManager = null;
20626
- this.polygonDrawManager = null;
20627
- }
20628
- onAdd(_map) {
20629
- _map._onResize = () => {
20630
- };
20631
- if (L.Browser.touch && L.Browser.mobile) {
20632
- _map.tap = false;
20633
- }
20634
- this.map = _map;
20635
- const style = document.createElement("style");
20636
- style.innerHTML = `
20637
- .leaflet-control a { background-color: #fff; color: #000; display: flex; align-items: center; justify-content: center; }
20638
- .leaflet-control a:hover { background-color: #f4f4f4; }
20639
- .leaflet-control a.active { background-color:rgb(128, 218, 255); color: #fff; }
20640
- .polydraw-indicator-active { background-color: #ffcc00 !important; }
20641
- .crosshair-cursor-enabled { cursor: crosshair !important; }
20642
- .crosshair-cursor-enabled * { cursor: crosshair !important; }
20643
- .leaflet-polydraw-p2p-marker { background-color: #fff; border: 2px solid #50622b; border-radius: 50%; box-sizing: border-box; }
20644
- .leaflet-polydraw-p2p-first-marker { position: relative; }
20645
- .leaflet-polydraw-p2p-first-marker:hover { transform: scale(1.5); transition: all 0.2s ease; }
20646
- `;
20647
- document.head.appendChild(style);
20648
- this.setupKeyboardHandlers();
20649
- const container = L.DomUtil.create("div", "leaflet-control leaflet-bar");
20650
- L.DomEvent.disableClickPropagation(container);
20651
- L.DomEvent.on(container, "mousedown", L.DomEvent.stopPropagation);
20652
- L.DomEvent.on(container, "touchstart", L.DomEvent.stopPropagation);
20653
- L.DomEvent.on(container, "click", L.DomEvent.stopPropagation);
20654
- container.style.display = "flex";
20655
- container.style.flexDirection = "column-reverse";
20656
- this.subContainer = L.DomUtil.create("div", "sub-buttons", container);
20657
- this.subContainer.style.maxHeight = "0px";
20658
- this.subContainer.style.overflow = "hidden";
20659
- this.subContainer.style.transition = "max-height 0.3s ease";
20660
- const onActivateToggle = () => {
20661
- const activate = container.querySelector(".icon-activate");
20662
- if (L.DomUtil.hasClass(activate, "active")) {
20663
- L.DomUtil.removeClass(activate, "active");
20664
- if (this.subContainer) {
20665
- this.subContainer.style.maxHeight = "0px";
20666
- }
20667
- } else {
20668
- L.DomUtil.addClass(activate, "active");
20669
- if (this.subContainer) {
20670
- this.subContainer.style.maxHeight = "250px";
20671
- }
20672
- }
20673
- this.updateActivateButtonIndicator();
20674
- };
20675
- const onDrawClick = (e) => {
20676
- if (e) {
20677
- e.preventDefault();
20678
- e.stopPropagation();
20679
- }
20680
- if (this.modeManager.getCurrentMode() === DrawMode.Add) {
20681
- this.setDrawMode(DrawMode.Off);
20682
- return;
20978
+ if (this.modeManager.getCurrentMode() === DrawMode.Add) {
20979
+ this.setDrawMode(DrawMode.Off);
20980
+ return;
20683
20981
  }
20684
20982
  this.setDrawMode(DrawMode.Add);
20685
20983
  this.polygonInformation.saveCurrentState();
20686
- };
20687
- const onSubtractClick = (e) => {
20984
+ });
20985
+ __publicField(this, "_handleSubtractClick", (e) => {
20688
20986
  if (e) {
20689
20987
  e.preventDefault();
20690
20988
  e.stopPropagation();
@@ -20695,8 +20993,8 @@ class Polydraw extends L.Control {
20695
20993
  }
20696
20994
  this.setDrawMode(DrawMode.Subtract);
20697
20995
  this.polygonInformation.saveCurrentState();
20698
- };
20699
- const onEraseClick = (e) => {
20996
+ });
20997
+ __publicField(this, "_handleEraseClick", (e) => {
20700
20998
  this.map.closePopup();
20701
20999
  if (e) {
20702
21000
  e.preventDefault();
@@ -20706,8 +21004,8 @@ class Polydraw extends L.Control {
20706
21004
  return;
20707
21005
  }
20708
21006
  this.removeAllFeatureGroups();
20709
- };
20710
- const onPointToPointClick = (e) => {
21007
+ });
21008
+ __publicField(this, "_handlePointToPointClick", (e) => {
20711
21009
  if (e) {
20712
21010
  e.preventDefault();
20713
21011
  e.stopPropagation();
@@ -20718,16 +21016,213 @@ class Polydraw extends L.Control {
20718
21016
  }
20719
21017
  this.setDrawMode(DrawMode.PointToPoint);
20720
21018
  this.polygonInformation.saveCurrentState();
21019
+ });
21020
+ /**
21021
+ * Handle marker hover when modifier key is held - event handler version
21022
+ */
21023
+ __publicField(this, "onMarkerHoverForEdgeDeletionEvent", (e) => {
21024
+ if (!this.isModifierKeyHeld) return;
21025
+ const element = e.target;
21026
+ if (element) {
21027
+ element.style.backgroundColor = this.config.colors.edgeDeletion.hover;
21028
+ element.style.borderColor = this.config.colors.edgeDeletion.hover;
21029
+ element.classList.add("edge-deletion-hover");
21030
+ }
21031
+ });
21032
+ /**
21033
+ * Handle marker leave when modifier key is held - event handler version
21034
+ */
21035
+ __publicField(this, "onMarkerLeaveForEdgeDeletionEvent", (e) => {
21036
+ const element = e.target;
21037
+ if (element) {
21038
+ element.style.backgroundColor = "";
21039
+ element.style.borderColor = "";
21040
+ element.classList.remove("edge-deletion-hover");
21041
+ }
21042
+ });
21043
+ this.config = defaultConfig;
21044
+ if (options == null ? void 0 : options.configPath) {
21045
+ this.loadExternalConfig(options.configPath, options == null ? void 0 : options.config);
21046
+ } else {
21047
+ this.config = { ...defaultConfig, ...(options == null ? void 0 : options.config) || {} };
21048
+ this.initializeComponents();
21049
+ }
21050
+ }
21051
+ /**
21052
+ * Method called when the control is added to the map.
21053
+ * It initializes the control, creates the UI, and sets up event listeners.
21054
+ * @param _map - The map instance.
21055
+ * @returns The control's container element.
21056
+ */
21057
+ onAdd(_map) {
21058
+ const extendedMap = _map;
21059
+ const browser = L.Browser;
21060
+ extendedMap._onResize = () => {
20721
21061
  };
21062
+ if (browser.touch && browser.mobile) {
21063
+ extendedMap.tap = false;
21064
+ }
21065
+ this.map = _map;
21066
+ this.setupKeyboardHandlers();
21067
+ const container = L.DomUtil.create("div", "leaflet-control leaflet-bar");
21068
+ this.initializeUI(container);
21069
+ this.createTracer();
21070
+ this.initializeManagers();
21071
+ this.setupEventListeners();
21072
+ return container;
21073
+ }
21074
+ /**
21075
+ * Method called when the control is removed from the map.
21076
+ * It handles the cleanup of layers, events, and handlers.
21077
+ * @param _map - The map instance, unused but required by the L.Control interface.
21078
+ */
21079
+ onRemove(_map) {
21080
+ this.removeKeyboardHandlers();
21081
+ if (this.tracer) {
21082
+ this.map.removeLayer(this.tracer);
21083
+ }
21084
+ this.removeAllFeatureGroups();
21085
+ }
21086
+ /**
21087
+ * Adds the control to the given map.
21088
+ * @param map - The map instance.
21089
+ * @returns The current instance of the control.
21090
+ */
21091
+ addTo(map) {
21092
+ super.addTo(map);
21093
+ return this;
21094
+ }
21095
+ /**
21096
+ * Returns the array of feature groups currently managed by the control.
21097
+ * @returns An array of L.FeatureGroup objects.
21098
+ */
21099
+ getFeatureGroups() {
21100
+ return this.arrayOfFeatureGroups;
21101
+ }
21102
+ /**
21103
+ * Adds a predefined polygon to the map.
21104
+ * @param geographicBorders - An array of LatLng arrays representing the polygon's coordinates.
21105
+ * @param options - Optional parameters, including visual optimization level.
21106
+ */
21107
+ async addPredefinedPolygon(geographicBorders, options) {
21108
+ if (!geographicBorders || geographicBorders.length === 0) {
21109
+ throw new Error("Cannot add empty polygon array");
21110
+ }
21111
+ if (!this.map) {
21112
+ throw new Error("Map not initialized");
21113
+ }
21114
+ if (!this.polygonMutationManager) {
21115
+ throw new Error("PolygonMutationManager not initialized");
21116
+ }
21117
+ const visualOptimizationLevel = (options == null ? void 0 : options.visualOptimizationLevel) ?? 0;
21118
+ for (const [groupIndex, group] of geographicBorders.entries()) {
21119
+ if (!group || !group[0] || group[0].length < 4) {
21120
+ throw new Error(
21121
+ `Invalid polygon data at index ${groupIndex}: A polygon must have at least 3 unique vertices.`
21122
+ );
21123
+ }
21124
+ try {
21125
+ const coords = group.map((ring) => ring.map((latlng) => [latlng.lng, latlng.lat]));
21126
+ const polygon2 = this.turfHelper.getMultiPolygon([coords]);
21127
+ const result = await this.polygonMutationManager.addPolygon(polygon2, {
21128
+ simplify: false,
21129
+ noMerge: false,
21130
+ visualOptimizationLevel
21131
+ });
21132
+ if (!result.success) {
21133
+ console.error("Error adding polygon via manager:", result.error);
21134
+ throw new Error(result.error || "Failed to add polygon");
21135
+ }
21136
+ this.polygonInformation.createPolygonInformationStorage(this.arrayOfFeatureGroups);
21137
+ } catch (error) {
21138
+ console.error("Error adding auto polygon:", error);
21139
+ throw error;
21140
+ }
21141
+ }
21142
+ }
21143
+ /**
21144
+ * Sets the current drawing mode.
21145
+ * @param mode - The drawing mode to set.
21146
+ */
21147
+ setDrawMode(mode) {
21148
+ const previousMode = this.drawMode;
21149
+ this._updateDrawModeState(mode);
21150
+ if (previousMode === DrawMode.PointToPoint && mode !== DrawMode.PointToPoint) {
21151
+ this.polygonDrawManager.clearP2pMarkers();
21152
+ this.stopDraw();
21153
+ } else if (mode === DrawMode.Off) {
21154
+ this.stopDraw();
21155
+ } else if (mode !== DrawMode.PointToPoint) {
21156
+ this.stopDraw();
21157
+ }
21158
+ if (this.map) {
21159
+ this._updateUIAfterDrawModeChange(mode);
21160
+ this._updateMapInteractions();
21161
+ }
21162
+ }
21163
+ /**
21164
+ * Returns the current drawing mode.
21165
+ * @returns The current DrawMode.
21166
+ */
21167
+ getDrawMode() {
21168
+ return this.modeManager.getCurrentMode();
21169
+ }
21170
+ /**
21171
+ * Registers an event listener for a given event type.
21172
+ * @param event - The event type to listen for.
21173
+ * @param callback - The callback function to execute when the event is triggered.
21174
+ */
21175
+ on(event, callback) {
21176
+ this.eventManager.on(event, callback);
21177
+ }
21178
+ /**
21179
+ * Unregisters an event listener for a given event type.
21180
+ * @param event - The event type to stop listening for.
21181
+ * @param callback - The callback function to remove.
21182
+ */
21183
+ off(event, callback) {
21184
+ this.eventManager.off(event, callback);
21185
+ }
21186
+ /**
21187
+ * Removes all feature groups from the map and clears the internal storage.
21188
+ */
21189
+ removeAllFeatureGroups() {
21190
+ this.arrayOfFeatureGroups.forEach((featureGroups) => {
21191
+ try {
21192
+ this.map.removeLayer(featureGroups);
21193
+ } catch (error) {
21194
+ }
21195
+ });
21196
+ this.arrayOfFeatureGroups.length = 0;
21197
+ this.polygonInformation.deletePolygonInformationStorage();
21198
+ this.polygonInformation.updatePolygons();
21199
+ this.updateActivateButtonIndicator();
21200
+ }
21201
+ /**
21202
+ * Initializes the user interface, creates DOM elements, sets up buttons, and injects styles.
21203
+ * @param container - The main control container element.
21204
+ */
21205
+ initializeUI(container) {
21206
+ injectDynamicStyles(this.config);
21207
+ L.DomEvent.disableClickPropagation(container);
21208
+ L.DomEvent.on(container, "mousedown", L.DomEvent.stopPropagation);
21209
+ L.DomEvent.on(container, "touchstart", L.DomEvent.stopPropagation);
21210
+ L.DomEvent.on(container, "click", L.DomEvent.stopPropagation);
21211
+ container.style.display = "flex";
21212
+ container.style.flexDirection = "column-reverse";
21213
+ this.subContainer = L.DomUtil.create("div", "sub-buttons", container);
21214
+ this.subContainer.style.maxHeight = "0px";
21215
+ this.subContainer.style.overflow = "hidden";
21216
+ this.subContainer.style.transition = "max-height 0.3s ease";
20722
21217
  createButtons(
20723
21218
  container,
20724
21219
  this.subContainer,
20725
21220
  this.config,
20726
- onActivateToggle,
20727
- onDrawClick,
20728
- onSubtractClick,
20729
- onEraseClick,
20730
- onPointToPointClick
21221
+ this._handleActivateToggle,
21222
+ this._handleDrawClick,
21223
+ this._handleSubtractClick,
21224
+ this._handleEraseClick,
21225
+ this._handlePointToPointClick
20731
21226
  );
20732
21227
  const uiUpdateListener = (mode) => {
20733
21228
  const drawButton = container.querySelector(".icon-draw");
@@ -20736,28 +21231,11 @@ class Polydraw extends L.Control {
20736
21231
  if (subtractButton) subtractButton.classList.toggle("active", mode === DrawMode.Subtract);
20737
21232
  };
20738
21233
  this.drawModeListeners.push(uiUpdateListener);
20739
- this.tracer = L.polyline([], this.config.polyLineOptions);
20740
- try {
20741
- this.tracer.addTo(this.map);
20742
- } catch (error) {
20743
- }
20744
- this.polygonDrawManager = new PolygonDrawManager({
20745
- turfHelper: this.turfHelper,
20746
- map: this.map,
20747
- config: this.config,
20748
- modeManager: this.modeManager,
20749
- eventManager: this.eventManager,
20750
- tracer: this.tracer
20751
- });
20752
- this.polygonMutationManager = new PolygonMutationManager({
20753
- turfHelper: this.turfHelper,
20754
- polygonInformation: this.polygonInformation,
20755
- map: this.map,
20756
- config: this.config,
20757
- modeManager: this.modeManager,
20758
- eventManager: this.eventManager,
20759
- getFeatureGroups: () => this.arrayOfFeatureGroups
20760
- });
21234
+ }
21235
+ /**
21236
+ * Attaches listeners to polygonMutationManager and eventManager.
21237
+ */
21238
+ setupEventListeners() {
20761
21239
  this.polygonMutationManager.on("polygonOperationComplete", (data) => {
20762
21240
  this.updateActivateButtonIndicator();
20763
21241
  this.modeManager.updateStateForMode(DrawMode.Off);
@@ -20799,123 +21277,147 @@ class Polydraw extends L.Control {
20799
21277
  this.stopDraw();
20800
21278
  this.setDrawMode(DrawMode.Off);
20801
21279
  });
20802
- return container;
20803
21280
  }
20804
- addTo(map) {
20805
- super.addTo(map);
20806
- return this;
20807
- }
20808
- getFeatureGroups() {
20809
- return this.arrayOfFeatureGroups;
20810
- }
20811
- onRemove(_map) {
20812
- this.removeKeyboardHandlers();
20813
- if (this.tracer) {
20814
- this.map.removeLayer(this.tracer);
21281
+ /**
21282
+ * Initializes and adds the tracer polyline to the map.
21283
+ */
21284
+ createTracer() {
21285
+ this.tracer = L.polyline([], {
21286
+ ...this.config.polyLineOptions,
21287
+ color: this.config.colors.polyline
21288
+ });
21289
+ try {
21290
+ this.tracer.addTo(this.map);
21291
+ } catch (error) {
20815
21292
  }
20816
- this.removeAllFeatureGroups();
20817
21293
  }
20818
- async addPredefinedPolygon(geographicBorders, options) {
20819
- if (!geographicBorders || geographicBorders.length === 0) {
20820
- throw new Error("Cannot add empty polygon array");
20821
- }
20822
- if (!this.map) {
20823
- throw new Error("Map not initialized");
20824
- }
20825
- if (!this.polygonMutationManager) {
20826
- throw new Error("PolygonMutationManager not initialized");
20827
- }
20828
- const visualOptimizationLevel = (options == null ? void 0 : options.visualOptimizationLevel) ?? 0;
20829
- for (const [groupIndex, group] of geographicBorders.entries()) {
20830
- if (!group || !group[0] || group[0].length < 4) {
20831
- throw new Error(
20832
- `Invalid polygon data at index ${groupIndex}: A polygon must have at least 3 unique vertices.`
20833
- );
20834
- }
20835
- try {
20836
- const coords = group.map((ring) => ring.map((latlng) => [latlng.lng, latlng.lat]));
20837
- const polygon2 = this.turfHelper.getMultiPolygon([coords]);
20838
- const result = await this.polygonMutationManager.addPolygon(polygon2, {
20839
- simplify: false,
20840
- noMerge: false,
20841
- visualOptimizationLevel
20842
- });
20843
- if (!result.success) {
20844
- console.error("Error adding polygon via manager:", result.error);
20845
- throw new Error(result.error || "Failed to add polygon");
20846
- }
20847
- this.polygonInformation.createPolygonInformationStorage(this.arrayOfFeatureGroups);
20848
- } catch (error) {
20849
- console.error("Error adding auto polygon:", error);
20850
- throw error;
21294
+ /**
21295
+ * Sets up PolygonDrawManager and PolygonMutationManager with the map.
21296
+ */
21297
+ initializeManagers() {
21298
+ this.polygonDrawManager = new PolygonDrawManager({
21299
+ turfHelper: this.turfHelper,
21300
+ map: this.map,
21301
+ config: this.config,
21302
+ modeManager: this.modeManager,
21303
+ eventManager: this.eventManager,
21304
+ tracer: this.tracer
21305
+ });
21306
+ this.polygonMutationManager = new PolygonMutationManager({
21307
+ turfHelper: this.turfHelper,
21308
+ polygonInformation: this.polygonInformation,
21309
+ map: this.map,
21310
+ config: this.config,
21311
+ modeManager: this.modeManager,
21312
+ eventManager: this.eventManager,
21313
+ getFeatureGroups: () => this.arrayOfFeatureGroups
21314
+ });
21315
+ }
21316
+ /**
21317
+ * Loads an external configuration file and merges it with the default and inline configs.
21318
+ * @param configPath - The path to the external configuration file.
21319
+ * @param inlineConfig - An optional inline configuration object.
21320
+ */
21321
+ async loadExternalConfig(configPath, inlineConfig) {
21322
+ try {
21323
+ const response = await fetch(configPath);
21324
+ if (!response.ok) {
21325
+ throw new Error(
21326
+ `Failed to load config from ${configPath}: ${response.status} ${response.statusText}`
21327
+ );
20851
21328
  }
21329
+ const externalConfig = await response.json();
21330
+ this.config = {
21331
+ ...defaultConfig,
21332
+ ...externalConfig,
21333
+ ...inlineConfig || {}
21334
+ };
21335
+ this.initializeComponents();
21336
+ } catch (error) {
21337
+ console.warn(
21338
+ "Failed to load external config, falling back to default + inline config:",
21339
+ error
21340
+ );
21341
+ this.config = { ...defaultConfig, ...inlineConfig || {} };
21342
+ this.initializeComponents();
20852
21343
  }
20853
21344
  }
20854
- setDrawMode(mode) {
20855
- const previousMode = this.drawMode;
21345
+ /**
21346
+ * Initializes the core components of the Polydraw control.
21347
+ */
21348
+ /**
21349
+ * Updates the state of the drawing mode.
21350
+ * @param mode - The new drawing mode.
21351
+ */
21352
+ _updateDrawModeState(mode) {
20856
21353
  this.drawMode = mode;
20857
21354
  this.modeManager.updateStateForMode(mode);
20858
21355
  this.emitDrawModeChanged();
20859
21356
  this.updateMarkerDraggableState();
20860
- if (previousMode === DrawMode.PointToPoint && mode !== DrawMode.PointToPoint) {
20861
- this.polygonDrawManager.clearP2pMarkers();
20862
- this.stopDraw();
20863
- } else if (mode === DrawMode.Off) {
20864
- this.stopDraw();
20865
- } else if (mode !== DrawMode.PointToPoint) {
20866
- this.stopDraw();
21357
+ }
21358
+ /**
21359
+ * Updates the UI after a change in the drawing mode.
21360
+ * @param mode - The new drawing mode.
21361
+ */
21362
+ _updateUIAfterDrawModeChange(mode) {
21363
+ const shouldShowCrosshair = this.modeManager.shouldShowCrosshairCursor();
21364
+ if (shouldShowCrosshair) {
21365
+ L.DomUtil.addClass(this.map.getContainer(), "crosshair-cursor-enabled");
21366
+ } else {
21367
+ L.DomUtil.removeClass(this.map.getContainer(), "crosshair-cursor-enabled");
20867
21368
  }
20868
- if (this.map) {
20869
- const shouldShowCrosshair = this.modeManager.shouldShowCrosshairCursor();
20870
- const mapDragEnabled = this.modeManager.canPerformAction("mapDrag");
20871
- const mapZoomEnabled = this.modeManager.canPerformAction("mapZoom");
20872
- const mapDoubleClickEnabled = this.modeManager.canPerformAction("mapDoubleClickZoom");
20873
- if (shouldShowCrosshair) {
20874
- L.DomUtil.addClass(this.map.getContainer(), "crosshair-cursor-enabled");
20875
- } else {
20876
- L.DomUtil.removeClass(this.map.getContainer(), "crosshair-cursor-enabled");
20877
- }
20878
- this.events(mode !== DrawMode.Off);
20879
- try {
20880
- switch (mode) {
20881
- case DrawMode.Off:
20882
- this.tracer.setStyle({ color: "" });
20883
- break;
20884
- case DrawMode.Add:
20885
- this.tracer.setStyle({
20886
- color: defaultConfig.polyLineOptions.color,
20887
- dashArray: null
20888
- // Reset to solid line
20889
- });
20890
- break;
20891
- case DrawMode.Subtract:
20892
- this.tracer.setStyle({
20893
- color: "#D9460F",
20894
- dashArray: null
20895
- // Reset to solid line
20896
- });
20897
- break;
20898
- case DrawMode.PointToPoint:
20899
- this.tracer.setStyle({
20900
- color: defaultConfig.polyLineOptions.color,
20901
- dashArray: "5, 5"
20902
- });
20903
- break;
20904
- }
20905
- } catch (error) {
21369
+ try {
21370
+ switch (mode) {
21371
+ case DrawMode.Off:
21372
+ this.tracer.setStyle({ color: "" });
21373
+ break;
21374
+ case DrawMode.Add:
21375
+ this.tracer.setStyle({
21376
+ color: this.config.colors.polyline,
21377
+ dashArray: null
21378
+ // Reset to solid line
21379
+ });
21380
+ break;
21381
+ case DrawMode.Subtract:
21382
+ this.tracer.setStyle({
21383
+ color: this.config.colors.subtractLine,
21384
+ dashArray: null
21385
+ // Reset to solid line
21386
+ });
21387
+ break;
21388
+ case DrawMode.PointToPoint:
21389
+ this.tracer.setStyle({
21390
+ color: this.config.colors.polyline,
21391
+ dashArray: "5, 5"
21392
+ });
21393
+ break;
20906
21394
  }
20907
- this.setLeafletMapEvents(mapDragEnabled, mapDoubleClickEnabled, mapZoomEnabled);
21395
+ } catch (error) {
20908
21396
  }
20909
21397
  }
20910
- getDrawMode() {
20911
- return this.modeManager.getCurrentMode();
20912
- }
20913
- on(event, callback) {
20914
- this.eventManager.on(event, callback);
21398
+ _updateMapInteractions() {
21399
+ const mapDragEnabled = this.modeManager.canPerformAction("mapDrag");
21400
+ const mapZoomEnabled = this.modeManager.canPerformAction("mapZoom");
21401
+ const mapDoubleClickEnabled = this.modeManager.canPerformAction("mapDoubleClickZoom");
21402
+ this.events(this.drawMode !== DrawMode.Off);
21403
+ this.setLeafletMapEvents(mapDragEnabled, mapDoubleClickEnabled, mapZoomEnabled);
20915
21404
  }
20916
- off(event, callback) {
20917
- this.eventManager.off(event, callback);
21405
+ initializeComponents() {
21406
+ this.turfHelper = new TurfHelper(this.config);
21407
+ this.mapStateService = new MapStateService();
21408
+ this.eventManager = new EventManager();
21409
+ this.polygonInformation = new PolygonInformationService(this.mapStateService);
21410
+ this.modeManager = new ModeManager(this.config, this.eventManager);
21411
+ this.polygonInformation.onPolygonInfoUpdated((_k) => {
21412
+ this.updateActivateButtonIndicator();
21413
+ });
21414
+ this._boundKeyDownHandler = this.handleKeyDown.bind(this);
21415
+ this.polygonMutationManager = null;
21416
+ this.polygonDrawManager = null;
20918
21417
  }
21418
+ /**
21419
+ * Emits an event to notify listeners that the drawing mode has changed.
21420
+ */
20919
21421
  emitDrawModeChanged() {
20920
21422
  this.eventManager.emit("polydraw:mode:change", {
20921
21423
  mode: this.modeManager.getCurrentMode()
@@ -20948,30 +21450,34 @@ class Polydraw extends L.Control {
20948
21450
  });
20949
21451
  });
20950
21452
  }
20951
- removeAllFeatureGroups() {
20952
- this.arrayOfFeatureGroups.forEach((featureGroups) => {
20953
- try {
20954
- this.map.removeLayer(featureGroups);
20955
- } catch (error) {
20956
- }
20957
- });
20958
- this.arrayOfFeatureGroups.length = 0;
20959
- this.polygonInformation.deletePolygonInformationStorage();
20960
- this.polygonInformation.updatePolygons();
20961
- this.updateActivateButtonIndicator();
20962
- }
21453
+ /**
21454
+ * Stops the current drawing operation and resets the tracer.
21455
+ */
20963
21456
  stopDraw() {
20964
21457
  this.resetTracker();
20965
21458
  this.drawStartedEvents(false);
20966
21459
  }
21460
+ /**
21461
+ * Enables or disables Leaflet's default map interactions.
21462
+ * @param enableDragging - Whether to enable map dragging.
21463
+ * @param enableDoubleClickZoom - Whether to enable double-click zoom.
21464
+ * @param enableScrollWheelZoom - Whether to enable scroll wheel zoom.
21465
+ */
20967
21466
  setLeafletMapEvents(enableDragging, enableDoubleClickZoom, enableScrollWheelZoom) {
20968
21467
  enableDragging ? this.map.dragging.enable() : this.map.dragging.disable();
20969
21468
  enableDoubleClickZoom ? this.map.doubleClickZoom.enable() : this.map.doubleClickZoom.disable();
20970
21469
  enableScrollWheelZoom ? this.map.scrollWheelZoom.enable() : this.map.scrollWheelZoom.disable();
20971
21470
  }
21471
+ /**
21472
+ * Resets the tracer polyline by clearing its LatLngs.
21473
+ */
20972
21474
  resetTracker() {
20973
21475
  this.tracer.setLatLngs([]);
20974
21476
  }
21477
+ /**
21478
+ * Attaches or detaches the mouse move and mouse up event listeners for drawing.
21479
+ * @param onoff - A boolean indicating whether to attach or detach the events.
21480
+ */
20975
21481
  drawStartedEvents(onoff) {
20976
21482
  const onoroff = onoff ? "on" : "off";
20977
21483
  this.map[onoroff]("mousemove", this.mouseMove, this);
@@ -20990,6 +21496,57 @@ class Polydraw extends L.Control {
20990
21496
  }
20991
21497
  }
20992
21498
  }
21499
+ /**
21500
+ * Attaches or detaches the main drawing event listeners.
21501
+ * @param onoff - A boolean indicating whether to attach or detach the events.
21502
+ */
21503
+ events(onoff) {
21504
+ const onoroff = onoff ? "on" : "off";
21505
+ this.map[onoroff]("mousedown", this.mouseDown, this);
21506
+ this.map[onoroff]("dblclick", this.handleDoubleClick, this);
21507
+ if (onoff) {
21508
+ this._boundTouchStart = (e) => this.mouseDown(e);
21509
+ this.map.getContainer().addEventListener("touchstart", this._boundTouchStart, { passive: false });
21510
+ } else {
21511
+ if (this._boundTouchStart) {
21512
+ this.map.getContainer().removeEventListener("touchstart", this._boundTouchStart);
21513
+ }
21514
+ }
21515
+ }
21516
+ /**
21517
+ * Handles the mouse down event to start a drawing operation.
21518
+ * @param event - The mouse or touch event.
21519
+ */
21520
+ mouseDown(event) {
21521
+ if ("cancelable" in event && event.cancelable) {
21522
+ event.preventDefault();
21523
+ }
21524
+ if (this.modeManager.isInOffMode()) {
21525
+ return;
21526
+ }
21527
+ let clickLatLng;
21528
+ if ("latlng" in event && event.latlng) {
21529
+ clickLatLng = event.latlng;
21530
+ } else if ("touches" in event && event.touches && event.touches.length > 0) {
21531
+ clickLatLng = this.map.containerPointToLatLng([
21532
+ event.touches[0].clientX,
21533
+ event.touches[0].clientY
21534
+ ]);
21535
+ }
21536
+ if (!clickLatLng) {
21537
+ return;
21538
+ }
21539
+ if (this.modeManager.getCurrentMode() === DrawMode.PointToPoint) {
21540
+ this.polygonDrawManager.handlePointToPointClick(clickLatLng);
21541
+ return;
21542
+ }
21543
+ this.tracer.setLatLngs([clickLatLng]);
21544
+ this.startDraw();
21545
+ }
21546
+ /**
21547
+ * Handles the mouse move event to draw the tracer polyline.
21548
+ * @param event - The mouse or touch event.
21549
+ */
20993
21550
  mouseMove(event) {
20994
21551
  if ("cancelable" in event && event.cancelable) {
20995
21552
  event.preventDefault();
@@ -21004,33 +21561,10 @@ class Polydraw extends L.Control {
21004
21561
  this.tracer.addLatLng(latlng);
21005
21562
  }
21006
21563
  }
21007
- async handleFreehandDrawCompletion(geoPos) {
21008
- try {
21009
- switch (this.modeManager.getCurrentMode()) {
21010
- case DrawMode.Add: {
21011
- const result = await this.polygonMutationManager.addPolygon(geoPos, {
21012
- simplify: true,
21013
- noMerge: false
21014
- });
21015
- if (!result.success) {
21016
- console.error("Error adding polygon via manager:", result.error);
21017
- }
21018
- break;
21019
- }
21020
- case DrawMode.Subtract: {
21021
- const subtractResult = await this.polygonMutationManager.subtractPolygon(geoPos);
21022
- if (!subtractResult.success) {
21023
- console.error("Error subtracting polygon via manager:", subtractResult.error);
21024
- }
21025
- break;
21026
- }
21027
- default:
21028
- break;
21029
- }
21030
- } catch (error) {
21031
- console.error("Error in mouseUpLeave polygon operation:", error);
21032
- }
21033
- }
21564
+ /**
21565
+ * Handles the mouse up event to complete a drawing operation.
21566
+ * @param event - The mouse or touch event.
21567
+ */
21034
21568
  async mouseUpLeave(event) {
21035
21569
  if ("cancelable" in event && event.cancelable) {
21036
21570
  event.preventDefault();
@@ -21080,57 +21614,62 @@ class Polydraw extends L.Control {
21080
21614
  }
21081
21615
  this.polygonInformation.createPolygonInformationStorage(this.arrayOfFeatureGroups);
21082
21616
  }
21083
- events(onoff) {
21084
- const onoroff = onoff ? "on" : "off";
21085
- this.map[onoroff]("mousedown", this.mouseDown, this);
21086
- this.map[onoroff]("dblclick", this.handleDoubleClick, this);
21087
- if (onoff) {
21088
- this._boundTouchStart = (e) => this.mouseDown(e);
21089
- this.map.getContainer().addEventListener("touchstart", this._boundTouchStart, { passive: false });
21090
- } else {
21091
- if (this._boundTouchStart) {
21092
- this.map.getContainer().removeEventListener("touchstart", this._boundTouchStart);
21617
+ /**
21618
+ * Handles the completion of a freehand drawing operation.
21619
+ * @param geoPos - The GeoJSON feature representing the drawn polygon.
21620
+ */
21621
+ async handleFreehandDrawCompletion(geoPos) {
21622
+ try {
21623
+ switch (this.modeManager.getCurrentMode()) {
21624
+ case DrawMode.Add: {
21625
+ const result = await this.polygonMutationManager.addPolygon(geoPos, {
21626
+ simplify: true,
21627
+ noMerge: false
21628
+ });
21629
+ if (!result.success) {
21630
+ console.error("Error adding polygon via manager:", result.error);
21631
+ }
21632
+ break;
21633
+ }
21634
+ case DrawMode.Subtract: {
21635
+ const subtractResult = await this.polygonMutationManager.subtractPolygon(geoPos);
21636
+ if (!subtractResult.success) {
21637
+ console.error("Error subtracting polygon via manager:", subtractResult.error);
21638
+ }
21639
+ break;
21640
+ }
21641
+ default:
21642
+ break;
21093
21643
  }
21644
+ } catch (error) {
21645
+ console.error("Error in mouseUpLeave polygon operation:", error);
21094
21646
  }
21095
21647
  }
21096
- mouseDown(event) {
21097
- if ("cancelable" in event && event.cancelable) {
21098
- event.preventDefault();
21099
- }
21100
- if (this.modeManager.isInOffMode()) {
21101
- return;
21102
- }
21103
- let clickLatLng;
21104
- if ("latlng" in event && event.latlng) {
21105
- clickLatLng = event.latlng;
21106
- } else if ("touches" in event && event.touches && event.touches.length > 0) {
21107
- clickLatLng = this.map.containerPointToLatLng([
21108
- event.touches[0].clientX,
21109
- event.touches[0].clientY
21110
- ]);
21111
- }
21112
- if (!clickLatLng) {
21113
- return;
21114
- }
21115
- if (this.modeManager.getCurrentMode() === DrawMode.PointToPoint) {
21116
- this.polygonDrawManager.handlePointToPointClick(clickLatLng);
21117
- return;
21118
- }
21119
- this.tracer.setLatLngs([clickLatLng]);
21120
- this.startDraw();
21121
- }
21648
+ /**
21649
+ * Starts a drawing operation by attaching the necessary event listeners.
21650
+ */
21122
21651
  startDraw() {
21123
21652
  this.drawStartedEvents(true);
21124
21653
  }
21654
+ /**
21655
+ * Sets up the keyboard event handlers for the document.
21656
+ */
21125
21657
  setupKeyboardHandlers() {
21126
21658
  this._boundKeyUpHandler = this.handleKeyUp.bind(this);
21127
21659
  document.addEventListener("keydown", this._boundKeyDownHandler);
21128
21660
  document.addEventListener("keyup", this._boundKeyUpHandler);
21129
21661
  }
21662
+ /**
21663
+ * Removes the keyboard event handlers from the document.
21664
+ */
21130
21665
  removeKeyboardHandlers() {
21131
21666
  document.removeEventListener("keydown", this._boundKeyDownHandler);
21132
21667
  document.removeEventListener("keyup", this._boundKeyUpHandler);
21133
21668
  }
21669
+ /**
21670
+ * Handles the key down event for keyboard shortcuts.
21671
+ * @param e - The keyboard event.
21672
+ */
21134
21673
  handleKeyDown(e) {
21135
21674
  if (e.key === "Escape") {
21136
21675
  if (this.modeManager.getCurrentMode() === DrawMode.PointToPoint) {
@@ -21144,6 +21683,10 @@ class Polydraw extends L.Control {
21144
21683
  this.updateAllMarkersForEdgeDeletion(true);
21145
21684
  }
21146
21685
  }
21686
+ /**
21687
+ * Handles the key up event for keyboard shortcuts.
21688
+ * @param e - The keyboard event.
21689
+ */
21147
21690
  handleKeyUp(e) {
21148
21691
  const isModifierPressed = this.isModifierKeyPressed(e);
21149
21692
  if (!isModifierPressed && this.isModifierKeyHeld) {
@@ -21180,6 +21723,10 @@ class Polydraw extends L.Control {
21180
21723
  element.style.borderColor = "";
21181
21724
  }
21182
21725
  }
21726
+ /**
21727
+ * Handles the double-click event for point-to-point drawing.
21728
+ * @param e - The mouse event.
21729
+ */
21183
21730
  handleDoubleClick(e) {
21184
21731
  if (this.modeManager.getCurrentMode() !== DrawMode.PointToPoint) {
21185
21732
  return;
@@ -21198,6 +21745,9 @@ class Polydraw extends L.Control {
21198
21745
  return event.ctrlKey;
21199
21746
  }
21200
21747
  }
21748
+ /**
21749
+ * Updates the visual indicator on the activate button to show if there are active polygons.
21750
+ */
21201
21751
  updateActivateButtonIndicator() {
21202
21752
  if (typeof this.getContainer !== "function") {
21203
21753
  return;