UNPKG

lrm-ign-geoservices

Version:

Support for Ign Geoservices in Leaflet Routing Machine

192 lines (168 loc) 5.63 kB
const L = require('leaflet'); const corslite = require('@mapbox/corslite'); if (L.Routing === undefined) { L.Routing = {}; } L.Routing.IgnGeoservices = L.Evented.extend({ options: { serviceUrl: 'https://wxs.ign.fr/calcul/geoportail/itineraire/rest/1.0.0/route', timeout: 10 * 1000, resource: 'bdtopo-osrm', // or 'bdtopo-pgr' profile: 'car', // Or 'pedestrian' optimization: 'fastest', // or shortest }, initialize(options) { L.Util.setOptions(this, options); }, _routeDone(response, inputWaypoints, options, callback, context) { const alts = []; const route = { name: '', summary: { totalTime: response.duration, totalDistance: response.distance, }, coordinates: response.geometry.coordinates.map(x => L.latLng(x[1], x[0])), waypoints: this._toWaypoints(response), waypointIndices: this._toWaypointsIndices(response), inputWaypoints, instructions: this._toInstructions(response), }; alts.push(route); callback.call(context, null, alts); }, _toWaypoint(str, name = null, options = {}) { const latlng = str.split(','); return new L.Routing.Waypoint(L.latLng(parseFloat(latlng[1]), parseFloat(latlng[0])), name, options); }, _toWaypoints(response) { const wps = [this._toWaypoint(response.portions[0].start)]; response.portions.forEach((x) => { wps.push(this._toWaypoint(x.end)); }); return wps; }, _isValidStep(step) { return (step.geometry.coordinates.length > 2 || step.geometry.coordinates[0][0] !== step.geometry.coordinates[1][0] || step.geometry.coordinates[0][1] !== step.geometry.coordinates[1][1]); }, _toWaypointsIndices(response) { const indices = [0]; let total = 0; response.portions.forEach((portion) => { portion.steps.forEach((step) => { if (this._isValidStep(step)) total += step.geometry.coordinates.length - 1; }); indices.push(total); }); return indices; }, _toInstructions(response) { const instr = []; response.portions.forEach((portion) => { portion.steps.forEach((step) => { if (this._isValidStep(step)) { let text = ''; if (step.instruction) text = step.instruction; else { if (step.attributes.name.cpx_numero) text = step.attributes.name.cpx_numero; if (step.attributes.name.cpx_numero || step.attributes.name.nom_1_gauche || step.attributes.name.nom_1_droite) { text += ' '; } if (step.attributes.name.nom_1_gauche) text += step.attributes.name.nom_1_gauche; else if (step.attributes.name.nom_1_droite) text += step.attributes.name.nom_1_droite; } instr.push({ distance: step.distance, time: step.duration, text, }); } }); }); return instr; }, route(waypoints, callback, context, options = {}) { let timedOut = false; const _options = L.extend({}, this.options, options); const wps = waypoints.map(wp => ({ latLng: wp.latLng, name: wp.name, options: wp.options, })); const routeOpts = this.buildRouteOpts(wps, _options); const url = _options.serviceUrl + L.Util.getParamString(routeOpts); const timer = setTimeout(() => { timedOut = true; callback.call(context || callback, { status: -1, message: 'IgnGeoservices request timed out.', }); }, _options.timeout); // eslint-disable-next-line func-names const xhr = corslite(url, L.bind(function (err, resp) { const error = {}; clearTimeout(timer); if (!timedOut) { if (!err) { try { try { const data = JSON.parse(resp.responseText); this._routeDone(data, wps, options, callback, context); return; } catch (ex) { error.status = -3; error.message = ex.toString(); } } catch (ex) { error.status = -2; error.message = `Error parsing IgnGeoservices response: ${ex.toString()}`; } } else { error.message = `IgnGeoservices HTTP request failed: ${err.type}` + `${err.target && err.target.status ? ` HTTP ${err.target.status}: ${err.target.statusText}` : ''}`; error.url = url; error.status = -1; error.target = err; } callback.call(context || callback, error); } else { xhr.abort(); } }, this)); return xhr; }, buildRouteOpts(waypoints, options) { const wps = waypoints.map(wp => ({ latLng: wp.latLng, name: wp.name, options: wp.options, })); const startLatLng = wps.shift().latLng; const endLatLng = wps.pop().latLng; const viaPoints = wps.map(wp => L.Util.template('{lng},{lat}', wp.latLng)); const opt = { resource: options.resource, start: L.Util.template('{lng},{lat}', startLatLng), end: L.Util.template('{lng},{lat}', endLatLng), intermediates: viaPoints.join('|'), profile: options.profile, optimization: options.optimization, getSteps: true, geometryFormat: 'geojson', getBbox: false, crs: 'EPSG:4326', timeUnit: 'second', distanceUnit: 'meter', waysAttributes: '', }; return opt; }, }); L.Routing.ignGeoservices = function ignGeoservices(options) { return new L.Routing.IgnGeoservices(options); }; module.exports = L.Routing.IgnGeoservices;