The page OpenRouteService.org is a very easy to use website which provides routing from A to B via C. It also allows to choose between different routing types for trucks, pedestrians or bicycles and isochrone analyses based on time and distance. In this article I would like to show you, how to embed the OpenRouteSevrice API into your very own Leaflet based webmap.
The Leaflet Basics
We will start with a very simple Leaflet based webmap: a basemap and a simple geojson point dataset:
As you can see: we do have a basemap and two markers. Both elements can act as an input provider of routing information for the API. But we would like to make this individually based on the input. Therefore I am using the context menu plugin for Leaflet. I add the contextmenu as an option for the map as well as for the markers. Yet the markers contextmenu depends on eachn feature I will use the onEachFeature functionality from Leaflet:
var map = L.map('map',{
contextmenu: true,
contextmenuWidth: 140,
contextmenuItems: [
{
text: 'get Isochrones',
callback: getAccess
}
]
}).setView([53, -1], 10);
// and the geoJSON marker:
function onEachMarker(feature, layer){
layer.bindContextMenu({
contextmenu: true,
contextmenuWidth: 140,
contextmenuItems: [
{
text: 'get Isochrones from marker',
callback: getAccessFromMarker
}
]
})
layer.bindPopup(feature.properties.name);
};
var markers = L.geoJSON(data, {
onEachFeature: onEachMarker
}).addTo(map);
As you can see, we call two different functions for the isochrones. So here comes the magic:
We will use jquery’s Ajax calls to get a JSON object from the API
First we will tidy up the response using turf.js
We will add them to the map
We will need some color magic
Calling the OpenRouteService.org API
Calling the URL is quite simple as you can see on the swaggerhub page. In the very basic these are a few lines in HTML/Javascript. The example shows the isochrone URL with a static coordinate pair and some other static values. Please make sure to get your own API key!
<script src="https://code.jquery.com/jquery-1.11.1.min.js"></script>
function getAccess(e){
$.ajax({
type: "GET", //rest Type
dataType: 'json',
url: "https://api.openrouteservice.org/isochrones?locations=-1.1428,52.955&profile=driving-car&range_type=time&interval=300&range=1800&units=&location_type=start&intersections=false&api_key=58d904a497c67e00015b45fc90fa91f0d345426145bb09e67e859771",
async: false,
contentType: "application/json; charset=utf-8",
success: function (data) {
console.log(data);
}
});
}
Now we would like to create a more dynamic way by handing over the coordinates of desire to the function. At the very moment the function has an event object as input. This objects holds all necessary information:
point = e.relatedTarget.feature.geometry.coordinates;
As another needed step we will add the response to the map instead of writing it to the log and remove maybe old entries from the map:
map.eachLayer(function (layer) {
if (layer.id === 'access'){// it's the access layer
map.removeLayer(layer);
}
});
access = new L.geoJson(data).addTo(map);
access.id="access";
Now the marker is surrounded by a nice looking polygon feature:
Isochrones from the OpenRouteService API
But we see some major problems:
The polygons are overlapping each other.
The color needs adjustment to differentiate each polygon.
Better Polygons from the OpenRouteService API
In the next step we will enhance the result. Therefore we will create a difference polygon by subtracting the smaller polygons from the bigger ones in a loop. Therefore I am using the turf.js Javascript library and the difference function, which is quite fast:
var difference=[];
for (i=0; i<(data.features.length-1); i++){
difference.push(turf.difference(data.features[i+1],data.features[i]));
}
difference.push(data.features[0]);
data.features=difference;
The result looks like this:
Difference polygons from the OpenRouteService API
But still, the color scheme does not respect any travel times ( I was using 5min intervals for a maximum of 30min). To do so, I will need a rgb calculation based on the ratio of the time value compared to the maximal value of 30min. Instead of using the default style, we will use a style function:
With this enhancement the overall look is much better:
colored polygons from the OpenRouteService API
These are the main ingredients at the moment.
Getting Isochrones from the map without a marker
The above steps took the marker geometry as inputs. The work with a map and it’s coordinate is quite similar:
Instead of asking for the feature geometry the event from the map has a direct object called latlng:
point = e.latlng;
But instead of writing the whole function again we will simply create a different function with the main functionality that is called either from the map event or the marker event. The whole code loks like this in the end:
Great example, David! Thanks for the easy-to-follow instructions to use ORS:) You mind posting your Twitter handle for proper attribution?
Sam
4 years ago
This is a fantastic tutorial – however looks like the ORS API it consumes has changed recently and now a CORS issue is present in the browser devtools, so it fails to retrieve the data now.
Is this something you could adjust easily, I’ve been trying things on my version and I’m wondering if ORS have caused it to break?
In one of our latest projects we faced a sad truth: geocoding results often sucks and points are not scattered enough but concentrate on distinct locations and clusters…
There are so many applications out there but they probably share one thing: export your data as a XXX-delimited table. And it’s also very easy to create a…
If you are reading this post – you might know something about satellite imagery. This is a valuable source to power quite a lot of analytics and monitoring…
Great example, David! Thanks for the easy-to-follow instructions to use ORS:) You mind posting your Twitter handle for proper attribution?
This is a fantastic tutorial – however looks like the ORS API it consumes has changed recently and now a CORS issue is present in the browser devtools, so it fails to retrieve the data now.
Is this something you could adjust easily, I’ve been trying things on my version and I’m wondering if ORS have caused it to break?
Yes, but it looks like they just changed the URL and moved away from GET requests towards POST only.