No description
Find a file
2025-05-29 19:15:17 +02:00
data Daten befuellen 2025-05-29 19:10:09 +02:00
docker-compose.yaml Daten befuellen 2025-05-29 19:10:09 +02:00
README.md README 2025-05-29 19:15:17 +02:00

🗺️ 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

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

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
  • Einblendung zusätzlicher GeoJSON-Layer
  • Legende mit Farbskala & Layer-Steuerung
  • Lizenzhinweis im Footer

HTML-Code

<!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

{
  "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"
    }
  }]
}