feat(windkarte): geometry eingebettet in wind_area CMS-Einträge
Deploy / verify (push) Successful in 49s
Deploy / deploy (push) Successful in 1m8s

GeoJSON-Geometrie direkt in CMS-Einträgen gespeichert — kein separates
GeoJSON-File mehr. WindkarteMap baut FeatureCollection aus areas[].geometry.
WindArea-Typ bekommt geometry-Feld. geojsonUrl-Prop entfernt.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Peter Meier
2026-05-13 11:34:59 +02:00
parent ee56a457d3
commit ca742345f3
3 changed files with 25 additions and 15 deletions
+23 -11
View File
@@ -5,13 +5,11 @@
let {
areas,
geojsonUrl,
onselect,
onready = null,
initialGebietsNr = null,
}: {
areas: WindArea[];
geojsonUrl: string;
onselect: (area: WindArea | null, center: [number, number] | null) => void;
onready?: ((ctrl: { reset: () => void }) => void) | null;
initialGebietsNr?: string | null;
@@ -136,8 +134,21 @@
});
try {
const geoRes = await fetch(geojsonUrl);
const geo: GeoJSON.FeatureCollection = await geoRes.json();
// Build FeatureCollection directly from CMS areas (geometry embedded)
const geo: GeoJSON.FeatureCollection = {
type: "FeatureCollection",
features: areas
.filter((a) => a.geometry)
.map((a) => ({
type: "Feature" as const,
properties: {
name: a.gebiets_nr,
bezeichnung: a.bezeichnung,
status: a.status ?? "rechtskraeftig",
},
geometry: a.geometry!,
})),
};
const layerMap = new Map<string, { feature: GeoJSON.Feature; layer: import("leaflet").Layer }>();
@@ -147,8 +158,9 @@
return style(s, false);
},
onEachFeature: (feature, layer) => {
const cmsArea = byNr[feature.properties?.name] ?? null;
if (cmsArea) feature.properties.cms = cmsArea;
const p = feature.properties ?? {};
const area = byNr[p.name] ?? { _slug: "", gebiets_nr: p.name ?? "", status: p.status, bezeichnung: p.bezeichnung };
feature.properties.cms = area;
const name = feature.properties?.name ?? "";
layerMap.set(name, { feature, layer });
@@ -169,15 +181,15 @@
layer.on("click", async (e) => {
L.DomEvent.stopPropagation(e);
await selectFeature(L, feature, layer, cmsArea);
await selectFeature(L, feature, layer, area);
});
// Hover tooltip
const hoverLabel = feature.properties?.bezeichnung ?? name;
const hoverLabel = area.bezeichnung ?? p.name ?? "";
layer.bindTooltip(hoverLabel, { sticky: true, className: "windkarte-tooltip" });
// Permanent label via divIcon marker at polygon center
const nr = cmsArea?.gebiets_nr ?? name;
const nr = area.gebiets_nr ?? p.name;
if (nr && labelLayer) {
const center = (layer as import("leaflet").Polygon).getBounds().getCenter();
L.marker(center, {
@@ -217,11 +229,11 @@
if (initialGebietsNr) {
const entry = layerMap.get(initialGebietsNr);
if (entry) {
await selectFeature(L, entry.feature, entry.layer, byNr[initialGebietsNr] ?? null, true);
await selectFeature(L, entry.feature, entry.layer, byNr[initialGebietsNr] ?? null);
}
}
} catch (e) {
console.error("GeoJSON laden fehlgeschlagen:", e);
console.error("Karte laden fehlgeschlagen:", e);
}
});
@@ -15,9 +15,7 @@
env.PUBLIC_CMS_URL || "http://localhost:3000"
).replace(/\/$/, "");
const GEOJSON_URL = `${CMS_BASE}/api/assets/geodaten/windvorranggebiete_swt_2012.geojson`;
let areas = $state<WindArea[]>([]);
let areas = $state<WindArea[]>([]);
let selectedArea = $state<WindArea | null>(null);
let selectedCenter = $state<[number, number] | null>(null);
let mapReady = $state(false);
@@ -106,7 +104,6 @@
{#await MapComponent then Map}
<Map
{areas}
geojsonUrl={GEOJSON_URL}
{initialGebietsNr}
onselect={handleSelect}
onready={(ctrl) => { resetMap = ctrl.reset; }}
+1
View File
@@ -10,4 +10,5 @@ export type WindArea = {
gemeinden?: string[];
stellungnahme?: { _slug: string; slug?: string } | string | null;
notizen?: string;
geometry?: GeoJSON.Geometry;
};