Mit dem Coordinate Picker Koordinaten erfassen

cloudtec Stack: Coordinate Picker mit Open Source

Es mag wie ein simples Feature erscheinen, hat es aber in sich – unser Coordinate Picker, der auf der OpenSource Bibliothek OpenLayers basiert. Mit ihm ist das lästige Koordinaten Kopieren von Google Maps oder anderen Karten-Anbietern Geschichte! Nahtlos in unsere Online-Plattformen integriert, wird die User-Experience nicht unterbrochen.

Im nachfolgenden Beitrag gehen wir darauf ein, wieso wir einen Coordinate Picker implementiert haben, was OpenLayers ist und wie wir den Coordinate Picker umgesetzt haben.

Warum wir den Coordinate Picker implementiert haben

Der Coordinate Picker in Aktion

In vielen unserer Projekte gibt es eine Karte, auf welcher beispielsweise Unternehmens-Standorte, Termine je Standort oder Wanderungen und Aktivitäten angezeigt werden sollen. Sei dies auf einer Website oder auf einer Online-Plattform. Damit diese Standorte auf der Karte angezeigt werden können, müssen die Koordinaten erfasst sein. Dies kann ein mühsames Unterfangen sein, wenn der Standort erst bspw. über Google Maps geöffnet und dann von dort die Koordinaten kopiert werden müssen. Im Zielsystem ist visuell nicht mehr ersichtlich, ob die Koordinaten auch wirklich stimmen. Zudem musste für die Nutzer erklärt werden, von wo und wie die Koordinaten kopiert werden können und wie diese korrekt eingefügt werden müssen (damit bspw. nicht Höhen- und Breitengrade vertauscht werden). Dies empfanden wir als unbefriedigenden und unnötigen Unterbruch in der User Experience. Auf der Suche nach einer nahtlos integrierten Lösung haben wir daher unser eigenes Widget für die Koordinaten-Auswahl implementiert. Es kann direkt in unsere Plattformen eingebaut und verwendet werden, ohne dass der User auf eine andere Website abspringen muss.

Was ist OpenLayers?

OpenLayers ist eine Open-Source-JavaScript-Bibliothek. Sie wird verwendet, um interaktive Karten in Webanwendungen zu erstellen. Hier die wichtigsten Eigenschaften von OpenLayers:

  • Open-Source: OpenLayers ist eine freie und quelloffene Bibliothek. Dies bedeutet, dass Entwickler sie frei verwenden, ändern und weitergeben können, solange die Bedingungen der Lizenz eingehalten werden.
  • Interaktive Karten: Entwickler können interaktive Karten in ihre Webanwendungen integrieren. Diese Karten können verschiedene Ebenen, Marker, Pop-up-Informationen und Interaktionen wie Zoomen und Verschieben enthalten.
  • Basiskarten und Layer: OpenLayers ermöglichen es, verschiedene Basiskarten einzubinden, darunter etwa Karten von OpenStreetMap, swisstopo, Bing Maps, Google Maps und anderen Anbietern. Zudem wird die Integration benutzerdefinierter Kartenebenen und Datenquellen unterstützt.
  • Integration von Geodaten: OpenLayers bietet Funktionen zur Integration von Geodaten in Karten. Diese können etwa in Formaten wie GeoJSON, KML und WMS daherkommen. Diese Formate ermöglichen es, Geodaten in Karten darzustellen und zu visualisieren.
  • Anpassbarkeit und Erweiterbarkeit: Entwickler können die Bibliothek verwenden, um Karten nach ihren spezifischen Anforderungen anzupassen und zu erweitern. Dies umfasst beispielsweise das Hinzufügen eigener Funktionen, das Styling von Karten und das Anpassen von Interaktionen.
  • Unterstützung für mobile Geräte: Die Bibliothek ist responsiv und optimiert für die Verwendung auf verschiedenen Bildschirmgrössen und Gerätetypen. OpenLayers unterstützt somit die Entwicklung von kartenbasierten Anwendungen für mobile Geräte.
  • Community und Dokumentation: Wie üblich für OpenSource Entwicklungen, verfügt OpenLayers über eine aktive Community von Entwicklern und Benutzern, welche Unterstützung bieten und zur Weiterentwicklung der Bibliothek beitragen. Zudem gibt es umfangreiche Dokumentationen, Tutorials und Beispiele, die zur effektiven Nutzung beitragen.

