<?xml version="1.0" encoding="utf-8"?><?xml-stylesheet type="text/xsl" href="atom.xsl"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <id>https://geodaten-guerilla.net/blog</id>
    <title>GeoDatenGuerilla Blog</title>
    <updated>2025-12-25T00:00:00.000Z</updated>
    <generator>https://github.com/jpmonette/feed</generator>
    <link rel="alternate" href="https://geodaten-guerilla.net/blog"/>
    <subtitle>GeoDatenGuerilla Blog</subtitle>
    <icon>https://geodaten-guerilla.net/img/gdg_favicon.ico</icon>
    <entry>
        <title type="html"><![CDATA[MapLibre mit WebGIS-Funktionen]]></title>
        <id>https://geodaten-guerilla.net/blog/maplibre-plugins-strassenraumkarte</id>
        <link href="https://geodaten-guerilla.net/blog/maplibre-plugins-strassenraumkarte"/>
        <updated>2025-12-25T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Eine MapLibre-Karte lässt sich mit verschiedenen Plugins mit WebGIS-Funktionen (Legende, Messen, Druckexport, Zeichnen, Info-Ausgabe) ausstatten.]]></summary>
        <content type="html"><![CDATA[<p>Vor einem Jahr habe ich gezeigt, wie sich mit <a href="https://maplibre.org/" target="_blank" rel="noopener noreferrer">MapLibre</a> und Open Data eine <a href="https://geodaten-guerilla.net/blog/strassenraumaufteilung-online-karte">3D-Karte mit der Straßenraumaufteilung in Kiel</a> erstellen lässt. Die <a href="https://geodaten-guerilla.net/maps/strassenraumaufteilung-kiel/" target="_blank" rel="noopener noreferrer">Online-Karte</a> hat sich seitdem stark weiterentwickelt. Statt grauer Boxen als Gebäude (LoD1) und Straßendaten eingebunden als langsamer WMS-Dienst bietet die Karte nun bessere 3D-Visualisierungen der Gebäude (LoD2), Mess- und Malwerkzeuge, Druckmöglichkeiten, eine Legende, Druckfunktionen, Bäume und eine bessere Performance durch VectorTiles. Damit bietet die Karte nun die grundlegenden Funktionen, die mensch von einem WebGIS erwartet. Durch das hinzugefügten Malwerkzeug lassen sich nun auch Straßenflächen in die Karte zeichnen, wodurch sich veränderte Straßenräume visualisieren lassen.</p>
<p>Auf der Code-Basis der Straßenraumkarte habe ich die <a href="https://geodaten-guerilla.net/maps/autobahn-20/" target="_blank" rel="noopener noreferrer">A20-Karte</a>, ohne 3D-Funktionalität, von <a href="https://mapbender.org/" target="_blank" rel="noopener noreferrer">Mapbender</a> auf MapLibre umgestellt. DIe Karte zur <a href="https://www.bielenbergkoppel.de/" target="_blank" rel="noopener noreferrer">Südspange in Kiel</a> habe ich in dem Zuge deaktiviert, da die Planungen an diesem unsinnigem Autobahnprojekt weiter vorangeschritten sind und die Südspange dadurch vorerst <a href="https://www.bielenbergkoppel.de/blog/deges-gutachten-suedspange.html" target="_blank" rel="noopener noreferrer">gestorben</a> ist (leider nicht auch der A21-Ausbau im Vieburger Gehölz).</p>
<p>In diesem Blogpost möchte ich am Beispiel der <a href="https://geodaten-guerilla.net/maps/strassenraumaufteilung-kiel/" target="_blank" rel="noopener noreferrer">Straßenraumkarte</a> den Code für eine MapLibre-Karte mit den entsprechenden Daten, 3D-Funktionen, Mess- und Malwerkzeug, Druckmöglichkeit, Legende und Druckfunktion vorstellen. Außerdem zeige ich, welche Datengrundlagen und welche Software für die Karte benötigt werden. Natürlich komplett Open Data und Open Source :)</p>
<p><img decoding="async" loading="lazy" alt="Es ist ein Screenshot zu sehen, der den Bereich Westring / Eckernförder Straße / Geibelplatz in Kiel zeigt. Bei den Straßen sind die verschiedenen Typen des Straßenraums (Gehweg, Radweg, Fahrbahn etc.) farblich hervorgehoben. Die Gebäude und Bäume sind in 3D." src="https://geodaten-guerilla.net/assets/images/maplibre-screenshot-strassenraum-prof-peters-platz-d64626bf512692d6332a1d04c002f45c.png" title="Westring, Eckernförder Straße und Geibelplatz in Kiel mit Aufteilung des Straßenraums." width="1918" height="1349" class="img_ev3q"></p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="datengrundlagen">Datengrundlagen<a href="https://geodaten-guerilla.net/blog/maplibre-plugins-strassenraumkarte#datengrundlagen" class="hash-link" aria-label="Direkter Link zur Datengrundlagen" title="Direkter Link zur Datengrundlagen">​</a></h2>
<p>Für eine Karte braucht es Geodaten. Um die Straßenraumkarte in ihrem derzeitigen Stand zu reproduzieren werden folgende Geodaten benötigt:</p>
<ul>
<li>Die Straßenraumaufteilung in Kiel</li>
<li>Bäume in Kiel</li>
<li>3D-Gebäude</li>
<li>eine Basemap</li>
</ul>
<p>Die Straßenraumaufteilung und die Bäume in Kiel lassen sich von der Stadt Kiel beschaffen. Im <a href="https://sh-mis.gdi-sh.de/" target="_blank" rel="noopener noreferrer">Schleswig-Holsteinischen Metainformationssystem (SH-MIS)</a> finden sich die Geodaten, die die Stadt Kiel als Open Data zur Verfügung stellt. In den <a href="https://sh-mis.gdi-sh.de/smartfinder-sdi/?lang=de#/datasets/iso/7ccb4026-11ad-4173-a47a-a07ad06e80b8" target="_blank" rel="noopener noreferrer">Geodaten der Stadt Kiel</a> finden sich, neben den einzelnen Datensätzen, sowohl ein WMS- als auch ein WFS-Dienst mit sämtlichen Datensätzen. Ich nutze aus dem WFS-Dienst (<a href="https://ims.kiel.de/geodatenextern/services/Stadtplan/LHKielWmsWfs/MapServer/WFSServer?request=GetCapabilities&amp;service=WFS" target="_blank" rel="noopener noreferrer">https://ims.kiel.de/geodatenextern/services/Stadtplan/LHKielWmsWfs/MapServer/WFSServer?request=GetCapabilities&amp;service=WFS</a>) die Datensätze <em>Strassenbestandsflaechen</em> für die Straßenraumaufteilung und <em>Baeume</em> für die Bäume. Zu letzterem sei gesagt, dass es sich hierbei nur um erfasste Bäume auf städtischem Grund handelt. Die Daten stehen unter der Lizenz CC BY 4.0. Zur Datenqualität der Straßenraumaufteilung habe ich bereits <a href="https://geodaten-guerilla.net/blog/strassenraumaufteilung-online-karte#stra%C3%9Fenraum">im letzten Blogpost</a> eine Einschätzung abgegeben. Auch wie ich die Datensätze in VectorTiles konvertierte habe ich <a href="https://geodaten-guerilla.net/blog/strassenraumaufteilung-online-karte#konvertierung-zu-mbtiles">bereits beschrieben</a>.</p>
<p>Sowohl die Basemap als auch die 3D-Gebäude beziehe ich aus der selben Quelle. Die <a href="https://basemap.de/produkte-und-dienste/3d/" target="_blank" rel="noopener noreferrer">basemap.de</a> enthält nämlich beides. Es gibt sogar Code-Beispiele für funktionierende 3D-Karten mit MapLibre und Cesium. Ich habe den Code für <em>LoD2-MapLibre</em> als Ausgangspunkt für die Kartenerstellung genutzt.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="software">Software<a href="https://geodaten-guerilla.net/blog/maplibre-plugins-strassenraumkarte#software" class="hash-link" aria-label="Direkter Link zur Software" title="Direkter Link zur Software">​</a></h2>
<p>Um die Kartenanwendung zu betreiben, werden drei Komponenten benötigt:</p>
<ul>
<li><a href="https://github.com/consbio/mbtileserver" target="_blank" rel="noopener noreferrer">mbtileserver</a> als Tileserver</li>
<li><a href="https://maplibre.org/maputnik/" target="_blank" rel="noopener noreferrer">maputnik</a> zur Erstellung von MapLibre-Styles</li>
<li><a href="https://maplibre.org/" target="_blank" rel="noopener noreferrer">MapLibre</a> für die eigentliche Karte</li>
</ul>
<p>Die Nutzung von <em>mbtileserver</em> habe ich <a href="https://geodaten-guerilla.net/blog/strassenraumaufteilung-online-karte#tileserver">bereits beschrieben</a>. In <em>mbtileserver</em> lade ich die VectorTiles der Straßenraumaufteilung und der Bäume. Mit Maputnik erstelle ich nun einen Style, der die basemap.de, die Straßenraumaufteilung und die Bäume enthält (dieser lässt sich <a href="https://geodaten-guerilla.net/downloads/Strassenraumaufteilung-Kiel/basemap_de/strassenraumaufteilung-basemap.json" target="_blank" rel="noopener noreferrer">hier</a> herunterladen). Diese Herangehensweise spart Code, da so nicht jeder einzelne Layer im Code eingebunden und gestyled werden muss. <a href="https://geodaten-guerilla.net/blog/strassenraumaufteilung-online-karte#hintergrundkarte">Die Bedienung von Maputnik habe ich auch bereits angeschnitten</a>. Bei der Darstellung der Bäume habe ich mich eines Tricks bedient, da mir keine 3D-Modelle zur Verfügung standen.</p>
<p><img decoding="async" loading="lazy" alt="Es ist ein sehr nah reingezoomter Kartenausschnitt mit einfacher 3D-Darstellung von Bäumen dargestellt." src="https://geodaten-guerilla.net/assets/images/maplibre-baeume-darstellungstrick-a82dfc10fb82ebe6ed2327dc93339a73.png" title="Einfache 3D-Bäume." width="830" height="575" class="img_ev3q"></p>
<p>Ich habe mit <a href="https://qgis.org/" target="_blank" rel="noopener noreferrer">QGIS</a> einen dünnen Buffer für die Stämme und einen breiten Buffer für die Kronen erstellt und in VectorTiles konvertiert. In Maputnik gebe ich beiden eine Extrusion und setze die Krone in die Luft. So entsteht die Illusion eines 3D-Objekts.</p>
<p>Mit <em>MapLibre</em> wird die eigentliche Kartenanwendung erstellt. Um die zusätzlichen Funktionen, wie Legende, Export oder Messungen, umzusetzen, nutze ich mehrere <a href="https://maplibre.org/maplibre-gl-js/docs/plugins/" target="_blank" rel="noopener noreferrer">Plugins</a>:</p>
<ul>
<li><a href="https://github.com/watergis/maplibre-gl-area-switcher" target="_blank" rel="noopener noreferrer">maplibre-gl-area-switcher</a> um zu vordefinierten Gebieten springen zu können.</li>
<li><a href="https://github.com/watergis/maplibre-gl-export" target="_blank" rel="noopener noreferrer">maplibre-gl-export</a> um Druck-/Exportfunktion anzubieten.</li>
<li><a href="https://github.com/watergis/maplibre-gl-legend" target="_blank" rel="noopener noreferrer">maplibre-gl-legend</a> für eine Legende und um Layer ein-/auszuschalten.</li>
<li><a href="https://github.com/watergis/maplibre-gl-terradraw" target="_blank" rel="noopener noreferrer">maplibre-gl-terradraw</a> und <a href="https://github.com/JamesLMilner/terra-draw" target="_blank" rel="noopener noreferrer">terra-draw</a>, um eine Zeichnenfunktion zu ermöglichen.</li>
<li><a href="https://github.com/jdsantos/maplibre-gl-measures" target="_blank" rel="noopener noreferrer">maplibre-gl-measures</a> ist ein Messwerkzeug.</li>
</ul>
<p>Den Code mit den Plugins zeige ich unten.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="der-code">Der Code<a href="https://geodaten-guerilla.net/blog/maplibre-plugins-strassenraumkarte#der-code" class="hash-link" aria-label="Direkter Link zur Der Code" title="Direkter Link zur Der Code">​</a></h2>
<p>Ich werde an dieser Stelle einzelne Teile aus dem Code der <a href="https://geodaten-guerilla.net/maps/strassenraumaufteilung-kiel/" target="_blank" rel="noopener noreferrer">Kartenanwendung</a> vorstellen. Der gesamte Code befindet sich am Ende des Blogposts. In diesem befinden sich nämlich auch das CSS für die Gestaltung der Kartenanwendung und Funktionen für eine Mobilansicht, mit denen ich nicht große Lücken in den Fließtext reißen möchte. Zur Transparenz möchte ich noch anmerken, dass ich für die Code-Erstellung auf KI zurückgegriffen habe. Mir ist KI beim coden eine sehr große Hilfe. Mir sind die negativen Folgen von KI bewusst.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="die-grundfunktionen">Die Grundfunktionen<a href="https://geodaten-guerilla.net/blog/maplibre-plugins-strassenraumkarte#die-grundfunktionen" class="hash-link" aria-label="Direkter Link zur Die Grundfunktionen" title="Direkter Link zur Die Grundfunktionen">​</a></h3>
<p>Folgender Code-Schnipsel ermöglicht bereits die Darstellung einer grundlegenden Kartenanwendung. In dieser lässt sich scrollen, reinzoomen und der Blickwinkel ändern. Die 3D-Inhalte werden auch angezeigt. Oben werden Grenzen definiert, in denen sich der Kartenausschnitt bewegen lässt. Unter <em>style</em> ist der <a href="https://geodaten-guerilla.net/blog/maplibre-plugins-strassenraumkarte#software">oben beschriebene</a> <em>Maputnik</em>-Stil eingefügt. Dadurch wird Code gespart, da nicht jeder einzelne Layer im Code eingebunden wird. Unten werden noch Navigationsbuttons und eine dynamische Maßstableiste hinzugefügt. Die 3D-Gebäude werden auf dem selben Weg eingebunden, wie es auf <a href="https://basemap.de/produkte-und-dienste/3d/" target="_blank" rel="noopener noreferrer">basemap.de</a> beschrieben wird.</p>
<div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">//////////// Basemap einbinden und Karte generieren ////////////</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">// Grenzen, innerhalb derer die Karte verschoben werden kann, festlegen</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">const bounds = [</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">[9.44955, 53.7632],</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">[10.7106, 54.6175]</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">]; </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">// Basemap und Karte laden</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">const map = new maplibregl.Map({</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    container: 'map',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    style: 'tiles/strassenraumaufteilung-basemap.json',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    center: [10.131885, 54.315275],</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    zoom: 14,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    maxPitch: 80,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    attributionControl: true,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    hash: true,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    maxBounds: bounds,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    preserveDrawingBuffer: true,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">});</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">//////////// 3D-Gebäude hinzufügen ////////////</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">if (window.innerWidth &gt; 768) {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    map.on('style.load', function () {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      let lod2_layer = new Mapbox3DTiles.Mapbox3DTilesLayer({</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        id: 'lod2_building',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        url: 'https://sg.geodatenzentrum.de/gdz_basemapde_3d_gebaeude/lod2_3857_null.json',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        colorWall: '#c2c2c2',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        colorRoof: '#ff5c4d',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        colorBridge: '#999999'</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      });</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      map.addLayer(lod2_layer, 'Gebaeude3D_nicht_oeffentlich');</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      map.setLayoutProperty('Gebaeude3D_oeffentlich', 'visibility', 'none');</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      map.setLayoutProperty('Gebaeude3D_nicht_oeffentlich', 'visibility', 'none');</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      map.setLayoutProperty('Hauskoordinate', 'visibility', 'none');</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    });</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">}</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">// Gebäude erst ab Zoom 16 anzeigen</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">let lod2Visible = false;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">map.on('zoomend', () =&gt; {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    const zoom = map.getZoom();</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    const shouldBeVisible = zoom &gt;= 16;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    if (shouldBeVisible !== lod2Visible) {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      map.setLayoutProperty('lod2_building', 'visibility', shouldBeVisible ? 'visible' : 'none');</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      lod2Visible = shouldBeVisible;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">});</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">//////////// Vollbild-Button hinzufügen ////////////</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">map.addControl(new maplibregl.FullscreenControl(), 'top-right',);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">//////////// Navigationsbuttons hinzufügen ////////////</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">map.addControl(new maplibregl.NavigationControl({</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    visualizePitch: true,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    visualizeRoll: true,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    showZoom: true,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    showCompass: true,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    zoomInTitle: 'Hineinzoomen',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    zoomOutTitle: 'Herauszoomen',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    compassTitle: 'Nach Norden ausrichten'</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">}),</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">'top-right'</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">//////////// Maßstableiste hinzufügen ////////////</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">map.addControl(</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	new maplibregl.ScaleControl({</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		maxWidth: 150, // maximale Breite in Pixel</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		unit: 'metric' // 'imperial' für Meilen/Fuß</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	}),</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">'bottom-left' // Position der Maßstableiste</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">);</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="In die Zwischenablage kopieren" title="Kopieren" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="legende">Legende<a href="https://geodaten-guerilla.net/blog/maplibre-plugins-strassenraumkarte#legende" class="hash-link" aria-label="Direkter Link zur Legende" title="Direkter Link zur Legende">​</a></h3>
<p>Mit dem Plugin <a href="https://github.com/watergis/maplibre-gl-legend" target="_blank" rel="noopener noreferrer">maplibre-gl-legend</a> wird eine Legende eingefügt, mit der sich auch einzelne Layer ein- und ausschalten lassen. Wichtig ist, die in der Legende anzuzeigenden Layer zu definieren. Denn allein durch die basemap.de sind technisch gesehen sehr viele Layer in der Karte untergebracht. Die Layernamen sind diejenigen, die in Maputnik definiert wurden.</p>
<div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">//////////// Legende hinzufügen ////////////</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">// Legenden-Einträge definieren</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">map.on('load', function() {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    const targets = {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        // Layername: Anzeigename</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        'Baumstämme': 'Baumstämme',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        'Baumkronen': 'Baumkronen',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        'Fahrbahn': 'Fahrbahn',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        'Radweg': 'Radweg',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        'Fahrbahn / Bushaltefläche': 'Fahrbahn / Bushaltefläche',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        'Fahrbahn / Busspur': 'Fahrbahn / Busspur',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        'Fahrbahn / Radfahrstreifen': 'Fahrbahn / Radfahrstreifen',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        'Fahrbahn / Schutzstreifen': 'Fahrbahn / Schutzstreifen',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        'Fahrbahn / Überwege': 'Fahrbahn / Überwege',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        'Fahrbahn Sperrfläche': 'Fahrbahn Sperrfläche',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        'Fahrradbügelfläche': 'Fahrradbügelfläche',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        'Gehweg': 'Gehweg',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        'Gehweg / Fahrgastwartefläche': 'Gehweg / Fahrgastwartefläche',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        'Gehweg / Radfahrer frei': 'Gehweg / Radfahrer frei',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        'Gehweg / Überfahrt': 'Gehweg / Überfahrt',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        'Komb. Geh- und Radweg': 'Komb. Geh- und Radweg',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        'Parkstreifen': 'Parkstreifen',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        'Radweg / Überfahrt': 'Radweg / Überfahrt',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        'Schutz- / Trennstreifen': 'Schutz- / Trennstreifen',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        'Seitenraum': 'Seitenraum',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        'Seitenstreifen': 'Seitenstreifen',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        'Sonstiges': 'Sonstiges',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        'Sonstiges / Mauerwerk / Stützwände': 'Sonstiges / Mauerwerk / Stützwände',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        'Straßenbegleitgrün': 'Straßenbegleitgrün',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        'Überfahrt / Zufahrt': 'Überfahrt / Zufahrt',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    };</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    // Legende-Button hinzufügen</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    if (window.innerWidth &gt; 768) {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    	map.addControl(new MaplibreLegendControl.MaplibreLegendControl(targets, {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            showDefault: false,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            showCheckbox: true,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            onlyRendered: true,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            reverseOrder: true,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            title: 'Legende',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    	}), 'top-right');</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">})</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="In die Zwischenablage kopieren" title="Kopieren" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="3d-2d-ansicht-button">3D-/2D-Ansicht-Button<a href="https://geodaten-guerilla.net/blog/maplibre-plugins-strassenraumkarte#3d-2d-ansicht-button" class="hash-link" aria-label="Direkter Link zur 3D-/2D-Ansicht-Button" title="Direkter Link zur 3D-/2D-Ansicht-Button">​</a></h3>
<p>Für einen Button, der zwischen 3D- und 2D-Ansicht wechselt, braucht es kein Zusatzplugin, aber viel Code. Wie sinnvoll ein solcher Button ist, ist tatsächlich fraglich, da sich mit der rechten Maustauste bereits der Blickwinkel ändern lässt. Aber der Button leuchtet grün, wenn mensch auf "3D" klickt und ist ein guter Hinweis bzw. Werkzeug für alle, die nicht wissen, dass sich mit der rechten Maustaste der Blickwinkel ändern lässt.</p>
<div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">//////////// 3D-/2D-Ansicht-Button hinzufügen ////////////</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">// Custom-Control-Klasse mit 2D/3D-Umschaltung</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">class Toggle3DControl {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    onAdd(map) {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        this.map = map;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        this.container = document.createElement('div');</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        this.container.className = 'maplibregl-ctrl maplibregl-ctrl-group';</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        const button = document.createElement('button');</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        button.type = 'button';</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        button.textContent = '3D'; // Startmodus</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        button.title = '3D-Ansicht aktivieren';</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        button.style.fontWeight = 'bold';</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        button.style.transition = 'background-color 0.2s ease, color 0.2s ease';</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        let is3D = false;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        button.addEventListener('click', () =&gt; {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            is3D = !is3D;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            if (is3D) {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                // Cineastischer Wechsel zu 3D</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                map.easeTo({</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                    pitch: 60,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                    bearing: -17.6,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                    duration: 1500,     // sanfte Animation</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                    easing: t =&gt; t*(2-t) // smoother easing</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                });</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                button.textContent = '2D';</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                button.title = '2D-Ansicht aktivieren';</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                button.style.backgroundColor = '#4CAF50';</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                button.style.color = '#fff';</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            } else {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                // Zurück zu 2D</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                map.easeTo({</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                    pitch: 0,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                    bearing: 0,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                    duration: 1500,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                    easing: t =&gt; t*(2-t)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                });</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                button.textContent = '3D';</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                button.title = '3D-Ansicht aktivieren';</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                button.style.backgroundColor = '';</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                button.style.color = '';</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        });</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        this.container.appendChild(button);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        return this.container;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    onRemove() {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        this.container.parentNode.removeChild(this.container);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        this.map = undefined;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">}</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">// 3D-Button hinzufügen</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">if (window.innerWidth &gt; 768) {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    map.addControl(new Toggle3DControl(), 'top-right');</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="In die Zwischenablage kopieren" title="Kopieren" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="messwerkzeug">Messwerkzeug<a href="https://geodaten-guerilla.net/blog/maplibre-plugins-strassenraumkarte#messwerkzeug" class="hash-link" aria-label="Direkter Link zur Messwerkzeug" title="Direkter Link zur Messwerkzeug">​</a></h3>
<p>Mit dem Messwerkzeug lassen sich Entfernungen und Flächen in der Karte messen. Genutzt wird das Plugin <a href="https://github.com/jdsantos/maplibre-gl-measures" target="_blank" rel="noopener noreferrer">maplibre-gl-measures</a>.</p>
<div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">//////////// Messwerkzeug hinzufügen ////////////</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">map.addControl(new maplibreGLMeasures.default({</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	lang: {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        areaMeasurementButtonTitle: 'Fläche messen',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        lengthMeasurementButtonTitle: 'Entfernung messen',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        clearMeasurementsButtonTitle: 'Messungen löschen',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	},</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    units: 'metric',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    unitsGroupingSeparator: '.',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	style: {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		text: {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            radialOffset: 0.9,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            letterSpacing: 0.05,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            color: '#0000FF',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            haloColor: '#fff',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            haloWidth: 4,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            font: 'Open Sans Bold',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		},</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		common: {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            midPointRadius: 6,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            midPointColor: '#0000FF',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            midPointHaloRadius: 10,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            midPointHaloColor: '#FFF',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        },</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		areaMeasurement: {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            fillColor: '#6969E6',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            fillOutlineColor: '#0000FF',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            fillOpacity: 0.2,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            lineWidth: 3,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		},</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		lengthMeasurement: {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            lineWidth: 4,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            lineColor: "#0000FF",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		},</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	}</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">}), 'top-right');</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="In die Zwischenablage kopieren" title="Kopieren" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="zeichnen-tool">Zeichnen-Tool<a href="https://geodaten-guerilla.net/blog/maplibre-plugins-strassenraumkarte#zeichnen-tool" class="hash-link" aria-label="Direkter Link zur Zeichnen-Tool" title="Direkter Link zur Zeichnen-Tool">​</a></h3>
<p>Das Tool, um Flächen in die Karte zu zeichnen, ist recht umfangreich. Denn es sollen nicht nur einfach Flächen eingezeichnet werden können, sondern diese sollen auch die Farben der verschiedenen Straßenräume haben können, also bspw. Fahrbahn, Gehweg oder Radweg. Das wird ermöglich, indem beim Aufruf der Flächenzeichnung ein Auswahlmenü erscheint. So lassen sich in der Kartendarstellung umgestaltete Straßenräume visualisieren. Ich nutze dafür die Plugins <a href="https://github.com/watergis/maplibre-gl-terradraw" target="_blank" rel="noopener noreferrer">maplibre-gl-terradraw</a> und <a href="https://github.com/JamesLMilner/terra-draw" target="_blank" rel="noopener noreferrer">terra-draw</a>. Die Erstellung von Kreisen und Linien ist zwar auch aktiviert, aber nicht mit einem Farbauswahl-Menü versehen.</p>
<div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">// Konfiguration von maplibre-gl-terradraw</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">const draw = new MaplibreTerradrawControl.MaplibreTerradrawControl({</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    modes: [</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        'render', // comment this to always show drawing tool</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        'point',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        'linestring',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        'polygon',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        //'rectangle',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        'circle',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        //'freehand',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        //'angled-rectangle',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        //'sensor',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        //'sector',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        'select',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        'delete-selection',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        'delete',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        'download'</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	],</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    open: false,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	modeOptions: {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		point: new terraDraw.TerraDrawPointMode({</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">			styles: {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                pointColor: '#FF0000',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                pointWidth: 3,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                pointOutlineColor: '#FF0000',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                pointOutlineWidth: 1</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">			}</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		}),</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        linestring: new terraDraw.TerraDrawLineStringMode({</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">			styles: {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">				lineStringColor: '#FF0000',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">				lineStringWidth: 2,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">				closingPointColor: '#FFFFFF',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">				closingPointWidth: 3,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                closingPointOutlineColor: '#FF0000',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">				closingPointOutlineWidth: 1</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">			}</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		}),</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        polygon: new terraDraw.TerraDrawPolygonMode({</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            styles: {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            	// fillColor und fillOpacity werden über ein Farbmenü eingestellt</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            	fillColor: ({ id }) =&gt; {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            		if (!colorCache[id]) {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            			showColorMenu(id);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            			return "#000000";</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            		}</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            		return colorCache[id].color;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            	},</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            	fillOpacity: ({ id }) =&gt; {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            		return colorCache[id]?.opacity ?? 1.0;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            	},</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            	//outlineColor: '#FF0000',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            	outlineWidth: 0,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            	closingPointColor: '#FAFAFA',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            	closingPointWidth: 3,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            	closingPointOutlineColor: '#FF0000',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            	closingPointOutlineWidth: 1</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		}),</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        circle: new terraDraw.TerraDrawCircleMode({</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">			styles: {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">				fillColor: '#F5AEAE',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">				outlineColor: '#FF0000',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">				outlineWidth: 2,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">				fillOpacity: 0.7,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">			}</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		})</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	}</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">});</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">// Draw-Werkzeug wird hinzugefügt</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">if (window.innerWidth &gt; 768) {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	map.addControl(draw, 'top-right');</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">}</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">// Farben und Kategorien für das Farbauswahlmenü</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">const palette = [</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    { color: "#464646", label: "Fahrbahn" },</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    { color: "#0000FF", label: "Radweg" },</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    { color: "#6E0000", label: "Fahrbahn / Bushaltefläche" },</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    { color: "#FF7B7B", label: "Fahrbahn / Busspur" },</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    { color: "#56EDD1", label: "Fahrbahn / Radfahrstreifen" },</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    { color: "#0DC773", label: "Fahrbahn / Schutzstreifen" },</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    { color: "#696D53", label: "Fahrbahn / Überwege" },</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    { color: "#9F9F9F", label: "Fahrbahn Sperrfläche" },</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    { color: "#7B7BB9", label: "Fahrradbügelfläche" },</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    { color: "#E6DD79", label: "Gehweg" },</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    { color: "#FF0000", label: "Gehweg / Fahrgastwartefläche" },</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    { color: "#E09524", label: "Gehweg / Radfahrer frei" },</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    { color: "#F9DB81", label: "Komb. Geh- und Radweg" },</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    { color: "#F14D97", label: "Parkstreifen" },</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    { color: "#313179", label: "Radweg / Überfahrt" },</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    { color: "#9A6ABE", label: "Schutz- / Trennstreifen" },</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    { color: "#52917E", label: "Seitenraum" },</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    { color: "#A4A4A4", label: "Seitenstreifen" },</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    { color: "#8E8E8E", label: "Sonstiges" },</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    { color: "#7A7A88", label: "Sonstiges / Mauerwerk / Stützwände" },</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    { color: "#94D180", label: "Straßenbegleitgrün" },</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    { color: "#91AA23", label: "Überfahrt / Zufahrt" },</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">];</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">// state</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">let activeMenuFeatureId = null;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">const dismissedMenus = new Set(); // optional: wenn Nutzer*in X drückt -&gt; nicht wieder automatisch öffnen</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">// DOM refs</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">const menu = document.getElementById("colorMenu");</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">const colorList = document.getElementById("colorList");</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">const slider = document.getElementById("opacitySlider");</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">const valueLabel = document.getElementById("opacityValue");</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">const closeBtn = document.getElementById("colorMenuClose");</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">// Buttons bauen</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">function buildColorMenu() {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	colorList.innerHTML = "";</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	for (const entry of palette) {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		const btn = document.createElement("button");</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		btn.type = "button";</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		btn.className = "color-option";</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		btn.dataset.color = entry.color;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		btn.innerHTML = `</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">			&lt;span class="color-circle" style="background:${entry.color}"&gt;&lt;/span&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">			&lt;span class="color-label"&gt;${entry.label}&lt;/span&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		`;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		// optional: aria</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		btn.setAttribute("aria-label", `${entry.label} (${entry.color})`);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		colorList.appendChild(btn);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	}</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">}</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">buildColorMenu(); // einmal aufbauen</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">// Farbe mit Klick auswählen</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">colorList.addEventListener("click", (ev) =&gt; {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	const btn = ev.target.closest(".color-option");</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    if (!btn) return;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    if (!activeMenuFeatureId) return;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    const selectedColor = btn.dataset.color;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    if (!colorCache[activeMenuFeatureId]) colorCache[activeMenuFeatureId] = { color: selectedColor, opacity: 1.0 };</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    colorCache[activeMenuFeatureId].color = selectedColor;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    draw.updateStyles();</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">});</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">// Opacity-Slider</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">slider.addEventListener("input", () =&gt; {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	const v = parseFloat(slider.value);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	valueLabel.textContent = v.toFixed(1);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	if (activeMenuFeatureId) {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		if (!colorCache[activeMenuFeatureId]) colorCache[activeMenuFeatureId] = { color: palette[0].color, opacity: v };</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		colorCache[activeMenuFeatureId].opacity = v;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		draw.updateStyles();</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	}</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">});</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">function showColorMenu(featureId) {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	if (dismissedMenus.has(featureId)) return;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	activeMenuFeatureId = featureId;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	if (!colorCache[featureId]) colorCache[featureId] = { color: palette[0].color, opacity: 1.0 };</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	slider.value = colorCache[featureId].opacity;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	valueLabel.textContent = parseFloat(slider.value).toFixed(1);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	menu.removeAttribute("hidden");</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	// optional: focus first button for accessibility</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	const first = colorList.querySelector(".color-option");</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	if (first) first.focus();</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">}</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">function hideColorMenu() {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	activeMenuFeatureId = null;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	menu.setAttribute("hidden", "");</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">}</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">// Close button (speichert dismiss-Einstellung)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">closeBtn.addEventListener("click", () =&gt; {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	if (activeMenuFeatureId) dismissedMenus.add(activeMenuFeatureId);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	hideColorMenu();</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">});</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">// ESC schließt das Menü ebenfalls</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">document.addEventListener("keydown", (e) =&gt; { if (e.key === "Escape") { if (activeMenuFeatureId) dismissedMenus.add(activeMenuFeatureId); hideColorMenu(); } });</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">// Optional: verberge Menü, wenn Draw-Mode gewechselt wird</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">if (draw &amp;&amp; typeof draw.on === "function") {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	draw.on("modechange", (event) =&gt; {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		if (event.mode !== "polygon") hideColorMenu();</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	});</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="In die Zwischenablage kopieren" title="Kopieren" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="area-switcher">Area-Switcher<a href="https://geodaten-guerilla.net/blog/maplibre-plugins-strassenraumkarte#area-switcher" class="hash-link" aria-label="Direkter Link zur Area-Switcher" title="Direkter Link zur Area-Switcher">​</a></h3>
<p>Mit dem Plugin <a href="https://github.com/watergis/maplibre-gl-area-switcher" target="_blank" rel="noopener noreferrer">maplibre-gl-area-switcher</a> lassen Punkte definieren, wohin der Kartenausschnitt springen soll. So lassen sich mehrere Points of Interests hinterlegen, die besonders interessant erscheinen. Die Konfiguration ist mit Name, Koordinaten und Zoomstufe sehr zugänglich.</p>
<div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">//////////// Area-Switcher einfügen ////////////</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">map.addControl(new MaplibreAreaSwitcherControl([</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    {title: "Holtenauer Straße",latlng: [10.131849, 54.331142],zoom: 18},</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    {title: "Andreas-Gayk-Straße",latlng: [10.133646, 54.3190029],zoom: 18},</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    {title: "Friedrichsorter Straße",latlng: [10.1729513, 54.3958302],zoom: 18},</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    {title: "Seefischmarkt",latlng: [10.180681, 54.325865],zoom: 18},</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    {title: "Gaarden-Ost",latlng: [10.145751, 54.31152],zoom: 16},</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">]), 'top-right');</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="In die Zwischenablage kopieren" title="Kopieren" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="export-funktion">Export-Funktion<a href="https://geodaten-guerilla.net/blog/maplibre-plugins-strassenraumkarte#export-funktion" class="hash-link" aria-label="Direkter Link zur Export-Funktion" title="Direkter Link zur Export-Funktion">​</a></h3>
<p>Die Exportfunktion von <a href="https://github.com/watergis/maplibre-gl-export" target="_blank" rel="noopener noreferrer">maplibre-gl-export</a> erlaubt es, Kartenausschnitte in verschiedene Bild- und Dateiformaten zu exportieren. Die Seitengrößen, die beim Export angeboten werden, können im Code konfiguriert werden.</p>
<div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">//////////// Export-Funktion hinzufügen ////////////</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">if (window.innerWidth &gt; 768) {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	map.addControl(new MaplibreExportControl.MaplibreExportControl({</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		PageSize: MaplibreExportControl.Size.A4,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		PageOrientation: MaplibreExportControl.PageOrientation.Landscape,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		Format: MaplibreExportControl.Format.PNG,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		DPI: MaplibreExportControl.DPI[96],</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		Crosshair: true,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		PrintableArea: true,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		Local: 'de',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		AllowedSizes:[</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">			"A2", "A3", "A4", "A5", "A6",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		],</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		Filename: 'Karte-GeoDatenGuerilla',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		attributionOptions: {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">			'visibility': 'visible',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">			'position': 'bottom-right',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		},</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	}),</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	'top-right'</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="In die Zwischenablage kopieren" title="Kopieren" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="info-button">Info-Button<a href="https://geodaten-guerilla.net/blog/maplibre-plugins-strassenraumkarte#info-button" class="hash-link" aria-label="Direkter Link zur Info-Button" title="Direkter Link zur Info-Button">​</a></h3>
<p>Zuletzt ist noch ein Info-Button eingefügt. Wenn dieser grün leuchtet, ist er aktiviert. Wenn mensch dann auf eine Straßenfläche klickt, werden einem Infos über diese Fläche eingeblendet. Der Button ist so konfiguriert, dass beim Klicken in die Karte nur bestimmte Layer abgefragt und die Infos angezeigt werden. Gleichzeitig wird die angeklickte Fläche hervorgehoben. Der Code für diesen Button ist recht umfangreich, kommt aber ohne Plugins aus.</p>
<div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">//////////// Pop-Up bei Klick auf Objekte hinzufügen ////////////</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">// Popup vorbereiten</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">let popup = new maplibregl.Popup({ closeButton: false, closeOnClick: false });</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">// Highlight-Sources vorbereiten</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">map.on('load', () =&gt; {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	map.addSource('highlight-feature', {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		type: 'geojson',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		data: { type: 'FeatureCollection', features: [] }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	});</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	// Highlight-Layer hinzufügen</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	map.addLayer({</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		id: 'highlight-line-outline',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		type: 'line',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		source: 'highlight-feature',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		paint: {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">			'line-color': '#000000',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">			'line-width': 8,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">			'line-opacity': 0.8</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		},</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		filter: ['==', '$type', 'LineString']</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	});</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	map.addLayer({</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		id: 'highlight-line',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		type: 'line',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		source: 'highlight-feature',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		paint: {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">			'line-color': '#ffff00',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">			'line-width': 6,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">			'line-opacity': 0.7</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		},</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		filter: ['==', '$type', 'LineString']</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	});</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	map.addLayer({</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		id: 'highlight-fill',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		type: 'fill',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		source: 'highlight-feature',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		paint: {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">			'fill-color': '#ffff00',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">			'fill-opacity': 0.3</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		},</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		filter: ['==', '$type', 'Polygon']</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	});</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	map.addLayer({</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		id: 'highlight-fill-outline',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		type: 'line',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		source: 'highlight-feature',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        paint: {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">			'line-color': '#000000',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">			'line-width': 2,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">			'line-opacity': 0.8</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		},</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		filter: ['==', '$type', 'Polygon']</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	});</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	map.addLayer({</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		id: 'highlight-point',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		type: 'circle',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		source: 'highlight-feature',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		paint: {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">			'circle-radius': 10,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">			'circle-color': '#ffff00',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">			'circle-opacity': 0.6,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">			'circle-stroke-color': '#000000',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">			'circle-stroke-width': 2</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		},</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		filter: ['==', '$type', 'Point']</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	});</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">});</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">// Layerliste für Popups</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">const popupLayers = [</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	'Fahrbahn', 'Radweg', 'Fahrbahn / Bushaltefläche', 'Fahrbahn / Busspur',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	'Fahrbahn / Radfahrstreifen', 'Fahrbahn / Schutzstreifen', 'Fahrbahn / Überwege',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	'Fahrbahn Sperrfläche', 'Fahrradbügelfläche', 'Gehweg',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	'Gehweg / Fahrgastwartefläche', 'Gehweg / Radfahrer frei', 'Gehweg / Überfahrt',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	'Komb. Geh- und Radweg', 'Parkstreifen', 'Radweg / Überfahrt',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	'Schutz- / Trennstreifen', 'Seitenraum', 'Seitenstreifen', 'Sonstiges',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	'Sonstiges / Mauerwerk / Stützwände', 'Straßenbegleitgrün', 'Überfahrt / Zufahrt'</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">];</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">// Button für Popups</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">let popupEnabled = true;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">class TogglePopupControl {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	onAdd(map) {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		this.map = map;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		this.container = document.createElement('div');</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		this.container.className = 'maplibregl-ctrl maplibregl-ctrl-group';</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		const button = document.createElement('button');</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		button.type = 'button';</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		button.title = 'Popup-Funktion ein-/ausschalten';</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		button.style.display = 'flex';</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		button.style.alignItems = 'center';</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		button.style.justifyContent = 'center';</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		// SVGs vorbereiten</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		const iconActive = `</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">			&lt;svg xmlns="http://www.w3.org/2000/svg"</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">					width="20" height="20" viewBox="0 0 24 24"</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">					fill="none" stroke="currentColor" stroke-width="2"</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">					stroke-linecap="round" stroke-linejoin="round"&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">				&lt;circle cx="12" cy="12" r="10"&gt;&lt;/circle&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">				&lt;line x1="12" y1="16" x2="12" y2="12"&gt;&lt;/line&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">				&lt;line x1="12" y1="8" x2="12" y2="8"&gt;&lt;/line&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">			&lt;/svg&gt;`;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		const iconInactive = `</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">			&lt;svg xmlns="http://www.w3.org/2000/svg"</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">					width="20" height="20" viewBox="0 0 24 24"</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">					fill="none" stroke="currentColor" stroke-width="2"</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">					stroke-linecap="round" stroke-linejoin="round"&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">				&lt;circle cx="12" cy="12" r="10"&gt;&lt;/circle&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">				&lt;line x1="12" y1="16" x2="12" y2="12"&gt;&lt;/line&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">				&lt;line x1="12" y1="8" x2="12" y2="8"&gt;&lt;/line&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">				&lt;line x1="4" y1="20" x2="20" y2="4" stroke="red"&gt;&lt;/line&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">			&lt;/svg&gt;`;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		// Funktion für Zustand wechseln</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		function updateButtonState() {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">			if (popupEnabled) {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">				button.innerHTML = iconActive;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">				button.style.backgroundColor = '#4CAF50';</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">				button.style.color = '#fff';</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">			} else {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">				button.innerHTML = iconInactive;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">				button.style.backgroundColor = '';</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">				button.style.color = '';</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">			}</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		}</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		// Initialzustand: aktiv</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		updateButtonState();</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		// Klick-Handler</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		button.addEventListener('click', () =&gt; {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">			popupEnabled = !popupEnabled;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">			updateButtonState();</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">			if (!popupEnabled) {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">				// Popup + Highlight zurücksetzen</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">				map.getSource('highlight-feature').setData({</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">					type: 'FeatureCollection',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">					features: []</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">				});</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">				popup.remove();</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">			}</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		});</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		this.container.appendChild(button);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		return this.container;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	}</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	onRemove() {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		this.container.parentNode.removeChild(this.container);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		this.map = undefined;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	}</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">}</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">// Button hinzufügen</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">map.addControl(new TogglePopupControl(), 'top-right');</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">// Klick-Events</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">popupLayers.forEach(layerId =&gt; {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	map.on('click', layerId, (e) =&gt; {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		if (!popupEnabled) return; // Nur wenn aktiv</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		if (!e.features.length) return;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		const feature = e.features[0];</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		// Highlight aktualisieren</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		map.getSource('highlight-feature').setData(feature);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		// Popup-Inhalt dynamisch aus Properties bauen</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		let propsHtml = '&lt;b&gt;Eigenschaften:&lt;/b&gt;&lt;br&gt;&lt;ul&gt;';</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		for (let key in feature.properties) {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">			propsHtml += `&lt;li&gt;&lt;b&gt;${key}&lt;/b&gt;: ${feature.properties[key]}&lt;/li&gt;`;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		}</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		propsHtml += '&lt;/ul&gt;';</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		popup</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">			.setLngLat(e.lngLat)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">			.setHTML(propsHtml)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">			.addTo(map);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	});</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    // Cursor ändern bei Hover</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	map.on('mouseenter', layerId, () =&gt; {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		if (popupEnabled) map.getCanvas().style.cursor = 'pointer';</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	});</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	map.on('mouseleave', layerId, () =&gt; {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		if (popupEnabled) map.getCanvas().style.cursor = '';</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	});</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">});</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">// Klick irgendwo anders → nur wenn Popups aktiv</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">map.on('click', (e) =&gt; {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	if (!popupEnabled) return;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	const features = map.queryRenderedFeatures(e.point, { layers: popupLayers });</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	if (!features.length) {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		map.getSource('highlight-feature').setData({</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">			type: 'FeatureCollection',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">			features: []</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		});</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		popup.remove();</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	}</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">});</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="In die Zwischenablage kopieren" title="Kopieren" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="fazit-und-ausblick">Fazit und Ausblick<a href="https://geodaten-guerilla.net/blog/maplibre-plugins-strassenraumkarte#fazit-und-ausblick" class="hash-link" aria-label="Direkter Link zur Fazit und Ausblick" title="Direkter Link zur Fazit und Ausblick">​</a></h2>
<p>Mit einer Mischung aus Plugins und zusätzlichem eigenen Code lässt sich MapLibre mit grundlegenden WebGIS-Funktionen ausstatten. Die hier vorgestellte fortgeschrittene <a href="https://geodaten-guerilla.net/maps/strassenraumaufteilung-kiel/" target="_blank" rel="noopener noreferrer">Kartenanwendung zur Straßenraumaufteilung</a> hat zusätzlich noch das besondere Feature, Straßenflächen selbst in die Karte zeichnen zu können. Damit lassen sich Straßenräume verändern und bspw. mit breiteren Geh- und Radwegen ausstatten. Das Ergebnis wird dann in der Kartenanwendung der*dem Nutzer*in visualisiert.</p>
<p>Ich bin allerdings mit der 3D-Darstellung in MapLibre nicht zufrieden. Es werden zwar 3D-Gebäude in der Karte angezeigt, aber der Straßenraum-Layer scheint durch die Gebäude hindurch. Darum möchte in Zukunft auch noch andere Bibliotheken wie Cesium ausprobieren und prüfen, wie sie die Darstellung händeln.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="der-vollständige-code">Der vollständige Code<a href="https://geodaten-guerilla.net/blog/maplibre-plugins-strassenraumkarte#der-vollst%C3%A4ndige-code" class="hash-link" aria-label="Direkter Link zur Der vollständige Code" title="Direkter Link zur Der vollständige Code">​</a></h2>
<p>Hier ist der vollständige Code für die <a href="https://geodaten-guerilla.net/maps/strassenraumaufteilung-kiel/" target="_blank" rel="noopener noreferrer">Kartenanwendung</a> zu finden:</p>
<div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">&lt;!DOCTYPE html&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">&lt;html lang="de"&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  &lt;head&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    &lt;title&gt;Straßenraumaufteilung in Kiel | GeoDatenGuerilla&lt;/title&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    &lt;meta charset="utf-8"&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    &lt;meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    &lt;link rel="icon" href="img/gdg_favicon.ico" type="image/x-icon"&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    &lt;!-- MapLibre GL JS: https://github.com/maplibre/maplibre-gl-js --&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    &lt;link rel="stylesheet" href="libs/maplibre-gl-4-7-1.css" /&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    &lt;script src="libs/maplibre-gl-4-7-1.js"&gt;&lt;/script&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    &lt;!-- basemap.de 3D / Testbetrieb-Lizenz: https://basemap.de/produkte-und-dienste/3d/ --&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    &lt;script src="libs/Maplibre3DTiles.js"&gt;&lt;/script&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    &lt;!-- watergis maplibre-gl-area-switcher / MIT-Lizenz: https://github.com/watergis/maplibre-gl-area-switcher --&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    &lt;link href='libs/maplibre-gl-area-switcher.css' rel='stylesheet' /&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    &lt;script src="libs/maplibre-gl-area-switcher.umd.js"&gt;&lt;/script&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    &lt;!-- watergis maplibre-gl-export / MIT-Lizenz: https://github.com/watergis/maplibre-gl-export --&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    &lt;link href="libs/maplibre-gl-export.css" rel="stylesheet" /&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    &lt;script src="libs/maplibre-gl-export.umd.js"&gt;&lt;/script&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    &lt;!-- watergis maplibre-gl-legend / MIT-Lizenz: https://github.com/watergis/maplibre-gl-legend --&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    &lt;link href='libs/maplibre-gl-legend.css' rel='stylesheet' /&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    &lt;script src="libs/maplibre-gl-legend.umd.js"&gt;&lt;/script&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    &lt;!-- watergis maplibre-gl-terradraw / MIT-Lizenz: https://github.com/watergis/maplibre-gl-terradraw --&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    &lt;link rel="stylesheet" href="libs/maplibre-gl-terradraw.css" /&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    &lt;script src="libs/maplibre-gl-terradraw.umd.js"&gt;&lt;/script&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    &lt;!-- JamesLMilner terra-draw / MIT-Lizenz: https://github.com/JamesLMilner/terra-draw --&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    &lt;script src="libs/terra-draw.umd.js"&gt;&lt;/script&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    &lt;!-- jdsantos maplibre-gl-measures / MIT-Lizenz: https://github.com/jdsantos/maplibre-gl-measures --&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    &lt;script src='libs/maplibre-gl-measures.js'&gt;&lt;/script&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    &lt;style&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      body { margin: 0; padding: 0; }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      /* Roboto VariableFont einbinden */</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      @font-face {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        font-family: 'RobotoVariable';</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        src: url('/fonts/Roboto-VariableFont.woff2') format('woff2');</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        font-weight: 100 900;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        font-style: normal;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        font-display: swap;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      @media (max-width: 768px) {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        #topbar { height: 45px; }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        #bottombar { height: 35px; font-size: 14px; }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        #topbar-links { display: none; } /* Links ausblenden */</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        #menu-toggle { display: block; } /* z.B. Burger-Icon zeigen */</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      /* Einheitliche Schrift für UI-Elemente */</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      #topbar,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      #bottombar {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        font-family: 'Segoe UI', RobotoVariable, sans-serif;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        -webkit-font-smoothing: antialiased;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        -moz-osx-font-smoothing: grayscale;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        text-rendering: optimizeLegibility;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      /* Fokus für Tastaturen */</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      button:focus, a:focus {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        outline: 2px solid #1976d2; /* Blau oder rot passend zum Design */</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        outline-offset: 2px;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      /* Topbar */</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      #topbar {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        position: absolute;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        top: 0;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        left: 0;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        width: 100%;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        height: 60px;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        background-color: white;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        z-index: 999;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      #topbar-inner {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        height: 32px;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        margin: 14px 17px;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        display: flex;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        align-items: center;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      #topbar-links {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        display: flex;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        align-items: center;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        margin-left: 20px; /* Abstand zwischen Logo und erster Link */</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      #topbar-links a {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        margin-left: 15px; /* Abstand zwischen den Links */</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        text-decoration: none;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        color: black;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        font-weight: 500;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        font-size: 16px;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        transition: color 0.2s;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      #topbar-links a:hover {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        color: red;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      #logo-text-link {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        display: flex;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        align-items: center;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        height: 100%;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        text-decoration: none;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        color: black;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        font-size: 18px;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        font-weight: bold;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      #topbar-logo {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        height: 100%;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        display: block;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      #site-name-text {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        margin-left: 10px;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      #logo-text-link:hover {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        color: red;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      /* Burger-Button Standard: versteckt */</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      #menu-toggle {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        display: none;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        font-size: 24px;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        background: none;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        border: none;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        cursor: pointer;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        margin-left: auto;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      /* Mobile-Ansicht */</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      @media (max-width: 768px) {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        #topbar-links {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          display: none;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          position: absolute;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          top: 60px;   /* direkt unter der Topbar */</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          left: 0;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          width: 100%;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          background: white;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          flex-direction: column;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          padding: 10px 0;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          border-top: 1px solid #ddd;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          z-index: 1000;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        #topbar-links a {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          padding: 12px 20px;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          margin: 0;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          font-size: 16px;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          border-bottom: 1px solid #eee;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        #menu-toggle {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          display: block;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        /* Wenn das Menü aktiv ist */</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        #topbar-links.active {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          display: flex;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      /* Bottombar */</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      #bottombar {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        position: absolute;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        bottom: 0;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        left: 0;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        width: 100%;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        height: 40px;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        background-color: #303846;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        color: white;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        z-index: 999;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        display: flex;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        justify-content: center;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        align-items: center;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      #bottombar a {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        color: white;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        text-decoration: none;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        font-weight: bold;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        margin: 0 15px;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        transition: color 0.2s;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      #bottombar a:hover {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        color: red;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      /* Farbauswahlmenü für maplibre-gl-terradraw --- */</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      :root {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        --menu-padding: 8px;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        --menu-radius: 8px;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        --menu-gap: 6px;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        --circle-size: 18px;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        --menu-shadow: 0 2px 10px rgba(0,0,0,0.12);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        --border: #e9e9e9;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      #colorMenu {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        position: absolute;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        top: 70px;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        right: 50px;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        padding: var(--menu-padding);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        background: #fff;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        border-radius: var(--menu-radius);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        border: 1px solid #ccc;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        box-shadow: var(--menu-shadow);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        font-family: 'Segoe UI', Roboto, sans-serif;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        font-size: 14px;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        z-index: 2000;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      /* einfache Möglichkeit, Menü zu verstecken */</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      #colorMenu[hidden] { display: none; }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      /* Header */</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      #colorMenuHeader {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        display:flex;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        align-items:center;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        justify-content:space-between;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        gap:8px;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        padding-bottom:8px;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        border-bottom:1px solid var(--border);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        margin-bottom:8px;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        font-weight:600;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      /* Schließen-Button */</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      #colorMenuClose {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        border: none;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        background: transparent;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        cursor: pointer;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        font-size: 18px;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        line-height: 1;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        padding: 2px 6px;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      #colorMenuClose:hover { opacity: 0.8; }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      /* Farben-Liste */</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      #colorList {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        display:flex;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        flex-direction:column;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        gap: var(--menu-gap);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      /* Jede Option ist ein Button (Keyboard + Screenreader ok) */</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      .color-option {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        display:flex;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        align-items:center;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        gap:10px;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        padding:6px;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        border-radius:6px;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        background:transparent;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        border: none;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        text-align:left;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        cursor: pointer;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      .color-option:hover,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      .color-option:focus {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        background: #f6f6f6;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        outline: none;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      /* Kreise */</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      .color-circle {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        width: var(--circle-size);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        height: var(--circle-size);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        border-radius:50%;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        box-shadow: 0 0 3px rgba(0,0,0,0.2);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        flex-shrink:0;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      /* Label */</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      .color-label { flex:1; }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      /* Opacity-Block */</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      #opacityControl {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        margin-top:10px;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        padding-top:8px;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        border-top:1px solid var(--border);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        display:flex;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        align-items:center;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        gap:10px;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        justify-content:space-between;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      #opacitySlider { width:140px; }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      #opacityValue { min-width:36px; text-align:right; font-family:monospace; }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      #map {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        position: absolute;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        top: 60px;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        bottom: 40px;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        width: 100%;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      .mapboxgl-popup {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        max-width: 300px;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        font: 12px/1.5 sans-serif;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    &lt;/style&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  &lt;/head&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  &lt;body&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    &lt;!-- Topbar mit innerer Box --&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    &lt;div id="topbar"&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      &lt;div id="topbar-inner"&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        &lt;a href="https://geodaten-guerilla.net/" target="_blank" id="logo-text-link"&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          &lt;img src="img/gdg_logo_ohne_text.svg"</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">              alt="Logo GeoDatenGuerilla und Link zur Webseite"</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">              id="topbar-logo"&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          &lt;span id="site-name-text"&gt;GeoDatenGuerilla&lt;/span&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        &lt;/a&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        &lt;!-- Hamburger-Menü --&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        &lt;button id="menu-toggle" aria-expanded="false" aria-controls="topbar-links" aria-label="Menü öffnen"&gt;☰&lt;/button&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        &lt;!-- Link-Container für die Links in der TopBar --&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        &lt;nav id="topbar-links"&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          &lt;a href="https://geodaten-guerilla.net/karten" target="_blank"&gt;Karten&lt;/a&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          &lt;a href="https://geodaten-guerilla.net/blog" target="_blank"&gt;Blog&lt;/a&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          &lt;a href="https://geodaten-guerilla.net/mitmachen-kontakt" target="_blank"&gt;Mitmachen und Kontakt&lt;/a&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          &lt;a href="https://geodaten-guerilla.net/docs/intro" target="_blank"&gt;Dokumentation&lt;/a&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          &lt;a href="https://geodaten-guerilla.net/downloads/" target="_blank"&gt;Downloads&lt;/a&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        &lt;/nav&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      &lt;/div&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    &lt;/div&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    &lt;!-- Map --&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    &lt;div id="map"&gt;&lt;/div&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    &lt;!-- Farbauswahl-Menü maplibre-gl-terradraw --&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    &lt;div id="colorMenu" hidden&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      &lt;div id="colorMenuHeader"&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        &lt;span&gt;Füllstil&lt;/span&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        &lt;button id="colorMenuClose" aria-label="Menü schließen" title="Menü schließen"&gt;&amp;times;&lt;/button&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      &lt;/div&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      &lt;!-- Farbbuttons --&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      &lt;div id="colorList" role="radiogroup" aria-label="Füllfarbe auswählen"&gt;&lt;/div&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      &lt;!-- Opacity-Slider --&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      &lt;div id="opacityControl"&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        &lt;label for="opacitySlider"&gt;Transparenz&lt;/label&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        &lt;div style="display:flex;align-items:center;gap:8px;"&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          &lt;input id="opacitySlider" type="range" min="0" max="1" step="0.1" value="1"&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          &lt;span id="opacityValue"&gt;1.0&lt;/span&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        &lt;/div&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      &lt;/div&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    &lt;/div&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    &lt;!-- Bottombar --&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    &lt;div id="bottombar"&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      &lt;a href="https://geodaten-guerilla.net/impressum" target="_blank"&gt;Impressum&lt;/a&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      &lt;a href="https://geodaten-guerilla.net/datenschutzerklaerung" target="_blank"&gt;Datenschutz&lt;/a&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      &lt;a href="https://climatejustice.social/@GeoDatenGuerilla" target="_blank"&gt;Mastodon&lt;/a&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    &lt;/div&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    &lt;script&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      //////////// Hamburger-Menü ////////////</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      const menuToggle = document.getElementById("menu-toggle");</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      const topbarLinks = document.getElementById("topbar-links");</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      menuToggle.addEventListener("click", () =&gt; {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        const isActive = topbarLinks.classList.toggle("active");</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        menuToggle.setAttribute("aria-expanded", isActive);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      });</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      //////////// Basemap einbinden und Karte generieren ////////////</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      // Grenzen, innerhalb derer die Karte verschoben werden kann, festlegen</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      const bounds = [</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        [9.44955, 53.7632],</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        [10.7106, 54.6175]</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      ]; </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      // Basemap und Karte laden</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      const map = new maplibregl.Map({</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        container: 'map',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        style: 'tiles/strassenraumaufteilung-basemap.json',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        center: [10.131885, 54.315275],</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        zoom: 14,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        maxPitch: 80,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        attributionControl: true,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        hash: true,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        maxBounds: bounds,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        preserveDrawingBuffer: true,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      });</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      //////////// 3D-Gebäude hinzufügen ////////////</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      if (window.innerWidth &gt; 768) {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        map.on('style.load', function () {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          let lod2_layer = new Mapbox3DTiles.Mapbox3DTilesLayer({</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            id: 'lod2_building',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            url: 'https://sg.geodatenzentrum.de/gdz_basemapde_3d_gebaeude/lod2_3857_null.json',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            colorWall: '#c2c2c2',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            colorRoof: '#ff5c4d',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            colorBridge: '#999999'</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          });</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          map.addLayer(lod2_layer, 'Gebaeude3D_nicht_oeffentlich');</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          map.setLayoutProperty('Gebaeude3D_oeffentlich', 'visibility', 'none');</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          map.setLayoutProperty('Gebaeude3D_nicht_oeffentlich', 'visibility', 'none');</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          map.setLayoutProperty('Hauskoordinate', 'visibility', 'none');</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        });</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      // Gebäude erst ab Zoom 16 anzeigen</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      let lod2Visible = false;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      map.on('zoomend', () =&gt; {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        const zoom = map.getZoom();</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        const shouldBeVisible = zoom &gt;= 16;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        if (shouldBeVisible !== lod2Visible) {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          map.setLayoutProperty('lod2_building', 'visibility', shouldBeVisible ? 'visible' : 'none');</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          lod2Visible = shouldBeVisible;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      });</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      //////////// Legende hinzufügen ////////////</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      // Legenden-Einträge definieren</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      map.on('load', function() {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        const targets = {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            // Layername: Anzeigename</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            'Baumstämme': 'Baumstämme',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            'Baumkronen': 'Baumkronen',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            'Fahrbahn': 'Fahrbahn',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            'Radweg': 'Radweg',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            'Fahrbahn / Bushaltefläche': 'Fahrbahn / Bushaltefläche',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            'Fahrbahn / Busspur': 'Fahrbahn / Busspur',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            'Fahrbahn / Radfahrstreifen': 'Fahrbahn / Radfahrstreifen',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            'Fahrbahn / Schutzstreifen': 'Fahrbahn / Schutzstreifen',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            'Fahrbahn / Überwege': 'Fahrbahn / Überwege',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            'Fahrbahn Sperrfläche': 'Fahrbahn Sperrfläche',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            'Fahrradbügelfläche': 'Fahrradbügelfläche',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            'Gehweg': 'Gehweg',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            'Gehweg / Fahrgastwartefläche': 'Gehweg / Fahrgastwartefläche',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            'Gehweg / Radfahrer frei': 'Gehweg / Radfahrer frei',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            'Gehweg / Überfahrt': 'Gehweg / Überfahrt',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            'Komb. Geh- und Radweg': 'Komb. Geh- und Radweg',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            'Parkstreifen': 'Parkstreifen',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            'Radweg / Überfahrt': 'Radweg / Überfahrt',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            'Schutz- / Trennstreifen': 'Schutz- / Trennstreifen',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            'Seitenraum': 'Seitenraum',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            'Seitenstreifen': 'Seitenstreifen',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            'Sonstiges': 'Sonstiges',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            'Sonstiges / Mauerwerk / Stützwände': 'Sonstiges / Mauerwerk / Stützwände',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            'Straßenbegleitgrün': 'Straßenbegleitgrün',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            'Überfahrt / Zufahrt': 'Überfahrt / Zufahrt',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        };</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        // Legende-Button hinzufügen</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        if (window.innerWidth &gt; 768) {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          map.addControl(new MaplibreLegendControl.MaplibreLegendControl(targets, {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">              showDefault: false, </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">              showCheckbox: true,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">              onlyRendered: true,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">              reverseOrder: true,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">              title: 'Legende',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          }), 'top-right');</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      })</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      //////////// Vollbild-Button hinzufügen ////////////</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      map.addControl(new maplibregl.FullscreenControl(), 'top-right',);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      //////////// Navigationsbuttons hinzufügen ////////////</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      map.addControl(new maplibregl.NavigationControl({</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        visualizePitch: true,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        visualizeRoll: true,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        showZoom: true,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        showCompass: true,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        zoomInTitle: 'Hineinzoomen',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        zoomOutTitle: 'Herauszoomen',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        compassTitle: 'Nach Norden ausrichten'</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      }),</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      'top-right'</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      );</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      //////////// 3D-/2D-Ansicht-Button hinzufügen ////////////</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      // Custom-Control-Klasse mit 2D/3D-Umschaltung</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      class Toggle3DControl {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        onAdd(map) {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          this.map = map;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          this.container = document.createElement('div');</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          this.container.className = 'maplibregl-ctrl maplibregl-ctrl-group';</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          const button = document.createElement('button');</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          button.type = 'button';</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          button.textContent = '3D'; // Startmodus</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          button.title = '3D-Ansicht aktivieren';</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          button.style.fontWeight = 'bold';</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          button.style.transition = 'background-color 0.2s ease, color 0.2s ease';</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          let is3D = false;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          button.addEventListener('click', () =&gt; {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            is3D = !is3D;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            if (is3D) {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">              // Cineastischer Wechsel zu 3D</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">              map.easeTo({</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                pitch: 60,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                bearing: -17.6,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                duration: 1500,     // sanfte Animation</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                easing: t =&gt; t*(2-t) // smoother easing</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">              });</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">              button.textContent = '2D';</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">              button.title = '2D-Ansicht aktivieren';</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">              button.style.backgroundColor = '#4CAF50';</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">              button.style.color = '#fff';</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            } else {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">              // Zurück zu 2D</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">              map.easeTo({</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                pitch: 0,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                bearing: 0,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                duration: 1500,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                easing: t =&gt; t*(2-t)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">              });</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">              button.textContent = '3D';</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">              button.title = '3D-Ansicht aktivieren';</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">              button.style.backgroundColor = '';</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">              button.style.color = '';</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          });</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          this.container.appendChild(button);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          return this.container;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        onRemove() {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          this.container.parentNode.removeChild(this.container);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          this.map = undefined;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      // 3D-Button hinzufügen</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      if (window.innerWidth &gt; 768) {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        map.addControl(new Toggle3DControl(), 'top-right');</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      //////////// Messwerkzeug hinzufügen ////////////</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      map.addControl(new maplibreGLMeasures.default({</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        lang: {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            areaMeasurementButtonTitle: 'Fläche messen',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            lengthMeasurementButtonTitle: 'Entfernung messen',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            clearMeasurementsButtonTitle:  'Messungen löschen',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        },</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        units: 'metric',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        unitsGroupingSeparator: '.',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        style: {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          text: {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            radialOffset:  0.9,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            letterSpacing: 0.05,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            color: '#0000FF',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            haloColor: '#fff',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            haloWidth: 4,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            font: 'Open Sans Bold',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          },</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          common: {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            midPointRadius: 6,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            midPointColor: '#0000FF',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            midPointHaloRadius: 10,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            midPointHaloColor: '#FFF',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          },</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          areaMeasurement: {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            fillColor: '#6969E6',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            fillOutlineColor: '#0000FF',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            fillOpacity: 0.2,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            lineWidth: 3,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          },</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          lengthMeasurement: {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            lineWidth: 4,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            lineColor: "#0000FF",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          },</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      }), 'top-right');</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      //////////// Draw-Tool einfügen ////////////</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      // Cache für Styles (Farbe + Opacity pro Feature)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      const colorCache = {};</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      // Konfiguration von maplibre-gl-terradraw</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      const draw = new MaplibreTerradrawControl.MaplibreTerradrawControl({</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">				modes: [</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          'render', // comment this to always show drawing tool</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          'point',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          'linestring',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          'polygon',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          //'rectangle',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          'circle',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          //'freehand',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          //'angled-rectangle',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          //'sensor',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          //'sector',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          'select',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          'delete-selection',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          'delete',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          'download'</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        ],</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">				open: false,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        modeOptions: {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          point: new terraDraw.TerraDrawPointMode({</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">						styles: {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">							pointColor: '#FF0000',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">							pointWidth: 3,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">							pointOutlineColor: '#FF0000',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">							pointOutlineWidth: 1</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">						}</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">					}),</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          linestring: new terraDraw.TerraDrawLineStringMode({</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">						styles: {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">							lineStringColor: '#FF0000',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">							lineStringWidth: 2,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">							closingPointColor: '#FFFFFF',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">							closingPointWidth: 3,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">							closingPointOutlineColor: '#FF0000',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">							closingPointOutlineWidth: 1</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">						}</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">					}),</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          polygon: new terraDraw.TerraDrawPolygonMode({</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">						styles: {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">              // fillColor und fillOpacity werden über ein Farbmenü eingestellt</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">							fillColor: ({ id }) =&gt; {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                if (!colorCache[id]) {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                  showColorMenu(id);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                  return "#000000";</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                return colorCache[id].color;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">              },</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">              fillOpacity: ({ id }) =&gt; {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                return colorCache[id]?.opacity ?? 1.0;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">              },</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">							//outlineColor: '#FF0000',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">							outlineWidth: 0,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">							closingPointColor: '#FAFAFA',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">							closingPointWidth: 3,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">							closingPointOutlineColor: '#FF0000',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">							closingPointOutlineWidth: 1</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">						}</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">					}),</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          circle: new terraDraw.TerraDrawCircleMode({</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            styles: {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">              fillColor: '#F5AEAE',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">              outlineColor: '#FF0000',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">              outlineWidth: 2,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">              fillOpacity: 0.7,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          })</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">			});</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      // Draw-Werkzeug wird hinzugefügt</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      if (window.innerWidth &gt; 768) {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">			  map.addControl(draw, 'top-right');</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      // Farben und Kategorien für das Farbauswahlmenü</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      const palette = [</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        { color: "#464646", label: "Fahrbahn" },</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        { color: "#0000FF", label: "Radweg" },</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        { color: "#6E0000", label: "Fahrbahn / Bushaltefläche" },</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        { color: "#FF7B7B", label: "Fahrbahn / Busspur" },</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        { color: "#56EDD1", label: "Fahrbahn / Radfahrstreifen" },</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        { color: "#0DC773", label: "Fahrbahn / Schutzstreifen" },</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        { color: "#696D53", label: "Fahrbahn / Überwege" },</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        { color: "#9F9F9F", label: "Fahrbahn Sperrfläche" },</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        { color: "#7B7BB9", label: "Fahrradbügelfläche" },</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        { color: "#E6DD79", label: "Gehweg" },</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        { color: "#FF0000", label: "Gehweg / Fahrgastwartefläche" },</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        { color: "#E09524", label: "Gehweg / Radfahrer frei" },</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        { color: "#F9DB81", label: "Komb. Geh- und Radweg" },</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        { color: "#F14D97", label: "Parkstreifen" },</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        { color: "#313179", label: "Radweg / Überfahrt" },</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        { color: "#9A6ABE", label: "Schutz- / Trennstreifen" },</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        { color: "#52917E", label: "Seitenraum" },</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        { color: "#A4A4A4", label: "Seitenstreifen" },</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        { color: "#8E8E8E", label: "Sonstiges" },</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        { color: "#7A7A88", label: "Sonstiges / Mauerwerk / Stützwände" },</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        { color: "#94D180", label: "Straßenbegleitgrün" },</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        { color: "#91AA23", label: "Überfahrt / Zufahrt" },</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      ];</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      // state</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      let activeMenuFeatureId = null;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      const dismissedMenus = new Set(); // optional: wenn Nutzer*in X drückt -&gt; nicht wieder automatisch öffnen</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      // DOM refs</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      const menu = document.getElementById("colorMenu");</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      const colorList = document.getElementById("colorList");</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      const slider = document.getElementById("opacitySlider");</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      const valueLabel = document.getElementById("opacityValue");</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      const closeBtn = document.getElementById("colorMenuClose");</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      // Buttons bauen</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      function buildColorMenu() {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        colorList.innerHTML = "";</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        for (const entry of palette) {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          const btn = document.createElement("button");</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          btn.type = "button";</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          btn.className = "color-option";</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          btn.dataset.color = entry.color;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          btn.innerHTML = `</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            &lt;span class="color-circle" style="background:${entry.color}"&gt;&lt;/span&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            &lt;span class="color-label"&gt;${entry.label}&lt;/span&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          `;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          // optional: aria</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          btn.setAttribute("aria-label", `${entry.label} (${entry.color})`);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          colorList.appendChild(btn);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      buildColorMenu(); // einmal aufbauen</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      // Farbe mit Klick auswählen</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      colorList.addEventListener("click", (ev) =&gt; {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        const btn = ev.target.closest(".color-option");</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        if (!btn) return;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        if (!activeMenuFeatureId) return;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        const selectedColor = btn.dataset.color;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        if (!colorCache[activeMenuFeatureId]) colorCache[activeMenuFeatureId] = { color: selectedColor, opacity: 1.0 };</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        colorCache[activeMenuFeatureId].color = selectedColor;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        draw.updateStyles();</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      });</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      // Opacity-Slider</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      slider.addEventListener("input", () =&gt; {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        const v = parseFloat(slider.value);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        valueLabel.textContent = v.toFixed(1);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        if (activeMenuFeatureId) {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          if (!colorCache[activeMenuFeatureId]) colorCache[activeMenuFeatureId] = { color: palette[0].color, opacity: v };</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          colorCache[activeMenuFeatureId].opacity = v;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          draw.updateStyles();</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      });</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      function showColorMenu(featureId) {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        if (dismissedMenus.has(featureId)) return;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        activeMenuFeatureId = featureId;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        if (!colorCache[featureId]) colorCache[featureId] = { color: palette[0].color, opacity: 1.0 };</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        slider.value = colorCache[featureId].opacity;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        valueLabel.textContent = parseFloat(slider.value).toFixed(1);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        menu.removeAttribute("hidden");</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        // optional: focus first button for accessibility</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        const first = colorList.querySelector(".color-option");</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        if (first) first.focus();</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      function hideColorMenu() {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        activeMenuFeatureId = null;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        menu.setAttribute("hidden", "");</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      // Close button (speichert dismiss-Einstellung)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      closeBtn.addEventListener("click", () =&gt; {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        if (activeMenuFeatureId) dismissedMenus.add(activeMenuFeatureId);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        hideColorMenu();</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      });</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      // ESC schließt das Menü ebenfalls</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      document.addEventListener("keydown", (e) =&gt; { if (e.key === "Escape") { if (activeMenuFeatureId) dismissedMenus.add(activeMenuFeatureId); hideColorMenu(); } });</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      // Optional: verberge Menü, wenn Draw-Mode gewechselt wird</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      if (draw &amp;&amp; typeof draw.on === "function") {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        draw.on("modechange", (event) =&gt; {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          if (event.mode !== "polygon") hideColorMenu();</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        });</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      //////////// Area-Switcher einfügen ////////////</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      map.addControl(new MaplibreAreaSwitcherControl([</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        {title: "Holtenauer Straße",latlng: [10.131849, 54.331142],zoom: 18}, </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        {title: "Andreas-Gayk-Straße",latlng: [10.133646, 54.3190029],zoom: 18}, </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        {title: "Friedrichsorter Straße",latlng: [10.1729513, 54.3958302],zoom: 18},</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        {title: "Seefischmarkt",latlng: [10.180681, 54.325865],zoom: 18},</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        {title: "Gaarden-Ost",latlng: [10.145751, 54.31152],zoom: 16},</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      ]), 'top-right');</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      //////////// Export-Funktion hinzufügen ////////////</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      if (window.innerWidth &gt; 768) {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        map.addControl(new MaplibreExportControl.MaplibreExportControl({</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          PageSize: MaplibreExportControl.Size.A4,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          PageOrientation: MaplibreExportControl.PageOrientation.Landscape,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          Format: MaplibreExportControl.Format.PNG,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          DPI: MaplibreExportControl.DPI[96],</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          Crosshair: true,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          PrintableArea: true, </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          Local: 'de',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          AllowedSizes:[</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "A2", "A3", "A4", "A5", "A6", </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          ],</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          Filename: 'Karte-GeoDatenGuerilla',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          attributionOptions: {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            'visibility': 'visible',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            'position': 'bottom-right',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          },</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        }), </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        'top-right' // Position des Export-Buttons</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        );</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      //////////// Maßstableiste hinzufügen ////////////</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      map.addControl(</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        new maplibregl.ScaleControl({</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          maxWidth: 150,   // maximale Breite in Pixel</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          unit: 'metric'   // 'imperial' für Meilen/Fuß</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        }),</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        'bottom-left'      // Position der Maßstableiste</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      );</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      //////////// Pop-Up bei Klick auf Objekte hinzufügen ////////////</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      // Popup vorbereiten</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      let popup = new maplibregl.Popup({ closeButton: false, closeOnClick: false });</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      // Highlight-Sources vorbereiten</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      map.on('load', () =&gt; {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        map.addSource('highlight-feature', {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          type: 'geojson',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          data: { type: 'FeatureCollection', features: [] }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        });</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        // Highlight-Layer hinzufügen</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        map.addLayer({</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          id: 'highlight-line-outline',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          type: 'line',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          source: 'highlight-feature',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          paint: {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            'line-color': '#000000',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            'line-width': 8,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            'line-opacity': 0.8</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          },</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          filter: ['==', '$type', 'LineString']</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        });</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        map.addLayer({</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          id: 'highlight-line',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          type: 'line',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          source: 'highlight-feature',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          paint: {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            'line-color': '#ffff00',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            'line-width': 6,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            'line-opacity': 0.7</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          },</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          filter: ['==', '$type', 'LineString']</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        });</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        map.addLayer({</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          id: 'highlight-fill',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          type: 'fill',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          source: 'highlight-feature',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          paint: {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            'fill-color': '#ffff00',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            'fill-opacity': 0.3</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          },</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          filter: ['==', '$type', 'Polygon']</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        });</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        map.addLayer({</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          id: 'highlight-fill-outline',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          type: 'line',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          source: 'highlight-feature',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          paint: {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            'line-color': '#000000',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            'line-width': 2,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            'line-opacity': 0.8</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          },</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          filter: ['==', '$type', 'Polygon']</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        });</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        map.addLayer({</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          id: 'highlight-point',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          type: 'circle',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          source: 'highlight-feature',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          paint: {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            'circle-radius': 10,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            'circle-color': '#ffff00',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            'circle-opacity': 0.6,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            'circle-stroke-color': '#000000',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            'circle-stroke-width': 2</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          },</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          filter: ['==', '$type', 'Point']</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        });</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      });</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      // Layerliste für Popups</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      const popupLayers = [</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        'Fahrbahn', 'Radweg', 'Fahrbahn / Bushaltefläche', 'Fahrbahn / Busspur', </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        'Fahrbahn / Radfahrstreifen', 'Fahrbahn / Schutzstreifen', 'Fahrbahn / Überwege', </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        'Fahrbahn Sperrfläche', 'Fahrradbügelfläche', 'Gehweg', </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        'Gehweg / Fahrgastwartefläche', 'Gehweg / Radfahrer frei', 'Gehweg / Überfahrt', </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        'Komb. Geh- und Radweg', 'Parkstreifen', 'Radweg / Überfahrt', </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        'Schutz- / Trennstreifen', 'Seitenraum', 'Seitenstreifen', 'Sonstiges', </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        'Sonstiges / Mauerwerk / Stützwände', 'Straßenbegleitgrün', 'Überfahrt / Zufahrt'</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      ];</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      // Button für Popups</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      let popupEnabled = true;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      class TogglePopupControl {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        onAdd(map) {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          this.map = map;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          this.container = document.createElement('div');</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          this.container.className = 'maplibregl-ctrl maplibregl-ctrl-group';</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          const button = document.createElement('button');</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          button.type = 'button';</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          button.title = 'Popup-Funktion ein-/ausschalten';</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          button.style.display = 'flex';</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          button.style.alignItems = 'center';</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          button.style.justifyContent = 'center';</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          // SVGs vorbereiten</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          const iconActive = `</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            &lt;svg xmlns="http://www.w3.org/2000/svg" </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                width="20" height="20" viewBox="0 0 24 24" </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                fill="none" stroke="currentColor" stroke-width="2" </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                stroke-linecap="round" stroke-linejoin="round"&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">              &lt;circle cx="12" cy="12" r="10"&gt;&lt;/circle&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">              &lt;line x1="12" y1="16" x2="12" y2="12"&gt;&lt;/line&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">              &lt;line x1="12" y1="8" x2="12" y2="8"&gt;&lt;/line&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            &lt;/svg&gt;`;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          const iconInactive = `</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            &lt;svg xmlns="http://www.w3.org/2000/svg" </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                width="20" height="20" viewBox="0 0 24 24" </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                fill="none" stroke="currentColor" stroke-width="2" </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                stroke-linecap="round" stroke-linejoin="round"&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">              &lt;circle cx="12" cy="12" r="10"&gt;&lt;/circle&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">              &lt;line x1="12" y1="16" x2="12" y2="12"&gt;&lt;/line&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">              &lt;line x1="12" y1="8" x2="12" y2="8"&gt;&lt;/line&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">              &lt;line x1="4" y1="20" x2="20" y2="4" stroke="red"&gt;&lt;/line&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            &lt;/svg&gt;`;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          // Funktion für Zustand wechseln</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          function updateButtonState() {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            if (popupEnabled) {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">              button.innerHTML = iconActive;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">              button.style.backgroundColor = '#4CAF50';</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">              button.style.color = '#fff';</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            } else {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">              button.innerHTML = iconInactive;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">              button.style.backgroundColor = '';</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">              button.style.color = '';</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          // Initialzustand: aktiv</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          updateButtonState();</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          // Klick-Handler</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          button.addEventListener('click', () =&gt; {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            popupEnabled = !popupEnabled;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            updateButtonState();</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            if (!popupEnabled) {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">              // Popup + Highlight zurücksetzen</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">              map.getSource('highlight-feature').setData({</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                type: 'FeatureCollection',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                features: []</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">              });</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">              popup.remove();</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          });</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          this.container.appendChild(button);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          return this.container;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        onRemove() {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          this.container.parentNode.removeChild(this.container);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          this.map = undefined;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      // Button hinzufügen</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      map.addControl(new TogglePopupControl(), 'top-right');</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      // Klick-Events</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      popupLayers.forEach(layerId =&gt; {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        map.on('click', layerId, (e) =&gt; {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          if (!popupEnabled) return; // Nur wenn aktiv</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          if (!e.features.length) return;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          const feature = e.features[0];</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          // Highlight aktualisieren</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          map.getSource('highlight-feature').setData(feature);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          // Popup-Inhalt dynamisch aus Properties bauen</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          let propsHtml = '&lt;b&gt;Eigenschaften:&lt;/b&gt;&lt;br&gt;&lt;ul&gt;';</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          for (let key in feature.properties) {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            propsHtml += `&lt;li&gt;&lt;b&gt;${key}&lt;/b&gt;: ${feature.properties[key]}&lt;/li&gt;`;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          propsHtml += '&lt;/ul&gt;';</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          popup</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            .setLngLat(e.lngLat)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            .setHTML(propsHtml)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            .addTo(map);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        });</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        // Cursor ändern bei Hover</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        map.on('mouseenter', layerId, () =&gt; {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          if (popupEnabled) map.getCanvas().style.cursor = 'pointer';</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        });</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        map.on('mouseleave', layerId, () =&gt; {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          if (popupEnabled) map.getCanvas().style.cursor = '';</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        });</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      });</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      // Klick irgendwo anders → nur wenn Popups aktiv</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      map.on('click', (e) =&gt; {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        if (!popupEnabled) return;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        const features = map.queryRenderedFeatures(e.point, { layers: popupLayers });</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        if (!features.length) {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          map.getSource('highlight-feature').setData({</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            type: 'FeatureCollection',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            features: []</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          });</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          popup.remove();</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      });</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    &lt;/script&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  &lt;/body&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">&lt;/html&gt;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="In die Zwischenablage kopieren" title="Kopieren" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>]]></content>
        <author>
            <name>Johanna I. Klitzschmüller</name>
            <email>altesholz@riseup.net</email>
            <uri>https://tech.lgbt/@fedora</uri>
        </author>
        <category label="Geodaten" term="Geodaten"/>
        <category label="3D" term="3D"/>
        <category label="GIS" term="GIS"/>
        <category label="MapLibre" term="MapLibre"/>
        <category label="Verkehrswende" term="Verkehrswende"/>
        <category label="open-source" term="open-source"/>
        <category label="freie Software" term="freie Software"/>
        <category label="Johanna" term="Johanna"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Straßenraumaufteilung in einer Online-Karte]]></title>
        <id>https://geodaten-guerilla.net/blog/strassenraumaufteilung-online-karte</id>
        <link href="https://geodaten-guerilla.net/blog/strassenraumaufteilung-online-karte"/>
        <updated>2024-12-22T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Mit Hilfe der 3D City Database, dem entsprechenden QGIS-Plugin und QGIS2threejs lassen sich 3D-Gebäudemodelle aus LOD-Daten in QGIS visualisieren.]]></summary>
        <content type="html"><![CDATA[<p>In meinen Blogposts zum Thema <a href="https://geodaten-guerilla.net/blog/tags/fernerkundung">Fernerkundung</a> und einem Vortrag auf dem <a href="https://www.webmontag-kiel.de/" target="_blank" rel="noopener noreferrer">WebMontag Kiel</a>, habe ich beschrieben, wie sich mit Hilfe von Satellitendaten und maschinellem Lernen Landnutzungen klassifizieren lassen. Im Nachhinein wurde ich mehrmals angesprochen und bin auf Diskussionen aufmerksam geworden, ob sich diese Technik nutzen ließe, Parkplätze und andere räumliche Nutzungen im städtischen Raum zu untersuchen. Diese Anfragen kamen allesamt von Verkehrswendeaktivist*innen, was ich selbst auch bin. In Verbindung mit Vorträgen und Projekten, die (Verkehrs-)Daten sammeln, nutzbar machen oder selbst generieren, ist mir aufgefallen, dass es ein massives Bedürfnis nach Daten gibt, um für eine <strong>Verkehrswende</strong> zu kämpfen.</p>
<p>Im <a href="https://geodaten-guerilla.net/blog/qgis-3dcitydb-gebaeude">letzten Blogpost</a> habe ich beschrieben, wie sich 3D-Gebäudemodelle in QGIS visualisieren lassen. Da ich in Verbindung mit dem Thema Fernerkundung auf Parkplätze und räumliche Nutzungen angesprochen wurde, kam ich auf die Idee, dass eine Karte, in der die Aufteilung des Straßenraums - in diesem Fall in Kiel - ein gutes karten- und datenbasiertes Werkzeug im Kampf für eine Verkehrswende sein kann. In Verbindung mit den 3D-Gebäudemodellen lässt sich im besten Fall eine Online-Karte erstellen, mit der sich die Straßenräume in 3D erkunden lassen und sich bspw. untersuchen lässt, wie viel Platz für den motorisierten Individualverkehr und für Rad- und Fußverkehr zur Verfügung steht.</p>
<p><img decoding="async" loading="lazy" alt="Zu sehen ist eine Visualisierung von Straßenzügen und Gebäuden. Die Gebäude sind graue Blöcke, die Straßen sind bunt, entsprechend der Aufteilung des Straßenraums. Blick auf die Straße Radbruchstraße in Kiel." src="https://geodaten-guerilla.net/assets/images/demobild-onlinekarte-strassenraum-3D-gebaeude-c2baa2e639176af54560604eeb3fb1e6.png" title="3D-Visualisierung mit Straßenraumaufteilung Radbruchstraße Kiel" width="915" height="786" class="img_ev3q"></p>
<p>Mittels offenen Daten und open-source Software lässt sich eine entsprechende Online-Karte erstellen. In diesem Blogpost zeige ich, welche Daten und welche (Software-)Komponenten benötigt werden, um eine <strong>einfache</strong> Online-Karte zu erstellen.</p>
<p><strong>Die Karte lässt sich hier aufrufen:</strong> <a href="https://geodaten-guerilla.net/maps/strassenraumaufteilung-kiel/" target="_blank" rel="noopener noreferrer">https://geodaten-guerilla.net/maps/strassenraumaufteilung-kiel/</a></p>
<p>Die Karte lässt sich mittels Rechtsklick verschieben. Mit dem Mausrad oder den Navigationsbuttons oben rechts lässt sich in die Karte rein- und rauszommen. Mit Rechtsklick lässt sich der Blickwinkel und die Blickrichtung ändern, sodass eine 3D-Ansicht möglich ist.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="geodaten">Geodaten<a href="https://geodaten-guerilla.net/blog/strassenraumaufteilung-online-karte#geodaten" class="hash-link" aria-label="Direkter Link zur Geodaten" title="Direkter Link zur Geodaten">​</a></h2>
<p>Für diese Online-Karte benötigen wir vor allem Geodaten. Zum einen Daten zur Aufteilung des Straßenraums, zum anderen die 3D-Gebäudemodelle inklusive Hintergrundkarte. Diese Online-Karte wird nicht auf Fernerkundungs-/Satellitendaten basieren, da mir hierfür keine ausreichend hoch aufgelösten Daten zur Verfügung stehen und ich bereits am Anfang meiner Recherche davon ausgegangen bin, dass amtliche Stellen entsprechende Daten vorhalten.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="straßenraum">Straßenraum<a href="https://geodaten-guerilla.net/blog/strassenraumaufteilung-online-karte#stra%C3%9Fenraum" class="hash-link" aria-label="Direkter Link zur Straßenraum" title="Direkter Link zur Straßenraum">​</a></h3>
<p>Bevor wir uns mit der Erstellung der Karte auseinandersetzen, benötigen wir zunächst Geodaten zur Straßenraumaufteilung. Die Landeshauptstadt Kiel besitzt zum Glück solche Daten. Diese wollte sie nach einer ersten Mailanfrage nicht herausgeben, aber nach einer <a href="https://fragdenstaat.de/anfrage/izg-sh-vig-auszug-aus-strassenbestandsflaechen/" target="_blank" rel="noopener noreferrer">Anfrage auf FragDenStaat</a> hat die Stadt Kiel diese zur Verfügung gestellt. Seitdem finden sich die Daten als OpenData mit dem Layernamen "Strassenbestandsflaechen" in den WMS- und WFS-Servern der Stadt.<br>
<!-- -->WMS: <a href="https://ims.kiel.de/geodatenextern/services/Stadtplan/StadtplanKielDe/MapServer/WMSServer?request=getcapabilities&amp;service=wms" target="_blank" rel="noopener noreferrer">https://ims.kiel.de/geodatenextern/services/Stadtplan/StadtplanKielDe/MapServer/WMSServer?request=getcapabilities&amp;service=wms</a><br>
<!-- -->WFS: <a href="https://ims.kiel.de/geodatenextern/services/Stadtplan/LHKielWmsWfs/MapServer/WfsServer?request=getcapabilities&amp;service=wfs" target="_blank" rel="noopener noreferrer">https://ims.kiel.de/geodatenextern/services/Stadtplan/LHKielWmsWfs/MapServer/WfsServer?request=getcapabilities&amp;service=wfs</a></p>
<p>Das besondere an der Stelle ist, dass die Lizenzbedingungen explizit eine Nutzung der Geodaten für <a href="https://www.openstreetmap.org/" target="_blank" rel="noopener noreferrer">OpenStreetMap (OSM)</a> erlauben. Voraussetzung ist eine Nennung der Landeshauptstadt Kiel in der Liste der Beitragenden. Dies ist mittlerweile im <a href="https://wiki.openstreetmap.org/wiki/Contributors#Germany" target="_blank" rel="noopener noreferrer">OpenStreetMap-Wiki</a> erfolgt. Das bedeutet, dass die Daten nicht nur für dieses Projekt unter den Bedingungen der Lizenz <a href="https://creativecommons.org/licenses/by/4.0/" target="_blank" rel="noopener noreferrer">CC BY 4.0</a>, sondern auch für die Erweiterung von OSM-Datenbank genutzt werden können.</p>
<p>Da die Straßenbestandsflächen via WMS-/WFS-Server zur Verfügung stehen, können wir diese später direkt in unsere Online-Karte einbinden. Ich gehe allerdings noch den Umweg, für den Datensatz einen eigenen Style in <a href="https://qgis.org/" target="_blank" rel="noopener noreferrer">QGIS</a> zu erstellen und mittels meinem selbstbetriebenen QGIS-Server in die Karte als WMS einzubinden. Der Style ist oben im Screenshot sehen. Der komplette Datensatz mit dem von mir erstellten Style lässt sich unter <a href="https://geodaten-guerilla.net/downloads/Strassenraumaufteilung-Kiel/strassenbestandsflaechen/strassenbestandsflaechen.gpkg" target="_blank" rel="noopener noreferrer">Downloads</a> als GeoPackage herunterladen.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="datenqualität">Datenqualität<a href="https://geodaten-guerilla.net/blog/strassenraumaufteilung-online-karte#datenqualit%C3%A4t" class="hash-link" aria-label="Direkter Link zur Datenqualität" title="Direkter Link zur Datenqualität">​</a></h3>
<p>Bei der Betrachtung der Daten zur Straßenraumaufteilung und dem Vergleich mit der Realität fällt auf, dass die Daten nur darstellen, als was die jeweiligen Flächen offiziell ausgewiesen/"gewidmet" sind. Wenn bspw. am Straßenrand geparkt werden darf, aber nicht explizit an dieser Straße Parkflächen ausgewiesen sind, dann findet sich in den Daten nur eine Fahrbahn, aber keine Parkflächen an dieser Stelle. Ein anderes Beispiel sind Fahrradstraßen, in denen auch Kfz-Verlehr zugelassen ist. Diese sind auch nur als Fahrbahnen ausgewiesen. Die Daten sollten also mit Vorsicht behandelt werden, geben aber dennoch gut die Verhältnisse wieder, welcher Verkehrsträger in welchem Ausmaß Platz erhält.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="hintergrundkarte">Hintergrundkarte<a href="https://geodaten-guerilla.net/blog/strassenraumaufteilung-online-karte#hintergrundkarte" class="hash-link" aria-label="Direkter Link zur Hintergrundkarte" title="Direkter Link zur Hintergrundkarte">​</a></h3>
<p>Zusätzlich benötigen wir für die Online-Karte noch eine Hintergrundkarte und 3D-Gebäudemodelle. Die 3D-Gebäudemodelle bringen unsere einfache Karte zunächst in die dritte Dimension. Im <a href="https://geodaten-guerilla.net/blog/qgis-3dcitydb-gebaeude">letzten Blogpost</a> habe ich bereits beschrieben, wie sich 3D-Gebäudemodelle in QGIS visualisieren lassen, zunächst werden wir diese Gebäudemodelle aber nicht nutzen. Mit der <a href="https://basemap.de/" target="_blank" rel="noopener noreferrer">basemap.de</a> existiert ein Projekt, mit dem sich amtliche Geodaten als Hintergrundkarten, inklusive 3D-Gebäudemodelle, in Online-Karten einbinden lassen. Leider sind die Gebäude nur im LoD1-Format vorhanden, wodurch diese nur als Blöcke visualisiert werden. Aber für unsere einfache Karte reicht dies zunächst aus.</p>
<p>Es wird zwar eine Beta mit <a href="https://basemap.de/beta-lod2/" target="_blank" rel="noopener noreferrer">LoD2-Gebäuden</a> von basemap.de angeboten, in dieser fehlen allerdings die Gebäude in Schleswig-Holstein.</p>
<p>Zuletzt sei noch erwähnt, dass sich die basemap.de als VectorTiles in Karten einbinden lässt. Das erlaubt uns, den Style anzupassen. Im Fall der basemap.de sind die die Gebäudemodelle leicht durchsichtig, was in meinen Augen irritierend sein kann. Mit <a href="https://maplibre.org/maputnik/" target="_blank" rel="noopener noreferrer">Maputnik</a> gibt es einen open-source Editor, der eine Anpassung des Styles ermöglicht. Dafür muss mensch oben in der Leiste auf "Open" klicken.
<img decoding="async" loading="lazy" alt="Obere Steuerungsleiste von Maputnik" src="https://geodaten-guerilla.net/assets/images/maputnik-leiste-oben-ac873abd07b9b740f92cc986f0b3e7ed.png" title="Obere Steuerungsleiste von Maputnik" width="824" height="95" class="img_ev3q">
Darauffhin öffnet sich ein Fenster, in dem sich der Link zum Style der basemap.de eingeben lässt. Der Style, den wir anpassen wollen hat folgenden Link: <a href="https://sgx.geodatenzentrum.de/gdz_basemapde_vektor/styles/bm_web_col.json" target="_blank" rel="noopener noreferrer">https://sgx.geodatenzentrum.de/gdz_basemapde_vektor/styles/bm_web_col.json</a></p>
<p><img decoding="async" loading="lazy" alt="Zu sehen ist der Open-Dialog von Maputnik. Onem lässt sich eine Datei mittels Upload-Button hochlagen, darunter ist ein Feld, in dem sich ein Link zu einem Style laden lässt. Darunter ist eine Galerie mit vorgefertigten Styles, die sich auswählen lassen, zu finden." src="https://geodaten-guerilla.net/assets/images/maputnik-open-fenster-022d51cf303c4a09c380d5c82372324b.png" title="Open-Dialog von Maputnik" width="605" height="1153" class="img_ev3q"></p>
<p>Wenn der Style geladen ist, erscheint links ein umfangreiches Menü, den Style anzupassen. Rechts in der Kartenansicht lassen sich die Auswirkungen der Anpassungen beobachten.</p>
<p><img decoding="async" loading="lazy" alt="Links sind viele Schaltflächen zu sehen, mit denen sich der Style von VectorTiles bearbeiten lässt. Rechts ist eine Karte zu sehen, in dem Gebäude als Blöcke dargestellt werden." src="https://geodaten-guerilla.net/assets/images/maputnik-style-editor-c3522c5df0eaf0aaed4c9b241cd127b9.png" title="Maputnik Style-Editor" width="1320" height="1078" class="img_ev3q"></p>
<p>Ist der Style fertig angepasst, muss nur noch auf <em>Export</em> und dann auf <em>Download Style</em> geklickt werden. Als Ergebnis erhalten wir eine json-Datei, die sich dann in die Karte einbinden lässt. Meine angepasste json-Datei für die basemap.de ist hier zu finden: <a href="https://geodaten-guerilla.net/downloads/Strassenraumaufteilung-Kiel/basemap_de/basemap-de-angepasster-style-3d-gebaeude.json" target="_blank" rel="noopener noreferrer">https://geodaten-guerilla.net/downloads/Strassenraumaufteilung-Kiel/basemap_de/basemap-de-angepasster-style-3d-gebaeude.json</a>. In diesem Style sind die 3D-Gebäudemodelle nicht mehr durchsichtig.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="kartenanwendung">Kartenanwendung<a href="https://geodaten-guerilla.net/blog/strassenraumaufteilung-online-karte#kartenanwendung" class="hash-link" aria-label="Direkter Link zur Kartenanwendung" title="Direkter Link zur Kartenanwendung">​</a></h2>
<p>Da wir die nun alle Daten beisammen haben, wird es Zeit, die Kartenanwendung zu bauen. Um Online-Karten zu erstellen, gibt es open-source Bibliotheken wie <a href="https://openlayers.org/" target="_blank" rel="noopener noreferrer">OpenLayers</a>, <a href="https://leafletjs.com/" target="_blank" rel="noopener noreferrer">Leaflet</a> oder <a href="https://maplibre.org/" target="_blank" rel="noopener noreferrer">MapLibre</a>. Ich habe mich in diesem Fall für <strong>MapLibre</strong> entschieden.</p>
<p>Für <em>MapLibre</em> gibt es eine <a href="https://maplibre.org/maplibre-gl-js/docs/" target="_blank" rel="noopener noreferrer">Dokumentation</a>, die auch verschiedene <a href="https://maplibre.org/maplibre-gl-js/docs/examples/" target="_blank" rel="noopener noreferrer">Code-Beispiele</a> enthält.</p>
<p>Eine Erfahrung, die ich in der Arbeit mit verschiedenen, auf <em>MapLibre</em> basierenden Tools gemacht habe, ist, dass es sinnvoll ist, möglichst alle Daten, die mensch einbinden will, auf externe Dienste auszulagern und nicht als geojson-Datei einzubinden. Denn bei großen Dateigrößen dauert das Laden der Karte sehr lange oder die Karte wird gar nicht erst geladen.</p>
<p>Die Karte initialisieren wir einfach mit dem folgenden Code. Dieser basiert auf dem <a href="https://maplibre.org/maplibre-gl-js/docs/examples/wms/" target="_blank" rel="noopener noreferrer">Dokumentations-Beispiel zur Einbindung von WMS-Services</a>.</p>
<div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">&lt;!DOCTYPE html&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">&lt;html lang="en"&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">&lt;head&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    &lt;title&gt;Straßenraumaufteilung in Kiel&lt;/title&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    &lt;meta property="og:description" content="Add an external Web Map Service raster layer to the map using addSource's tiles option." /&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    &lt;meta charset='utf-8'&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    &lt;meta name="viewport" content="width=device-width, initial-scale=1"&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    &lt;link rel='stylesheet' href='https://unpkg.com/maplibre-gl@4.7.1/dist/maplibre-gl.css' /&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    &lt;script src='https://unpkg.com/maplibre-gl@4.7.1/dist/maplibre-gl.js'&gt;&lt;/script&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    &lt;style&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        body { margin: 0; padding: 0; }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        html, body, #map { height: 100%; }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    &lt;/style&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">&lt;/head&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">&lt;body&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">&lt;div&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    &lt;a href="https://maplibre.org/"&gt;MapLibre&lt;/a&gt; &lt;b&gt;|&lt;/b&gt; © GeoBasis-DE / &lt;a href="https://www.bkg.bund.de"&gt;BKG&lt;/a&gt; 2024 &lt;a href="https://creativecommons.org/licenses/by/4.0/"&gt;CC BY 4.0&lt;/a&gt; (Style angepasst) | Landeshauptstadt Kiel CC-BY-4.0 &lt;b&gt;|&lt;/b&gt; &lt;a href="https://geodaten-guerilla.net/impressum"&gt;Impressum&lt;/a&gt; | &lt;a href="https://geodaten-guerilla.net/datenschutzerklaerung"&gt;Datenschutz&lt;/a&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">&lt;/div&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">&lt;div id="map"&gt;&lt;/div&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">&lt;script&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    const map = new maplibregl.Map({</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        container: 'map',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        style: 'https://geowebdienste.geodaten-guerilla.net/downloads/basemap-de-angepasster-style-3d-gebaeude.json',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        zoom: 13,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        center: [10.131885, 54.315275], // Zentriert auf Kiel</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        attributionControl: false,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        maxPitch: 85,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    });</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    map.addControl(new maplibregl.NavigationControl());</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    map.on('load', () =&gt; {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        map.addSource('wms-test-source', {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            'type': 'raster',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            // use the tiles option to specify a WMS tile source URL</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            // https://maplibre.org/maplibre-style-spec/sources/</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            'tiles': [</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                'https://geowebdienste.geodaten-guerilla.net/qgisserver?MAP=/opt/owsprojects/strassenbestandsflaechen-wms/strassenbestandsflaechen-wms.qgs&amp;bbox={bbox-epsg-3857}&amp;format=image/png&amp;service=WMS&amp;version=1.1.1&amp;request=GetMap&amp;srs=EPSG:3857&amp;transparent=true&amp;width=256&amp;height=256&amp;layers=strassenbestandsflaechen'</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            ],</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            'tileSize': 256,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        });</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        map.addLayer(</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                'id': 'wms-test-layer',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                'type': 'raster',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                'source': 'wms-test-source',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                'paint': {}</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            },</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        );</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    });</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">&lt;/script&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">&lt;/body&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">&lt;/html&gt;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="In die Zwischenablage kopieren" title="Kopieren" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>In der Zeile <em>style</em> ist die Hintergrundkarte mit dem angepassten Style eingebunden.</p>
<div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">const map = new maplibregl.Map({</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        container: 'map',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        style: 'https://geowebdienste.geodaten-guerilla.net/downloads/basemap-de-angepasster-style-3d-gebaeude.json',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        zoom: 13,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        center: [10.131885, 54.315275], // Zentriert auf Kiel</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        attributionControl: false,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        maxPitch: 85,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    });</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="In die Zwischenablage kopieren" title="Kopieren" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Mittels <em>map.addControl</em> werden Navigationsbuttons angezeigt.</p>
<div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">map.addControl(new maplibregl.NavigationControl());</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="In die Zwischenablage kopieren" title="Kopieren" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Die Quellenangaben werden erstmal mit einem einfachen <em>div</em> angezeigt. <em>MapLibre</em> bietet eine eigene Funktion an, Quellenangaben anzuzeigen, diese verwenden wir aber erstmal nicht.</p>
<div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">&lt;div&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    &lt;a href="https://maplibre.org/"&gt;MapLibre&lt;/a&gt; &lt;b&gt;|&lt;/b&gt; © GeoBasis-DE / &lt;a href="https://www.bkg.bund.de"&gt;BKG&lt;/a&gt; 2024 &lt;a href="https://creativecommons.org/licenses/by/4.0/"&gt;CC BY 4.0&lt;/a&gt; (Style angepasst) | Landeshauptstadt Kiel CC-BY-4.0 &lt;b&gt;|&lt;/b&gt; &lt;a href="https://geodaten-guerilla.net/impressum"&gt;Impressum&lt;/a&gt; | &lt;a href="https://geodaten-guerilla.net/datenschutzerklaerung"&gt;Datenschutz&lt;/a&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">&lt;/div&gt;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="In die Zwischenablage kopieren" title="Kopieren" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Die Straßenraumaufteilung wird über den WMS-Server eingebunden, der meinen eigenen Style enthält.</p>
<div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">    map.on('load', () =&gt; {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        map.addSource('wms-test-source', {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            'type': 'raster',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            // use the tiles option to specify a WMS tile source URL</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            // https://maplibre.org/maplibre-style-spec/sources/</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            'tiles': [</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                'https://geowebdienste.geodaten-guerilla.net/qgisserver?MAP=/opt/owsprojects/strassenbestandsflaechen-wms/strassenbestandsflaechen-wms.qgs&amp;bbox={bbox-epsg-3857}&amp;format=image/png&amp;service=WMS&amp;version=1.1.1&amp;request=GetMap&amp;srs=EPSG:3857&amp;transparent=true&amp;width=256&amp;height=256&amp;layers=strassenbestandsflaechen'</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            ],</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            'tileSize': 256,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        });</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        map.addLayer(</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                'id': 'wms-test-layer',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                'type': 'raster',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                'source': 'wms-test-source',</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                'paint': {}</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            },</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        );</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    });</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="In die Zwischenablage kopieren" title="Kopieren" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Mit diesem einfachen Code-Schnipsel haben wir mit <em>MapLibre</em> eine funktionierende, einfache Kartenanwendung gebaut, in der sich die Straßenraumaufteilung in einer 3D-Umgebung untersuchen lässt.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="tileserver">Tileserver<a href="https://geodaten-guerilla.net/blog/strassenraumaufteilung-online-karte#tileserver" class="hash-link" aria-label="Direkter Link zur Tileserver" title="Direkter Link zur Tileserver">​</a></h2>
<p>Auch wenn wir jetzt eine funktionierende Kartenanwendung haben, in der Daten mittels WMS eingebunden werden, möchte ich noch die Installation und Verwendung eines Tileservers erklären. Es ist nämlich sinnvoll, alle Daten extern mit Services wie WMS oder VectorTiles einzubinden, da es bei großen Datenmengen, die als Dateien direkt in die Kartenanwendung eingebunden werden, dauern kann, bis die Kartenanwendung vollständig lädt. Außerdem kann eine flüssige Bedienung der Kartenanwendung dabei unmöglich werden. VectorTiles haben den Vorteil, dass das Datenformat für die <a href="https://wheregroup.com/blog/details/vector-tiles-und-qgis/" target="_blank" rel="noopener noreferrer">schnelle Übertragung über das Internet optimiert ist</a>.</p>
<p>Es gibt verschiedene <a href="https://wiki.openstreetmap.org/wiki/Tile_servers" target="_blank" rel="noopener noreferrer">open-source Software-Lösungen für Tileserver</a>. Ich habe mich für <a href="https://github.com/consbio/mbtileserver" target="_blank" rel="noopener noreferrer">mbtileserver</a> entschieden, da es sehr einfach zu installieren und zu betreiben ist.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="mbtileserver">mbtileserver<a href="https://geodaten-guerilla.net/blog/strassenraumaufteilung-online-karte#mbtileserver" class="hash-link" aria-label="Direkter Link zur mbtileserver" title="Direkter Link zur mbtileserver">​</a></h3>
<p>Nach der Installation von <em>mbtileserver</em> lässt sich dieser mit einem einfachen Befehl im Ordner, wo es installiert wurde, starten:
<code>./mbtileserver -d /path/to/mbtiles --enable-fs-watch --root-url /tileserver --generate-ids</code>.<br>
<!-- -->Mit diesem Befehl beobachtet <em>mbtileserver</em> Veränderungen im Ablageordner, ist via /tileserver aufrufbar und, um die Ordnerstruktur nicht nach außen zu leaken, wird die URL IDs statt den Dateipfad enthalten.</p>
<p>Wenn mbtileserver gestartet ist, lässt sich im Browser unter url/tileserver eine JSON-Ansicht aufrufen, in der sich alle VectorTiles, die mbtileserver zur Verfügung stellen kann, auffinden lassen.</p>
<p><img decoding="async" loading="lazy" alt="Es ist die JSON-Ansicht von Firefox zu sehen. In der Mitte ist eine URL markiert, die zu der Detailansicht des VectorTile führt." src="https://geodaten-guerilla.net/assets/images/mbtileserver-uebersicht-bc854b127cabff3e247e22fa57358932.png" title="mbtileserver-Übersicht" width="700" height="179" class="img_ev3q"></p>
<p>Wenn mensch auf die URL klickt, erscheint eine Detailansicht des Vectortiles mit seinen Eigenschaften, Layern und Attributen.</p>
<p><img decoding="async" loading="lazy" alt="mbtileserver-detailansicht.png" src="https://geodaten-guerilla.net/assets/images/mbtileserver-detailansicht-679bc60b3b14d3bd17fc6da42e5323f6.png" title="mbtileserver-Detailansicht" width="964" height="896" class="img_ev3q"></p>
<p>In dieser Detailansicht ist der Link unter tiles → 0 der entscheidende. Diesen können wir nutzen, um die VectorTiles in <em>QGIS</em> oder unserer Kartenanwendung einzubinden. Allerdings werden wir dann noch keinen Style in der Karte für die VectorTiles haben. Aber auch hierfür können wir <a href="https://maplibre.org/maputnik/" target="_blank" rel="noopener noreferrer">Maputnik</a> nutzen, um einen Style zu erstellen. Die Detailansicht von <em>mbtiles</em> können wir nämlich einfach als JSON-Datei herunterladen (strg+s drücken) und in <em>Maputnik</em> hochladen.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="konvertierung-zu-mbtiles">Konvertierung zu mbtiles<a href="https://geodaten-guerilla.net/blog/strassenraumaufteilung-online-karte#konvertierung-zu-mbtiles" class="hash-link" aria-label="Direkter Link zur Konvertierung zu mbtiles" title="Direkter Link zur Konvertierung zu mbtiles">​</a></h3>
<p>Damit mbtileserver oder andere Tileserver VectorTiles zur Verfügung stellen können, müssen die entsprechenden Geodaten zunächst in das mbtiles-Dateiformat konvertiert werden. Hierfür gibt es mehrere open-source Tools:</p>
<ul>
<li><strong>QGIS</strong> - Als weit verbreitetes open-source GIS beherrscht <em>QGIS</em> die Funktion, Geodaten in mbtiles zu konvertieren. Laut meiner Erfahrung braucht QGIS allerdings sehr lange bei großen Datenmengen dafür. Darum empfehle ich es an der Stelle nicht.</li>
<li><strong>GDAL</strong> -  Auch <em>GDAL</em> besitzt eine entsprechende <a href="https://gdal.org/en/latest/drivers/raster/mbtiles.html" target="_blank" rel="noopener noreferrer">Konvertierungsfunktion</a>. Diese lässt sich mittels <code>ogr2ogr -f MBTILES target.mbtiles source.gpkg -dsco MAXZOOM=10</code> nutzen.</li>
<li><strong>tippecanoe</strong> - Hierbei handelt es sich um einen <a href="https://github.com/felt/tippecanoe?tab=readme-ov-file" target="_blank" rel="noopener noreferrer">gepflegten Fork</a> der <a href="https://github.com/mapbox/tippecanoe?tab=readme-ov-file" target="_blank" rel="noopener noreferrer">gleichnamigen Mapbox-Anwendung</a>. <em>tippecanoe</em> erstellt die mbtiles aus GeoJSON-Dateien.</li>
</ul>
<p>Ich habe mich am Ende für <em>tippecanoe</em> entschieden, da ich das Konvertierungsergebnis als am besten empfand. Genutzt habe ich folgendenen Befehl zum Konvertieren:<br>
<code>tippecanoe --force -Z 12 -zg -o strassenbestandsflaechen.mbtiles --extend-zooms-if-still-dropping *.geojson</code></p>
<ul>
<li>The <code>-zg</code> option will make Tippecanoe choose a maximum zoom level that should be high enough to reflect the precision of the original data.</li>
<li><code>-f</code> or <code>--force</code>: Delete the mbtiles file if it already exists instead of giving an error</li>
<li><code>-Z</code> <em>zoom</em> or <code>--minimum-zoom=</code> <em>zoom</em>: Minzoom: the lowest zoom level for which tiles are generated (default 0)</li>
</ul>
<p>Die genutzten Parameter sind im <em><a href="https://github.com/felt/tippecanoe?tab=readme-ov-file#cookbook" target="_blank" rel="noopener noreferrer">tippecanoe-Repository</a></em> dokumentiert. Wichtig an der Stelle zu wissen ist, dass <em>tippecanoe</em> <a href="https://epsg.io/4326" target="_blank" rel="noopener noreferrer">EPSG:4326</a> bei den Eingangsdaten erwartet.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="fazit">Fazit<a href="https://geodaten-guerilla.net/blog/strassenraumaufteilung-online-karte#fazit" class="hash-link" aria-label="Direkter Link zur Fazit" title="Direkter Link zur Fazit">​</a></h2>
<p>Mit der nun fertigen Online-Karte haben wir eine zwar erstmal einfache Karte, aber mit ihr können wir für die ganze Stadt Kiel visualisieren, wie die Straßenräume aufgeteilt sind. Damit wird es möglich, datenbasiert die politischen Diskussionen zu führen, wie der Raum in der Stadt aufgeteilt ist und aufgeteilt werden sollte. Damit steht uns ein weiteres Werkzeug im Kampf für die Verkehrswende zur Verfügung.</p>]]></content>
        <author>
            <name>Johanna I. Klitzschmüller</name>
            <email>altesholz@riseup.net</email>
            <uri>https://tech.lgbt/@fedora</uri>
        </author>
        <category label="Geodaten" term="Geodaten"/>
        <category label="3D" term="3D"/>
        <category label="GIS" term="GIS"/>
        <category label="QGIS" term="QGIS"/>
        <category label="MapLibre" term="MapLibre"/>
        <category label="Verkehrswende" term="Verkehrswende"/>
        <category label="open-source" term="open-source"/>
        <category label="freie Software" term="freie Software"/>
        <category label="Johanna" term="Johanna"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[3D-Gebäudemodelle mit der 3D City Database und QGIS2threejs in QGIS visualisieren]]></title>
        <id>https://geodaten-guerilla.net/blog/qgis-3dcitydb-gebaeude</id>
        <link href="https://geodaten-guerilla.net/blog/qgis-3dcitydb-gebaeude"/>
        <updated>2024-03-31T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Mit Hilfe der 3D City Database, dem entsprechenden QGIS-Plugin und QGIS2threejs lassen sich 3D-Gebäudemodelle aus LOD-Daten in QGIS visualisieren.]]></summary>
        <content type="html"><![CDATA[<p><a href="https://digitalcourage.social/" target="_blank" rel="noopener noreferrer">Mastodon</a> und der <a href="https://www.webmontag-kiel.de/" target="_blank" rel="noopener noreferrer">WebMontag Kiel</a> sind cool. Die Gespräche nach meinem ersten <a href="https://geodaten-guerilla.net/blog/WebMontag-GeographyForFuture">Vortrag beim WebMontag</a> setzte den Gedanken in meinen Kopf, die Arbeit mit Geodaten und Karten in die dritte Dimension zu überführen. Nach dem zweiten Vortrag (Blogposts <a href="https://geodaten-guerilla.net/blog/Fernerkundung-Informationsgewinnung-ferne">1</a> und <a href="https://geodaten-guerilla.net/blog/Fernerkundung-Klassifikation-Anpassung">2</a> zu Fernerkundung) entstand ein langer <a href="https://digitalcourage.social/@thijs_lucas@norden.social/110730839899048621" target="_blank" rel="noopener noreferrer">Mastodon-Thread</a> mit der ursprünglichen Idee, Flächenaufteilungen in Städten kenntlich zu machen.</p>
<p>Daraus entstand eine Projektidee, die das Ziel hat, ein 3D-Modell der Stadt Kiel mit der Aufteilung des Straßenraums in einem GIS - im besten Fall in einem WebGIS - zu haben, in welchem mensch Berechnungen zur Aufteilung des Straßenraums durchführen kann und in dem Änderungen eingebaut und visualisiert werden können. Ob dieses Projekt für mich umsetzbar ist, vermag ich an dieser Stelle noch nicht zu vorherzusagen, aber ich möchte dennoch mein Vorgehen, meine Ideen und die Probleme, auf die ich stoße, in zukünftigen Blogposts beschreiben. An dieser Stelle sei auch gesagt, dass ich gerne <a href="https://geodaten-guerilla.net/mitmachen-kontakt#kontakt">Ideen, Anregungen und Hilfe annehme</a>.</p>
<p>Der erste Schritt ist in meinen Augen, die Gebäude in der Stadt in 3D darzustellen. Damit gewinnen wir bereits einen ersten räumlichen Eindruck des städtischen Raumes, außerdem liegen 3D-Gebäudemodelle vom Vermessungsamt als OpenData vor. Wie eine Visualisierung dieser 3D-Gebäudemodelle im open-source GIS <a href="https://qgis.org/" target="_blank" rel="noopener noreferrer">QGIS</a> gelingen kann, beschreibe ich in diesem Blogpost.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="lod-daten-in-qgis">LoD-Daten in QGIS<a href="https://geodaten-guerilla.net/blog/qgis-3dcitydb-gebaeude#lod-daten-in-qgis" class="hash-link" aria-label="Direkter Link zur LoD-Daten in QGIS" title="Direkter Link zur LoD-Daten in QGIS">​</a></h2>
<p>Das <a href="https://www.schleswig-holstein.de/DE/landesregierung/ministerien-behoerden/LVERMGEOSH/lvermgeosh_node.html" target="_blank" rel="noopener noreferrer">Landesamt für Vermessung und Geoinformation Schleswig-Holstein</a> stellt <a href="https://www.schleswig-holstein.de/DE/landesregierung/ministerien-behoerden/LVERMGEOSH/Service/serviceGeobasisdaten/geodatenService_Geobasisdaten_LoD.html" target="_blank" rel="noopener noreferrer">3D-Gebäudemodelle in LoD1 und LoD2 (Level of Detail)</a> als OpenData zur Verfügung. LoD1 bedeutet, dass die Gebäude als Blöcke oder Klötze mit Flachdach dargestellt werden. Die Höhe der Blöcke wird durch den höchsten Punkt des Gebäudes bestimmt. In LoD2 erhalten die Gebäudemodelle Standarddachformen. Ich möchte für die Visualisierung die Gebäude im LoD2 verwenden. Diese kann mensch im <a href="https://geodaten.schleswig-holstein.de/gaialight-sh/_apps/dladownload/" target="_blank" rel="noopener noreferrer">Downloadportal für offene Geobasisdaten</a> herunterladen.</p>
<p>Die Gebäudemodelle liegen im CityGML-Dateiformat vor. Auch wenn QGIS GML lesen kann, zeigen sich in der Kartenansicht sofort die ersten Probleme: Es fehlen Gebäude. Bei der Ansicht der LoD1-Gebäude sind die Lücken gut zu erkennen:</p>
<p><img decoding="async" loading="lazy" alt="Kartendarstellung in QGIS. Die magentafarbenen Polygone stellen Gebäude dar. Darunter ist eine Hintergrundkarte zu sehen." src="https://geodaten-guerilla.net/assets/images/qgis-lod1-luecken-8d2b3bd9f3923721ddc49a0febee187f.png" title="LoD1 als Polygone mit Gebäudelücken" width="2050" height="1690" class="img_ev3q"></p>
<p>Auch bei den LoD2-Gebäuden zeigen sich Lücken und sie werden von QGIS als Linien eingelesen:</p>
<p><img decoding="async" loading="lazy" alt="Kartendarstellung in QGIS. Die lilafarbenen Linien stellen Gebäude dar. Darunter ist eine Hintergrundkarte zu sehen." src="https://geodaten-guerilla.net/assets/images/qgis-lod2-nur-linien-cba41f95870cad4338d5dadc5a3e099c.png" title="LoD2 als Linien mit Gebäudelücken" width="2050" height="1690" class="img_ev3q"></p>
<p>Zu den hier sichtbaren Problemen kam dann auch noch, dass QGIS das Höhen-Attribut entweder als Real oder als String ausgelesen hat. Angesichts dieser Probleme erscheint QGIS nicht als das Mittel der Wahl, mit 3D-Gebäudemodellen zu arbeiten. Dennoch habe ich erste Visualisierungen mit Gebäuden, Straßenraumaufteilung und Bäumen erstellt:</p>
<p><img decoding="async" loading="lazy" alt="Zu sehen ist eine Visualisierung von Straßenzügen und Gebäuden. Die Gebäude sind graue Blöcke, die Straßen sind bunt, entsprechend der Aufteilung des Straßenraums. Blick auf die Straße Brauner Berg in Kiel." src="https://geodaten-guerilla.net/assets/images/FrOrt-dfaad8b3e416cccb7cf211e1991f0ed1.png" title="3D-Visualisierung Brauner Berg in Kiel" width="1566" height="353" class="img_ev3q"></p>
<p>Die Probleme zeigen, dass es einen Weg braucht, die 3D-Gebäudemodelle so einzulesen und zu speichern, dass QGIS diese vernünftig anzeigen und visualisieren kann. Zum Glück gibt es mit der <a href="https://www.3dcitydb.org/3dcitydb/" target="_blank" rel="noopener noreferrer">3D City Database</a> eine Datenbank, die auf die Speicherung und Verwaltung von CityGML-Dateien ausgelegt ist.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="3d-city-database">3D City Database<a href="https://geodaten-guerilla.net/blog/qgis-3dcitydb-gebaeude#3d-city-database" class="hash-link" aria-label="Direkter Link zur 3D City Database" title="Direkter Link zur 3D City Database">​</a></h2>
<p>Die <a href="https://www.3dcitydb.org/3dcitydb/" target="_blank" rel="noopener noreferrer">3D City Database</a> (3DCityDB) ist eine Geodatenbank, die 3D-Städte- und Gebäudemodelle speichern, verwalten und repräsentieren kann. Sie ist dabei insbesondere auf das CityGML-Format, in dem die schleswig-holsteinischen LoD-Daten vorliegen, ausgelegt. Da die <em>3DCityDB</em> vom Prinzip eine PostGIS-Datenbank mit Erweiterungen, die die Arbeit mit 3D-Modellen ermöglichen, ist, ist eine Verbindung mit QGIS einfach herzustellen. Die Installation und Einrichtung der <em>3DCityDB</em> ist ausführlich <a href="https://3dcitydb-docs.readthedocs.io/en/latest/index.html" target="_blank" rel="noopener noreferrer">dokumentiert</a>. Ich habe die <em>3DCityDB</em> mittels Docker installiert:</p>
<p>docker pull 3dcitydb/3dcitydb-pg<!-- -->:latest</p>
<p>docker run -d -p 5432:5432 --name 3dcitydatabase -e \
POSTGRES_PASSWORD=SuperGeheimesPasswort -e SRID=25832 <br>
<!-- -->-e POSTGRES_DB=SuperTollerDatenbankname <br>
<!-- -->-e POSTGRES_USER=SuperTollerUser -e POSTGIS_SFCGAL=true <br>
<!-- -->3dcitydb/3dcitydb-pg</p>
<p>Weitere mögliche Anpassungen des Docker-Containers, bspw. bessere Performace der PostGIS-Datenbank, sind <a href="https://3dcitydb-docs.readthedocs.io/en/latest/3dcitydb/docker.html" target="_blank" rel="noopener noreferrer">dokumentiert</a>. Sobald die <em>3DCityDB</em> installiert und einsatzbereit ist, ist der wichtigste Punkt, eine Möglichkeit, 3D-Gebäudemodelle entsprechend ihrem Datenformat zu speichern, erledigt. Nun müssen die Gebäudemodelle ihren Weg in die Datenbank finden.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="importer-für-die-3d-city-database">Importer für die 3D City Database<a href="https://geodaten-guerilla.net/blog/qgis-3dcitydb-gebaeude#importer-f%C3%BCr-die-3d-city-database" class="hash-link" aria-label="Direkter Link zur Importer für die 3D City Database" title="Direkter Link zur Importer für die 3D City Database">​</a></h2>
<p>Wenn die Datenbank installiert und einsatzbereit ist, können CityGML-Dateien mittels eines Importers importiert werden. Für den Importer liegt ein grafisches Installationsprogramm vor. Der Importer muss nicht auf dem Server, wo die <em>3DCityDB</em> installiert ist, installiert werden, sondern kann auf jedem Computer installiert werden, der eine Verbindung zur <em>3DCityDB</em> herstellen soll.</p>
<p>Die Nutzung des Importers geht einfach von der Hand. Im Reiter Database muss mensch die Verbindungsdaten zur <em>3DCityDB</em> eingeben und sich mit der Datenbank verbinden. Danach geht es unter dem Reiter Import weiter, wo mensch die zu importieren CityGML-Dateien auswählen und dann importieren muss. Auch die Installation und Nutzung des Importers ist ausführlich <a href="https://3dcitydb-docs.readthedocs.io/en/latest/impexp/index.html" target="_blank" rel="noopener noreferrer">dokumentiert</a>.</p>
<p>Damit sind die 3D-Gebäudemodelle in der Datenbank. Allerdings fehlt noch ein Workflow und ein Weg, die 3D-Gebäudemodelle vernünftig in QGIS einzulesen. Denn trotz Datenbank und Importer müssen Stand jetzt die Modelle wieder aus der Datenbank exportiert werden, um sie dann in QGIS einzufügen. Damit wären wir wieder am Anfang. Aber für die Zusammenarbeit zwischen der <em>3DCityDB</em> und QGIS gibt es ein praktisches QGIS-Plugin.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="3dcitydb-tools">3DCityDB-Tools<a href="https://geodaten-guerilla.net/blog/qgis-3dcitydb-gebaeude#3dcitydb-tools" class="hash-link" aria-label="Direkter Link zur 3DCityDB-Tools" title="Direkter Link zur 3DCityDB-Tools">​</a></h2>
<p>Im Pluginmanager von QGIS findet sich das Plugin <strong>3DCityDB Tools</strong>. Mit diesem lassen sich die 3D-Gebäudemodelle, die sich in der <em>3DCityDB</em> befinden, in QGIS anzeigen und bearbeiten. Es zeigt sich, dass die Gebäude nun vollständig in QGIS zu sehen sind. Es sind keine Gebäudelücken zu sehen und die Dachstrukturen lassen sich in der 2D-Kartenansicht schon erahnen:</p>
<p><img decoding="async" loading="lazy" alt="Kartendarstellung in QGIS. Die roten Polygone mit den schwarzen Linien stellen Gebäude dar. Darunter ist eine Hintergrundkarte zu sehen." src="https://geodaten-guerilla.net/assets/images/qgis-lod2-mapview-b5018b7543c0921a2c6c474428655c9c.png" title="LoD2-Gebäudemodelle aus der 3DCityDB in QGIS" width="2050" height="1690" class="img_ev3q"></p>
<p>Für die Einrichtung des 3DCityDB-Tools-Plugin existiert eine Schritt-für-Schritt-Anleitung. Diese ist über <em>Database &gt; 3DCityDB Tools &gt; User Guide (PDF)</em> aufzufinden. Wenn mensch weitere 3D-Gebäudemodelle hinzufügen möchte, müssen diese über den Importer in die <em>3DCityDB</em> importiert werden. Danach muss im <em>Layer Loader</em> des Plugins auf <em>Refresh layers</em> und <em>refresh extents</em> geklickt werden.</p>
<p>Damit ist die Datenbank, in der die 3D-Gebäudemodelle gespeichert werden, und ein Workflow aus Importer und <em>3DCityDB-Tools</em>, um die Gebäudemodelle in QGIS zu laden, einsatzbereit. Nun fehlt nur noch die Visualisierung der 3D-Gebäude.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="qgis2threejs">QGIS2threejs<a href="https://geodaten-guerilla.net/blog/qgis-3dcitydb-gebaeude#qgis2threejs" class="hash-link" aria-label="Direkter Link zur QGIS2threejs" title="Direkter Link zur QGIS2threejs">​</a></h2>
<p>Für die Visualisierung der 3D-Gebäudemodelle nutze ich das QGIS-Plugin <em>QGIS2threejs</em>. QGIS hat zwar einen eigenen 3D-Viewer, hierfür muss mensch aber erst Styles in den Layer-Eigenschaften erstellen. In <em>QGIS2threejs</em> werden die Gebäudemodelle direkt mit ihren Dachformen angezeigt. Ich nutze das Plugin vorerst nur als Viewer. Es kann aber weitaus mehr, wie bspw. 3D-Daten im Webbrowser visualisieren.</p>
<p>Beim Öffnen von <em>QGIS2threejs</em> fällt auf, dass es links eine Layer-Ansicht gibt. In dieser wählt mensch die verschiedenen Bestandteile der Gebäudemodelle aus. In diesem Fall die Dächer und Wände der Gebäude und der Gebäudeteile. Mit einem Rechtsklick auf die jeweiligen Layer lassen sich die Eigenschaften öffnen, in denen mensch die Layer stylen kann, also bspw. rot für die Dächer.</p>
<p><img decoding="async" loading="lazy" alt="Zu sehen ist ein Screenshot der in QGIS2threejs auswählbaren Layer" src="https://geodaten-guerilla.net/assets/images/qgis2threejs-layers-557777dbedcd23dec82d8a7ce1e91965.png" title="Layer-Ansicht in QGIS2threejs" width="245" height="662" class="img_ev3q"></p>
<p>Zusätzlich habe ich in das QGIS-Projekt ein digitales Geländemodell mit einer Gitterweite von 200 Metern (DGM200) eingefügt. Es handelt sich dabei um das DGM vom <a href="https://daten.gdz.bkg.bund.de/produkte/dgm/dgm200/aktuell/dgm200.utm32s.xyzascii.zip" target="_blank" rel="noopener noreferrer">Bundesamt für Kartographie und Geodäsie</a>. Dieses habe ich für die Nutzung in QGIS mit der Bibliothek GDAL in eine tif-Datei umgewandelt:</p>
<p>gdal_translate -a_srs EPSG:25832 dgm200_utm32s.xyz germanyDGM200.tif</p>
<p>Der Hintergrund ist, dass ich dann in <em>QGIS2threejs</em> beim Layer <em>Straßenbestandsflächen</em> in den Eigenschaften den Modus auf <em>Relative to "germanyDGM200" layer</em> einstellen konnte. Dadurch befinden sich die <em>Straßenbestandsflächen</em> im <em>QGIS2threejs</em>-Viewerauf der selben Höhe wie die Gebäude.</p>
<p>Damit ist alles bereit, 3D-Gebäudemodelle zu visualisieren. Angereichert mit Daten zur Aufteilung des Straßenraums und Bäumen aus <a href="https://www.openstreetmap.org/" target="_blank" rel="noopener noreferrer">OpenStreetMap</a> ergeben sich ansehnliche Visualisierungen:</p>
<p><img decoding="async" loading="lazy" alt="Zu sehen ist eine Visualisierung von Straßenzügen und Gebäuden. Die Gebäude haben graue Wände und rote Dächer, die Straßen sind bunt, entsprechend der Aufteilung des Straßenraums. Blick auf die Straße Brauner Berg in Kiel." src="https://geodaten-guerilla.net/assets/images/qgis-lod2-frort-threejs-78154450f7440a634082553b8533b765.png" title="3D-Visualisierung Brauner Berg Kiel" width="1658" height="1475" class="img_ev3q">
<img decoding="async" loading="lazy" alt="Zu sehen ist eine Visualisierung von Straßenzügen und Gebäuden. Die Gebäude haben graue Wände und rote Dächer, die Straßen sind bunt, entsprechend der Aufteilung des Straßenraums. Blick auf die das Viertel am Exerzierplatz in Kiel." src="https://geodaten-guerilla.net/assets/images/qgis-lod2-exer-threejs-34c9fa6fd36796c86d31fb86ab0231d0.png" title="3D-Visualisierung Exerzierplatz Kiel" width="1658" height="1475" class="img_ev3q">)
<img decoding="async" loading="lazy" alt="Zu sehen ist eine Visualisierung von Straßenzügen und Gebäuden. Die Gebäude haben graue Wände und rote Dächer, die Straßen sind bunt, entsprechend der Aufteilung des Straßenraums. Blick auf das Viertel zwischen Westring, Kronshagener Weg und Hasseldieksdammer Weg in Kiel." src="https://geodaten-guerilla.net/assets/images/qgis-lod2-phil-threejs-53f594e7898fb859abb6b5ee25211e47.png" title="3D-Visualisierung Westring/Kronshagener Weg/Hasseldieksdammer Weg Kiel" width="1658" height="1471" class="img_ev3q"></p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="nächste-schritte">Nächste Schritte<a href="https://geodaten-guerilla.net/blog/qgis-3dcitydb-gebaeude#n%C3%A4chste-schritte" class="hash-link" aria-label="Direkter Link zur Nächste Schritte" title="Direkter Link zur Nächste Schritte">​</a></h2>
<p>Der logische nächste Schritt ist, das QGIS-Projekt mit weiteren Objekten zu füllen. Gebäude und Straßenraumaufteilungen sind schon vorhanden. Die Bäume in den Visualisierungen stammen aus OpenStreetMap. Hieraus lassen sich weitere Objekte entnehmen und den Visualisierungen hinzufügen.</p>
<p>Außerdem ist es denkbar, die Daten zu verändern und mit dem Ist-Zustand zu vergleichen. So ließe sich dann sehen, was für Auswirkungen es hätte, an einer Stelle Parkplatze zu entfernen und dafür Bäume zu pflanzen. Spannend wird es dann, das in einen Webviewer zu packen und den Menschen die Möglichkeit zu geben, veränderte städtische Umgebungen in 3D zu erkunden. Ich werde <a href="https://geodaten-guerilla.net/blog">hier</a> und vor allem auf <a href="https://climatejustice.social/@GeoDatenGuerilla" target="_blank" rel="noopener noreferrer">Mastodon</a> weiter dazu schreiben.</p>]]></content>
        <author>
            <name>Johanna I. Klitzschmüller</name>
            <email>altesholz@riseup.net</email>
            <uri>https://tech.lgbt/@fedora</uri>
        </author>
        <category label="Geodaten" term="Geodaten"/>
        <category label="3D" term="3D"/>
        <category label="GIS" term="GIS"/>
        <category label="QGIS" term="QGIS"/>
        <category label="Datenbank" term="Datenbank"/>
        <category label="PostGIS" term="PostGIS"/>
        <category label="PostgreSQL" term="PostgreSQL"/>
        <category label="3DCityDB" term="3DCityDB"/>
        <category label="QGIS2threejs" term="QGIS2threejs"/>
        <category label="threejs" term="threejs"/>
        <category label="open-source" term="open-source"/>
        <category label="freie Software" term="freie Software"/>
        <category label="Johanna" term="Johanna"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[FOSSGIS-Konferenz 2024 in Hamburg]]></title>
        <id>https://geodaten-guerilla.net/blog/fossgis-konferenz-2024</id>
        <link href="https://geodaten-guerilla.net/blog/fossgis-konferenz-2024"/>
        <updated>2024-03-22T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Ich war drei Tage lang auf der FOSSGIS-Konferenz 2024 in Hamburg. Ich verlinke hier die Aufnahme meines Vortrags und gebe Empfehlungen für andere Vorträge ab.]]></summary>
        <content type="html"><![CDATA[<p>Ich war vom 20. bis 22. März 2024 auf der FOSSGIS-Konferenz in Hamburg zugegen. Das waren drei Tage voller interessanter Vorträge und Gespräche. Ich habe mich an der Konferenz mit dem Vortrag <a href="https://pretalx.com/fossgis2024/talk/BFPLZH/" target="_blank" rel="noopener noreferrer">GeographyForFuture: Mit Geodaten Politik machen</a> beteiligt und dargestellt, wie wir Geodaten und Karten als Werkzeuge für den Kampf für eine bessere Welt nutzen können. Eine Aufnahme des Vortrags (inklusive gelobten Pullover) ist <a href="https://media.ccc.de/v/fossgis2024-38928-geographyforfuture-mit-geodaten-politik-machen" target="_blank" rel="noopener noreferrer">hier</a> zu finden und die Folien stehen <a href="https://geodaten-guerilla.net/downloads/Vortraege-Workshops/FOSSGIS-Konferenz-2024/2024-03-21-FOSSGIS-2024-Praesentation.pdf" target="_blank" rel="noopener noreferrer">hier</a> zum Download bereit.</p>
<p>Wer sich in die Thematik weiter einarbeiten möchte, dem empfehle ich meine vergangenen Blogposts:</p>
<ul>
<li><a href="https://geodaten-guerilla.net/blog/Geodaten-Karten-Werkzeug">Geodaten und Karten im Kampf für das gute Leben für alle</a></li>
<li><a href="https://geodaten-guerilla.net/blog/WebMontag-GeographyForFuture">GeographyForFuture: Mit Geodaten Politik machen</a></li>
<li><a href="https://geodaten-guerilla.net/blog/geographien-der-hoffnung">Mit GIS, Karten und Geodaten Geographien der Hoffnung schaffen</a></li>
</ul>
<p>Außerdem empfehle ich als Einstieg in die kritische Kartographie und Critical GIS folgende Literatur:</p>
<ul>
<li>Glasze, G. (2014): Sozialwissenschaftliche Kartographie-, GIS- und GeowebForschung. In: KN - Journal of Cartography and Geographic Information 64 (3), S. 123-129.</li>
<li>Pavlovskaya, M. (2018): Critical GIS as a tool for social transformation. In: The Canadian Geographer / Le Géographe canadien 62 (1), S. 40-54. (Download auf <a href="https://www.researchgate.net/publication/322664047_Critical_GIS_as_a_tool_for_social_transformation_GIS_for_social_transformation" target="_blank" rel="noopener noreferrer">ResearchGate</a>, danke an <a href="https://climatejustice.social/@oeLLph@23.social/112134819176095470" target="_blank" rel="noopener noreferrer">moeLLph</a> für den Hinweis)</li>
</ul>
<p>Neben meinem Vortrag hatte FOSSGIS-Konferenz noch viele weitere spannende Vorträge im Angebot. Eine kleine persönliche Auswahl:</p>
<ul>
<li><a href="https://media.ccc.de/v/fossgis2024-38554-wie-vollstndig-sind-die-daten-bei-openstreetmap-" target="_blank" rel="noopener noreferrer">Wie vollständig sind die Daten bei OpenStreetMap?</a> von Mathias Gröbe</li>
<li><a href="https://media.ccc.de/v/fossgis2024-39041-ki-gebudeerkennung-deep-learning-modelle-zur-aktualisierung-der-alkis-gebude" target="_blank" rel="noopener noreferrer">KI-Gebäudeerkennung – Deep-Learning-Modelle zur Aktualisierung der ALKIS-Gebäude</a> von Jonas Bostelmann, Birger Giesen und Valentina Schmidt</li>
<li><a href="https://media.ccc.de/v/fossgis2024-39050-evaluierung-von-hausumringen-alkis-osm-microsoft-und-unsere-ki-im-vergleich" target="_blank" rel="noopener noreferrer">Evaluierung von Hausumringen: ALKIS, OSM, Microsoft und unsere KI im Vergleich</a> von Lukas Sanner und Mike Engel</li>
<li><a href="https://media.ccc.de/v/fossgis2024-38772-mapbender-die-neue-version-4-stellt-sich-vor" target="_blank" rel="noopener noreferrer">Mapbender - die neue Version 4 stellt sich vor</a> von Astrid Emde</li>
<li><a href="https://media.ccc.de/v/fossgis2024-38883-starkregengefahrenhinweiskarten-fr-niedersachsen-schleswig-holstein-hb-und-hamburg" target="_blank" rel="noopener noreferrer">Starkregengefahrenhinweiskarten für Niedersachsen/Schleswig-Holstein/HB und Hamburg</a> von Barbara Werth und Uwe Ross</li>
<li><a href="https://media.ccc.de/v/fossgis2024-38537-basemap-de-aktuelles-und-ausblick" target="_blank" rel="noopener noreferrer">basemap.de Aktuelles und Ausblick</a> von Arnulf B. Christl</li>
</ul>]]></content>
        <author>
            <name>Johanna I. Klitzschmüller</name>
            <email>altesholz@riseup.net</email>
            <uri>https://tech.lgbt/@fedora</uri>
        </author>
        <category label="Geodaten" term="Geodaten"/>
        <category label="Karten" term="Karten"/>
        <category label="GIS" term="GIS"/>
        <category label="Kartographie" term="Kartographie"/>
        <category label="open-source" term="open-source"/>
        <category label="freie Software" term="freie Software"/>
        <category label="FOSSGIS" term="FOSSGIS"/>
        <category label="Politik" term="Politik"/>
        <category label="Autobahn" term="Autobahn"/>
        <category label="Johanna" term="Johanna"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Mit GIS, Karten und Geodaten Geographien der Hoffnung schaffen]]></title>
        <id>https://geodaten-guerilla.net/blog/geographien-der-hoffnung</id>
        <link href="https://geodaten-guerilla.net/blog/geographien-der-hoffnung"/>
        <updated>2024-02-11T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[GIS, Karten und Geodaten können wertvolle Werkzeuge sein, um soziale Transformation und Hoffnung zu schaffen.]]></summary>
        <content type="html"><![CDATA[<p>In den vergangenen Jahren beschäftigte ich mich mit zwei großen Themen: Gegen Zerstörungen und Katastrophen kämpfen und über Zerstörungen und Katastrophen lernen. Politisch aktiv geworden bin ich mit dem Großwerden der aktuellen Klimagerechtigkeitsbewegung 2018/2019. Seitdem ist der Kampf gegen die Klimakatastrophe, aber auch gegen soziale Ungerechtigkeit und Faschismus, insbesondere in den heutigen Tagen, ein ständiger Begleiter. Ob in Lützerath oder hier in Kiel.
<img decoding="async" loading="lazy" alt="Screenshots mehrerer Mastodon-Posts (von links nach rechts): 1. Bild: Das Gefühl, #Barrikaden zu bauen, um einen Ort, der aufgrund von offensichtlich falschen Entscheidungen zerstört werden soll, ist in einer #Demokratie vollkommen surreal. Aber in #Lützerath gerade Realität. Durch die Räumung werde der #Rechtsstaat verteidigt, heißt es von Politikerseite. Durch die Besetzung Lüzeraths wird das Pariser #Klimaabkommen verteidigt, steht dem auf einem Banner entgegen. (1/6). 2. Bild: Die Räumung findet aufgrund fadenscheiniger Gründe statt. Die #Kohle unter #Luetzerath wird nicht für die #Energiesicherheit benötigt. Ein Abbauen der #Kohle wird das #1komma5 Grad Ziel sprengen und gegen das deutsche #Klimaschutzgesetz verstoßen. Die #Klimakatastrophe wird sich weiter verschlimmern. Bereits jetzt ist sie für viele Menschen im globalen Süden die Hölle und wird ihre und unsere #Zukunft zerstören. (2/6). 3. Bild: Während mensch weiter #Barrikaden baut, schießt die Frage durch den Kopf, welchen Wert politische und wirtschaftliche Systeme haben, die ihre eigenen Gesetze und #Völkerrecht missachten, und die die Zerstörung unser aller Zukunft und Lebensgrundlagen nicht verhindert. (3/6). 4. Bild: So sitze ich hier, mit Blick auf den Tagebau #Garzweiler und stelle mir diese und weitere Fragen und kämpfe mit Trauer und Wut angesicht der anstehenden Räumung. Es ist so frustrierend, mit all dem Wissen über die #Klimakrise, das selbst angeeignet oder durch das #Geographie Studium angeeignet wurde, hier zu sitzen. Trotzdem versuche ich mir vorzustellen, dass eine bessere Welt möglich ist und werde weiter dafür kämpfen. (4/6). 5. Bild: Nur der Gedanke, am Montag wieder zur #Lohnarbeit zu müssen, reißt einen wieder raus. Aber die Gedanken werden auch im Büro und im Alltag bleiben. (5/6). 6. Bild: Die #Räumung wird sehr hässlich. Die #Polizei und #RWE werden all die Menschen, die eine bessere Zukunft wünschen, mit aller Macht und Brutalität hier rauszerren. Ich wünsche allen Menschen, die in #Lützerath und anderswo unser aller Zukunft verteidigen, viel Kraft. Wir sehen uns hinter den #Barrikaden oder auf der #Großdemo. #LütziBleibt #LuetziBleibt (6/6)." src="https://geodaten-guerilla.net/assets/images/luetzi-mastodon-posts-91cb0416435d7af4cf8d3d3c81580f32.png" title="Mastodon-Post vom Account GeoDatenGuerilla zur Räumung von Lützerath" width="1754" height="810" class="img_ev3q">
Mit dem ersten Tag des Geographiestudiums war das Lernen über die ökologischen und sozialen Katastrophen der Gegenwart Teil meines Lebens. Denn ein großer Teil der Geographie befasst sich mit den unzähligen ökologischen und sozialen Bedrohungen, denen wir gegenüberstehen (Lawson 2007, S. 335). Und auch wenn sich nicht jede Vorlesung damit befasst hat, so war es doch immer möglich, das neu Gelernte mit den ökologischen und sozialen Bedrohungen und Katastrophen der Gegenwart zu verknüpfen. Mit <strong>GeoDatenGuerilla</strong> führe ich den Aktivismus und Werkzeuge aus dem Geographiestudium zusammen und <a href="https://geowebdienste.geodaten-guerilla.net/mapbender/" target="_blank" rel="noopener noreferrer">kartiere drohende Zerstörungen</a> und schreibe darüber, <a href="https://geodaten-guerilla.net/blog">wie sich GIS, Geodaten und Karten als Werkzeuge für eine bessere Welt einsetzen lassen</a>.</p>
<p>Doch trotz all der Krisen gibt es Grund zur Hoffnung. So wie die Geographie und andere Wissenschaften die (ökologischen) Bedrohungen, Katastrophen und die mit ihr verbundenen Ängste erforschen, so erforschen sie auch, wie Hoffnung entsteht und welche Werkzeuge uns zur Verfügung stehen, um Hoffnung zu schaffen. Diese wissenschaftliche Perspektive formuliert Lawson (2007, S. 335) passend: <code>Zu unserem Überleben gehört es, die Auswirkungen der Angst zu verstehen und sie zu überwinden, indem wir hoffnungsvolle Alternativen theoretisieren und in die Tat umsetzen.</code> Und so finden sich wissenschaftlichen Arbeiten zu <em>hoffnungsvollen Alternativen</em> und ihren Praktiken unter dem Schlagwort <em>Geographie der Hoffnung</em>. Damit zeigt sich, dass die Geographie mehr ist, als die ökologischen und sozialen Fragestellungen, mit denen sie sich beschäftigt. <code>Die Geografie verfügt über alle Instrumente, um Raum für alternative, hoffnungsvolle Visionen des sozialen, ökologischen und politischen Lebens zu schaffen</code> (Lawson 2007, S. 336). Ich möchte im folgenden die <em>Geographie der Hoffnung</em> aber nicht als wissenschaftliches Untersuchungsgebiet nutzen, sondern als Praktik verstehen, Alternativen zu unserer ungerechten Welt und damit Hoffnung zu schaffen. Da ich mich mit <strong>GeoDatenGuerilla</strong> hauptsächlich mit <a href="https://geodaten-guerilla.net/blog/Geoportal-erstellen#desktop-gis">GIS (Geographische Informationssysteme)</a>, <a href="https://geodaten-guerilla.net/blog/Geodaten-Karten-Werkzeug#karten-sind-nicht-neutral">Karten</a> und <a href="https://geodaten-guerilla.net/blog/Geodaten-Karten-Werkzeug#geodaten-und-geographische-informationen">Geodaten</a> in politischen Kontexten beschäftige, stellt sich die Frage, wie sich GIS, Geodaten und Karten als Werkzeug nutzen lassen, Hoffnung zu schaffen. Um dem nachzugehen, möchte ich zunächst zeigen, wie sich durch Katastrophen Möglichkeitsfenster ergeben, Hoffnung zu schaffen. Danach zeige ich die lokalen und gemeinschaftlichen Eigenschaften der Geographien der Hoffnung und schlussendlich GIS als Werkzeug der Hoffnung.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="aus-katastrophen-hoffnung-schöpfen">Aus Katastrophen Hoffnung schöpfen<a href="https://geodaten-guerilla.net/blog/geographien-der-hoffnung#aus-katastrophen-hoffnung-sch%C3%B6pfen" class="hash-link" aria-label="Direkter Link zur Aus Katastrophen Hoffnung schöpfen" title="Direkter Link zur Aus Katastrophen Hoffnung schöpfen">​</a></h2>
<p>Die Geographie ist eine Wissenschaft, die sich viel mit Katastrophen und ökologischen und sozialen Bedrohungen auseinandersetzt (vgl. Lawson 2007). Mit Klima- und Biodiversitätskrise ereignen sich Katastrophen, die unser aller Lebensgrundlagen bedrohen. Doch trotz dieser Bedrohungen scheint es Hoffnung zu geben. Denn die Forschung über Katastrophen zeigt, dass Katastrophen immer auch Handlungsräume ermöglichen, in denen Alternativen geschaffen werden können.</p>
<p>Ausgangspunkt der Überlegung, wie Handlungsräume entstehen, ist, dass <code>die Kraft der Katastrophe in der Unterbrechung des Alltagslebens [liegt]</code> (Cretney 2017, S. 5). Die Normalität, der Alltag und das politische Handeln der Institutionen in der Zeit zuvor ist geprägt durch kapitalistische Praktiken, die Ungerechtigkeiten verursachen. Mit der Katastrophe kommt der Bruch dieser Normalität und es stellt sich unweigerlich die Frage, wie der Wiederaufbau organisiert, die Lasten verteilt und die Zeit nach der Katastrophe gestaltet werden soll (Cretney 2017, S. 1ff). Die Politik der Vor-Normalität wird bei der Bewältigung der Katastrophe zu einer ungleichen Verteilung der Lasten und Folgen führen und die Ungleichheiten der Vor-Normalität aufdecken (Cretney 2017, S. 7). Wir sehen das symbolhaft an der Klimakrise. Der globale Süden, gefangen in neokolonialen Abhängigkeiten zum globalen Norden, ist durch seinen geringen Beitrag am weltweiten CO2-Ausstoß kaum für die Klimakrise verantwortlich. Allerdings leidet der globale Süden am meisten unter der Klimakrise. Gleichzeitig wird der globale Norden seiner Verantwortung nicht gerecht und kommt nicht im ausreichenden Ausmaß für die Folgekosten auf und überzieht durch mangelnde Klimaschutzmaßnahmen seine eigenen Kohlenstoffbudgets. Aus diesen beiden Konstellationen, die Aushandlung des Wiederaufbaus und die aufgedeckte Ungleichheit, bieten sich nun Anlässe, sich mit verschiedenen Wirtschafts- und Gesellschaftsformen auseinanderzusetzen und für die Schaffung und Aufrechterhaltung von Alternativen zu kämpfen (Cretney 2017, S. 2ff).</p>
<p>Dieses Möglichkeitsfenster kann von lokal verankerten Akteur*innen genutzt werden, für Partizipation an den politischen Wiederaufbauprozessen kämpfen. Damit sorgen sie (im Besten Fall) für die Beteiligung vieler betroffener Menschen und für die Veränderung von Governance-Prozessen. Der gleichzeitige Aufbau von Gemeingütern stellt ein Infragestellen der derzeitigen kapitalistischen Praktiken dar. Damit können Katastrophen Praktiken und Werte fördern, die Alternativen ermöglichen (Cretney 2017, S. 6f). Hierbei kann die Nutzung von <a href="https://geodaten-guerilla.net/blog/Geodaten-Karten-Werkzeug#geodaten-und-geographische-informationen">Geodaten</a>- und <a href="https://geodaten-guerilla.net/blog/Geoportal-erstellen#desktop-gis">GIS</a>-Technologien ein wertvolles Werkzeug sein, um Gemeinschaftsprojekte und Partizipation zu fördern (Klinkenberg 2007, S. 355).</p>
<p>Da das beschriebene Handeln von lokalen Akteur*innen ausgeht, scheint es, dass Gemeinschaft und Lokalität wichtige Aspekte bei der Schaffung von Hoffnung sind.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="lokalität-der-hoffnung">Lokalität der Hoffnung<a href="https://geodaten-guerilla.net/blog/geographien-der-hoffnung#lokalit%C3%A4t-der-hoffnung" class="hash-link" aria-label="Direkter Link zur Lokalität der Hoffnung" title="Direkter Link zur Lokalität der Hoffnung">​</a></h2>
<p>Ob nach Katastrophen oder im alltäglichen politischen und gesellschaftlichen Handeln, es kristallisieren sich zwei wichtige Aspekte heraus, die für die Schaffung von Hoffnung essenziell sind: Die Lokalität und die Gemeinschaft. Lokalität meint hier die lokale räumliche Ebene, auf der Menschen leben und handeln. Des Weiteren sind mit der Lokalität die alltäglichen Handlungen der Menschen eng verbunden. Zum einen ist es der lokale Widerstand gegen die herrschenden Verhältnisse bzw. ungerechten Katastrophenbewältigungen, der Wege aus Katastrophen und zu gesellschaftlichen Alternativen aufzeigt (Cretney 2017, S. 6). Zum anderen kann ein Experimentieren in den alltäglichen Handlungsformen, mit dem bspw. alternative Ökonomien eingebunden werden, ein Katalysator für eben jenen gesellschaftlichen Wandel sein (Cretney 2017, S. 6). Das bedeutet, dass die Menschen Widerstand in ihren Nachbarschaften und Gemeinden organisieren müssen und alternative Praktiken in ihre alltäglichen Handlungsabläufe integrieren müssen. Hierbei ist es entscheidend, gemeinschaftlich zu handeln und so Gemeingüter aufzubauen und damit neue gesellschaftliche Handlungsformen zu implementieren. Basierend auf der Verbesserung des lokalen Umfelds und dem Einbringen verschiedener Perspektiven der Menschen, können damit gemeinschaftlich (in der Bewältigung der Katastrophe) Formen von Ungerechtigkeiten und die herrschenden Verhältnisse in Frage gestellt werden (Cretney 2017, S. 7; Klinkenberg 2007, S. 355).</p>
<p>Ein wichtiges Werkzeug für lokale Akteur*innen und Gemeinschaften kann die Nutzung von GIS und Geodaten sein. Und dies wird tatsächlich von Gemeinschaften auf der ganzen Welt genutzt, um ihre Arbeit zu unterstützen, zu verbessern und ihre Anliegen besser zu kommunizieren (Pavlovskaya 2018, S. 41ff). Oftmals nutzen indigene Bevölkerungsgruppen <a href="https://www.theguardian.com/science/blog/2018/mar/06/counter-mapping-cartography-that-lets-the-powerless-speak" target="_blank" rel="noopener noreferrer">Counter-Mapping/Gegenkartierungen</a>, um für ihre Rechte zu kämpfen, Initiativen nutzen GIS als Tool, um Öffentlichkeitsbeteiligungen zu stärken, in Städten versuchen Gemeinschaftsprojekte GIS, Stadtplanung und  Ökologie zu verbinden, um eine sozialökologische Stadtplanung voranzutreiben (Lawson 2007, S. 336; Pavlovskaya 2018, S. 45). Das Ergebnis solcher Projekte ist dabei oftmals, dass mit der Kartierung Hoffnung, bspw. Orte alternativer Ökonomien, auf die Karte gesetzt wird, womit sich die Hoffnung bzw. Alternativen auch möglich oder real anfühlen (Pavlovskaya 2018, S. 44f). <a href="https://geodaten-guerilla.net/blog/Geodaten-Karten-Werkzeug#karten-sind-nicht-neutral">Denn Karten reproduzieren soziale Wirklichkeiten</a> und machen damit die Hoffnung möglich. Außerdem ermöglichen die Demokratisierung von Geodaten und der Technologien hinter GIS die Nutzung dieser für den Kampf lokaler Akteur*innen und Gemeinschaften für ihre Kämpfe und schaffen so Empowerment und Hoffnung (Klinkenberg 2007, S. 357f).</p>
<p>Die Praktiken, die auf der lokalen Ebene entstehen und erprobt werden, können Hoffnung schaffen. Aber erst durch Vernetzungen zu Akteur*innen an anderen Orten und Entscheidungsebenen haben sie Einfluss über die lokale Ebene hinaus und können die Gesellschaft verändern (Cretney 2017, S. 6). Der Erfolg der Veränderung beruht dabei darauf, dass sich die gesellschaftlichen Werte und (Produktions)praktiken gesamtgesellschaftlich ändern (Lawson 2007, S. 336). Das Internet samt Social-Media bietet den Akteur*innen dabei unzählige Möglichkeiten: Die Verbreitung ihrer GIS-Projekte und (open-source) Software, der Austausch von Erkenntnissen, Taktiken und Praktiken zwischen verschiedenen Akteur*innen, wodurch auch andere Gruppen profitieren und mitarbeiten können, und Vernetzung zwischen den Akteur*innen auf den verschiedenen Entscheidungsebenen (Klinkenberg 2007, S. 352; Pavlovskaya 2018, S. 43; Petersen und Barnes 2019, S. 7).</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="mit-gis-und-geodaten-hoffnung-schaffen">Mit GIS und Geodaten Hoffnung schaffen<a href="https://geodaten-guerilla.net/blog/geographien-der-hoffnung#mit-gis-und-geodaten-hoffnung-schaffen" class="hash-link" aria-label="Direkter Link zur Mit GIS und Geodaten Hoffnung schaffen" title="Direkter Link zur Mit GIS und Geodaten Hoffnung schaffen">​</a></h2>
<p>Wie bereits gezeigt wurde, werden GIS und Geodaten als Werkzeug in sozialen Kämpfen genutzt. Die Macht, die dieses Werkzeug dabei entfalten kann, basiert auf der <a href="https://geodaten-guerilla.net/blog/Geodaten-Karten-Werkzeug#geodaten-und-geographische-informationen">Schlüsselstellung, die Geodaten und geographische Informationen in den letzten Jahrzehnten in den Informations- und Wissensgesellschaften errungen haben</a>. So können mit GIS räumliche Fragestellungen zu Umwelt- und Städteplanung, Gesundheitsrisiken, Notfallmanagement etc. untersucht werden und ermöglichen eine bessere Interpretation von Daten und einen räumlichen Erkenntnisgewinn (Klinkenberg 2007, S. 350ff). Lokale Gemeinschaften und Akteur*innen, die gegen soziale Ungerechtigkeiten kämpfen, können die Zusammenhänge zwischen ihren Wohnorten und den Gesundheitsrisiken durch nahe Autobahnen herausarbeiten oder sie können zeigen, wie bestimmte Räume (Geschlechter-)Diskriminierung fördern (Klinkenberg 2007, S. 354ff). Sie können alternative städteplanerische Konzepte erarbeiten, die ihre Nachbarschaften sicherer machen, für eine angemessenere Mischung von Flächennutzungen sorgen oder umweltfreundlichere Verkehrsmittel fördern (Klinkenberg 2007, S. 354ff). Außerdem wird es für eben jene Akteur*innen und Gemeinschaften möglich, die Analysen und Argumente anderer zu entkräften und Ungereimtheiten, Fehler und Auslassungen in deren Analysen aufzudecken (Klinkenberg 2007, S. 352). Damit ermöglicht GIS eine Ermächtigung der Öffentlichkeit durch den Transfer von Wissen aus den Händen einiger weniger in die Hände von vielen, einer Verschiebung des Machtgleichgewichts und wird so zu einem Werkzeug für soziale Transformation (Klinkenberg 2007, S. 350ff; Pavlovskaya 2018, S. 41).</p>
<p>All diese Möglichkeiten hängen mit einem wichtigen Prozess zusammen, der die Entwicklung von GIS und den dahinterliegenden Technologien in den letzten zwei Jahrzehnten geprägt: Die Demokratisierung von Geodaten und der entsprechenden Software (Klinkenberg 2007, S. 357f; Pavlovskaya 2018, S. 42). Diese Demokratisierung wurde vor allem durch Open-Source, Open-Data und der Verbreitung der entsprechenden Tools und Daten über das Internet vorangetrieben, wodurch sehr viele Menschen in die Lage versetzt wurden, Daten zu sammeln, zu verbreiten und Karten zu erstellen (Klinkenberg 2007, S. 352; Pavlovskaya 2018, S. 42). In der Folge haben sich Communities um Kartierungsprojekte gebildet und lokale Gemeinschaften nutzen diese für ihre Kämpfe (Klinkenberg 2007, S. 357f; Pavlovskaya 2018, S. 42).</p>
<p>Das bekannteste Beispiel für die Demokratisierung von Geodaten ist wohl <a href="https://www.openstreetmap.org/" target="_blank" rel="noopener noreferrer">OpenStreetMap</a>. Hier sammeln tausende Freiwillige Geodaten und tragen diese in einer großen Datenbank zusammen, die dank einer freien Lizenz für jede*n nutzbar ist. So besteht unabhängig von staatlichen und privaten Anbietern jederzeit ein Zugang zu einem Geodatensatz der ganzen Welt. Die OpenStreetMap-Datenbank ist aber bei weitem nicht vollständig. Insbesondere im Katastrophenfall kann dies für vulnerable Gruppen gefährlich sein, da Hilfsorganisationen und -Maßnahmen auf Geodaten angewiesen sind. <a href="https://www.missingmaps.org/" target="_blank" rel="noopener noreferrer">MissingMaps</a> versucht dieses Problem zu mindern, indem Freiwillige Satellitenbilder in die OpenStreetMap-Datenbank abzeichnen und Menschen aus den jeweiligen lokalen Gemeinschaften Details nachtragen. Diese Daten können dann von Hilfsorganisation für Risikomanagement und, im Katastrophenfall, für Hilfsmaßnahmen genutzt werden. Damit verbindet sich eine globale offene Geodatenbank mit der Katastrophenbewältigung lokaler Gemeinschaften. Des Weiteren lassen sich mit Geodaten Citizen-Science Projekte aufbauen, die bspw. Radfahren sicherer machen wollen. Mit dem <a href="https://www.openbikesensor.org/" target="_blank" rel="noopener noreferrer">OpenBikeSensor</a> lassen sich die Überholabstände von Autos messen und auf einer <a href="https://obs.adfc-luebeck.de/map" target="_blank" rel="noopener noreferrer">Karte</a> darstellen, wo es für Radfahrende am gefährlichsten ist. Mit dem Trend zu 3D-Geodaten und Daten der Einteilung des Straßenraums lässt sich darstellen, wie viel Platz der jeweilige Verkehrsträger auf der Straße hat.
<img decoding="async" loading="lazy" alt="3D-Ansicht einer Straße in Kiel-Friedrichsort, wo Gebäude als graue Blöcke und die die Aufteilung des Straßenraums zu sehen ist. Hier kennzeichnen verschiedene Farben die Nutzung, bspw. Radweg, Parkplatz, Gehweg etc." src="https://geodaten-guerilla.net/assets/images/FrOrt-dfaad8b3e416cccb7cf211e1991f0ed1.png" title="3D-Ansicht einer Straße in Kiel-Friedrichsort, wo Gebäude als graue Blöcke und die die Aufteilung des Straßenraums zu sehen ist. Hier kennzeichnen verschiedene Farben die Nutzung, bspw. Radweg, Parkplatz, Gehweg etc." width="1566" height="353" class="img_ev3q">
Solche Projekte ermöglichen Partizipation in politischen Prozessen, decken Missstände auf und bieten durch die Daten Argumentationsgrundlagen für Verbesserungen. GIS und Geodaten schaffen also zusätzliche Möglichkeitsräume, eröffnen so einen Raum für politischen und sozialen Wandel und schaffen auf diese Weise Hoffnung (Pavlovskaya 2018, S. 41).</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="schaffen-wir-geographien-der-hoffnung">Schaffen wir Geographien der Hoffnung<a href="https://geodaten-guerilla.net/blog/geographien-der-hoffnung#schaffen-wir-geographien-der-hoffnung" class="hash-link" aria-label="Direkter Link zur Schaffen wir Geographien der Hoffnung" title="Direkter Link zur Schaffen wir Geographien der Hoffnung">​</a></h2>
<p>Wir leben nicht in einfachen Zeiten. Denn obwohl das Ende der Geschichte einst ausgerufen wurde, erleben wir und werden in naher Zukunft große Umwälzungen erleben. Die Klima- und Biodiversitätskrise, die unser aller Lebensgrundlagen bedroht, sorgt bereits für viele Katastrophen, die riesigen soziale Ungleichheiten zwischen dem globalen Norden und Süden und innerhalb der Gesellschaften droht diese zu zerreißen und angesichts der multiplen Krisen sind Autoritarismus und Faschismus auf dem Vormarsch. Im Angesicht der Katastrophen besteht dennoch Hoffnung. Wir haben gesehen, dass Katastrophen Möglichkeitsräume öffnen können, da sie die Ungleichheiten wie unter einem Brennglas aufzeigen. Dies können wir nutzen, um Alternativen aufzubauen. Damit schaffen wir Hoffnung. Insbesondere wir Geograph*innen besitzen die analytischen Fähigkeiten und Werkzeuge, um hoffnungsvolle Alternativen aufzuzeigen und aufzubauen. <code>Geographen können und müssen an der Spitze von Analysen stehen, die die Richtung für eine sicherere Welt vorgeben. Wir sollten uns noch stärker in eine Reihe drängender gesellschaftlicher Debatten über zunehmende Ungleichheit und Armut, globale Gesundheitspandemien, ökologische Nachhaltigkeit, Hungersnöte und Konflikte einbringen und dort sichtbar sein. Framing-Analysen der Prozesse, die Angst erzeugen, sollten uns nicht zu Lähmung und Rückzug verleiten. Vielmehr sollte sie uns mobilisieren, ein hoffnungsvolles Verständnis unserer komplexen Welt zu entwickeln. Hoffnungsvolle Analysen können uns dazu bewegen, über die Vermeidung oder Bewältigung verschiedener Gefahren hinauszugehen und eine nachhaltigere, gerechtere und demokratischere Zukunft zu schaffen</code> (Lawson 2007, S. 337).</p>
<p>Neben den Analysen stehen uns mit GIS und Karten Werkzeuge zur Verfügung, die sich konkret in die Kämpfe für eine bessere Welt einbringen lassen. Wir können mit Counter-Mapping die Geschichten marginalisierter Menschen erzählen, wir können Tools erstellen, die Partizipation an politischen (Planungs-)Prozessen ermöglicht, wir können Karten erstellen, die die Zerstörungen in unserer Welt darstellen. Und wir können die Orte auf die Karte setzen, die für alternative Wirtschafts- und Gesellschaftsformen stehen und damit Hoffnung sichtbar machen. Natürlich sind GIS und Karten nicht der Weiheit letzter Schluss in diesen Kämpfen, aber sie sind ein Baustein, mit dem sich nach und nach <em>Geographien der Hoffnung</em> und Veränderungen schaffen lassen.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="literatur">Literatur<a href="https://geodaten-guerilla.net/blog/geographien-der-hoffnung#literatur" class="hash-link" aria-label="Direkter Link zur Literatur" title="Direkter Link zur Literatur">​</a></h2>
<p>Cretney, R. M. (2017): Towards a critical geography of disaster recovery politics: Perspectives on crisis and hope. In: Geography Compass 11 (1).<br>
<!-- -->Klinkenberg, B. (2007): Geospatial Technologies and the Geographies of Hope and Fear. In: Annals of the Association of American Geographers 97 (2), S. 350-360.<br>
<!-- -->Lawson, V. (2007): Introduction: Geographies of Fear and Hope. In: Annals of the Association of American Geographers 97 (2), S. 335-337.<br>
<!-- -->Pavlovskaya, M. (2018): Critical GIS as a tool for social transformation. In: The Canadian Geographer / Le Géographe canadien 62 (1), S. 40-54.<br>
<!-- -->Petersen, B. und J. R. Barnes (2019): From Hopelessness to Transformation in Geography Classrooms. Journal of Geography 119 (1), S. 3-11.</p>]]></content>
        <author>
            <name>Johanna I. Klitzschmüller</name>
            <email>altesholz@riseup.net</email>
            <uri>https://tech.lgbt/@fedora</uri>
        </author>
        <category label="Geodaten" term="Geodaten"/>
        <category label="Karten" term="Karten"/>
        <category label="Hoffnung" term="Hoffnung"/>
        <category label="Geographie der Hoffnung" term="Geographie der Hoffnung"/>
        <category label="Geographies of Hope" term="Geographies of Hope"/>
        <category label="GIS" term="GIS"/>
        <category label="Kartographie" term="Kartographie"/>
        <category label="open-source" term="open-source"/>
        <category label="freie Software" term="freie Software"/>
        <category label="Johanna" term="Johanna"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Ein eigenes (kleines) Geoportal erstellen]]></title>
        <id>https://geodaten-guerilla.net/blog/Geoportal-erstellen</id>
        <link href="https://geodaten-guerilla.net/blog/Geoportal-erstellen"/>
        <updated>2023-10-06T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Mit Hilfe von freier und open-source Software lassen sich Geoportale erstellen. Ein kleines Geoportal besteht aus Online-Karten, OWS-Services, die die Geodaten zur Verfügung stellen und einer Dokumentation.]]></summary>
        <content type="html"><![CDATA[<p>Geoportale gibt es mittlerweile wie Sand am Meer. Sehr viele Behörden und Kommunen stellen mit ihren Geoportalen Geodaten und ihr Kartenmaterial online zur Verfügung. Mit <strong>GeoDatenGuerilla</strong> und den hier zu findenden <a href="https://geowebdienste.geodaten-guerilla.net/mapbender/" target="_blank" rel="noopener noreferrer">Online-Karten</a> und Geodaten betreibe ich quasi selber ein eigenes Geoportal. Im Folgenden möchte ich anhand der hier eingesetzten Software zeigen, wie sich jede*r ein eigenes kleines Geoportal erstellen kann. Als Geoportal verstehe ich an dieser Stelle eine im Web-Browser aufrufbare Anwendung bzw. Webseite, die verschiedene Online-Karten zur Verfügung stellt, sowie die dahinter liegende Infrastruktur, um Geodaten bereitzustellen. Außerdem ist in meinen Augen eine Dokumentation essenziell, um Beschreibungen, Lizenzinformationen etc. der Datensätze den Nutzenden zu Verfügung zu stellen.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="desktop-gis">Desktop-GIS<a href="https://geodaten-guerilla.net/blog/Geoportal-erstellen#desktop-gis" class="hash-link" aria-label="Direkter Link zur Desktop-GIS" title="Direkter Link zur Desktop-GIS">​</a></h2>
<p>Die Grundlage aller meiner Karten und Geodatenanalysen, ob online oder offline, ist ein Geographisches Informationssystem (GIS) auf dem Computer. Dieses erlaubt die Erstellung, Verwaltung und Analyse von <a href="https://geodaten-guerilla.net/blog/Geodaten-Karten-Werkzeug#geodaten-und-geographische-informationen">Geodaten</a>. Als Verfechter von freier und open-source Software nutze ich <a href="https://qgis.org/de/site/" target="_blank" rel="noopener noreferrer">QGIS</a>.</p>
<p>In QGIS importiere, bearbeite und erstelle ich die Geodaten, die ich später zur Verfügung stellen möchte.
<img decoding="async" loading="lazy" alt="qgis-mitmachen-screenshot.png" src="https://geodaten-guerilla.net/assets/images/qgis-mitmachen-screenshot-e944bee7e4c5120a91dae57279597cfe.png" width="1946" height="1586" class="img_ev3q">
Die Daten der <a href="https://geowebdienste.geodaten-guerilla.net/mapbender/application/autobahn-20" target="_blank" rel="noopener noreferrer">Online-Karte zur A20</a> sehen in meinem QGIS-Projekt so aus, wie in dem Screenshot zu sehen. In dem Fall habe ich Übersichtspläne und Übersichtslagepläne in QGIS georeferenziert, um dann die Autobahntrasse von diesen abzuzeichnen. Außerdem habe ich die Flächen von Mooren und Schutzgebieten eingefügt. Die Trasse und die Schutzgebiete sind entsprechend auch in der Online-Karte zu finden.</p>
<p>Um die Nutzung von QGIS zu lernen, ist der erste Anlaufpunkt die umfangreiche <a href="https://qgis.org/de/docs/index.html" target="_blank" rel="noopener noreferrer">Dokumentation</a>. Außerdem bieten die Weiten des Internets viele Tutorials.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="geodaten-bereitstellen">Geodaten bereitstellen<a href="https://geodaten-guerilla.net/blog/Geoportal-erstellen#geodaten-bereitstellen" class="hash-link" aria-label="Direkter Link zur Geodaten bereitstellen" title="Direkter Link zur Geodaten bereitstellen">​</a></h2>
<p>Hat mensch die Geodaten in den Zustand gebracht, in dem sie veröffentlicht werden sollen, bieten sich zwei verschiedene Schritte an. Die Geodaten lassen sich entweder per <a href="https://de.wikipedia.org/wiki/Geodienst" target="_blank" rel="noopener noreferrer">OWS-Service</a>, also WMS/WMTS, WFS oder WCS, zur Verfügung stellen oder mensch stellt die Dateien direkt zum Download zur Verfügung. Beide Schritte schließen sich aber nicht aus. In meinem Fall stelle ich die Geodaten per WMS der <a href="https://geowebdienste.geodaten-guerilla.net/mapbender/" target="_blank" rel="noopener noreferrer">Kartenanwendung</a> und die GIS-lesbaren Dateien als <a href="https://geodaten-guerilla.net/downloads/" target="_blank" rel="noopener noreferrer">Download</a> zur Verfügung.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="ows-services">OWS-Services<a href="https://geodaten-guerilla.net/blog/Geoportal-erstellen#ows-services" class="hash-link" aria-label="Direkter Link zur OWS-Services" title="Direkter Link zur OWS-Services">​</a></h3>
<p>Als <a href="https://de.wikipedia.org/wiki/Geodienst" target="_blank" rel="noopener noreferrer">OpenGIS Web Services</a> (OWS) werden verschiedene Webservices bezeichnet, die Geodaten zur Verfügung stellen können. Die wohl wichtigsten sind der <a href="https://de.wikipedia.org/wiki/Web_Map_Service" target="_blank" rel="noopener noreferrer">Web Map Service</a> (WMS), welcher Karten in Form von Rasterdaten ausgibt, und der <a href="https://de.wikipedia.org/wiki/Web_Feature_Service" target="_blank" rel="noopener noreferrer">Web Feature Service</a> (WFS), der Vektordaten ausgibt. Um die entsprechenden Services anzubieten, gibt es verschiedene Software, die mensch auf einem Server installieren kann. <a href="https://mapserver.org/" target="_blank" rel="noopener noreferrer">Mapserver</a>, <a href="https://geoserver.org/" target="_blank" rel="noopener noreferrer">Geoserver</a> und <a href="https://docs.qgis.org/3.28/en/docs/server_manual/index.html" target="_blank" rel="noopener noreferrer">QGIS Server</a> sind freie und open-source Software, mit denen sich solche Services erstellen und betreiben lassen.</p>
<p>Wie bereits beschrieben, nutze ich WMS, um der <a href="https://geowebdienste.geodaten-guerilla.net/mapbender/" target="_blank" rel="noopener noreferrer">Kartenanwendung</a> die Geodaten bereitzustellen. Die dafür genutzte Software ist <a href="https://docs.qgis.org/3.28/en/docs/server_manual/index.html" target="_blank" rel="noopener noreferrer">QGIS Server</a>. QGIS Server hat den großen Vorteil, dass die Karten, die per WMS ausgegeben werden, genauso so aussehen, wie mensch es in seinem QGIS-Projekt einstellt. Dies lässt sich ganz gut im Vergleich mit dem Screenshot oben und der <a href="https://geowebdienste.geodaten-guerilla.net/mapbender/application/autobahn-20" target="_blank" rel="noopener noreferrer">Kartenanwendung der A20</a> erkennen. So sehen die Trassen und die Markierungen der Bauabschnitte gleich aus. Außerdem lassen sich die Webservices direkt im QGIS-Projekt einrichten. So lassen sich in den Layer-Eigenschaften die Infos für "GetCapabilities"-Abfragen eintragen.
<img decoding="async" loading="lazy" alt="qgis-server-einstellungen-layer-properties.png" src="https://geodaten-guerilla.net/assets/images/qgis-server-einstellungen-layer-properties-bb0cddea984cf2cf0109b42feb2bc4ce.png" width="1604" height="1451" class="img_ev3q">
Die Projekt-Eigenschaften erlauben weiteres Feintuning, bspw. dass Layer, die im QGIS-Projekt enthalten sind, nicht Teil des Service sein sollen. Dies mache ich u.a. mit den Plankarten der A20. Aus diesem Grund sind diese oben zwar im Screenshot von QGIS zu sehen, aber nicht in der Kartenanwendung.
<img decoding="async" loading="lazy" alt="qgis-server-einstellungen-project-properties.png" src="https://geodaten-guerilla.net/assets/images/qgis-server-einstellungen-project-properties-357ad7e202c574f801454bbbd1b752bb.png" width="1649" height="1434" class="img_ev3q">
Wenn in dem QGIS-Projekt der QGIS Server konfiguriert wurde, braucht mensch die Projektdatei mitsamt der Layer-Dateien nur noch auf den Server kopieren und kann die OWS-Services nutzen und in Anwendungen einbinden.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="dateien">Dateien<a href="https://geodaten-guerilla.net/blog/Geoportal-erstellen#dateien" class="hash-link" aria-label="Direkter Link zur Dateien" title="Direkter Link zur Dateien">​</a></h3>
<p>Der klassische Weg, Geodaten zur Verfügung zu stellen, ist, diese zum <a href="https://geodaten-guerilla.net/downloads/" target="_blank" rel="noopener noreferrer">Download</a> anzubieten. Wenn mensch möchte, dass die Daten bei anderen im GIS genauso aussehen, wie im eigenen, lässt sich zusätzlich der Layer-Style als Datei mit zur Verfügung stellen. Geopackages erlauben es sogar, den Style in der Datei zu speichern. Aber auch für Online-Karten kann es sich anbieten, die Geodaten nicht per OWS-Service, sondern als Datei einzubinden. So bietet <a href="https://geodaten-guerilla.net/blog/Online-Karten-uMap" target="_blank" rel="noopener noreferrer">uMap</a> die Möglichkeit an, Geodaten in Form von GeoJSON- oder GPX-Dateien einzubinden.</p>
<p>Die hier genutzte Kartenanwendung unterstützt dies nicht. Die Geodaten werden mittels WMS eingebunden. Aber die Geodaten stehen als <a href="https://geodaten-guerilla.net/downloads/" target="_blank" rel="noopener noreferrer">Download</a> zur Verfügung und sind zusätzlich in der <a href="https://geodaten-guerilla.net/docs/intro">Dokumentation</a> verlinkt.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="kartenanwendung">Kartenanwendung<a href="https://geodaten-guerilla.net/blog/Geoportal-erstellen#kartenanwendung" class="hash-link" aria-label="Direkter Link zur Kartenanwendung" title="Direkter Link zur Kartenanwendung">​</a></h2>
<p>Das Herzstück eines Geoportals sind die Karten. Um interaktive Online-Karten anzubieten, gibt es auch hierfür verschiedene freie und open-source Software. Mit <a href="https://mapbender.org/" target="_blank" rel="noopener noreferrer">Mapbender</a> und <a href="https://geonode.org/" target="_blank" rel="noopener noreferrer">Geonode</a> stehen Softwarelösungen bereit, die als "Content-Management-Systeme für Karten" das Erstellen von Online-Karten sehr einfach machen und kaum bis gar keine Programmierkenntnisse erfordern. Dem gegenüber stehen Softwarelösungen wie <a href="https://openlayers.org/" target="_blank" rel="noopener noreferrer">OpenLayers</a>, <a href="https://maplibre.org/" target="_blank" rel="noopener noreferrer">MapLibre</a> oder <a href="https://leafletjs.com/" target="_blank" rel="noopener noreferrer">Leaflet</a>, die Programmierkenntnisse erfordern, sich dafür aber auch komplett den eigenen Bedürfnissen anpassen lassen. Und wer seine Online-Karten nicht selber hosten möchte, kann diese mit Hilfe von <a href="https://umap.openstreetmap.de/de/" target="_blank" rel="noopener noreferrer">uMap</a> erstellen und teilen.</p>
<p>Als <a href="https://geowebdienste.geodaten-guerilla.net/mapbender/" target="_blank" rel="noopener noreferrer">Kartenanwendung</a> kommt hier Mapbender zum Einsatz. Mapbender macht einem das Erstelllen von Online-Karten sehr einfach, da sich, wie in einem Content-Management-System, die Inhalte zusammenklicken lassen.
<img decoding="async" loading="lazy" alt="mapbender-cms-einstellungen-beispiel.png" src="https://geodaten-guerilla.net/assets/images/mapbender-cms-einstellungen-beispiel-33c70fa7ab10f64d1e300f5a971e23dd.png" width="1185" height="1323" class="img_ev3q">
Die Geodaten werden mittels WMS, der von QGIS Server bereitgestellt wird, in Mapbender eingebunden.</p>
<p>Ein weiterer Pluspunkt von Mapbender ist die einfache Installation. Diese ist in der <a href="https://doc.mapbender.org/" target="_blank" rel="noopener noreferrer">Dokumentation</a> beschrieben. Ich rate aber dazu, vor dem Ausprobieren noch eine PostgreSQL- oder MySQL-Datenbank für Mapbender einzurichten. Das Vorgehen dazu ist auch in der Dokumentation beschrieben.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="dokumentation">Dokumentation<a href="https://geodaten-guerilla.net/blog/Geoportal-erstellen#dokumentation" class="hash-link" aria-label="Direkter Link zur Dokumentation" title="Direkter Link zur Dokumentation">​</a></h2>
<p>Als letzten wichtigen Baustein sehe ich für ein kleines Geoportal eine Dokumentation. Diese ist dazu gedacht, jeden Datensatz zu beschreiben, seine evtl. Quellen und die Lizenz, unter dem der Datensatz steht, anzugeben. Die <a href="https://geodaten-guerilla.net/docs/intro">Dokumentation</a> hier dokumentiert die <a href="https://geowebdienste.geodaten-guerilla.net/mapbender/" target="_blank" rel="noopener noreferrer">Kartenanwendungen</a>. Unter <a href="https://geodaten-guerilla.net/downloads/" target="_blank" rel="noopener noreferrer">Downloads</a> finden sich aber nicht nur die Geodaten der Kartenanwendungen, sondern auch Karten als PDF. Diese sind nicht dokumentiert, was aber auf langfristige Sicht sinnvoll ist.</p>]]></content>
        <author>
            <name>Johanna I. Klitzschmüller</name>
            <email>altesholz@riseup.net</email>
            <uri>https://tech.lgbt/@fedora</uri>
        </author>
        <category label="freie Software" term="freie Software"/>
        <category label="open-source" term="open-source"/>
        <category label="QGIS" term="QGIS"/>
        <category label="Mapbender" term="Mapbender"/>
        <category label="GIS" term="GIS"/>
        <category label="WebGIS" term="WebGIS"/>
        <category label="Software" term="Software"/>
        <category label="OWS" term="OWS"/>
        <category label="Geoportal" term="Geoportal"/>
        <category label="Johanna" term="Johanna"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Klassifikation von Landbedeckungen: Anpassung der Klassen]]></title>
        <id>https://geodaten-guerilla.net/blog/Fernerkundung-Klassifikation-Anpassung</id>
        <link href="https://geodaten-guerilla.net/blog/Fernerkundung-Klassifikation-Anpassung"/>
        <updated>2023-08-20T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Die Klassifikation von Landbedeckungen ist ein Praxisbeispiel für die Anwendung der Fernerkundung. Die Anpassung von Klassen und Trainingsgebieten hat große Auswirkungen auf das Ergebnis und sollte entsprechend der Frage- und Aufgabenstellung durchgeführt werden.]]></summary>
        <content type="html"><![CDATA[<p>Im <a href="https://geodaten-guerilla.net/blog/Fernerkundung-Informationsgewinnung-ferne">letzten Blogpost</a> haben wir uns mit der sogenannten <a href="https://geodaten-guerilla.net/blog/Fernerkundung-Informationsgewinnung-ferne#satelliten-strahlung-und-sensoren">Fernerkundung</a> beschäftigt, welche uns die Untersuchung der Erdoberfläche mit Hilfe von elektromagnetischer Strahlung ermöglicht. Mit der Klassifikation von Landbedeckungen in Satellitendaten mittels <a href="https://geodaten-guerilla.net/blog/Fernerkundung-Informationsgewinnung-ferne#klassifikation-mittels-maschinellen-lernens">maschinellem Lernen</a> haben wir ein Anwendungsbeispiel kennengelernt. Die dabei durchgeführte Klassifikation brachte bereits beeindruckende Ergebnisse zustande. Siedlungsstrukturen, große Verkehrswege und verschiedene Grünflächen wurden erkannt. Doch bei der Prüfung der Klassifikation sind verschiedene Fehlklassifikationen aufgefallen. Um solche Fehlklassifikationen zu verringern, habe ich Änderungen der Klasseneinteilungen vorgeschlagenen. In der darauffolgenden Zeit habe ich die Klassifikation zweimal mit jeweils anderen Klasseneinteilungen neu durchgeführt. Dabei hat sich gezeigt, dass Einteilung der <a href="https://geodaten-guerilla.net/blog/Fernerkundung-Informationsgewinnung-ferne#festlegen-von-klassen-und-trainingsgebiete">Klassen und der Trainingsgebiete</a> eine entscheidende Rolle beim Ergebnis der Klassifikation spielen.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="erster-neuer-durchgang">Erster neuer Durchgang<a href="https://geodaten-guerilla.net/blog/Fernerkundung-Klassifikation-Anpassung#erster-neuer-durchgang" class="hash-link" aria-label="Direkter Link zur Erster neuer Durchgang" title="Direkter Link zur Erster neuer Durchgang">​</a></h2>
<p>Im ersten neuen Klassifikationsversuch habe ich die Klasseneinteilung so gestaltet und die Trainingsgebiete entsprechend angepasst, wie ich sie im <a href="https://geodaten-guerilla.net/blog/Fernerkundung-Informationsgewinnung-ferne#n%C3%A4chste-schritte">letzten Blogpost</a> angeregt habe:</p>
<ul>
<li>Wasser für Wasserflächen</li>
<li>Straßen für Verkehrsflächen, Straßen, Parkplätze und andere große Plätze</li>
<li>Bahn für Bahnanlagen bzw. Bahnschienen</li>
<li>Wald für Wälder und Baumgruppen</li>
<li>Gebäude für alle Arten von Gebäuden</li>
<li>Landwirtschaft für landwirtschaftlich genutzte Flächen</li>
<li>Grünflächen für Grünflächen, die nicht landwirtschaftlich genutzt werden oder Wälder sind</li>
</ul>
<p>Mit dieser Klasseneinteilung sind in diesem Durchgang erstaunliche Fehlklassifikationen aufgetreten, die über "Kleinigkeiten" hinausgehen. So werden ganze Strandabschnitte als Gebäude oder Straßen erkannt, wobei eine Fehlklassifikation mangels der Klasse Strand zu erwarten ist. Außerdem werden sehr viele Straßen, insbesondere im innerörtlichen Bereich mit enger Bebauung, als Bahn erkannt. Auch einige landwirtschaftliche Flächen und Flussläufe ereilte das Schicksal, als Bahn oder als Gebäude klassifiziert zu werden. Die Tatsache, dass Hafenanlagen als Gebäude klassifiziert wurden, ist, vor dem Hintergrund der genannten haarsträubenden Fehler, zu verschmerzen. Positiv anzumerken ist, dass die Aufnahme von sedimentreichen Küstengewässern in die Trainingsgebiete der Wasserflächen dafür sorgte, dass nur noch Gewässer mit sehr hohem Sedimentanteil als etwas anderes als Wasser klassifiziert wurden.</p>
<p>Auf Basis dieses Ergebnisses bietet sich an, für weitere Klassifikationen eine eigene Klasse für Strände zu erstellen. Ihre Anzahl und Größe in Schleswig-Holstein legen das nahe, was großflächige Fehlklassifikationen vermeiden würde. Bei den fehlklassifizierten Küstengewässern bietet sich eine Erweiterung der Trainingsgebiete an, um hier eine noch höhere Präzision zu erreichen. Bei den fehlklassifizierten landwirtschaftlichen Flächen könnte eine Ausdehnung der Trainingsgebiete auf einige der betroffenen Flächen in Betracht kommen.</p>
<p><img decoding="async" loading="lazy" alt="kiel-vorhersage-vergleich-strand.png" src="https://geodaten-guerilla.net/assets/images/kiel-vorhersage-vergleich-strand-483d592ac9011f9c4c1ff3721c2da192.png" width="7015" height="4960" class="img_ev3q">
<img decoding="async" loading="lazy" alt="kiel-vorhersage-vergleich-strasse.png" src="https://geodaten-guerilla.net/assets/images/kiel-vorhersage-vergleich-strasse-2cd9e1f7767e0e0c3c196ecc2b010d7d.png" width="7015" height="4960" class="img_ev3q"></p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="zweiter-neuer-durchgang">Zweiter neuer Durchgang<a href="https://geodaten-guerilla.net/blog/Fernerkundung-Klassifikation-Anpassung#zweiter-neuer-durchgang" class="hash-link" aria-label="Direkter Link zur Zweiter neuer Durchgang" title="Direkter Link zur Zweiter neuer Durchgang">​</a></h2>
<p>Ein weiterer Durchgang fand ohne die Klasse Bahn statt, um zu untersuchen, welchen Einfluss diese Änderung auf die Klassifikation haben wird:</p>
<ul>
<li>Wasser für Wasserflächen</li>
<li>Straßen für Verkehrsflächen, Straßen, Parkplätze und andere große Plätze</li>
<li>Wald für Wälder und Baumgruppen</li>
<li>Gebäude für alle Arten von Gebäuden</li>
<li>Landwirtschaft für landwirtschaftlich genutzte Flächen</li>
<li>Grünflächen für Grünflächen, die nicht landwirtschaftlich genutzt werden oder Wälder sind</li>
</ul>
<p>Das Ergebnis war das selbe, wie das eben beschriebene. Die fehlende Klasse Bahn hat allerdings die Auswirkung, dass die Pixel, die vorher als Bahnstrecken (fehl-)klassifiziert wurden, als Gebäude klassifiziert werden.
<img decoding="async" loading="lazy" alt="kiel-vorhersage-vergleich-bahn.png" src="https://geodaten-guerilla.net/assets/images/kiel-vorhersage-vergleich-bahn-86890b4fc85e329f0528896206e6600a.png" width="7015" height="4960" class="img_ev3q"></p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="fazit">Fazit<a href="https://geodaten-guerilla.net/blog/Fernerkundung-Klassifikation-Anpassung#fazit" class="hash-link" aria-label="Direkter Link zur Fazit" title="Direkter Link zur Fazit">​</a></h2>
<p>Anhand der bisher durchgeführten Klassifikationen lassen sich weitere Anpassungen der Klassen und der Erstellung der Trainingsgebiete erdenken, um grobe Fehlklassifikationen zu vermeiden und die Präzision zu erhöhen. Ein paar Möglichkeiten dafür wurden oben schon genannt. Als weitere Anpassung wäre eine Klasse Verkehrswege, die sowohl Straßen als auch Bahnenstrecken enthält, denkbar, da beide Klassen tlw. als die jeweils andere Klasse erkannt werden. Bei der Erstellung der Trainingsgebiete sollte mehr darauf geachtet werden, in dicht bebauten Gebieten keine anzulegen, um in den Trainingsgebieten möglichst nur "sortenreine" Pixel einzubeziehen. Eine weitere Verbesserung könnte der Einbezug von Vegetationsindizes bedeuten.</p>
<p>Es zeigt sich, dass die Klassifikation von Landbedeckungen, was nur ein Praxisbeispiel von vielen in der Fernerkundung ist, ein Prozess ist, in dem die einzelnen Arbeitsschritte und (Teil-)Ergebnisse immer wieder überprüft und validiert werden müssen, um zu zufriedenstellenden Ergebnissen zu gelangen. Die Einteilung der Klassen und der Trainingsgebiete müssen immer wieder der Fragen- und Aufgabenstellung angepasst und hinterfragt werden. Fehler können ärgerlich sein, aber bringen einem immer näher zu einem besseren Ergebnis.</p>]]></content>
        <author>
            <name>Johanna I. Klitzschmüller</name>
            <email>altesholz@riseup.net</email>
            <uri>https://tech.lgbt/@fedora</uri>
        </author>
        <category label="Geodaten" term="Geodaten"/>
        <category label="Karten" term="Karten"/>
        <category label="Satellitendaten" term="Satellitendaten"/>
        <category label="Python" term="Python"/>
        <category label="GIS" term="GIS"/>
        <category label="Programmierung" term="Programmierung"/>
        <category label="Fernerkundung" term="Fernerkundung"/>
        <category label="remote sensing" term="remote sensing"/>
        <category label="Landbedeckung" term="Landbedeckung"/>
        <category label="maschinelles Lernen" term="maschinelles Lernen"/>
        <category label="Johanna" term="Johanna"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Fernerkundung: Informationsgewinnung aus der Ferne]]></title>
        <id>https://geodaten-guerilla.net/blog/Fernerkundung-Informationsgewinnung-ferne</id>
        <link href="https://geodaten-guerilla.net/blog/Fernerkundung-Informationsgewinnung-ferne"/>
        <updated>2023-06-11T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Mit der Fernerkundung lassen sich große Gebiete (meist mit Satellitendaten) aus der Entfernung untersuchen. Dafür macht mensch sich zu Nutze, dass jedes Objekt eine charakteristische Signaturkurve im elektromagnetischen Spektrum aufweist. Ein Anwendungsbeispiel für die Fernerkundung ist die Klassifikation von Landbedeckungen mit Hilfe von Satellitendaten.]]></summary>
        <content type="html"><![CDATA[<p>Geodaten haben in den letzten Jahrzehnten eine <a href="https://geodaten-guerilla.net/blog/Geodaten-Karten-Werkzeug#geodaten-und-geographische-informationen" target="_blank" rel="noopener noreferrer">Schlüsselstellung in der Entwicklung der Informations- und Wissensgesellschaften auf der Welt errungen</a>. Viele Anwendungen, die auf Geodaten aufbauen, bspw. in der Umweltüberwachung, der Nutzung natürlicher Ressourcen, der Verkehrsplanung, der Raumplanung und amtliche Statistiken, besitzen eine große gesellschaftliche und politische Relevanz (Kappas 2012, S. 8 ff). Allerdings stehen nicht immer bereits gesammelte oder aufbereitete Geodaten (zur freien Nutzung) zur Verfügung. In solchen Fällen kann es notwendig sein, eigene Daten zu sammeln, zu kartieren und aufzubereiten. Aber das setzt voraus, dass mensch selbst oder eine beauftragte Person ins Feld geht und die Daten sammelt. Das ist nicht immer möglich oder praktisch umsetzbar, wenn bspw. das Untersuchungsgebiet zu groß ist. Außerdem ist die Ebene der Informationen, die wir sammeln können, auf die Messgeräte beschränkt, tlw. sogar nur auf unsere Augen, die wir mitführen können.</p>
<p>Aus diesem Grund soll dieser Text die Methode der Fernerkundung vorstellen, die es uns erlaubt, Geodaten aus der Ferne zu sammeln und zu analysieren. Mehr noch: Mit der Fernerkundung können wir große Flächen weltweit untersuchen und neue Informationsebenen erschließen, da uns elektromagnetische Strahlung als Informationsübermittler dient. Die Gewinnung von Informationen durch die Fernerkundung hat eine große Bedeutung und wird als Standardverfahren u.a. in der Wetterbeobachtung und im Umweltmonitoring eingesetzt. Damit hat die Fernerkundung auch ein großes Potenzial, die dadurch gewonnen Daten in unseren Kampf für eine bessere Welt einzubringen. Ein Praxisbeispiel, die Klassifikation von Landbedeckungen mit Hilfe von Satellitendaten, soll außerdem zeigen, wie wir die Fernerkundung nutzen können.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="satelliten-strahlung-und-sensoren">Satelliten, Strahlung und Sensoren<a href="https://geodaten-guerilla.net/blog/Fernerkundung-Informationsgewinnung-ferne#satelliten-strahlung-und-sensoren" class="hash-link" aria-label="Direkter Link zur Satelliten, Strahlung und Sensoren" title="Direkter Link zur Satelliten, Strahlung und Sensoren">​</a></h2>
<p>Die Fernerkundung ist ein sehr breites Feld, das in seiner Gesamtheit nicht in einem Text zu erfassen ist. Um einen Einstieg zu ermöglichen, möchte ich die Fernerkundung und das Grundprinzip, mit dem Informationen aus reflektierter und emittierter Strahlung gewonnen werden, kurz darstellen.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="was-ist-fernerkundung">Was ist Fernerkundung?<a href="https://geodaten-guerilla.net/blog/Fernerkundung-Informationsgewinnung-ferne#was-ist-fernerkundung" class="hash-link" aria-label="Direkter Link zur Was ist Fernerkundung?" title="Direkter Link zur Was ist Fernerkundung?">​</a></h3>
<p>Im ersten Schritt möchte ich den Begriff Fernerkundung definieren. Das soll uns eine Eingrenzung dieses sehr weiten Feldes für den Rest des Texts und des Praxisbeispiels ermöglichen.</p>
<p><em>"Remote sensing is the practice of deriving information about the Earth’s land and water surfaces using images acquired from an overhead perspective, using electromagnetic radiation in one or more regions of the electromagnetic spectrum, reflected or emitted from the Earth’s surface" (Campbell et al. 2022, S. 4).</em></p>
<p>In der Fernerkundung leiten wir also Informationen über die Erd- und Wasseroberflächen ab, indem wir Bilder nutzen, die aus einer Überkopfperspektive aufgenommen werden. Diese Überkopfperspektive wird durch Sensoren erreicht, die auf Flugzeugen, Satelliten oder Drohnen befestigt sind. Bei der Informationsgewinnung nutzen wir die von den Sensoren aufgenommene elektromagnetische Strahlung, die von der Erdoberfläche reflektiert oder emittiert wird. Das umfasst auch die Strahlung, die für das menschliche Auge nicht sichtbar ist. Das zentrale Konzept ist also klar: Das Sammeln von Informationen aus der Ferne mit Hilfe von elektromagnetischer Strahlung (Campbell et al. 2022, S. 3f; de Lange 2020, S. 431). Damit steht uns eine sehr leistungsfähige Methodik zur Verfügung, aus der Ferne große Flächen in verschiedenen Wellenlängenbereichen des elektromagnetischen Spektrums und Veränderungen im Laufe der Zeit zu beobachten (Campbell et al. 2022, S. 3; de Lange 2020, S. 432).</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="elektromagnetische-strahlung-und-sensoren">Elektromagnetische Strahlung und Sensoren<a href="https://geodaten-guerilla.net/blog/Fernerkundung-Informationsgewinnung-ferne#elektromagnetische-strahlung-und-sensoren" class="hash-link" aria-label="Direkter Link zur Elektromagnetische Strahlung und Sensoren" title="Direkter Link zur Elektromagnetische Strahlung und Sensoren">​</a></h3>
<p>Da nun klar ist, dass wir die von der Erde reflektierte und emittierte elektromagnetische Strahlung zur Informationsgewinnung nutzen, stellt sich die Frage, nach welchem Grundprinzip das funktioniert. Zunächst müssen wir uns klar werden, dass elektromagnetische Strahlung in unterschiedlichen Wellenlängen, abhängig von ihrer Energie, vorkommt. Für die Fernerkundung sind bestimmte Wellenlängenbereiche von besonderer Bedeutung. Zu nennen sind hier das sehr kurzwellige Ultraviolett, das sichtbare Licht, welches unsere Augen sehen können, Infrarot und Mikrowellen, welche Anwendung in Radaren findet. Das Infrarot lässt sich noch weiter unterteilen in das nahe Infrarot, das sich u.a. für die Untersuchung von lebender Vegetation eignet, das mittlere Infrarot, geeignet u.a. für die Untersuchung von Bränden, Mineralien und der Pflanzengesundheit, und das ferne Infrarot, auch Thermal- oder Wärmestrahlung genannt. Die Abgrenzungen sind nicht scharf definiert, mitunter fließend und teilweise auch autorenabhängig (Campbell et al. 2022, S. 28f; de Lange 2020, S. 438). Wichtig ist aber anzumerken, dass nicht alle Wellenlängenbereiche für die Fernerkundung nutzbar sind. Das hängt mit der Durch- bzw. Undurchlässigkeit der Atmosphäre für bestimmte Wellenlängenbereiche, aufgrund von Absorption, Streuung und atmosphärischen Fenstern, zusammen (Campbell et al. 2022, S. 28f; de Lange 2020, S. 440).</p>
<p>Wenn wir nun mit einem Sensor die von unseren Untersuchungsobjekten reflektierte und emittierte Strahlung messen, werden wir feststellen, dass jedes Objekt abhängig von seiner Art, Beschaffenheit und Zustand auf unterschiedliche Weise emittiert oder reflektiert. So werden wir feststellen, dass jedes Objekt ein charakteristisches Strahlungs- oder Reflexionsverhalten besitzt. Das erlaubt uns, sogenannte Reflexions- bzw. Signaturkurven zu erstellen und so Objekte zu indentifizieren (de Lange 2020, S. 431ff). Mit diesem Wissen können wir dann Aussagen bspw. über den Zustand von Vegetation treffen oder Flächen mit ähnlichen Signaturkurven einer bestimmten Landbedeckung zuordnen (de Lange 2020, S. 442ff).</p>
<p>Aber wie funktionieren diese Sensoren, die die elektromagnetische Strahlung messen? Denn wir müssen insbesondere für das Praxisbeispiel bedenken, dass diese keine Bilder wie "normale" Kameras aufnehmen. Jeder Sensor (ein Satellit kann mit mehreren Sensoren ausgestattet sein) wird darauf eingestellt, die eingehende elektromagnetische Strahlung bestimmter Wellenlängenbereiche zu messen. So kann bspw. ein Satellit einen Sensor für das nahe Infrarot und für das ferne Infrarot mitführen. Diese Wellenlängenbereiche, die die verschiedenen Sensoren eines Satelliten messen, werden Kanäle genannt (de Lange 2020, S. 442). Die Daten, die die Sensoren dann liefern, sind wie gesagt, keine Bilder, sondern bestehen für jeden Kanal aus Zahlenmatrizen. Die Werte der Matrizen entsprechen der Einstrahlungsintensität der elektromagnetischen Strahlung am Sensor. Wenn wir nun die jeweiligen Matrizen eines Kanals an einem Bildschirm anzeigen lassen, entstehen Graustufenbilder (de Lange 2020, S. 462f). Bei einer 8-Bit-Farbtiefe steht dann der Wert 0 für die Farbe schwarz und der Wert 255 für weiß. Die Werte dazwischen sind dann entsprechende Graustufen. Wenn wir die Kanäle im sichtbaren Licht, falls entsprechende Sensoren am Aufnahmesystem vorhanden sind, kombinieren, können wir am Bildschirm auch Echtfarbenbilder produzieren.</p>
<p>Neben den Kanälen ist die Auflösung ein wichtiger Parameter bei den Sensoren. Die Auflösung eines Sensors wird in mehreren Kategorien angegeben. Die räumliche Auflösung gibt die Seitenlänge der Pixel an, die der Senor aufnimmt. Die spektrale Auflösung wird durch die Anzahl der Kanäle bestimmt. Die radiometrische Auflösung gibt die Anzahl der Grauwerte an, die zur Verfügung stehen. Üblich sind hierbei 256 Graustufen pro Kanal, was bei der Speicherung 8 Bit notwendig macht. In so einem Fall wird die radiometrische Auflösung mit 8 Bit angegeben. Die temporale Auflösung, oder Repetitionsrate, gibt den Zeitabstand an, innerhalb dessen ein Gebiet von einem bestimmten Sensor wiederholt aufgezeichnet wird (de Lange 2020, S. 443f).</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="fernerkundung-in-der-praxis-klassifikation-von-landbedeckung">Fernerkundung in der Praxis: Klassifikation von Landbedeckung<a href="https://geodaten-guerilla.net/blog/Fernerkundung-Informationsgewinnung-ferne#fernerkundung-in-der-praxis-klassifikation-von-landbedeckung" class="hash-link" aria-label="Direkter Link zur Fernerkundung in der Praxis: Klassifikation von Landbedeckung" title="Direkter Link zur Fernerkundung in der Praxis: Klassifikation von Landbedeckung">​</a></h2>
<p>Mit dem Wissen, dass fast jedes Objekt eine charakteristische spektrale Signaturkurve besitzt, können wir Untersuchungsansätze entwickeln. Einen Ansatz möchte ich im Folgenden anhand eines Praxisbeispiels vorstellen: Die <strong>Klassifikation</strong> von Landbedeckungen in einem Ausschnitt von Schleswig-Holstein. Das bedeutet, wir wollen anhand von Fernerkundungsdaten herausfinden, was die vor Ort vorzufindende Landbedeckung ist, ohne die jeweiligen Orte selbst zu besuchen. Diese Daten können dann die Grundlage für weitere Untersuchungen bilden, bspw. über den Anteil versiegelter Flächen oder den Zustand von Vegetation in bestimmten Bereichen. Ich beschränke mich im Folgendem auf die Klassifikation der Landbedeckungen. Für die großflächige <strong>Klassifikation</strong> von Landbedeckungen eignen sich satellitengestützte Sensoren, die neben dem sichtbaren Licht auch mindestens das nahe Infrarot erfassen, welches die Untersuchung von Vegetation möglich macht (de Lange 2020, S. 436).</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="datenbezug">Datenbezug<a href="https://geodaten-guerilla.net/blog/Fernerkundung-Informationsgewinnung-ferne#datenbezug" class="hash-link" aria-label="Direkter Link zur Datenbezug" title="Direkter Link zur Datenbezug">​</a></h3>
<p>Der erste Schritt wird die Beschaffung von Satellitendaten sein. Anlaufstellen dafür sind natürlich die großen Weltraumbehörden, wie die NASA oder ESA, aber es existieren auch private Weltraummissionen, die kommerzielle Daten zur Verfügung stellen. Freie Fernerkundungsdaten der Landsat- und Sentinel-Missionen finden sich beim USGS Earth Resources Observation and Science Center (EROS) und beim Copernicus-Programm. Ersteres stellt große Mengen an Landsat-Satellitenbildern frei zur Verfügung, zweiteres stellt Daten der Sentinel-Missionen zur Verfügung, welches ein unabhängiges europäisches Erdbeobachtungssystem darstellt. Viele der bei beiden angebotenen Daten sind auch bereits vorverarbeitet, also georeferenziert und können damit direkt im GIS genutzt werden (de Lange 2020, S. 463f).</p>
<p>Für unser Projekt werden wir Daten der Sentinel-Satelliten der Copernicus-Mission nutzen. Das Ziel dieser Mission ist, Datengrundlagen für die Land- und Forstwirtschaft, Landmanagement, Gewässerüberwachung, Katastrophenschutz, Klimawissenschaft u.v.m zu liefern (Campbell et al. 2022, S. 182; de Lange 2020, S. 459). Im speziellen werden die für das Projekt verwendeten Daten vom Satelliten Sentinel-2A kommen. Sentinel-2A ist nämlich mit einem hochauflösenden multispektralen Sensor ausgestattet, der u.a. blau, grün, rot und infrarot mit einer Auflösung von 10 Metern misst (de Lange 2020, S. 459). Damit erscheint Sentinel-2A gute Voraussetzungen mitzubringen, um Landbedeckungen zu klassifizieren. Insbesondere da auch infrarot gemessen wird, was für die Untersuchung von Vegetation gut geeignet ist.</p>
<p>Satellitendaten der Sentinel-Satelliten können wir vom <a href="https://scihub.copernicus.eu/dhus/#/home" target="_blank" rel="noopener noreferrer">Copernicus Open Access Hub</a> herunterladen. Es gibt mittlerweile ein neues <a href="https://dataspace.copernicus.eu/" target="_blank" rel="noopener noreferrer">Copernicus Data Space Ecosystem</a>, der <em>Open Access Hub</em> ist aber noch funktionstüchtig. Die Bedienung des <em>Open Access Hub</em> ist allerdings etwas kompliziert. Es benötigt erstmal einen Account. Dieser lässt sich mit einem Klick oben rechts auf das Kopfsymbol erstellen. Danach lässt sich direkt nach sogenannten Szenen suchen. Wenn mensch die genaue Bezeichnung einer Szene nicht weiß, lässt sich mit Rechtsklick auf die Karte ein Polygon zeichnen. In Verbindung mit der erweiterten Suche, die sich über die drei Striche im Suchfeld erreichen lässt, lassen sich Szenen nach ausgewählten Kriterien im Bereich des vorher gezeichneten Polygons suchen. Wenn mensch dann eine Szene gewählt hat, ist diese im "Warenkorb" (Einkaufswagensymbol) zu finden und herunterzuladen. Für unser Praxisbeispiel nutzen wir die Szene "S2A_MSIL2A_20200623T103031_N0214_R108_T32UNF_20200623T142851". Diese erstreckt sich über den Nordosten Schleswig-Holsteins und Südosten Dänemarks und stammt aus dem Juni 2020.</p>
<p><img decoding="async" loading="lazy" alt="copernicus-open-access-hub-bemerkungen.png" src="https://geodaten-guerilla.net/assets/images/copernicus-open-access-hub-bemerkungen-af648a4cae1b2fb81fe208fd1e24d1c5.png" width="1911" height="1421" class="img_ev3q"></p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="vorbereitung-der-daten">Vorbereitung der Daten<a href="https://geodaten-guerilla.net/blog/Fernerkundung-Informationsgewinnung-ferne#vorbereitung-der-daten" class="hash-link" aria-label="Direkter Link zur Vorbereitung der Daten" title="Direkter Link zur Vorbereitung der Daten">​</a></h3>
<p>Sind die Daten heruntergeladen, können wir diese direkt ins GIS laden und uns mit diesen vertraut machen. Die "<em>MTD_MSIL2A.xml</em>" bietet uns bereits verschiedene Variationen aus Echtfarben- und Falschfarbenbildern. Für unsere nächsten Schritte laden wir die Bilddaten für die Bänder 2 bis 4 und Band 8, die sich als jp2-Dateien unter "Projektordner/GRANULE/L2A_T32UNF_A026131_20200623T103426/IMG_DATA/R10m/" finden lassen, ins GIS und exportieren diese dann als GeoTiff-Dateien. Diese Tiff-Dateien werden später vom Skript genutzt, dass die Klassifikation durchführt. Als Ergebnis sehen wir zunächst Graustufenbilder. Jede Rasterzelle beinhaltet den Wert, den der Sensor an der jeweiligen Stelle für den jeweiligen Kanal gemessen hat.</p>
<p><img decoding="async" loading="lazy" alt="qgis-rohe-satellitendaten-kiel.png" src="https://geodaten-guerilla.net/assets/images/qgis-rohe-satellitendaten-kiel-fa9a29868be7017ae95e3ac0b65512c7.png" width="1920" height="1560" class="img_ev3q"></p>
<p>Aus den Tiff-Dateien können wir nun ein virtuelles Raster als Echtfarbenbild generieren. Dafür müssen wir in den Eigenschaften des virtuellen Rasters den Render type auf Multiband color einstellen und die jeweils richtigen Bänder zuweisen. Es lassen sich auch die im Datensatz vorhandenen Echtfarbenbilder nutzen. Diese Echtfarbenbilder nutzen wir im weiteren Verlauf, um <strong>Klassen</strong> und <strong>Trainingsgebiete</strong> festzulegen.</p>
<p><img decoding="async" loading="lazy" alt="qgis-virt-raster-kiel.png" src="https://geodaten-guerilla.net/assets/images/qgis-virt-raster-kiel-344cb6b71f37d1a2e9e3b055529b6cad.png" width="1920" height="1560" class="img_ev3q"></p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="festlegen-von-klassen-und-trainingsgebiete">Festlegen von Klassen und Trainingsgebiete<a href="https://geodaten-guerilla.net/blog/Fernerkundung-Informationsgewinnung-ferne#festlegen-von-klassen-und-trainingsgebiete" class="hash-link" aria-label="Direkter Link zur Festlegen von Klassen und Trainingsgebiete" title="Direkter Link zur Festlegen von Klassen und Trainingsgebiete">​</a></h3>
<p>In diesem Text fielen bereits die Begriffe <strong>Klassifikation</strong>, <strong>Klassen</strong> und <strong>Trainingsgebiete</strong>. Doch was haben diese mit dem Ziel, Landbedeckungen in einem ausgewählten Bereich der Erde herauszufinden, zu tun? Die Satellitendaten, die uns vorliegen, bestehen aus Pixeln, die alle unterschiedliche Werte, und damit Eigenschaften, haben. Das Ziel ist, alle Pixel, die ähnliche Eigenschaften haben, einer jeweiligen Landbedeckungsart zuzuordnen, sprich zu klassifizieren. Denn es ist generell davon auszugehen, dass die verschiedenen Landbedeckungsarten eigene, für sie charakteristische Reflexionsverhalten haben (de Lange 2020, S. 483ff).</p>
<p>Zuerst legen wir Klassen fest. Dies sollen die Landbedeckungen sein, die wir erwarten oder hoffen, zu finden und zu klassifizieren. Als Hilfsmittel dient hier das generierte Echtfarbenbild. Anhand dessen können wir Landbedeckungen, die wir in diesem sehen, als Klassen festlegen. Kritierium sollte dabei sein, dass diese auf dem Bild homogen aussehen. Anhand dieser Voraussetzungen habe ich folgende Klassen festgelegt:</p>
<ul>
<li>Wasser für Wasserflächen</li>
<li>Industrie und Gewerbe für Industrie- und Gewerbegebiete</li>
<li>Straßen für Straßen, Parkplätze und andere große Plätze</li>
<li>Bahn für Bahnanlagen bzw. Bahnschienen</li>
<li>Wald für Wälder und Baumgruppen</li>
<li>Gebäude für alle Gebäude, die nicht Industrie oder Gewerbe sind</li>
<li>Landwirtschaft für landwirtschaftlich genutzte Flächen</li>
<li>Grünflächen für Grünflächen, die nicht landwirtschaftlich genutzt werden oder Wälder sind</li>
<li>Sportanlagen für Sportanlagen und Laufbahnen</li>
<li>Kleingärten für Kleingartengebiete</li>
</ul>
<p>Der nächste Schritt ist die Festlegung von Trainingsgebieten. Dafür zeichnen wir im <em>GIS</em> mehrere Polygone für jede Klasse. Da wir das Echtfarbenbild als Hintergrund nutzen können, sollte dies einfach von der Hand gehen. Ist das erledigt, können wir zum nächsten Schritt übergehen, in welchem wir jeder Fläche einer Landbedeckung zuordnen werden.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="klassifikation-mittels-maschinellen-lernens">Klassifikation mittels maschinellen Lernens<a href="https://geodaten-guerilla.net/blog/Fernerkundung-Informationsgewinnung-ferne#klassifikation-mittels-maschinellen-lernens" class="hash-link" aria-label="Direkter Link zur Klassifikation mittels maschinellen Lernens" title="Direkter Link zur Klassifikation mittels maschinellen Lernens">​</a></h3>
<p>Die folgende Klassifikation der Satellitendaten lassen wir ein Python-Skript übernehmen. Dieses wird mittels maschinellem Lernen automatisiert alle Pixel einer der vorher definierten Klassen zuordnen. Klassifikationsverfahren, die dem maschinellen Lernen zuzuordnen sind, sind mittlerweile zum Standard geworden (de Lange 2020, S. 496). Für unser Praxisbeispiel habe ich mich für den sogenannten <a href="https://de.wikipedia.org/wiki/Random_Forest" target="_blank" rel="noopener noreferrer">Random-Forest-Classifier</a> als Klassifikationsverfahren entschieden.</p>
<p>Es sind allerdings Einschränkungen bei der automatisierten Klassifizierung von Landbedeckung zu beachten. Die Signaturkurven von Objekten können sich je nach Jahreszeit oder Atmosphärenzustand ändern, sodass mensch nicht von allgemeingütligen Signaturkurven ausgehen kann. Außerdem setzen die geometrische und spektrale Auflösung der Sensoren bei der Erkennung von Mischformen von Klassen Grenzen (de Lange 2020, S. 443ff).</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="ein-ausbaufähiges-ergebnis">Ein ausbaufähiges Ergebnis<a href="https://geodaten-guerilla.net/blog/Fernerkundung-Informationsgewinnung-ferne#ein-ausbauf%C3%A4higes-ergebnis" class="hash-link" aria-label="Direkter Link zur Ein ausbaufähiges Ergebnis" title="Direkter Link zur Ein ausbaufähiges Ergebnis">​</a></h3>
<p>Wenn das Skript erfolgreich durchgelaufen ist, erhalten wir eine Rasterdatei als Ergebnis zurück, in welchem jedes Pixel die ihm zugeordnete Klasse enthält. In dem dargestellten Ausschnitt des Untersuchungsgebiets (Kieler Innenförde) sind die Strukturen, wie sie auch in der Realität zu finden sind, gut zu erkennen.</p>
<p><img decoding="async" loading="lazy" alt="kiel-vorhersage-grau.png" src="https://geodaten-guerilla.net/assets/images/kiel-vorhersage-grau-b145dd150d1b8a8e832348381ba3b418.png" width="7015" height="4960" class="img_ev3q"></p>
<p>Entsprechend ihrer Klasse lassen sich jedem Pixel Farbwerte zuordnen. Daraufhin erkennen wir schonmal grob die Siedlungsstrukturen, die Wasser- und Grünflächen und Verkehrswege rund um die Innenförde.</p>
<p><img decoding="async" loading="lazy" alt="kiel-vohersage-foerde.png" src="https://geodaten-guerilla.net/assets/images/kiel-vohersage-foerde-16603329cf38ed3dc6776f6d30f4afc9.png" width="7015" height="4960" class="img_ev3q"></p>
<p>Nun gilt es anhand von Orten, die mensch kennt, zu beurteilen, ob das Klassifikationsverfahren valide Ergebnisse hervorgebracht hat. Dabei stechen einige auffällige Fehler hervor, die das Gesamtergebnis schmälern. Zum einen wurden Küstengewässer tlw. falsch klassifiziert und als Industrie- und Gewerbegebiete erkannt. Außerdem wurden landwirtschaftlich genutzte Flächen als Sportanlagen klassifiziert.</p>
<p><img decoding="async" loading="lazy" alt="kiel-vorhersage-vergleich-flachwasser.png" src="https://geodaten-guerilla.net/assets/images/kiel-vorhersage-vergleich-flachwasser-8f6c2a83ba0bf1e002945f26c37fd42c.png" width="7015" height="4960" class="img_ev3q"></p>
<p>Zum anderen sticht eine große Fehleinschätzung der Klassifikation bei den Wäldern hervor. In größeren Waldgebiete wurden diese nämlich als Gebäude klassifiziert.</p>
<p><img decoding="async" loading="lazy" alt="kiel-vorhersage-vergleich-wald.png" src="https://geodaten-guerilla.net/assets/images/kiel-vorhersage-vergleich-wald-84539b200b5e830aa74bedd6a8f10917.png" width="7015" height="4960" class="img_ev3q"></p>
<p>Weitere Fehlklassifikationen lassen sich u.a. bei Kleingartengebieten finden, die mal als Grünflächen, Gebäude oder landwirtschaftlich genutzte Flächen falsch erkannt wurden. Doch wie gehen wir mit diesen Fehlern um?</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="nächste-schritte">Nächste Schritte<a href="https://geodaten-guerilla.net/blog/Fernerkundung-Informationsgewinnung-ferne#n%C3%A4chste-schritte" class="hash-link" aria-label="Direkter Link zur Nächste Schritte" title="Direkter Link zur Nächste Schritte">​</a></h3>
<p>Die aufgetretenen Fehlklassifikationen zeigen, dass Handlungsbedarf besteht. Es bestehen grundsätzlich mehrere Möglichkeiten, mit den Fehlern umzugehen. Zum einen ist das eine Änderung der Trainingsgebiete, in der Hoffnung, dass die Klassifikation daraufhin besser funktioniert, zum anderen ist das eine Veränderung der zu klassifizierenden Klassen. In meinen Augen erscheint in unserem Praxisbeispiel die folgende Anpassung der Klassen am sinnvollsten:</p>
<ul>
<li>Wasser für Wasserflächen</li>
<li>Straßen für Verkehrsflächen, Straßen, Parkplätze und andere große Plätze</li>
<li>Bahn für Bahnanlagen bzw. Bahnschienen</li>
<li>Wald für Wälder und Baumgruppen</li>
<li>Gebäude für alle Arten von Gebäuden</li>
<li>Landwirtschaft für landwirtschaftlich genutzte Flächen</li>
<li>Grünflächen für Grünflächen, die nicht landwirtschaftlich genutzt werden oder Wälder sind</li>
</ul>
<p>Bei diesem Vorschlag ändert sich zum einen, dass es keine Unterscheidung zwischen "normalen" Gebäuden und Industrie und Gewerbe gibt. Eine Unterscheidung erscheint hier nicht sinnvoll. Die großen Flächen, die Industriegebäude oft umgeben, bspw. Parkplätze, sollen der Klasse "Straßen" zugeordnet werden und entsprechend in den Trainingsgebieten berücksichtigt werden. Zum anderen wird die Klasse Kleingärten entfernt. Diese bestehen oft aus einer Mischung von Gebäuden (Lauben, Schuppen) und Grünflächen. Entsprechend wurden Kleingartenflächen auch kaum als diese klassifiziert. Tlw. wurden sie sogar als landwirtschaftlich genutzte Fläche identifiziert. Ein Entfernen der Klasse soll dafür sorgen, dass die Gärten als Grünflächen und die in ihnen liegenden Gebäude als Gebäude klassifiziert werden. Eine genaue Identifikation von Kleingärten mit eindeutigen Signaturkurven ist aufgrund der beschriebenen Mischungen nicht möglich. Außerdem entfällt die Klasse Sportanlagen. Da ich eine Unterscheidung zwischen Rasenflächen von Sportanlagen und "normalen" Grünflächen im ersten Durchgang als unrealistisch gesehen habe, hatte ich bei den Trainingsgebiete sowieso nur Laufbahnen und Tennisplätze berücksichtigt. Da landwirtschaftliche Flächen mit Sportanlagen verwechselt wurden und Sportanlagen von ihrer Anzahl vernachlässigbar erscheinen, würde ich diese als eigene Klasse nicht mehr berücksichtigen.</p>
<p>Wenn wir diese Änderungen durchgeführt haben, können wir das Skript nochmal durchlaufen lassen.</p>
<p>Die Ergebnisse des erneuten Durchlaufs werden Thema eines weiteren Blogpost sein. Das Python-Skript soll unter einer freien Lizenz veröffentlicht werden. Ein Zeitpunkt ist aber noch nicht absehbar, da es dafür Anpassungen des Codes bedarf.</p>
<p><em><a href="https://geodaten-guerilla.net/blog/Fernerkundung-Klassifikation-Anpassung">Fortsetzung folgt</a></em></p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="literatur">Literatur<a href="https://geodaten-guerilla.net/blog/Fernerkundung-Informationsgewinnung-ferne#literatur" class="hash-link" aria-label="Direkter Link zur Literatur" title="Direkter Link zur Literatur">​</a></h2>
<p>Campbell, J. B.,Wynne, R. H. und V. A. Thomas (2022): Introduction to Remote Sensing. 6. Auflage. New York.
de Lange, N. (2020): Geoinformatik in Theorie und Praxis. 4. Auflage. Berlin/Heidelberg.
Kappas, M. (2012): Geographische Informationssysteme. 2. Auflage. Braunschweig.</p>]]></content>
        <author>
            <name>Johanna I. Klitzschmüller</name>
            <email>altesholz@riseup.net</email>
            <uri>https://tech.lgbt/@fedora</uri>
        </author>
        <category label="Geodaten" term="Geodaten"/>
        <category label="Karten" term="Karten"/>
        <category label="Satellitendaten" term="Satellitendaten"/>
        <category label="Python" term="Python"/>
        <category label="GIS" term="GIS"/>
        <category label="Programmierung" term="Programmierung"/>
        <category label="Fernerkundung" term="Fernerkundung"/>
        <category label="remote sensing" term="remote sensing"/>
        <category label="Landbedeckung" term="Landbedeckung"/>
        <category label="maschinelles Lernen" term="maschinelles Lernen"/>
        <category label="Johanna" term="Johanna"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[GeographyForFuture: Mit Geodaten Politik machen]]></title>
        <id>https://geodaten-guerilla.net/blog/WebMontag-GeographyForFuture</id>
        <link href="https://geodaten-guerilla.net/blog/WebMontag-GeographyForFuture"/>
        <updated>2023-03-21T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Dies ist die Verschriftlichung des Vortrag auf dem WebMontag 2/2023, der anhand eines Praxisbeispiels zeigt, wie sich Geodaten politisch nutzen lassen]]></summary>
        <content type="html"><![CDATA[<p>Beim <a href="https://www.webmontag-kiel.de/event/webmontag-2-2023/" target="_blank" rel="noopener noreferrer">WebMontag 2/2023</a> habe ich den Vortrag "GeographyForFuture: Mit Geodaten Politik machen" gehalten. In diesem habe ich, anhand der Vorgeschichte der <strong>GeoDatenGuerilla</strong> und einem Praxisbeispiel, einen Ansatz vorgestellt, wie sich Geodaten politisch nutzen lassen. Ich möchte an dieser Stelle die Vortragsinhalte und meine Notizen verschriftlichen und auf diese etwas tiefer eingehen, als dies im Vortrag möglich war. Außerdem habe ich bereits einen <a href="https://geodaten-guerilla.net/blog/Geodaten-Karten-Werkzeug">Blog-Artikel</a> veröffentlicht, der das Vortragsthema aufgreift. Die Vortragsfolien sind <a href="https://geodaten-guerilla.net/downloads/Vortr%c3%a4ge-Workshops/WebMontag-02-2023/" target="_blank" rel="noopener noreferrer">hier</a> zu finden.
<img decoding="async" loading="lazy" alt="webmontag-02-23-deckblatt.png" src="https://geodaten-guerilla.net/assets/images/webmontag-02-23-deckblatt-167d9a45e70abe12ecfbcb98835870ca.png" width="1102" height="620" class="img_ev3q"></p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="vorgeschichte">Vorgeschichte<a href="https://geodaten-guerilla.net/blog/WebMontag-GeographyForFuture#vorgeschichte" class="hash-link" aria-label="Direkter Link zur Vorgeschichte" title="Direkter Link zur Vorgeschichte">​</a></h2>
<p>Ich fand Karten schon immer toll und war sehr faszieniert von ihnen. Im Geographie-Studium habe ich dann endlich gelernt, mit Hilfe von <em>GIS</em> <strong>Karten</strong> zu erstellen. Außerdem lernte ich die Erfassung, Verwaltung und Analyse von <strong>Geodaten</strong> mittels <em>GIS</em>. Im humangeographischen Teil des Studiums beschäftigte ich mich mit Karten als <strong>Machtinstrument</strong> und lernte die <em>kritische Kartographie</em> kennen. Gleichzeitig fing ich im Studium an, mich klimapolitisch zu engagieren. Bei den Protesten gegen den <a href="https://geodaten-guerilla.net/karten/application/a21-suedspange" target="_blank" rel="noopener noreferrer">Aus- und Neubau der A21 und Südspange in Kiel</a> fing ich an, Karten des Straßenbauprojekts auf Basis der offiziellen Plankarten zu erstellen. Daraus entwickelte sich dann die Idee, <strong>Geodaten</strong> und <strong>Karten</strong>, auf Basis der Theorien "Critical GIS" (GIS als Werkzeug sozialer Transformation) und "kritische Kartographie" (kritische Auseinandersetzung mit Karten und Kartographie), mehr in politische Auseinandersetzungen einzubringen. <strong>GeoDatenGuerilla</strong>, seit Ende 2022 online, ist das Ergebnis.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="begriffserklärungen">Begriffserklärungen<a href="https://geodaten-guerilla.net/blog/WebMontag-GeographyForFuture#begriffserkl%C3%A4rungen" class="hash-link" aria-label="Direkter Link zur Begriffserklärungen" title="Direkter Link zur Begriffserklärungen">​</a></h2>
<p>Zunächst möchte ich zwei Begriffe, die bereits gefallen sind, klären. Zum einen <em>GIS</em>. <em>GIS</em> steht für Geo(graphisches) Informationssystem. Dies ist Software, mit der sich <strong>Geodaten</strong> erfassen, verwalten, analysieren und präsentieren lassen. Die am weitesten verbreiteten GIS sind das proprietäre ArcGIS von ESRI und das freie QGIS. Für die Arbeit in der <strong>GeoDatenGuerilla</strong> nutze ich QGIS.
<img decoding="async" loading="lazy" alt="qgis-mitmachen-screenshot.png" src="https://geodaten-guerilla.net/assets/images/qgis-mitmachen-screenshot-e944bee7e4c5120a91dae57279597cfe.png" width="1946" height="1586" class="img_ev3q">
In dem Bild sieht mensch einen Screenshot von QGIS, in welchem die Dateien für die <a href="https://geodaten-guerilla.net/karten/application/autobahn-20" target="_blank" rel="noopener noreferrer">A20-Kartenanwendung</a> geöffnet sind. Dabei ist zu sehen, dass die Plankarten an der Stelle georeferenziert sind und somit die Trasse abgezeichnet werden kann. Außerdem ist das in QGIS genutzte Layer-Prinzip zu erkennen. Layer sind Kartenebenen, die entsprechend ihrer Reihenfolge gerendert werden. Jeder Layer kann immer einen Datentyp enthalten, nämlich Punkte, Linien, Polygone oder Rasterdaten.</p>
<p>Zum anderen ist der Begriff <strong>Geodaten</strong> zu klären. Sehr vereinfacht handelt es sich dabei um Daten bzw. Merkmalsausprägungen, die einen räumlichen Bezug haben. Das kann die Größe eines Waldes, die Adresse eines Ortes, der Weg vom Bett zum Kühlschrank u.v.m. sein. Das bedeutet auch, dass Geodaten zentral für unsere Handlungen sind. Sie haben aber auch auf der gesellschaftlichen, politischen und wirtschaftlichen Ebene eine zentrale Bedeutung. <strong>Geodaten</strong> finden bspw. in der Umweltüberwachung, Ressourcenmanagement, Verkehrsplanung, Raumplanung etc. Verwendung. Viele kommerzielle Geodaten-Anwendungen bestimmen unseren alltäglichen Tagesablauf, wie Google Maps, dass das Routing unsere Wege berechnet oder durch seine Algorithmen bestimmt, welche Geschäfte wir auf der Karte wann zu sehen bekommen. <strong>Geodaten</strong> sind damit wichtiger Bestandteil der datengetriebenen Geschäftsmodelle der Tech-Konzerne. Außerdem werden <strong>Geodaten</strong> für staatliche und private Repression, rassistische Praktiken und Überwachung eingesetzt. Es zeigt sich also: <strong>Geodaten</strong> sind ein <strong>Machtinstrument</strong>.</p>
<p>Wie sich bisher bei der <strong>GeoDatenGuerilla</strong> und auch am Praxisbeispiel des Vortrags zeigt, ist die gängige Methode, <strong>Geodaten</strong> darzustellen, die <strong>Karte</strong>.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="exkurs-karten-sind-nicht-neutral">Exkurs: Karten sind nicht neutral<a href="https://geodaten-guerilla.net/blog/WebMontag-GeographyForFuture#exkurs-karten-sind-nicht-neutral" class="hash-link" aria-label="Direkter Link zur Exkurs: Karten sind nicht neutral" title="Direkter Link zur Exkurs: Karten sind nicht neutral">​</a></h2>
<p>Da <strong>Geodaten</strong> meist mit <strong>Karten</strong> visualisiert werden, folgt ein kleiner Exkurs in die <em>kritische Kartographie</em>. Denn Karten sind nicht neutral. Da im Vortrag dieser Punkt nur kurz angerissen wurde, möchte ich dies nochmal kurz darstellen. Etwas ausführlicher wird die Problematik, dass Karten keine neutrale Abbildung der Erdoberfläche sind, im <a href="https://geodaten-guerilla.net/blog/Geodaten-Karten-Werkzeug#karten-sind-nicht-neutral">ersten Blogpost</a> ausgeführt.</p>
<p>„Eine Karte ist ein verkleinertes, vereinfachtes und verebnetes Abbild der Erdoberfläche, ggf. einschließlich mit ihr in Verbindung stehender Sachverhalte, und die Kartographie ist das Fachgebiet, welches sich mit der Herstellung derartiger Abbilder befasst“ (Kohlstock, P. (2014): Kartographie: Eine Einführung. 3. Auflage. Paderborn. Seite 17)
Diese Definition von <strong>Karten</strong> und der Kartographie zeigt das Verständnis, dass Karten neutral und mehr oder weniger die Wirklichkeit abbilden. Die <em>kritische Kartographie</em> hinterfragt dieses Paradigma. Denn <strong>Karten</strong> spiegeln gesellschaftliche Machtstrukturen wieder und werden durch Machtinteressen geprägt. Sie sind keine neutralen Wissenserklärungen der Welt, sondern die sozialen Strukturen ihres Entstehungszeitpunkt sind in ihnen angebildet. <strong>Karten</strong> produzieren also (soziale) Weltbilder. Im Gegenzug bedeutet das aber auch, dass sie sich dafür auch im eigenen Sinne nutzen lassen.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="mit-geodaten-und-karten-kämpfen-lernen">Mit Geodaten und Karten kämpfen lernen<a href="https://geodaten-guerilla.net/blog/WebMontag-GeographyForFuture#mit-geodaten-und-karten-k%C3%A4mpfen-lernen" class="hash-link" aria-label="Direkter Link zur Mit Geodaten und Karten kämpfen lernen" title="Direkter Link zur Mit Geodaten und Karten kämpfen lernen">​</a></h2>
<p>Was für Ansatzpunkte gibt es nun, mit <strong>Geodaten</strong> Politik zu machen? Ich möchte einen Ansatzpunkt, den ich "Sichtbarmachen und Einordnen" nenne, an einem Praxisbeispiel vorstellen. Dies möchte ich anhand der schon angesprochenen Karten der <a href="https://geodaten-guerilla.net/downloads/A21-S%c3%bcdspange/" target="_blank" rel="noopener noreferrer">A21/Südspange</a>, aus denen sich <strong>GeoDatenGuerilla</strong> entwickelt hat.</p>
<p>Das folgende Bild ist ein Auschnitt der Plankarte des Planfall 1 der <em>A21/Südspange</em> (Anlage 6 der <a href="https://ratsinfo.kiel.de/bi/vo020.asp?VOLFDNR=19031" target="_blank" rel="noopener noreferrer">Drucksache 0277/2016 im Ratsinformationssystem der Stadt Kiel</a>) aus dem Jahr 2016:
<img decoding="async" loading="lazy" alt="Planfall1_Screenshot.png" src="https://geodaten-guerilla.net/assets/images/Planfall1_Screenshot-3b644fbee98081180a930be6ab6bd80b.png" width="1919" height="1273" class="img_ev3q">
Die Karte ist für Laien schwer zu lesen und eine eine Einordnung, was dieses Projekt für die betroffenen Flächen und die Umgebung bedeuten würde, ist nur schwer möglich. Was für Flächen in welcher Größe betroffen sein werden, ist der Karte auch nicht zu entnehmen.</p>
<p>Aus diesem Grund habe ich dann von der Plankarte die Trassen und Flächenverbräuche abgezeichnet und mit offenen Daten verbunden. Daraus ist folgende Karte für eine Aktion entstanden, die danach immer wieder Verwendung fand:
<img decoding="async" loading="lazy" alt="2020_08_19_Uebersichtskarte-Flaechenangaben.png" src="https://geodaten-guerilla.net/assets/images/2020_08_19_Uebersichtskarte-Flaechenangaben-5afe5c0debef03da993a9a90d36c436a.png" width="4960" height="3507" class="img_ev3q">
Auf dieser Karte sind die Trassenverläufe sehr viel klarer zu erkennen. Das Ausmaß der benötigten Flächen und in welcher Zahl diese betroffen sein werden, ist nun klar. Außerdem wird in dieser Karte die Aufmerksamkeit klar auf die Grünflächen gelenkt (Karten sind von Machtinteressen geprägt). Mit dieser Karte hatte mensch in den Protesten auf einmal etwas in der Hand, womit sich Gespräche führen ließen und das Ausmaß der Zerstörung klar gemacht werden konnte. Es ließ sich Aufmerksamkeit generieren und konkrete Zahlen in Auseinandersetzungen einbringen.</p>
<p>In der Folgezeit sind weitere Karten entstanden, die für verschiedene Zwecke genutzt wurden:
<img decoding="async" loading="lazy" alt="2021_05_27_Klimaguertel_Karte_Flyer.png" src="https://geodaten-guerilla.net/assets/images/2021_05_27_Klimaguertel_Karte_Flyer-b46924d3f836239d84c48c9c3f2f0fdd.png" width="2267" height="1275" class="img_ev3q">
<img decoding="async" loading="lazy" alt="2021_09_02_Neuer-Flyer-Karte.png" src="https://geodaten-guerilla.net/assets/images/2021_09_02_Neuer-Flyer-Karte-e82b0cbfb7b9cad2733f98c345b60dca.png" width="1523" height="1464" class="img_ev3q"></p>
<p>Die gezeigten Beispiele sind nur statische Karten, die entweder ausgedruckt oder als pdf-Dateien zur Verfügung gestellt wurden. Die nächste Evolutionsstufe sind interaktive <strong>Web-Karten</strong>. Zur <em>A21/Südspange</em> ist <a href="https://geodaten-guerilla.net/karten/" target="_blank" rel="noopener noreferrer">hier</a> auch eine verfügbar. Mit diesen lassen sich Objekte abfragen, die eigene Position lässt sich orten und damit der betroffene Raum direkt erkunden.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="weitere-ansatzpunkte">Weitere Ansatzpunkte<a href="https://geodaten-guerilla.net/blog/WebMontag-GeographyForFuture#weitere-ansatzpunkte" class="hash-link" aria-label="Direkter Link zur Weitere Ansatzpunkte" title="Direkter Link zur Weitere Ansatzpunkte">​</a></h2>
<p>Wir sehen also, <strong>Geodaten</strong> und <strong>Karten</strong> haben das Potenzial, ein Werkzeug für den Kampf um eine bessere Welt zu sein. Dazu kommt, dass der Zugang zu Werkzeugen für Geodatenverarbeitung und Kartographie so einfach ist, wie nie zuvor, und Projekte wie OpenStreetMap und der (erkämpfte) Trend zu OpenData sorgen für eine Demokratisierung von <strong>Geodaten</strong> und <strong>Karten</strong>.
Aus dem bisherigen Text und Überlegungen beim Verfassen gehen erstmal drei Ansatzpunkte hervor, was getan werden kann. Diese sind natürlich nicht abschließend und es gibt sehr viel mehr Möglichkeiten und Ansätze.</p>
<ul>
<li>Das Sammeln von (Geo-)Daten, sowohl von welchen, die frei verfügbar sind, bspw. OpenData-Datensätze oder Planunterlagen von (Bau-)Projekten, als auch selbst gesammelte (Geo-)Daten aus bspw. Kartierungen. Mit diesem Prozess lassen sich auch Machtstrukturen aufbrechen und die Hoheit über (Geo-)Daten erlangen, indem Daten gesammelt und zusammengetragen werden, die sonst nicht von offiziellen Stellen oder Privatunternehmen gesammelt werden. Die (Geo-)Daten lassen sich durch offene Lizenzen und Projekte wie OpenStreetMap auch anderen Kämpfen zur Verfügung stellen und in Diskurse einbringen.</li>
<li>In den Karten lassen sich die Sachverhalte in den Fokus stellen, die die Menschen, die politischen Kämpfe führen, wichtig finden. Dies kann damit auch ein Werkzeug sein, von Diskriminierung und Stigmatisierung betroffenen Menschen und Gruppen (bspw. in sogenannten "sozialen Brennpunkten" oder Indigene) die Hoheit über die eigene Darstellung zu geben.</li>
<li>Mit der Verbreitung von (Geo-)Daten und Karten über verschiedene Kanäle werden diese zugänglich für viele verschiedene Menschen. Mit interaktiven Karten können diese einbezogen werden. Das kann hilfreich in der Agitation oder in der Sichtbarmachung und Mobilisierung von Problemstellungen sein. Selbst das Aufmerksammachen auf bereits vorhandene (Geo-)Daten oder die Befreiung von Informationen durch IFG-Anfragen, bspw. über <a href="https://fragdenstaat.de/" target="_blank" rel="noopener noreferrer">FragDenStaat</a>, ist eine Ansatzpunkt.</li>
</ul>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="schlussworte">Schlussworte<a href="https://geodaten-guerilla.net/blog/WebMontag-GeographyForFuture#schlussworte" class="hash-link" aria-label="Direkter Link zur Schlussworte" title="Direkter Link zur Schlussworte">​</a></h2>
<p>Zum Schluss möchte ich noch zwei Literaturempfehlungen geben. Zur kritischen Kartographie:<br>
<!-- -->Glasze, G. (2014): Sozialwissenschaftliche Kartographie-, GIS- und Geoweb-Forschung. In: KN - Journal of Cartography and Geographic Information 64 (3), S. 123-129.<br>
<!-- -->Literaturempfehlung zu Critical GIS:<br>
<!-- -->Pavlovskaya, M. (2018): Critical GIS as a tool for social transformation. In: The Canadian Geographer / Le Géographe canadien 62 (1), S. 40-54.</p>
<p>Wenn Du mitmachen möchtest, egal ob Du Vorkenntnisse hast oder nicht, <a href="https://geodaten-guerilla.net/mitmachen-kontakt/">kannst Du dies gerne tun</a>.
Wenn Du <strong>GeoDatenGuerilla</strong> folgen möchtest, geht das auf <a href="https://climatejustice.rocks/@GeoDatenGuerilla" target="_blank" rel="noopener noreferrer">Mastodon</a>.</p>]]></content>
        <author>
            <name>Johanna I. Klitzschmüller</name>
            <email>altesholz@riseup.net</email>
            <uri>https://tech.lgbt/@fedora</uri>
        </author>
        <category label="Geodaten" term="Geodaten"/>
        <category label="Karten" term="Karten"/>
        <category label="WebMontag" term="WebMontag"/>
        <category label="kritisch" term="kritisch"/>
        <category label="GIS" term="GIS"/>
        <category label="Kartographie" term="Kartographie"/>
        <category label="Politik" term="Politik"/>
        <category label="Autobahn" term="Autobahn"/>
        <category label="Johanna" term="Johanna"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Laufende Projekte und Call for Help]]></title>
        <id>https://geodaten-guerilla.net/blog/Projekte-Call-for-Help</id>
        <link href="https://geodaten-guerilla.net/blog/Projekte-Call-for-Help"/>
        <updated>2023-03-02T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Der Text stellt die derzeit laufenden Projekte dar und fordert zum Mitmachen auf]]></summary>
        <content type="html"><![CDATA[<p><strong>GeoDatenGuerilla</strong> ist gerade noch ein Ein-Mensch-Projekt. Das bedeutet, dass alle Projektideen, Serveradministration, Kommunikation und Textproduktion von einer Person gemacht werden. Dadurch dauern die Dinge natürlich alle etwas länger, weil Lohnarbeit und persönliches Leben auch ihren Anteil an der Tageszeit haben.  An Motivation und Ideen mangelt es aber zum Glück nicht. An dieser Stelle möchte ich einmal die derzeit laufenden Projekte darstellen.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="a21südspange">A21/Südspange<a href="https://geodaten-guerilla.net/blog/Projekte-Call-for-Help#a21s%C3%BCdspange" class="hash-link" aria-label="Direkter Link zur A21/Südspange" title="Direkter Link zur A21/Südspange">​</a></h2>
<p>Das Kartenmaterial der <strong>A21/Südspange</strong> in der <a href="https://geowebdienste.geodaten-guerilla.net/mapbender/application/a21-suedspange" target="_blank" rel="noopener noreferrer">Kartenanwendung</a> und unter <a href="https://geodaten-guerilla.net/downloads/A21-S%c3%bcdspange/" target="_blank" rel="noopener noreferrer">Downloads</a> basiert noch auf dem Planfall 1 aus dem Jahr 2016 (siehe <a href="https://geodaten-guerilla.net/docs/category/a21s%C3%BCdspange-neu--und-ausbau-in-kiel-inklusive-ostring-ii">Dokumentation</a>). Allerdings wird derzeit durch die DEGES (Deutsche Einheit Fernstraßenplanungs- und -bau GmbH) eine vertiefende Variantenprüfung durchgeführt. Gleichzeitig ist in der Ratsversammlung der Stadt Kiel ein Antrag anhängig, der sich gegen die A21/Südspange ausspricht. Dieser Antrag wurde bisher aber immer zurückgestellt. Laut einer Anfrage auf der Plattform <a href="https://fragdenstaat.de/anfrage/a21-ausbau-der-b404-zur-bundesautobahn-und-neubau-der-suedspange-kiel/" target="_blank" rel="noopener noreferrer">FragDenStaat</a> ist im Sommer mit einer Veröffenlichung der vertiefenden Variantenprüfung zu rechnen.<br>
<!-- -->Das Ziel ist, möglichst schnell nach der Veröffentlichung der Variantenprüfung neues Kartenmaterial zu erstellen.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="a20">A20<a href="https://geodaten-guerilla.net/blog/Projekte-Call-for-Help#a20" class="hash-link" aria-label="Direkter Link zur A20" title="Direkter Link zur A20">​</a></h2>
<p>Die <a href="https://geowebdienste.geodaten-guerilla.net/mapbender/application/autobahn-20" target="_blank" rel="noopener noreferrer">Kartenanwendung</a> zum <strong>Neubau der A20</strong> enthält alle Trassenverläufe der geplanten A20. Das als "Küstenautobahn" getaufte Autobahnprojekt enthält aber auch den Neubau der <strong>A26</strong> von Stade nach Drochtersen.<br>
<!-- -->Der Trassenverlauf der <strong>A26</strong> soll noch nachgezeichnet und in die Kartenanwendung integriert werden. Außerdem gibt es noch die Idee, mehr Daten zu vom Autobahnbau betroffenen Mooren zu sammeln und kartografisch darzustellen.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="reichenkataster">"Reichenkataster"<a href="https://geodaten-guerilla.net/blog/Projekte-Call-for-Help#reichenkataster" class="hash-link" aria-label="Direkter Link zur &quot;Reichenkataster&quot;" title="Direkter Link zur &quot;Reichenkataster&quot;">​</a></h2>
<p>Beim Projekt "Reichenkataster" handelt es sich bisher nur um eine grobe Idee. Ausgangspunkt ist die Problematik, dass Menschen, die staatliche Transferleistungen in Anspruch nehmen wollen, ihre finanzielle Situation bis ins kleinste Detail offenlegen müssen. Gleichzeitig gibt es über Reichtum kaum Daten. Also ist es an der Zeit, loszuziehen und den (sichtbaren) Reichtum in den Villenvierteln zu kartieren.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="maschinelles-lernen-mit-satellitendaten">Maschinelles Lernen mit Satellitendaten<a href="https://geodaten-guerilla.net/blog/Projekte-Call-for-Help#maschinelles-lernen-mit-satellitendaten" class="hash-link" aria-label="Direkter Link zur Maschinelles Lernen mit Satellitendaten" title="Direkter Link zur Maschinelles Lernen mit Satellitendaten">​</a></h2>
<p>Mit maschinellen Lernverfahren lassen sich Satellitendaten analysieren. In der Uni habe ich mit Python Landnutzungen mit Sentinal2-Daten klassifiziert und möchte das in <strong>GeoDatenGuerilla</strong> einbringen. Mit der Nutzung von Satellitendaten ergeben sich neue Möglichkeiten für Projekte und Datengewinnung. Derzeit wird hier die meiste Zeit investiert, um Programmcode aus dem Uni-Projekt nutzbar zu machen und unter einer freien Lizenz zu veröffentlichen.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="openbikesensor">OpenBikeSensor<a href="https://geodaten-guerilla.net/blog/Projekte-Call-for-Help#openbikesensor" class="hash-link" aria-label="Direkter Link zur OpenBikeSensor" title="Direkter Link zur OpenBikeSensor">​</a></h2>
<p><a href="https://www.openbikesensor.org/" target="_blank" rel="noopener noreferrer"><strong>OpenBikeSensor</strong></a> ist ein Sensor, der beim Fahrradfahren den Abstand von Überholmanövern durch Autofahrende misst und den Überholmanövern Geodaten zuordnet. Ziel ist, Schwachstellen und Verbesserungspotenzial in der Verkehrsinfrastruktur aufzuzeigen und diese in Kooperation mit Stadtplaner*innen zu beheben. In Kiel bildet sich derzeit eine Gruppe, die den Sensor in Kiel zusammenbauen und unter die Menschen bringen möchte. Das Projekt läuft nicht über <strong>GeoDatenGuerilla</strong>, aber ich bin in der Gruppe in Kiel involviert. Bei Interesse gerne <a href="https://geodaten-guerilla.net/mitmachen-kontakt#kontakt">melden</a>.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="medien">Medien<a href="https://geodaten-guerilla.net/blog/Projekte-Call-for-Help#medien" class="hash-link" aria-label="Direkter Link zur Medien" title="Direkter Link zur Medien">​</a></h2>
<p>Derzeit läuft alle öffentliche Kommunikation über <a href="https://climatejustice.rocks/@GeoDatenGuerilla" target="_blank" rel="noopener noreferrer">Mastodon</a> oder den <a href="https://geodaten-guerilla.net/blog">Blog</a>. Insbesondere beim Blog sind die Veröffentlichungen sehr unregelmäßig, was derzeit zeitlich nicht anders möglich ist. Es wäre schön, hier regelmäßiger Texte zu veröffentlichen. Auch die Idee eines Podcasts über Themen wie "kritische Kartographie" und "critical GIS" schwebt im Raum.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="neue-hardware">Neue Hardware<a href="https://geodaten-guerilla.net/blog/Projekte-Call-for-Help#neue-hardware" class="hash-link" aria-label="Direkter Link zur Neue Hardware" title="Direkter Link zur Neue Hardware">​</a></h2>
<p>Die Webseite läuft derzeit auf einem virtuellen Server bei einem großen Hosting-Anbieter. Der Plan ist, in den nächsten Wochen auf einen dedizierten Server umzusteigen. Die Hardware dafür steht auch schon bereit. Sie muss nur noch zusammengebastelt und die Software installiert werden.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="neue-web-gis-software">Neue Web-GIS-Software<a href="https://geodaten-guerilla.net/blog/Projekte-Call-for-Help#neue-web-gis-software" class="hash-link" aria-label="Direkter Link zur Neue Web-GIS-Software" title="Direkter Link zur Neue Web-GIS-Software">​</a></h2>
<p>Mit dem Wechsel des Servers liegt auch die Idee nahe, weitere Web-GIS-Software neben dem derzeit für die <a href="https://geowebdienste.geodaten-guerilla.net/mapbender/" target="_blank" rel="noopener noreferrer">Kartenanwendungen</a> genutzten <a href="https://mapbender.org/" target="_blank" rel="noopener noreferrer">Mapbender</a> auszuprobieren. Insbesondere <a href="https://geonode.org/" target="_blank" rel="noopener noreferrer">Geonode</a> ist sehr interessant.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="mitmachen-und-helfen">Mitmachen und helfen<a href="https://geodaten-guerilla.net/blog/Projekte-Call-for-Help#mitmachen-und-helfen" class="hash-link" aria-label="Direkter Link zur Mitmachen und helfen" title="Direkter Link zur Mitmachen und helfen">​</a></h2>
<p>Du interessierst Dich für eines oder mehrere der dargestellten Projekte oder hast sogar weitere Ideen? Du möchtest was über Karten und Geodaten lernen? <a href="https://geodaten-guerilla.net/mitmachen-kontakt">Melde dich gerne</a>, egal, ob Du schon Kenntnisse in GIS, Kartenerstellung, Programmierung etc. hast oder nicht. Jede Hilfe ist willkommen und Skillshares werden immer gerne gegeben :)</p>]]></content>
        <author>
            <name>Johanna I. Klitzschmüller</name>
            <email>altesholz@riseup.net</email>
            <uri>https://tech.lgbt/@fedora</uri>
        </author>
        <category label="Geodaten" term="Geodaten"/>
        <category label="Karten" term="Karten"/>
        <category label="Hardware" term="Hardware"/>
        <category label="kritisch" term="kritisch"/>
        <category label="GIS" term="GIS"/>
        <category label="Kartographie" term="Kartographie"/>
        <category label="Hilfe" term="Hilfe"/>
        <category label="mitmachen" term="mitmachen"/>
        <category label="Projekte" term="Projekte"/>
        <category label="Johanna" term="Johanna"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Einfach Online-Karten mit uMap erstellen]]></title>
        <id>https://geodaten-guerilla.net/blog/Online-Karten-uMap</id>
        <link href="https://geodaten-guerilla.net/blog/Online-Karten-uMap"/>
        <updated>2023-02-26T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Wie mensch einfach Online-Karten mit uMap erstellen und teilen kann]]></summary>
        <content type="html"><![CDATA[<p><a href="https://geodaten-guerilla.net/blog/Geodaten-Karten-Werkzeug">Geodaten und Karten können ein mächtiges Werkzeug im Kampf für eine bessere Welt sein</a>. Allerdings benötigen professionelle Geographische Informationssysteme (GIS), wie <a href="https://qgis.org/" target="_blank" rel="noopener noreferrer">QGIS</a> oder <a href="https://www.esri.com/de-de/arcgis/products/arcgis-pro/overview" target="_blank" rel="noopener noreferrer">ArcGIS</a>, auch bedeutenden Aufwand, ihre Nutzung und die verwendeten Dateiformate zu erlernen und zu verstehen. Durch viele, im Internet zu findende kostenlose Tutorials und Dokumentationen, ist ein Einstieg aber machbar. Es besteht aber das Problem, dass es für die Breitstellung erstellter Karten weitere Infrastruktur, Software und Kenntnisse benötigt. Insbesondere, wenn es sich bei diesen Karten um (interaktive) Web-Karten handeln soll. Mit <a href="https://wiki.openstreetmap.org/wiki/DE:UMap" target="_blank" rel="noopener noreferrer">uMap</a> existiert ein einfaches Tool, um Online-Karten mit <a href="https://wiki.openstreetmap.org/wiki/DE:UMap" target="_blank" rel="noopener noreferrer">OpenStreetMap-Hintergründen</a> zu erstellen und in eine Webseite zu integrieren (alternativ lässt sich auch ein Link zur Karte teilen). Außerdem handelt es sich bei <strong>uMap</strong> um freie und open-source Software.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="umap">uMap<a href="https://geodaten-guerilla.net/blog/Online-Karten-uMap#umap" class="hash-link" aria-label="Direkter Link zur uMap" title="Direkter Link zur uMap">​</a></h2>
<p>Laut <a href="https://wiki.openstreetmap.org/wiki/DE:UMap" target="_blank" rel="noopener noreferrer">OpenStreetMap-Wiki</a> erlaubt es <strong>uMap</strong>, Karten in einer Minute zu erstellen. Dafür stehen mehrere Instanzen zur Auswahl, die die erstellten Karten auch dauerhaft auf der gewählten Instanz speichern. Dadurch entfällt bereits die Notwendigkeit, eigene Infrastruktur für das Hosting von Karten zu unterhalten. Mittels iframe kann mensch die Karte einfach in die eigene Webseite einbinden. Es benötigt aber nicht einmal eine eigene Webseite, denn nach dem Speichern einer Karte lässt sich auch ein Link zur Karte teilen. Für die Arbeit mit <strong>uMap</strong> empfiehlt sich ein <a href="https://www.openstreetmap.org/login" target="_blank" rel="noopener noreferrer">OpenStreetMap-Account</a>, damit mensch Karten speichern und später weiter bearbeiten kann. Gleichzeitig ermöglicht ein OpenStreetMap-Account auch das Bearbeiten von OpenStreetMap, womit sich gesammelte Daten der Community zur Weiterverwendung zur Verfügung stellen lassen. Bearbeitungen von OpenStreetMap fließen damit auch direkt in die Basiskarten ein, die in <strong>uMap</strong> als Hintergrund zur Verfügung stehen. Der Prozess der Kartenerstellung geht einfach von der Hand: Hintergrundkarte auswählen und dann auf dieser Punkte, Linien und Flächen einzeichnen. Diese lassen sich dann mit Informationen ausstatten, stylisieren und verschiedenen Kartenebenen zuordnen. Eine Anleitung zur Nutzung von <strong>uMap</strong> findet sich im <a href="https://wiki.openstreetmap.org/wiki/DE:UMap/Anleitung" target="_blank" rel="noopener noreferrer">OpenStreetMap-Wiki</a>. <strong>uMap</strong> überzeugt damit als einfacher Einstieg, um einfache Karten zu erstellen und zu teilen, ohne große Expertise oder Infrastruktur zu benötigen.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="umap-im-zusammenspiel-mit-qgis">uMap im Zusammenspiel mit QGIS<a href="https://geodaten-guerilla.net/blog/Online-Karten-uMap#umap-im-zusammenspiel-mit-qgis" class="hash-link" aria-label="Direkter Link zur uMap im Zusammenspiel mit QGIS" title="Direkter Link zur uMap im Zusammenspiel mit QGIS">​</a></h2>
<p><strong>uMap</strong> stößt dann an seine Grenzen, sobald mensch "mehr" machen möchte, als Marker auf einer Karte zu verteilen. Für räumliche Berechnungen, Georeferenzierung von Karten und Plänen oder Analysen von Geodaten braucht es ein Geographisches Informationssystem (GIS). Das am meisten verbreitete open-source GIS ist wohl <a href="https://qgis.org/" target="_blank" rel="noopener noreferrer">QGIS</a>. Um den Umgang mit <strong>QGIS</strong> zu lernen, ist der beste Ausgangspunkt dessen <a href="https://docs.qgis.org/3.22/de/docs/user_manual/" target="_blank" rel="noopener noreferrer">Dokumentation</a>. Zusätzlich stellen viele weitere Webseiten und YouTube-Kanäle Tutorials bereit und <a href="https://gis.stackexchange.com/" target="_blank" rel="noopener noreferrer">StackExchange</a> hat einen eigenen Bereich für Fragen rund um GIS. Mit <strong>uMap</strong> lassen sich dann die Geodaten, die mensch in <strong>QGIS</strong> erstellt hat, auf einer Web-Karte darstellen. Denn <strong>uMap</strong> bietet den Import von GIS-lesbaren Daten an. Diese müssen dafür in bestimmten Vektor-Dateiformaten (u.a. geojson, gpx) vorliegen. Außerdem bietet <strong>uMap</strong> nur eingeschränkte Möglichkeiten, die importierten Daten zu stylisieren. Dennoch ermöglicht <strong>uMap</strong> damit einen einfachen Einstieg, in <strong>QGIS</strong> erstellte Daten als Web-Karte darzustellen, ohne eine eigene Infrastruktur aufzubauen. Für komplexere Onlinekartenprojekte benötigt es aber dennoch eine komplexere Infrastruktur aus WMS/WMTS/WFS und WebGIS.</p>]]></content>
        <author>
            <name>Johanna I. Klitzschmüller</name>
            <email>altesholz@riseup.net</email>
            <uri>https://tech.lgbt/@fedora</uri>
        </author>
        <category label="Geodaten" term="Geodaten"/>
        <category label="Karten" term="Karten"/>
        <category label="uMap" term="uMap"/>
        <category label="OpenStreetMap" term="OpenStreetMap"/>
        <category label="interaktiv" term="interaktiv"/>
        <category label="Online-Karten" term="Online-Karten"/>
        <category label="online" term="online"/>
        <category label="Johanna" term="Johanna"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Geodaten und Karten im Kampf für das gute Leben für alle]]></title>
        <id>https://geodaten-guerilla.net/blog/Geodaten-Karten-Werkzeug</id>
        <link href="https://geodaten-guerilla.net/blog/Geodaten-Karten-Werkzeug"/>
        <updated>2023-02-11T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Der Text zeigt die Grundlagen, wie Geodaten und Karten ein Werkzeug für den Kampf für eine bessere Welt sein können.]]></summary>
        <content type="html"><![CDATA[<p>Wir leben in einer Zeit, in der viele Krisen zusammen auftreten und miteinander verbunden sind. Klimakatastrophe und der Verlust der Biodiversität bedrohen unsere Lebensgrundlagen, riesige Vermögensungleichheiten, sowohl zwischen dem globalen Norden und dem globalen Süden als auch in den jeweiligen Gesellschaften sorgen mit für soziale Krisen, Rassismus und Nationalismus bedrohen unser Zusammenleben und Errungenschaften im Kampf für Gleichberechtigung und gegen Rassismus. Doch viele Menschen kämpfen für den Traum einer solidarischen Welt, für Klimagerechtigkeit, für soziale Gerechtigkeit, für Gleichberechtigung und gegen Rassismus und Faschismus. Diese Kämpfe haben eine große Aktions- und Methodenvielfalt hervorgebracht. Die Kämpfe finden auf den Straßen, in Parlamenten, mit Demonstrationen, Streiks, direkten Aktionen, Sabotage, zivilen Ungehorsam u.v.m. statt. Wie passt eine <strong>GeoDatenGuerilla</strong> in diese Kämpfe? Geodaten und Karten können ein Werkzeug für den Kampf um eine bessere Welt sein. Das Ziel der <strong>GeoDatenGuerilla</strong> ist es, dieses Werkzeug zu nutzen und den kämpfenden Bewegungen zur Verfügung zu stellen: Mit der Erstellung von Karten (<a href="https://geodaten-guerilla.net/karten/" target="_blank" rel="noopener noreferrer">interaktive Online-Karten</a> und zum <a href="https://geodaten-guerilla.net/downloads/" target="_blank" rel="noopener noreferrer">Download</a>), Skillshares und der zur Verfügungstellung von Infrastruktur. Doch wie können uns Geodaten und Karten im Kampf für eine bessere Welt unterstützen? Dieser Text, gestützt auf sozialwissenschaftlichen Forschungen zur "kritischen Kartographie" und "Critical GIS", soll erste Antworten und Grundlagen liefern.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="karten-sind-neutral">Karten sind neutral!<a href="https://geodaten-guerilla.net/blog/Geodaten-Karten-Werkzeug#karten-sind-neutral" class="hash-link" aria-label="Direkter Link zur Karten sind neutral!" title="Direkter Link zur Karten sind neutral!">​</a></h2>
<p>„Eine Karte ist ein verkleinertes, vereinfachtes und verebnetes Abbild der Erdoberfläche, ggf. einschließlich mit ihr in Verbindung stehender Sachverhalte, und die Kartographie ist das Fachgebiet, welches sich mit der Herstellung derartiger Abbilder befasst“ (Kohlstock 2014, S. 17).</p>
<p>Dies ist ein Satz, wie er wohl in vielen Kartographie-Lehrbüchern zu finden ist. Dahinter steckt die Vorstellung, dass Karten die Wirklichkeit abbilden und so werden Karten bis heute realistisch modelliert (Glasze 2009, S. 182). Und wie kann es anders sein? Durch Google Maps, die Weltkarte der Abendnachrichten, der Schulatlas oder der sympathische Reiseführer, wir sind in der heutigen Zeit umgeben von Karten. Karten, von denen wir glauben, dass diese die Realität wiederspiegeln. Karten, welche uns glauben lassen, dass diese das reine Ergebnis einer Vermessung und Visualisierung der Welt sind, frei von politischen, kulturellen oder sozialen Einflüssen. Das obenstehende Zitat verdeutlicht dies und steht stellvertretend für diese Selbstverständlichkeit, wie sie in vielen Kartographie-Lehrbüchern zu finden ist und wie sie wohl viele Menschen wahrnehmen.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="geodaten-und-geographische-informationen">Geodaten und geographische Informationen<a href="https://geodaten-guerilla.net/blog/Geodaten-Karten-Werkzeug#geodaten-und-geographische-informationen" class="hash-link" aria-label="Direkter Link zur Geodaten und geographische Informationen" title="Direkter Link zur Geodaten und geographische Informationen">​</a></h2>
<p>Karten sind das sichtbare Ergebnis eines Prozesses, das u.a. aus Kartieren, Sammeln von Daten und deren Verknüpfung mit bekanntem Wissen besteht. Karten sind am Ende dieses Prozesses die gängige Methode, die räumlichen/geographischen Informationen und (Geo-)Daten darzustellen. Die wichtigste Eigenschaft von geographischen Informationen ist ihr Raumbezug, also die Möglichkeit, diese einem Ort in der Realität zuzuordnen, bspw. über eine Karte. Informationen entstehen durch die Verknüpfung von Daten mit abgeleitetem oder bekanntem Wissen. Geodaten sind Merkmalswerte, die sich auf einen Raum beziehen und diesen repräsentieren können (z.B. Flächengröße einer Waldparzelle) (Kappas 2012, S. 8 ff). Bereits das Sammeln von Daten und das Gewinnen von Informationen aus ihnen ist ein sozialer Prozess, mit dem sich Wandel anstoßen und Gegenmacht aufbauen lässt (vgl. Pavlovskaya 2018 und Elwood 2022). Geodaten haben in den letzten Jahrzehnten eine Schlüsselstellung in der Entwicklung der Informations- und Wissensgesellschaften auf der Welt errungen. Viele Anwendungen, die auf Geodaten aufbauen, bspw. in der Umweltüberwachung, der Nutzung natürlicher Ressourcen, der Verkehrsplanung, der Raumplanung und amtliche Statistiken, besitzen eine große gesellschaftliche und politische Relevanz (Kappas 2012, S. 8 ff). Kommerzielle Anwendungen, die auf Geodaten aufbauen, wie Google oder Apple Maps, sind mittlerweile selbstverständliche Teile unseres Lebens geworden. Damit sind Geodaten auch wichtige Bestandteile datengetriebener Geschäftsmodelle geworden (Glasze 2014, S. 125 f). Geodaten werden aber auch für rassistische Praktiken, staatliche und private Repressionen und Überwachung genutzt (Elwood 2022, S. 436). Es zeigt sich also, dass das Sammeln und der Besitz von Geodaten Akteur*innen Macht verleiht, was aber auch im Gegenzug bedeutet, dass sich damit auch Gegenmacht aufbauen lässt.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="karten-sind-nicht-neutral">Karten sind nicht neutral!<a href="https://geodaten-guerilla.net/blog/Geodaten-Karten-Werkzeug#karten-sind-nicht-neutral" class="hash-link" aria-label="Direkter Link zur Karten sind nicht neutral!" title="Direkter Link zur Karten sind nicht neutral!">​</a></h2>
<p>Karten sind nicht neutral! Karten spiegeln gesellschaftliche Machtstrukturen wieder, werden von bestimmenten (Macht-)Interessen geprägt, und reproduzieren diese. Die sozialen Strukturen der Entstehungszeit der Karte finden sich in der Karte und im Prozess der Kartenschaffung wieder und stellen damit (soziale) Wirklichkeiten her (Glasze 2014, S. 123 f). Dies zeigt sich an einem einfachen Beispiel. Viele Menschen haben als Bild von der Welt die "klassische" Weltkarte in der Mercator-Projektion im Kopf, die in wohl fast jedem Klassenzimmer hängt. Die Mercator-Projektion ist eine winkeltreue Projektion, die Flächen verzerrt. So werden Flächen, je weiter sie sich im Norden oder Süden der Karte befinden, immer größer. Gemäß dem Prinzip der Ethnozentrizität stellen die Erschaffenden der Karte sich selbst ins Zentrum. Das führte dazu, dass diese Weltkarten genordet werden und die größer wirkenden Flächen von Nordamerika und Europa in die Mitte der Karte gelegt werden. Dazu kommt, dass die moderne, digitalgestützte Kartographie und Geodatenverarbeitung in ihren Anfängen fest in der Hand von Staaten und Unternehmen waren und enormes, auf Nordamerika und Europa konzentriertes Fachwissen benötigten. Wir sind also geprägt von einem im Zentrum stehenden Europa und Nordamerika, die auch noch größer wirken als sie eigentlich sind (Glasze 2009, S. 183; Glasze 2014, S. 124; Pavlovskaya 2018, S. 42). Dazu kommt, dass Karten, ähnlich wie Bildern, eine hohe Evidenz zugesprochen wird, "denn sie zeigen, was ist" (Glasze2009, S. 184 f). Es wird also folgendes deutlich: Karten sind keine neutralen Wissenserklärungen, sie produzieren (soziale) Weltbilder. Diese Eigenschaften lassen sich im Gegenzug aber auch nutzen, um Gegenmacht aufzubauen (Pavlovskaya 2018, S. 52).</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="mit-geodaten-und-karten-kämpfen-lernen">Mit Geodaten und Karten kämpfen lernen<a href="https://geodaten-guerilla.net/blog/Geodaten-Karten-Werkzeug#mit-geodaten-und-karten-k%C3%A4mpfen-lernen" class="hash-link" aria-label="Direkter Link zur Mit Geodaten und Karten kämpfen lernen" title="Direkter Link zur Mit Geodaten und Karten kämpfen lernen">​</a></h2>
<p>Wir sehen also, die Nutzung von Geodaten und Karten hat Potenzial, Teil von Kämpfen für eine bessere Welt zu sein. Wenn wir progressive geographische Vorstellungen mit konkret greifbaren Karten verschmelzen, können sie Werkzeuge einer sozialen Transformation sein (Pavlovskaya 2018, S. 41). Das Potenzial ist auch deswegen sehr groß, weil sich die für Geodatenverarbeitung und Kartographie notwendigen Technologien stark verbreitet und dezentralisiert haben und mit Social-Media verbunden werden können. Es gibt mittlerweile unzählige Tools, mit denen sich im Internet interaktive Karten bereitstellen lassen, was dank open-source auch kostengünstig möglich ist. Auf diese Weise lassen sich Communities um Mapping-Projekte aufbauen (Pavlovskaya 2018, S. 42f). Auf der ganzen Welt gibt es Aktivist*innen, die mit Hilfe von Geodaten und Karten auf kreative Art und Weise Politik machen. Ob im Kampf gegen Gentrifizierung in Städten, für die Rechte von Indigenen, für mehr Mitbestimmung in Planungsprozessen, gegen rassistische Polizeiarbeit u.v.m. (vgl. Elwood 2022 und Pavlovskaya 2018).</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="geographinnen-aller-länder-vereinigt-euch">Geograph*innen aller Länder vereinigt euch<a href="https://geodaten-guerilla.net/blog/Geodaten-Karten-Werkzeug#geographinnen-aller-l%C3%A4nder-vereinigt-euch" class="hash-link" aria-label="Direkter Link zur Geograph*innen aller Länder vereinigt euch" title="Direkter Link zur Geograph*innen aller Länder vereinigt euch">​</a></h2>
<p>Wir sehen also, Geodaten und Karten haben das Potenzial, ein Werkzeug für den Kampf um eine bessere Welt zu sein. Dazu kommt, dass der Zugang zu Werkzeugen für Geodatenverarbeitung und Kartographie so einfach ist, wie nie zuvor, und Projekte wie OpenStreetMap und der (erkämpfte) Trend zu OpenData sorgen für eine Demokratisierung von Geodaten und Karten.
Aus dem bisherigen Text und Überlegungen beim Verfassen gehen erstmal drei Ansatzpunkte hervor, was getan werden kann. Diese sind natürlich nicht abschließend und es gibt sehr viel mehr Möglichkeiten und Ansätze.</p>
<ul>
<li>Das Sammeln von (Geo-)Daten, sowohl von welchen, die frei verfügbar sind, bspw. OpenData-Datensätze oder Planunterlagen von (Bau-)Projekten, als auch selbst gesammelte (Geo-)Daten aus bspw. Kartierungen. Mit diesem Prozess lassen sich auch Machtstrukturen aufbrechen und die Hoheit über (Geo-)Daten erlangen, indem Daten gesammelt und zusammengetragen werden, die sonst nicht von offiziellen Stellen oder Privatunternehmen gesammelt werden. Die (Geo-)Daten lassen sich durch offene Lizenzen und Projekte wie OpenStreetMap auch anderen Kämpfen zur Verfügung stellen und in Diskurse eingebracht werden.</li>
<li>In den Karten als die konventionelle Darstellung von Geodaten lassen sich die Sachverhalte in den Fokus stellen, die die Menschen in den politische Kämpfe wichtig finden. Dies kann damit auch ein Werkzeug sein, von Diskriminierung und Stigmatisierung betroffenen Menschen und Gruppen (bspw. in sogenannten "Sozialen Brennpunkten" oder Indigene) die Hoheit über die eigene Darstellung zu geben.</li>
<li>Mit der Verbreitung von (Geo-)Daten und Karten über verschiedene Kanäle werden diese zugänglich für viele verschiedene Menschen. Mit interaktiven Karten können diese einbezogen werden. Das kann hilfreich in der Agitation oder in der Sichtbarmachung und Mobilisierung von Problemstellungen sein. Selbst das Aufmerksammachen von bereits vorhanden (Geo-)Daten oder die Befreiung von Informationen durch IFG-Anfragen, bspw. über <a href="https://fragdenstaat.de/" target="_blank" rel="noopener noreferrer">FragDenStaat</a>, ist eine wichtige Aktionsform.</li>
</ul>
<p>Darum liebe Geograph*innen, Geoinformatiker*innen, Kartograph*innen und alle anderen, die sich mit Karten, GIS und Geodatendatenverarbeitung auskennen: Bringt Eure Fachkenntnisse ein, empowered Menschen, Karten zu nutzen und gebt Euer Wissen weiter. Und alle Menschen, die sich für Karten interessieren oder fasziniert von ihnen sind: Setzt Eure Ideen um. Es ist so einfach wie nie zuvor. <a href="https://geodaten-guerilla.net/mitmachen-kontakt">Schließt Euch der GeoDatenGuerilla an</a>.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="literatur">Literatur<a href="https://geodaten-guerilla.net/blog/Geodaten-Karten-Werkzeug#literatur" class="hash-link" aria-label="Direkter Link zur Literatur" title="Direkter Link zur Literatur">​</a></h2>
<p>Elwood, S. (2022): Toward a Fourth Generation Critical GIS: Extraordinary Politics. In: ACME: An International Journal for Critical Geographies 21 (4), S. 436-447.<br>
<!-- -->Glasze, G. (2009): Kritische Kartographie. In: Geographische Zeitschrift 97 (4), S. 181-191.<br>
<!-- -->Glasze, G. (2014): Sozialwissenschaftliche Kartographie-, GIS- und Geoweb-Forschung. In: KN - Journal of Cartography and Geographic Information 64 (3), S. 123-129.<br>
<!-- -->Kappas, M. (2012): Geographische Informationssysteme. 2. Auflage. Braunschweig.<br>
<!-- -->Kohlstock, P. (2014): Kartographie: Eine Einführung. 3. Auflage. Paderborn.<br>
<!-- -->Pavlovskaya, M. (2018): Critical GIS as a tool for social transformation. In: The Canadian Geographer / Le Géographe canadien 62 (1), S. 40-54.</p>]]></content>
        <author>
            <name>Johanna I. Klitzschmüller</name>
            <email>altesholz@riseup.net</email>
            <uri>https://tech.lgbt/@fedora</uri>
        </author>
        <category label="Geodaten" term="Geodaten"/>
        <category label="Karten" term="Karten"/>
        <category label="Kampf" term="Kampf"/>
        <category label="kritisch" term="kritisch"/>
        <category label="GIS" term="GIS"/>
        <category label="Forschung" term="Forschung"/>
        <category label="Kartographie" term="Kartographie"/>
        <category label="Johanna" term="Johanna"/>
    </entry>
</feed>