Google Map API to Open Street Map

Ende der Google Map API

Am 2018.08.16 setzte Google für die Google Map API und andere Dienste ein recht undurchsichtiges Bezahlmodel ein. Obwohl ich mich als informiert bezeichnen würde, erführ ich davon nur durch das Ausgrauen meiner eingebetteten Karten. Darüber liegt ein Popup für alle einsehbar. Bei Street View ist es noch schlimmer, da wurden glatt die Farben invertiert. Die Methoden sind recht brutal, zumal ich über eine Google ID auch Werbung schalte und somit erreichbar sein sollte. Eine Vorab-Information wäre wohl nicht zu viel gewesen.

Google hat zwar versucht, sein neues Pay-Model zu erklären, aber es mangelt gewaltig an Klarheit:

  • nirgends ist ersichtlich, wie hoch sein eigener aktueller Zugriff auf diese Dienste ist. Theoretisch geht das mit der Fehlerkonsole, ich komme aber nur diese Meldung:
    You have exceeded your request quota for this API. See
    https://developers.google.com/maps/documentation/javascript/error-messages?utm_source=maps_js&utm_medium=degraded&utm_campaign=billing

    Speichert man den Log, so stehen  dort etwas mehr Zahlen, aber Schlau wird man daraus nicht:

    (anonymous) @ js?key=AIzaSyAtEa2HEuZiEIMzmC7EzpCB1oNKkPgxbuE:53
    (anonymous) @ js?key=AIzaSyAtEa2HEuZiEIMzmC7EzpCB1oNKkPgxbuE:126
    (anonymous) @ js?key=AIzaSyAtEa2HEuZiEIMzmC7EzpCB1oNKkPgxbuE:53
  • Versucht man anhand des “Pricings” schlau zu werden wird einerseits mit gross wirkenden Zugriffzahlen geködert, es wird aber kein Bezugszeitraum genannt (Tag, Monat, Jahr). Aber auch beim Angebot wird verschleiert: Was ist der unterschied zwischen “Emeded” und “Embeded Adavanced”?
  • Derzeit sind Zugriffe auf mobilen Geräten ausgenommen. Aber wie lange? Generell werden keine Angaben gemacht, wie, wo und wann weitere Preise angepasst werden. Das ist bei dem aktuellen Preissprung mehr als kommerziell relevant.
  • Nach einiger Zeit kommt man auf den relevanten einen Schlüsselwert: US$14 für 1000 Karten pro Monat. Mit einem so genannten “Gratis”-Guthaben von US$200/Monat wird man ab 28000 Karten tributpflichtig. Dieses Preisschema gilt für die so genannten “Embeded Adavanced Map”, das ist die Standard-API mit Street View (wobei Street View eigens mit dem selben Schema zu Buche schlägt).

Über dieses Ziel schiesse ich anscheinend, wenn auch knapp, hinaus. Ich kann es nicht genau erfassen, weil User auf einen Grossteil meiner Seiten Google Maps selber aufklappen können. Die 800 verzeichneten Märkte meiner Seiten kommen auf rund 70000 Zugriffe, allerdings pro Woche.

Alternativen zur Google Maps API

Mit diesen Werten gibt es nicht viele mögliche Alternativen:

  • Brauchbare Luftbilder sind anderswo auch nur kostenpflichtig erhältlich:
    • Bing Maps API kostet ab ca. 10000 Aufrufe pro Monat. Allerdings finde ich nirgends was es dann wirklich kostet. Kein flächiges Street View.
    • Mapbox ist gratis bis 50000 Aufrufe pro Monat, danach US$0.5/1000 Karten. Allerdings keine flächendeckenden Luftbilder.
    • Nationale Geodienste sind meist ebenso teuer, in meinem Fall in Frankreich EUR5500/10000000 Zugriffe/Jahr für Géoportail. Hier gibt gar keine kostenfreie Anfangsnutzung.
  • Kartendienste ohne Luftbilder:
    • Open Street Map (OSM) gibt es in vielen Varianten und ebenso vielen APIs dazu. Klingt gut, aber neben  dem Manko Luftbilder, sind die Tiles-Server ein Damokles-Schwert: es gibt eine Hand voll brauchbarer Server, welche Kacheln liefern, die sich mit einer API analog zu Google Maps einbinden lässt. Manche sind frei und bitten den Dienst nicht zu missbrauchen (darunter openstreetmap.org selber), manche haben Quotas, andere beschränken sich auf Zonen, Länder oder Regionen und dann gibt es wiederum spezielle thematische Darstellungen. Natürlich gibt es auch kommerzielle Dienste auf OSM-Basis.
    • Alle anderen Dienste sind entweder auf Städte beschränkt oder fokussieren mehr auf Routing als Darstellung.