OpenLayers ist also eine leistungsstarke, vielseitige und flexible Bibliothek, die bei der Erstellung von interaktiven Kartenanwendungen in Web Umgebungen eingesetzt werden kann.

Wie wurde der Coordinate Picker umgesetzt?

Die Funktion des Coordinate Pickers an sich ist sehr simpel. Es gibt ein Widget, in dem eine Karte angezeigt wird. Innerhalb des Widgets kann gezoomt und ein Punkt gesetzt werden. Dieser Punkt wird gespeichert und kann anschliessend an einem beliebigen anderen Ort einer Applikation auf einer Karte angezeigt werden. Doch was steckt alles dahinter?

Grundlagen

Unser Coordinate Picker wurde auf Basis von OpenLayers erstellt. Dabei wird das Kartenmaterial von swisstopo eingesetzt. Dies schränkt die Verwendung des Coordinate Pickers zum jetzigen Zeitpunkt auf die Schweiz ein. Es gibt folgende Interaktionen im Widget: zoomen, löschen und zurücksetzen. Im Hintergrund gibt es je ein Input-Feld für die Höhen- und Breitengrade. Die Felder werden ausgefüllt, sobald der Punkt gesetzt wird.

Für das Feature wurde native JavaScript eingesetzt, also Standard JavaScript Objekte. Zudem wird jQuery verwendet. Verschiedene globale Einstellungen geben die Darstellung und Ansicht des Widgets vor. So etwa die Zoomstufe und der Ausschnitt beim Aufruf des Widgets, welche in einer Bounding-Box definiert sind. Diese stellt zudem sicher, dass ein Punkt nicht über das Kartenmaterial hinaus gesetzt werden kann und stellt das Seitenverhältnis sicher, indem die Anzeige flexibel auf die Grösse des Widgets angepasst wird.

Zurücksetzen von Koordinaten

Ausserdem gibt es verschiedene Event Listeners, so zum Beispiel beim Klick des Users, bei dem der Pin gesetzt wird. Hierbei wird der Event von OpenLayers in ein Coordinate Picker Event transformiert, damit weitere Events ausgelöst werden können - bspw. das direkte Speichern der Koordinaten eines Punktes. Des Weiteren gibt es beim Aufruf des Widgets Mechanismen, die sicherstellen, dass das Widget nicht doppelt initialisiert und somit auch die Aktionen nicht doppelt ausgeführt und gespeichert werden. Bei der Initialisierung werden zudem bereits vorhandene Daten geladen und die Action-Buttons angezeigt.

Im Hintergrund gibt es zwei verschiedene Koordinatensysteme bzw. Projektionen: WGS84/Pseudo-Mercator und EPSG:3857 (GPS-System, damit Koordinaten in Höhen- und Breitengraden gespeichert werden können), dabei muss zwischen den beiden Systemen umgerechnet werden. Die Funktion für die Umrechnung stellt OpenLayers bereit. Damit die Umrechnung funktioniert, muss OpenLayers korrekt konfiguriert sein, ansonsten stimmen die Punkte nicht und die Fehlersuche wird schwierig.

Code

Für alle Neugierigen und ganz nach dem Open Source Prinzip, finden Sie hier den vollständigen Code zu unserem Feature.

