You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
safe-bike-routing/src/L.Routing.OpenRouteService....

170 lines
4.6 KiB
JavaScript

(function() {
'use strict';
var L = require('leaflet');
L.Routing = L.Routing || {};
L.Routing.OpenRouteService = L.Evented.extend({
options: {
serviceUrl: 'https://api.openrouteservice.org/v2/directions',
profile: 'cycling-regular',
orsOptions: {}, // see https://openrouteservice.org/dev/#/api-docs/v2/directions/{profile}/post
},
initialize: function(apiKey, options) {
this._apiKey = apiKey;
L.Util.setOptions(this, options);
},
route: async function(waypoints, callback, context, options) {
options = options || {}
const url = `${this.options.serviceUrl}/${this.options.profile}/json`
const instructions = !options.geometryOnly
const coordinates = waypoints.map(wp => [wp.latLng.lng, wp.latLng.lat])
const res = await fetch(url, {
method: 'POST',
headers: {
'authorization': this._apiKey,
'content-type': 'application/json',
},
body: JSON.stringify({
instructions,
coordinates,
maneuvers: true,
geometry_simplify: options.simplifyGeometry,
...this.options.orsOptions,
}),
})
const ratelimit = {
limit: Number(res.headers.get('X-RateLimit-Limit')),
remaining: Number(res.headers.get('X-RateLimit-Remaining')),
reset: Number(res.headers.get('X-RateLimit-Reset')),
}
const parsed = await res.json()
const payload = res.ok
? [null, this.toIRoute(parsed, waypoints)]
: [{ status: res.statusText, message: parsed.error }, null]
callback.call(context || callback, ...payload)
return this;
},
toIRoute: function(orsResponse, inputWaypoints) {
const routes = []
for (const r of orsResponse.routes) {
const coordinates = this.decodePolyline(r.geometry)
const steps = [].concat(...r.segments.map(s => s.steps))
const instructions = steps.map(s => ({
distance: s.distance,
time: s.duration,
text: s.instruction,
road: s.name,
type: this.instructionType(s.type),
direction: s.maneuver ? this.direction(s.maneuver.bearing_after) : undefined,
}))
routes.push({
name: '',
coordinates,
instructions,
summary: {
totalDistance: r.summary.distance,
totalTime: r.summary.duration,
},
inputWaypoints,
actualWaypoints: r.way_points.map(i => ({ latLng: coordinates[i] })),
waypointIndices: r.way_points,
})
}
return routes
},
direction: bearing => {
if (bearing === undefined) return undefined
const labels = ['N', 'NE', 'E', 'SE', 'S', 'SW', 'W', 'NW']
const fac = 360/labels.length
const i = Math.floor((bearing + fac/2) % 360 / fac)
return labels[i]
},
instructionType: i => {
switch (i) {
case 0: return 'Left'
case 1: return 'Right'
case 2: return 'SharpLeft'
case 3: return 'SharpRight'
case 4: return 'SlightLeft'
case 5: return 'SlightRight'
case 6: return 'Straight'
case 7: return 'Roundabout' // enter
case 8: return 'Roundabout' // exit
case 9: return 'TurnAround'
case 10: return 'DestinationReached'
case 11: return 'StartAt'
case 12: return 'Left'
case 13: return 'Right'
default: return undefined
}
},
decodePolyline: (encodedPolyline, includeElevation) => {
// array that holds the points as [lat,lng,alt?]
let points = []
let index = 0
const len = encodedPolyline.length
let lat = 0
let lng = 0
let ele = 0
while (index < len) {
let b
let shift = 0
let result = 0
do {
b = encodedPolyline.charAt(index++).charCodeAt(0) - 63 // finds ascii
// and subtract it by 63
result |= (b & 0x1f) << shift
shift += 5
} while (b >= 0x20)
lat += ((result & 1) !== 0 ? ~(result >> 1) : (result >> 1))
shift = 0
result = 0
do {
b = encodedPolyline.charAt(index++).charCodeAt(0) - 63
result |= (b & 0x1f) << shift
shift += 5
} while (b >= 0x20)
lng += ((result & 1) !== 0 ? ~(result >> 1) : (result >> 1))
if (includeElevation) {
shift = 0
result = 0
do {
b = encodedPolyline.charAt(index++).charCodeAt(0) - 63
result |= (b & 0x1f) << shift
shift += 5
} while (b >= 0x20)
ele += ((result & 1) !== 0 ? ~(result >> 1) : (result >> 1))
}
try {
let location = [(lat / 1E5), (lng / 1E5)]
if (includeElevation) location.push((ele / 100))
points.push(L.latLng(location))
} catch (e) {
console.error(e)
}
}
return points
},
});
L.Routing.openRouteService = function(apiKey, options) {
return new L.Routing.OpenRouteService(apiKey, options);
};
module.exports = L.Routing.OpenRouteService;
})();