Es gibt viele Möglichkeiten, ansprechende Karten mit interessanten Funktionen und Inhalten zu erstellen. In diesem Artikel konzentrieren wir uns auf interaktive Karten im Web, die auf Vektordaten basieren und mit OpenLayers erstellt werden.

Genauer gesagt werden wir uns mit den aktuellen Entwicklungen von OpenLayers auseinandersetzen, welche die WebGL API zu nutzen und so eine viel bessere Rendering-Leistung zu erzielen. Gleichzeitig sehen wir was genau im Rendering-Code vor sich geht. Lassen Sie uns eintauchen!
 

Using WebGL for rendering maps in OpenLayers | © Peakpx

Etwas Hintergrundwissen


OpenLayers ist eine beliebte Bibliothek für die Erstellung interaktiver Karten. Es gibt diese Bibliothek bereits seit einiger Zeit, und sie hat zahlreiche Refactorings und Überarbeitungen erfahren. Neben der Erstellung von Karten bietet OpenLayers auch viele Hilfsprogramme für die Umwandlung von Daten aus und in zahlreiche Formate wie GeoJSON, GPX und Mapbox Vector Tiles, sowie die Interaktion mit Standardprotokollen wie WMS, WFS, usw.

Der jüngste Anstieg der Nutzung von Vektordaten nach dem Erscheinen von Hochleistungs-Renderern wie Mapbox war eine echte Herausforderung für OpenLayers: Traditionell ging man davon aus, dass große Vektordatensätze in Bilder gebacken und entweder in Kacheln (z. B. über WMTS) oder als Bilder in benutzerdefinierter Größe (über WMS) bereitgestellt werden. Das Rendern tatsächlicher Formen anstelle von Bildern, die diese Formen enthalten, würde also nicht allzu oft und nicht in allzu großen Mengen vorkommen.

Using WebGL for rendering maps in OpenLayers | © Camptocamp

Obwohl der Schwerpunkt in den vergangenen Jahren nicht auf Vektordaten lag, ist der in OpenLayers verfügbare Vektor-Renderer hochgradig optimiert und kann mit Tausenden von komplexen Formen umgehen. Er vereinfacht Linien und Polygone in Echtzeit und verwendet einen räumlichen Index für die schnelle Filterung von Geometrien außerhalb der aktuellen Ansicht. Bei wirklich dichten Datensätzen (typischerweise vector tiles) kann der Renderer jedoch nicht mithalten, und die Leistung wird in vielen Situationen zu einem limitierenden Faktor.

Es wurden Umgehungslösungen gefunden, Optimierungen vorgenommen, und man konnte damit interaktive Karten mit vielen Vektordaten erstellen und sich dabei auf OpenLayers verlassen, welches bereits im bewährten Einsatz steht. Aber letztendlich ist das Grundproblem immer noch vorhanden: Das Rendern von Formen ist derzeit einfach nicht schnell genug.
 

Eine Reise zu WebGL

Wo wir stehen


Grundsätzlich stehen bis dato zwei Hauptalternativen für das Rendern von Grafiken auf einer Webseite zur Verfügung: die Canvas API und die WebGL API.

OpenLayers konnte sich traditionell auf verschiedene Rendering-Methoden stützen: In der Vergangenheit konnten Dinge mit SVG oder sogar dem DOM gerendert werden, aber heutzutage basieren die wichtigsten Rendering-Fähigkeiten auf der Canvas-API. Diese API bietet eine hervorragende visuelle Qualität, konsistente Ergebnisse und eine leistungsstarke Textwiedergabe. Ihr größter Nachteil ist wahrscheinlich die Tatsache, dass sie für komplexe Operationen einfach zu langsam ist.

Die WebGL-API hingegen hat das Potenzial, extrem schnell zu sein, ist aber andererseits kostspielig in der Implementierung, sehr fehleranfällig und sehr, sehr schlecht beim Zeichnen von Text. In der Tat wird sie Ihnen bei Text überhaupt nicht helfen und Ihnen das Vergnügen bereiten, ein Experte für Kerning, Ligaturen und andere Freuden des Lebens zu werden.

