diff --git a/Components/Pages/Home.razor b/Components/Pages/Home.razor
index 17ac592..1aa5ca8 100644
--- a/Components/Pages/Home.razor
+++ b/Components/Pages/Home.razor
@@ -673,6 +673,17 @@
Imposta 0 per lasciare i messaggi visibili fino alla chiusura manuale.
+
+
@@ -877,6 +888,9 @@
private bool GpsActive { get; set; }
private bool GpsOverlayCollapsed { get; set; }
private bool ShowGpsPosition { get; set; } = true;
+ private bool ShowCompass { get; set; }
+ private string CompassMode { get; set; } = "heading";
+ private bool CompassSensorSubscribed { get; set; }
private bool ShowSelectedParcels { get; set; } = true;
private bool ShowFiducialPoints { get; set; } = true;
private bool KeepPreviousFiducialPoints { get; set; } = true;
@@ -1788,6 +1802,15 @@
return InvokeAsync(StateHasChanged);
}
+ [JSInvokable]
+ public async Task SetCompassFromLayerManager(bool enabled)
+ {
+ ShowCompass = enabled;
+ SaveFlagPreferences();
+ await ConfigureCompassSensorAsync();
+ await InvokeAsync(StateHasChanged);
+ }
+
[JSInvokable]
public Task GetOfficialCadastralSheetsNear(double latitude, double longitude) =>
OfficialCadastreService.GetSheetsNearAsync(latitude, longitude);
@@ -2298,6 +2321,8 @@
ShowDrawingMeasurements = options.ShowDrawingMeasurements;
DrawToolsVisible = options.DrawToolsVisible;
ShowGpsPosition = options.GpsPositionVisible;
+ ShowCompass = options.CompassVisible;
+ CompassMode = options.CompassMode is "fixed" ? "fixed" : "heading";
ShowSelectedParcels = options.SelectedParcelsVisible;
TrailEnabled = options.TrailEnabled;
@@ -2307,6 +2332,7 @@
layer.Enabled = activeLayers.Contains(layer.Key);
}
SaveFlagPreferences();
+ _ = ConfigureCompassSensorAsync();
}
private async Task DeleteProject()
@@ -2718,6 +2744,8 @@
ShowDrawingMeasurements = GetFlagPreference("show_drawing_measurements", true);
DrawToolsVisible = GetFlagPreference("draw_tools_visible", false);
ShowGpsPosition = GetFlagPreference("show_gps_position", true);
+ ShowCompass = GetFlagPreference("show_compass", false);
+ CompassMode = Preferences.Default.Get($"{FlagPreferencePrefix}compass_mode", "heading") is "fixed" ? "fixed" : "heading";
ShowSelectedParcels = GetFlagPreference("show_selected_parcels", true);
ShowFiducialPoints = GetFlagPreference("show_fiducial_points", true);
KeepPreviousFiducialPoints = GetFlagPreference("keep_previous_fiducials", true);
@@ -2761,6 +2789,8 @@
SetFlagPreference("show_drawing_measurements", ShowDrawingMeasurements);
SetFlagPreference("draw_tools_visible", DrawToolsVisible);
SetFlagPreference("show_gps_position", ShowGpsPosition);
+ SetFlagPreference("show_compass", ShowCompass);
+ Preferences.Default.Set($"{FlagPreferencePrefix}compass_mode", CompassMode);
SetFlagPreference("show_selected_parcels", ShowSelectedParcels);
SetFlagPreference("show_fiducial_points", ShowFiducialPoints);
SetFlagPreference("keep_previous_fiducials", KeepPreviousFiducialPoints);
@@ -2801,6 +2831,8 @@
await JS.InvokeVoidAsync("lmeMap.setDrawingMeasurementsVisible", ShowDrawingMeasurements);
await JS.InvokeVoidAsync("lmeMap.setDrawToolsVisible", DrawToolsVisible);
await JS.InvokeVoidAsync("lmeMap.setGpsPositionVisible", ShowGpsPosition);
+ await JS.InvokeVoidAsync("lmeMap.setCompassOptions", ShowCompass, CompassMode);
+ await ConfigureCompassSensorAsync();
await JS.InvokeVoidAsync("lmeMap.setSelectedParcelsVisible", ShowSelectedParcels);
await JS.InvokeVoidAsync("lmeMap.setFiducialColor", FiducialColor);
await JS.InvokeVoidAsync("lmeMap.setFiducialPointsVisible", ShowFiducialPoints);
@@ -2819,6 +2851,68 @@
await JS.InvokeVoidAsync("lmeMap.setInfoTimeout", MapMessageTimeoutSeconds);
}
+ private async Task ApplyCompassOptions()
+ {
+ CompassMode = CompassMode is "fixed" ? "fixed" : "heading";
+ SaveFlagPreferences();
+ await JS.InvokeVoidAsync("lmeMap.setCompassOptions", ShowCompass, CompassMode);
+ await ConfigureCompassSensorAsync();
+ }
+
+ private Task ConfigureCompassSensorAsync()
+ {
+ var compass = Microsoft.Maui.Devices.Sensors.Compass.Default;
+ var shouldMonitor = ShowCompass && CompassMode == "heading" && compass.IsSupported;
+ try
+ {
+ if (shouldMonitor && !CompassSensorSubscribed)
+ {
+ compass.ReadingChanged += OnCompassReadingChanged;
+ CompassSensorSubscribed = true;
+ compass.Start(Microsoft.Maui.Devices.Sensors.SensorSpeed.UI);
+ }
+ else if (!shouldMonitor && CompassSensorSubscribed)
+ {
+ compass.ReadingChanged -= OnCompassReadingChanged;
+ CompassSensorSubscribed = false;
+ if (compass.IsMonitoring)
+ {
+ compass.Stop();
+ }
+ }
+ }
+ catch
+ {
+ if (CompassSensorSubscribed)
+ {
+ compass.ReadingChanged -= OnCompassReadingChanged;
+ CompassSensorSubscribed = false;
+ }
+ }
+
+ return Task.CompletedTask;
+ }
+
+ private async void OnCompassReadingChanged(
+ object? sender,
+ Microsoft.Maui.Devices.Sensors.CompassChangedEventArgs args)
+ {
+ if (!MapReady || !ShowCompass || CompassMode != "heading")
+ {
+ return;
+ }
+
+ try
+ {
+ await InvokeAsync(() => JS.InvokeVoidAsync(
+ "lmeMap.setCompassHeading",
+ args.Reading.HeadingMagneticNorth).AsTask());
+ }
+ catch
+ {
+ }
+ }
+
private async Task ApplyAdvancedOptions()
{
SaveFlagPreferences();
@@ -2893,6 +2987,8 @@
public bool ShowDrawingMeasurements { get; init; } = true;
public bool DrawToolsVisible { get; init; }
public bool GpsPositionVisible { get; init; } = true;
+ public bool CompassVisible { get; init; }
+ public string CompassMode { get; init; } = "heading";
public bool SelectedParcelsVisible { get; init; } = true;
public bool TrailEnabled { get; init; }
}
@@ -2922,6 +3018,16 @@
GpsLookupCancellation?.Dispose();
ProjectAutoSaveCancellation?.Cancel();
ProjectAutoSaveCancellation?.Dispose();
+ var compass = Microsoft.Maui.Devices.Sensors.Compass.Default;
+ if (CompassSensorSubscribed)
+ {
+ compass.ReadingChanged -= OnCompassReadingChanged;
+ if (compass.IsMonitoring)
+ {
+ compass.Stop();
+ }
+ CompassSensorSubscribed = false;
+ }
MapCallbackReference?.Dispose();
return ValueTask.CompletedTask;
}
diff --git a/wwwroot/css/app.css b/wwwroot/css/app.css
index fbed80d..3e17b55 100644
--- a/wwwroot/css/app.css
+++ b/wwwroot/css/app.css
@@ -1674,6 +1674,72 @@ label {
line-height: 1;
}
+.map-compass {
+ --compass-rotation: 0deg;
+ position: absolute;
+ top: 50%;
+ left: 12px;
+ z-index: 810;
+ width: 54px;
+ height: 54px;
+ transform: translateY(-50%);
+ border: 2px solid rgba(255, 255, 255, 0.92);
+ border-radius: 50%;
+ background: rgba(22, 31, 38, 0.86);
+ box-shadow: 0 2px 9px rgba(0, 0, 0, 0.3);
+ color: #fff;
+ pointer-events: none;
+}
+
+.map-compass-north {
+ position: absolute;
+ top: 2px;
+ left: 50%;
+ transform: translateX(-50%);
+ color: #fca5a5;
+ font-size: 11px;
+ font-weight: 900;
+ line-height: 1;
+}
+
+.map-compass-needle {
+ position: absolute;
+ bottom: 25px;
+ left: 50%;
+ width: 4px;
+ height: 18px;
+ transform: translateX(-50%) rotate(var(--compass-rotation));
+ transform-origin: 50% 100%;
+ border-radius: 4px 4px 1px 1px;
+ background: #ef4444;
+ transition: transform 120ms linear;
+}
+
+.map-compass-needle::after {
+ position: absolute;
+ top: -5px;
+ left: 50%;
+ width: 0;
+ height: 0;
+ transform: translateX(-50%);
+ border-right: 5px solid transparent;
+ border-bottom: 7px solid #ef4444;
+ border-left: 5px solid transparent;
+ content: "";
+}
+
+.map-compass-center {
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ width: 8px;
+ height: 8px;
+ transform: translate(-50%, -50%);
+ border: 2px solid #fff;
+ border-radius: 50%;
+ background: #17212b;
+}
+
.wms-preview[hidden] {
display: none;
}
@@ -1948,6 +2014,12 @@ footer {
white-space: normal;
}
+ .map-compass {
+ left: 8px;
+ width: 48px;
+ height: 48px;
+ }
+
.map-info-text {
display: -webkit-box;
overflow: hidden;
diff --git a/wwwroot/index.html b/wwwroot/index.html
index 4c0e2f9..6a33e3e 100644
--- a/wwwroot/index.html
+++ b/wwwroot/index.html
@@ -27,6 +27,7 @@
+
diff --git a/wwwroot/js/lme-map.js b/wwwroot/js/lme-map.js
index 4a88e72..5d0dd59 100644
--- a/wwwroot/js/lme-map.js
+++ b/wwwroot/js/lme-map.js
@@ -12,6 +12,7 @@ const lmeState = {
"selectedParcels",
"importedSheets",
"imported",
+ "compass",
"cadastre"
],
cadastre: null,
@@ -61,6 +62,11 @@ const lmeState = {
gpsTrailStartedAt: null,
gpsWatchId: null,
lastPosition: null,
+ compassLayer: null,
+ compassElement: null,
+ compassVisible: false,
+ compassMode: "heading",
+ compassHeading: 0,
infoTimeoutSeconds: 3,
infoTimer: null,
fileImportBound: false,
@@ -185,6 +191,8 @@ window.lmeMap = {
getGpsTrailStats,
setNativeGpsPosition,
setGpsPositionVisible,
+ setCompassOptions,
+ setCompassHeading,
setGpsError,
saveGpsMeasurementPoint,
restoreLastTrashItem,
@@ -259,7 +267,13 @@ function init(dotNetReference) {
lmeState.map = L.map("map", {
zoomControl: false,
- attributionControl: false
+ attributionControl: false,
+ rotate: true,
+ bearing: 0,
+ dragRotate: false,
+ touchRotate: false,
+ shiftKeyRotate: false,
+ rotateControl: false
}).setView([41.9028, 12.4964], 17);
L.control.zoom({ position: "bottomright" }).addTo(lmeState.map);
@@ -303,13 +317,19 @@ function init(dotNetReference) {
lmeState.baseLayers.offline = createOfflineTileLayer();
lmeState.currentBase = lmeState.baseLayers.satellite.addTo(lmeState.map);
+ lmeState.compassLayer = createCompassLayer();
restoreLayerOrder();
Object.values(managedLayerPanes()).forEach(paneName => {
if (!lmeState.map.getPane(paneName)) {
- lmeState.map.createPane(paneName);
+ const noRotation = paneName === "gpsPositionPane" || paneName === "fiducialsPane";
+ lmeState.map.createPane(paneName, noRotation
+ ? (lmeState.map._norotatePane || lmeState.map._mapPane)
+ : (lmeState.map._rotatePane || lmeState.map._mapPane));
}
});
- const managerHighlightPane = lmeState.map.createPane("managerHighlightPane");
+ lmeState.map.createPane("drawingsMarkerPane", lmeState.map._norotatePane || lmeState.map._mapPane);
+ lmeState.map.createPane("gpsAccuracyPane", lmeState.map._rotatePane || lmeState.map._mapPane);
+ const managerHighlightPane = lmeState.map.createPane("managerHighlightPane", lmeState.map._rotatePane || lmeState.map._mapPane);
managerHighlightPane.style.zIndex = "650";
lmeState.drawingsRenderer = L.canvas({ pane: "drawingsPane", tolerance: 14 });
setLayerOrder(lmeState.layerOrder);
@@ -322,10 +342,10 @@ function init(dotNetReference) {
lmeState.selectedParcelsLayer = L.featureGroup().addTo(lmeState.map);
lmeState.fiducials = L.featureGroup().addTo(lmeState.map);
lmeState.gpsParcelLayer = L.featureGroup().addTo(lmeState.map);
- const navigationSheetPane = lmeState.map.createPane("navigationSheetPane");
+ const navigationSheetPane = lmeState.map.createPane("navigationSheetPane", lmeState.map._rotatePane || lmeState.map._mapPane);
navigationSheetPane.style.zIndex = "465";
navigationSheetPane.style.pointerEvents = "none";
- const cadastreZoningPane = lmeState.map.createPane("cadastreZoningPane");
+ const cadastreZoningPane = lmeState.map.createPane("cadastreZoningPane", lmeState.map._rotatePane || lmeState.map._mapPane);
cadastreZoningPane.style.zIndex = "455";
cadastreZoningPane.style.pointerEvents = "none";
lmeState.navigationSheetLayer = L.layerGroup().addTo(lmeState.map);
@@ -416,6 +436,71 @@ function init(dotNetReference) {
setInfo("Mappa pronta: satellite + catasto AdE");
}
+function createCompassLayer() {
+ return new (L.Layer.extend({
+ onAdd(map) {
+ const element = L.DomUtil.create("div", "map-compass");
+ element.setAttribute("role", "img");
+ element.setAttribute("aria-label", "Bussola: nord");
+ element.innerHTML = `N`;
+ L.DomEvent.disableClickPropagation(element);
+ map.getContainer().appendChild(element);
+ lmeState.compassElement = element;
+ updateCompassDisplay();
+ },
+ onRemove() {
+ lmeState.compassElement?.remove();
+ lmeState.compassElement = null;
+ }
+ }))();
+}
+
+function setCompassOptions(visible, mode = "heading") {
+ lmeState.compassVisible = Boolean(visible);
+ lmeState.compassMode = mode === "fixed" ? "fixed" : "heading";
+ if (!lmeState.map || !lmeState.compassLayer) return;
+ if (lmeState.compassVisible) {
+ lmeState.managerHiddenCategories.delete("compass");
+ if (!lmeState.map.hasLayer(lmeState.compassLayer)) {
+ lmeState.compassLayer.addTo(lmeState.map);
+ }
+ } else {
+ lmeState.managerHiddenCategories.add("compass");
+ if (lmeState.map.hasLayer(lmeState.compassLayer)) {
+ lmeState.map.removeLayer(lmeState.compassLayer);
+ }
+ }
+ if (!lmeState.compassVisible || lmeState.compassMode === "fixed") {
+ lmeState.map.setHeading?.(null);
+ lmeState.map.setBearing?.(0);
+ } else if (Number.isFinite(lmeState.compassHeading)) {
+ lmeState.map.setHeading?.(lmeState.compassHeading, { ease: 0.2, deadzone: 1 });
+ }
+ updateCompassDisplay();
+ refreshLayerManager();
+}
+
+function setCompassHeading(heading) {
+ const parsed = Number(heading);
+ if (!Number.isFinite(parsed)) return;
+ lmeState.compassHeading = ((parsed % 360) + 360) % 360;
+ if (lmeState.compassVisible && lmeState.compassMode === "heading") {
+ lmeState.map?.setHeading?.(lmeState.compassHeading, { ease: 0.2, deadzone: 1 });
+ }
+ updateCompassDisplay();
+}
+
+function updateCompassDisplay() {
+ const element = lmeState.compassElement;
+ if (!element) return;
+ const rotation = lmeState.compassMode === "fixed" ? 0 : -lmeState.compassHeading;
+ element.classList.toggle("is-fixed", lmeState.compassMode === "fixed");
+ element.style.setProperty("--compass-rotation", `${rotation}deg`);
+ element.setAttribute("aria-label", lmeState.compassMode === "fixed"
+ ? "Bussola: nord fisso in alto"
+ : `Bussola: nord, orientamento ${Math.round(lmeState.compassHeading)} gradi`);
+}
+
function showSearchResult(latitude, longitude, label) {
const lat = Number(latitude);
const lon = Number(longitude);
@@ -1353,6 +1438,7 @@ function managedLayerPanes() {
fiducials: "fiducialsPane",
importedSheets: "importedSheetPane",
imported: "importedPane",
+ compass: "compassPane",
cadastre: "cadastrePane"
};
}
@@ -1366,10 +1452,14 @@ function setLayerOrder(order) {
return;
}
normalized.forEach((key, index) => {
- const pane = lmeState.map.getPane(panes[key]);
- if (pane) {
- pane.style.zIndex = String(590 - index * 20);
- }
+ const zIndex = String(590 - index * 20);
+ const paneNames = [panes[key]];
+ if (key === "drawings") paneNames.push("drawingsMarkerPane");
+ if (key === "gpsPosition") paneNames.push("gpsAccuracyPane");
+ paneNames.forEach(paneName => {
+ const pane = lmeState.map.getPane(paneName);
+ if (pane) pane.style.zIndex = zIndex;
+ });
});
try {
localStorage.setItem("lmeMapLayerOrder", JSON.stringify(normalized));
@@ -1382,6 +1472,10 @@ function restoreLayerOrder() {
const saved = JSON.parse(localStorage.getItem("lmeMapLayerOrder") || "null");
if (Array.isArray(saved)) {
const remaining = saved.filter(key => !["gpsPosition", "gpsTrail", "fiducials"].includes(key));
+ if (!remaining.includes("compass")) {
+ const cadastreIndex = remaining.indexOf("cadastre");
+ remaining.splice(cadastreIndex >= 0 ? cadastreIndex : remaining.length, 0, "compass");
+ }
lmeState.layerOrder = ["gpsPosition", "gpsTrail", "fiducials", ...remaining];
}
} catch {
@@ -1443,6 +1537,7 @@ function layerManagerCategories() {
{ key: "fiducials", label: "Punti fiduciali", roots: [lmeState.fiducials].filter(Boolean), blocks: true },
{ key: "importedSheets", label: "Cornici e fogli importati", roots: [lmeState.importedSheets].filter(Boolean), blocks: true },
{ key: "imported", label: "Progetti e dati importati", roots: [lmeState.imported].filter(Boolean), blocks: true },
+ { key: "compass", label: "Bussola", roots: [lmeState.compassLayer].filter(Boolean), uiOnly: true },
{ key: "cadastre", label: "Layer catastali AdE", roots: [lmeState.cadastre].filter(Boolean) }
];
}
@@ -1480,6 +1575,9 @@ function collectManagedLeafLayers(layer, categoryKey, parent, records) {
}
function managedRecordsForCategory(category) {
+ if (category.uiOnly) {
+ return [];
+ }
const records = [];
category.roots.forEach(root => collectManagedLeafLayers(root, category.key, lmeState.map, records));
lmeState.managerHiddenObjects.forEach(record => {
@@ -2712,7 +2810,7 @@ function addDrawingFeature(feature, select = false) {
style: storedFeatureStyle,
pointToLayer: (item, latlng) => item?.properties?._lmeShape === "circle" && Number(item.properties._lmeRadius) > 0
? L.circle(latlng, { pane: "drawingsPane", renderer: lmeState.drawingsRenderer, radius: Number(item.properties._lmeRadius) })
- : L.marker(latlng, { pane: "drawingsPane", draggable: false }),
+ : L.marker(latlng, { pane: "drawingsMarkerPane", draggable: false }),
onEachFeature: (item, layer) => {
annotateDrawingLayer(layer, item?.properties?._lmeShape);
applyStyleFromProperties(layer);
@@ -3389,6 +3487,13 @@ function setManagedCategoryVisible(category, visible) {
lmeState.fiducialsVisible = visible;
} else if (category.key === "gpsPosition") {
lmeState.gpsPositionVisible = visible;
+ } else if (category.key === "compass") {
+ lmeState.compassVisible = visible;
+ void lmeState.dotNetReference?.invokeMethodAsync("SetCompassFromLayerManager", visible);
+ if (!visible) {
+ lmeState.map.setHeading?.(null);
+ lmeState.map.setBearing?.(0);
+ }
}
if (visible) {
lmeState.managerHiddenCategories.delete(category.key);
@@ -3992,7 +4097,7 @@ function addProjectMarker(name) {
rememberMapChange();
const center = lmeState.map.getCenter();
const label = (name || "Nuovo POI").trim();
- const marker = L.marker(center, { pane: "drawingsPane", draggable: false }).addTo(lmeState.drawings);
+ const marker = L.marker(center, { pane: "drawingsMarkerPane", draggable: false }).addTo(lmeState.drawings);
marker.lmeManagerLabel = `POI: ${label}`;
marker.feature = {
type: "Feature",
@@ -4697,7 +4802,7 @@ function addMeasurementLabel(targetGroup, latLng, html, labelType, context) {
return;
}
L.marker(latLng, {
- pane: context.sourceType === "drawing" ? "drawingsPane" : "importedPane",
+ pane: "tooltipPane",
interactive: false,
keyboard: false,
icon: L.divIcon({
@@ -4840,7 +4945,7 @@ function circleToPolygon(center, radiusMeters) {
function createProjectSnapshot(includeCadastralParcels) {
const center = lmeState.map.getCenter();
return JSON.stringify({
- schemaVersion: 6,
+ schemaVersion: 7,
view: {
latitude: center.lat,
longitude: center.lng,
@@ -4905,7 +5010,7 @@ function loadProjectSnapshot(raw, projectName) {
fillOpacity: 0.2
});
}
- return L.marker(latlng, { pane: "drawingsPane", draggable: false });
+ return L.marker(latlng, { pane: "drawingsMarkerPane", draggable: false });
},
onEachFeature: (feature, layer) => {
bindStoredFeaturePopup(feature, layer);
@@ -5023,6 +5128,8 @@ function captureDisplayOptions() {
showDrawingMeasurements: lmeState.showDrawingMeasurements,
drawToolsVisible: Boolean(lmeState.drawControl),
gpsPositionVisible: lmeState.gpsPositionVisible,
+ compassVisible: lmeState.compassVisible,
+ compassMode: lmeState.compassMode,
selectedParcelsVisible: lmeState.selectedParcelsVisible,
fiducialsVisible: lmeState.fiducialsVisible,
fiducialColor: lmeState.fiducialColor,
@@ -5092,6 +5199,9 @@ function applyProjectDisplayOptions(options) {
setBaseLayer(options.baseLayer);
}
setGpsPositionVisible(options.gpsPositionVisible !== false);
+ const compassVisible = Boolean(options.compassVisible)
+ && !lmeState.managerHiddenCategories.has("compass");
+ setCompassOptions(compassVisible, options.compassMode);
setSelectedParcelsVisible(options.selectedParcelsVisible !== false);
if (typeof options.fiducialColor === "string") {
setFiducialColor(options.fiducialColor);
@@ -5145,6 +5255,19 @@ function emptyFeatureCollection() {
function managedGroupGeoJson(group, categoryKey) {
const collection = group?.toGeoJSON?.() || emptyFeatureCollection();
const features = [...(collection.features || [])];
+ const knownIds = new Set(features.map(feature => feature?.properties?._lmeManagerId).filter(Boolean));
+ lmeState.managerHiddenObjects.forEach(record => {
+ if (record.categoryKey !== categoryKey || typeof record.layer?.toGeoJSON !== "function") return;
+ const stored = record.layer.toGeoJSON();
+ const hiddenFeatures = stored?.type === "FeatureCollection" ? stored.features : [stored];
+ hiddenFeatures.filter(feature => feature?.type === "Feature").forEach(feature => {
+ const id = feature?.properties?._lmeManagerId;
+ if (!id || !knownIds.has(id)) {
+ features.push(feature);
+ if (id) knownIds.add(id);
+ }
+ });
+ });
const categoryName = lmeState.managerCategoryNames[categoryKey];
if (categoryName) {
features.forEach(feature => {
@@ -6102,7 +6225,7 @@ function updateGpsPositionLayers(latlng, accuracy) {
lmeState.gpsMarker.lmeManagerId = "gps-position-marker";
lmeState.gpsMarker.lmeManagerLabel = "Posizione GPS";
lmeState.gpsAccuracy = L.circle(latlng, {
- pane: "gpsPositionPane",
+ pane: "gpsAccuracyPane",
radius: accuracy,
color: "#2563eb",
weight: 2,
diff --git a/wwwroot/lib/leaflet-rotate/LICENSE b/wwwroot/lib/leaflet-rotate/LICENSE
new file mode 100644
index 0000000..c4b0e60
--- /dev/null
+++ b/wwwroot/lib/leaflet-rotate/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2026 Grzegorz Tomicki
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/wwwroot/lib/leaflet-rotate/leaflet-rotate.umd.min.js b/wwwroot/lib/leaflet-rotate/leaflet-rotate.umd.min.js
new file mode 100644
index 0000000..e82a419
--- /dev/null
+++ b/wwwroot/lib/leaflet-rotate/leaflet-rotate.umd.min.js
@@ -0,0 +1,2 @@
+/*! @tomickigrzegorz/leaflet-rotate v0.3.0 | MIT */
+!function(t,i){"object"==typeof exports&&"undefined"!=typeof module?i(require("leaflet")):"function"==typeof define&&define.amd?define(["leaflet"],i):i((t="undefined"!=typeof globalThis?globalThis:t||self).L)}(this,function(t){"use strict";t.Point.prototype.rotate=function(i){var e=Math.cos(i),o=Math.sin(i);return new t.Point(this.x*e-this.y*o,this.x*o+this.y*e)},t.Point.prototype.rotateFrom=function(t,i){return i?this.subtract(i).rotate(t).add(i):this.rotate(t)};const i=Math.PI/180,e=180/Math.PI;function o(t){return(t%360+360)%360}function a(t){return o(t+180)-180}function n(t){var i=2*Math.PI;return((t+Math.PI)%i+i)%i-Math.PI}const s=1e3/60;function r(t,i){return 1-Math.pow(1-t,i/s)}function h(){return"undefined"!=typeof performance&&performance.now?performance.now():Date.now()}var _=t.Map.prototype;t.Map.mergeOptions({rotate:!1,bearing:0,touchRotate:!1,shiftKeyRotate:!1,dragRotate:!0,rotateControl:!1,rotateClockwise:!0});var p=_.initialize;_.initialize=function(t,i){i&&i.rotate&&(this._rotate=!0,this._bearing=0,this._bearingRad=0),p.call(this,t,i),this._rotate&&this.setBearing(i.bearing||0)};var l=_._initPanes;_._initPanes=function(){if(l.call(this),this._rotate){var i=this._mapPane;this._rotatePane=t.DomUtil.create("div","leaflet-rotate-pane",i),this._norotatePane=t.DomUtil.create("div","leaflet-norotate-pane",i),this._rotatePane.appendChild(this._panes.tilePane),this._rotatePane.appendChild(this._panes.overlayPane),this._norotatePane.appendChild(this._panes.shadowPane),this._norotatePane.appendChild(this._panes.markerPane),this._norotatePane.appendChild(this._panes.tooltipPane),this._norotatePane.appendChild(this._panes.popupPane),t.DomUtil.addClass(this._rotatePane,"leaflet-proxy leaflet-zoom-animated")}},_.setBearing=function(e){if(!this._rotate||!isFinite(e))return this;var a=this._bearing||0,n=o(e);if(n===a)return this;if(this._commitRotatePan(),this._bearing=n,this._bearingRad=n*i,this._updateRotatePaneTransform(),0===a!=(0===n))for(var s in this._layers){var r=this._layers[s];r instanceof t.Renderer&&r._update()}return this.fire("rotate")},_.getBearing=function(){return this._bearing||0},_._updateRotatePaneTransform=function(){if(this._rotatePane){if(!this._bearing)return this._rotatePane.style[t.DomUtil.TRANSFORM]="",void(this._rotatePane.style[t.DomUtil.TRANSFORM+"Origin"]="");var i=this.getSize().divideBy(2);this._rotatePane.style[t.DomUtil.TRANSFORM+"Origin"]=i.x+"px "+i.y+"px",this._rotatePane.style[t.DomUtil.TRANSFORM]="rotate("+this._bearingRad+"rad)"}},_._commitRotatePan=function(){if(this._rotate&&!this._committingRotatePan){var t=this._getMapPanePos();!t||0===t.x&&0===t.y||(this._committingRotatePan=!0,this._resetView(this.getCenter(),this.getZoom(),!0),this._committingRotatePan=!1)}};var m=_.containerPointToLayerPoint;_.containerPointToLayerPoint=function(i){if(!this._rotate||!this._bearing)return m.call(this,i);var e=t.point(i),o=this._getMapPanePos(),a=this.getSize().divideBy(2);return e.subtract(o).subtract(a).rotate(-this._bearingRad).add(a)};var d=_.layerPointToContainerPoint;_.layerPointToContainerPoint=function(i){if(!this._rotate||!this._bearing)return d.call(this,i);var e=t.point(i),o=this._getMapPanePos(),a=this.getSize().divideBy(2);return e.subtract(a).rotate(this._bearingRad).add(a).add(o)},_.rotatedPointToMapPanePoint=function(i){if(!this._bearing)return t.point(i);var e=this.getSize().divideBy(2);return t.point(i).rotateFrom(this._bearingRad,e)},_.mapPanePointToRotatedPoint=function(i){if(!this._bearing)return t.point(i);var e=this.getSize().divideBy(2);return t.point(i).rotateFrom(-this._bearingRad,e)};var c=_._getCenterOffset;_._getCenterOffset=function(t){return this._rotate&&this._bearing?this.project(t).subtract(this.project(this.getCenter())).rotate(this._bearingRad):c.call(this,t)};var u=_.getBounds;_.getBounds=function(){if(!this._rotate||!this._bearing)return u.call(this);var i=this.getSize(),e=t.latLngBounds();return e.extend(this.containerPointToLatLng(t.point(0,0))),e.extend(this.containerPointToLatLng(t.point(i.x,0))),e.extend(this.containerPointToLatLng(t.point(i.x,i.y))),e.extend(this.containerPointToLatLng(t.point(0,i.y))),e},_.mapBoundsToContainerBounds=function(i){return t.bounds([this.latLngToContainerPoint(i.getNorthWest()),this.latLngToContainerPoint(i.getNorthEast()),this.latLngToContainerPoint(i.getSouthEast()),this.latLngToContainerPoint(i.getSouthWest())])};var g=_.getBoundsZoom;_.getBoundsZoom=function(i,e,o){if(!this._rotate||!this._bearing)return g.call(this,i,e,o);i=t.latLngBounds(i),o=t.point(o||[0,0]);var a=this.getZoom()||0,n=this.getMinZoom(),s=this.getMaxZoom(),r=this.getSize().subtract(o);if(r.x<=0||r.y<=0)return a;var h=this.mapBoundsToContainerBounds(i).getSize(),_=this.options.zoomSnap,p=r.x/h.x,l=r.y/h.y,m=e?Math.max(p,l):Math.min(p,l);return a=this.getScaleZoom(m,a),_&&(a=Math.round(a/_)*_),Math.max(n,Math.min(s,a))},_._animateZoomNoDelay=function(t,i,e){this._mapPane&&(e&&(this._animatingZoom=!0,this._animateToCenter=t,this._animateToZoom=i),this._move(this._animateToCenter,this._animateToZoom,void 0,!0),this._onZoomTransitionEnd())};var f=_._tryAnimatedZoom;_._tryAnimatedZoom=function(t,i,e){return this._rotate&&this._bearing&&!this._animatingZoom&&this._commitRotatePan(),f.call(this,t,i,e)};var v=_.invalidateSize;_.invalidateSize=function(i){var e=t.Util.extend({animate:!1,pan:!0},!0===i?{animate:!0}:i);if(!(this._rotate&&this._bearing&&this._loaded&&e.pan))return v.call(this,i);var o=this.getSize(),a=this.getCenter(),n=this.getZoom();this._sizeChanged=!0,this._lastCenter=null;var s=this.getSize();return o.equals(s)?this:(this._committingRotatePan=!0,this._resetView(a,n,!0),this._committingRotatePan=!1,this.fire("resize",{oldSize:o,newSize:s}))},t.Map.addInitHook(function(){this._rotate&&this.on("resize",this._updateRotatePaneTransform,this)});var y=t.GridLayer.prototype.getEvents;t.GridLayer.prototype.getEvents=function(){var t=y.call(this);return this._map&&this._map._rotate&&(t.rotate=this._onRotate),t},t.GridLayer.prototype._onRotate=function(){this._update()};var R=t.GridLayer.prototype._invalidateAll;t.GridLayer.prototype._invalidateAll=function(){if(!this._map||!this._map._committingRotatePan)return R.call(this)};var P=t.GridLayer.prototype._getTiledPixelBounds;t.GridLayer.prototype._getTiledPixelBounds=function(i){if(!this._map._rotate||!this._map._bearing)return P.call(this,i);for(var e=this._map,o=e._animatingZoom?Math.max(e._animateToZoom,e.getZoom()):e.getZoom(),a=e.getZoomScale(o,this._tileZoom),n=e.project(i,this._tileZoom).floor(),s=e.getSize().divideBy(2*Math.min(a,1)).multiplyBy(1.25),r=new t.Bounds,h=[t.point(-s.x,-s.y),t.point(s.x,-s.y),t.point(s.x,s.y),t.point(-s.x,s.y)],_=0;_<4;_++)r.extend(n.add(h[_].rotate(-e._bearingRad)));return r};var T=t.Renderer.prototype.onAdd;t.Renderer.prototype.onAdd=function(i){T.call(this,i),i._rotate&&t.DomUtil.addClass(this._container,"leaflet-zoom-animated")};var b=t.Renderer.prototype._updateTransform;t.Renderer.prototype._updateTransform=function(i,e){if(!this._map||!this._map._rotate||!this._map._bearing)return b.call(this,i,e);if(this._bounds&&this._boundsMinLatLng){var o=this._map,a=o.getZoomScale(e,this._zoom),n=o._latLngToNewLayerPoint(this._boundsMinLatLng,e,i);t.DomUtil.setTransform(this._container,n,a)}};var M=t.Renderer.prototype._update;t.Renderer.prototype._update=function(){if(!this._map||!this._map._rotate||!this._map._bearing)return M.call(this);var i=Math.max(this.options.padding||0,1.5),e=this._map,o=e.getSize(),a=e.containerPointToLayerPoint(o.divideBy(2)),n=o.multiplyBy(.5+i),s=Math.ceil(Math.sqrt(n.x*n.x+n.y*n.y));this._bounds=new t.Bounds(a.subtract([s,s]).round(),a.add([s,s]).round()),this._center=e.getCenter(),this._zoom=e.getZoom(),this._boundsMinLatLng=e.layerPointToLatLng(this._bounds.min)};const E=t.Map.prototype;E.setHeading=function(t,i){return this._rotate?null==t||isNaN(t)?this.stopHeadingUp():(i=i||{},this._headingUp=!0,this._headingEase=null!=i.ease?i.ease:.2,this._headingDeadzone=null!=i.deadzone?i.deadzone:.5,this._headingTarget=o(-t),this._startHeadingAnim(),this):this},E.stopHeadingUp=function(){return this._headingUp=!1,this._headingRAF&&(t.Util.cancelAnimFrame(this._headingRAF),this._headingRAF=null),this},t.Map.addInitHook(function(){this.on("unload",this.stopHeadingUp,this)}),E.getHeadingUp=function(){return!!this._headingUp},E._startHeadingAnim=function(){this._headingRAF||(this._headingLastT=0,this._headingRAF=t.Util.requestAnimFrame(this._headingAnim,this))},E._headingAnim=function(){if(this._headingRAF=null,this._headingUp){var i=this.getBearing(),e=a(this._headingTarget-i);if(Math.abs(e).001&&this.setBearing(this._headingTarget);else{var o=h(),n=this._headingLastT?Math.min(o-this._headingLastT,100):s;this._headingLastT=o,this.setBearing(i+e*r(this._headingEase,n)),this._headingRAF=t.Util.requestAnimFrame(this._headingAnim,this)}}},t.Marker.mergeOptions({rotation:0,rotateWithView:!1,scale:void 0});var D=t.Marker.prototype.getEvents;t.Marker.prototype.getEvents=function(){var t=D.call(this);return this._map&&this._map._rotate&&(t.rotate=this._rotateReposition,t.rotateend=this._rotateEnd),t};var A=t.Marker.prototype._setPos;function L(i,e){var o=i.options.rotation||0;if(i.options.rotateWithView&&(o+=e._bearing||0),o||i.options.scale){var a=t.DomUtil.getPosition(i._icon)||new t.Point(0,0),n="translate3d("+a.x+"px,"+a.y+"px,0)";o&&(n+=" rotate("+o+"deg)"),i.options.scale&&(n+=" scale("+i.options.scale+")"),i._icon.style[t.DomUtil.TRANSFORM]=n}}t.Marker.prototype._setPos=function(i){this._map&&this._map._rotate&&this._map._bearing&&(i=this._map.rotatedPointToMapPanePoint(i)),A?A.call(this,i):(t.DomUtil.setPosition(this._icon,i),this._shadow&&t.DomUtil.setPosition(this._shadow,i),this._zIndex=i.y+this.options.zIndexOffset,this._resetZIndex())};var O=t.Marker.prototype.update;t.Marker.prototype.update=function(){var t=O.call(this);return this._icon&&this._map&&L(this,this._map),t},t.Marker.prototype._rotateReposition=function(){var t,i=this._map;i&&this._icon&&(i._rotInertia&&this._rotLayerPt?t=this._rotLayerPt:(t=i.latLngToLayerPoint(this._latlng),i._rotInertia&&(this._rotLayerPt=t)),this._setPos(t),L(this,i))},t.Marker.prototype._rotateEnd=function(){this._rotLayerPt=null,this.update()};var S=t.Marker.prototype._resetZIndex;if(t.Marker.prototype._resetZIndex=function(){if(!this._map||!this._map._rotating)return S.call(this)},t.Marker.prototype._panOnFocus){var C=t.Marker.prototype._panOnFocus;t.Marker.prototype._panOnFocus=function(){if(!this._map||!this._map._rotate)return C.call(this)}}var Z=t.Icon.prototype._setIconStyles;if(t.Icon.prototype._setIconStyles=function(i,e){Z.call(this,i,e);var o=this.options.iconAnchor||this.options.shadowAnchor;o&&(i.style[t.DomUtil.TRANSFORM+"Origin"]=o[0]+"px "+o[1]+"px")},t.DivOverlay){var B=t.DivOverlay.prototype.getEvents;t.DivOverlay.prototype.getEvents=function(){var t=B.call(this);return this._map&&this._map._rotate&&(t.rotate=this._updatePosition),t}}if(t.Popup){var I=t.Popup.prototype._updatePosition;t.Popup.prototype._updatePosition=function(){if(this._map){if(!this._map._rotate||!this._map._bearing)return I.call(this);var i=this._map.latLngToLayerPoint(this._latlng),e=this._map.rotatedPointToMapPanePoint(i),o=t.point(this.options.offset),a=this._getAnchor();this._zoomAnimated?t.DomUtil.setPosition(this._container,e.add(a)):o=o.add(e).add(a),this._containerBottom=-o.y,this._containerLeft=-Math.round(this._containerWidth/2)+o.x,this._container.style.bottom=this._containerBottom+"px",this._container.style.left=this._containerLeft+"px"}};var x=t.Popup.prototype._animateZoom;t.Popup.prototype._animateZoom=function(i){if(!this._map||!this._map._rotate||!this._map._bearing)return x?x.call(this,i):void 0;var e=this._map._latLngToNewLayerPoint(this._latlng,i.zoom,i.center);e=this._map.rotatedPointToMapPanePoint(e);var o=this._getAnchor();t.DomUtil.setPosition(this._container,e.add(o))};var U=t.Popup.prototype._adjustPan;t.Popup.prototype._adjustPan=function(){this._map&&this._map._rotate||U&&U.call(this)}}if(t.Tooltip){var H=t.Tooltip.prototype._updatePosition;t.Tooltip.prototype._updatePosition=function(){if(this._map){if(!this._map._rotate||!this._map._bearing)return H.call(this);var t=this._map.latLngToLayerPoint(this._latlng);this._setPosition(this._map.rotatedPointToMapPanePoint(t))}};var k=t.Tooltip.prototype._animateZoom;t.Tooltip.prototype._animateZoom=function(t){if(!this._map||!this._map._rotate||!this._map._bearing)return k?k.call(this,t):void 0;var i=this._map._latLngToNewLayerPoint(this._latlng,t.zoom,t.center);this._setPosition(this._map.rotatedPointToMapPanePoint(i))}}if(t.Map.TouchGestures=t.Handler.extend({_ROTATION_THRESHOLD:30*i,_SCALE_THRESHOLD:.04,_SCALE_THRESHOLD_ROT:.12,_MOVE_THRESHOLD:4,_ZOOM_EPS:.01,_PAN_EPS:2,_ZOOM_SNAP_STEP:0,_ROT_INERTIA:!0,_ROT_DECAY:.0018,_ROT_MIN_VELOCITY:.004,_ROT_MAX_VELOCITY:1.2,_ROT_VELOCITY_SMOOTH:.4,_ROT_STALE_MS:80,addHooks:function(){t.DomEvent.on(this._map._container,"touchstart",this._onTouchStart,this),t.DomEvent.on(this._map._container,"touchmove",this._onTouchMove,this),t.DomEvent.on(this._map._container,"touchend touchcancel",this._onTouchEnd,this)},removeHooks:function(){t.DomEvent.off(this._map._container,"touchstart",this._onTouchStart,this),t.DomEvent.off(this._map._container,"touchmove",this._onTouchMove,this),t.DomEvent.off(this._map._container,"touchend touchcancel",this._onTouchEnd,this),this._animRequest&&(t.Util.cancelAnimFrame(this._animRequest),this._animRequest=null),this._stopRotateInertia()},_onTouchStart:function(i){if(!this._active||i.touches&&2===i.touches.length||(this._lastRotTime=0,this._onTouchEnd(i)),this._stopRotateInertia(),i.touches&&2===i.touches.length){var e=this._map;e.dragging&&e.dragging.enabled()&&(this._draggingWasEnabled=!0,e.dragging.disable()),e._stop&&e._stop(),this._rotVelocity=0,this._lastRotTime=0,this._lastRotBearing=0,e.stopHeadingUp(),e._commitRotatePan();var o=e.mouseEventToContainerPoint(i.touches[0]),a=e.mouseEventToContainerPoint(i.touches[1]);this._startDist=o.distanceTo(a),this._startDist<1?this._active=!1:(this._touchZoomCenter="center"===e.options.touchZoom,this._centerPoint=e.getSize().divideBy(2),this._startCenter=e.getCenter(),this._startMidpoint=this._touchZoomCenter?this._centerPoint:o.add(a).divideBy(2),this._startAngle=Math.atan2(a.y-o.y,a.x-o.x),this._startBearing=e.getBearing(),this._startBearingRad=e._bearingRad||0,this._startZoom=e.getZoom(),this._anchorLatLng=this._touchZoomCenter?this._startCenter:e.containerPointToLatLng(this._startMidpoint),this._moved=!1,this._active=!0,this._rotationActive=!1,this._scaleActive=!1,this.zoom=!1,this._lastMoveZoom=this._startZoom,this._lastMoveMidpoint=this._startMidpoint,t.DomEvent.preventDefault(i))}else this._active=!1},_onTouchMove:function(i){if(i.touches&&2===i.touches.length&&this._active){var s=this._map,r=s.mouseEventToContainerPoint(i.touches[0]),_=s.mouseEventToContainerPoint(i.touches[1]),p=this._touchZoomCenter?this._centerPoint:r.add(_).divideBy(2),l=r.distanceTo(_),m=Math.atan2(_.y-r.y,_.x-r.x),d=p.distanceTo(this._startMidpoint),c=l/this._startDist,u=Math.abs(c-1),g=n(m-this._startAngle),f=s.options.touchRotate&&Math.abs(g)>this._ROTATION_THRESHOLD,v=u>(this._rotationActive?this._SCALE_THRESHOLD_ROT:this._SCALE_THRESHOLD),y=d>this._MOVE_THRESHOLD;if(!this._moved){if(!f&&!v&&!y)return void t.DomEvent.preventDefault(i);s._moveStart(!0,!1),this._moved=!0}var R=this._startZoom;!this._scaleActive&&v&&(this._scaleActive=!0),this._scaleActive&&(R=s.getScaleZoom(c,this._startZoom),!s.options.bounceAtZoomLimits&&(Rs.getMaxZoom()&&c>1)&&(R=Math.max(s.getMinZoom(),Math.min(s.getMaxZoom(),R))),this._ZOOM_SNAP_STEP>0&&(R=Math.round(R/this._ZOOM_SNAP_STEP)*this._ZOOM_SNAP_STEP));var P=this._startBearingRad;if(s.options.touchRotate&&(this._rotationActive||Math.abs(g)>this._ROTATION_THRESHOLD&&(this._rotationActive=!0,this._rotRefAngle=m,s._rotating=!0,s.stopHeadingUp(),s.fire("rotatestart")),this._rotationActive)){var T=n(m-this._rotRefAngle),b=!1===s.options.rotateClockwise?-1:1,M=o(this._startBearing+b*T*e);s.setBearing(M),P=s._bearingRad||0;var E=h();if(this._lastRotTime){var D=E-this._lastRotTime;if(D>0){var A=a(M-this._lastRotBearing)/D,L=this._ROT_VELOCITY_SMOOTH;this._rotVelocity=(1-L)*(this._rotVelocity||0)+L*A}}this._lastRotTime=E,this._lastRotBearing=M}var O=Math.abs(R-this._lastMoveZoom)>this._ZOOM_EPS,S=p.distanceTo(this._lastMoveMidpoint)>this._PAN_EPS;if(this._scaleActive&&(O||S)){var C=s.getSize().divideBy(2),Z=p.subtract(C),B=s.project(this._anchorLatLng,R).subtract(Z.rotate(-P)),I=s.unproject(B,R);this._center=I,this._zoom=R,this.zoom=!0,this._lastMoveZoom=R,this._lastMoveMidpoint=p,this._animRequest&&t.Util.cancelAnimFrame(this._animRequest);var x=t.Util.bind(s._move,s,I,R,{pinch:!0,round:!1},void 0);this._animRequest=t.Util.requestAnimFrame(x,this,!0)}else this._scaleActive||(this._center=this._startCenter,this._zoom=this._startZoom,this.zoom=!1,this._animRequest&&(t.Util.cancelAnimFrame(this._animRequest),this._animRequest=null));t.DomEvent.preventDefault(i)}},_onTouchEnd:function(i){var e=this._map;this._draggingWasEnabled&&e.dragging&&(e.dragging.enable(),this._draggingWasEnabled=!1),this._active&&(this._active=!1,this._moved&&(this._animRequest&&(t.Util.cancelAnimFrame(this._animRequest),this._animRequest=null),this.zoom?e.options.zoomAnimation?e._animateZoom(this._center,e._limitZoom(this._zoom),!0,e.options.zoomSnap):e._resetView(this._center,e._limitZoom(this._zoom)):e._moveEnd(!0),this._rotationActive&&(this._startRotateInertia()||(e._rotating=!1,e.fire("rotateend"))),this.zoom=!1))},_stopRotateInertia:function(){this._rotInertiaReq&&(t.Util.cancelAnimFrame(this._rotInertiaReq),this._rotInertiaReq=null);var i=this._map;i&&i._rotating&&(i._rotating=!1,i._rotInertia=!1,i.fire("rotateend"))},_startRotateInertia:function(){var i=this._map;if(!this._ROT_INERTIA)return!1;var e=h();if(!this._lastRotTime||e-this._lastRotTime>this._ROT_STALE_MS||Math.abs(this._rotVelocity||0)a&&(o=a),o<-a&&(o=-a);var n=this._ROT_DECAY,s=this._ROT_MIN_VELOCITY,r=e,_=this;i._rotInertia=!0;var p=function(){var e=h(),a=e-r;if(r=e,a<=0&&(a=16),o*=Math.exp(-n*a),Math.abs(o)',this._needle=o.firstChild,this._link=o,this._container=e,t.DomEvent.disableClickPropagation(e),t.DomEvent.on(o,"click",this._onClick,this),i.on("rotate",this._updateDisplay,this),"toggle"===this.options.behavior?this.options.enabled?this._enableRotation():this._disableRotation():this._updateDisplay(),e},onRemove:function(i){i.off("rotate",this._updateDisplay,this),t.DomEvent.off(this._link,"click",this._onClick,this)},_onClick:function(i){t.DomEvent.stop(i),"toggle"===this.options.behavior?this._enabled?this._disableRotation():this._enableRotation():this._map.setBearing(0)},_disableRotation:function(){this._enabled=!1,this._map.stopHeadingUp(),this._map.dragRotate&&this._map.dragRotate.disable(),this._map.touchGestures&&this._map.touchGestures.disable(),this._map.touchZoom&&this._map.touchZoom.enable(),this._map.shiftKeyRotate&&this._map.shiftKeyRotate.disable(),this._map.setBearing(0),this._updateDisplay()},_enableRotation:function(){this._enabled=!0,this._map.dragRotate&&this._map.options.dragRotate&&this._map.dragRotate.enable(),this._map.touchGestures&&this._map.options.touchRotate&&(this._map.touchGestures.enable(),this._map.touchZoom&&this._map.touchZoom.disable()),this._map.shiftKeyRotate&&this._map.options.shiftKeyRotate&&this._map.shiftKeyRotate.enable(),this._updateDisplay()},_updateDisplay:function(){if(this._map&&this._link){var i=this._map.getBearing();this._needle&&(this._needle.style[t.DomUtil.TRANSFORM]="rotate("+-i+"deg)"),"toggle"===this.options.behavior?this._enabled?t.DomUtil.removeClass(this._container,"leaflet-control-rotate--inactive"):t.DomUtil.addClass(this._container,"leaflet-control-rotate--inactive"):this.options.closeOnZeroBearing&&(this._container.style.display=0===i?"none":"")}}}),t.control.rotate=function(i){return new t.Control.Rotate(i)},t.Map.addInitHook(function(){if(this.options.rotate&&this.options.rotateControl){var i=!0===this.options.rotateControl?{}:this.options.rotateControl;this.rotateControl=t.control.rotate(i),this.addControl(this.rotateControl)}}),t.Map.mergeOptions({preventPageGestures:!0}),t.Map.addInitHook(function(){if(this.options.preventPageGestures){var t=["gesturestart","gesturechange","gestureend"],i=function(t){t.preventDefault()};t.forEach(function(t){document.addEventListener(t,i,{passive:!1})}),this.on("unload",function(){t.forEach(function(t){document.removeEventListener(t,i,{passive:!1})})})}});const q="leaflet-rotate-panes";if("undefined"!=typeof document&&!document.getElementById(q)){const t=document.createElement("style");t.id=q,t.textContent=[".leaflet-rotate-pane { position: absolute; top: 0; left: 0; will-change: transform; }",".leaflet-norotate-pane { position: absolute; top: 0; left: 0; z-index: 600; }"].join("\n"),document.head.appendChild(t)}});