feat: highlight dwelling parcels

This commit is contained in:
2026-07-23 01:44:30 +01:00
parent f4e55349ca
commit 3a7bfbf0c2
+71 -1
View File
@@ -2,6 +2,7 @@ const DEFAULT_CENTER = [-8.65, 39.55];
const API_CAPABILITIES = "/api/capabilities"; const API_CAPABILITIES = "/api/capabilities";
const API_WMS = "/api/wms"; const API_WMS = "/api/wms";
const PARCEL_LAYER_NAME = "xpro:parcelas"; const PARCEL_LAYER_NAME = "xpro:parcelas";
const DWELLING_PARCEL_LAYER_NAME = "xpro:parcelas_habitacao";
const FEATURE_INFO_LAYER_NAMES = new Set(["parcelas", "predios"]); const FEATURE_INFO_LAYER_NAMES = new Set(["parcelas", "predios"]);
const DEVICE_ORIENTATION_EVENTS = ["deviceorientationabsolute", "deviceorientation"]; const DEVICE_ORIENTATION_EVENTS = ["deviceorientationabsolute", "deviceorientation"];
const COMPASS_HEADING_DEADBAND = 2; const COMPASS_HEADING_DEADBAND = 2;
@@ -67,6 +68,21 @@ const wmsLayer = new ol.layer.Image({
source: wmsSource, source: wmsSource,
}); });
const dwellingParcelSource = new ol.source.Vector();
const dwellingParcelLayer = new ol.layer.Vector({
source: dwellingParcelSource,
// The pale halo keeps the red dwelling boundary distinct over every
// supported basemap and the existing parcel fills.
style: [
new ol.style.Style({
stroke: new ol.style.Stroke({ color: "rgba(255, 255, 255, 0.9)", width: 6 }),
}),
new ol.style.Style({
stroke: new ol.style.Stroke({ color: "#d71920", width: 3.5 }),
}),
],
});
const parcelSearchSource = new ol.source.Vector(); const parcelSearchSource = new ol.source.Vector();
const parcelSearchLayer = new ol.layer.Vector({ const parcelSearchLayer = new ol.layer.Vector({
source: parcelSearchSource, source: parcelSearchSource,
@@ -106,7 +122,14 @@ const map = new ol.Map({
tipLabel: "Reset map orientation to north", tipLabel: "Reset map orientation to north",
}), }),
]), ]),
layers: [softBasemapLayer, openStreetMapLayer, satelliteLayer, wmsLayer, parcelSearchLayer], layers: [
softBasemapLayer,
openStreetMapLayer,
satelliteLayer,
wmsLayer,
dwellingParcelLayer,
parcelSearchLayer,
],
view: new ol.View({ view: new ol.View({
center: ol.proj.fromLonLat(DEFAULT_CENTER), center: ol.proj.fromLonLat(DEFAULT_CENTER),
zoom: 7, zoom: 7,
@@ -494,6 +517,7 @@ async function loadLayers() {
renderLayerList(); renderLayerList();
syncSelectedLayers(); syncSelectedLayers();
await loadDwellingParcels();
fitToLayerExtent(availableLayers[0]); fitToLayerExtent(availableLayers[0]);
updateStatus(`Showing ${availableLayers.length} layer(s) from GeoServer.`, "success"); updateStatus(`Showing ${availableLayers.length} layer(s) from GeoServer.`, "success");
@@ -502,6 +526,8 @@ async function loadLayers() {
updateStatus(error.message || "Unable to load the WMS service.", "error"); updateStatus(error.message || "Unable to load the WMS service.", "error");
availableLayers = []; availableLayers = [];
selectedLayers = []; selectedLayers = [];
dwellingParcelSource.clear();
dwellingParcelLayer.setVisible(false);
renderLayerList(); renderLayerList();
syncSelectedLayers(); syncSelectedLayers();
} }
@@ -590,6 +616,50 @@ function syncSelectedLayers() {
LAYERS: [...orderedSelectedLayers].reverse().join(","), LAYERS: [...orderedSelectedLayers].reverse().join(","),
_: Date.now(), _: Date.now(),
}); });
dwellingParcelLayer.setVisible(
selectedLayers.some((name) => {
const layerName = unqualifiedLayerName(name);
return layerName === "parcelas" || layerName === unqualifiedLayerName(DWELLING_PARCEL_LAYER_NAME);
}),
);
}
async function loadDwellingParcels() {
const publishedDwellingLayer = availableLayers.find(
(layer) => unqualifiedLayerName(layer.name) === unqualifiedLayerName(DWELLING_PARCEL_LAYER_NAME),
);
dwellingParcelSource.clear();
if (!publishedDwellingLayer) {
console.warn("The dwelling parcel layer is not published by GeoServer.");
return;
}
try {
const params = new URLSearchParams({
service: "WFS",
version: "2.0.0",
request: "GetFeature",
typeNames: publishedDwellingLayer.name,
outputFormat: "application/json",
srsName: "EPSG:3857",
});
const response = await fetch(`${API_WMS}?${params}`);
if (!response.ok) {
throw new Error(`Dwelling parcel request failed with status ${response.status}.`);
}
const featureCollection = await response.json();
const features = new ol.format.GeoJSON().readFeatures(featureCollection, {
featureProjection: "EPSG:3857",
});
dwellingParcelSource.addFeatures(features);
} catch (error) {
// Keep the normal map usable when a deployment has not yet published the
// optional layer; the error remains available for operational diagnosis.
console.error(error);
}
} }
async function showFeatureInformation(event) { async function showFeatureInformation(event) {