An der Implementierung von WebGL-basierten Renderern in OpenLayers wird nun schon seit einigen Jahren gearbeitet, und in letzter Zeit wurden einige beeindruckende Fortschritte erzielt. Dennoch bleiben die Mainstream-Renderer, die auf Canvas basieren, oft die Standardoption, die alle Funktionalitäten bietet und die meisten Anwendungsfälle erfüllt.
 

Nächster Meilenstein: nicht (mehr) so weit weg!

Derzeit bietet OpenLayers nur einen WebGL-basierten Renderer für Punkte. Jede andere Art von Vektordaten (Linien, Polygone) muss über den Canvas-basierten Renderer laufen. Dies kann zwar in Szenarien wie der Datenvisualisierung hilfreich sein, aber nicht, wenn es um vollwertige Vektorkacheln geht (z.B. OpenStreetMap-Daten).

Der offensichtliche nächste Schritt ist, auch Linien und Polygone rendern zu können. Beide Geometrietypen sind wesentlich schwieriger zu handhaben als Punkte: WebGL bietet keine Linien- oder Polygonprimitive, so dass beide für das Rendering in Dreiecke zerlegt werden müssen.

Die gute Nachricht ist, dass es viele Inspirationsquellen im Internet gibt, da es sich im Grunde um ein (irgendwie) gelöstes Problem in WebGL handelt. Andererseits bietet das Rendern von Geometrien auf einer Karte andere Herausforderungen als beispielsweise ein 3D-Mesh. Das bedeutet, dass wir die ganze Arbeit selbst machen müssen und uns nicht auf bestehende Tools  verlassen dürfen! Aber wo bliebe sonst der Spaß?
 

An die Arbeit


An dieser Stelle wird dieser Artikel technisch. Wir werden einen Blick auf die aktuelle WebGL-Rendering-Logik werfen und wie sie sich weiterentwickeln wird.
 


Rendering von Punkten ist eigentlich ganz einfach
 

Wie andere Arten von Geometrien müssen auch Punkte in Dreiecke zerlegt werden, um gerendert werden zu können.

Der übliche Ansatz besteht darin, ein so genanntes Quad zu erstellen:

Using WebGL for rendering maps in OpenLayers | © Camptocamp
Using WebGL for rendering maps in OpenLayers | © Camptocamp

 

 

Vier Scheitelpunkte, zwei Dreiecke, ein Quad.

Dieser sehr einfache Aufbau gibt uns eine Arbeitsfläche, auf der wir den Punkt darstellen können, wobei wir alles von einfachen Farben bis hin zu tatsächlichen Bildern verwenden können:

Dieser Ansatz hat mehrere Vorteile: Für jeden Punkt wird eine feste Anzahl von Dreiecken benötigt, und die Logik zur Erzeugung der Eckpunktpositionen ist trivial (Hinzufügen eines Offsets zum Punktzentrum).

 

Von Daten zu Dreiecken


Punkte müssen aus einer Vektordatenquelle gelesen werden; diese Art von Quelle kann ihre Daten von überall her beziehen: lokale Dateien, WFS-Dienste, dynamisch erzeugte Objekte usw.

Als solche bietet sie die perfekte Abstraktion für das Rendern von Objekten aus vielen verschiedenen Quellen.

 

Die Klasse, die für das Rendern von Punkten mit WebGL verantwortlich ist, heißt WebGLPointsLayerRenderer und funktioniert folgendermaßen:

Using WebGL for rendering maps in OpenLayers | © Camptocamp

Natürlich ist die Realität ein wenig komplexer, aber dies ist eine genaue Darstellung des allgemeinen Arbeitsablaufs. Es ist auch erwähnenswert, dass der Schritt der Dreiecksgenerierung in einem anderen Thread erfolgt, um eine zu große Beeinträchtigung des flüssigen Benutzererlebnisses zu vermeiden.

