Zum Inhalt springen
Sprache
DE EN FR
Projekt starten

cloudtec Stack: Coordinate Picker mit Open Source

Koordinaten in einer fremden Karte heraussuchen, kopieren und im Zielsystem blind einfügen: Diesen Umweg haben wir durch ein eigenes Widget auf Basis von OpenLayers ersetzt.

Ein Feature, das nach wenig aussieht, aber einiges an Detailarbeit enthält: unser Coordinate Picker auf Basis der Open-Source-Bibliothek OpenLayers. Er ist direkt in unsere Plattformen eingebaut, damit beim Erfassen eines Standorts niemand die Anwendung verlassen muss.

Warum wir den Coordinate Picker gebaut haben

In vielen unserer Projekte gibt es eine Karte: Firmenstandorte, Termine je Standort, Wanderungen, Aktivitäten. Damit ein Punkt auf dieser Karte erscheint, müssen seine Koordinaten erfasst sein, und genau dort begann der Umweg. Standort in einem Kartendienst suchen, Koordinaten kopieren, ins Formular einfügen. Im Zielsystem war danach nicht mehr sichtbar, ob der Punkt wirklich stimmt. Dazu musste erklärt werden, woher die Werte kommen und in welcher Reihenfolge sie gehören, damit Längen- und Breitengrad nicht vertauscht werden.

Das ist ein unnötiger Bruch in der Bedienung. Statt weiter zu erklären, haben wir ein eigenes Widget für die Koordinaten-Auswahl gebaut, das in unseren Plattformen direkt im Formular sitzt.

Formularfeld «Koordinaten Startort» mit eingebetteter swisstopo-Karte, Zoom-Schaltflächen links und Löschen-Schaltfläche rechts oben.
Punkt setzen: Kartenausschnitt wählen, in die Karte klicken: der Marker sitzt, die Koordinaten stehen im Feld.

Was OpenLayers ist

OpenLayers ist eine quelloffene JavaScript-Bibliothek für interaktive Karten in Webanwendungen. Was sie für uns brauchbar macht:

  • Open Source. Frei einsetzbar, anpassbar und weitergebbar, solange die Lizenzbedingungen eingehalten werden.
  • Interaktive Karten. Mehrere Ebenen, Marker, Popups sowie Zoomen und Verschieben sind Teil der Bibliothek.
  • Freie Wahl der Grundkarte. OpenStreetMap, die swisstopo-Karten des Bundes und weitere WMS-, WMTS- oder XYZ-Quellen lassen sich einbinden, eigene Ebenen dazu.
  • Geodaten-Formate. Vektordaten wie GeoJSON und KML lassen sich direkt darstellen, Rasterdaten kommen über WMS oder WMTS dazu.
  • Erweiterbar. Eigene Funktionen, eigenes Styling und angepasste Interaktionen sind vorgesehen, nicht nachgerüstet.
  • Mobil nutzbar. Die Karten funktionieren auf unterschiedlichen Bildschirmgrössen und mit Touch-Bedienung.
  • Dokumentation und Community. Umfangreiche Beispiele und eine aktive Entwickler-Community, wie bei Open Source üblich.

Wie der Coordinate Picker umgesetzt ist

Von aussen ist die Funktion simpel: ein Widget mit einer Karte, in der du zoomen und einen Punkt setzen kannst. Der Punkt wird gespeichert und lässt sich an beliebiger anderer Stelle der Anwendung wieder anzeigen. Dahinter steckt etwas mehr.

Dieselbe Karte mit einem bereits gesetzten Marker und der Löschen-Schaltfläche rechts oben.
Ein gesetzter Punkt lässt sich verschieben oder über die Schaltfläche rechts oben wieder ganz entfernen.

Grundlagen

Als Kartenmaterial setzen wir die Pixelkarte von swisstopo ein. Das schränkt den Coordinate Picker auf die Schweiz ein. Für unsere Projekte ist das der richtige Zuschnitt, für andere Gebiete tauschst du die Kartenquelle. Im Widget gibt es drei Interaktionen: zoomen, zurücksetzen und löschen. Im Hintergrund liegen zwei Eingabefelder für Längen- und Breitengrad, die gefüllt werden, sobald der Punkt gesetzt ist.

Umgesetzt ist das Feature mit Standard-JavaScript plus jQuery. Globale Einstellungen geben Zoomstufe und Ausschnitt beim Aufruf vor. Eine Bounding Box begrenzt die Karte auf das Schweizer Gebiet, sodass kein Punkt ausserhalb des Kartenmaterials gesetzt werden kann; gleichzeitig hält sie das Seitenverhältnis, wenn sich die Grösse des Widgets ändert.

Dazu kommen Event Listener, etwa beim Klick, der den Pin setzt. Das Ereignis von OpenLayers wird dabei in ein eigenes Coordinate-Picker-Event übersetzt, an das sich weitere Aktionen hängen lassen, zum Beispiel das direkte Speichern des Punkts. Beim Aufruf stellen Mechanismen sicher, dass sich das Widget nicht doppelt initialisiert und Aktionen nicht doppelt ausgeführt werden. Bereits vorhandene Daten werden geladen, die Schaltflächen entsprechend eingeblendet.

Zwei Koordinatensysteme

Im Hintergrund laufen zwei Projektionen nebeneinander. Die Karte von swisstopo liefert EPSG:3857, also WGS 84 / Pseudo-Mercator, das übliche Web-Mercator-Raster für Kachelkarten. Nach aussen arbeitet das Widget dagegen mit EPSG:4326: WGS 84 in Längen- und Breitengrad, so wie es auch GPS-Geräte ausgeben und wie wir die Werte speichern. Zwischen beiden muss umgerechnet werden; die Funktion dafür bringt OpenLayers mit. Ist die Projektion falsch konfiguriert, liegen die Punkte daneben, und die Fehlersuche wird zäh, weil das Widget ansonsten normal funktioniert.

Code

Für alle Neugierigen und ganz im Sinn von Open Source: die Voreinstellungen und die Umrechnung, an der sich das Prinzip ablesen lässt.

class CoordinatePicker extends EventTarget {
    // global defaults
    static options = {
        center: [915000, 5910000], // center of switzerland
        boundingBox: [670433, 5744676, 1162476, 6078756], // swiss extent in EPSG:3857
        zoom: 14, // used when there is already a coordinate set
        backgroundLayerUrl: 'https://wmts.geo.admin.ch/1.0.0/ch.swisstopo.pixelkarte-farbe/default/current/3857/{z}/{x}/{y}.jpeg',
    };

    // expects coordinates in GPS (WGS84, EPSG:4326) format
    setData(long, lat) {
        // set data on input fields
        let inputs = this.getInputs();
        inputs.long.val(long);
        inputs.lat.val(lat);
        inputs.long.trigger("change");
        inputs.lat.trigger("change");

        // convert to map coordinates and set the marker
        let coords = ol.proj.transform([long, lat], 'EPSG:4326', 'EPSG:3857');
        this.markerSource.clear();
        this.markerSource.addFeature(new ol.Feature({
            geometry: new ol.geom.Point(coords)
        }));
    }
}
Geschrieben von Lukas Knöpfel Senior Fullstack Software Developer

Tech 4 Minuten Lesezeit