Displaying maps on mobile devices is a common requirement. I expect a mobile map to be scalable, rotatable and always readable. The data that needs to be transferred for showing the map should not exceed my monthly free data amount. Most applications display raster maps that consist of several image tiles. The problem is: If I rotate the map everything, also the lettering and symbols, are turned and finally displayed upside down. On my high definition display the lettering is tiny, hardly readable and despite image compression the data consumption gets high when zooming and panning in a regular manner. This is how we solved this challenge with the OpenSource GeoServer extension gs-mvt.
Only a few web-map frameworks like OpenLayers support map rotation. Rendering the map directly on the client would solve most of these issues. Over the last years, mobile devices became more powerful and mobile web-map frameworks using Web GL like Mapbox GL or Tangrams have been established. These frameworks request vector tiles from a defined backend. In my case I want to host my own map data. There are existing solutions like TileStache which is written in Python. But if you are used to the Java-World and GeoServer, as I am, a GeoServer would be the preferred option.
Vector Tile Standards
There is currently no available OGC standard for the vector tile output format. Common used open standards are:
- GeoJSON clipped to a tile
- TopoJSON
- Mapbox Vector Tile (MVT)
GeoJSON and TopoJSON are JSON extensions and consequently text containing attribute-value pairs. TopoJSON is much smaller than GeoJSON but less readable. A good blog entry regarding size reduction with TopoJSON has been posted by ZevRoss.
Mapbox Vector Tiles use google’s protocol buffers as binary output format which is even much smaller than TopoJSON but not human readable.
Tile Map Request Protocols
Besides an output format definition, the modality of requesting the tiles is important. Looking at the most popular JavaScript frameworks Mapbox GL JS and Tangrams, I discovered two protocols that are supported by both clients:
- Tile Map Service (TMS)
- Slippy Map Tiles (aka XYZ)
Both standards have REST like structure. The TMS allows different clips and coordinate reference systems. Slippy Map Tiles is a special TMS restricted to the Transversal Mercator Projection with mirrored y-Axis, a defined origin and used by big players like OpenStreetMap, Google maps or Bing maps. Consequently the slippy map tiles have become to a de facto standard in serving tiles.
GeoServer Extension
The OpenSource GeoServer supports most of the OGC compliant standards for web mapping, is shipped with a tile caching system (GeoWebCache) and easy extensible. To address the problem I developed an extension that adds the ability to the GeoServer’s Web Mapping Service (WMS) to deliver Mapbox Vector Tiles. If you have installed this extension (gs-mvt) and trigger a WMS request with the format parameter “application/x-protobuf”, a google protocol buffer encoded tile is returned instead of an image. Additionally gs-mvt provides a controller that converts Slippy Map Tile requests to WMS compliant ones and redirects the client. Unfortunately I did not find a way to extent the (internal) GeoWebCache, for caching binary vector tiles, without changing the source code. Consequently all vector tiles requested from the GeoServer are rendered “live” in the current version.
On high zoom levels (e.g. showing the whole world) all available geometric features are loaded and transferred to the client. But usually I neither need that much detail nor all kind of features to be displayed. Therefore the gs-mvt extension provides some mechanism for filtering and generalization:
- Geometries that are smaller than 0.1 display units are filtered
- Geometries are simplified by the Douglas-Peucker algorithm
- Filter rules of the (SLD) style will be applied to the vector data
Visualization
To visualize the results I used the Mapbox GL JS client and referenced to a custom TileJSON (endpoint definition file) that contains the URL to my GeoServer. The styling on client side is done with a Style JSON that is structured similar to CartoCSS. For use with the GeoServer it is mandatory to set the “source-layer” attribute to the GeoServer’s layer name. The Style JSON allows the definition of more than one source, so I combined my custom street layer with the OSM data retrieved from the Mapbox server. In contrary to a WMS overlay, my custom data is embedded and rendered together with the Mapbox data.