/** * CoordinatePicker * The map uses EPSG:3857 (WGS84/Pseudo-Mercator) as projection given by swisstopo. * But all interfaces (setData, inputs, events) use EPSG:4326 (WGS84, GPS) as it's the most common format. * * Events: * - select: {long, lat} when a coordinate is selected * * Usage: * CoordinatePicker.options.zoom = 10; // global default * new CoordinatePicker('#map', {zoom: 10}); // initialization with selector & options * new CoordinatePicker($('#map')); // initialization with jQuery object * new CoordinatePicker($('#map')).rollback() // getting already initialized picker and rollback it */ 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`, }; #container; #options = {} #originalData = {long: 0, lat: 0} constructor(container, options) { super(); container = $(container); // make sure it's a jQuery object $.extend(this.#options, CoordinatePicker.options, options); // prevent double initialization if (container.data('coordinate-picker')) { return container.data('coordinate-picker'); } this.#container = container; container.data('coordinate-picker', this); // save existing data for rollback let inputs = this.getInputs(); this.#originalData = { long: inputs.long.val(), lat: inputs.lat.val() }; // map layer this.backgroundLayer = new ol.layer.Tile({ name: "background", source: new ol.source.XYZ({ url: this.#options.backgroundLayerUrl }) }); // marker layer this.markerSource = new ol.source.Vector() this.markerLayer = new ol.layer.Vector({ source: this.markerSource, style: new ol.style.Style({ image: new ol.style.Icon({ src: `{{ asset('assets/img/map/icon-pin.svg') }}`, anchor: [0.5, 1], scale: 0.15 }) }) }); // perspective this.view = new ol.View({ projection: "EPSG:3857", // WGS84/Pseudo-Mercator. Also used in Google Maps, Bing, etc. center: this.#options.center, zoom: this.#options.zoom, extent: this.#scaleExtent(this.#options.boundingBox, 1.1) }) // initialize openlayers this.map = new ol.Map({ target: this.#container.get(0), controls: ol.control.defaults.defaults({ zoom: true, attribution: false, rotate: false }), layers: [this.backgroundLayer, this.markerLayer], view: this.view }); // click on map event this.map.on('singleclick', (e) => { let lonLat = ol.proj.toLonLat(e.coordinate, 'EPSG:3857'); // convert to GPS coordinates this.dispatchEvent(new CustomEvent('select', {detail: {long: lonLat[0], lat: lonLat[1]}})); }); // update input fields on coordinate select this.addEventListener('select', (e) => { this.setData(e.detail.long, e.detail.lat); }); // set initial data if (this.#originalData.long && this.#originalData.lat) { // set marker and zoom to it this.setData(this.#originalData.long, this.#originalData.lat); let coords = ol.proj.transform([this.#originalData.long, this.#originalData.lat], 'EPSG:4326', 'EPSG:3857'); this.view.setCenter(coords) } else { // remove rollback button and show full swiss map $('.l-rollback', this.#container).remove(); this.view.fit(this.#options.boundingBox); } // wire controls $('.l-rollback', this.#container).on('click', () => this.rollback()); $('.l-clear', this.#container).on('click', () => this.clear()); // hide rollback initially. will be displayed as soon as user changes the coordinates $('.l-rollback', this.#container).hide(); } // 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); // trigger change event on input fields inputs.long.trigger("change"); inputs.lat.trigger("change"); // set marker let coords = ol.proj.transform([long, lat], 'EPSG:4326', 'EPSG:3857'); // convert to map coordinates this.markerSource.clear(); this.markerSource.addFeature(new ol.Feature({ geometry: new ol.geom.Point(coords) })); $('.l-rollback', this.#container).show(); } getInputs() { return { long: $('input[name$="[longitude]"]', this.#container), lat: $('input[name$="[latitude]"]', this.#container) } } rollback() { this.setData(this.#originalData.long, this.#originalData.lat); let coords = ol.proj.transform([this.#originalData.long, this.#originalData.lat], 'EPSG:4326', 'EPSG:3857'); // convert to map coordinates this.view.setCenter(coords); $('.l-rollback', this.#container).hide(); } clear() { // clear data on input fields let inputs = this.getInputs(); inputs.long.val(''); inputs.lat.val(''); // trigger change event on input fields inputs.long.trigger("change"); inputs.lat.trigger("change"); // remove marker this.markerSource.clear(); } #scaleExtent(extent, factor) { let geom = ol.geom.Polygon.fromExtent(extent); geom.scale(factor); return geom.getExtent(); } }

Sind Sie bereit für Ihre eigene massgeschneiderte Online-Plattform mit komplexen Karten-Funktionen?

Erfassen auch Sie Ihre Koordinaten noch mit mühsamen Copy&Paste über Google Maps und möchten das ändern? Oder möchten Sie Geodaten auf Ihrer neuen Website oder Ihrem neuen Portal mit Hilfe von Karten anzeigen und wissen bisher nicht, wie Sie dies umsetzen können? Wir konzipieren Ihre Online-Plattform mit Karten-Lösung! Lassen Sie uns den Schritt in Richtung saubere und nahtlose Integration aller Funktionen in einem System gehen. Wir freuen uns, gemeinsam Ihre Geschäftsprozesse zu analysieren und diese in ein funktionierendes System zu übersetzen. Nutzen Sie unser Kontaktformular und erläutern Sie uns Ihr Projekt.