feat(windkarte): geometry eingebettet in wind_area CMS-Einträge
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:
@@ -5,13 +5,11 @@
|
|||||||
|
|
||||||
let {
|
let {
|
||||||
areas,
|
areas,
|
||||||
geojsonUrl,
|
|
||||||
onselect,
|
onselect,
|
||||||
onready = null,
|
onready = null,
|
||||||
initialGebietsNr = null,
|
initialGebietsNr = null,
|
||||||
}: {
|
}: {
|
||||||
areas: WindArea[];
|
areas: WindArea[];
|
||||||
geojsonUrl: string;
|
|
||||||
onselect: (area: WindArea | null, center: [number, number] | null) => void;
|
onselect: (area: WindArea | null, center: [number, number] | null) => void;
|
||||||
onready?: ((ctrl: { reset: () => void }) => void) | null;
|
onready?: ((ctrl: { reset: () => void }) => void) | null;
|
||||||
initialGebietsNr?: string | null;
|
initialGebietsNr?: string | null;
|
||||||
@@ -136,8 +134,21 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const geoRes = await fetch(geojsonUrl);
|
// Build FeatureCollection directly from CMS areas (geometry embedded)
|
||||||
const geo: GeoJSON.FeatureCollection = await geoRes.json();
|
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 }>();
|
const layerMap = new Map<string, { feature: GeoJSON.Feature; layer: import("leaflet").Layer }>();
|
||||||
|
|
||||||
@@ -147,8 +158,9 @@
|
|||||||
return style(s, false);
|
return style(s, false);
|
||||||
},
|
},
|
||||||
onEachFeature: (feature, layer) => {
|
onEachFeature: (feature, layer) => {
|
||||||
const cmsArea = byNr[feature.properties?.name] ?? null;
|
const p = feature.properties ?? {};
|
||||||
if (cmsArea) feature.properties.cms = cmsArea;
|
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 ?? "";
|
const name = feature.properties?.name ?? "";
|
||||||
layerMap.set(name, { feature, layer });
|
layerMap.set(name, { feature, layer });
|
||||||
@@ -169,15 +181,15 @@
|
|||||||
|
|
||||||
layer.on("click", async (e) => {
|
layer.on("click", async (e) => {
|
||||||
L.DomEvent.stopPropagation(e);
|
L.DomEvent.stopPropagation(e);
|
||||||
await selectFeature(L, feature, layer, cmsArea);
|
await selectFeature(L, feature, layer, area);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Hover tooltip
|
// Hover tooltip
|
||||||
const hoverLabel = feature.properties?.bezeichnung ?? name;
|
const hoverLabel = area.bezeichnung ?? p.name ?? "";
|
||||||
layer.bindTooltip(hoverLabel, { sticky: true, className: "windkarte-tooltip" });
|
layer.bindTooltip(hoverLabel, { sticky: true, className: "windkarte-tooltip" });
|
||||||
|
|
||||||
// Permanent label via divIcon marker at polygon center
|
// Permanent label via divIcon marker at polygon center
|
||||||
const nr = cmsArea?.gebiets_nr ?? name;
|
const nr = area.gebiets_nr ?? p.name;
|
||||||
if (nr && labelLayer) {
|
if (nr && labelLayer) {
|
||||||
const center = (layer as import("leaflet").Polygon).getBounds().getCenter();
|
const center = (layer as import("leaflet").Polygon).getBounds().getCenter();
|
||||||
L.marker(center, {
|
L.marker(center, {
|
||||||
@@ -217,11 +229,11 @@
|
|||||||
if (initialGebietsNr) {
|
if (initialGebietsNr) {
|
||||||
const entry = layerMap.get(initialGebietsNr);
|
const entry = layerMap.get(initialGebietsNr);
|
||||||
if (entry) {
|
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) {
|
} 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"
|
env.PUBLIC_CMS_URL || "http://localhost:3000"
|
||||||
).replace(/\/$/, "");
|
).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 selectedArea = $state<WindArea | null>(null);
|
||||||
let selectedCenter = $state<[number, number] | null>(null);
|
let selectedCenter = $state<[number, number] | null>(null);
|
||||||
let mapReady = $state(false);
|
let mapReady = $state(false);
|
||||||
@@ -106,7 +104,6 @@
|
|||||||
{#await MapComponent then Map}
|
{#await MapComponent then Map}
|
||||||
<Map
|
<Map
|
||||||
{areas}
|
{areas}
|
||||||
geojsonUrl={GEOJSON_URL}
|
|
||||||
{initialGebietsNr}
|
{initialGebietsNr}
|
||||||
onselect={handleSelect}
|
onselect={handleSelect}
|
||||||
onready={(ctrl) => { resetMap = ctrl.reset; }}
|
onready={(ctrl) => { resetMap = ctrl.reset; }}
|
||||||
|
|||||||
@@ -10,4 +10,5 @@ export type WindArea = {
|
|||||||
gemeinden?: string[];
|
gemeinden?: string[];
|
||||||
stellungnahme?: { _slug: string; slug?: string } | string | null;
|
stellungnahme?: { _slug: string; slug?: string } | string | null;
|
||||||
notizen?: string;
|
notizen?: string;
|
||||||
|
geometry?: GeoJSON.Geometry;
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user