Meine hohen Zugriffszahlen werden mir sicher früher oder später zum Problem, das heisst, ich werde mir selber einen Kachel-Server herrichten müssen, um allen Zugriffsgrenzen trotzen zu können.

Wechsel zu OSM mit der Leaflet API

Ich habe mir einige APIs angeschaut, vor allem wie sie mit KML- oder GPX-Overlays umgehen. Nur Leaflet mit Plugins by Pavel Shramov erfüllte schnell meine Wünsche. Beide können als lokale JavaScript-Lib gespeichert werden und müssen nicht extern verlinkt werden (obwohl das auch geht). Ein Vorteil der genannten Plugins ist, dass man je nach Anwendung nur einen gewissen Teil der Library laden muss (oft nur eine Datei).

Beispiel OSM mit KML-Overaly via Leaflet-Plugins

<style>
 #myMap{
   height:500px;
 }
</style>
<script src="/sys/OSMleaflet/leaflet.js"></script>
<script src="/sys/OSMleaflet/leaflet-plugins/layer/vector/KML.js"></script>
<script type="text/javascript">
function init(){
  var map = new L.Map('myMap');
  var osm = new L.TileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
    attribution: '<a href="http://www.provence-guide.net/">Provence-Guide.Net</a>'
  });
  var track = new L.KML("/geo/<?php echo $kmlpath ?>.kml", {async: true});
  track.on("loaded", function(e) {
    map.fitBounds(e.target.getBounds());
  });
  map.addLayer(track);
  map.addLayer(osm);
}
</script>
<body onload="init()">
  <div id="myMap"></div>
</body>

In schwarz der Script-Teil für das Einfügen einer Karte. Wird später nicht auf einen Inhalt zentriert, muss man auch das Zentrum und die Zoomstufe angeben:

var map = L.map('myMap', {center: [43.875403, 5.398600], zoom: 13});

Die OSM-Kacheln sind, wie später auch das Overlay, als Ebene (Layer) eingebunden. Die Syntax für die verschiedenen Server ist unterschiedlich, kostenpflichtige Dienste übergeben auch eine ID als Parameter. {s} ist verfügbar, wenn der Kachel-Server aus verschiedenen Hardware-Servern besteht. {z}, {x} und {y} sind selbsterklärend. An diesen Stellen  sind keine Werte einzusetzen! In der Browserkonsole kann man sehen, welche Kacheln so aufgerufen werden;

In grau ist eine Option dargestellt, hier wird der Urheberhinweis rechts unten erweitert.

In violett sind Teile der Plugins by Pavel Shramov. Hier wird eine fertige KML-Datei samt Track-Farben und eigenen Icons und Popups geladen und genau wie unter Google Earth  (oder zuvor der Google Maps API) dargestellt. Erst nach dem Laden der Daten wird die Karte auf diesen Inhalt zentriert und gezoomt.

In orange der Ausschnitt aus dem CSS-Bereich. Das <div>, wo die OSM-Karte erscheinen soll, muss eine definierte Höhe haben. Anderenfalls wird keine Karte angezeigt. Die Breite geht ohne weiteren Angaben auf die verfügbaren 100%.

In blau ein Ausschnitt aus dem HTML-Bereich. Ein <div>, wo die OSM-Karte erscheinen soll, muss vor dem Aufrufen der Initialisierung vorhanden sein. Die Initialisierung muss nicht onload erfolgen, es geht auch mittels User-Aktion onclick zum Beispiel. Man zeigt die Karte nur auf Verlangen und spart Traffic.

Beispiel mit einfachem Marker via Leaflet-Plugins

<style>
 #myMap{
   height:500px;
 }
</style>
<link rel="stylesheet" href="/sys/OSMleaflet/leaflet.css"/>
<script src="/sys/OSMleaflet/leaflet.js" crossorigin=""></script>
<script src="/sys/OSMleaflet/leaflet-plugins/layer/Marker.Text.js"></script>
<script type="text/javascript">
  function initMaps(){
    var map = new L.Map('myMap', {center: new L.LatLng(<?php echo $m['gmLink'][1].','.$m['gmLink'][2] ?>), zoom: 17});
    map.addLayer(new L.TileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png'), {
      attribution: '<a href="http://www.provence-guide.net/">Provence-Guide.Net</a>'
    });
    var marker = new L.Marker.Text(map.getCenter(), 'markerName');
    map.addLayer(marker);
}
</script>

Hier wird der Marker auf das zuvor gesetzte Kartenzentrum platziert. Wie man an den PHP-Arrays sieht, stammen die Daten teilweise noch auch Google Maps (gm…), es ist die Umstellung somit nicht schwierig.

