Widget:LeafletWWW: Unterschied zwischen den Versionen
HorstR (Diskussion | Beiträge) Keine Bearbeitungszusammenfassung |
HorstR (Diskussion | Beiträge) Keine Bearbeitungszusammenfassung |
||
| (8 dazwischenliegende Versionen desselben Benutzers werden nicht angezeigt) | |||
| Zeile 1: | Zeile 1: | ||
< | <!DOCTYPE html> | ||
< | <html> | ||
<head> | |||
<title>Köln - Was War Wo</title> | |||
<meta charset="utf-8" /> | |||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"/> | |||
<link rel="stylesheet" href="https://unpkg.com/leaflet-control-geocoder/dist/Control.Geocoder.css"/> | <link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css"/> | ||
<script src="https://unpkg.com/leaflet-control-geocoder/dist/Control.Geocoder.js"></script> | <script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script> | ||
<link rel="stylesheet" href="https://unpkg.com/leaflet-control-geocoder/dist/Control.Geocoder.css" /> | |||
<script src="https://unpkg.com/leaflet-control-geocoder/dist/Control.Geocoder.js"></script> | |||
<style> | <style> | ||
body { padding:10px; font-family:sans-serif; } | |||
#map-frame { border-radius:8px; position: relative;} | |||
#map { | |||
width: 100%; | |||
border | height: 88vh; /* größere Karte */ | ||
border: 3px solid black; | |||
} | border-radius: 10px; | ||
} | |||
. | #map-title { | ||
position: absolute; | |||
top: 10px; | |||
left: 50%; | |||
transform: translateX(-50%); | |||
} | z-index: 1000; | ||
background: rgba(255,255,255,0.85); | |||
padding: 6px 14px; | |||
font-weight: bold; | |||
font-size: 18px; | |||
border-radius: 6px; | |||
box-shadow: 0 0 6px rgba(0,0,0,0.3); | |||
} | |||
#map-footer { | |||
background:rgba(255,255,255,0. | position: absolute; | ||
padding:10px; | bottom: 10px; | ||
border-radius:6px; | left: 10px; | ||
box-shadow:0 0 | z-index: 1000; | ||
background: rgba(255,255,255,0.85); | |||
} | padding: 4px 10px; | ||
border-radius: 6px; | |||
font-size: 13px; | |||
box-shadow: 0 0 6px rgba(0,0,0,0.3); | |||
} | |||
.layerbox h4{ | #map-footer a { | ||
margin: | color: red; | ||
cursor:pointer; | text-decoration: none; | ||
} | font-weight: bold; | ||
} | |||
.legend { display:none; line-height:18px; color:#555; background:rgba(255,255,255,0.85); padding:10px; border-radius:5px; box-shadow:0 0 15px rgba(0,0,0,0.2); } | |||
.legend i { width:18px; height:18px; float:left; margin-right:8px; opacity:0.7; } | |||
.layerbox { background:rgba(255,255,255,0.9); padding:10px; border-radius:6px; box-shadow:0 0 10px rgba(0,0,0,0.3); font-size:14px; } | |||
.layerbox h4 { margin:0; cursor:pointer; } | |||
.layercontent { display:block; margin-top:8px; } | |||
.leaflet-bar button { cursor:pointer; font-weight:bold; } | |||
.layerbox b { display:block; margin-top:6px; } | |||
.search-input { width:100%; margin-bottom:6px; padding:4px; border:1px solid #ccc; border-radius:4px; } | |||
.layerbox { | |||
background:rgba(255,255,255,0.9); | |||
padding:10px; | |||
border-radius:6px; | |||
box-shadow:0 0 10px rgba(0,0,0,0.3); | |||
font-size:14px; | |||
max-height:70vh; | |||
overflow-y:auto; | |||
} | |||
</style> | |||
</head> | |||
<body> | |||
<div id="map-frame"> | |||
</ | <div id="map-title">Was War Wo</div> | ||
< | <div id="map"></div> | ||
<div id="map-footer"> | |||
<a href="https://hermsdoerfer.familyds.com/" target="_blank"> | |||
© Dietmar Hermsdörfer | |||
</a> | |||
</div> | |||
</div> | |||
<script> | |||
// --- Karte --- | |||
var map = L.map('map',{ | |||
preferCanvas:true, | |||
tap: window.screen.width < 600, | |||
zoomSnap:0.5, | |||
' | zoomDelta:0.5 | ||
}).setView([50.95,6.95],12); | |||
{ | |||
}) | |||
var | // --- Basemap --- | ||
var osm = L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {maxZoom:19, attribution:'© OpenStreetMap'}); | |||
var satellite = L.tileLayer('https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}', {attribution:'Tiles © Esri'}); | |||
osm.addTo(map); | |||
var baseMaps = {"Open Street Map":osm,"Satellit":satellite}; | |||
L.control.layers(baseMaps).addTo(map); | |||
function insidePolygon(point, vs){ | |||
var x=point[0], y=point[1], inside=false; | |||
for(var i=0,j=vs.length-1;i<vs.length;j=i++){ | |||
var xi=vs[i].lat, yi=vs[i].lng; | |||
var xj=vs[j].lat, yj=vs[j].lng; | |||
var intersect = ((yi>y)!=(yj>y)) && (x < (xj-xi)*(y-yi)/(yj-yi)+xi); | |||
if(intersect) inside = !inside; | |||
} | |||
return inside; | |||
} | |||
// --- Geocoder --- | |||
L.Control.geocoder({position:'topleft', defaultMarkGeocode:true, placeholder:"Suche ..."}).addTo(map); | |||
}; | // --- Farben für Nutzungen --- | ||
var nutzungColors = { | |||
'Hof':'red', | |||
'Mühle':'blue', | |||
'Fabrik':'black', | |||
'Gewerbe':'gray', | |||
'Verwaltung':'orange', | |||
'Bahn':'brown', | |||
'Brücke':'navy', | |||
'Hafen':'blue', | |||
'Flughafen':'green', | |||
'Versorgung':'gray', | |||
'Tankstelle':'maroon', | |||
'Brauerei':'yellow', | |||
'Ziegelei':'red', | |||
'Kloster':'orange', | |||
'Kirche':'purple', | |||
'Synagoge':'violet', | |||
'Krankenhaus':'red', | |||
'Friedhof':'green', | |||
'Hochbunker':'black', | |||
'Militär':'green', | |||
'Äußerer Festungsring 1873-1914':'red', | |||
'Stadtumwallung 1882-1891':'orange', | |||
'Umwallung Deutz 1818-1840':'gray', | |||
'Innerer Festungsring 1816-1873':'navy', | |||
'Enceinte 1815-1829':'yellow', | |||
'Bastionen 1632-1689':'gray', | |||
'Umwallung Mülheim 1588-1614':'darkblue', | |||
'Umwallung Worringen':'purple', | |||
'Stadtmauer 1180-1259':'maroon', | |||
'Stadterweiterung 1106-1141':'lightblue', | |||
'Stadterweiterung 950':'cyan', | |||
'Römische Befestigung':'blue', | |||
'Wohnen':'brown', | |||
'Schule':'red', | |||
'Freizeit':'green' | |||
}; | |||
// --- WMS-Historische Karten --- | |||
var wmsDOP2010 = L.tileLayer.wms("https://www.wms.nrw.de/geobasis/wms_nw_hist_dop",{layers:"nw_hist_dop_2010",format:"image/png",transparent:true,opacity:0.6,attribution:"Orthophoto 2010"}); | |||
var wmsDOP1998 = L.tileLayer.wms("https://www.wms.nrw.de/geobasis/wms_nw_hist_dop",{layers:"nw_hist_dop_1998",format:"image/png",transparent:true,opacity:0.6,attribution:"Orthophoto 1998"}); | |||
var wmsDOP1987 = L.tileLayer.wms("https://www.wms.nrw.de/geobasis/wms_nw_hist_dop",{layers:"nw_hist_dop_1987",format:"image/png",transparent:true,opacity:0.6,attribution:"Orthophoto 1987"}); | |||
var wmsDOP1981 = L.tileLayer.wms("https://www.wms.nrw.de/geobasis/wms_nw_hist_dop",{layers:"nw_hist_dop_1981",format:"image/png",transparent:true,opacity:0.6,attribution:"Orthophoto 1981"}); | |||
var wmsDOP1951 = L.tileLayer.wms("https://www.wms.nrw.de/geobasis/wms_nw_hist_dop",{layers:"nw_hist_dop_1951",format:"image/png",transparent:true,opacity:0.6,attribution:"Orthophoto 1951"}); | |||
var wmsMeyer = L.tileLayer("https://mapwarper.net/maps/tile/39790/{z}/{x}/{y}.png",{opacity:0.6, attribution:"Meyers Stadtplan 1900"}); | |||
var wmsKataster1836 = L.tileLayer("https://mapwarper.net/maps/tile/99312/{z}/{x}/{y}.png",{opacity:0.6, attribution:"Kataster 1836"}); | |||
var wmsKoeln1830 = L.tileLayer("https://mapwarper.net/maps/tile/101214/{z}/{x}/{y}.png",{opacity:0.6, attribution:"Köln 1830"}); | |||
var wmsVogtPicquet = L.tileLayer("https://mapwarper.net/maps/tile/39826/{z}/{x}/{y}.png",{opacity:0.6, attribution:"Vogt/Picquet 1815"}); | |||
var wmsNeuaufnahme = L.tileLayer.wms("https://www.wms.nrw.de/geobasis/wms_nw_neuaufnahme",{layers:"nw_neuaufnahme",format:"image/png",transparent:true,opacity:0.6,attribution:"Neuaufnahme 1891-1912"}); | |||
var wmsUraufnahme = L.tileLayer.wms("https://www.wms.nrw.de/geobasis/wms_nw_uraufnahme",{layers:"nw_uraufnahme_rw",format:"image/png",transparent:true,opacity:0.6,attribution:"Uraufnahme 1836-1850"}); | |||
var wmsTranchot = L.tileLayer.wms("https://www.wms.nrw.de/geobasis/wms_nw_tranchot",{layers:"nw_tranchot",format:"image/png",transparent:true,opacity:0.6,attribution:"Tranchot 1801-1828"}); | |||
var wmsStockdale = L.tileLayer("https://mapwarper.net/maps/tile/39780/{z}/{x}/{y}.png",{opacity:0.6, attribution:"Stockdale 1800"}); | |||
var wmsReinhardt = L.tileLayer("https://mapwarper.net/maps/tile/41691/{z}/{x}/{y}.png",{opacity:0.6, attribution:"Reinhardt 1752"}); | |||
var wmsMerian = L.tileLayer("https://mapwarper.net/maps/tile/39783/{z}/{x}/{y}.png",{opacity:0.6, attribution:"Merian 1641"}); | |||
var wmsMercator = L.tileLayer("https://mapwarper.net/maps/tile/40952/{z}/{x}/{y}.png",{opacity:0.6, attribution:"Mercator 1571"}); | |||
// --- | // --- GeoJSON Layer --- | ||
var | var geojsonLayer = L.geoJSON(null, { | ||
renderer: L.canvas(), | |||
style: function(feature){ | |||
return { color: nutzungColors[feature.properties.Nutzung] || "black", weight: 2, fillOpacity:0.4 }; | |||
} | |||
}).addTo(map); | |||
var highlightedLayers = []; | |||
// --- GeoJSON laden --- | |||
fetch('/alteskoeln/WasWarWo.geojson') | |||
.then(res => res.json()) | |||
.then(data => { | |||
geojsonLayer.addData(data); | |||
buildLayerbox(data); // dynamische Layerbox für Gruppen & Nutzungen | |||
}); | |||
// --- Klick auf Polygon --- | |||
map.on('click', function(e){ | |||
var clickedFeatures = []; | |||
// alte Highlights zurücksetzen | |||
highlightedLayers.forEach(layer => geojsonLayer.resetStyle(layer)); | |||
highlightedLayers = []; | |||
geojsonLayer.eachLayer(function(layer){ | |||
if(!map.hasLayer(layer)) return; // nur sichtbare Features | |||
if(layer instanceof L.Polygon && pointInLayer(e.latlng, layer)){ | |||
clickedFeatures.push(layer.feature.properties); | |||
highlightedLayers.push(layer); | |||
layer.setStyle({fillColor:'yellow', color:"cyan", weight:4, fillOpacity:0.6}); | |||
} | |||
}); | |||
if(clickedFeatures.length > 0){ | |||
( | showPopup(clickedFeatures, e.latlng); | ||
}; | // --- nach 2 Sekunden alle Highlights zurücksetzen --- | ||
setTimeout(function(){ | |||
highlightedLayers.forEach(layer => geojsonLayer.resetStyle(layer)); | |||
highlightedLayers = []; | |||
}, 2000); // 2000ms = 2 Sekunden | |||
} | |||
}); | |||
function showPopup(features, latlng){ | |||
var content = "<div style='max-height:50vh;overflow-y:auto;min-width:200px;'>"; | |||
if(features.length > 1){ | |||
content += "<div style='background:#eee;padding:8px;margin-bottom:12px;font-weight:bold;text-align:center;border-radius:6px;'>"+features.length+" historische Orte hier</div>"; | |||
} | |||
features.forEach(function(props){ | |||
var name = props.Name||"Unbekannt"; | |||
var nutzung = props.Nutzung||"-"; | |||
var von = props.von||"?"; | |||
var bis = props.bis||"?"; | |||
var info = props.Info||""; | |||
var bild = props.Bild ? '<a href="'+props.Bild+'" target="_blank"><img src="'+props.Bild+'" loading="lazy" style="width:100%;max-height:180px;object-fit:cover;border-radius:6px;margin-top:6px;"></a>' : ''; | |||
var link = props.Link ? '<br><a href="'+props.Link+'" target="_blank" style="color:blue;font-size:1em;">➔ Mehr Infos</a>' : ''; | |||
content += "<div style='margin-bottom:18px;border-bottom:1px solid #ccc;padding-bottom:12px;'>"+ | |||
"<b>"+name+"</b><br><small><i>"+nutzung+"</i></small><br>"+ | |||
"<b>Zeit:</b> "+von+" bis "+bis+"<br>"+ | |||
"<p style='font-size:1em;line-height:1.4;margin:8px 0;'>"+info+"</p>"+bild+link+"</div>"; | |||
}); | |||
content += "</div>"; | |||
}; | L.popup({maxWidth: window.innerWidth<600?300:400, minWidth:window.innerWidth<600?220:250, autoPanPadding:[20,20]}) | ||
.setLatLng(latlng) | |||
.setContent(content) | |||
.openOn(map); | |||
// Zoom auf alle ausgewählten Flächen | |||
var group = L.featureGroup(highlightedLayers); | |||
map.fitBounds(group.getBounds(), {padding:[40,40], maxZoom:17}); | |||
} | |||
// --- Punkt-in-Polygon --- | |||
function pointInLayer(latlng, layer){ | |||
var lat = latlng.lat, lng = latlng.lng; | |||
var polys = layer.getLatLngs(); | |||
if(layer.feature.geometry.type==="MultiPolygon"){ | |||
return polys.some(polyPart => insidePolygon([lat,lng], polyPart[0])); | |||
} | |||
return insidePolygon([lat,lng], polys[0]); | |||
} | |||
function insidePolygon(point, vs){ | |||
var x=point[0], y=point[1], inside=false; | |||
for(var i=0,j=vs.length-1;i<vs.length;j=i++){ | |||
var xi=vs[i].lat, yi=vs[i].lng; | |||
var xj=vs[j].lat, yj=vs[j].lng; | |||
var intersect = ((yi>y)!=(yj>y)) && (x < (xj-xi)*(y-yi)/(yj-yi)+xi); | |||
if(intersect) inside = !inside; | |||
} | |||
return inside; | |||
} | |||
layerBox.addTo(map); | // --- Layerbox & Suche --- | ||
function buildLayerbox(data){ | |||
var div = L.DomUtil.create('div','layerbox'); | |||
div.innerHTML = ` | |||
<h4 id="layerToggle">☰ Layer</h4> | |||
<div id="layerContent" class="layercontent" style="display:block;"> | |||
<input type="text" id="searchName" placeholder="Suche nach Name ..." class="search-input"> | |||
<b>Historische Orte</b> | |||
<div id="gruppen"></div> | |||
<b style="cursor:pointer;" onclick="toggleGroup('historische')">▶ Historische Karten</b> | |||
<div id="historische" style="margin-left:10px; display:none;"> | |||
<b style="cursor:pointer;" onclick="toggleGroup('orthophotos')">▶ Orthophotos</b> | |||
<div id="orthophotos" style="margin-left:10px; display:none;"> | |||
<label><input type="checkbox" id="layerDOP2010"> 2010</label><br> | |||
<label><input type="checkbox" id="layerDOP1998"> 1998</label><br> | |||
<label><input type="checkbox" id="layerDOP1987"> 1987</label><br> | |||
<label><input type="checkbox" id="layerDOP1981"> 1981</label><br> | |||
<label><input type="checkbox" id="layerDOP1951"> 1951</label> | |||
</div> | |||
<b style="cursor:pointer;" onclick="toggleGroup('kataster')">▶ Kataster & Stadtpläne</b> | |||
<div id="kataster" style="margin-left:10px; display:none;"> | |||
<label><input type="checkbox" id="layerMeyer"> 1900 Meyers Stadtplan</label><br> | |||
<label><input type="checkbox" id="layerKataster1836"> 1836 Kataster</label><br> | |||
<label><input type="checkbox" id="layerKoeln1830"> 1830 Köln</label><br> | |||
<label><input type="checkbox" id="layerVogtPicquet"> 1815 Vogt/Picquet</label><br> | |||
<label><input type="checkbox" id="layerStockdale"> 1800 Stockdale</label><br> | |||
<label><input type="checkbox" id="layerReinhardt"> 1752 Reinhardt</label><br> | |||
<label><input type="checkbox" id="layerMerian"> 1641 Merian</label><br> | |||
<label><input type="checkbox" id="layerMercator"> 1571 Mercator</label> | |||
</div> | |||
<b style="cursor:pointer;" onclick="toggleGroup('militaer')">▶ Militärkarten</b> | |||
<div id="militaer" style="margin-left:10px; display:none;"> | |||
<label><input type="checkbox" id="layerNeuaufnahme"> ~1890 Neuaufnahme</label><br> | |||
<label><input type="checkbox" id="layerUraufnahme"> 1836-1850 Uraufnahme</label><br> | |||
<label><input type="checkbox" id="layerTranchot"> 1801–1828 Tranchot</label><br> | |||
</div> | |||
<b>Transparenz Historische Karten</b> | |||
<input type="range" id="opacitySlider" min="0" max="100" value="60" style="width:100%;"> | |||
</div> | |||
</div> | |||
`; | |||
L.DomEvent.disableClickPropagation(div); | |||
layerBox = L.control({position:'topright'}); | |||
layerBox.onAdd = function(){ return div; }; | |||
layerBox.addTo(map); | |||
// --- dynamische Gruppen & Nutzungen --- | |||
var gruppenDiv = document.getElementById('gruppen'); | |||
var groups = {}; | |||
data.features.forEach(f => { | |||
if(!groups[f.properties.Gruppe]) groups[f.properties.Gruppe] = {}; | |||
if(!groups[f.properties.Gruppe][f.properties.Nutzung]) groups[f.properties.Gruppe][f.properties.Nutzung] = 0; | |||
groups[f.properties.Gruppe][f.properties.Nutzung]++; | |||
}); | |||
document. | for (var g in groups) { | ||
var gDiv = document.createElement('div'); | |||
// Flex-Container für Pfeil + Name + Gruppen-Checkbox | |||
gDiv.innerHTML = ` | |||
} | <div style="display:flex; align-items:center; gap:6px;"> | ||
<span class="groupArrow" style="cursor:pointer;" data-target="g_${g}">▶</span> | |||
<span style="flex:1;">${g}</span> | |||
<input type="checkbox" class="groupToggle" data-gruppe="${g}" checked> | |||
</div> | |||
`; | |||
// Untercontainer für alle Nutzungen der Gruppe | |||
var inner = document.createElement('div'); | |||
inner.id = `g_${g}`; | |||
inner.style.marginLeft = "20px"; | |||
inner.style.display = "none"; // start geschlossen | |||
for (var n in groups[g]) { | |||
var color = nutzungColors[n] || "black"; | |||
} | inner.innerHTML += `<label style="color:black; display:flex; align-items:center; gap:4px;"> | ||
<span style="width:14px; height:14px; background-color:${color}; display:inline-block; border:1px solid #000;"></span> | |||
<input type="checkbox" class="layerNutzung" data-gruppe="${g}" data-nutzung="${n}" checked> | |||
${n} (${groups[g][n]}) | |||
</label><br>`; | |||
} | |||
gDiv.appendChild(inner); | |||
gruppenDiv.appendChild(gDiv); | |||
} | } | ||
// Pfeil-Event separat, nur Pfeil klickbar | |||
document.querySelectorAll('.groupArrow').forEach(arrow => { | |||
arrow.addEventListener('click', function() { | |||
var targetId = this.dataset.target; | |||
var el = document.getElementById(targetId); | |||
if (!el) return; | |||
var isHidden = (el.style.display === "none"); | |||
el.style.display = isHidden ? "block" : "none"; | |||
// Pfeil wechseln | |||
this.textContent = isHidden ? "▼" : "▶"; | |||
}); | |||
}); | |||
document. | // --- Gruppen-Checkbox Event --- | ||
document.querySelectorAll('.groupToggle').forEach(cb => { | |||
cb.addEventListener('change', function(){ | |||
var gruppe = this.dataset.gruppe; | |||
var checked = this.checked; | |||
geojsonLayer.eachLayer(layer => { | |||
if(layer.feature.properties.Gruppe === gruppe){ | |||
if(checked) map.addLayer(layer); | |||
else map.removeLayer(layer); | |||
} | |||
}); | |||
// Auch Nutzung-Checkboxen aktualisieren | |||
document.querySelectorAll(`.layerNutzung[data-gruppe="${gruppe}"]`).forEach(nutzCb => { | |||
nutzCb.checked = checked; | |||
}); | |||
}); | |||
}); | |||
var | // --- Einzelne Nutzung Checkbox Event --- | ||
document.querySelectorAll('.layerNutzung').forEach(cb => { | |||
cb.addEventListener('change', function(){ | |||
var gruppe = this.dataset.gruppe; | |||
var nutzung = this.dataset.nutzung; | |||
geojsonLayer.eachLayer(layer => { | |||
if(layer.feature.properties.Gruppe===gruppe && layer.feature.properties.Nutzung===nutzung){ | |||
if(cb.checked) map.addLayer(layer); | |||
else map.removeLayer(layer); | |||
} | |||
}); | |||
// Gruppen-Checkbox anpassen | |||
var allChecked = Array.from(document.querySelectorAll(`.layerNutzung[data-gruppe="${gruppe}"]`)).every(nutzCb => nutzCb.checked); | |||
document.querySelector(`.groupToggle[data-gruppe="${gruppe}"]`).checked = allChecked; | |||
}); | |||
}); | |||
// --- Suche nach Name (gelb) --- | |||
document.getElementById('searchName').addEventListener('input', function(){ | |||
var val = this.value.toLowerCase(); | |||
highlightedLayers.forEach(layer => geojsonLayer.resetStyle(layer)); | |||
highlightedLayers = []; | |||
if(val === "") return; | |||
geojsonLayer.eachLayer(layer => { | |||
if(layer.feature.properties.Name && layer.feature.properties.Name.toLowerCase().includes(val)){ | |||
layer.setStyle({color:'yellow', weight:4, fillOpacity:0.6}); | |||
highlightedLayers.push(layer); | |||
} | |||
}); | |||
if(highlightedLayers.length){ | |||
map.fitBounds(L.featureGroup(highlightedLayers).getBounds(), {padding:[40,40], maxZoom:17}); | |||
} | |||
}); | |||
}); | // --- Historische Karten Layer Toggle --- | ||
document.addEventListener('change', function(e){ | |||
if(e.target.id==="layerDOP2010") toggleLayer(wmsDOP2010,e.target.checked); | |||
if(e.target.id==="layerDOP1998") toggleLayer(wmsDOP1998,e.target.checked); | |||
if(e.target.id==="layerDOP1987") toggleLayer(wmsDOP1987,e.target.checked); | |||
if(e.target.id==="layerDOP1981") toggleLayer(wmsDOP1981,e.target.checked); | |||
if(e.target.id==="layerDOP1951") toggleLayer(wmsDOP1951,e.target.checked); | |||
if(e.target.id==="layerMeyer") toggleLayer(wmsMeyer,e.target.checked); | |||
if(e.target.id==="layerKataster1836") toggleLayer(wmsKataster1836,e.target.checked); | |||
if(e.target.id==="layerKoeln1830") toggleLayer(wmsKoeln1830,e.target.checked); | |||
if(e.target.id==="layerVogtPicquet") toggleLayer(wmsVogtPicquet,e.target.checked); | |||
if(e.target.id==="layerStockdale") toggleLayer(wmsStockdale,e.target.checked); | |||
if(e.target.id==="layerReinhardt") toggleLayer(wmsReinhardt,e.target.checked); | |||
if(e.target.id==="layerMerian") toggleLayer(wmsMerian,e.target.checked); | |||
if(e.target.id==="layerMercator") toggleLayer(wmsMercator,e.target.checked); | |||
if(e.target.id==="layerNeuaufnahme") toggleLayer(wmsNeuaufnahme,e.target.checked); | |||
if(e.target.id==="layerUraufnahme") toggleLayer(wmsUraufnahme,e.target.checked); | |||
if(e.target.id==="layerTranchot") toggleLayer(wmsTranchot,e.target.checked); | |||
}); | |||
function toggleLayer(layer,visible){ | |||
if(visible) map.addLayer(layer); | |||
else map.removeLayer(layer); | |||
} | |||
} | // --- Transparenzregler --- | ||
var opacitySlider = document.getElementById('opacitySlider'); | |||
var historicalLayers = [ | |||
wmsDOP2010, wmsDOP1998, wmsDOP1987, wmsDOP1981, wmsDOP1951, | |||
wmsMeyer, wmsKataster1836, wmsKoeln1830, wmsVogtPicquet, | |||
wmsStockdale, wmsReinhardt, wmsMerian, wmsMercator, | |||
wmsNeuaufnahme, wmsUraufnahme, wmsTranchot | |||
]; | |||
opacitySlider.addEventListener('input', function(){ | |||
var value = this.value / 100; | |||
historicalLayers.forEach(layer => { | |||
if(map.hasLayer(layer)) layer.setOpacity(value); | |||
else layer.options.opacity = value; | |||
}); | |||
}); | |||
} | |||
// --- Toggle-Funktion mit Pfeil ▶ / ▼ --- | |||
function toggleGroup(id){ | |||
var el = document.getElementById(id); | |||
if(!el) return; | |||
var isHidden = (el.style.display==="none"); | |||
el.style.display = isHidden ? "block" : "none"; | |||
var bTag = el.previousElementSibling; | |||
if(bTag){ | |||
bTag.innerHTML = (isHidden ? "▼ " : "▶ ") + bTag.textContent.slice(2); | |||
} | |||
} | |||
</script> | </script> | ||
</body> | |||
</html> | |||
Aktuelle Version vom 18. März 2026, 11:15 Uhr
<!DOCTYPE html> <html> <head>
<title>Köln - Was War Wo</title> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"/>
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css"/> <script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script> <link rel="stylesheet" href="https://unpkg.com/leaflet-control-geocoder/dist/Control.Geocoder.css" /> <script src="https://unpkg.com/leaflet-control-geocoder/dist/Control.Geocoder.js"></script>
<style>
body { padding:10px; font-family:sans-serif; }
#map-frame { border-radius:8px; position: relative;}
#map { width: 100%; height: 88vh; /* größere Karte */ border: 3px solid black; border-radius: 10px; }
#map-title { position: absolute; top: 10px; left: 50%; transform: translateX(-50%); z-index: 1000; background: rgba(255,255,255,0.85); padding: 6px 14px; font-weight: bold; font-size: 18px; border-radius: 6px; box-shadow: 0 0 6px rgba(0,0,0,0.3); }
#map-footer { position: absolute; bottom: 10px; left: 10px; z-index: 1000; background: rgba(255,255,255,0.85); padding: 4px 10px; border-radius: 6px; font-size: 13px; box-shadow: 0 0 6px rgba(0,0,0,0.3); }
#map-footer a { color: red; text-decoration: none; font-weight: bold; }
.legend { display:none; line-height:18px; color:#555; background:rgba(255,255,255,0.85); padding:10px; border-radius:5px; box-shadow:0 0 15px rgba(0,0,0,0.2); }
.legend i { width:18px; height:18px; float:left; margin-right:8px; opacity:0.7; }
.layerbox { background:rgba(255,255,255,0.9); padding:10px; border-radius:6px; box-shadow:0 0 10px rgba(0,0,0,0.3); font-size:14px; }
.layerbox h4 { margin:0; cursor:pointer; }
.layercontent { display:block; margin-top:8px; }
.leaflet-bar button { cursor:pointer; font-weight:bold; }
.layerbox b { display:block; margin-top:6px; }
.search-input { width:100%; margin-bottom:6px; padding:4px; border:1px solid #ccc; border-radius:4px; }
.layerbox { background:rgba(255,255,255,0.9); padding:10px; border-radius:6px; box-shadow:0 0 10px rgba(0,0,0,0.3); font-size:14px; max-height:70vh; overflow-y:auto; }
</style> </head> <body>
<script>
// --- Karte ---
var map = L.map('map',{ preferCanvas:true, tap: window.screen.width < 600, zoomSnap:0.5, zoomDelta:0.5 }).setView([50.95,6.95],12);
// --- Basemap ---
var osm = L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {maxZoom:19, attribution:'© OpenStreetMap'});
var satellite = L.tileLayer('https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}', {attribution:'Tiles © Esri'});
osm.addTo(map);
var baseMaps = {"Open Street Map":osm,"Satellit":satellite};
L.control.layers(baseMaps).addTo(map);
function insidePolygon(point, vs){ var x=point[0], y=point[1], inside=false; for(var i=0,j=vs.length-1;i<vs.length;j=i++){ var xi=vs[i].lat, yi=vs[i].lng; var xj=vs[j].lat, yj=vs[j].lng; var intersect = ((yi>y)!=(yj>y)) && (x < (xj-xi)*(y-yi)/(yj-yi)+xi); if(intersect) inside = !inside; } return inside; }
// --- Geocoder ---
L.Control.geocoder({position:'topleft', defaultMarkGeocode:true, placeholder:"Suche ..."}).addTo(map);
// --- Farben für Nutzungen ---
var nutzungColors = {
'Hof':'red', 'Mühle':'blue', 'Fabrik':'black', 'Gewerbe':'gray', 'Verwaltung':'orange', 'Bahn':'brown', 'Brücke':'navy', 'Hafen':'blue', 'Flughafen':'green', 'Versorgung':'gray', 'Tankstelle':'maroon', 'Brauerei':'yellow', 'Ziegelei':'red', 'Kloster':'orange', 'Kirche':'purple', 'Synagoge':'violet', 'Krankenhaus':'red', 'Friedhof':'green', 'Hochbunker':'black', 'Militär':'green', 'Äußerer Festungsring 1873-1914':'red', 'Stadtumwallung 1882-1891':'orange', 'Umwallung Deutz 1818-1840':'gray', 'Innerer Festungsring 1816-1873':'navy', 'Enceinte 1815-1829':'yellow', 'Bastionen 1632-1689':'gray', 'Umwallung Mülheim 1588-1614':'darkblue', 'Umwallung Worringen':'purple', 'Stadtmauer 1180-1259':'maroon', 'Stadterweiterung 1106-1141':'lightblue', 'Stadterweiterung 950':'cyan', 'Römische Befestigung':'blue', 'Wohnen':'brown', 'Schule':'red', 'Freizeit':'green'
};
// --- WMS-Historische Karten ---
var wmsDOP2010 = L.tileLayer.wms("https://www.wms.nrw.de/geobasis/wms_nw_hist_dop",{layers:"nw_hist_dop_2010",format:"image/png",transparent:true,opacity:0.6,attribution:"Orthophoto 2010"});
var wmsDOP1998 = L.tileLayer.wms("https://www.wms.nrw.de/geobasis/wms_nw_hist_dop",{layers:"nw_hist_dop_1998",format:"image/png",transparent:true,opacity:0.6,attribution:"Orthophoto 1998"});
var wmsDOP1987 = L.tileLayer.wms("https://www.wms.nrw.de/geobasis/wms_nw_hist_dop",{layers:"nw_hist_dop_1987",format:"image/png",transparent:true,opacity:0.6,attribution:"Orthophoto 1987"});
var wmsDOP1981 = L.tileLayer.wms("https://www.wms.nrw.de/geobasis/wms_nw_hist_dop",{layers:"nw_hist_dop_1981",format:"image/png",transparent:true,opacity:0.6,attribution:"Orthophoto 1981"});
var wmsDOP1951 = L.tileLayer.wms("https://www.wms.nrw.de/geobasis/wms_nw_hist_dop",{layers:"nw_hist_dop_1951",format:"image/png",transparent:true,opacity:0.6,attribution:"Orthophoto 1951"});
var wmsMeyer = L.tileLayer("https://mapwarper.net/maps/tile/39790/{z}/{x}/{y}.png",{opacity:0.6, attribution:"Meyers Stadtplan 1900"});
var wmsKataster1836 = L.tileLayer("https://mapwarper.net/maps/tile/99312/{z}/{x}/{y}.png",{opacity:0.6, attribution:"Kataster 1836"});
var wmsKoeln1830 = L.tileLayer("https://mapwarper.net/maps/tile/101214/{z}/{x}/{y}.png",{opacity:0.6, attribution:"Köln 1830"});
var wmsVogtPicquet = L.tileLayer("https://mapwarper.net/maps/tile/39826/{z}/{x}/{y}.png",{opacity:0.6, attribution:"Vogt/Picquet 1815"});
var wmsNeuaufnahme = L.tileLayer.wms("https://www.wms.nrw.de/geobasis/wms_nw_neuaufnahme",{layers:"nw_neuaufnahme",format:"image/png",transparent:true,opacity:0.6,attribution:"Neuaufnahme 1891-1912"});
var wmsUraufnahme = L.tileLayer.wms("https://www.wms.nrw.de/geobasis/wms_nw_uraufnahme",{layers:"nw_uraufnahme_rw",format:"image/png",transparent:true,opacity:0.6,attribution:"Uraufnahme 1836-1850"});
var wmsTranchot = L.tileLayer.wms("https://www.wms.nrw.de/geobasis/wms_nw_tranchot",{layers:"nw_tranchot",format:"image/png",transparent:true,opacity:0.6,attribution:"Tranchot 1801-1828"});
var wmsStockdale = L.tileLayer("https://mapwarper.net/maps/tile/39780/{z}/{x}/{y}.png",{opacity:0.6, attribution:"Stockdale 1800"});
var wmsReinhardt = L.tileLayer("https://mapwarper.net/maps/tile/41691/{z}/{x}/{y}.png",{opacity:0.6, attribution:"Reinhardt 1752"});
var wmsMerian = L.tileLayer("https://mapwarper.net/maps/tile/39783/{z}/{x}/{y}.png",{opacity:0.6, attribution:"Merian 1641"});
var wmsMercator = L.tileLayer("https://mapwarper.net/maps/tile/40952/{z}/{x}/{y}.png",{opacity:0.6, attribution:"Mercator 1571"});
// --- GeoJSON Layer ---
var geojsonLayer = L.geoJSON(null, {
renderer: L.canvas(),
style: function(feature){
return { color: nutzungColors[feature.properties.Nutzung] || "black", weight: 2, fillOpacity:0.4 };
}
}).addTo(map);
var highlightedLayers = [];
// --- GeoJSON laden ---
fetch('/alteskoeln/WasWarWo.geojson')
.then(res => res.json())
.then(data => {
geojsonLayer.addData(data);
buildLayerbox(data); // dynamische Layerbox für Gruppen & Nutzungen
});
// --- Klick auf Polygon ---
map.on('click', function(e){ var clickedFeatures = [];
// alte Highlights zurücksetzen highlightedLayers.forEach(layer => geojsonLayer.resetStyle(layer)); highlightedLayers = [];
geojsonLayer.eachLayer(function(layer){ if(!map.hasLayer(layer)) return; // nur sichtbare Features
if(layer instanceof L.Polygon && pointInLayer(e.latlng, layer)){ clickedFeatures.push(layer.feature.properties); highlightedLayers.push(layer); layer.setStyle({fillColor:'yellow', color:"cyan", weight:4, fillOpacity:0.6}); } });
if(clickedFeatures.length > 0){ showPopup(clickedFeatures, e.latlng);
// --- nach 2 Sekunden alle Highlights zurücksetzen --- setTimeout(function(){ highlightedLayers.forEach(layer => geojsonLayer.resetStyle(layer)); highlightedLayers = []; }, 2000); // 2000ms = 2 Sekunden } });
function showPopup(features, latlng){
var content = "
if(features.length > 1){
content += " }
features.forEach(function(props){
var name = props.Name||"Unbekannt";
var nutzung = props.Nutzung||"-";
var von = props.von||"?";
var bis = props.bis||"?";
var info = props.Info||"";
var bild = props.Bild ? '<a href="'+props.Bild+'" target="_blank"><img src="'+props.Bild+'" loading="lazy" style="width:100%;max-height:180px;object-fit:cover;border-radius:6px;margin-top:6px;"></a>' : ;
var link = props.Link ? '
<a href="'+props.Link+'" target="_blank" style="color:blue;font-size:1em;">➔ Mehr Infos</a>' : ;
content += """+name+""
"+nutzung+"
"+ "Zeit: "+von+" bis "+bis+"
"+
"+info+"
"+bild+link+"});content += "
";
L.popup({maxWidth: window.innerWidth<600?300:400, minWidth:window.innerWidth<600?220:250, autoPanPadding:[20,20]})
.setLatLng(latlng)
.setContent(content)
.openOn(map);
// Zoom auf alle ausgewählten Flächen
var group = L.featureGroup(highlightedLayers);
map.fitBounds(group.getBounds(), {padding:[40,40], maxZoom:17});
}
// --- Punkt-in-Polygon ---
function pointInLayer(latlng, layer){
var lat = latlng.lat, lng = latlng.lng;
var polys = layer.getLatLngs();
if(layer.feature.geometry.type==="MultiPolygon"){
return polys.some(polyPart => insidePolygon([lat,lng], polyPart[0]));
}
return insidePolygon([lat,lng], polys[0]);
}
function insidePolygon(point, vs){
var x=point[0], y=point[1], inside=false;
for(var i=0,j=vs.length-1;i<vs.length;j=i++){
var xi=vs[i].lat, yi=vs[i].lng;
var xj=vs[j].lat, yj=vs[j].lng;
var intersect = ((yi>y)!=(yj>y)) && (x < (xj-xi)*(y-yi)/(yj-yi)+xi);
if(intersect) inside = !inside;
}
return inside;
}
// --- Layerbox & Suche ---
function buildLayerbox(data){ var div = L.DomUtil.create('div','layerbox'); div.innerHTML = `
☰ Layer
<input type="text" id="searchName" placeholder="Suche nach Name ..." class="search-input"> Historische Orte
▶ Historische Karten
`; L.DomEvent.disableClickPropagation(div); layerBox = L.control({position:'topright'}); layerBox.onAdd = function(){ return div; }; layerBox.addTo(map);
// --- dynamische Gruppen & Nutzungen --- var gruppenDiv = document.getElementById('gruppen'); var groups = {}; data.features.forEach(f => { if(!groups[f.properties.Gruppe]) groups[f.properties.Gruppe] = {}; if(!groups[f.properties.Gruppe][f.properties.Nutzung]) groups[f.properties.Gruppe][f.properties.Nutzung] = 0; groups[f.properties.Gruppe][f.properties.Nutzung]++; });
for (var g in groups) { var gDiv = document.createElement('div');
// Flex-Container für Pfeil + Name + Gruppen-Checkbox gDiv.innerHTML = `
▶ ${g} <input type="checkbox" class="groupToggle" data-gruppe="${g}" checked>
`;
// Untercontainer für alle Nutzungen der Gruppe var inner = document.createElement('div'); inner.id = `g_${g}`; inner.style.marginLeft = "20px"; inner.style.display = "none"; // start geschlossen
for (var n in groups[g]) {
var color = nutzungColors[n] || "black";
inner.innerHTML += `<label style="color:black; display:flex; align-items:center; gap:4px;">
<input type="checkbox" class="layerNutzung" data-gruppe="${g}" data-nutzung="${n}" checked>
${n} (${groups[g][n]})
</label>
`;
}
gDiv.appendChild(inner); gruppenDiv.appendChild(gDiv); }
// Pfeil-Event separat, nur Pfeil klickbar document.querySelectorAll('.groupArrow').forEach(arrow => { arrow.addEventListener('click', function() { var targetId = this.dataset.target; var el = document.getElementById(targetId); if (!el) return;
var isHidden = (el.style.display === "none"); el.style.display = isHidden ? "block" : "none";
// Pfeil wechseln this.textContent = isHidden ? "▼" : "▶"; }); });
// --- Gruppen-Checkbox Event --- document.querySelectorAll('.groupToggle').forEach(cb => { cb.addEventListener('change', function(){ var gruppe = this.dataset.gruppe; var checked = this.checked; geojsonLayer.eachLayer(layer => { if(layer.feature.properties.Gruppe === gruppe){ if(checked) map.addLayer(layer); else map.removeLayer(layer); } }); // Auch Nutzung-Checkboxen aktualisieren document.querySelectorAll(`.layerNutzung[data-gruppe="${gruppe}"]`).forEach(nutzCb => { nutzCb.checked = checked; }); }); });
// --- Einzelne Nutzung Checkbox Event --- document.querySelectorAll('.layerNutzung').forEach(cb => { cb.addEventListener('change', function(){ var gruppe = this.dataset.gruppe; var nutzung = this.dataset.nutzung; geojsonLayer.eachLayer(layer => { if(layer.feature.properties.Gruppe===gruppe && layer.feature.properties.Nutzung===nutzung){ if(cb.checked) map.addLayer(layer); else map.removeLayer(layer); } }); // Gruppen-Checkbox anpassen var allChecked = Array.from(document.querySelectorAll(`.layerNutzung[data-gruppe="${gruppe}"]`)).every(nutzCb => nutzCb.checked); document.querySelector(`.groupToggle[data-gruppe="${gruppe}"]`).checked = allChecked; }); });
// --- Suche nach Name (gelb) --- document.getElementById('searchName').addEventListener('input', function(){ var val = this.value.toLowerCase(); highlightedLayers.forEach(layer => geojsonLayer.resetStyle(layer)); highlightedLayers = []; if(val === "") return; geojsonLayer.eachLayer(layer => { if(layer.feature.properties.Name && layer.feature.properties.Name.toLowerCase().includes(val)){ layer.setStyle({color:'yellow', weight:4, fillOpacity:0.6}); highlightedLayers.push(layer); } }); if(highlightedLayers.length){ map.fitBounds(L.featureGroup(highlightedLayers).getBounds(), {padding:[40,40], maxZoom:17}); } });
// --- Historische Karten Layer Toggle --- document.addEventListener('change', function(e){ if(e.target.id==="layerDOP2010") toggleLayer(wmsDOP2010,e.target.checked); if(e.target.id==="layerDOP1998") toggleLayer(wmsDOP1998,e.target.checked); if(e.target.id==="layerDOP1987") toggleLayer(wmsDOP1987,e.target.checked); if(e.target.id==="layerDOP1981") toggleLayer(wmsDOP1981,e.target.checked); if(e.target.id==="layerDOP1951") toggleLayer(wmsDOP1951,e.target.checked); if(e.target.id==="layerMeyer") toggleLayer(wmsMeyer,e.target.checked); if(e.target.id==="layerKataster1836") toggleLayer(wmsKataster1836,e.target.checked); if(e.target.id==="layerKoeln1830") toggleLayer(wmsKoeln1830,e.target.checked); if(e.target.id==="layerVogtPicquet") toggleLayer(wmsVogtPicquet,e.target.checked); if(e.target.id==="layerStockdale") toggleLayer(wmsStockdale,e.target.checked); if(e.target.id==="layerReinhardt") toggleLayer(wmsReinhardt,e.target.checked); if(e.target.id==="layerMerian") toggleLayer(wmsMerian,e.target.checked); if(e.target.id==="layerMercator") toggleLayer(wmsMercator,e.target.checked); if(e.target.id==="layerNeuaufnahme") toggleLayer(wmsNeuaufnahme,e.target.checked); if(e.target.id==="layerUraufnahme") toggleLayer(wmsUraufnahme,e.target.checked); if(e.target.id==="layerTranchot") toggleLayer(wmsTranchot,e.target.checked); });
function toggleLayer(layer,visible){ if(visible) map.addLayer(layer); else map.removeLayer(layer); }
// --- Transparenzregler --- var opacitySlider = document.getElementById('opacitySlider'); var historicalLayers = [ wmsDOP2010, wmsDOP1998, wmsDOP1987, wmsDOP1981, wmsDOP1951, wmsMeyer, wmsKataster1836, wmsKoeln1830, wmsVogtPicquet, wmsStockdale, wmsReinhardt, wmsMerian, wmsMercator, wmsNeuaufnahme, wmsUraufnahme, wmsTranchot ]; opacitySlider.addEventListener('input', function(){ var value = this.value / 100; historicalLayers.forEach(layer => { if(map.hasLayer(layer)) layer.setOpacity(value); else layer.options.opacity = value; }); }); }
// --- Toggle-Funktion mit Pfeil ▶ / ▼ --- function toggleGroup(id){ var el = document.getElementById(id); if(!el) return; var isHidden = (el.style.display==="none"); el.style.display = isHidden ? "block" : "none"; var bTag = el.previousElementSibling; if(bTag){ bTag.innerHTML = (isHidden ? "▼ " : "▶ ") + bTag.textContent.slice(2); } }
</script> </body> </html>
