Release 0.4.3 with contextual help and parcel deduplication
This commit is contained in:
1 parent
f1224b21c4
commit
cfba1b998b
8 files changed
+325
-11
No files matched your search
+116
-5
@@ -367,7 +367,7 @@ function displayOfficialParcel(xmlText, latitude, longitude, parcel, label, shou
|
||||
const lon = Number(longitude);
|
||||
if (!Number.isFinite(lat) || !Number.isFinite(lon)) {
|
||||
setInfo("Coordinate della particella non valide.");
|
||||
return;
|
||||
return "invalid";
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -389,27 +389,63 @@ function displayOfficialParcel(xmlText, latitude, longitude, parcel, label, shou
|
||||
lmeState.map.setView([lat, lon], 20);
|
||||
}
|
||||
setInfo("Posizione trovata, ma il servizio WFS dell'Agenzia non ha restituito il confine. Riprova tra poco.");
|
||||
return;
|
||||
return "missing";
|
||||
}
|
||||
|
||||
const ref = feature.properties?.NATIONALCADASTRALREFERENCE || feature.properties?.INSPIREID_LOCALID || label;
|
||||
const targetGroup = normalizedParcel ? lmeState.selectedParcelsLayer : lmeState.gpsParcelLayer;
|
||||
if (normalizedParcel) {
|
||||
lmeState.selectedParcelsVisible = true;
|
||||
lmeState.managerHiddenCategories.delete("selectedParcels");
|
||||
if (!lmeState.map.hasLayer(targetGroup)) {
|
||||
targetGroup.addTo(lmeState.map);
|
||||
}
|
||||
targetGroup.bringToFront();
|
||||
}
|
||||
if (!normalizedParcel) {
|
||||
targetGroup.clearLayers();
|
||||
}
|
||||
|
||||
const existingLayer = normalizedParcel
|
||||
? findParcelLayerByReference(targetGroup, ref)
|
||||
? findParcelLayerByReference(targetGroup, ref) || restoreHiddenParcelLayerByReference(ref)
|
||||
: null;
|
||||
if (existingLayer) {
|
||||
if (typeof existingLayer.setStyle === "function") {
|
||||
existingLayer.setStyle({ color: "#ef4444", weight: 4, opacity: 1, fillColor: "#fbbf24", fillOpacity: 0.26 });
|
||||
}
|
||||
targetGroup.bringToFront();
|
||||
if (shouldFit) {
|
||||
fitLayer(existingLayer);
|
||||
}
|
||||
setText("parcelState", `Particella selezionata: ${ref}`);
|
||||
setInfo(`La particella ${ref} e' gia evidenziata sulla mappa.`);
|
||||
return;
|
||||
updateGpsInsideState();
|
||||
refreshLayerManager();
|
||||
return "selected";
|
||||
}
|
||||
|
||||
const importedRecord = normalizedParcel ? findImportedParcelRecord(feature, ref) : null;
|
||||
if (importedRecord) {
|
||||
restoreManagedRecordVisibility(importedRecord);
|
||||
lmeState.importedVisible = true;
|
||||
lmeState.managerHiddenCategories.delete("imported");
|
||||
if (!lmeState.map.hasLayer(lmeState.imported)) {
|
||||
lmeState.imported.addTo(lmeState.map);
|
||||
}
|
||||
lmeState.imported.bringToFront();
|
||||
if (shouldFit) {
|
||||
fitLayer(importedRecord.layer);
|
||||
}
|
||||
setText("parcelState", `Particella gia presente nei dati importati: ${ref}`);
|
||||
setInfo(`La particella ${ref} e' gia presente in un progetto o file importato: nessun duplicato aggiunto.`);
|
||||
refreshLayerManager();
|
||||
return "imported";
|
||||
}
|
||||
|
||||
feature.properties = {
|
||||
...(feature.properties || {}),
|
||||
_lmeParcelReference: String(ref || label || normalizedParcel)
|
||||
};
|
||||
const layer = L.geoJSON(feature, {
|
||||
pane: normalizedParcel ? "selectedParcelsPane" : "gpsParcelsPane",
|
||||
style: normalizedParcel
|
||||
@@ -418,6 +454,9 @@ function displayOfficialParcel(xmlText, latitude, longitude, parcel, label, shou
|
||||
}).addTo(targetGroup);
|
||||
layer.lmeParcelReference = ref;
|
||||
layer.bindPopup(`<strong>${escapeHtml(ref)}</strong>`);
|
||||
if (normalizedParcel) {
|
||||
targetGroup.bringToFront();
|
||||
}
|
||||
if (shouldFit) {
|
||||
fitLayer(layer);
|
||||
}
|
||||
@@ -429,9 +468,12 @@ function displayOfficialParcel(xmlText, latitude, longitude, parcel, label, shou
|
||||
} else {
|
||||
setText("parcelState", `Dentro particella AdE: ${ref}`);
|
||||
}
|
||||
updateGpsInsideState();
|
||||
refreshLayerManager();
|
||||
return normalizedParcel ? "added" : "gps";
|
||||
} catch (error) {
|
||||
setInfo(`Geometria catastale non leggibile: ${error.message}`);
|
||||
return "error";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -440,12 +482,13 @@ function normalizeParcel(parcel) {
|
||||
}
|
||||
|
||||
function findParcelLayerByReference(group, reference) {
|
||||
const expected = normalizeParcelReference(reference);
|
||||
let match = null;
|
||||
group.eachLayer(layer => {
|
||||
if (match) {
|
||||
return;
|
||||
}
|
||||
if (layer.lmeParcelReference === reference) {
|
||||
if (parcelLayerMatchesReference(layer, expected)) {
|
||||
match = layer;
|
||||
return;
|
||||
}
|
||||
@@ -456,6 +499,74 @@ function findParcelLayerByReference(group, reference) {
|
||||
return match;
|
||||
}
|
||||
|
||||
function restoreHiddenParcelLayerByReference(reference) {
|
||||
const expected = normalizeParcelReference(reference);
|
||||
const entry = [...lmeState.managerHiddenObjects.entries()].find(([, record]) =>
|
||||
record.categoryKey === "selectedParcels" && parcelLayerMatchesReference(record.layer, expected));
|
||||
if (!entry) return null;
|
||||
const [id, record] = entry;
|
||||
lmeState.managerHiddenObjects.delete(id);
|
||||
lmeState.managerHiddenObjectIds.delete(id);
|
||||
lmeState.managerHiddenMeasurementSummaryIds.delete(id);
|
||||
lmeState.managerHiddenMeasurementSideIds.delete(id);
|
||||
record.parent?.addLayer?.(record.layer);
|
||||
return record.layer;
|
||||
}
|
||||
|
||||
function parcelLayerMatchesReference(layer, normalizedReference) {
|
||||
const properties = layer?.feature?.properties || {};
|
||||
return [
|
||||
layer?.lmeParcelReference,
|
||||
properties._lmeParcelReference,
|
||||
properties.NATIONALCADASTRALREFERENCE,
|
||||
properties.INSPIREID_LOCALID
|
||||
].some(value => normalizeParcelReference(value) === normalizedReference);
|
||||
}
|
||||
|
||||
function findImportedParcelRecord(feature, reference) {
|
||||
const category = layerManagerCategories().find(item => item.key === "imported");
|
||||
if (!category) return null;
|
||||
const normalizedReference = normalizeParcelReference(reference);
|
||||
return managedRecordsForCategory(category).find(record =>
|
||||
parcelLayerMatchesReference(record.layer, normalizedReference)
|
||||
|| parcelGeometriesEquivalent(record.layer?.toGeoJSON?.(), feature)) || null;
|
||||
}
|
||||
|
||||
function restoreManagedRecordVisibility(record) {
|
||||
if (!record) return;
|
||||
lmeState.managerHiddenObjects.delete(record.id);
|
||||
lmeState.managerHiddenObjectIds.delete(record.id);
|
||||
lmeState.managerHiddenMeasurementSummaryIds.delete(record.id);
|
||||
lmeState.managerHiddenMeasurementSideIds.delete(record.id);
|
||||
if (record.parent && !record.parent.hasLayer?.(record.layer)) {
|
||||
record.parent.addLayer?.(record.layer);
|
||||
}
|
||||
}
|
||||
|
||||
function parcelGeometriesEquivalent(candidate, target) {
|
||||
const candidateType = candidate?.geometry?.type;
|
||||
const targetType = target?.geometry?.type;
|
||||
if (!["Polygon", "MultiPolygon"].includes(candidateType)
|
||||
|| !["Polygon", "MultiPolygon"].includes(targetType)) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
const candidateArea = turf.area(candidate);
|
||||
const targetArea = turf.area(target);
|
||||
if (!(candidateArea > 0) || !(targetArea > 0)) return false;
|
||||
const areaRatio = Math.max(candidateArea, targetArea) / Math.min(candidateArea, targetArea);
|
||||
if (areaRatio > 1.03) return false;
|
||||
const overlap = turf.intersect(turf.featureCollection([candidate, target]));
|
||||
return Boolean(overlap) && turf.area(overlap) / Math.min(candidateArea, targetArea) >= 0.985;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function normalizeParcelReference(reference) {
|
||||
return String(reference || "").trim().toUpperCase().replace(/\s+/g, "");
|
||||
}
|
||||
|
||||
function resize() {
|
||||
if (!lmeState.map) {
|
||||
return;
|
||||
|
||||
Reference in new issue
Block a user