diff --git a/Components/Pages/Home.razor b/Components/Pages/Home.razor
index 4444ed7..868b408 100644
--- a/Components/Pages/Home.razor
+++ b/Components/Pages/Home.razor
@@ -242,13 +242,16 @@
Caricamento...
-
![Vista WMS catastale dell'area corrente]()
+
+
![Vista WMS catastale dell'area corrente]()
+
+
diff --git a/LMEMappeCatastaliApp.csproj b/LMEMappeCatastaliApp.csproj
index 07110b8..422416f 100644
--- a/LMEMappeCatastaliApp.csproj
+++ b/LMEMappeCatastaliApp.csproj
@@ -28,8 +28,8 @@
com.companyname.lmemappecatastaliapp
- 0.2.4
- 8
+ 0.2.5
+ 9
None
diff --git a/README.md b/README.md
index ccf6abe..0c06560 100644
--- a/README.md
+++ b/README.md
@@ -28,6 +28,7 @@ App .NET MAUI Blazor Hybrid per Android, iOS, Mac Catalyst e Windows, pensata pe
- Le particelle cercate possono essere aggiunte una dopo l'altra, mantenendo contemporaneamente sulla mappa tutti i confini selezionati.
- Comandi separati per rimuovere le particelle selezionate o pulire importazioni, disegni, POI e traccia GPS.
- Anteprima WMS ufficiale mostrata dentro l'app senza aprire una nuova finestra Android.
+- Confini delle particelle selezionate e della particella GPS sovrapposti anche all'anteprima WMS corrente.
- Collegamenti separati al Geoportale pubblico e all'Area riservata AdE per CAPTCHA, SPID/CIE e download ufficiali.
## Limite ufficiale AdE da considerare
diff --git a/Services/AzureMapsService.cs b/Services/AzureMapsService.cs
index 2824685..f53bfaa 100644
--- a/Services/AzureMapsService.cs
+++ b/Services/AzureMapsService.cs
@@ -13,7 +13,7 @@ public sealed class AzureMapsService
public AzureMapsService()
{
- _httpClient.DefaultRequestHeaders.UserAgent.ParseAdd("LMEMappeCatastali/0.2.4");
+ _httpClient.DefaultRequestHeaders.UserAgent.ParseAdd("LMEMappeCatastali/0.2.5");
_httpClient.DefaultRequestHeaders.Accept.ParseAdd("application/json");
}
diff --git a/wwwroot/css/app.css b/wwwroot/css/app.css
index 2acb340..8381965 100644
--- a/wwwroot/css/app.css
+++ b/wwwroot/css/app.css
@@ -527,14 +527,46 @@ label {
color: var(--muted);
}
-.wms-preview-body img {
- display: block;
- max-width: 100%;
- max-height: 100%;
- object-fit: contain;
+.wms-preview-map {
+ position: relative;
+ flex: 0 0 auto;
+ overflow: hidden;
background: #fff;
}
+.wms-preview-map[hidden] {
+ display: none;
+}
+
+.wms-preview-map img,
+.wms-preview-map svg {
+ display: block;
+ width: 100%;
+ height: 100%;
+}
+
+.wms-preview-map svg {
+ position: absolute;
+ inset: 0;
+ pointer-events: none;
+}
+
+.wms-preview-parcel {
+ fill: rgba(251, 191, 36, 0.28);
+ fill-rule: evenodd;
+ stroke: #ef4444;
+ stroke-width: 4px;
+ vector-effect: non-scaling-stroke;
+}
+
+.wms-preview-gps-parcel {
+ fill: rgba(56, 189, 248, 0.24);
+ fill-rule: evenodd;
+ stroke: #1d4ed8;
+ stroke-width: 4px;
+ vector-effect: non-scaling-stroke;
+}
+
.bottom-tabs {
position: absolute;
right: 0;
diff --git a/wwwroot/js/lme-map.js b/wwwroot/js/lme-map.js
index 56030ed..0902239 100644
--- a/wwwroot/js/lme-map.js
+++ b/wwwroot/js/lme-map.js
@@ -265,40 +265,114 @@ function exportCadastreView() {
bbox
});
const preview = document.getElementById("wmsPreview");
+ const previewBody = preview?.querySelector(".wms-preview-body");
+ const previewMap = document.getElementById("wmsPreviewMap");
const image = document.getElementById("wmsPreviewImage");
+ const overlay = document.getElementById("wmsPreviewOverlay");
const loading = document.getElementById("wmsPreviewLoading");
- if (!preview || !image || !loading) {
+ if (!preview || !previewBody || !previewMap || !image || !overlay || !loading) {
setInfo("Vista WMS interna non disponibile.");
return;
}
+ preview.hidden = false;
+ const availableWidth = Math.max(1, previewBody.clientWidth - 24);
+ const availableHeight = Math.max(1, previewBody.clientHeight - 24);
+ const displayScale = Math.min(1, availableWidth / width, availableHeight / height);
+ previewMap.style.width = `${Math.max(1, Math.round(width * displayScale))}px`;
+ previewMap.style.height = `${Math.max(1, Math.round(height * displayScale))}px`;
+ previewMap.hidden = true;
+ renderPreviewParcelOverlay(overlay, bounds, width, height);
+
loading.textContent = "Caricamento...";
loading.hidden = false;
- image.hidden = true;
image.onload = () => {
loading.hidden = true;
- image.hidden = false;
- setInfo(`Vista WMS caricata con ${layers.length} layer.`);
+ previewMap.hidden = false;
+ const highlightedCount = lmeState.selectedParcelsLayer.getLayers().length
+ + lmeState.gpsParcelLayer.getLayers().length;
+ setInfo(`Vista WMS caricata con ${layers.length} layer e ${highlightedCount} particelle evidenziate.`);
};
image.onerror = () => {
+ previewMap.hidden = true;
loading.textContent = "Il servizio WMS non ha restituito l'immagine. Riprova tra poco.";
setInfo("Vista WMS non disponibile.");
};
- preview.hidden = false;
image.src = `${cadastreUrl()}${params}`;
}
function closeCadastrePreview() {
const preview = document.getElementById("wmsPreview");
+ const previewMap = document.getElementById("wmsPreviewMap");
const image = document.getElementById("wmsPreviewImage");
+ const overlay = document.getElementById("wmsPreviewOverlay");
if (preview) {
preview.hidden = true;
}
+ if (previewMap) {
+ previewMap.hidden = true;
+ }
if (image) {
image.onload = null;
image.onerror = null;
image.removeAttribute("src");
}
+ overlay?.replaceChildren();
+}
+
+function renderPreviewParcelOverlay(svg, bounds, width, height) {
+ svg.replaceChildren();
+ svg.setAttribute("viewBox", `0 0 ${width} ${height}`);
+ appendPreviewGeometry(svg, lmeState.selectedParcelsLayer.toGeoJSON(), "wms-preview-parcel", bounds, width, height);
+ appendPreviewGeometry(svg, lmeState.gpsParcelLayer.toGeoJSON(), "wms-preview-gps-parcel", bounds, width, height);
+}
+
+function appendPreviewGeometry(svg, featureCollection, className, bounds, width, height) {
+ const namespace = "http://www.w3.org/2000/svg";
+ for (const feature of featureCollection?.features || []) {
+ for (const polygon of geometryPolygons(feature.geometry)) {
+ const pathData = polygon
+ .map(ring => ring
+ .map((coordinate, index) => {
+ const point = previewPixel(coordinate, bounds, width, height);
+ return `${index ? "L" : "M"}${point.x.toFixed(2)} ${point.y.toFixed(2)}`;
+ })
+ .join(" ") + " Z")
+ .join(" ");
+ if (!pathData.trim()) {
+ continue;
+ }
+ const path = document.createElementNS(namespace, "path");
+ path.setAttribute("d", pathData);
+ path.setAttribute("class", className);
+ svg.appendChild(path);
+ }
+ }
+}
+
+function geometryPolygons(geometry) {
+ if (!geometry) {
+ return [];
+ }
+ if (geometry.type === "Polygon") {
+ return [geometry.coordinates || []];
+ }
+ if (geometry.type === "MultiPolygon") {
+ return geometry.coordinates || [];
+ }
+ if (geometry.type === "GeometryCollection") {
+ return (geometry.geometries || []).flatMap(geometryPolygons);
+ }
+ return [];
+}
+
+function previewPixel(coordinate, bounds, width, height) {
+ const longitude = Number(coordinate?.[0]);
+ const latitude = Number(coordinate?.[1]);
+ return {
+ x: ((longitude - bounds.getWest()) / (bounds.getEast() - bounds.getWest())) * width,
+ y: ((bounds.getNorth() - latitude) / (bounds.getNorth() - bounds.getSouth())) * height
+ };
}
function bindFileImport() {