Don’t hesitate to contact us:
Forum: discuss.graphhopper.com
Email: support@graphhopper.com
This is a guest post by Robin, founder of Kurviger, a motorcycle rouplaner that is based on GraphHopper’s open source route planning library, GraphHopper core contributor, and open source enthusiast.
The whole mapping community was shocked when Mapzen announced that they will shutdown their services by the end of January 2018. The announcement was made on January 2nd 2018, which leaves consumers of their services less than one month to migrate to a different service. At Kurviger we only consumed vector tiles by Mapzen, so this post will be a bit map focused, but I will also talk about migrating from their mobility (routing) and search (geocoding) products.
The Kurviger app is used for planning motorcycle routes as well as turn-by-turn navigation. Besides offline maps, which require that a user downloads the maps first, the app also offers to use online maps, which makes it very easy to start planning a route and browsing the map. Kurviger’s primary provider for online maps was Mapzen. From a service consumer perspective Mapzen’s vector tiles service provided many excellent properties, like different formats (Mvt, GeoJson, TopoJson), different tile sizes, and usage based plans. So finding an alternative provider was not that easy. Luckily Kurviger didn’t use Mapzen’s SDK but VTM, an open source vector map library, that supports different providers, is actively developed, and easy to extend to use new providers. The “only” task left was to create a new online vector tile provider for VTM. But which provider is a good alternative to Mapzen?
Potential vector map providers for Kurviger were MapBox, Thunderforest, and TileHosting. There are more providers, but either they have restrictive terms, don’t use OSM data, or were not production ready at the time of writing this, so I did not include them here, for example ESRI or OsmBuildings. All these providers offer vector tiles, using the Mapbox Vector Tiles specification (MVT) and could be enabled in VTM easily. But MVT tiles are compatible with a wide range of renderers like Tangram, Mapbox-GL, or OpenLayers. Support for TileHosting has been added to VTM by the Kurviger team recently.
Any of the aforementioned providers offer their own benefits and downsides. When choosing a vector tile provider, besides the obvious criteria like pricing, terms, and support, I find it very important to check which tags are provided and at which zoom-level they are available. Most providers use their own schemas, that are usually not compatible with each other. For example Mapzen transformed many tags to kind
and kind_detail
, you can find more about this here. TileHosting uses the OpenMapTiles scheme, which transforms tags into class
and subclass
tags. Mapbox uses a similar approach using class
and type
. Hence, none of these providers offer native OSM tags. This is done to make it easier to write render themes, because the OSM tags are quite complex for tile rendering. In addition most providers don’t offer all OSM tags, but a subset of tags that each provider deems important when rendering maps. So make sure that your required tags are actually there. Also every provider requires different render themes because they use different schemas. An excellent tool to debug and compare different vector tile providers is Maputnik, they offer an Inspect Mode
to debug the vector tiles and a Map Mode
to view render themes. For Kurviger we decided to go with TileHosting. But I don’t want to give any recommendations for your use case, every provider has its own value proposition and ways to differentiate from each other.
The next step was to transform the Kurviger map theme, which is a theme optimized for motorcyclists and easy readability, to the OpenMapTiles scheme. Below you can find a preview of our Kurviger style using TileHosting.
Mapzen’s Mobility service provided routing, matrix, map matching, and isochrones. The good news is, that all these features are also available in the GraphHopper Directions API. GraphHopper provides clients for most common languages. First class supported are the Java client (including Android) and the Javascript client.
Let’s compare a simple routing scenario for both APIs. A simple routing request for Mapzen’s Turn-by-Turn API would look like this:
https://valhalla.mapzen.com/route?json={"locations":[{"lat":42.358528,"lon":-83.271400},{"lat":42.996613,"lon":-78.749855}],"costing":"auto"}&api_key=your-mapzen-api-key
The same request for GraphHopper’s Routing API would look like this:
https://graphhopper.com/api/1/route?point=42.358528,-83.271400&point=42.996613,-78.749855&vehicle=car&weighting=fastest&elevation=true&key=your-graphhopper-api-key
As you can see, the request looks a bit different, but all the basic elements appear in both requests. Mapzen used a json structure encoded in the URL, whereas GraphHopper uses regular query string parameters. locations
are named points
. The cost function defines what parameters a routing library uses to calculate the shortest or fastest route. With Mapzen you would define a costing
, where you could pass parameters like auto
or auto_shorter
. GraphHopper provides a vehicle
parameter that accepts values like car
, bike
and many more. In addition you can specify the routing mode using the weighting
parameter; the default is fastest
.
Comparing the results of a GraphHopper routing to a Mapzen routing result, you will see that both are json. Both Mapzen and GraphHopper provide the polyline of a route as encoded polyline, Mapzen calls this shape
, GraphHopper calls this points
. If you use the GraphHopper its JS or Java client, you don’t need to care about decoding the polyline as it is already done there or you can also add points_encoded=false
as parameter in the URL to receive a non encoded GeoJson LineString instead of an encoded polyline. Mapzen provides turn instructions in a maneuvers
array, GraphHopper calls this instructions
. Both a maneuver and instruction look quite similar. Both use reference indexes of the polyline (points), Mapzen calls this begin_shape_index
and end_shape_index
, GraphHopper has an interval
array with the first index being the start and the second index the end. Both encode the actual instruction e.g. “turn right” as a symbol (Mapzen type
, GraphHopper sign
). A detailed list of GraphHopper’s signs can be found here. Both provide a textual representation of the instruction that can be used by a TTS engine to notify a driver about the upcoming turn, as well as more details like street name. You can test the GraphHopper Routing API using the GraphHopper Maps demo.
Mapzen’s geocoding engine had a couple of interesting features: autocomplete, forward geocoding, and backward geocoding. Autocomplete means that you get suggestions for a place while still typing; for example when you type “New Y”, it might already show you “New York”. Forward geocoding describes the process of translating the name of a place to its coordinates. Reverse geocoding is the opposite process, that finds places that are close to a coordinate.
GraphHopper offers a Geocoding API that provides you with autocomplete, forward, and reverse geocoding as well. The default provider is a hosted version of the open source project Photon. Besides the default provider, the Geocoding API also provides access to Nominatim and OpenCageData. Also see Gisgraphy and Osmnames via Tilehosting for more alternatives.
Let’s have a look on how to convert a Geocoding request to GraphHopper’s Geocoding API. A sample geocoding request against Mapzen’s search API could be:
https://search.mapzen.com/v1/search?text=new york&focus.point.lat=-33.83434&focus.point.lon=151.1459&api_key=your-mapzen-api-key
The similar request for GraphHopper’s Geocoding API would look like this:
https://graphhopper.com/api/1/geocode?q=new york&point=-33.83434,151.1459&key=your-graphhopper-key
Again both APIs work quite similar. The search query for Mapzen would be called text
, GraphHopper calls this q
. You can promote local search results, while still receiving global results by specifying a focus.point
(Mapzen) or point
(GraphHopper). Both APIs return a json array containing the search results, including the name, coordinates, and additional meta information, like country and postcode. In contrast to Mapzens search API, the results of the GraphHopper Geocoding API can be used for autocompletion and don’t require a special autocomplete endpoint with a different pricing. Performing reverse geocoding with the GraphHopper Geocoding API is very easy as well, just add the parameter reverse=true
and a point.
GraphHopper further provides a Route Optimization API, a Map Matching API, an Isochrone API, and a Matrix API and all come with developer examples here. This should allow you to fully migrate your product. The equivalent of Mapzen’s “optimized route” is the GraphHopper Routing API with the parameter optimize=true. Whereas the Route Optimization API from GraphHopper does more than just reordering the points for a route: it considers multiple vehicles, time windows, vehicle capacities and more.
Let me know about your experience and pain points while migration!