asphalt.netzecke.de/README.md
2025-05-29 19:15:17 +02:00

208 lines
5.1 KiB
Markdown
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 🗺️ GeoTIFF-Viewer Dokumentation
## Ziel
Interaktive Visualisierung von **GeoTIFF-Dateien** mit Farbcodierung und zusätzlichen **GeoJSON-Overlays** (z.B. Stadtgrenzen). Die Anwendung basiert auf Leaflet und ist per Docker containerisiert.
---
## Projektstruktur
```bash
geotiff-viewer/
├── data/
│ ├── class_Mainz_maxlike_gold.tif # GeoTIFF Rasterdaten
│ ├── stadtgrenze.geojson # GeoJSON für Overlay (z.B. Stadtgrenzen)
│ └── index.html # Weboberfläche mit Leaflet + GeoRaster
└── docker-compose.yaml # Nginx-Container zur Bereitstellung
```
---
## Anforderungen
- Docker
- Nginx Proxy Manager zur Weiterleitung via Subdomain
---
## Docker-Setup
```yaml
services:
geotiff-viewer:
image: nginx:alpine
container_name: geotiff-viewer
restart: unless-stopped
volumes:
- ./data:/usr/share/nginx/html:ro
networks:
- npm-network
networks:
npm-network:
external: true
```
---
## Weboberfläche (`index.html`)
### Funktionen
- Anzeige des GeoTIFFs als farbige Heatmap mittels [chroma.js](https://gka.github.io/chroma.js/)
- Einblendung zusätzlicher GeoJSON-Layer
- Legende mit Farbskala & Layer-Steuerung
- Lizenzhinweis im Footer
### HTML-Code
```html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>GeoTIFF Viewer</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="https://unpkg.com/leaflet/dist/leaflet.css" />
<style>
html, body, #map { height: 100%; margin: 0; padding: 0; }
.legend {
position: absolute;
bottom: 20px;
right: 20px;
background: white;
padding: 10px;
border-radius: 5px;
font-family: sans-serif;
font-size: 12px;
line-height: 1.2;
box-shadow: 0 0 5px rgba(0,0,0,0.3);
}
.legend-gradient {
height: 10px;
width: 200px;
background: linear-gradient(to right, #440154, #3b528b, #21918c, #5ec962, #fde725);
margin-bottom: 5px;
}
.legend-labels {
display: flex;
justify-content: space-between;
}
</style>
</head>
<body>
<div id="map"></div>
<div class="legend">
<div class="legend-gradient"></div>
<div class="legend-labels">
<span id="min-val">min</span>
<span id="max-val">max</span>
</div>
</div>
<script src="https://unpkg.com/leaflet/dist/leaflet.js"></script>
<script src="https://unpkg.com/georaster"></script>
<script src="https://unpkg.com/georaster-layer-for-leaflet"></script>
<script src="https://unpkg.com/chroma-js/chroma.min.js"></script>
<script>
const map = L.map("map").setView([50.0, 8.25], 10);
// Basiskarte
const baseLayer = L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", {
attribution: "© OpenStreetMap contributors"
}).addTo(map);
const overlayLayers = {};
// GeoTIFF laden
fetch("class_Mainz_maxlike_gold.tif")
.then(response => response.arrayBuffer())
.then(tiffData => {
parseGeoraster(tiffData).then(georaster => {
const min = georaster.mins[0];
const max = georaster.maxs[0];
const colorScale = chroma.scale("viridis").domain([min, max]);
document.getElementById("min-val").textContent = min.toFixed(2);
document.getElementById("max-val").textContent = max.toFixed(2);
const geotiffLayer = new GeoRasterLayer({
georaster: georaster,
pixelValuesToColorFn: values => {
const val = values[0];
if (val === null || isNaN(val)) return null;
return colorScale(val).alpha(0.7).css();
},
resolution: 64
});
geotiffLayer.addTo(map);
map.fitBounds(geotiffLayer.getBounds());
overlayLayers["GeoTIFF Heatmap"] = geotiffLayer;
});
});
// GeoJSON laden
fetch("stadtgrenze.geojson")
.then(response => response.json())
.then(geojson => {
const geojsonLayer = L.geoJSON(geojson, {
style: {
color: "blue",
weight: 2
},
onEachFeature: (feature, layer) => {
if (feature.properties?.name) {
layer.bindPopup(feature.properties.name);
}
}
}).addTo(map);
overlayLayers["Stadtgrenze"] = geojsonLayer;
});
// Layer-Steuerung hinzufügen
setTimeout(() => {
L.control.layers({ "OpenStreetMap": baseLayer }, overlayLayers, { collapsed: false }).addTo(map);
}, 1000);
</script>
<div style="
position: absolute;
bottom: 0;
left: 0;
width: 100%;
background: rgba(255,255,255,0.8);
text-align: center;
font-size: 11px;
font-family: sans-serif;
padding: 3px 6px;
z-index: 999;
">
©GeoBasis-DE / LVermGeoRP 2025, dl-de/by-2-0, <a href="https://www.lvermgeo.rlp.de" target="_blank">www.lvermgeo.rlp.de</a> [Daten bearbeitet]
</div>
</body>
</html>
```
### Overlays
```json
{
"type": "FeatureCollection",
"features": [{
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [[[8.20, 50.00], [8.30, 50.00], [8.30, 50.05], [8.20, 50.05], [8.20, 50.00]]]
},
"properties": {
"name": "Stadtgrenze Mainz"
}
}]
}
```
---