Ergebnis 1 bis 8 von 8

Thema: Schritt für Schritt: OpenStreetMap Karte ohne Erweiterung

  1. #1
    Alter Contao-Hase Avatar von Franko
    Registriert seit
    22.06.2009.
    Beiträge
    1.091
    Partner-ID
    6122

    Standard Schritt für Schritt: OpenStreetMap Karte ohne Erweiterung

    Es exisitieren zahlreiche Erweiterungen zum Thema für Contao [1,2,3,4].
    Diese bieten einfache Integration und umfangreiche Funktionen zur Kartendarstellung.

    In den meisten Fällen benötigt man wahrscheinlich lediglich eine einfache Karte mit einem Marker.
    Dies könnte man auch mit Contao Bordmitteln ohne Erweiterung realisieren - Daher ...

    Zur Umsetzung helfen aktuelle JS-Frameworks wie z.B.: Leaflet o. OpenLayers.
    Die Frameworks selbst stellen kein Kartenmaterial zur Verfügung. Dazu werden Kartenanbieter wie Google-Maps, OpenStreetMap, mapbox usw. herangezogen.
    Manche sind kostenfrei, manche nicht. Einige bieten eine eigene API und/oder erfordern Anmeldung sowie API-Keys zur Nutzung.

    Die folgenden Beispiele nutzen das Leaflet-Framework zusammen mit OpenStreetMap (deutsche Karte).
    Die Leaflet Tutorials [5] bieten einen übersichtlichen Einstieg.

    Das Framework ist gut dokumentiert [6] und im Netz finden sich zahlreiche weitere Hilfenstellungen.
    Getestet habe ich lokal noch mit Contao 4.8.x - sollte aber auch mit der 4.9.x funktionieren.



    [1] con4gis/maps
    [2] netzmacht/contao-leaflet-maps
    [3] chrmue/cm_membermaps
    [4] delahaye/dlh_googlemaps

    [5] Leaflet Tutorials
    [6] Leaflet Dokumentation
    Geändert von Franko (02.04.2020 um 09:47 Uhr)
    Carpe diem ...

  2. #2
    Alter Contao-Hase Avatar von Franko
    Registriert seit
    22.06.2009.
    Beiträge
    1.091
    Partner-ID
    6122

    Standard OpenStreetMap Karte mit Marker und eigenem Icon

    Zur Umsetzung in Contao nutzen wir:

    • jQuery: Muss im Seitenlayout aktiviert werden
    • Contao Inhaltselement vom Typ "HTML"
    • Eigenes Template für das obige Inhaltselement


    Zunächst laden wir die aktuelle Leaflet Version (z.Zeit v1.6.0)
    herunter und speichern diese in einem bel. Verzeichnis unterhalb von Contao "files" ab.
    Benötigt werden hier die Dateien "leaflet.css" und "leaflet.js".

    Vorgehensweise:

    • Erstellt ein neues Template basierend auf "ce_html.html5" und benennt es z.B. "ce_html_map.html5".
    • Erstellt ein neues Inhaltselement vom Typ "HTML" und wählt hier obiges Template "ce_html_map.html5" aus.


    Im Inhaltselement selbst trägt man folgendes ein:

    HTML-Code:
    <div id="MYMAP" class="block" style="height:80vh"></div>
    Hinweis:
    Die CSS-Angabe "height" (in px o. vh) ist zwingend erforderlich!
    Zur Demo hier inline eingetragen. Kann aber auch über ein externes CSS-Stylesheet gesetzt werden.
    Die CSS-ID "MYMAP" ist beliebig muss aber im folgenden Template entsprechend lauten.

    Im Template trägt man folgendes ein:

    Code:
    <link rel="stylesheet" href="/files/MeinPfadZurDatei/leaflet.css"/>
    <script src="/files/MeinPfadZurDatei/leaflet.js"></script>
    
    <?= $this->html ?>
    
    <script>
    function createMap(){
    	
    	// container CSS-ID
            const mapCssId = 'MYMAP';
    	
    	// coordinates
    	const latitude = 51.492789;
    	const longitude = 7.451879;
    	const latLng = L.latLng(latitude, longitude);
    
    	const zoomDefault = 15;
    	const zoomMin = 8;
    	const zoomMax = 18;
    
    	const myMarkerIconURL = '/files/MeinPfadZurDatei/marker-icon.png'; // marker icon path
    	const myMarkerHtmlInfo = '<b>Signal Iduna Park</b><br>Borussia Dortmund'; // marker popup info
    
    	// Custom Marker Icon
    	var myMarkerIcon = new L.icon({
    	  iconUrl: myMarkerIconURL,
    	  iconSize:     [25, 41], // size of the icon
    	  iconAnchor:   [12, 41], // point of the icon which will correspond to marker's location
    	  popupAnchor:  [0, -30]  // point from which the popup should open relative to the iconAnchor
    	});
    
           // create marker
           var myMarker = new L.marker(latLng, {icon: myMarkerIcon}).bindPopup(myMarkerHtmlInfo);
    
    	// add layer(s) to group
    	var myGroup = new L.featureGroup([myMarker]);
    
    	// map tiles provider - see for example https://leaflet-extras.github.io/leaflet-providers/preview/
    	var mapProvider =
    	new L.tileLayer('https://{s}.tile.openstreetmap.de/tiles/osmde/{z}/{x}/{y}.png', {
    	  attribution: '&copy;<a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
    	});
    
    	// initiate map
    	var map = new L.Map(mapCssId, {
    	  minZoom: zoomMin,
    	  maxZoom: zoomMax,
    	  scrollWheelZoom: false,
    	  fadeAnimation: false,
    	  layers: [mapProvider, myGroup]
    	});
    
            map.setView(latLng, zoomDefault); // show map and center to coordinates
    
            myMarker.openPopup(); // optional open Marker Popup 
    
    	// on resize ...
    	map.on("resize", function(e){ 
    	  map.setView(latLng, zoomDefault); // ... center back to marker
    	});
    }
    
    (function($){
      $(document).ready(function(){ 
        createMap();	  
      });
    })(jQuery);
    </script>

    Alle obigen Einträge a la MeinPfadZurDatei bitte mit den tatsächlichen Pfadangaben ersetzen!

    Die Kommentare helfen hoffentlich.
    Die Variablen dienen nur der Übersicht.
    Setzt man anstelle der Variablen die Werte und entfernt die Kommentare bleiben nur wenige Zeilen übrig.


    Einbindung der Leaflet Dateien:
    Im Beispiel wurden die Dateien "leaflet.css" und "leaflet.js" (Reihenfolge beachten!) direkt gesetzt.
    Man kann diese aber auch über die Contao Mittel a la
    $GLOBALS['TL_CSS'][] = '...' und $GLOBALS['TL_JAVASCRIPT'][] = '...' einfügen lassen.

    Marker Icon:
    Das Beispiel bezieht sich auf das Standard Leaflet Marker-Icon "marker-icon.png" (befindet sich im Leaflet Verzeichnis).
    Wenn man hier ein anderes, eigenes Icon nutzen möchte müssen die Angaben "iconSize", "iconAnchor" u. "popupAnchor" entsprechend angepasst werden.

    GEO-Koordinaten:
    Im Beispiel werden die GEO-Koordinaten für das BVB-Stadion in Dortmund gesetzt :-).
    Für "latitude" und "longitude" dann die passenden Werte der jeweiligen Adresse (s.u.) eintragen.

    Davon abgesehen kann man mit den Werten "zoomMin", "zoomMax" (normalerweise von 0 bis 20) und "zoomDefault" spielen.
    Ansonsten müssen zukünftig lediglich die Werte für "latitude" und "longitude" im Template geändert werden.

    Das Ergenbnis:
    Abhängig von der Containter "height" Angabe erhalten Sie eine Kartendarstellung mit der entsprechenden Zoom-Stufe ("zoomDefault").
    Neben den Copyright Infos erhalten Sie Zoom-Buttons zur Kontrolle des Zooms (begrentzt durch Angabe von "zoomMin" und "zoomMax").

    GEO-Koordinaten manuell ermitteln:
    Es gibt zahlreiche Möglichkeiten diese GEO-Daten anhand einer Adresse zu ermitteln. Am einfachsten:

    - Adresse mit Google-Maps suchen
    - Dann RechtsKlick auf den Ergebnis-Marker und Auswahl "Was ist hier"
    - Die entsprechenden Koordinaten werden dann angezeigt
    Geändert von Franko (02.04.2020 um 09:37 Uhr)
    Carpe diem ...

  3. #3
    Alter Contao-Hase Avatar von Franko
    Registriert seit
    22.06.2009.
    Beiträge
    1.091
    Partner-ID
    6122

    Standard Mehr als nur Marker

    Man kann mehr als nur einzelne Marker setzen. Auch Linien, Rechtecke oder Kreise könnten mit entsprechenden Koordinaten der Karte hinzugefügt werden.

    Im folgenden ein Beispiel für eine zusätzliche Kreis-Darstellung. Ausgehend von den obigen Koordinaten für das BVB-Stadion zeichen wir einen Kreis.
    Der Mittelpunkt des Kreises ist identisch mit den Marker Koordinaten.

    Ersetzt hierzu im Template den Eintrag:

    PHP-Code:
        // add layer(s) to group
        
    var myGroup = new L.featureGroup([myMarker]); 
    mit

    PHP-Code:
      // create a circle layer and add to Leaflet featureGroup
        
    var myCircle = new L.circle((latLng), {
            
    radius200
            
    weight1
            
    color'#000000'
            
    fillColor'#FFF333'
            
    opacity0.8
            
    fillOpacity0.5
        
    });

        
    // add layer(s) to group
        
    var myGroup = new L.featureGroup([myMarkermyCircle]); 
    Tipp:

    Probiert die Seite geojson.io.
    Der Dienst bietet, neben anderen Funktionen, u.a. auch hilfreiche Tools zum Zeichnen an.
    Geändert von Franko (02.04.2020 um 09:34 Uhr)
    Carpe diem ...

  4. #4
    Alter Contao-Hase Avatar von Franko
    Registriert seit
    22.06.2009.
    Beiträge
    1.091
    Partner-ID
    6122

    Standard Umsetzung mit einer GeoJSON Datei

    Mit den obigen Beispielen könnte man ein o. mehrere Layer (Marker etc.) setzen.
    Eine Alternative hierzu wäre die Nutzung einer GeoJSON Datei. Hierbei werden die Karten-Inhalte quasi ausgelagert.

    Folgendes Beispiel für das Template:

    Code:
    <link rel="stylesheet" href="/files/MeinPfadZurDatei/leaflet.css"/>
    <script src="/files/MeinPfadZurDatei/leaflet.js"></script>
    
    <?= $this->html ?>
    
    <script>
    function createMap(){
    	
    	// container CSS-ID
           const mapCssId = 'MYMAP';
    	
    	var fileGeoData = '/files/MeinPfadZurDatei/mymapdata.geojson';
    
    	const zoomDefault = 15;
    	const zoomMin = 8;
    	const zoomMax = 18;
    
    	const myMarkerIconURL = '/files/MeinPfadZurDatei/marker-icon.png'; // marker icon path
    	const myMarkerHtmlInfo = '<b>Signal Iduna Park</b><br>Borussia Dortmund'; // marker popup info
    
    	// Custom Marker Icon
    	var myMarkerIcon = new L.icon({
    	  iconUrl: myMarkerIconURL,
    	  iconSize:     [25, 41], // size of the icon
    	  iconAnchor:   [12, 41], // point of the icon which will correspond to marker's location
    	  popupAnchor:  [0, -30]  // point from which the popup should open relative to the iconAnchor
    	});
    
    	// map tiles provider - see for example https://leaflet-extras.github.io/leaflet-providers/preview/
    	var mapProvider =
    	new L.tileLayer('https://{s}.tile.openstreetmap.de/tiles/osmde/{z}/{x}/{y}.png', {
    	  attribution: '&copy;<a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
    	});
    
    	// initiate map
    	var map = new L.Map(mapCssId, {
    	  minZoom: zoomMin,
    	  maxZoom: zoomMax,
    	  scrollWheelZoom: false,
    	  fadeAnimation: false,
    	  layers: [mapProvider]
    	});
    
    	// create feature content
    	function getEachFeature(feature, layer){
    	  var popupContent = "";
    	  
    	  if (feature.properties && feature.properties.name && feature.properties.info) {
    	    popupContent += "<b>" + feature.properties.name + "</b><br>" +
    	    feature.properties.info;
    	  }
     
    	  layer.bindPopup(popupContent);
    	};
    
    	// read .geojson file and fetch all feature properties
           $.getJSON(fileGeoData, function(data){
    
           locations = L.geoJson(data, {
            // fetch all features
            onEachFeature: getEachFeature, pointToLayer: function(feature, latlng){
              return L.marker(latlng, {icon: myMarkerIcon}); // create marker
    	    }
          });
    
          map.fitBounds(locations.getBounds(), {padding: [50,50]}); // fit map with optional padding (takes into account the map maxZoom value)
          locations.addTo(map);
          
          function openMarkerPopup(id){
            locations.eachLayer(function(feature){
              if(feature.feature.properties.id==id){
                feature.openPopup();
              }
            });
          }
          
          // optional open a specific marker popup from feature ID property
          openMarkerPopup(10);
         });
    	
        // on resize ...
        map.on("resize", function(e){ 
         map.fitBounds(locations.getBounds(), {padding: [50,50]}); // with optional padding
       });
    }
    
    (function($){
      $(document).ready(function(){
        createMap();	  
      });
    })(jQuery);
    </script>
    Ersetzt auch hier wieder zunächst alle MeinPfadZurDatei Einträge mit den tatsächlichen Pfadangaben!
    Scheint etwas komplizierter - Aber lediglich die Variable "fileGeoData" (s.u.) ist hier relevant.

    Über jquery lesen wir die json Datei ein ($.getJSON ...) und in der Funktion (getEachFeature()) werden die eigentlichen Karten features verarbeitet.
    Weiteres zur eigentlichen json Datei s.u..
    Geändert von Franko (02.04.2020 um 09:38 Uhr)
    Carpe diem ...

  5. #5
    Alter Contao-Hase Avatar von Franko
    Registriert seit
    22.06.2009.
    Beiträge
    1.091
    Partner-ID
    6122

    Standard Die GeoJSON Datei

    Im obigen Template muss für die Variable "fileGeoData" der Pfad auf die Datei "mymapdata.geojson" gesetzt werden.

    Der eigentliche Dateiname im Beispiel lautet demnach "mymapdata.geojson".
    Erstellt also eine Datei "mymapdata.geojson" und speichert diese im Contao "files" Verzeichnis ab.

    Die Datei "mymapdata.geojson":

    Code:
    {
      "type": "FeatureCollection",
      "features": [
        {
          "type": "Feature",
          "properties": {
            "id": 10,
            "name": "Signal Iduna Park",
            "info": "Borussia Dortmund"
          },
          "geometry": {
            "type": "Point",
            "coordinates": [
              7.451879,
              51.492789
            ]
          }
        }
      ]
    }
    Das Beispiel orientiert sich wieder an den bisherigen BVB-Stadion Settings.
    Unter "coordinates" setzen wir die GEO-Koordinaten.

    Die "Feature-Properties" sind frei wählbar:
    Im Beispiel "id", "name" und "info". Diese werden in der Funktion "getEachFeature()" des Templates genutzt:
    Ändernt man hier die Einträge in der json Datei müssen diese auch in der Funktion geändert/berücksichtigt werden!

    Als Ergebnis erhalten wir analog zum ersten Beispiel die Kartendarstellung mit einem Marker.


    Benefit:
    Der Vorteil hierbei ist: Man muss das Template selbst nicht mehr ändern.
    Lediglich den Inhalt der GeoJSON Datei ...

    Eine alternative GeoJSON Datei:

    Code:
    {
      "type": "FeatureCollection",
      "features": [
        {
          "type": "Feature",
          "properties": {
            "id": 10,
            "name": "Signal Iduna Park",
            "info": "Borussia Dortmund"
          },
          "geometry": {
            "type": "Point",
            "coordinates": [
              7.451879,
              51.492789
            ]
          }
        },
        {
          "type": "Feature",
          "properties": {
            "id": 20,
            "name": "Stadion",
            "info": "Rote Erde"
          },
          "geometry": {
            "type": "Point",
            "coordinates": [
              7.454207,
              51.493477
            ]
          }
        },
        {
          "type": "Feature",
          "properties": {
            "id": 30,
            "name": "Reitanlage",
            "info": "Dortmunder Reitverein e.V."
          },
          "geometry": {
            "type": "Point",
            "coordinates": [
              7.449840,
              51.495247
            ]
          }
        },
        {
          "type": "Feature",
          "properties": {
            "id": 40,
            "name": "Messehalle",
            "info": "Halle 3"
          },
          "geometry": {
            "type": "Point",
            "coordinates": [
              7.454164,
              51.495795
            ]
          }
        },
        {
          "type": "Feature",
          "properties": {
            "id": 50,
            "name": "Westfalenhalle",
            "info": "Halle 1"
          },
          "geometry": {
            "type": "Point",
            "coordinates": [
              7.456859,
              51.496589
            ]
          }
        }    
      ]
    }
    Ergebnis: Eine Karte mit 5 Markern ohne Template Änderungen.


    Formatierung der GeoJSON Datei

    Ich weiss nicht ob die GeoJSON-Beispiele nach dem Kopieren über das Forum korrekt funktionieren.
    Letztlich sollte man bei der Formatierung wie bei allen json Daten keine Tabs sondern Leerzeichen etc. berücksichtigen.

    Am besten checkt man die Formatierung über geojson.io!
    Ist die Anzeige hier OK - dann einfach als Datei speichern ...
    Carpe diem ...

  6. #6
    Alter Contao-Hase Avatar von Franko
    Registriert seit
    22.06.2009.
    Beiträge
    1.091
    Partner-ID
    6122

    Standard Nützliche Leaflet PlugIns

    Das beliebte Leaflet-Framework kann man mit PlugIn's erweitern.
    Eine kleine Übersicht findet sich hier: https://leafletjs.com/plugins.html

    Beispiele:

    https://github.com/Leaflet/Leaflet.fullscreen
    Erweitert die Karten Controls mit einem FullScreen-Button/Ansicht.

    https://github.com/Zverik/leaflet-grayscale
    Manche Kartenanbieter verfügen über SW/Graustufen Tiles.
    Mit diesem PlugIn kann man bel. Karten in Graustufen anzeigen lassen.

    https://github.com/Leaflet/Leaflet.markercluster
    Wenn man wirklich viele Marker nutzt werden hierüber, abhängig vom Zoom-Level,
    mehrere Marker übersichtlich zusammengefasst und dargestellt.

    3D-Ansichten:
    Auch hierzu gibt es zahlreiche Möglichkeiten. Eine wäre https://osmbuildings.org/.
    Auch in Kombination mit Leaflet: https://osmbuildings.org/documentation/leaflet/
    Carpe diem ...

  7. #7
    Alter Contao-Hase Avatar von Franko
    Registriert seit
    22.06.2009.
    Beiträge
    1.091
    Partner-ID
    6122

    Standard Der Datenschutz

    Auch bei der Verwendung von OSM (o. anderen) Kartenmaterial sollte man dies in der Datenschutzerklärung aufnehmen.
    Die OSM-Policies sind hier erreichbar: https://wiki.osmfoundation.org/wiki/Privacy_Policy

    Alternativ könnte man die Karte auch erst nach einem Mausklick erstellen lassen und anzeigen.
    Denkbar wäre zuvor die Angabe von Text oder Images. Exemplarisch im Inhaltselement:

    HTML-Code:
    <style>#MYMAP.map_pre{cursor: pointer; background-color: #ccc; color: #000;} #MYMAP.map_pre:before{content: 'Klicken Sie hier zur Anzeige der Karte'}</style>
    <div id="MYMAP" class="block map_pre" style="height:80vh"></div>
    Und dann im Template (ganz unten):

    PHP-Code:
    (function($){
      $(
    document).ready(function(){

        
    // create map after click
        
    $('#MYMAP').click(function(e){
          $(
    '#MYMAP').removeClass('map_pre');
          
    e.preventDefault(); 
          
    createMap();      
         });
      });
    })(
    jQuery); 
    Die Leaflet Daten in dem einfachen Beispiel werden zwar dennoch geladen,
    die eigentliche Karte (mit dem Tile-Provider Requests) aber erst nach dem Mausclick erstellt - you get the idea.
    Geändert von Franko (02.04.2020 um 09:33 Uhr)
    Carpe diem ...

  8. #8
    Alter Contao-Hase Avatar von Franko
    Registriert seit
    22.06.2009.
    Beiträge
    1.091
    Partner-ID
    6122

    Standard Das GEO-Coding

    Die oben genannten Contao Erweiterungen nehmen einem das GEO-Coding ab.
    Für ein oder auch zwei, drei Marker oder einige Shapes (Kreis, Linien etc.) ist das manuelle Geo-Coding dennoch nicht aufwendig.

    Wenn man das lokal, unabhängig vom CMS, automatisieren möchte bzw. mal wirklich viele Koordinaten benötigt
    existieren hierzu zahlreiche Möglichkeiten (und auch Tutorials).

    Man könnte z.B. lokal ebenfalls in Kombination mit Leaflet
    ein eigenes Geo-Coding Frontend aufsetzen (z.B. https://github.com/perliedman/leaflet-control-geocoder).

    Auch für node.js existieren zahlreiche Tools - einfach mal suchen z.B.:

    https://github.com/nchaulet/node-geocoder
    https://github.com/bigmountainideas/google-geocoder
    https://github.com/googlemaps/google-maps-services-js

    Denkbar wäre dann das Einlesen einer Adress-Datei als .csv (z.B. via phpMyAdmin Abfrage über die tl_member),
    daraus dann die Koordinaten (ü. obige tools) ermitteln und als GeoJSON formatiert ausgeben (z.B mit node handlebars: https://github.com/wycats/handlebars.js).

    Da das ja dann nur lokal herangezogen wird ist die Wahl des Dienstleisters eigentlich egal.

    Allerdings sollte man bei Massen-Abfragen die API-Policies der Anbieter berücksichtigen - manche reagieren durchaus empfindlich.
    Die meisten bitten aber lediglich um ein Zeitfenster a la: Nur 1 Request pro Sekunde usw..
    Carpe diem ...

Aktive Benutzer

Aktive Benutzer

Aktive Benutzer in diesem Thema: 2 (Registrierte Benutzer: 0, Gäste: 2)

Lesezeichen

Lesezeichen

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •