feat: Leitungsverlaeufe aus DB mit dynamischem Puffer und Abstaenden integriert
Deploy Bürgerwind / deploy (push) Successful in 17s Details

This commit is contained in:
Johannes Baumeister 2026-05-29 10:51:53 +02:00
parent 47c77b69e9
commit e0e36a6917
2 changed files with 142 additions and 1 deletions

107
app.js
View File

@ -1202,7 +1202,112 @@ document.addEventListener('DOMContentLoaded', async () => {
console.warn("Restriktionsabstände-Layer konnte nicht geladen werden."); console.warn("Restriktionsabstände-Layer konnte nicht geladen werden.");
} }
statusEl.innerText = "Layer geladen (ALKIS DB & Artennachweise integriert)."; // Leitungsverläufe aus DB laden
console.log("Lade Leitungsverläufe aus Datenbank...");
const ltgResp = await fetch('/api/layers/leitungsverlaeufe').catch(err => {
console.error("Netzwerkfehler beim Laden der Leitungsverläufe:", err);
return null;
});
if (ltgResp?.ok) {
const data = await ltgResp.json();
console.log(`Leitungsverläufe API: ${data.features ? data.features.length : 0} Features erhalten.`);
// Alte lokale Layer aufräumen
const localLtgKeys = Object.keys(overlays).filter(k =>
(k.toLowerCase().includes('freileitung') || k.toLowerCase().includes('wasserstoff') || k.toLowerCase().includes('leitung')) && !k.includes('(db)')
);
localLtgKeys.forEach(key => {
console.log(`Entferne lokalen Leitungs-Layer "${key}" (wird durch DB ersetzt).`);
if (state.map.hasLayer(overlays[key])) {
state.map.removeLayer(overlays[key]);
}
layerControl.removeLayer(overlays[key]);
delete overlays[key];
if (state.bakedData[key]) delete state.bakedData[key];
});
// In zwei Gruppen splitten
const freileitungen = { type: 'FeatureCollection', features: [] };
const wasserstoff = { type: 'FeatureCollection', features: [] };
if (data.features) {
data.features.forEach(f => {
const art = (f.properties.art || '').toLowerCase();
if (art.includes('freileitung')) {
freileitungen.features.push(f);
} else if (art.includes('wasserstoff')) {
wasserstoff.features.push(f);
}
});
}
const createDbLayer = (geojsonData, name, styleFunc, isFreileitung) => {
if (geojsonData.features.length === 0) return;
const layer = L.geoJSON(geojsonData, {
style: styleFunc,
onEachFeature: (feature, l) => {
if (feature.properties) {
let popup = `<b>${name}</b><br><hr style="margin: 5px 0; border: 0; border-top: 1px solid #444;">`;
for (let key in feature.properties) {
const val = feature.properties[key];
if (val !== null && val !== undefined) popup += `<b>${key}:</b> ${val}<br>`;
}
l.bindPopup(popup);
}
}
});
overlays[name] = layer;
state.map.addLayer(layer);
layerControl.addOverlay(layer, name);
// In bakedData eintragen für die Abstandslinien (updateProximityLines)
state.bakedData[name] = { data: geojsonData, style: styleFunc() };
// Dynamischer Turf Buffer für Freileitungen
if (isFreileitung) {
try {
const bufferedFeatures = [];
geojsonData.features.forEach(f => {
let dist = 0.05; // 50m default
const spannung = (f.properties.spannung || '').toString().toLowerCase();
if (spannung.includes('110')) dist = 0.035;
else if (spannung.includes('380')) dist = 0.05;
const b = turf.buffer(f, dist, {units: 'kilometers'});
if (b) bufferedFeatures.push(b);
});
if (bufferedFeatures.length > 0) {
const bufferLayer = L.geoJSON({ type: 'FeatureCollection', features: bufferedFeatures }, {
style: {
color: '#ffff00',
weight: 0,
fillColor: '#ffff00',
fillOpacity: 0.3
}
});
const bufferName = name + " (Puffer)";
overlays[bufferName] = bufferLayer;
state.map.addLayer(bufferLayer);
layerControl.addOverlay(bufferLayer, bufferName);
bufferLayer.bringToBack();
}
} catch(err) {
console.error("Fehler beim Erstellen des Puffers für " + name, err);
}
}
};
createDbLayer(freileitungen, "Freileitungen (DB)", () => ({ color: '#ccaa00', weight: 3, fillOpacity: 0 }), true);
createDbLayer(wasserstoff, "Wasserstoffleitungen (DB)", () => ({ color: '#9400d3', weight: 2.5, fillOpacity: 0 }), false);
} else {
console.warn("Leitungsverläufe-Layer konnte nicht geladen werden.");
}
statusEl.innerText = "Layer geladen (ALKIS DB, Artennachweise & Leitungen integriert).";
} catch (e) { } catch (e) {
if (!isLocalFile) console.error("Layer-Init fehlgeschlagen:", e); if (!isLocalFile) console.error("Layer-Init fehlgeschlagen:", e);
} }

View File

@ -300,6 +300,42 @@ app.get('/api/layers/artennachweise_restriktionen', async (req, res) => {
} }
}); });
// NEU: API zum Laden der Leitungsverläufe (Freileitung, Wasserstoff etc.)
app.get('/api/layers/leitungsverlaeufe', async (req, res) => {
log("Lade Leitungsverläufe aus Datenbank...");
try {
const result = await pool.query(
`SELECT jsonb_build_object(
'type', 'FeatureCollection',
'features', COALESCE(jsonb_agg(features.feature), '[]'::jsonb)
)
FROM (
SELECT jsonb_build_object(
'type', 'Feature',
'geometry', ST_AsGeoJSON(ST_Transform(geom, 4326))::jsonb,
'properties', jsonb_build_object(
'art', art,
'spannung', spannung,
'ltg_name', ltg_name,
'bezeichnun', bezeichnun,
'bemerkung', bemerkung,
'status', status,
'quelle', quelle,
'info', info,
'vorschlag', vorschlag
)
) AS feature
FROM geodaten.leitungsverlaeufe
WHERE art ILIKE '%wasserstoff%' OR art ILIKE '%freileitung%'
) features`
);
res.json(result.rows[0].jsonb_build_object);
} catch (err) {
log(`FEHLER beim Laden der Leitungsverläufe: ${err.message}`);
res.status(500).json({ error: err.message });
}
});
// API für Projekt-Statistiken (Fortschrittsanzeige) // API für Projekt-Statistiken (Fortschrittsanzeige)
app.get('/api/stats/:projekt_id', async (req, res) => { app.get('/api/stats/:projekt_id', async (req, res) => {
const { projekt_id } = req.params; const { projekt_id } = req.params;