Beispiel mit mehreren Markern nur mit Leaflet

<link rel="stylesheet" href="/sys/OSMleaflet/leaflet.css"/>
<script src="/sys/OSMleaflet/leaflet.js"></script>
<script>
  function initMap() {
    var randos = L.layerGroup();
    var bounds = new Array();
    var points = [$data4gmArray];
    for (var i = 0; i < points.length; i++) {
      var point = points[i];
      var myMarker = L.circleMarker([point[1],point[2]],{radius:7,weight:1,color:'#ff0000'}).bindTooltip(point[3]).bindPopup(point[0]).addTo(randos);
      myMarker.on('click', function(e){
        this.closeTooltip();
      });
      bounds.push(new Array(point[1],point[2]));
    }
    var osm = new L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
       attribution: '<a href="http://www.provence-guide.net/">Provence-Guide.Net</a>'
    });
    var map = L.map('mapDiv',{layers:[osm,randos]}).fitBounds(bounds);
  }
</script>

In den ersten zwei blauen Zeilen werden CSS und Javascript für die Leaflet-API eingefügt. Darunter folgt eine Funktion, welche die Karte und das interactive Overlay bereitstellt. Die Karte besteht aus OSM-Kacheln als Basis und einem Overlay aus Punkten, die mit Tooltips und Popup-Blasen versehen sind.
Orange ist das Overlay gekennzeichnet, es wird vor dem Breitstellen der Karte in einer Gruppe (randos) zusammengestellt und erst zusammen mit der Karte eingeblendet.
Violett sind die Bereiche, welche das Zentrieren um die Punkte bewerkstelligen. Dies erfolgt nicht an den eingefügten Punkten in der Karte, sondern rein rechnerisch über eine Koordinatenliste (bounds) und kommt ebenso erst ganz am Ende beim Einfügen der Karte zur Anwendung.

In der for-Schleife werden die Punkte durchgenommen, welche via PHP aus der Datenbank kamen und bereits in der Liste $data4gmArray zur Verfügung stehen (fertiges HTML für das Popup, Koordinatenpaar und Text für das Tooltip).

In der langen Zeile in der Mitte, mit dem roten Abschnitt, werden die Marker gebaut. circleMarker sind kreisrunde Marker, deren Grösse man besser Steuern kann, Parameter werden dahinter übergeben. Die folgenden bind-Methoden fügen Funktionen an den Marker, die Reihenfolge ist unerheblich, ebenso wo addTo() steht.

Die türkis gekennzeichnet Anweisungen für Tootips nehmen nur Text an. Allerdings ist die Standardeinstellung zusammen mit Popup-Blasen widersprüchlich, da das Tooltip beim Aufruf onclick nicht verschwindet. Deswegen braucht der Marker eine Variable (myMarker), an der darunter eine Funktion zum Schliessen des Tooltips gehängt wird.

Der grau gehaltene Code für die Popup-Blase ist einfach, er kann CSS3-HTML umfassen. Theoretisch passt sich die Blase an den Inhalt an, aber dies stimmt nur bedingt:

  • Die Breite ist auf 300px beschränkt, das kann man aber per CSS mit !important überschreiben.
  • Ich habe in den Blasen auch kleine Bilder. Obwohl diese sauber mit Breite und Höhe versehen sind, wird dies nicht evaluiert und das Bild ragte unten aus der Blase heraus. Es half allerdings rund um das Bild ein <div> samt passender Höhenangabe zu platzieren.

In grüner Farbe wird die OSM-Karte vordefiniert.

In der letzten Zeile wird alles zusammengebaut und eingebunden/angezeigt.

Aufsetzen eines eigenen Tiles-Servers

Alles hier unten ist in Arbeit.

Maximale Grösse der Kacheln am Server

Ein Hauptproblem beim Betreiben eines eigenen Tiles-Servers sind die am Server fertig generierten Kacheln. Mit SSD-Disks ist Speicherplatz wieder relevant geworden, während Bandbreite weniger Kopfzerbrechen bereitet. Natürlich ist die Kachelgenerierung “intelligent”, es wird nie alles abgerufen und klarerweise gibt es Kacheln mit wenig graphischen Inhalt. Trotzdem sollte man von einer Maximal-Zahl ausgehen. Diese ist nur anhand der rechnerisch existierenden Kacheln in einem Ausschnitt errechenbar. Ein Ansatz dazu findet sich unter dem Tile Calculator.
Für mein Gebiet, Provence-Alpes-Côte-d’Azur, kommt es mit einem rechteckigen Ausschnitt (also auch viel Meer und “Fremdland”) auf rund 10 Millionen Kacheln und 25GB bis zur Zoomstufe 18.

Datenquelle

Europa, Länder und Regionen

No Comments

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.