Unter Leaflet OSM-Karten bei Zoomwechsel tauschen

Es gibt mehrere Anbieter, die Kacheln laden lassen. Jedoch sind oft nicht alle Zoombereiche verfügbar. Analog gilt diese Einschränkung auch für unterschiedliche geographische Bereiche.

Unter Leaflet change tile service on zoom ist dieser Wechsel grundlegend erklärt und beispielhaft ausgeführt. Es werden zwei Ebenen mit Karten-Kacheln definiert und diese Layer werden beim Zoom-Wechsel ausgetauscht. Soweit so trivial, aber der Code hat ein paar Mängel:

  • Mit if(map.getZoom() > 16){} und else {} fügt man den einen Layer bei jedem Zoom-Wechel hinzu und den anderen nimmt man weg. Man braucht es aber nur einmal beim Schlüsselwert machen.
  • Der Wechsel erfolgt bei map.on("zoomend", function(e){ }). Statt zoomend gibt es noch andere Event-Trigger, aber alle haben den Nachteil, dass dabei der Wechsel zu einem (z.B. höheren) Wert bereits erfolgt. Liegt dies genau über dem Maximal-Wert des Layers der Entfernt werden soll, so passiert das zwar, aber zuvor werden noch dessen Kacheln aufgerufen (und 404er-Fehler generiert, weil diese ja nicht existieren).

Screenshot der Browser-Console mit Ladefehlern


Im verlinkten Beispiel oben ist der Wechsel bei Zoom kein Problem, weil für beide Layer alle Zoomstufen existieren. Aber Open Topo Map liefert nur Kacheln bis Zoom 16. Darüber will ich original OSM-Kachel ausliefern. Mache ich den Wechsel bei Zoom 15, erfolgen keine falschen Aufrufe, aber ich kann Zoom 16 von Open Topo Map nicht anzeigen. Es geht auch nicht den Zoom-Level mtit maxZoom:16 zu begrenzen, denn sonst sperrt das Zoom-Control-Panel eben bei Zoom 16.

Die Abhilfe ist nicht perfekt, vielleicht gibt es ja Vorschläge für Verbesserungen:

  • Das Begrenzen des Wechsels nur beim Schwellenwert kann man mit if(map.hasLayer(mapNormal)){} bewerkstelligen. Man fragt ob der Layer existiert, wenn nicht, dann braucht auch nichts zu erfolgen (im gegebenen Fall bei Zoom 17, 18 und 19).
  • Den Sprung sauber beim Wert 16 schaffen geht allerdings nicht. Optisch passt es prima, aber es kommen eben die Ladefehler. Ich konnte mir nur damit helfen, maxZoom:16.99 für den Layer zu setzen, der nicht über Zoom 16 hinaus geht. Ich hatte erwartet, dass der Zoom Stufen von ...,15,16,17,18,... macht, aber es ist  ...,15,16,16.99,18,... Man kann nicht den Wert auf 16.01 setzen, weil man sonst einen Zwischenschritt erzeugt: ...,15,16,16.01,17,18,...

Screenshot der Browser-Console mit Zoom-Sprüngen


Als JS-Code sieht meine derzeitige Lösung so aus:

<link rel="stylesheet" href="/sys/OSMleaflet/leaflet.css"/>
<script src="/sys/OSMleaflet/leaflet.js" crossorigin=""></script>
<script src="/sys/OSMleaflet/leaflet-plugins/layer/vector/KML.js"></script>
<script type="text/javascript">
  function init(){
    var map = new L.Map('rndGM');
    var mapNormal = L.tileLayer('https://{s}.tile.opentopomap.org/{z}/{x}/{y}.png', {
      attribution: '[...]',
      minZoom:7,
      maxZoom:16.99
    });
    var mapZoom = L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
      attribution: '[...]',
      minZoom:16,
      maxZoom:19
    });
    var track = new L.KML("$furl$fnnx$sllang.kml", {async: true});
    track.on("loaded", function(e) {
      map.fitBounds(e.target.getBounds()); // INNITIERT ERSTES ZOOM-EVENT
    });
    map.addLayer(track);
    // HIER NOCH KEIN RASTER-LAYER
    map.on("zoomend", function(e){ // ERSTE KARTE WIRD ONZOOM HINZUGEFÜGT. SO KANN getBounds NICHT IN EINEN FALSCHEN LAYER GREIFEN
      console.log("Zoom level: ", map.getZoom());
      if(map.getZoom() > 16){
        if(map.hasLayer(mapNormal)){
          map.removeLayer(mapNormal);
        }
        mapZoom.addTo(map);
      } else {
        if(map.hasLayer(mapZoom)){
          map.removeLayer(mapZoom);
        }
      mapNormal.addTo(map);
      }
    });
  }
</script>

No Comments

Leave a Comment

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