Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bb30f23d67 | ||
|
|
87304b1568 | ||
|
|
a23eff6124 | ||
|
|
4da47a8835 | ||
|
|
fc303e2555 | ||
|
|
49ed7d5f0e |
No files matched your search
@@ -472,6 +472,7 @@
|
|||||||
private bool DrawToolsVisible { get; set; }
|
private bool DrawToolsVisible { get; set; }
|
||||||
private bool TrailEnabled { get; set; }
|
private bool TrailEnabled { get; set; }
|
||||||
private bool LayerPanelOpen { get; set; }
|
private bool LayerPanelOpen { get; set; }
|
||||||
|
private DotNetObjectReference<Home>? MapCallbackReference { get; set; }
|
||||||
private bool IncludeCadastralParcels { get; set; } = true;
|
private bool IncludeCadastralParcels { get; set; } = true;
|
||||||
private bool IncludeKmlSheetLayer { get; set; }
|
private bool IncludeKmlSheetLayer { get; set; }
|
||||||
private bool ShowImportedSheetLayer { get; set; }
|
private bool ShowImportedSheetLayer { get; set; }
|
||||||
@@ -570,7 +571,8 @@
|
|||||||
{
|
{
|
||||||
if (firstRender)
|
if (firstRender)
|
||||||
{
|
{
|
||||||
await JS.InvokeVoidAsync("lmeMap.init");
|
MapCallbackReference = DotNetObjectReference.Create(this);
|
||||||
|
await JS.InvokeVoidAsync("lmeMap.init", MapCallbackReference);
|
||||||
await ApplyFlagPreferencesToMapAsync();
|
await ApplyFlagPreferencesToMapAsync();
|
||||||
await CenterOnInitialLocationAsync();
|
await CenterOnInitialLocationAsync();
|
||||||
await MigrateLegacyProjectAsync();
|
await MigrateLegacyProjectAsync();
|
||||||
@@ -1047,6 +1049,21 @@
|
|||||||
await JS.InvokeVoidAsync("lmeMap.setDrawingMeasurementsVisible", ShowDrawingMeasurements);
|
await JS.InvokeVoidAsync("lmeMap.setDrawingMeasurementsVisible", ShowDrawingMeasurements);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[JSInvokable]
|
||||||
|
public Task SetMeasurementsFromLayerManager(string category, bool enabled)
|
||||||
|
{
|
||||||
|
if (category == "imported")
|
||||||
|
{
|
||||||
|
ShowImportedMeasurements = enabled;
|
||||||
|
}
|
||||||
|
else if (category == "drawings")
|
||||||
|
{
|
||||||
|
ShowDrawingMeasurements = enabled;
|
||||||
|
}
|
||||||
|
SaveFlagPreferences();
|
||||||
|
return InvokeAsync(StateHasChanged);
|
||||||
|
}
|
||||||
|
|
||||||
private async Task ToggleDrawTools()
|
private async Task ToggleDrawTools()
|
||||||
{
|
{
|
||||||
DrawToolsVisible = !DrawToolsVisible;
|
DrawToolsVisible = !DrawToolsVisible;
|
||||||
@@ -1503,6 +1520,7 @@
|
|||||||
LocationService.StopTracking();
|
LocationService.StopTracking();
|
||||||
GpsLookupCancellation?.Cancel();
|
GpsLookupCancellation?.Cancel();
|
||||||
GpsLookupCancellation?.Dispose();
|
GpsLookupCancellation?.Dispose();
|
||||||
|
MapCallbackReference?.Dispose();
|
||||||
return ValueTask.CompletedTask;
|
return ValueTask.CompletedTask;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -28,8 +28,8 @@
|
|||||||
<ApplicationId>com.companyname.lmemappecatastaliapp</ApplicationId>
|
<ApplicationId>com.companyname.lmemappecatastaliapp</ApplicationId>
|
||||||
|
|
||||||
<!-- Versions -->
|
<!-- Versions -->
|
||||||
<ApplicationDisplayVersion>0.2.20</ApplicationDisplayVersion>
|
<ApplicationDisplayVersion>0.2.26</ApplicationDisplayVersion>
|
||||||
<ApplicationVersion>24</ApplicationVersion>
|
<ApplicationVersion>30</ApplicationVersion>
|
||||||
|
|
||||||
<!-- To develop, package, and publish an app to the Microsoft Store, see: https://aka.ms/MauiTemplateUnpackaged -->
|
<!-- To develop, package, and publish an app to the Microsoft Store, see: https://aka.ms/MauiTemplateUnpackaged -->
|
||||||
<WindowsPackageType>None</WindowsPackageType>
|
<WindowsPackageType>None</WindowsPackageType>
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ public sealed class AzureMapsService
|
|||||||
|
|
||||||
public AzureMapsService()
|
public AzureMapsService()
|
||||||
{
|
{
|
||||||
_httpClient.DefaultRequestHeaders.UserAgent.ParseAdd("LMEMappeCatastali/0.2.20");
|
_httpClient.DefaultRequestHeaders.UserAgent.ParseAdd("LMEMappeCatastali/0.2.22");
|
||||||
_httpClient.DefaultRequestHeaders.Accept.ParseAdd("application/json");
|
_httpClient.DefaultRequestHeaders.Accept.ParseAdd("application/json");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -78,6 +78,8 @@ public sealed class MapExportService
|
|||||||
BuildStyle("drawing", "ff1679f9", "333c92fb"),
|
BuildStyle("drawing", "ff1679f9", "333c92fb"),
|
||||||
BuildStyle("poi", "ffff7a00", "33ff7a00"),
|
BuildStyle("poi", "ffff7a00", "33ff7a00"),
|
||||||
BuildStyle("gps-trail", "ff00a5ff", "2200a5ff"));
|
BuildStyle("gps-trail", "ff00a5ff", "2200a5ff"));
|
||||||
|
var categoryFolders = new Dictionary<string, XElement>(StringComparer.Ordinal);
|
||||||
|
var groupFolders = new Dictionary<(string Category, string Group), XElement>();
|
||||||
|
|
||||||
foreach (var feature in features.EnumerateArray())
|
foreach (var feature in features.EnumerateArray())
|
||||||
{
|
{
|
||||||
@@ -102,7 +104,31 @@ public sealed class MapExportService
|
|||||||
placemark.Add(extendedData);
|
placemark.Add(extendedData);
|
||||||
}
|
}
|
||||||
placemark.Add(BuildGeometry(geometry));
|
placemark.Add(BuildGeometry(geometry));
|
||||||
document.Add(placemark);
|
var categoryName = GetString(properties, "_lmeCategoryName")?.Trim();
|
||||||
|
var groupName = GetString(properties, "_lmeGroupName")?.Trim();
|
||||||
|
var parent = document;
|
||||||
|
if (!string.IsNullOrWhiteSpace(categoryName))
|
||||||
|
{
|
||||||
|
if (!categoryFolders.TryGetValue(categoryName, out var categoryFolder))
|
||||||
|
{
|
||||||
|
categoryFolder = new XElement(Kml + "Folder", new XElement(Kml + "name", categoryName));
|
||||||
|
categoryFolders[categoryName] = categoryFolder;
|
||||||
|
document.Add(categoryFolder);
|
||||||
|
}
|
||||||
|
parent = categoryFolder;
|
||||||
|
}
|
||||||
|
if (!string.IsNullOrWhiteSpace(groupName))
|
||||||
|
{
|
||||||
|
var key = (categoryName ?? string.Empty, groupName);
|
||||||
|
if (!groupFolders.TryGetValue(key, out var groupFolder))
|
||||||
|
{
|
||||||
|
groupFolder = new XElement(Kml + "Folder", new XElement(Kml + "name", groupName));
|
||||||
|
groupFolders[key] = groupFolder;
|
||||||
|
parent.Add(groupFolder);
|
||||||
|
}
|
||||||
|
parent = groupFolder;
|
||||||
|
}
|
||||||
|
parent.Add(placemark);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new XDocument(new XDeclaration("1.0", "utf-8", null), new XElement(Kml + "kml", document)).ToString();
|
return new XDocument(new XDeclaration("1.0", "utf-8", null), new XElement(Kml + "kml", document)).ToString();
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ public sealed class NetworkLocationService
|
|||||||
|
|
||||||
public NetworkLocationService()
|
public NetworkLocationService()
|
||||||
{
|
{
|
||||||
httpClient.DefaultRequestHeaders.UserAgent.ParseAdd("LMEMappeCatastali/0.2.20");
|
httpClient.DefaultRequestHeaders.UserAgent.ParseAdd("LMEMappeCatastali/0.2.22");
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<NetworkLocationSnapshot?> GetApproximateLocationAsync(
|
public async Task<NetworkLocationSnapshot?> GetApproximateLocationAsync(
|
||||||
|
|||||||
+94
-9
@@ -176,10 +176,11 @@ input[type="checkbox"] {
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
top: 72px;
|
top: 72px;
|
||||||
right: 12px;
|
right: 12px;
|
||||||
|
bottom: calc(var(--nav-height) + 8px);
|
||||||
z-index: 940;
|
z-index: 940;
|
||||||
display: grid;
|
display: grid;
|
||||||
width: min(320px, calc(100% - 24px));
|
box-sizing: border-box;
|
||||||
max-height: calc(100% - 152px);
|
width: min(480px, 50vw);
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
border: 1px solid var(--line);
|
border: 1px solid var(--line);
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
@@ -274,8 +275,12 @@ input[type="checkbox"] {
|
|||||||
.layer-manager-block > summary,
|
.layer-manager-block > summary,
|
||||||
.layer-manager-object > summary {
|
.layer-manager-object > summary {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 28px 20px minmax(0, 1fr) auto auto;
|
grid-template-columns: 28px minmax(0, 1fr) 24px;
|
||||||
align-items: center;
|
grid-template-areas:
|
||||||
|
"handle title count"
|
||||||
|
". visibility moves"
|
||||||
|
". actions moves";
|
||||||
|
align-items: start;
|
||||||
gap: 6px;
|
gap: 6px;
|
||||||
min-height: 38px;
|
min-height: 38px;
|
||||||
padding: 4px 6px;
|
padding: 4px 6px;
|
||||||
@@ -290,6 +295,7 @@ input[type="checkbox"] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.layer-drag-handle {
|
.layer-drag-handle {
|
||||||
|
grid-area: handle;
|
||||||
width: 28px;
|
width: 28px;
|
||||||
height: 28px;
|
height: 28px;
|
||||||
border: 0;
|
border: 0;
|
||||||
@@ -302,9 +308,58 @@ input[type="checkbox"] {
|
|||||||
cursor: grab;
|
cursor: grab;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.layer-row-actions {
|
||||||
|
grid-area: actions;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: minmax(0, 1fr);
|
||||||
|
width: min(130px, 100%);
|
||||||
|
gap: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layer-manager-group > summary > input,
|
||||||
|
.layer-manager-block > summary > input,
|
||||||
|
.layer-manager-object > summary > input {
|
||||||
|
grid-area: visibility;
|
||||||
|
justify-self: start;
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
margin: 1px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layer-rename-button,
|
||||||
|
.layer-remove-button {
|
||||||
|
width: 100%;
|
||||||
|
min-height: 28px;
|
||||||
|
min-width: 0;
|
||||||
|
padding: 4px;
|
||||||
|
border: 1px solid #bfd4cd;
|
||||||
|
border-radius: 4px;
|
||||||
|
background: #eef8f5;
|
||||||
|
color: var(--accent-strong);
|
||||||
|
font-size: 10px;
|
||||||
|
font-weight: 800;
|
||||||
|
line-height: 1.15;
|
||||||
|
overflow-wrap: anywhere;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layer-rename-button:active {
|
||||||
|
background: #d9eee7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layer-remove-button {
|
||||||
|
border-color: #fecaca;
|
||||||
|
background: #fff1f2;
|
||||||
|
color: #b42318;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layer-remove-button:active {
|
||||||
|
background: #ffe4e6;
|
||||||
|
}
|
||||||
|
|
||||||
.layer-move-buttons {
|
.layer-move-buttons {
|
||||||
|
grid-area: moves;
|
||||||
display: inline-grid;
|
display: inline-grid;
|
||||||
grid-template-columns: 24px 24px;
|
grid-template-columns: 24px;
|
||||||
gap: 2px;
|
gap: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -326,6 +381,7 @@ input[type="checkbox"] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.layer-manager-title {
|
.layer-manager-title {
|
||||||
|
grid-area: title;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
overflow-wrap: anywhere;
|
overflow-wrap: anywhere;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
@@ -333,22 +389,45 @@ input[type="checkbox"] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.layer-manager-count {
|
.layer-manager-count {
|
||||||
|
grid-area: count;
|
||||||
|
justify-self: end;
|
||||||
color: var(--muted);
|
color: var(--muted);
|
||||||
font-size: 10px;
|
font-size: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.layer-manager-children {
|
.layer-manager-children {
|
||||||
padding: 0 5px 5px 18px;
|
padding: 0 4px 5px 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.layer-manager-details {
|
.layer-manager-details {
|
||||||
display: grid;
|
display: grid;
|
||||||
gap: 2px;
|
gap: 2px;
|
||||||
padding: 0 8px 7px 40px;
|
padding: 0 6px 7px 12px;
|
||||||
color: var(--muted);
|
color: var(--muted);
|
||||||
font-size: 10px;
|
font-size: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.layer-manager-suboption {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 18px minmax(0, 1fr);
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
min-height: 30px;
|
||||||
|
color: var(--ink);
|
||||||
|
font-size: 11px;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layer-manager-suboption input {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layer-manager-info {
|
||||||
|
display: grid;
|
||||||
|
gap: 2px;
|
||||||
|
padding: 3px 0 0 24px;
|
||||||
|
}
|
||||||
|
|
||||||
.layer-manager-dragging {
|
.layer-manager-dragging {
|
||||||
opacity: 0.55;
|
opacity: 0.55;
|
||||||
outline: 2px solid #2563eb;
|
outline: 2px solid #2563eb;
|
||||||
@@ -359,6 +438,12 @@ input[type="checkbox"] {
|
|||||||
box-shadow: inset 3px 0 #ff00d4;
|
box-shadow: inset 3px 0 #ff00d4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.layer-manager-parent-highlighted > summary,
|
||||||
|
.layer-manager-parent-selected > summary {
|
||||||
|
background: #fff0fb;
|
||||||
|
box-shadow: inset 3px 0 #ff00d4;
|
||||||
|
}
|
||||||
|
|
||||||
.gps-overlay {
|
.gps-overlay {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 72px;
|
top: 72px;
|
||||||
@@ -868,8 +953,8 @@ footer {
|
|||||||
.map-layer-panel {
|
.map-layer-panel {
|
||||||
top: 68px;
|
top: 68px;
|
||||||
right: 8px;
|
right: 8px;
|
||||||
width: min(320px, calc(100% - 16px));
|
bottom: calc(var(--nav-height) + 8px);
|
||||||
max-height: calc(100% - 144px);
|
width: 50vw;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tool-sheet {
|
.tool-sheet {
|
||||||
|
|||||||
+535
-37
@@ -51,11 +51,21 @@ const lmeState = {
|
|||||||
managerHighlight: null,
|
managerHighlight: null,
|
||||||
managerHighlightedObjectId: null,
|
managerHighlightedObjectId: null,
|
||||||
managerHighlightedCategoryKey: null,
|
managerHighlightedCategoryKey: null,
|
||||||
|
managerHighlightedParentKey: null,
|
||||||
|
managerHighlightedParentRecords: null,
|
||||||
|
managerHoveredParentKey: null,
|
||||||
|
managerHoveredParentRecords: null,
|
||||||
managerOutsideSelectionBound: false,
|
managerOutsideSelectionBound: false,
|
||||||
managerHiddenObjects: new Map(),
|
managerHiddenObjects: new Map(),
|
||||||
managerHiddenObjectIds: new Set(),
|
managerHiddenObjectIds: new Set(),
|
||||||
|
managerHiddenMeasurementSummaryIds: new Set(),
|
||||||
|
managerHiddenMeasurementSideIds: new Set(),
|
||||||
managerHiddenCategories: new Set(),
|
managerHiddenCategories: new Set(),
|
||||||
managerObjectOrder: {}
|
managerRemovedCategories: new Set(),
|
||||||
|
managerObjectOrder: {},
|
||||||
|
managerCategoryNames: {},
|
||||||
|
managerExpandedRows: new Set(),
|
||||||
|
dotNetReference: null
|
||||||
};
|
};
|
||||||
|
|
||||||
// AdE publishes the cadastral WMS in ETRS89. WMS 1.1.1 keeps the longitude,
|
// AdE publishes the cadastral WMS in ETRS89. WMS 1.1.1 keeps the longitude,
|
||||||
@@ -108,7 +118,10 @@ window.lmeMap = {
|
|||||||
showInfo: setInfo
|
showInfo: setInfo
|
||||||
};
|
};
|
||||||
|
|
||||||
function init() {
|
function init(dotNetReference) {
|
||||||
|
if (dotNetReference) {
|
||||||
|
lmeState.dotNetReference = dotNetReference;
|
||||||
|
}
|
||||||
if (lmeState.map) {
|
if (lmeState.map) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -216,11 +229,13 @@ function init() {
|
|||||||
});
|
});
|
||||||
if (!lmeState.managerOutsideSelectionBound) {
|
if (!lmeState.managerOutsideSelectionBound) {
|
||||||
document.addEventListener("pointerdown", event => {
|
document.addEventListener("pointerdown", event => {
|
||||||
if (!lmeState.managerHighlightedObjectId) {
|
if (!lmeState.managerHighlightedObjectId && !lmeState.managerHighlightedParentKey) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const selectedRow = event.target?.closest?.(".layer-manager-object");
|
const selectedObject = event.target?.closest?.(".layer-manager-object");
|
||||||
if (selectedRow?.dataset.objectId === lmeState.managerHighlightedObjectId) {
|
const selectedParent = event.target?.closest?.("[data-highlight-key]");
|
||||||
|
if (selectedObject?.dataset.objectId === lmeState.managerHighlightedObjectId
|
||||||
|
|| selectedParent?.dataset.highlightKey === lmeState.managerHighlightedParentKey) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
clearManagerHighlight();
|
clearManagerHighlight();
|
||||||
@@ -1138,6 +1153,159 @@ function managedObjectLabel(record, index) {
|
|||||||
return `Oggetto ${index + 1}`;
|
return `Oggetto ${index + 1}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function managedObjectEditableName(record) {
|
||||||
|
const properties = record?.layer?.feature?.properties || {};
|
||||||
|
return properties.name || properties.Name || properties.label || properties.LABEL || "";
|
||||||
|
}
|
||||||
|
|
||||||
|
function managedObjectCanRename(record) {
|
||||||
|
return ["drawings", "imported", "importedSheets"].includes(record.categoryKey)
|
||||||
|
&& record.layer?.feature?.properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
function renameManagedObject(record, index) {
|
||||||
|
if (!managedObjectCanRename(record)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const currentName = String(managedObjectEditableName(record) || managedObjectLabel(record, index)).trim();
|
||||||
|
const requestedName = window.prompt("Nuovo nome oggetto", currentName);
|
||||||
|
if (requestedName === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const name = requestedName.trim().slice(0, 120);
|
||||||
|
if (!name) {
|
||||||
|
setInfo("Nome non modificato: inserisci un testo.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const properties = record.layer.feature.properties;
|
||||||
|
properties.name = name;
|
||||||
|
record.layer.lmeManagerLabel = record.categoryKey === "drawings" && record.layer instanceof L.Marker
|
||||||
|
? `POI: ${name}`
|
||||||
|
: null;
|
||||||
|
updateStoredFeaturePopup(record.layer);
|
||||||
|
refreshImportedMeasurements();
|
||||||
|
refreshDrawingMeasurements();
|
||||||
|
refreshLayerManager();
|
||||||
|
setInfo(`Oggetto rinominato: ${name}.`);
|
||||||
|
}
|
||||||
|
|
||||||
|
function managedCategoryName(category, records) {
|
||||||
|
const storedName = lmeState.managerCategoryNames[category.key];
|
||||||
|
const featureName = records
|
||||||
|
.map(record => record.layer?.feature?.properties?._lmeCategoryName)
|
||||||
|
.find(Boolean);
|
||||||
|
const name = String(storedName || featureName || category.label).trim();
|
||||||
|
if (name !== category.label) {
|
||||||
|
lmeState.managerCategoryNames[category.key] = name;
|
||||||
|
}
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
function managedCategoryCanRename(category) {
|
||||||
|
return ["drawings", "imported", "importedSheets"].includes(category.key);
|
||||||
|
}
|
||||||
|
|
||||||
|
function renameManagedCategory(category, records) {
|
||||||
|
const currentName = managedCategoryName(category, records);
|
||||||
|
const requestedName = window.prompt("Nuovo nome gruppo", currentName);
|
||||||
|
if (requestedName === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const name = requestedName.trim().slice(0, 120);
|
||||||
|
if (!name) {
|
||||||
|
setInfo("Nome non modificato: inserisci un testo.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
lmeState.managerCategoryNames[category.key] = name;
|
||||||
|
records.forEach(record => {
|
||||||
|
if (record.layer?.feature?.properties) {
|
||||||
|
record.layer.feature.properties._lmeCategoryName = name;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
refreshLayerManager();
|
||||||
|
setInfo(`Gruppo rinominato: ${name}.`);
|
||||||
|
}
|
||||||
|
|
||||||
|
function managedBlockName(source, records) {
|
||||||
|
return String(records
|
||||||
|
.map(record => record.layer?.feature?.properties?._lmeGroupName)
|
||||||
|
.find(Boolean) || source);
|
||||||
|
}
|
||||||
|
|
||||||
|
function renameManagedBlock(category, source, records) {
|
||||||
|
const currentName = managedBlockName(source, records);
|
||||||
|
const requestedName = window.prompt("Nuovo nome gruppo", currentName);
|
||||||
|
if (requestedName === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const name = requestedName.trim().slice(0, 120);
|
||||||
|
if (!name) {
|
||||||
|
setInfo("Nome non modificato: inserisci un testo.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
records.forEach(record => {
|
||||||
|
if (record.layer?.feature?.properties) {
|
||||||
|
record.layer.feature.properties._lmeGroupName = name;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
refreshLayerManager();
|
||||||
|
setInfo(`Gruppo rinominato: ${name}.`);
|
||||||
|
}
|
||||||
|
|
||||||
|
function managedCategoryCanRemove(category, records) {
|
||||||
|
return records.length > 0
|
||||||
|
&& ["drawings", "imported", "importedSheets", "selectedParcels", "gpsParcels"].includes(category.key);
|
||||||
|
}
|
||||||
|
|
||||||
|
function managedObjectCanRemove(record) {
|
||||||
|
return ["drawings", "imported", "importedSheets", "selectedParcels", "gpsParcels"].includes(record.categoryKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
function layerManagerRowActions(renameButton, removeButton) {
|
||||||
|
if (!renameButton && !removeButton) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return `<span class="layer-row-actions">${renameButton}${removeButton}</span>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeManagedRecords(records, subject) {
|
||||||
|
if (!records.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const message = records.length === 1
|
||||||
|
? `Rimuovere ${subject} dal progetto? Non verra incluso nel prossimo salvataggio.`
|
||||||
|
: `Rimuovere ${subject} e tutti i suoi ${records.length} oggetti dal progetto? Non verranno inclusi nel prossimo salvataggio.`;
|
||||||
|
if (!window.confirm(message)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const removedIds = new Set(records.map(record => record.id));
|
||||||
|
const categoryKeys = new Set(records.map(record => record.categoryKey));
|
||||||
|
records.forEach(record => {
|
||||||
|
if (record.parent?.hasLayer?.(record.layer)) {
|
||||||
|
record.parent.removeLayer(record.layer);
|
||||||
|
}
|
||||||
|
lmeState.managerHiddenObjects.delete(record.id);
|
||||||
|
lmeState.managerHiddenObjectIds.delete(record.id);
|
||||||
|
lmeState.managerHiddenMeasurementSummaryIds.delete(record.id);
|
||||||
|
lmeState.managerHiddenMeasurementSideIds.delete(record.id);
|
||||||
|
});
|
||||||
|
categoryKeys.forEach(categoryKey => {
|
||||||
|
const order = lmeState.managerObjectOrder[categoryKey] || [];
|
||||||
|
lmeState.managerObjectOrder[categoryKey] = order.filter(id => !removedIds.has(id));
|
||||||
|
const category = layerManagerCategories().find(item => item.key === categoryKey);
|
||||||
|
if (category && managedRecordsForCategory(category).length === 0) {
|
||||||
|
lmeState.managerRemovedCategories.add(categoryKey);
|
||||||
|
delete lmeState.managerCategoryNames[categoryKey];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
clearManagerHighlight();
|
||||||
|
refreshImportedMeasurements();
|
||||||
|
refreshDrawingMeasurements();
|
||||||
|
updateGpsInsideState();
|
||||||
|
refreshLayerManager();
|
||||||
|
setInfo(`${records.length === 1 ? "Oggetto rimosso" : `${records.length} oggetti rimossi`} dal progetto.`);
|
||||||
|
}
|
||||||
|
|
||||||
function managedObjectDetails(layer) {
|
function managedObjectDetails(layer) {
|
||||||
const details = [];
|
const details = [];
|
||||||
const properties = layer?.feature?.properties || {};
|
const properties = layer?.feature?.properties || {};
|
||||||
@@ -1180,6 +1348,9 @@ function refreshLayerManager() {
|
|||||||
if (!container || !lmeState.map) {
|
if (!container || !lmeState.map) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
captureLayerManagerExpansion(container);
|
||||||
|
const scrollHost = container.closest(".map-layer-panel");
|
||||||
|
const scrollTop = scrollHost?.scrollTop || 0;
|
||||||
applyStoredLayerManagerVisibility();
|
applyStoredLayerManagerVisibility();
|
||||||
container.innerHTML = "";
|
container.innerHTML = "";
|
||||||
lmeState.managerRecords = new Map();
|
lmeState.managerRecords = new Map();
|
||||||
@@ -1190,6 +1361,11 @@ function refreshLayerManager() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const records = managedRecordsForCategory(category);
|
const records = managedRecordsForCategory(category);
|
||||||
|
if (records.length) {
|
||||||
|
lmeState.managerRemovedCategories.delete(category.key);
|
||||||
|
} else if (lmeState.managerRemovedCategories.has(category.key)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
const savedOrder = lmeState.managerObjectOrder[category.key] || [];
|
const savedOrder = lmeState.managerObjectOrder[category.key] || [];
|
||||||
const positions = new Map(savedOrder.map((id, index) => [id, index]));
|
const positions = new Map(savedOrder.map((id, index) => [id, index]));
|
||||||
records.sort((left, right) =>
|
records.sort((left, right) =>
|
||||||
@@ -1200,6 +1376,12 @@ function refreshLayerManager() {
|
|||||||
applyManagedVisualOrder(container);
|
applyManagedVisualOrder(container);
|
||||||
bindLayerManagerDrag(container);
|
bindLayerManagerDrag(container);
|
||||||
bindLayerManagerMoveButtons(container);
|
bindLayerManagerMoveButtons(container);
|
||||||
|
if (scrollHost) {
|
||||||
|
scrollHost.scrollTop = scrollTop;
|
||||||
|
window.requestAnimationFrame(() => {
|
||||||
|
scrollHost.scrollTop = scrollTop;
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderLayerManagerCategory(category, records) {
|
function renderLayerManagerCategory(category, records) {
|
||||||
@@ -1207,15 +1389,36 @@ function renderLayerManagerCategory(category, records) {
|
|||||||
group.className = "layer-manager-group";
|
group.className = "layer-manager-group";
|
||||||
group.dataset.dragType = "category";
|
group.dataset.dragType = "category";
|
||||||
group.dataset.categoryKey = category.key;
|
group.dataset.categoryKey = category.key;
|
||||||
|
bindLayerManagerExpansion(group, `category:${category.key}`);
|
||||||
|
const categoryName = managedCategoryName(category, records);
|
||||||
|
const renameButton = managedCategoryCanRename(category)
|
||||||
|
? `<button type="button" class="layer-rename-button" aria-label="Rinomina gruppo" title="Rinomina">Rinomina</button>`
|
||||||
|
: "";
|
||||||
|
const removeButton = managedCategoryCanRemove(category, records)
|
||||||
|
? `<button type="button" class="layer-remove-button" aria-label="Rimuovi gruppo dal progetto" title="Rimuovi dal progetto">Rimuovi</button>`
|
||||||
|
: "";
|
||||||
|
const rowActions = layerManagerRowActions(renameButton, removeButton);
|
||||||
|
group.classList.toggle("layer-manager-with-actions", Boolean(rowActions));
|
||||||
const visibleCount = records.filter(record => !lmeState.managerHiddenObjectIds.has(record.id)).length;
|
const visibleCount = records.filter(record => !lmeState.managerHiddenObjectIds.has(record.id)).length;
|
||||||
const categoryVisible = !lmeState.managerHiddenCategories.has(category.key)
|
const categoryVisible = !lmeState.managerHiddenCategories.has(category.key)
|
||||||
&& (!category.roots.length || category.roots.some(layer => lmeState.map.hasLayer(layer)));
|
&& (!category.roots.length || category.roots.some(layer => lmeState.map.hasLayer(layer)));
|
||||||
const visible = categoryVisible;
|
const visible = categoryVisible;
|
||||||
group.innerHTML = `<summary><button type="button" class="layer-drag-handle" aria-label="Trascina gruppo">☰</button><input type="checkbox" ${visible ? "checked" : ""} aria-label="Mostra ${escapeHtml(category.label)}"><span class="layer-manager-title">${escapeHtml(category.label)}</span>${layerManagerMoveButtons("gruppo")}<span class="layer-manager-count">${records.length}</span></summary><div class="layer-manager-children"></div>`;
|
group.innerHTML = `<summary><button type="button" class="layer-drag-handle" aria-label="Trascina gruppo">☰</button><input type="checkbox" ${visible ? "checked" : ""} aria-label="Mostra ${escapeHtml(categoryName)}"><span class="layer-manager-title">${escapeHtml(categoryName)}</span>${rowActions}${layerManagerMoveButtons("gruppo")}<span class="layer-manager-count">${records.length}</span></summary><div class="layer-manager-children"></div>`;
|
||||||
const checkbox = group.querySelector("input");
|
const checkbox = group.querySelector("input");
|
||||||
checkbox.indeterminate = categoryVisible && records.length > 0 && visibleCount < records.length;
|
checkbox.indeterminate = categoryVisible && records.length > 0 && visibleCount < records.length;
|
||||||
checkbox.addEventListener("click", event => event.stopPropagation());
|
checkbox.addEventListener("click", event => event.stopPropagation());
|
||||||
checkbox.addEventListener("change", () => setManagedCategoryVisible(category, checkbox.checked));
|
checkbox.addEventListener("change", () => setManagedCategoryVisible(category, checkbox.checked));
|
||||||
|
group.querySelector(".layer-rename-button")?.addEventListener("click", event => {
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
renameManagedCategory(category, records);
|
||||||
|
});
|
||||||
|
group.querySelector(".layer-remove-button")?.addEventListener("click", event => {
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
removeManagedRecords(records, `il gruppo '${categoryName}'`);
|
||||||
|
});
|
||||||
|
bindManagedParentHighlight(group, `category:${category.key}`, records);
|
||||||
const children = group.querySelector(".layer-manager-children");
|
const children = group.querySelector(".layer-manager-children");
|
||||||
if (category.blocks) {
|
if (category.blocks) {
|
||||||
const blocks = new Map();
|
const blocks = new Map();
|
||||||
@@ -1237,9 +1440,15 @@ function renderLayerManagerBlock(category, source, records) {
|
|||||||
block.dataset.dragType = "block";
|
block.dataset.dragType = "block";
|
||||||
block.dataset.categoryKey = category.key;
|
block.dataset.categoryKey = category.key;
|
||||||
block.dataset.blockKey = source;
|
block.dataset.blockKey = source;
|
||||||
|
bindLayerManagerExpansion(block, `block:${category.key}:${source}`);
|
||||||
const visibleCount = records.filter(record => !lmeState.managerHiddenObjectIds.has(record.id)).length;
|
const visibleCount = records.filter(record => !lmeState.managerHiddenObjectIds.has(record.id)).length;
|
||||||
const visible = visibleCount === records.length;
|
const visible = visibleCount === records.length;
|
||||||
block.innerHTML = `<summary><button type="button" class="layer-drag-handle" aria-label="Trascina blocco">☰</button><input type="checkbox" ${visible ? "checked" : ""} aria-label="Mostra blocco"><span class="layer-manager-title">${escapeHtml(source)}</span>${layerManagerMoveButtons("blocco")}<span class="layer-manager-count">${records.length}</span></summary><div class="layer-manager-children"></div>`;
|
const blockName = managedBlockName(source, records);
|
||||||
|
const rowActions = layerManagerRowActions(
|
||||||
|
`<button type="button" class="layer-rename-button" aria-label="Rinomina gruppo" title="Rinomina">Rinomina</button>`,
|
||||||
|
`<button type="button" class="layer-remove-button" aria-label="Rimuovi gruppo dal progetto" title="Rimuovi dal progetto">Rimuovi</button>`);
|
||||||
|
block.classList.add("layer-manager-with-actions");
|
||||||
|
block.innerHTML = `<summary><button type="button" class="layer-drag-handle" aria-label="Trascina blocco">☰</button><input type="checkbox" ${visible ? "checked" : ""} aria-label="Mostra ${escapeHtml(blockName)}"><span class="layer-manager-title">${escapeHtml(blockName)}</span>${rowActions}${layerManagerMoveButtons("blocco")}<span class="layer-manager-count">${records.length}</span></summary><div class="layer-manager-children"></div>`;
|
||||||
const checkbox = block.querySelector("input");
|
const checkbox = block.querySelector("input");
|
||||||
checkbox.indeterminate = visibleCount > 0 && !visible;
|
checkbox.indeterminate = visibleCount > 0 && !visible;
|
||||||
checkbox.addEventListener("click", event => event.stopPropagation());
|
checkbox.addEventListener("click", event => event.stopPropagation());
|
||||||
@@ -1247,6 +1456,17 @@ function renderLayerManagerBlock(category, source, records) {
|
|||||||
records.forEach(record => setManagedObjectVisible(record, checkbox.checked, false));
|
records.forEach(record => setManagedObjectVisible(record, checkbox.checked, false));
|
||||||
refreshLayerManager();
|
refreshLayerManager();
|
||||||
});
|
});
|
||||||
|
block.querySelector(".layer-rename-button").addEventListener("click", event => {
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
renameManagedBlock(category, source, records);
|
||||||
|
});
|
||||||
|
block.querySelector(".layer-remove-button").addEventListener("click", event => {
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
removeManagedRecords(records, `il gruppo '${blockName}'`);
|
||||||
|
});
|
||||||
|
bindManagedParentHighlight(block, `block:${category.key}:${source}`, records);
|
||||||
const children = block.querySelector(".layer-manager-children");
|
const children = block.querySelector(".layer-manager-children");
|
||||||
records.forEach((record, index) => children.appendChild(renderLayerManagerObject(record, index)));
|
records.forEach((record, index) => children.appendChild(renderLayerManagerObject(record, index)));
|
||||||
return block;
|
return block;
|
||||||
@@ -1260,11 +1480,31 @@ function renderLayerManagerObject(record, index) {
|
|||||||
}
|
}
|
||||||
object.dataset.dragType = "object";
|
object.dataset.dragType = "object";
|
||||||
object.dataset.objectId = record.id;
|
object.dataset.objectId = record.id;
|
||||||
|
bindLayerManagerExpansion(object, `object:${record.id}`);
|
||||||
const visible = !lmeState.managerHiddenObjectIds.has(record.id);
|
const visible = !lmeState.managerHiddenObjectIds.has(record.id);
|
||||||
object.innerHTML = `<summary><button type="button" class="layer-drag-handle" aria-label="Trascina oggetto">☰</button><input type="checkbox" ${visible ? "checked" : ""} aria-label="Mostra oggetto"><span class="layer-manager-title">${escapeHtml(managedObjectLabel(record, index))}</span>${layerManagerMoveButtons("oggetto")}<span class="layer-manager-count">›</span></summary><div class="layer-manager-details"></div>`;
|
const renameButton = managedObjectCanRename(record)
|
||||||
|
? `<button type="button" class="layer-rename-button" aria-label="Rinomina oggetto" title="Rinomina">Rinomina</button>`
|
||||||
|
: "";
|
||||||
|
const removeButton = managedObjectCanRemove(record)
|
||||||
|
? `<button type="button" class="layer-remove-button" aria-label="Rimuovi oggetto dal progetto" title="Rimuovi dal progetto">Rimuovi</button>`
|
||||||
|
: "";
|
||||||
|
const rowActions = layerManagerRowActions(renameButton, removeButton);
|
||||||
|
object.classList.toggle("layer-manager-with-actions", Boolean(rowActions));
|
||||||
|
const objectName = managedObjectLabel(record, index);
|
||||||
|
object.innerHTML = `<summary><button type="button" class="layer-drag-handle" aria-label="Trascina oggetto">☰</button><input type="checkbox" ${visible ? "checked" : ""} aria-label="Mostra oggetto"><span class="layer-manager-title">${escapeHtml(objectName)}</span>${rowActions}${layerManagerMoveButtons("oggetto")}<span class="layer-manager-count">›</span></summary><div class="layer-manager-details"></div>`;
|
||||||
const checkbox = object.querySelector("input");
|
const checkbox = object.querySelector("input");
|
||||||
checkbox.addEventListener("click", event => event.stopPropagation());
|
checkbox.addEventListener("click", event => event.stopPropagation());
|
||||||
checkbox.addEventListener("change", () => setManagedObjectVisible(record, checkbox.checked, true));
|
checkbox.addEventListener("change", () => setManagedObjectVisible(record, checkbox.checked, true));
|
||||||
|
object.querySelector(".layer-rename-button")?.addEventListener("click", event => {
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
renameManagedObject(record, index);
|
||||||
|
});
|
||||||
|
object.querySelector(".layer-remove-button")?.addEventListener("click", event => {
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
removeManagedRecords([record], `'${objectName}'`);
|
||||||
|
});
|
||||||
object.querySelector(".layer-manager-title").addEventListener("click", event => {
|
object.querySelector(".layer-manager-title").addEventListener("click", event => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
@@ -1272,13 +1512,137 @@ function renderLayerManagerObject(record, index) {
|
|||||||
highlightManagedObject(record);
|
highlightManagedObject(record);
|
||||||
});
|
});
|
||||||
const details = object.querySelector(".layer-manager-details");
|
const details = object.querySelector(".layer-manager-details");
|
||||||
|
details.appendChild(renderLayerManagerVisibilityOption(
|
||||||
|
geometryVisibilityLabel(record.layer),
|
||||||
|
visible,
|
||||||
|
checked => setManagedObjectVisible(record, checked, true)));
|
||||||
|
if (supportsManagedMeasurements(record)) {
|
||||||
|
managedMeasurementKinds(record).forEach(kind => {
|
||||||
|
const measurementsVisible = managedMeasurementsGloballyVisible(record.categoryKey)
|
||||||
|
&& !managedMeasurementHiddenSet(kind.key).has(record.id);
|
||||||
|
details.appendChild(renderLayerManagerVisibilityOption(
|
||||||
|
kind.label,
|
||||||
|
measurementsVisible,
|
||||||
|
checked => setManagedMeasurementKindVisible(record, kind.key, checked)));
|
||||||
|
});
|
||||||
|
}
|
||||||
const rows = managedObjectDetails(record.layer);
|
const rows = managedObjectDetails(record.layer);
|
||||||
details.innerHTML = rows.length
|
const info = document.createElement("div");
|
||||||
|
info.className = "layer-manager-info";
|
||||||
|
info.innerHTML = rows.length
|
||||||
? rows.map(value => `<span>${escapeHtml(value)}</span>`).join("")
|
? rows.map(value => `<span>${escapeHtml(value)}</span>`).join("")
|
||||||
: "<span>Nessuna misura disponibile</span>";
|
: "<span>Nessuna misura disponibile</span>";
|
||||||
|
details.appendChild(info);
|
||||||
return object;
|
return object;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function renderLayerManagerVisibilityOption(label, checked, onChange) {
|
||||||
|
const option = document.createElement("label");
|
||||||
|
option.className = "layer-manager-suboption";
|
||||||
|
option.innerHTML = `<input type="checkbox" ${checked ? "checked" : ""}><span>${escapeHtml(label)}</span>`;
|
||||||
|
const checkbox = option.querySelector("input");
|
||||||
|
checkbox.addEventListener("click", event => event.stopPropagation());
|
||||||
|
checkbox.addEventListener("change", () => onChange(checkbox.checked));
|
||||||
|
return option;
|
||||||
|
}
|
||||||
|
|
||||||
|
function geometryVisibilityLabel(layer) {
|
||||||
|
if (layer instanceof L.Polygon || layer instanceof L.Circle) {
|
||||||
|
return "Area/geometria sulla mappa";
|
||||||
|
}
|
||||||
|
if (layer instanceof L.Polyline) {
|
||||||
|
return "Linea sulla mappa";
|
||||||
|
}
|
||||||
|
return "Punto sulla mappa";
|
||||||
|
}
|
||||||
|
|
||||||
|
function supportsManagedMeasurements(record) {
|
||||||
|
return ["imported", "drawings"].includes(record.categoryKey)
|
||||||
|
&& (record.layer instanceof L.Circle
|
||||||
|
|| record.layer instanceof L.Polygon
|
||||||
|
|| record.layer instanceof L.Polyline);
|
||||||
|
}
|
||||||
|
|
||||||
|
function managedMeasurementsGloballyVisible(categoryKey) {
|
||||||
|
return categoryKey === "imported"
|
||||||
|
? lmeState.showImportedMeasurements
|
||||||
|
: lmeState.showDrawingMeasurements;
|
||||||
|
}
|
||||||
|
|
||||||
|
function managedMeasurementKinds(record) {
|
||||||
|
if (record.layer instanceof L.Polygon) {
|
||||||
|
return [
|
||||||
|
{ key: "summary", label: "Superficie e perimetro sulla mappa" },
|
||||||
|
{ key: "sides", label: "Misure dei lati sulla mappa" }
|
||||||
|
];
|
||||||
|
}
|
||||||
|
if (record.layer instanceof L.Circle) {
|
||||||
|
return [{ key: "summary", label: "Superficie, raggio e circonferenza sulla mappa" }];
|
||||||
|
}
|
||||||
|
return [
|
||||||
|
{ key: "summary", label: "Lunghezza totale sulla mappa" },
|
||||||
|
{ key: "sides", label: "Misure dei tratti sulla mappa" }
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
function managedMeasurementHiddenSet(kind) {
|
||||||
|
return kind === "sides"
|
||||||
|
? lmeState.managerHiddenMeasurementSideIds
|
||||||
|
: lmeState.managerHiddenMeasurementSummaryIds;
|
||||||
|
}
|
||||||
|
|
||||||
|
function setManagedMeasurementKindVisible(record, kind, visible) {
|
||||||
|
const hiddenSet = managedMeasurementHiddenSet(kind);
|
||||||
|
if (visible) {
|
||||||
|
if (!managedMeasurementsGloballyVisible(record.categoryKey)) {
|
||||||
|
lmeState.managerRecords.forEach(candidate => {
|
||||||
|
if (candidate.categoryKey === record.categoryKey
|
||||||
|
&& supportsManagedMeasurements(candidate)) {
|
||||||
|
lmeState.managerHiddenMeasurementSummaryIds.add(candidate.id);
|
||||||
|
lmeState.managerHiddenMeasurementSideIds.add(candidate.id);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (record.categoryKey === "imported") {
|
||||||
|
lmeState.showImportedMeasurements = true;
|
||||||
|
} else {
|
||||||
|
lmeState.showDrawingMeasurements = true;
|
||||||
|
}
|
||||||
|
void lmeState.dotNetReference?.invokeMethodAsync(
|
||||||
|
"SetMeasurementsFromLayerManager",
|
||||||
|
record.categoryKey,
|
||||||
|
true);
|
||||||
|
}
|
||||||
|
hiddenSet.delete(record.id);
|
||||||
|
} else {
|
||||||
|
hiddenSet.add(record.id);
|
||||||
|
}
|
||||||
|
refreshImportedMeasurements();
|
||||||
|
refreshDrawingMeasurements();
|
||||||
|
refreshLayerManager();
|
||||||
|
}
|
||||||
|
|
||||||
|
function captureLayerManagerExpansion(container) {
|
||||||
|
container.querySelectorAll("details[data-expansion-key]").forEach(row => {
|
||||||
|
if (row.open) {
|
||||||
|
lmeState.managerExpandedRows.add(row.dataset.expansionKey);
|
||||||
|
} else {
|
||||||
|
lmeState.managerExpandedRows.delete(row.dataset.expansionKey);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function bindLayerManagerExpansion(row, key) {
|
||||||
|
row.dataset.expansionKey = key;
|
||||||
|
row.open = lmeState.managerExpandedRows.has(key);
|
||||||
|
row.addEventListener("toggle", () => {
|
||||||
|
if (row.open) {
|
||||||
|
lmeState.managerExpandedRows.add(key);
|
||||||
|
} else {
|
||||||
|
lmeState.managerExpandedRows.delete(key);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function setManagedCategoryVisible(category, visible) {
|
function setManagedCategoryVisible(category, visible) {
|
||||||
if (category.key === "imported") {
|
if (category.key === "imported") {
|
||||||
lmeState.importedVisible = visible;
|
lmeState.importedVisible = visible;
|
||||||
@@ -1372,33 +1736,107 @@ function highlightManagedObject(record) {
|
|||||||
document.querySelectorAll(".layer-manager-object").forEach(row => {
|
document.querySelectorAll(".layer-manager-object").forEach(row => {
|
||||||
row.classList.toggle("layer-manager-object-selected", row.dataset.objectId === record.id);
|
row.classList.toggle("layer-manager-object-selected", row.dataset.objectId === record.id);
|
||||||
});
|
});
|
||||||
const geojson = record.layer.toGeoJSON?.();
|
renderManagerHighlight([record]);
|
||||||
if (geojson) {
|
|
||||||
L.geoJSON(geojson, {
|
|
||||||
pane: "managerHighlightPane",
|
|
||||||
interactive: false,
|
|
||||||
style: { color: "#ff00d4", weight: 8, opacity: 1, fillColor: "#00fff0", fillOpacity: 0.16 },
|
|
||||||
pointToLayer: (feature, latlng) => L.circleMarker(latlng, {
|
|
||||||
pane: "managerHighlightPane",
|
|
||||||
radius: 12,
|
|
||||||
color: "#ff00d4",
|
|
||||||
weight: 5,
|
|
||||||
fillColor: "#00fff0",
|
|
||||||
fillOpacity: 0.9,
|
|
||||||
interactive: false
|
|
||||||
})
|
|
||||||
}).addTo(lmeState.managerHighlight);
|
|
||||||
}
|
|
||||||
fitLayer(record.layer);
|
fitLayer(record.layer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function bindManagedParentHighlight(row, key, records) {
|
||||||
|
const summary = row.querySelector(":scope > summary");
|
||||||
|
row.dataset.highlightKey = key;
|
||||||
|
row.classList.toggle("layer-manager-parent-selected", lmeState.managerHighlightedParentKey === key);
|
||||||
|
if (lmeState.managerHighlightedParentKey === key) {
|
||||||
|
lmeState.managerHighlightedParentRecords = records;
|
||||||
|
}
|
||||||
|
row.querySelector(":scope > summary > .layer-manager-title").addEventListener("click", event => {
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
row.open = true;
|
||||||
|
highlightManagedParent(row, key, records);
|
||||||
|
});
|
||||||
|
summary.addEventListener("pointerenter", () => {
|
||||||
|
lmeState.managerHoveredParentKey = key;
|
||||||
|
lmeState.managerHoveredParentRecords = records;
|
||||||
|
row.classList.add("layer-manager-parent-highlighted");
|
||||||
|
renderManagerHighlight(records);
|
||||||
|
});
|
||||||
|
summary.addEventListener("pointerleave", () => {
|
||||||
|
if (lmeState.managerHoveredParentKey !== key) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
lmeState.managerHoveredParentKey = null;
|
||||||
|
lmeState.managerHoveredParentRecords = null;
|
||||||
|
row.classList.remove("layer-manager-parent-highlighted");
|
||||||
|
renderSelectedManagerHighlight();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function highlightManagedParent(row, key, records) {
|
||||||
|
if (lmeState.managerHighlightedParentKey === key) {
|
||||||
|
clearManagerHighlight();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
clearManagerHighlight();
|
||||||
|
lmeState.managerHighlightedParentKey = key;
|
||||||
|
lmeState.managerHighlightedParentRecords = records;
|
||||||
|
lmeState.managerHighlightedCategoryKey = records[0]?.categoryKey || null;
|
||||||
|
row.classList.add("layer-manager-parent-selected");
|
||||||
|
renderManagerHighlight(records);
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderSelectedManagerHighlight() {
|
||||||
|
if (lmeState.managerHighlightedParentRecords?.length) {
|
||||||
|
renderManagerHighlight(lmeState.managerHighlightedParentRecords);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const selected = lmeState.managerRecords.get(lmeState.managerHighlightedObjectId);
|
||||||
|
renderManagerHighlight(selected ? [selected] : []);
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderManagerHighlight(records) {
|
||||||
|
lmeState.managerHighlight?.clearLayers();
|
||||||
|
const features = records.flatMap(record => {
|
||||||
|
const geojson = record.layer?.toGeoJSON?.();
|
||||||
|
if (!geojson) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
return geojson.type === "FeatureCollection" ? geojson.features : [geojson];
|
||||||
|
});
|
||||||
|
if (!features.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
L.geoJSON({ type: "FeatureCollection", features }, {
|
||||||
|
pane: "managerHighlightPane",
|
||||||
|
interactive: false,
|
||||||
|
style: { color: "#ff00d4", weight: 8, opacity: 1, fillColor: "#00fff0", fillOpacity: 0.16 },
|
||||||
|
pointToLayer: (feature, latlng) => L.circleMarker(latlng, {
|
||||||
|
pane: "managerHighlightPane",
|
||||||
|
radius: 12,
|
||||||
|
color: "#ff00d4",
|
||||||
|
weight: 5,
|
||||||
|
fillColor: "#00fff0",
|
||||||
|
fillOpacity: 0.9,
|
||||||
|
interactive: false
|
||||||
|
})
|
||||||
|
}).addTo(lmeState.managerHighlight);
|
||||||
|
}
|
||||||
|
|
||||||
function clearManagerHighlight() {
|
function clearManagerHighlight() {
|
||||||
lmeState.managerHighlight?.clearLayers();
|
lmeState.managerHighlight?.clearLayers();
|
||||||
lmeState.managerHighlightedObjectId = null;
|
lmeState.managerHighlightedObjectId = null;
|
||||||
lmeState.managerHighlightedCategoryKey = null;
|
lmeState.managerHighlightedCategoryKey = null;
|
||||||
|
lmeState.managerHighlightedParentKey = null;
|
||||||
|
lmeState.managerHighlightedParentRecords = null;
|
||||||
|
lmeState.managerHoveredParentKey = null;
|
||||||
|
lmeState.managerHoveredParentRecords = null;
|
||||||
document.querySelectorAll(".layer-manager-object-selected").forEach(row => {
|
document.querySelectorAll(".layer-manager-object-selected").forEach(row => {
|
||||||
row.classList.remove("layer-manager-object-selected");
|
row.classList.remove("layer-manager-object-selected");
|
||||||
});
|
});
|
||||||
|
document.querySelectorAll(".layer-manager-parent-highlighted").forEach(row => {
|
||||||
|
row.classList.remove("layer-manager-parent-highlighted");
|
||||||
|
});
|
||||||
|
document.querySelectorAll(".layer-manager-parent-selected").forEach(row => {
|
||||||
|
row.classList.remove("layer-manager-parent-selected");
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function layerManagerMoveButtons(label) {
|
function layerManagerMoveButtons(label) {
|
||||||
@@ -1624,6 +2062,7 @@ function applyImportedSheetVisibility() {
|
|||||||
function setImportedMeasurementsVisible(enabled) {
|
function setImportedMeasurementsVisible(enabled) {
|
||||||
lmeState.showImportedMeasurements = Boolean(enabled);
|
lmeState.showImportedMeasurements = Boolean(enabled);
|
||||||
refreshImportedMeasurements();
|
refreshImportedMeasurements();
|
||||||
|
refreshLayerManager();
|
||||||
setInfo(lmeState.showImportedMeasurements
|
setInfo(lmeState.showImportedMeasurements
|
||||||
? "Misure dei file GIS visibili."
|
? "Misure dei file GIS visibili."
|
||||||
: "Misure dei file GIS nascoste.");
|
: "Misure dei file GIS nascoste.");
|
||||||
@@ -1632,6 +2071,7 @@ function setImportedMeasurementsVisible(enabled) {
|
|||||||
function setDrawingMeasurementsVisible(enabled) {
|
function setDrawingMeasurementsVisible(enabled) {
|
||||||
lmeState.showDrawingMeasurements = Boolean(enabled);
|
lmeState.showDrawingMeasurements = Boolean(enabled);
|
||||||
refreshDrawingMeasurements();
|
refreshDrawingMeasurements();
|
||||||
|
refreshLayerManager();
|
||||||
setInfo(lmeState.showDrawingMeasurements
|
setInfo(lmeState.showDrawingMeasurements
|
||||||
? "Misure dei disegni visibili."
|
? "Misure dei disegni visibili."
|
||||||
: "Misure dei disegni nascoste.");
|
: "Misure dei disegni nascoste.");
|
||||||
@@ -1901,15 +2341,27 @@ function renderMeasurements(sourceGroup, targetGroup, visible, sourceType) {
|
|||||||
sourceType
|
sourceType
|
||||||
};
|
};
|
||||||
visitMeasurableLayers(sourceGroup, layer => {
|
visitMeasurableLayers(sourceGroup, layer => {
|
||||||
|
const categoryKey = sourceType === "imported" ? "imported" : "drawings";
|
||||||
|
const objectId = managedLayerId(layer, categoryKey);
|
||||||
|
const showSummary = !lmeState.managerHiddenMeasurementSummaryIds.has(objectId);
|
||||||
|
const showSides = !lmeState.managerHiddenMeasurementSideIds.has(objectId);
|
||||||
|
if (!showSummary && !showSides) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (context.count >= context.max || !layerIsInView(layer, context.bounds)) {
|
if (context.count >= context.max || !layerIsInView(layer, context.bounds)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
const layerContext = {
|
||||||
|
...context,
|
||||||
|
showSummary,
|
||||||
|
showSides: context.showSides && showSides
|
||||||
|
};
|
||||||
if (layer instanceof L.Circle) {
|
if (layer instanceof L.Circle) {
|
||||||
renderCircleMeasurement(layer, targetGroup, context);
|
renderCircleMeasurement(layer, targetGroup, layerContext);
|
||||||
} else if (layer instanceof L.Polygon) {
|
} else if (layer instanceof L.Polygon) {
|
||||||
renderPolygonMeasurement(layer, targetGroup, context);
|
renderPolygonMeasurement(layer, targetGroup, layerContext);
|
||||||
} else if (layer instanceof L.Polyline) {
|
} else if (layer instanceof L.Polyline) {
|
||||||
renderPolylineMeasurement(layer, targetGroup, context);
|
renderPolylineMeasurement(layer, targetGroup, layerContext);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -1936,6 +2388,9 @@ function layerIsInView(layer, mapBounds) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function renderCircleMeasurement(layer, targetGroup, context) {
|
function renderCircleMeasurement(layer, targetGroup, context) {
|
||||||
|
if (!context.showSummary) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
const radius = layer.getRadius();
|
const radius = layer.getRadius();
|
||||||
const area = Math.PI * radius * radius;
|
const area = Math.PI * radius * radius;
|
||||||
const circumference = 2 * Math.PI * radius;
|
const circumference = 2 * Math.PI * radius;
|
||||||
@@ -1964,12 +2419,14 @@ function renderPolygonMeasurement(layer, targetGroup, context) {
|
|||||||
const center = typeof layer.getCenter === "function"
|
const center = typeof layer.getCenter === "function"
|
||||||
? layer.getCenter()
|
? layer.getCenter()
|
||||||
: layer.getBounds().getCenter();
|
: layer.getBounds().getCenter();
|
||||||
addMeasurementLabel(
|
if (context.showSummary) {
|
||||||
targetGroup,
|
addMeasurementLabel(
|
||||||
center,
|
targetGroup,
|
||||||
`S: ${formatArea(Math.max(0, area))}<br>P: ${formatDistance(perimeter)}`,
|
center,
|
||||||
"summary",
|
`S: ${formatArea(Math.max(0, area))}<br>P: ${formatDistance(perimeter)}`,
|
||||||
context);
|
"summary",
|
||||||
|
context);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderPolylineMeasurement(layer, targetGroup, context) {
|
function renderPolylineMeasurement(layer, targetGroup, context) {
|
||||||
@@ -1979,7 +2436,7 @@ function renderPolylineMeasurement(layer, targetGroup, context) {
|
|||||||
lines.forEach(line => addSegmentLabels(line, false, targetGroup, context));
|
lines.forEach(line => addSegmentLabels(line, false, targetGroup, context));
|
||||||
}
|
}
|
||||||
const longest = lines.reduce((current, line) => line.length > current.length ? line : current, []);
|
const longest = lines.reduce((current, line) => line.length > current.length ? line : current, []);
|
||||||
if (longest.length) {
|
if (context.showSummary && longest.length) {
|
||||||
addMeasurementLabel(
|
addMeasurementLabel(
|
||||||
targetGroup,
|
targetGroup,
|
||||||
longest[Math.floor(longest.length / 2)],
|
longest[Math.floor(longest.length / 2)],
|
||||||
@@ -2325,7 +2782,11 @@ function captureDisplayOptions() {
|
|||||||
selectedParcelsVisible: lmeState.selectedParcelsVisible,
|
selectedParcelsVisible: lmeState.selectedParcelsVisible,
|
||||||
layerOrder: [...lmeState.layerOrder],
|
layerOrder: [...lmeState.layerOrder],
|
||||||
layerObjectOrder: { ...lmeState.managerObjectOrder },
|
layerObjectOrder: { ...lmeState.managerObjectOrder },
|
||||||
|
layerCategoryNames: { ...lmeState.managerCategoryNames },
|
||||||
|
removedLayerCategories: [...lmeState.managerRemovedCategories],
|
||||||
hiddenLayerObjects: [...lmeState.managerHiddenObjectIds],
|
hiddenLayerObjects: [...lmeState.managerHiddenObjectIds],
|
||||||
|
hiddenLayerMeasurementSummaries: [...lmeState.managerHiddenMeasurementSummaryIds],
|
||||||
|
hiddenLayerMeasurementSides: [...lmeState.managerHiddenMeasurementSideIds],
|
||||||
hiddenLayerCategories: [...lmeState.managerHiddenCategories],
|
hiddenLayerCategories: [...lmeState.managerHiddenCategories],
|
||||||
trailEnabled: lmeState.gpsTrailEnabled
|
trailEnabled: lmeState.gpsTrailEnabled
|
||||||
};
|
};
|
||||||
@@ -2359,9 +2820,21 @@ function applyProjectDisplayOptions(options) {
|
|||||||
if (options.layerObjectOrder && typeof options.layerObjectOrder === "object") {
|
if (options.layerObjectOrder && typeof options.layerObjectOrder === "object") {
|
||||||
lmeState.managerObjectOrder = options.layerObjectOrder;
|
lmeState.managerObjectOrder = options.layerObjectOrder;
|
||||||
}
|
}
|
||||||
|
if (options.layerCategoryNames && typeof options.layerCategoryNames === "object") {
|
||||||
|
lmeState.managerCategoryNames = { ...options.layerCategoryNames };
|
||||||
|
}
|
||||||
|
if (Array.isArray(options.removedLayerCategories)) {
|
||||||
|
lmeState.managerRemovedCategories = new Set(options.removedLayerCategories);
|
||||||
|
}
|
||||||
if (Array.isArray(options.hiddenLayerObjects)) {
|
if (Array.isArray(options.hiddenLayerObjects)) {
|
||||||
lmeState.managerHiddenObjectIds = new Set(options.hiddenLayerObjects);
|
lmeState.managerHiddenObjectIds = new Set(options.hiddenLayerObjects);
|
||||||
}
|
}
|
||||||
|
if (Array.isArray(options.hiddenLayerMeasurementSummaries)) {
|
||||||
|
lmeState.managerHiddenMeasurementSummaryIds = new Set(options.hiddenLayerMeasurementSummaries);
|
||||||
|
}
|
||||||
|
if (Array.isArray(options.hiddenLayerMeasurementSides)) {
|
||||||
|
lmeState.managerHiddenMeasurementSideIds = new Set(options.hiddenLayerMeasurementSides);
|
||||||
|
}
|
||||||
if (Array.isArray(options.hiddenLayerCategories)) {
|
if (Array.isArray(options.hiddenLayerCategories)) {
|
||||||
lmeState.managerHiddenCategories = new Set(options.hiddenLayerCategories);
|
lmeState.managerHiddenCategories = new Set(options.hiddenLayerCategories);
|
||||||
}
|
}
|
||||||
@@ -2439,18 +2912,35 @@ function managedGroupGeoJson(group, categoryKey) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
const categoryName = lmeState.managerCategoryNames[categoryKey];
|
||||||
|
if (categoryName) {
|
||||||
|
features.forEach(feature => {
|
||||||
|
feature.properties = { ...(feature.properties || {}), _lmeCategoryName: categoryName };
|
||||||
|
});
|
||||||
|
}
|
||||||
return { type: "FeatureCollection", features };
|
return { type: "FeatureCollection", features };
|
||||||
}
|
}
|
||||||
|
|
||||||
function resetLayerManagerProjectState() {
|
function resetLayerManagerProjectState() {
|
||||||
lmeState.managerHiddenObjects.clear();
|
lmeState.managerHiddenObjects.clear();
|
||||||
lmeState.managerHiddenObjectIds.clear();
|
lmeState.managerHiddenObjectIds.clear();
|
||||||
|
lmeState.managerHiddenMeasurementSummaryIds.clear();
|
||||||
|
lmeState.managerHiddenMeasurementSideIds.clear();
|
||||||
lmeState.managerHiddenCategories.clear();
|
lmeState.managerHiddenCategories.clear();
|
||||||
|
lmeState.managerRemovedCategories.clear();
|
||||||
lmeState.managerObjectOrder = {};
|
lmeState.managerObjectOrder = {};
|
||||||
|
lmeState.managerCategoryNames = {};
|
||||||
clearManagerHighlight();
|
clearManagerHighlight();
|
||||||
}
|
}
|
||||||
|
|
||||||
function clearManagedCategoryState(categoryKey) {
|
function clearManagedCategoryState(categoryKey) {
|
||||||
|
const category = layerManagerCategories().find(item => item.key === categoryKey);
|
||||||
|
if (category) {
|
||||||
|
managedRecordsForCategory(category).forEach(record => {
|
||||||
|
lmeState.managerHiddenMeasurementSummaryIds.delete(record.id);
|
||||||
|
lmeState.managerHiddenMeasurementSideIds.delete(record.id);
|
||||||
|
});
|
||||||
|
}
|
||||||
[...lmeState.managerHiddenObjects.entries()].forEach(([id, record]) => {
|
[...lmeState.managerHiddenObjects.entries()].forEach(([id, record]) => {
|
||||||
if (record.categoryKey === categoryKey) {
|
if (record.categoryKey === categoryKey) {
|
||||||
lmeState.managerHiddenObjects.delete(id);
|
lmeState.managerHiddenObjects.delete(id);
|
||||||
@@ -2462,10 +2952,18 @@ function clearManagedCategoryState(categoryKey) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function bindStoredFeaturePopup(feature, layer) {
|
function bindStoredFeaturePopup(feature, layer) {
|
||||||
const properties = feature?.properties || {};
|
updateStoredFeaturePopup(layer, feature?.properties);
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateStoredFeaturePopup(layer, sourceProperties) {
|
||||||
|
const properties = sourceProperties || layer?.feature?.properties || {};
|
||||||
const label = properties.name || properties.Name || properties.label || properties.LABEL;
|
const label = properties.name || properties.Name || properties.label || properties.LABEL;
|
||||||
if (label) {
|
if (label) {
|
||||||
layer.bindPopup(`<strong>${escapeHtml(label)}</strong>`);
|
layer.bindPopup(`<strong>${escapeHtml(label)}</strong>`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (typeof layer?.unbindPopup === "function") {
|
||||||
|
layer.unbindPopup();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user