Unify cadastral object selection
This commit is contained in:
1 parent
a0e24fc925
commit
74527638c1
4 files changed
+313
-128
No files matched your search
@@ -102,7 +102,7 @@
|
|||||||
],
|
],
|
||||||
"tools" =>
|
"tools" =>
|
||||||
[
|
[
|
||||||
"Tabella oggetti: apre una vista ordinata di particelle, file importati e disegni. Usa i flag per selezionare piu righe, evidenziate sulla mappa con contorno magenta e riempimento ciano; il lucchetto le protegge e la matita modifica i metadati.",
|
"Tabella oggetti: apre una vista ordinata di particelle catastali, file importati e disegni. La selezione e bidirezionale con mappa e pannello Layer: Singola sostituisce la scelta, Multipla aggiunge o rimuove oggetti, Disattivata deseleziona tutto e blocca nuove selezioni. Cancella selezione toglie soltanto lo stato selezionato e non elimina geometrie.",
|
||||||
"Colonna Note: il pulsante Note e sempre attivo e apre tutte le note dell'oggetto. La consultazione resta disponibile anche senza Pro; aggiunta, modifica ed eliminazione richiedono abbonamento o licenza manuale.",
|
"Colonna Note: il pulsante Note e sempre attivo e apre tutte le note dell'oggetto. La consultazione resta disponibile anche senza Pro; aggiunta, modifica ed eliminazione richiedono abbonamento o licenza manuale.",
|
||||||
"Copia metadati: nella maschera Metadati oggetto scegli Copia da e l'oggetto sorgente. Attiva Importa anche i valori per copiare nomi e contenuti; disattivalo per creare soltanto gli stessi campi, lasciandoli vuoti o mantenendo i valori gia presenti.",
|
"Copia metadati: nella maschera Metadati oggetto scegli Copia da e l'oggetto sorgente. Attiva Importa anche i valori per copiare nomi e contenuti; disattivalo per creare soltanto gli stessi campi, lasciandoli vuoti o mantenendo i valori gia presenti.",
|
||||||
"Coordinate WGS84 e UTM: scegli un punto sulla mappa per leggere latitudine e longitudine oppure le coordinate metriche UTM, utili per rilievi e confronti tecnici.",
|
"Coordinate WGS84 e UTM: scegli un punto sulla mappa per leggere latitudine e longitudine oppure le coordinate metriche UTM, utili per rilievi e confronti tecnici.",
|
||||||
|
|||||||
@@ -29,8 +29,8 @@
|
|||||||
<ApplicationId>it.liviomerola.lmemappecatastali.pro</ApplicationId>
|
<ApplicationId>it.liviomerola.lmemappecatastali.pro</ApplicationId>
|
||||||
|
|
||||||
<!-- Versions -->
|
<!-- Versions -->
|
||||||
<ApplicationDisplayVersion>1.0.23</ApplicationDisplayVersion>
|
<ApplicationDisplayVersion>1.0.24</ApplicationDisplayVersion>
|
||||||
<ApplicationVersion>123</ApplicationVersion>
|
<ApplicationVersion>124</ApplicationVersion>
|
||||||
<Version>$(ApplicationDisplayVersion)</Version>
|
<Version>$(ApplicationDisplayVersion)</Version>
|
||||||
|
|
||||||
<!-- 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 -->
|
||||||
|
|||||||
+31
-5
@@ -913,6 +913,11 @@ input[type="checkbox"] {
|
|||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.object-table-wrap tr.object-table-selected td {
|
||||||
|
background: #fce7f3;
|
||||||
|
box-shadow: inset 0 1px 0 #f0abfc, inset 0 -1px 0 #f0abfc;
|
||||||
|
}
|
||||||
|
|
||||||
.managed-notes-command {
|
.managed-notes-command {
|
||||||
display: grid;
|
display: grid;
|
||||||
gap: 5px;
|
gap: 5px;
|
||||||
@@ -1224,6 +1229,12 @@ input[type="checkbox"] {
|
|||||||
font-size: 11px;
|
font-size: 11px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.object-table-legend button {
|
||||||
|
min-height: 28px;
|
||||||
|
padding: 4px 9px;
|
||||||
|
font-size: 11px;
|
||||||
|
}
|
||||||
|
|
||||||
.object-table-wrap input[type="checkbox"] {
|
.object-table-wrap input[type="checkbox"] {
|
||||||
width: 18px;
|
width: 18px;
|
||||||
height: 18px;
|
height: 18px;
|
||||||
@@ -1271,17 +1282,23 @@ input[type="checkbox"] {
|
|||||||
opacity: 0.72;
|
opacity: 0.72;
|
||||||
}
|
}
|
||||||
|
|
||||||
.lme-geometry-toolbar a.lme-multi-selection-button.is-active {
|
.lme-geometry-toolbar a.lme-selection-mode-button.is-active {
|
||||||
background: #0f766e;
|
background: #0f766e;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
box-shadow: inset 0 0 0 2px #99f6e4;
|
box-shadow: inset 0 0 0 2px #99f6e4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.lme-geometry-toolbar a.lme-selection-mode-button.is-multiple {
|
||||||
|
background: #a21caf;
|
||||||
|
box-shadow: inset 0 0 0 2px #f5d0fe;
|
||||||
|
}
|
||||||
|
|
||||||
.lme-geometry-toolbar {
|
.lme-geometry-toolbar {
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
.lme-comparison-actions {
|
.lme-comparison-actions,
|
||||||
|
.lme-selection-actions {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: calc(100% + 6px);
|
right: calc(100% + 6px);
|
||||||
z-index: 1000;
|
z-index: 1000;
|
||||||
@@ -1294,7 +1311,12 @@ input[type="checkbox"] {
|
|||||||
box-shadow: 0 2px 8px rgb(0 0 0 / 22%);
|
box-shadow: 0 2px 8px rgb(0 0 0 / 22%);
|
||||||
}
|
}
|
||||||
|
|
||||||
.lme-geometry-toolbar .lme-comparison-actions a {
|
.lme-selection-actions {
|
||||||
|
min-width: 205px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lme-geometry-toolbar .lme-comparison-actions a,
|
||||||
|
.lme-geometry-toolbar .lme-selection-actions a {
|
||||||
display: flex !important;
|
display: flex !important;
|
||||||
width: auto !important;
|
width: auto !important;
|
||||||
height: 36px !important;
|
height: 36px !important;
|
||||||
@@ -1309,12 +1331,16 @@ input[type="checkbox"] {
|
|||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.lme-geometry-toolbar .lme-comparison-actions a:last-child {
|
.lme-geometry-toolbar .lme-comparison-actions a:last-child,
|
||||||
|
.lme-geometry-toolbar .lme-selection-actions a:last-child {
|
||||||
border-bottom: 0;
|
border-bottom: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.lme-geometry-toolbar .lme-comparison-actions a:hover,
|
.lme-geometry-toolbar .lme-comparison-actions a:hover,
|
||||||
.lme-geometry-toolbar .lme-comparison-actions a:focus-visible {
|
.lme-geometry-toolbar .lme-comparison-actions a:focus-visible,
|
||||||
|
.lme-geometry-toolbar .lme-selection-actions a:hover,
|
||||||
|
.lme-geometry-toolbar .lme-selection-actions a:focus-visible,
|
||||||
|
.lme-geometry-toolbar .lme-selection-actions a.is-current {
|
||||||
background: #e8f4f1;
|
background: #e8f4f1;
|
||||||
color: #075e54;
|
color: #075e54;
|
||||||
}
|
}
|
||||||
|
|||||||
+279
-120
@@ -38,8 +38,9 @@ const lmeState = {
|
|||||||
drawingScopeMenu: null,
|
drawingScopeMenu: null,
|
||||||
geometryToolsControl: null,
|
geometryToolsControl: null,
|
||||||
comparisonMenu: null,
|
comparisonMenu: null,
|
||||||
multiSelectionEnabled: false,
|
selectionMenu: null,
|
||||||
multiSelectionButton: null,
|
selectionMode: "single",
|
||||||
|
selectionModeButton: null,
|
||||||
fiducialDownloadButton: null,
|
fiducialDownloadButton: null,
|
||||||
ignoreMapClickUntil: 0,
|
ignoreMapClickUntil: 0,
|
||||||
activeDrawHandler: null,
|
activeDrawHandler: null,
|
||||||
@@ -402,7 +403,7 @@ function init(dotNetReference) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
hideDrawingScopeMenu();
|
hideDrawingScopeMenu();
|
||||||
if (!multiSelectionHasObjects()) clearManagerHighlight();
|
if (!selectionHasObjects()) clearManagerHighlight();
|
||||||
const info = await queryFeatureInfo(event.latlng);
|
const info = await queryFeatureInfo(event.latlng);
|
||||||
if (info) {
|
if (info) {
|
||||||
L.popup().setLatLng(event.latlng).setContent(info).openOn(lmeState.map);
|
L.popup().setLatLng(event.latlng).setContent(info).openOn(lmeState.map);
|
||||||
@@ -448,6 +449,10 @@ function init(dotNetReference) {
|
|||||||
&& !event.target?.closest?.(".lme-comparison-actions, .lme-comparison-button")) {
|
&& !event.target?.closest?.(".lme-comparison-actions, .lme-comparison-button")) {
|
||||||
hideComparisonMenu();
|
hideComparisonMenu();
|
||||||
}
|
}
|
||||||
|
if (lmeState.selectionMenu
|
||||||
|
&& !event.target?.closest?.(".lme-selection-actions, .lme-selection-mode-button")) {
|
||||||
|
hideSelectionMenu();
|
||||||
|
}
|
||||||
if (!lmeState.managerHighlightedObjectId && !lmeState.managerHighlightedParentKey) {
|
if (!lmeState.managerHighlightedObjectId && !lmeState.managerHighlightedParentKey) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -460,7 +465,7 @@ function init(dotNetReference) {
|
|||||||
|| selectedParent?.dataset.highlightKey === lmeState.managerHighlightedParentKey) {
|
|| selectedParent?.dataset.highlightKey === lmeState.managerHighlightedParentKey) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (multiSelectionHasObjects()) {
|
if (selectionHasObjects()) {
|
||||||
renderSelectedManagerHighlight();
|
renderSelectedManagerHighlight();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -791,6 +796,7 @@ function displayOfficialParcel(xmlText, latitude, longitude, parcel, label, shou
|
|||||||
targetGroup.bringToFront();
|
targetGroup.bringToFront();
|
||||||
}
|
}
|
||||||
if (!normalizedParcel) {
|
if (!normalizedParcel) {
|
||||||
|
clearManagedCategorySelection("gpsParcels");
|
||||||
targetGroup.clearLayers();
|
targetGroup.clearLayers();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -831,11 +837,11 @@ function displayOfficialParcel(xmlText, latitude, longitude, parcel, label, shou
|
|||||||
feature.properties = {
|
feature.properties = {
|
||||||
...(feature.properties || {}),
|
...(feature.properties || {}),
|
||||||
_lmeParcelReference: String(ref || label || normalizedParcel),
|
_lmeParcelReference: String(ref || label || normalizedParcel),
|
||||||
_lmeColor: feature.properties?._lmeColor || "#ef4444",
|
_lmeColor: feature.properties?._lmeColor || (normalizedParcel ? "#ef4444" : "#1d4ed8"),
|
||||||
_lmeFillColor: feature.properties?._lmeFillColor || "#fbbf24",
|
_lmeFillColor: feature.properties?._lmeFillColor || (normalizedParcel ? "#fbbf24" : "#38bdf8"),
|
||||||
_lmeWeight: Number(feature.properties?._lmeWeight) || 4,
|
_lmeWeight: Number(feature.properties?._lmeWeight) || 4,
|
||||||
_lmeOpacity: Number.isFinite(Number(feature.properties?._lmeOpacity)) ? Number(feature.properties._lmeOpacity) : 1,
|
_lmeOpacity: Number.isFinite(Number(feature.properties?._lmeOpacity)) ? Number(feature.properties._lmeOpacity) : 1,
|
||||||
_lmeFillOpacity: Number.isFinite(Number(feature.properties?._lmeFillOpacity)) ? Number(feature.properties._lmeFillOpacity) : 0.26
|
_lmeFillOpacity: Number.isFinite(Number(feature.properties?._lmeFillOpacity)) ? Number(feature.properties._lmeFillOpacity) : (normalizedParcel ? 0.26 : 0.2)
|
||||||
};
|
};
|
||||||
const layer = L.geoJSON(feature, {
|
const layer = L.geoJSON(feature, {
|
||||||
pane: normalizedParcel ? "selectedParcelsPane" : "gpsParcelsPane",
|
pane: normalizedParcel ? "selectedParcelsPane" : "gpsParcelsPane",
|
||||||
@@ -845,6 +851,7 @@ function displayOfficialParcel(xmlText, latitude, longitude, parcel, label, shou
|
|||||||
}).addTo(targetGroup);
|
}).addTo(targetGroup);
|
||||||
layer.lmeParcelReference = ref;
|
layer.lmeParcelReference = ref;
|
||||||
layer.bindPopup(`<strong>${escapeHtml(ref)}</strong>`);
|
layer.bindPopup(`<strong>${escapeHtml(ref)}</strong>`);
|
||||||
|
bindParcelMapSelection(layer, normalizedParcel ? "selectedParcels" : "gpsParcels", ref);
|
||||||
if (normalizedParcel) {
|
if (normalizedParcel) {
|
||||||
targetGroup.bringToFront();
|
targetGroup.bringToFront();
|
||||||
}
|
}
|
||||||
@@ -890,6 +897,16 @@ function findParcelLayerByReference(group, reference) {
|
|||||||
return match;
|
return match;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function bindParcelMapSelection(geoJsonLayer, categoryKey, reference) {
|
||||||
|
if (!geoJsonLayer || typeof geoJsonLayer.eachLayer !== "function") return;
|
||||||
|
geoJsonLayer.eachLayer(layer => {
|
||||||
|
layer.lmeParcelReference = reference;
|
||||||
|
layer.bindPopup?.(`<strong>${escapeHtml(reference)}</strong>`);
|
||||||
|
applyStyleFromProperties(layer);
|
||||||
|
bindManagedMapSelection(layer, categoryKey, geoJsonLayer);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function restoreHiddenParcelLayerByReference(reference) {
|
function restoreHiddenParcelLayerByReference(reference) {
|
||||||
const expected = normalizeParcelReference(reference);
|
const expected = normalizeParcelReference(reference);
|
||||||
const entry = [...lmeState.managerHiddenObjects.entries()].find(([, record]) =>
|
const entry = [...lmeState.managerHiddenObjects.entries()].find(([, record]) =>
|
||||||
@@ -1979,6 +1996,7 @@ function applyLayerManagerPalette(row, key) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function clearManagedObjectState(id) {
|
function clearManagedObjectState(id) {
|
||||||
|
lmeState.managerSelectedObjectIds.delete(id);
|
||||||
lmeState.managerHiddenObjects.delete(id);
|
lmeState.managerHiddenObjects.delete(id);
|
||||||
lmeState.managerHiddenObjectIds.delete(id);
|
lmeState.managerHiddenObjectIds.delete(id);
|
||||||
lmeState.managerHiddenMeasurementSummaryIds.delete(id);
|
lmeState.managerHiddenMeasurementSummaryIds.delete(id);
|
||||||
@@ -2255,7 +2273,7 @@ function refreshLayerManager() {
|
|||||||
scrollHost.scrollTop = scrollTop;
|
scrollHost.scrollTop = scrollTop;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (multiSelectionHasObjects()) renderSelectedManagerHighlight();
|
if (selectionHasObjects()) renderSelectedManagerHighlight();
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderLayerManagerCategory(category, records) {
|
function renderLayerManagerCategory(category, records) {
|
||||||
@@ -2389,7 +2407,7 @@ function renderLayerManagerBlock(category, source, records) {
|
|||||||
function renderLayerManagerObject(record, index) {
|
function renderLayerManagerObject(record, index) {
|
||||||
const object = document.createElement("details");
|
const object = document.createElement("details");
|
||||||
object.className = "layer-manager-object";
|
object.className = "layer-manager-object";
|
||||||
if (record.id === lmeState.managerHighlightedObjectId) {
|
if (record.id === lmeState.managerHighlightedObjectId || lmeState.managerSelectedObjectIds.has(record.id)) {
|
||||||
object.classList.add("layer-manager-object-selected");
|
object.classList.add("layer-manager-object-selected");
|
||||||
}
|
}
|
||||||
object.dataset.dragType = "object";
|
object.dataset.dragType = "object";
|
||||||
@@ -2471,7 +2489,7 @@ function renderLayerSelectionToolbar() {
|
|||||||
const toolbar = document.createElement("section");
|
const toolbar = document.createElement("section");
|
||||||
toolbar.className = "layer-selection-toolbar";
|
toolbar.className = "layer-selection-toolbar";
|
||||||
toolbar.innerHTML = `<label>Cerca oggetti<input type="search" value="${escapeHtml(lmeState.managerSearchText)}" placeholder="Nome o gruppo"></label>
|
toolbar.innerHTML = `<label>Cerca oggetti<input type="search" value="${escapeHtml(lmeState.managerSearchText)}" placeholder="Nome o gruppo"></label>
|
||||||
<div class="layer-selection-summary"><strong>${selectedCount} selezionati</strong><button type="button" data-action="clear">Deseleziona</button></div>
|
<div class="layer-selection-summary"><strong>${selectedCount} selezionati</strong><button type="button" data-action="clear" title="Toglie la selezione senza eliminare oggetti">Cancella selezione</button></div>
|
||||||
<div class="layer-batch-actions">
|
<div class="layer-batch-actions">
|
||||||
<button type="button" data-action="duplicate">Duplica</button><button type="button" data-action="move">Sposta geometria</button>
|
<button type="button" data-action="duplicate">Duplica</button><button type="button" data-action="move">Sposta geometria</button>
|
||||||
<button type="button" data-action="buffer">Buffer</button><button type="button" data-action="union">Unisci</button>
|
<button type="button" data-action="buffer">Buffer</button><button type="button" data-action="union">Unisci</button>
|
||||||
@@ -2493,8 +2511,7 @@ function renderLayerSelectionToolbar() {
|
|||||||
const records = [...lmeState.managerSelectedObjectIds]
|
const records = [...lmeState.managerSelectedObjectIds]
|
||||||
.map(id => lmeState.managerRecords?.get(id)).filter(Boolean);
|
.map(id => lmeState.managerRecords?.get(id)).filter(Boolean);
|
||||||
if (button.dataset.action === "clear") {
|
if (button.dataset.action === "clear") {
|
||||||
lmeState.managerSelectedObjectIds.clear();
|
clearManagedSelection();
|
||||||
refreshLayerManager();
|
|
||||||
} else if (!records.length) {
|
} else if (!records.length) {
|
||||||
setInfo("Seleziona almeno un oggetto dalle sue opzioni.");
|
setInfo("Seleziona almeno un oggetto dalle sue opzioni.");
|
||||||
} else if (button.dataset.action === "duplicate") duplicateManagedRecords(records);
|
} else if (button.dataset.action === "duplicate") duplicateManagedRecords(records);
|
||||||
@@ -2514,16 +2531,19 @@ function renderManagedGroupTools(records) {
|
|||||||
const properties = firstLayer?.feature?.properties || {};
|
const properties = firstLayer?.feature?.properties || {};
|
||||||
const lineColor = normalizedColor(properties._lmeColor || firstLayer?.options?.color, "#16806a");
|
const lineColor = normalizedColor(properties._lmeColor || firstLayer?.options?.color, "#16806a");
|
||||||
const fillColor = normalizedColor(properties._lmeFillColor || firstLayer?.options?.fillColor, lineColor);
|
const fillColor = normalizedColor(properties._lmeFillColor || firstLayer?.options?.fillColor, lineColor);
|
||||||
|
const selectionColor = normalizedColor(properties._lmeSelectionColor, "#d500f9");
|
||||||
tools.innerHTML = `<strong>Azioni gruppo</strong><span class="layer-group-totals">${escapeHtml(managedGroupTotals(records))}</span><div class="layer-style-controls">
|
tools.innerHTML = `<strong>Azioni gruppo</strong><span class="layer-group-totals">${escapeHtml(managedGroupTotals(records))}</span><div class="layer-style-controls">
|
||||||
${managedColorEditorMarkup("color", "Colore linea", lineColor)}
|
${managedColorEditorMarkup("color", "Colore linea", lineColor)}
|
||||||
${managedColorEditorMarkup("fillColor", "Colore riempimento", fillColor)}
|
${managedColorEditorMarkup("fillColor", "Colore riempimento", fillColor)}
|
||||||
|
${managedColorEditorMarkup("selectionColor", "Colore selezione", selectionColor)}
|
||||||
<label>Spessore<input type="range" data-field="weight" min="1" max="10" step="1" value="${Number(properties._lmeWeight) || Number(firstLayer?.options?.weight) || 3}"></label>
|
<label>Spessore<input type="range" data-field="weight" min="1" max="10" step="1" value="${Number(properties._lmeWeight) || Number(firstLayer?.options?.weight) || 3}"></label>
|
||||||
<label>Opacita<input type="range" data-field="opacity" min="0.1" max="1" step="0.1" value="${Number.isFinite(Number(properties._lmeOpacity)) ? Number(properties._lmeOpacity) : Number(firstLayer?.options?.opacity) || 1}"></label></div>
|
<label>Opacita<input type="range" data-field="opacity" min="0.1" max="1" step="0.1" value="${Number.isFinite(Number(properties._lmeOpacity)) ? Number(properties._lmeOpacity) : Number(firstLayer?.options?.opacity) || 1}"></label></div>
|
||||||
<div class="layer-compact-actions"><button type="button" data-group-action="select">Seleziona tutti</button><button type="button" data-group-action="lock">Blocca/sblocca</button><button type="button" data-group-action="labels">Etichette</button></div>`;
|
<div class="layer-compact-actions"><button type="button" data-group-action="select" ${lmeState.selectionMode === "off" ? "disabled" : ""}>Seleziona tutti</button><button type="button" data-group-action="lock">Blocca/sblocca</button><button type="button" data-group-action="labels">Etichette</button></div>`;
|
||||||
const applyCurrentStyle = () => {
|
const applyCurrentStyle = () => {
|
||||||
applyManagedStyle(records, {
|
applyManagedStyle(records, {
|
||||||
color: tools.querySelector("[data-color-picker='color']").value,
|
color: tools.querySelector("[data-color-picker='color']").value,
|
||||||
fillColor: tools.querySelector("[data-color-picker='fillColor']").value,
|
fillColor: tools.querySelector("[data-color-picker='fillColor']").value,
|
||||||
|
selectionColor: tools.querySelector("[data-color-picker='selectionColor']").value,
|
||||||
weight: Number(tools.querySelector("[data-field='weight']").value),
|
weight: Number(tools.querySelector("[data-field='weight']").value),
|
||||||
opacity: Number(tools.querySelector("[data-field='opacity']").value)
|
opacity: Number(tools.querySelector("[data-field='opacity']").value)
|
||||||
});
|
});
|
||||||
@@ -2531,7 +2551,18 @@ function renderManagedGroupTools(records) {
|
|||||||
bindManagedColorEditors(tools, applyCurrentStyle);
|
bindManagedColorEditors(tools, applyCurrentStyle);
|
||||||
tools.querySelectorAll("input[type='range']").forEach(input => input.addEventListener("change", applyCurrentStyle));
|
tools.querySelectorAll("input[type='range']").forEach(input => input.addEventListener("change", applyCurrentStyle));
|
||||||
tools.querySelector("[data-group-action='select']").addEventListener("click", () => {
|
tools.querySelector("[data-group-action='select']").addEventListener("click", () => {
|
||||||
records.forEach(record => lmeState.managerSelectedObjectIds.add(record.id)); refreshLayerManager();
|
if (lmeState.selectionMode === "off") {
|
||||||
|
setInfo("Selezione disattivata. Scegli Singola o Multipla dalla barra mappa.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (lmeState.selectionMode === "single") {
|
||||||
|
selectManagedRecord(records[0]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
records.forEach(record => lmeState.managerSelectedObjectIds.add(record.id));
|
||||||
|
refreshLayerManager();
|
||||||
|
refreshMultipleMapSelection(records.at(-1));
|
||||||
|
setInfo(`${lmeState.managerSelectedObjectIds.size} oggetti selezionati.`);
|
||||||
});
|
});
|
||||||
tools.querySelector("[data-group-action='lock']").addEventListener("click", () => {
|
tools.querySelector("[data-group-action='lock']").addEventListener("click", () => {
|
||||||
const lock = !records.every(record => Boolean(record.layer?.feature?.properties?._lmeLocked));
|
const lock = !records.every(record => Boolean(record.layer?.feature?.properties?._lmeLocked));
|
||||||
@@ -2658,11 +2689,13 @@ function renderManagedObjectTools(record) {
|
|||||||
tools.className = "layer-object-tools";
|
tools.className = "layer-object-tools";
|
||||||
const lineColor = normalizedColor(properties._lmeColor || record.layer?.options?.color, "#f97316");
|
const lineColor = normalizedColor(properties._lmeColor || record.layer?.options?.color, "#f97316");
|
||||||
const fillColor = normalizedColor(properties._lmeFillColor || record.layer?.options?.fillColor, lineColor);
|
const fillColor = normalizedColor(properties._lmeFillColor || record.layer?.options?.fillColor, lineColor);
|
||||||
tools.innerHTML = `<label class="layer-manager-suboption"><input type="checkbox" data-field="selected" ${selected ? "checked" : ""}><span>Seleziona per azioni multiple</span></label>
|
const selectionColor = normalizedColor(properties._lmeSelectionColor, "#d500f9");
|
||||||
|
tools.innerHTML = `<label class="layer-manager-suboption"><input type="checkbox" data-field="selected" ${selected ? "checked" : ""} ${lmeState.selectionMode === "off" ? "disabled" : ""}><span>Selezionato (${escapeHtml(selectionModeLabel().toLocaleLowerCase("it"))})</span></label>
|
||||||
<label class="layer-manager-suboption"><input type="checkbox" data-field="locked" ${locked ? "checked" : ""}><span>Blocca modifiche e rimozione</span></label>
|
<label class="layer-manager-suboption"><input type="checkbox" data-field="locked" ${locked ? "checked" : ""}><span>Blocca modifiche e rimozione</span></label>
|
||||||
<label class="layer-manager-suboption"><input type="checkbox" data-field="label" ${properties._lmeLabelVisible ? "checked" : ""}><span>Etichetta permanente sulla mappa</span></label>
|
<label class="layer-manager-suboption"><input type="checkbox" data-field="label" ${properties._lmeLabelVisible ? "checked" : ""}><span>Etichetta permanente sulla mappa</span></label>
|
||||||
<div class="layer-style-controls">${managedColorEditorMarkup("color", "Colore linea", lineColor)}
|
<div class="layer-style-controls">${managedColorEditorMarkup("color", "Colore linea", lineColor)}
|
||||||
${managedColorEditorMarkup("fillColor", "Colore riempimento", fillColor)}
|
${managedColorEditorMarkup("fillColor", "Colore riempimento", fillColor)}
|
||||||
|
${managedColorEditorMarkup("selectionColor", "Colore selezione", selectionColor)}
|
||||||
<label>Spessore<input type="range" data-field="weight" min="1" max="10" step="1" value="${Number(properties._lmeWeight) || 3}"></label>
|
<label>Spessore<input type="range" data-field="weight" min="1" max="10" step="1" value="${Number(properties._lmeWeight) || 3}"></label>
|
||||||
<label>Opacita<input type="range" data-field="opacity" min="0.1" max="1" step="0.1" value="${Number(properties._lmeOpacity) || 1}"></label>
|
<label>Opacita<input type="range" data-field="opacity" min="0.1" max="1" step="0.1" value="${Number(properties._lmeOpacity) || 1}"></label>
|
||||||
<label>Riempimento %<input type="range" data-field="fillOpacity" min="0" max="0.8" step="0.05" value="${Number.isFinite(Number(properties._lmeFillOpacity)) ? Number(properties._lmeFillOpacity) : 0.2}"></label>
|
<label>Riempimento %<input type="range" data-field="fillOpacity" min="0" max="0.8" step="0.05" value="${Number.isFinite(Number(properties._lmeFillOpacity)) ? Number(properties._lmeFillOpacity) : 0.2}"></label>
|
||||||
@@ -2672,15 +2705,25 @@ function renderManagedObjectTools(record) {
|
|||||||
${properties._lmePhoto ? `<img class="layer-photo-preview" src="${properties._lmePhoto}" alt="Foto allegata"><button type="button" data-action="remove-photo">Rimuovi foto</button>` : ""}
|
${properties._lmePhoto ? `<img class="layer-photo-preview" src="${properties._lmePhoto}" alt="Foto allegata"><button type="button" data-action="remove-photo">Rimuovi foto</button>` : ""}
|
||||||
<div class="layer-compact-actions"><button type="button" data-action="attributes">Attributi</button><button type="button" data-action="duplicate">Duplica</button><button type="button" data-action="numeric">Coordinate</button><button type="button" data-action="inspect">WGS84 / UTM</button><button type="button" data-action="move">Sposta geometria</button><button type="button" data-action="buffer">Buffer</button></div>`;
|
<div class="layer-compact-actions"><button type="button" data-action="attributes">Attributi</button><button type="button" data-action="duplicate">Duplica</button><button type="button" data-action="numeric">Coordinate</button><button type="button" data-action="inspect">WGS84 / UTM</button><button type="button" data-action="move">Sposta geometria</button><button type="button" data-action="buffer">Buffer</button></div>`;
|
||||||
tools.querySelector("[data-field='selected']").addEventListener("change", event => {
|
tools.querySelector("[data-field='selected']").addEventListener("change", event => {
|
||||||
if (event.target.checked) lmeState.managerSelectedObjectIds.add(record.id);
|
if (lmeState.selectionMode === "off") {
|
||||||
else lmeState.managerSelectedObjectIds.delete(record.id);
|
event.target.checked = lmeState.managerSelectedObjectIds.has(record.id);
|
||||||
refreshLayerManager();
|
setInfo("Selezione disattivata. Scegli Singola o Multipla dalla barra mappa.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (event.target.checked) {
|
||||||
|
selectManagedRecord(record);
|
||||||
|
} else {
|
||||||
|
lmeState.managerSelectedObjectIds.delete(record.id);
|
||||||
|
refreshLayerManager();
|
||||||
|
refreshMultipleMapSelection();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
tools.querySelector("[data-field='locked']").addEventListener("change", event => updateManagedProperties([record], value => { value._lmeLocked = event.target.checked; }));
|
tools.querySelector("[data-field='locked']").addEventListener("change", event => updateManagedProperties([record], value => { value._lmeLocked = event.target.checked; }));
|
||||||
tools.querySelector("[data-field='label']").addEventListener("change", event => updateManagedProperties([record], value => { value._lmeLabelVisible = event.target.checked; }));
|
tools.querySelector("[data-field='label']").addEventListener("change", event => updateManagedProperties([record], value => { value._lmeLabelVisible = event.target.checked; }));
|
||||||
const applyCurrentStyle = () => applyManagedStyle([record], {
|
const applyCurrentStyle = () => applyManagedStyle([record], {
|
||||||
color: tools.querySelector("[data-color-picker='color']").value,
|
color: tools.querySelector("[data-color-picker='color']").value,
|
||||||
fillColor: tools.querySelector("[data-color-picker='fillColor']").value,
|
fillColor: tools.querySelector("[data-color-picker='fillColor']").value,
|
||||||
|
selectionColor: tools.querySelector("[data-color-picker='selectionColor']").value,
|
||||||
weight: Number(tools.querySelector("[data-field='weight']").value),
|
weight: Number(tools.querySelector("[data-field='weight']").value),
|
||||||
opacity: Number(tools.querySelector("[data-field='opacity']").value),
|
opacity: Number(tools.querySelector("[data-field='opacity']").value),
|
||||||
fillOpacity: Number(tools.querySelector("[data-field='fillOpacity']").value),
|
fillOpacity: Number(tools.querySelector("[data-field='fillOpacity']").value),
|
||||||
@@ -3005,24 +3048,35 @@ function showObjectTable() {
|
|||||||
const details = managedObjectDetails(record.layer);
|
const details = managedObjectDetails(record.layer);
|
||||||
const selected = lmeState.managerSelectedObjectIds.has(record.id);
|
const selected = lmeState.managerSelectedObjectIds.has(record.id);
|
||||||
const locked = Boolean(properties._lmeLocked);
|
const locked = Boolean(properties._lmeLocked);
|
||||||
return `<tr data-object-id="${escapeHtml(record.id)}"><td><input type="checkbox" data-select="${escapeHtml(record.id)}" ${selected ? "checked" : ""} aria-label="Seleziona ${escapeHtml(managedObjectLabel(record, index))}"></td><td><input type="checkbox" data-lock="${escapeHtml(record.id)}" ${locked ? "checked" : ""} ${lmeState.readOnly ? "disabled" : ""} aria-label="Blocca ${escapeHtml(managedObjectLabel(record, index))}"></td><td><button type="button" data-locate="${escapeHtml(record.id)}" title="Mostra sulla mappa" aria-label="Mostra sulla mappa">⌖</button></td><td><button type="button" data-attributes="${escapeHtml(record.id)}" title="Modifica metadati" aria-label="Modifica metadati di ${escapeHtml(managedObjectLabel(record, index))}" ${lmeState.readOnly ? "disabled" : ""}>✎</button></td><td><button type="button" class="object-notes-button" data-notes="${escapeHtml(record.id)}" title="Visualizza note">Note (${managedNotes(properties).length})</button></td><td>${escapeHtml(managedObjectLabel(record, index))}</td><td>${escapeHtml(managedCategoryName(layerManagerCategories().find(item => item.key === record.categoryKey) || { key: record.categoryKey, label: record.categoryKey }, [record]))}</td><td>${escapeHtml(properties.foglio || properties.FOGLIO || "")}</td><td>${escapeHtml(properties.particella || properties.PARTICELLA || properties.LABEL || "")}</td><td>${escapeHtml(details.slice(0, 2).join(" | "))}</td></tr>`;
|
return `<tr class="${selected ? "object-table-selected" : ""}" data-object-id="${escapeHtml(record.id)}"><td><input type="checkbox" data-select="${escapeHtml(record.id)}" ${selected ? "checked" : ""} ${lmeState.selectionMode === "off" ? "disabled" : ""} aria-label="Seleziona ${escapeHtml(managedObjectLabel(record, index))}"></td><td><input type="checkbox" data-lock="${escapeHtml(record.id)}" ${locked ? "checked" : ""} ${lmeState.readOnly ? "disabled" : ""} aria-label="Blocca ${escapeHtml(managedObjectLabel(record, index))}"></td><td><button type="button" data-locate="${escapeHtml(record.id)}" title="Mostra sulla mappa" aria-label="Mostra sulla mappa">⌖</button></td><td><button type="button" data-attributes="${escapeHtml(record.id)}" title="Modifica metadati" aria-label="Modifica metadati di ${escapeHtml(managedObjectLabel(record, index))}" ${lmeState.readOnly ? "disabled" : ""}>✎</button></td><td><button type="button" class="object-notes-button" data-notes="${escapeHtml(record.id)}" title="Visualizza note">Note (${managedNotes(properties).length})</button></td><td>${escapeHtml(managedObjectLabel(record, index))}</td><td>${escapeHtml(managedCategoryName(layerManagerCategories().find(item => item.key === record.categoryKey) || { key: record.categoryKey, label: record.categoryKey }, [record]))}</td><td>${escapeHtml(properties.foglio || properties.FOGLIO || "")}</td><td>${escapeHtml(properties.particella || properties.PARTICELLA || properties.LABEL || "")}</td><td>${escapeHtml(details.slice(0, 2).join(" | "))}</td></tr>`;
|
||||||
}).join("");
|
}).join("");
|
||||||
const dialog = showAppDialog("Elenco oggetti e particelle", `<label class="object-table-search">Filtra<input type="search" placeholder="Nome, foglio, particella o gruppo"></label><div class="object-table-legend"><span>Seleziona più oggetti con i flag nella colonna Selez.</span><span>Il lucchetto impedisce modifiche e rimozioni; la matita modifica i metadati.</span><span>Note apre l'elenco completo; le modifiche richiedono LME Pro.</span></div><div class="object-table-wrap"><table><thead><tr><th>Selez.</th><th>Blocca</th><th>Mappa</th><th>Metadati</th><th>Note</th><th>Nome</th><th>Gruppo</th><th>Foglio</th><th>Particella</th><th>Misure</th></tr></thead><tbody>${body || "<tr><td colspan='10'>Nessun oggetto</td></tr>"}</tbody></table></div>`);
|
const dialog = showAppDialog("Elenco oggetti e particelle", `<label class="object-table-search">Filtra<input type="search" placeholder="Nome, foglio, particella o gruppo"></label><div class="object-table-legend"><span>Modalita: <strong>${escapeHtml(selectionModeLabel())}</strong>. La selezione e condivisa con mappa e pannello Layer.</span><button type="button" data-table-clear title="Toglie la selezione senza eliminare oggetti">Cancella selezione</button><span>Il lucchetto impedisce modifiche e rimozioni; la matita modifica i metadati.</span><span>Note apre l'elenco completo; le modifiche richiedono LME Pro.</span></div><div class="object-table-wrap"><table><thead><tr><th>Selez.</th><th>Blocca</th><th>Mappa</th><th>Metadati</th><th>Note</th><th>Nome</th><th>Gruppo</th><th>Foglio</th><th>Particella</th><th>Misure</th></tr></thead><tbody>${body || "<tr><td colspan='10'>Nessun oggetto</td></tr>"}</tbody></table></div>`);
|
||||||
const byId = new Map(records.map(record => [record.id, record]));
|
const byId = new Map(records.map(record => [record.id, record]));
|
||||||
dialog.querySelector("input[type='search']").addEventListener("input", event => {
|
dialog.querySelector("input[type='search']").addEventListener("input", event => {
|
||||||
const query = event.target.value.toLocaleLowerCase("it");
|
const query = event.target.value.toLocaleLowerCase("it");
|
||||||
dialog.querySelectorAll("tbody tr").forEach(row => { row.hidden = query && !row.textContent.toLocaleLowerCase("it").includes(query); });
|
dialog.querySelectorAll("tbody tr").forEach(row => { row.hidden = query && !row.textContent.toLocaleLowerCase("it").includes(query); });
|
||||||
});
|
});
|
||||||
|
dialog.querySelector("[data-table-clear]").addEventListener("click", () => {
|
||||||
|
clearManagedSelection();
|
||||||
|
dialog.querySelectorAll("[data-select]").forEach(candidate => {
|
||||||
|
candidate.checked = false;
|
||||||
|
candidate.closest("tr")?.classList.remove("object-table-selected");
|
||||||
|
});
|
||||||
|
});
|
||||||
dialog.querySelectorAll("[data-select]").forEach(input => input.addEventListener("change", () => {
|
dialog.querySelectorAll("[data-select]").forEach(input => input.addEventListener("change", () => {
|
||||||
if (input.checked) lmeState.managerSelectedObjectIds.add(input.dataset.select);
|
|
||||||
else lmeState.managerSelectedObjectIds.delete(input.dataset.select);
|
|
||||||
const record = byId.get(input.dataset.select);
|
const record = byId.get(input.dataset.select);
|
||||||
if (record && input.checked) {
|
if (!record) return;
|
||||||
lmeState.managerHighlightedObjectId = record.id;
|
if (input.checked) {
|
||||||
lmeState.managerHighlightedCategoryKey = record.categoryKey;
|
selectManagedRecord(record);
|
||||||
renderManagerHighlight([record]);
|
} else {
|
||||||
|
lmeState.managerSelectedObjectIds.delete(record.id);
|
||||||
|
refreshLayerManager();
|
||||||
|
refreshMultipleMapSelection();
|
||||||
}
|
}
|
||||||
refreshLayerManager();
|
dialog.querySelectorAll("[data-select]").forEach(candidate => {
|
||||||
|
candidate.checked = lmeState.managerSelectedObjectIds.has(candidate.dataset.select);
|
||||||
|
candidate.closest("tr")?.classList.toggle("object-table-selected", candidate.checked);
|
||||||
|
});
|
||||||
setInfo(`${lmeState.managerSelectedObjectIds.size} oggetti selezionati.`);
|
setInfo(`${lmeState.managerSelectedObjectIds.size} oggetti selezionati.`);
|
||||||
}));
|
}));
|
||||||
dialog.querySelectorAll("[data-lock]").forEach(input => input.addEventListener("change", () => {
|
dialog.querySelectorAll("[data-lock]").forEach(input => input.addEventListener("change", () => {
|
||||||
@@ -3033,7 +3087,9 @@ function showObjectTable() {
|
|||||||
}));
|
}));
|
||||||
dialog.querySelectorAll("[data-locate]").forEach(button => button.addEventListener("click", () => {
|
dialog.querySelectorAll("[data-locate]").forEach(button => button.addEventListener("click", () => {
|
||||||
const record = byId.get(button.dataset.locate); if (!record) return;
|
const record = byId.get(button.dataset.locate); if (!record) return;
|
||||||
dialog.remove(); highlightManagedObject(record);
|
dialog.remove();
|
||||||
|
if (lmeState.selectionMode !== "off") selectManagedRecord(record);
|
||||||
|
fitLayer(record.layer);
|
||||||
}));
|
}));
|
||||||
dialog.querySelectorAll("[data-attributes]").forEach(button => button.addEventListener("click", () => {
|
dialog.querySelectorAll("[data-attributes]").forEach(button => button.addEventListener("click", () => {
|
||||||
const record = byId.get(button.dataset.attributes); if (!record) return;
|
const record = byId.get(button.dataset.attributes); if (!record) return;
|
||||||
@@ -3054,6 +3110,7 @@ function showAuditLog() {
|
|||||||
|
|
||||||
function updateManagedProperties(records, change) {
|
function updateManagedProperties(records, change) {
|
||||||
if (lmeState.readOnly) { setInfo("Il progetto e' in sola lettura."); return; }
|
if (lmeState.readOnly) { setInfo("Il progetto e' in sola lettura."); return; }
|
||||||
|
restoreDirectManagerHighlights();
|
||||||
rememberMapChange();
|
rememberMapChange();
|
||||||
records.forEach(record => {
|
records.forEach(record => {
|
||||||
record.layer.feature ||= { type: "Feature", properties: {} };
|
record.layer.feature ||= { type: "Feature", properties: {} };
|
||||||
@@ -3073,6 +3130,7 @@ function applyManagedStyle(records, style) {
|
|||||||
properties._lmeFillColor = style.fillColor || style.color;
|
properties._lmeFillColor = style.fillColor || style.color;
|
||||||
properties._lmeWeight = style.weight;
|
properties._lmeWeight = style.weight;
|
||||||
properties._lmeOpacity = style.opacity;
|
properties._lmeOpacity = style.opacity;
|
||||||
|
if (style.selectionColor !== undefined) properties._lmeSelectionColor = style.selectionColor;
|
||||||
if (style.fillOpacity !== undefined) properties._lmeFillOpacity = style.fillOpacity;
|
if (style.fillOpacity !== undefined) properties._lmeFillOpacity = style.fillOpacity;
|
||||||
if (style.dash !== undefined) properties._lmeDash = style.dash;
|
if (style.dash !== undefined) properties._lmeDash = style.dash;
|
||||||
});
|
});
|
||||||
@@ -3081,6 +3139,7 @@ function applyManagedStyle(records, style) {
|
|||||||
function applyStyleFromProperties(layer) {
|
function applyStyleFromProperties(layer) {
|
||||||
const properties = layer?.feature?.properties || {};
|
const properties = layer?.feature?.properties || {};
|
||||||
if (typeof layer?.setStyle === "function") {
|
if (typeof layer?.setStyle === "function") {
|
||||||
|
lmeState.managerDirectHighlightStyles.delete(layer);
|
||||||
layer.setStyle({
|
layer.setStyle({
|
||||||
color: properties._lmeColor || layer.options.color,
|
color: properties._lmeColor || layer.options.color,
|
||||||
fillColor: properties._lmeFillColor || layer.options.fillColor,
|
fillColor: properties._lmeFillColor || layer.options.fillColor,
|
||||||
@@ -3419,18 +3478,8 @@ function hideComparisonMenu() {
|
|||||||
lmeState.comparisonMenu = null;
|
lmeState.comparisonMenu = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function toggleMultiSelection() {
|
function selectionHasObjects() {
|
||||||
lmeState.multiSelectionEnabled = !lmeState.multiSelectionEnabled;
|
return lmeState.managerSelectedObjectIds.size > 0;
|
||||||
lmeState.multiSelectionButton?.classList.toggle("is-active", lmeState.multiSelectionEnabled);
|
|
||||||
lmeState.multiSelectionButton?.setAttribute("aria-pressed", String(lmeState.multiSelectionEnabled));
|
|
||||||
setInfo(lmeState.multiSelectionEnabled
|
|
||||||
? "Selezione multipla attiva: tocca gli oggetti per aggiungerli o rimuoverli dalla selezione."
|
|
||||||
: "Selezione multipla disattivata.");
|
|
||||||
return lmeState.multiSelectionEnabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
function multiSelectionHasObjects() {
|
|
||||||
return lmeState.multiSelectionEnabled && lmeState.managerSelectedObjectIds.size > 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function refreshMultipleMapSelection(preferredRecord) {
|
function refreshMultipleMapSelection(preferredRecord) {
|
||||||
@@ -3440,9 +3489,119 @@ function refreshMultipleMapSelection(preferredRecord) {
|
|||||||
const current = selectedRecords.find(record => record.id === preferredRecord?.id) || selectedRecords.at(-1);
|
const current = selectedRecords.find(record => record.id === preferredRecord?.id) || selectedRecords.at(-1);
|
||||||
lmeState.managerHighlightedObjectId = current?.id || null;
|
lmeState.managerHighlightedObjectId = current?.id || null;
|
||||||
lmeState.managerHighlightedCategoryKey = current?.categoryKey || null;
|
lmeState.managerHighlightedCategoryKey = current?.categoryKey || null;
|
||||||
|
setSelectedDrawing(selectedRecords.length === 1 && current?.categoryKey === "drawings" ? current.layer : null);
|
||||||
renderManagerHighlight(selectedRecords);
|
renderManagerHighlight(selectedRecords);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function selectionModeLabel(mode = lmeState.selectionMode) {
|
||||||
|
return mode === "multiple" ? "Multipla" : mode === "off" ? "Disattivata" : "Singola";
|
||||||
|
}
|
||||||
|
|
||||||
|
function selectionModeIcon(mode = lmeState.selectionMode) {
|
||||||
|
return mode === "multiple" ? "☑" : mode === "off" ? "×" : "✓";
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateSelectionModeButton() {
|
||||||
|
const button = lmeState.selectionModeButton;
|
||||||
|
if (!button) return;
|
||||||
|
const label = `Selezione: ${selectionModeLabel()}`;
|
||||||
|
button.textContent = selectionModeIcon();
|
||||||
|
button.title = `${label}. Apri le opzioni`;
|
||||||
|
button.setAttribute("aria-label", button.title);
|
||||||
|
button.setAttribute("aria-pressed", String(lmeState.selectionMode !== "off"));
|
||||||
|
button.classList.toggle("is-active", lmeState.selectionMode !== "off");
|
||||||
|
button.classList.toggle("is-multiple", lmeState.selectionMode === "multiple");
|
||||||
|
}
|
||||||
|
|
||||||
|
function setSelectionMode(mode) {
|
||||||
|
const normalized = ["single", "multiple", "off"].includes(mode) ? mode : "single";
|
||||||
|
lmeState.selectionMode = normalized;
|
||||||
|
if (normalized === "off") {
|
||||||
|
lmeState.managerSelectedObjectIds.clear();
|
||||||
|
clearManagerHighlight();
|
||||||
|
} else if (normalized === "single" && lmeState.managerSelectedObjectIds.size > 1) {
|
||||||
|
const selectedIds = [...lmeState.managerSelectedObjectIds];
|
||||||
|
const retained = lmeState.managerSelectedObjectIds.has(lmeState.managerHighlightedObjectId)
|
||||||
|
? lmeState.managerHighlightedObjectId
|
||||||
|
: selectedIds.at(-1);
|
||||||
|
lmeState.managerSelectedObjectIds.clear();
|
||||||
|
if (retained) lmeState.managerSelectedObjectIds.add(retained);
|
||||||
|
}
|
||||||
|
updateSelectionModeButton();
|
||||||
|
refreshLayerManager();
|
||||||
|
renderSelectedManagerHighlight();
|
||||||
|
setInfo(normalized === "single"
|
||||||
|
? "Selezione singola attiva: tocca un oggetto per sostituire la selezione corrente."
|
||||||
|
: normalized === "multiple"
|
||||||
|
? "Selezione multipla attiva: tocca gli oggetti per aggiungerli o rimuoverli."
|
||||||
|
: "Selezione disattivata e selezione corrente cancellata. Nessun oggetto e' stato rimosso.");
|
||||||
|
return normalized;
|
||||||
|
}
|
||||||
|
|
||||||
|
function clearManagedSelection(announce = true) {
|
||||||
|
lmeState.managerSelectedObjectIds.clear();
|
||||||
|
clearManagerHighlight();
|
||||||
|
refreshLayerManager();
|
||||||
|
if (announce) setInfo("Selezione cancellata. Nessun oggetto e' stato rimosso.");
|
||||||
|
}
|
||||||
|
|
||||||
|
function selectManagedRecord(record, event, announce = true) {
|
||||||
|
if (!record) return false;
|
||||||
|
if (lmeState.selectionMode === "off") {
|
||||||
|
if (announce) setInfo("Selezione disattivata. Attivala dal pulsante Selezione nella barra mappa.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const multiple = lmeState.selectionMode === "multiple"
|
||||||
|
|| event?.ctrlKey || event?.metaKey || event?.shiftKey;
|
||||||
|
if (multiple) {
|
||||||
|
if (lmeState.managerSelectedObjectIds.has(record.id)) lmeState.managerSelectedObjectIds.delete(record.id);
|
||||||
|
else lmeState.managerSelectedObjectIds.add(record.id);
|
||||||
|
} else {
|
||||||
|
lmeState.managerSelectedObjectIds.clear();
|
||||||
|
lmeState.managerSelectedObjectIds.add(record.id);
|
||||||
|
}
|
||||||
|
refreshLayerManager();
|
||||||
|
refreshMultipleMapSelection(record);
|
||||||
|
if (lmeState.managerSelectedObjectIds.has(record.id)) {
|
||||||
|
window.requestAnimationFrame(() => revealManagedRecordInLayerManager(record.id));
|
||||||
|
}
|
||||||
|
if (announce) setInfo(`${lmeState.managerSelectedObjectIds.size} oggetti selezionati (${selectionModeLabel().toLocaleLowerCase("it")}).`);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function showSelectionMenu(button) {
|
||||||
|
if (lmeState.selectionMenu) {
|
||||||
|
hideSelectionMenu();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const menu = L.DomUtil.create("div", "lme-selection-actions", button.parentElement);
|
||||||
|
menu.style.top = `${button.offsetTop}px`;
|
||||||
|
menu.innerHTML = `<a href="#" data-selection-mode="single">✓ Selezione singola</a>
|
||||||
|
<a href="#" data-selection-mode="multiple">☑ Selezione multipla</a>
|
||||||
|
<a href="#" data-selection-mode="off">× Selezione disattivata</a>
|
||||||
|
<a href="#" data-selection-clear="true">⌫ Cancella selezione</a>`;
|
||||||
|
lmeState.selectionMenu = menu;
|
||||||
|
menu.querySelectorAll("a").forEach(link => {
|
||||||
|
const active = link.dataset.selectionMode === lmeState.selectionMode;
|
||||||
|
link.classList.toggle("is-current", active);
|
||||||
|
link.setAttribute("aria-current", active ? "true" : "false");
|
||||||
|
L.DomEvent.on(link, "click", L.DomEvent.stop)
|
||||||
|
.on(link, "mousedown", L.DomEvent.stopPropagation)
|
||||||
|
.on(link, "touchstart", L.DomEvent.stopPropagation)
|
||||||
|
.on(link, "click", () => {
|
||||||
|
const mode = link.dataset.selectionMode;
|
||||||
|
hideSelectionMenu();
|
||||||
|
if (mode) setSelectionMode(mode);
|
||||||
|
else clearManagedSelection();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function hideSelectionMenu() {
|
||||||
|
lmeState.selectionMenu?.remove();
|
||||||
|
lmeState.selectionMenu = null;
|
||||||
|
}
|
||||||
|
|
||||||
function showGeometryResult(title, message, tone = "success") {
|
function showGeometryResult(title, message, tone = "success") {
|
||||||
setInfo(`${title}: ${message}`);
|
setInfo(`${title}: ${message}`);
|
||||||
const icons = { success: "✓", warning: "!", error: "×" };
|
const icons = { success: "✓", warning: "!", error: "×" };
|
||||||
@@ -3464,7 +3623,7 @@ function showLeafletToolbarHelp() {
|
|||||||
<div><dt>▱</dt><dd><strong>Elimina disegni</strong>Premi il cestino e scegli Solo selezionato oppure Tutti. L'oggetto rimosso può essere recuperato con Annulla o dal cestino negli strumenti avanzati.</dd></div>
|
<div><dt>▱</dt><dd><strong>Elimina disegni</strong>Premi il cestino e scegli Solo selezionato oppure Tutti. L'oggetto rimosso può essere recuperato con Annulla o dal cestino negli strumenti avanzati.</dd></div>
|
||||||
<div><dt>✓</dt><dd><strong>Controlla e ripara</strong>Verifica gli oggetti selezionati e prova a correggere coordinate duplicate o poligoni non validi. Esempio: usalo quando un contorno importato non si esporta o si riempie male; al termine compare un riepilogo.</dd></div>
|
<div><dt>✓</dt><dd><strong>Controlla e ripara</strong>Verifica gli oggetti selezionati e prova a correggere coordinate duplicate o poligoni non validi. Esempio: usalo quando un contorno importato non si esporta o si riempie male; al termine compare un riepilogo.</dd></div>
|
||||||
<div><dt>◉</dt><dd><strong>Crea foro</strong>Seleziona esattamente due poligoni: prima l'area esterna, poi quella interna. Esempio: sottrai il cortile dal perimetro di un fabbricato o un'isola esclusa da un'area di lavoro.</dd></div>
|
<div><dt>◉</dt><dd><strong>Crea foro</strong>Seleziona esattamente due poligoni: prima l'area esterna, poi quella interna. Esempio: sottrai il cortile dal perimetro di un fabbricato o un'isola esclusa da un'area di lavoro.</dd></div>
|
||||||
<div><dt>☑</dt><dd><strong>Selezione multipla</strong>Attiva il comando e tocca più oggetti sulla mappa per aggiungerli o rimuoverli dalla selezione. Gli oggetti restano evidenziati anche aprendo e chiudendo i pannelli. Disattivalo per tornare alla selezione singola.</dd></div>
|
<div><dt>✓</dt><dd><strong>Modalita di selezione</strong>Scegli Singola, Multipla o Disattivata. Mappa, pannello Layer e tabella oggetti condividono la stessa selezione. Disattivata e Cancella selezione deselezionano tutto senza eliminare alcun oggetto.</dd></div>
|
||||||
<div><dt>⇄</dt><dd><strong>Confronta due confini</strong>Apri il comando e scegli Confronta dopo aver selezionato esattamente due poligoni. Il gruppo Confronto confini viene collocato sopra gli altri layer: rosso indica solo il primo, blu solo il secondo e verde la sovrapposizione. Usa Pulisci confronto per rimuovere soltanto questi risultati.</dd></div>
|
<div><dt>⇄</dt><dd><strong>Confronta due confini</strong>Apri il comando e scegli Confronta dopo aver selezionato esattamente due poligoni. Il gruppo Confronto confini viene collocato sopra gli altri layer: rosso indica solo il primo, blu solo il secondo e verde la sovrapposizione. Usa Pulisci confronto per rimuovere soltanto questi risultati.</dd></div>
|
||||||
<div><dt>PF</dt><dd><strong>Scarica Punti Fiduciali</strong>Seleziona una particella o un foglio catastale; in alternativa usa la particella rilevata dal GPS. I PF vengono aggiunti come sottogruppo del relativo foglio e richiedono LME Pro.</dd></div>
|
<div><dt>PF</dt><dd><strong>Scarica Punti Fiduciali</strong>Seleziona una particella o un foglio catastale; in alternativa usa la particella rilevata dal GPS. I PF vengono aggiunti come sottogruppo del relativo foglio e richiedono LME Pro.</dd></div>
|
||||||
<div><dt>?</dt><dd><strong>Guida</strong>Riapre questa descrizione. I risultati di riparazione e confronto vengono mostrati anche in una finestra; per uscire dalla visualizzazione rosso, blu e verde usa Pulisci confronto.</dd></div>
|
<div><dt>?</dt><dd><strong>Guida</strong>Riapre questa descrizione. I risultati di riparazione e confronto vengono mostrati anche in una finestra; per uscire dalla visualizzazione rosso, blu e verde usa Pulisci confronto.</dd></div>
|
||||||
@@ -3481,7 +3640,7 @@ function addGeometryToolsControl() {
|
|||||||
const actions = [
|
const actions = [
|
||||||
{ icon: "✓", title: "Controlla e ripara geometrie", run: validateAndRepairSelected },
|
{ icon: "✓", title: "Controlla e ripara geometrie", run: validateAndRepairSelected },
|
||||||
{ icon: "◉", title: "Crea foro da due poligoni", run: createHoleFromSelected },
|
{ icon: "◉", title: "Crea foro da due poligoni", run: createHoleFromSelected },
|
||||||
{ icon: "☑", title: "Attiva o disattiva selezione multipla", run: toggleMultiSelection, multiSelection: true },
|
{ icon: selectionModeIcon(), title: "Modalita e comandi di selezione", selection: true },
|
||||||
{ icon: "⇄", title: "Confronta o pulisci confronto", comparison: true },
|
{ icon: "⇄", title: "Confronta o pulisci confronto", comparison: true },
|
||||||
{ icon: "PF", title: "Scarica PF del foglio o della particella", run: downloadFiducialsForMapContext, fiducials: true },
|
{ icon: "PF", title: "Scarica PF del foglio o della particella", run: downloadFiducialsForMapContext, fiducials: true },
|
||||||
{ icon: "?", title: "Guida strumenti mappa", run: showLeafletToolbarHelp }
|
{ icon: "?", title: "Guida strumenti mappa", run: showLeafletToolbarHelp }
|
||||||
@@ -3498,14 +3657,15 @@ function addGeometryToolsControl() {
|
|||||||
lmeState.fiducialDownloadButton = button;
|
lmeState.fiducialDownloadButton = button;
|
||||||
}
|
}
|
||||||
if (action.comparison) button.classList.add("lme-comparison-button");
|
if (action.comparison) button.classList.add("lme-comparison-button");
|
||||||
if (action.multiSelection) {
|
if (action.selection) {
|
||||||
button.classList.add("lme-multi-selection-button");
|
button.classList.add("lme-selection-mode-button");
|
||||||
button.setAttribute("aria-pressed", String(lmeState.multiSelectionEnabled));
|
lmeState.selectionModeButton = button;
|
||||||
lmeState.multiSelectionButton = button;
|
updateSelectionModeButton();
|
||||||
}
|
}
|
||||||
L.DomEvent.on(button, "click", event => {
|
L.DomEvent.on(button, "click", event => {
|
||||||
L.DomEvent.stop(event);
|
L.DomEvent.stop(event);
|
||||||
if (action.comparison) showComparisonMenu(button);
|
if (action.comparison) showComparisonMenu(button);
|
||||||
|
else if (action.selection) showSelectionMenu(button);
|
||||||
else action.run();
|
else action.run();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -4000,22 +4160,10 @@ function managedCategoryEnabled(categoryKey) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function highlightManagedObject(record) {
|
function highlightManagedObject(record) {
|
||||||
if (lmeState.managerHighlightedObjectId === record.id) {
|
if (!selectManagedRecord(record)) return;
|
||||||
clearManagerHighlight();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
clearManagerHighlight();
|
|
||||||
lmeState.managerHighlightedObjectId = record.id;
|
|
||||||
lmeState.managerHighlightedCategoryKey = record.categoryKey;
|
|
||||||
document.querySelectorAll(".layer-manager-object").forEach(row => {
|
|
||||||
row.classList.toggle("layer-manager-object-selected", row.dataset.objectId === record.id);
|
|
||||||
});
|
|
||||||
setSelectedDrawing(record.categoryKey === "drawings" ? record.layer : null);
|
|
||||||
renderManagerHighlight([record]);
|
|
||||||
if (lmeState.autoFitSelectedObject) {
|
if (lmeState.autoFitSelectedObject) {
|
||||||
fitLayer(record.layer);
|
fitLayer(record.layer);
|
||||||
}
|
}
|
||||||
revealManagedRecordInLayerManager(record.id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function revealManagedRecordInLayerManager(recordId) {
|
function revealManagedRecordInLayerManager(recordId) {
|
||||||
@@ -4060,7 +4208,7 @@ function setSelectedDrawing(layer) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function selectDrawingLayer(layer) {
|
function selectDrawingLayer(layer) {
|
||||||
if (drawingEditActive()) {
|
if (drawingEditActive() || lmeState.selectionMode === "off") {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const record = {
|
const record = {
|
||||||
@@ -4070,14 +4218,10 @@ function selectDrawingLayer(layer) {
|
|||||||
parent: lmeState.drawings,
|
parent: lmeState.drawings,
|
||||||
source: String(layer?.feature?.properties?._lmeSource || "Progetto corrente")
|
source: String(layer?.feature?.properties?._lmeSource || "Progetto corrente")
|
||||||
};
|
};
|
||||||
clearManagerHighlight();
|
lmeState.managerSelectedObjectIds.clear();
|
||||||
lmeState.managerHighlightedObjectId = record.id;
|
lmeState.managerSelectedObjectIds.add(record.id);
|
||||||
lmeState.managerHighlightedCategoryKey = "drawings";
|
refreshLayerManager();
|
||||||
document.querySelectorAll(".layer-manager-object").forEach(row => {
|
refreshMultipleMapSelection(record);
|
||||||
row.classList.toggle("layer-manager-object-selected", row.dataset.objectId === record.id);
|
|
||||||
});
|
|
||||||
setSelectedDrawing(layer);
|
|
||||||
renderManagerHighlight([record]);
|
|
||||||
setInfo(`Selezione: ${managedObjectLabel(record, 0)}. Usa la matita per modificare o il cestino per eliminare.`);
|
setInfo(`Selezione: ${managedObjectLabel(record, 0)}. Usa la matita per modificare o il cestino per eliminare.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4111,6 +4255,10 @@ function bindManagedParentHighlight(row, key, records) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function highlightManagedParent(row, key, records) {
|
function highlightManagedParent(row, key, records) {
|
||||||
|
if (lmeState.selectionMode === "off") {
|
||||||
|
setInfo("Selezione disattivata. Scegli Singola o Multipla dalla barra mappa.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (lmeState.managerHighlightedParentKey === key) {
|
if (lmeState.managerHighlightedParentKey === key) {
|
||||||
clearManagerHighlight();
|
clearManagerHighlight();
|
||||||
return;
|
return;
|
||||||
@@ -4125,7 +4273,7 @@ function highlightManagedParent(row, key, records) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function renderSelectedManagerHighlight() {
|
function renderSelectedManagerHighlight() {
|
||||||
if (multiSelectionHasObjects()) {
|
if (selectionHasObjects()) {
|
||||||
const selected = [...lmeState.managerSelectedObjectIds]
|
const selected = [...lmeState.managerSelectedObjectIds]
|
||||||
.map(id => lmeState.managerRecords.get(id))
|
.map(id => lmeState.managerRecords.get(id))
|
||||||
.filter(Boolean);
|
.filter(Boolean);
|
||||||
@@ -4143,13 +4291,18 @@ function renderSelectedManagerHighlight() {
|
|||||||
function renderManagerHighlight(records) {
|
function renderManagerHighlight(records) {
|
||||||
restoreDirectManagerHighlights();
|
restoreDirectManagerHighlights();
|
||||||
lmeState.managerHighlight?.clearLayers();
|
lmeState.managerHighlight?.clearLayers();
|
||||||
records.forEach(record => applyDirectManagerHighlight(record.layer));
|
records.forEach(record => applyDirectManagerHighlight(record));
|
||||||
const features = records.flatMap(record => {
|
const features = records.flatMap(record => {
|
||||||
const geojson = record.layer?.toGeoJSON?.();
|
const geojson = record.layer?.toGeoJSON?.();
|
||||||
if (!geojson) {
|
if (!geojson) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
return geojson.type === "FeatureCollection" ? geojson.features : [geojson];
|
const selectionColor = managedSelectionColor(record.layer);
|
||||||
|
const items = geojson.type === "FeatureCollection" ? geojson.features : [geojson];
|
||||||
|
return items.map(feature => ({
|
||||||
|
...feature,
|
||||||
|
properties: { ...(feature.properties || {}), _lmeSelectionColorResolved: selectionColor }
|
||||||
|
}));
|
||||||
});
|
});
|
||||||
if (!features.length) {
|
if (!features.length) {
|
||||||
return;
|
return;
|
||||||
@@ -4157,22 +4310,34 @@ function renderManagerHighlight(records) {
|
|||||||
L.geoJSON({ type: "FeatureCollection", features }, {
|
L.geoJSON({ type: "FeatureCollection", features }, {
|
||||||
pane: "managerHighlightPane",
|
pane: "managerHighlightPane",
|
||||||
interactive: false,
|
interactive: false,
|
||||||
style: { color: "#ff00d4", weight: 8, opacity: 1, fillColor: "#00fff0", fillOpacity: 0.16 },
|
style: feature => ({
|
||||||
|
color: managedSelectionColor(null, feature?.properties?._lmeSelectionColorResolved),
|
||||||
|
weight: 8,
|
||||||
|
opacity: 1,
|
||||||
|
fillColor: managedSelectionColor(null, feature?.properties?._lmeSelectionColorResolved),
|
||||||
|
fillOpacity: 0.22
|
||||||
|
}),
|
||||||
pointToLayer: (feature, latlng) => L.circleMarker(latlng, {
|
pointToLayer: (feature, latlng) => L.circleMarker(latlng, {
|
||||||
pane: "managerHighlightPane",
|
pane: "managerHighlightPane",
|
||||||
radius: 12,
|
radius: 12,
|
||||||
color: "#ff00d4",
|
color: managedSelectionColor(null, feature?.properties?._lmeSelectionColorResolved),
|
||||||
weight: 5,
|
weight: 5,
|
||||||
fillColor: "#00fff0",
|
fillColor: managedSelectionColor(null, feature?.properties?._lmeSelectionColorResolved),
|
||||||
fillOpacity: 0.9,
|
fillOpacity: 0.9,
|
||||||
interactive: false
|
interactive: false
|
||||||
})
|
})
|
||||||
}).addTo(lmeState.managerHighlight);
|
}).addTo(lmeState.managerHighlight);
|
||||||
}
|
}
|
||||||
|
|
||||||
function applyDirectManagerHighlight(layer) {
|
function managedSelectionColor(layer, explicitColor) {
|
||||||
|
return normalizedColor(explicitColor || layer?.feature?.properties?._lmeSelectionColor, "#d500f9");
|
||||||
|
}
|
||||||
|
|
||||||
|
function applyDirectManagerHighlight(record) {
|
||||||
|
const layer = record?.layer;
|
||||||
if (!layer || typeof layer.setStyle !== "function" || lmeState.managerDirectHighlightStyles.has(layer)) return;
|
if (!layer || typeof layer.setStyle !== "function" || lmeState.managerDirectHighlightStyles.has(layer)) return;
|
||||||
const options = layer.options || {};
|
const options = layer.options || {};
|
||||||
|
const selectionColor = managedSelectionColor(layer);
|
||||||
lmeState.managerDirectHighlightStyles.set(layer, {
|
lmeState.managerDirectHighlightStyles.set(layer, {
|
||||||
color: options.color,
|
color: options.color,
|
||||||
weight: options.weight,
|
weight: options.weight,
|
||||||
@@ -4182,10 +4347,10 @@ function applyDirectManagerHighlight(layer) {
|
|||||||
dashArray: options.dashArray ?? null
|
dashArray: options.dashArray ?? null
|
||||||
});
|
});
|
||||||
layer.setStyle({
|
layer.setStyle({
|
||||||
color: "#ff00d4",
|
color: selectionColor,
|
||||||
weight: Math.max(7, (Number(options.weight) || 2) + 4),
|
weight: Math.max(7, (Number(options.weight) || 2) + 4),
|
||||||
opacity: 1,
|
opacity: 1,
|
||||||
fillColor: "#00fff0",
|
fillColor: selectionColor,
|
||||||
fillOpacity: 0.34,
|
fillOpacity: 0.34,
|
||||||
dashArray: null
|
dashArray: null
|
||||||
});
|
});
|
||||||
@@ -4933,7 +5098,7 @@ function bindDrawingLayerSelection(layer) {
|
|||||||
}
|
}
|
||||||
layer.lmeDrawingSelectionBound = true;
|
layer.lmeDrawingSelectionBound = true;
|
||||||
layer.on("click", event => {
|
layer.on("click", event => {
|
||||||
if (drawingEditActive()) {
|
if (drawingEditActive() || lmeState.selectionMode === "off") {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
lmeState.ignoreMapClickUntil = Date.now() + 1000;
|
lmeState.ignoreMapClickUntil = Date.now() + 1000;
|
||||||
@@ -4941,28 +5106,14 @@ function bindDrawingLayerSelection(layer) {
|
|||||||
event.originalEvent._lmeDrawingSelected = true;
|
event.originalEvent._lmeDrawingSelected = true;
|
||||||
L.DomEvent.stopPropagation(event.originalEvent);
|
L.DomEvent.stopPropagation(event.originalEvent);
|
||||||
}
|
}
|
||||||
const id = managedLayerId(layer, "drawings");
|
const record = {
|
||||||
const multiple = lmeState.multiSelectionEnabled
|
id: managedLayerId(layer, "drawings"),
|
||||||
|| event.originalEvent?.ctrlKey
|
categoryKey: "drawings",
|
||||||
|| event.originalEvent?.metaKey
|
layer,
|
||||||
|| event.originalEvent?.shiftKey;
|
parent: lmeState.drawings,
|
||||||
if (multiple) {
|
source: String(layer?.feature?.properties?._lmeSource || "Progetto corrente")
|
||||||
if (lmeState.managerSelectedObjectIds.has(id)) lmeState.managerSelectedObjectIds.delete(id);
|
};
|
||||||
else lmeState.managerSelectedObjectIds.add(id);
|
selectManagedRecord(record, event.originalEvent);
|
||||||
} else {
|
|
||||||
lmeState.managerSelectedObjectIds.clear();
|
|
||||||
lmeState.managerSelectedObjectIds.add(id);
|
|
||||||
}
|
|
||||||
refreshLayerManager();
|
|
||||||
if (multiple) {
|
|
||||||
refreshMultipleMapSelection({ id, categoryKey: "drawings", layer, parent: lmeState.drawings });
|
|
||||||
setInfo(`${lmeState.managerSelectedObjectIds.size} oggetti selezionati.`);
|
|
||||||
} else {
|
|
||||||
selectDrawingLayer(layer);
|
|
||||||
}
|
|
||||||
if (lmeState.managerSelectedObjectIds.has(id)) {
|
|
||||||
window.requestAnimationFrame(() => revealManagedRecordInLayerManager(id));
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4970,31 +5121,14 @@ function bindManagedMapSelection(layer, categoryKey, parent) {
|
|||||||
if (layer.lmeManagedMapSelectionBound) return;
|
if (layer.lmeManagedMapSelectionBound) return;
|
||||||
layer.lmeManagedMapSelectionBound = true;
|
layer.lmeManagedMapSelectionBound = true;
|
||||||
layer.on("click", event => {
|
layer.on("click", event => {
|
||||||
if (Date.now() < lmeState.ignoreMapClickUntil) return;
|
if (Date.now() < lmeState.ignoreMapClickUntil || lmeState.selectionMode === "off") return;
|
||||||
lmeState.ignoreMapClickUntil = Date.now() + 600;
|
lmeState.ignoreMapClickUntil = Date.now() + 600;
|
||||||
if (event.originalEvent) {
|
if (event.originalEvent) {
|
||||||
event.originalEvent._lmeDrawingSelected = true;
|
event.originalEvent._lmeDrawingSelected = true;
|
||||||
L.DomEvent.stopPropagation(event.originalEvent);
|
L.DomEvent.stopPropagation(event.originalEvent);
|
||||||
}
|
}
|
||||||
const record = { id: managedLayerId(layer, categoryKey), categoryKey, layer, parent, source: String(layer?.feature?.properties?._lmeSource || "Progetto corrente") };
|
const record = { id: managedLayerId(layer, categoryKey), categoryKey, layer, parent, source: String(layer?.feature?.properties?._lmeSource || "Progetto corrente") };
|
||||||
const multiple = lmeState.multiSelectionEnabled
|
selectManagedRecord(record, event.originalEvent);
|
||||||
|| event.originalEvent?.ctrlKey
|
|
||||||
|| event.originalEvent?.metaKey
|
|
||||||
|| event.originalEvent?.shiftKey;
|
|
||||||
if (!multiple) lmeState.managerSelectedObjectIds.clear();
|
|
||||||
if (multiple && lmeState.managerSelectedObjectIds.has(record.id)) lmeState.managerSelectedObjectIds.delete(record.id);
|
|
||||||
else lmeState.managerSelectedObjectIds.add(record.id);
|
|
||||||
refreshLayerManager();
|
|
||||||
if (multiple) {
|
|
||||||
refreshMultipleMapSelection(record);
|
|
||||||
setInfo(`${lmeState.managerSelectedObjectIds.size} oggetti selezionati.`);
|
|
||||||
} else {
|
|
||||||
highlightManagedObject(record);
|
|
||||||
setInfo(`Selezionato dalla mappa: ${managedObjectEditableName(record) || "oggetto"}.`);
|
|
||||||
}
|
|
||||||
if (lmeState.managerSelectedObjectIds.has(record.id)) {
|
|
||||||
window.requestAnimationFrame(() => revealManagedRecordInLayerManager(record.id));
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5523,7 +5657,7 @@ function loadProjectSnapshot(raw, projectName) {
|
|||||||
? Boolean(projectDisplayOptions.importedSheetsVisible)
|
? Boolean(projectDisplayOptions.importedSheetsVisible)
|
||||||
: data.schemaVersion >= 2 && Boolean(data.importedSheetsVisible);
|
: data.schemaVersion >= 2 && Boolean(data.importedSheetsVisible);
|
||||||
applyImportedSheetVisibility();
|
applyImportedSheetVisibility();
|
||||||
L.geoJSON(data.selectedParcels || emptyFeatureCollection(), {
|
const restoredParcels = L.geoJSON(data.selectedParcels || emptyFeatureCollection(), {
|
||||||
pane: "selectedParcelsPane",
|
pane: "selectedParcelsPane",
|
||||||
style: feature => ({
|
style: feature => ({
|
||||||
color: feature?.properties?._lmeColor || "#ef4444",
|
color: feature?.properties?._lmeColor || "#ef4444",
|
||||||
@@ -5544,6 +5678,15 @@ function loadProjectSnapshot(raw, projectName) {
|
|||||||
applyStyleFromProperties(layer);
|
applyStyleFromProperties(layer);
|
||||||
}
|
}
|
||||||
}).addTo(lmeState.selectedParcelsLayer);
|
}).addTo(lmeState.selectedParcelsLayer);
|
||||||
|
restoredParcels.eachLayer(layer => {
|
||||||
|
const properties = layer?.feature?.properties || {};
|
||||||
|
const reference = properties.NATIONALCADASTRALREFERENCE
|
||||||
|
|| properties.INSPIREID_LOCALID
|
||||||
|
|| properties.LABEL
|
||||||
|
|| "Particella catastale";
|
||||||
|
layer.lmeParcelReference = reference;
|
||||||
|
bindManagedMapSelection(layer, "selectedParcels", restoredParcels);
|
||||||
|
});
|
||||||
const restoredFiducials = L.geoJSON(data.fiducials || emptyFeatureCollection(), {
|
const restoredFiducials = L.geoJSON(data.fiducials || emptyFeatureCollection(), {
|
||||||
pointToLayer: (feature, latlng) => createFiducialMarker(feature, latlng),
|
pointToLayer: (feature, latlng) => createFiducialMarker(feature, latlng),
|
||||||
onEachFeature: (feature, layer) => {
|
onEachFeature: (feature, layer) => {
|
||||||
@@ -5790,6 +5933,7 @@ function resetLayerManagerProjectState() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function clearManagedCategoryState(categoryKey) {
|
function clearManagedCategoryState(categoryKey) {
|
||||||
|
clearManagedCategorySelection(categoryKey);
|
||||||
const category = layerManagerCategories().find(item => item.key === categoryKey);
|
const category = layerManagerCategories().find(item => item.key === categoryKey);
|
||||||
if (category) {
|
if (category) {
|
||||||
managedRecordsForCategory(category).forEach(record => {
|
managedRecordsForCategory(category).forEach(record => {
|
||||||
@@ -5807,6 +5951,21 @@ function clearManagedCategoryState(categoryKey) {
|
|||||||
delete lmeState.managerObjectOrder[categoryKey];
|
delete lmeState.managerObjectOrder[categoryKey];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function clearManagedCategorySelection(categoryKey) {
|
||||||
|
const ids = new Set();
|
||||||
|
lmeState.managerRecords?.forEach?.(record => {
|
||||||
|
if (record.categoryKey === categoryKey) ids.add(record.id);
|
||||||
|
});
|
||||||
|
const category = layerManagerCategories().find(item => item.key === categoryKey);
|
||||||
|
if (category) managedRecordsForCategory(category).forEach(record => ids.add(record.id));
|
||||||
|
ids.forEach(id => lmeState.managerSelectedObjectIds.delete(id));
|
||||||
|
if (lmeState.managerHighlightedCategoryKey === categoryKey) {
|
||||||
|
lmeState.managerHighlightedObjectId = null;
|
||||||
|
lmeState.managerHighlightedCategoryKey = null;
|
||||||
|
}
|
||||||
|
restoreDirectManagerHighlights();
|
||||||
|
}
|
||||||
|
|
||||||
function bindStoredFeaturePopup(feature, layer) {
|
function bindStoredFeaturePopup(feature, layer) {
|
||||||
updateStoredFeaturePopup(layer, feature?.properties);
|
updateStoredFeaturePopup(layer, feature?.properties);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user