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:
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:
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:
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
3 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?
Some months ago I published qgis2leaf which enables a QGIS user to publish a webmap the easy way. It was integrated into qgis2web which offers a leaflet and…
Let’s assume you like cruise ships, tanker, ferries or you’re so fortunate and own a fleet of vessels cruising over the oceans. But where the heck are the…
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.