Add heading-up compass and persist fiducial layers

This commit is contained in:
livio committed 2026-10-04 21:40:34 +02:00
1 parent bc037a57d4
commit 812420b86a
6 files changed
+340 -15

No files matched your search

+106
View File
@@ -673,6 +673,17 @@
<input type="number" min="0" max="30" step="1" @bind="MapMessageTimeoutSeconds" @bind:after="ApplyMapMessageOptions" />
</label>
<small class="field-help">Imposta 0 per lasciare i messaggi visibili fino alla chiusura manuale.</small>
<label class="toggle-line project-save-option">
<input type="checkbox" @bind="ShowCompass" @bind:after="ApplyCompassOptions" />
<span>Mostra bussola sulla mappa</span>
</label>
<label>
Orientamento bussola
<select @bind="CompassMode" @bind:after="ApplyCompassOptions" disabled="@(!ShowCompass)">
<option value="heading">Navigatore: direzione del dispositivo in alto</option>
<option value="fixed">Nord fisso in alto</option>
</select>
</label>
</section>
<section class="panel-section">
@@ -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<string> 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;
}
+72
View File
@@ -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;
+1
View File
@@ -27,6 +27,7 @@
<script src="_framework/blazor.webview.js" autostart="false"></script>
<script src="lib/leaflet/leaflet.js"></script>
<script src="lib/leaflet-rotate/leaflet-rotate.umd.min.js"></script>
<script src="lib/leaflet-draw/leaflet.draw.js"></script>
<script src="lib/googlemutant/Leaflet.GoogleMutant.js"></script>
<script src="lib/jszip/jszip.min.js"></script>
+138 -15
View File
@@ -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 = `<span class="map-compass-north">N</span><span class="map-compass-needle" aria-hidden="true"></span><span class="map-compass-center" aria-hidden="true"></span>`;
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,
+21
View File
@@ -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.
+2
View File
@@ -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._animLine truncated