Dies funktioniert für Punkte und es gibt keinen Grund, warum dies nicht auch für Linien oder Polygone funktionieren sollte! So etwas in der Art zum Beispiel:

Using WebGL for rendering maps in OpenLayers | © Camptocamp


Es gibt hier einen zusätzlichen Schritt, der aber nicht allzu komplex ist: die Unterscheidung von Geometrien nach Typ und deren Speicherung in separaten Listen, die später verarbeitet werden. Das ist wichtig, weil jede Geometrieart ihre eigenen Besonderheiten hat.

 

Ok, das ist doch einfach, oder?

Allerdings gibt es auch zwei neue Prozesse, über die wir noch nicht gesprochen haben:

 

Diese beiden hingegen sind sehr viel komplizierter. Schauen wir uns das mal genauer an.

Using WebGL for rendering maps in OpenLayers | © Camptocamp

Sind Polygone am Ende nicht wie Quadrate... eben nur mit mehr Seiten?

Das stimmt nicht ganz. Polygongeometrien können Hunderte oder Tausende von Scheitelpunkten aufweisen und komplizierte konkave Formen besitzen. Sie können sogar Löcher haben!

Die Zerlegung eines Polygons in Dreiecke (auch bekannt als Triangulation) ist ein komplexes Thema, das seit Jahrzehnten erforscht wird. Es wurden mehrere Algorithmen mit unterschiedlichen Ergebnissen und Stärken erfunden. In unserem Fall brauchen wir einen Algorithmus, der Geschwindigkeit über Präzision stellt und mit komplexen Polygonen mit Löchern umgehen kann, und glücklicherweise gibt es eine Open Source-Bibliothek, die genau das tut!

Diese Bibliothek ist Teil des Mapbox-gl-js-Renderers, den ich bereits erwähnt habe, und dies ist einer der Gründe, warum er so leistungsfähig ist. Die Neuimplementierung eines komplexen Algorithmus wie diesem würde wahrscheinlich keine Vorteile bringen, und die Bibliothek hat eine freizugängliche Lizenz, so dass man sich keine großen Sorgen machen muss.

Schauen wir uns also an, wie die Triangulation eines Polygons aussehen wird:

Using WebGL for rendering maps in OpenLayers | © Camptocamp


Ein Polygon wird in der Regel durch einen einzigen äußeren Ring und null bis viele innere Ringe definiert. Der äußere Ring ist die Begrenzung des Polygons und die inneren Ringe definieren die Löcher im Polygon.

Wie wir bereits gesehen haben, kann eine Ringform (die im Wesentlichen eine geschlossene Linie ist) nicht sofort verwendet werden, um einen abgegrenzten Bereich mit WebGL zu zeichnen: Wir müssen triangulieren. Das oben vorgestellte Schema zeigt, wie ein sehr einfaches Polygon gezeichnet wird, aber in der Realität können die Dinge viel haariger werden (dieses Bild ist ein Beispiel aus der mapbox/earcut-Bibliothek).

Alles in allem war das gar nicht so schwer, werden Sie vielleicht sagen! Ich stimme zu, das war eigentlich der einfachste Teil. Bei den Linien sind wir auf uns allein gestellt. Deshalb werden wir sie nicht in diesem Artikel behandeln, sondern in Teil 2!
 

Das nächste Mal


In diesem Artikel haben wir einen Blick darauf geworfen, was innerhalb der Rendering-Engine einer Bibliothek wie OpenLayers passiert, zumindest für Punkte und Polygone. In Teil 2 werden wir versuchen, uns mit Linien und ihren vielen Fallstricken vertraut zu machen und einen Blick auf die tatsächliche Implementierung mit einer Live-Demo werfen. Viel Spaß und bis bald!

Für weitere Informationen,

zögern Sie nicht, mit uns in Kontakt zu treten!

Mit dem Absenden dieses Formulars akzeptiere ich, dass die eingegebenen Informationen für die in der Datenschutzrichtlinie beschriebenen Zwecke verwendet werden.