From 76e1aa3a93bedc19ab6f692057ddabcb30cb2bae Mon Sep 17 00:00:00 2001 From: wwwouaiebe Date: Fri, 15 Jan 2021 21:32:06 +0100 Subject: [PATCH] Issue #150 ongoing --- buildNumber.json | 2 +- src/core/FileCompactor.js | 8 +- .../GraphHopperRouteProvider.js | 159 ++---------- .../MapboxRouteProvider.js | 111 +++----- .../MapzenValhallaRouteProvider.js | 102 ++------ .../OpenRouteServiceRouteProvider.js | 83 +----- src/osrmRouteProvider/OSRMRouteProvider.js | 88 ++----- src/polyline/Polyline.js | 238 ++++++++---------- src/polyline/Polyline.template | 6 - src/util/Constants.js | 4 +- 10 files changed, 204 insertions(+), 597 deletions(-) delete mode 100644 src/polyline/Polyline.template diff --git a/buildNumber.json b/buildNumber.json index 00d61865..3914245b 100644 --- a/buildNumber.json +++ b/buildNumber.json @@ -1 +1 @@ -{ "buildNumber" : "00004"} \ No newline at end of file +{ "buildNumber" : "00166"} \ No newline at end of file diff --git a/src/core/FileCompactor.js b/src/core/FileCompactor.js index db7c67d2..0f1f6637 100644 --- a/src/core/FileCompactor.js +++ b/src/core/FileCompactor.js @@ -48,7 +48,7 @@ Tests ... import { polyline } from '../polyline/Polyline.js'; import { theTravelNotesData } from '../data/TravelNotesData.js'; import { newTravel } from '../data/Travel.js'; -import { ROUTE_EDITION_STATUS, ELEV, ZERO, ONE, INVALID_OBJ_ID } from '../util/Constants.js'; +import { ROUTE_EDITION_STATUS, ELEV, ZERO, ONE, INVALID_OBJ_ID, LAT_LNG } from '../util/Constants.js'; /** @------------------------------------------------------------------------------------------------------------------------------ @@ -63,8 +63,6 @@ import { ROUTE_EDITION_STATUS, ELEV, ZERO, ONE, INVALID_OBJ_ID } from '../util/C function ourNewFileCompactor ( ) { - const POLYLINE_PRECISION = 6; - /** @-------------------------------------------------------------------------------------------------------------------------- @@ -92,7 +90,7 @@ function ourNewFileCompactor ( ) { } ); compressedItineraryPoints.latLngs = - polyline.encode ( compressedItineraryPoints.latLngs, POLYLINE_PRECISION ); + polyline.encode ( compressedItineraryPoints.latLngs, LAT_LNG.fixed ); routeObject.itinerary.itineraryPoints = compressedItineraryPoints; // routeObject.itinerary.maneuvers = []; @@ -112,7 +110,7 @@ function ourNewFileCompactor ( ) { function myDecompressRoute ( routeObject ) { routeObject.itinerary.itineraryPoints.latLngs = - polyline.decode ( routeObject.itinerary.itineraryPoints.latLngs, POLYLINE_PRECISION ); + polyline.decode ( routeObject.itinerary.itineraryPoints.latLngs, LAT_LNG.fixed, false ); let decompressedItineraryPoints = []; let latLngsCounter = ZERO; routeObject.itinerary.itineraryPoints.latLngs.forEach ( diff --git a/src/graphHopperRouteProvider/GraphHopperRouteProvider.js b/src/graphHopperRouteProvider/GraphHopperRouteProvider.js index 112c02f4..bb8a88b3 100644 --- a/src/graphHopperRouteProvider/GraphHopperRouteProvider.js +++ b/src/graphHopperRouteProvider/GraphHopperRouteProvider.js @@ -16,25 +16,15 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -/* eslint camelcase: "off" */ -/* eslint no-bitwise: "off" */ +import { polyline } from '../polyline/Polyline.js'; +import { ZERO, LAT_LNG, HTTP_STATUS_OK } from '../util/Constants.js'; function newGraphHopperRouteProvider ( ) { - const ZERO = 0; - const ONE = 1; - - const MY_LAT_LNG_ROUND = 6; + const GRAPHHOPPER_LAT_LNG_ROUND = 5; const FOUR = 4; const METERS_IN_KILOMETERS = 1000; - const NUMBER5 = 5; - const NUMBER31 = 0x1f; - const NUMBER32 = 0x20; - const NUMBER63 = 0x3f; - const NUMBER100 = 100; - const NUMBER1emin5 = 1e-5; - const LAT = 0; const LNG = 1; const ELEV = 2; @@ -58,67 +48,6 @@ function newGraphHopperRouteProvider ( ) { 'kRoundaboutRight' // USE_ROUNDABOUT = 6 ]; - /* - --- myDecodePath function ----------------------------------------------------------------------------------------- - - Adapted from https://github.com/graphhopper/directions-api-js-client/blob/master/src/GHUtil.js - See GHUtil.prototype.decodePath - See also https://developers.google.com/maps/documentation/utilities/polylinealgorithm - Some adaptation for eslint and inverted lat and lng in the results... - - ------------------------------------------------------------------------------------------------------------------- - */ - - function myDecodePath ( encoded, is3D ) { - let len = encoded.length; - let index = ZERO; - let array = []; - let lat = ZERO; - let lng = ZERO; - let ele = ZERO; - - while ( index < len ) { - let byte = null; - let shift = ZERO; - let result = ZERO; - do { - byte = encoded.charCodeAt ( index ++ ) - NUMBER63; - result |= ( byte & NUMBER31 ) << shift; - shift += NUMBER5; - } while ( NUMBER32 <= byte ); - let deltaLat = ( ( result & ONE ) ? ~ ( result >> ONE ) : ( result >> ONE ) ); - lat += deltaLat; - - shift = ZERO; - result = ZERO; - do { - byte = encoded.charCodeAt ( index ++ ) - NUMBER63; - result |= ( byte & NUMBER31 ) << shift; - shift += NUMBER5; - } while ( NUMBER32 <= byte ); - let deltaLon = ( ( result & ONE ) ? ~ ( result >> ONE ) : ( result >> ONE ) ); - lng += deltaLon; - - if ( is3D ) { - shift = ZERO; - result = ZERO; - do { - byte = encoded.charCodeAt ( index ++ ) - NUMBER63; - result |= ( byte & NUMBER31 ) << shift; - shift += NUMBER5; - } while ( NUMBER32 <= byte ); - let deltaEle = ( ( result & ONE ) ? ~ ( result >> ONE ) : ( result >> ONE ) ); - ele += deltaEle; - array.push ( [ lat * NUMBER1emin5, lng * NUMBER1emin5, ele / NUMBER100 ] ); - } - else { - array.push ( [ lat * NUMBER1emin5, lng * NUMBER1emin5 ] ); - } - } - - return array; - } - /* --- myParseResponse function -------------------------------------------------------------------------------------- @@ -140,8 +69,8 @@ function newGraphHopperRouteProvider ( ) { myRoute.itinerary.descent = ZERO; response.paths.forEach ( path => { - path.points = myDecodePath ( path.points, true ); - path.snapped_waypoints = myDecodePath ( path.snapped_waypoints, true ); + path.points = polyline.decode ( path.points, GRAPHHOPPER_LAT_LNG_ROUND, true ); + path.snapped_waypoints = polyline.decode ( path.snapped_waypoints, GRAPHHOPPER_LAT_LNG_ROUND, true ); // eslint-disable-line let itineraryPoints = []; for ( let pointsCounter = ZERO; pointsCounter < path.points.length; pointsCounter ++ ) { let itineraryPoint = window.L.travelNotes.itineraryPoint; @@ -200,8 +129,8 @@ function newGraphHopperRouteProvider ( ) { wayPointsString = wayPointsString ? wayPointsString + '&' : ''; wayPointsString += 'point=' + - wayPoint.lat.toFixed ( MY_LAT_LNG_ROUND ) + ',' + - wayPoint.lng.toFixed ( MY_LAT_LNG_ROUND ); + wayPoint.lat.toFixed ( LAT_LNG.fixed ) + ',' + + wayPoint.lng.toFixed ( LAT_LNG.fixed ); } ); @@ -226,78 +155,24 @@ function newGraphHopperRouteProvider ( ) { } /* - --- myGetXHRJsonPromise function ---------------------------------------------------------------------------------- - - This function ... + --- myGetRoute function ------------------------------------------------------------------------------------------- ------------------------------------------------------------------------------------------------------------------- */ - function myGetXHRJsonPromise ( url, requestHeaders ) { - - /* - --- jsonRequest function -------------------------------------------------------------------------------------- - - --------------------------------------------------------------------------------------------------------------- - */ - - function jsonRequest ( onOk, onError ) { - - const READY_STATE_DONE = 4; - const HTTP_STATUS_OK = 200; - const HTTP_STATUS_ERR = 400; - const REQUEST_TIME_OUT = 15000; - - let xmlHttpRequest = new XMLHttpRequest ( ); - xmlHttpRequest.timeout = REQUEST_TIME_OUT; - - xmlHttpRequest.onreadystatechange = function ( ) { - if ( READY_STATE_DONE === xmlHttpRequest.readyState ) { - if ( HTTP_STATUS_OK === xmlHttpRequest.status ) { - let response = null; - try { - response = JSON.parse ( xmlHttpRequest.responseText ); - onOk ( response ); - } - catch ( err ) { - onError ( new Error ( 'JSON parsing error. File : ' + xmlHttpRequest.responseURL ) ); - } - } - else if ( HTTP_STATUS_ERR <= xmlHttpRequest.status ) { - onError ( - new Error ( 'Error HTTP ' + xmlHttpRequest.status + ' ' + xmlHttpRequest.statusText ) - ); + function myGetRoute ( onOk, onError ) { + fetch ( myGetUrl ( ) ) + .then ( + response => { + if ( HTTP_STATUS_OK === response.status && response.ok ) { + response.json ( ) + .then ( result => myParseResponse ( result, onOk, onError ) ); } else { - onError ( new Error ( 'Error XMLHttpRequest - File : ' + xmlHttpRequest.responseURL ) ); + onError ( new Error ( 'Invalid status ' + response.status ) ); } } - }; - xmlHttpRequest.open ( 'GET', url, true ); - if ( requestHeaders ) { - requestHeaders.forEach ( - header => xmlHttpRequest.setRequestHeader ( header.headerName, header.headerValue ) - ); - } - xmlHttpRequest.overrideMimeType ( 'application/json' ); - xmlHttpRequest.send ( null ); - } - - return new Promise ( jsonRequest ); - } - - /* - --- myGetRoute function ------------------------------------------------------------------------------------------- - - ------------------------------------------------------------------------------------------------------------------- - */ - - function myGetRoute ( onOk, onError ) { - - myGetXHRJsonPromise ( myGetUrl ( ) ) - .then ( response => myParseResponse ( response, onOk, onError ) ) - .catch ( err => onError ( err ) ); - + ); } /* diff --git a/src/mapboxRouteProvider/MapboxRouteProvider.js b/src/mapboxRouteProvider/MapboxRouteProvider.js index 486e91aa..e15b551d 100644 --- a/src/mapboxRouteProvider/MapboxRouteProvider.js +++ b/src/mapboxRouteProvider/MapboxRouteProvider.js @@ -15,16 +15,35 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ +/* +Changes: + - v2.1.0: + - Created from leaflet.TravelNotesMapbox +Doc reviewed ... +Tests ... + +----------------------------------------------------------------------------------------------------------------------- +*/ + +/** +@------------------------------------------------------------------------------------------------------------------------------ + +@file MapboxRouteProvider.js +@copyright Copyright - 2017 2021 - wwwouaiebe - Contact: https://www.ouaie.be/ +@license GNU General Public License +@private + +@------------------------------------------------------------------------------------------------------------------------------ +*/ import { polyline } from '../polyline/Polyline.js'; import { osrmTextInstructions } from '../providersUtil/OsrmTextInstructions.js'; import { theIconList } from '../providersUtil/IconList.js'; -import { ZERO, ONE, TWO } from '../util/Constants.js'; +import { ZERO, ONE, TWO, LAT_LNG, HTTP_STATUS_OK } from '../util/Constants.js'; function newMapboxRouteProvider ( ) { - const MY_POLYLINE_PRECISION = 6; - const MY_LAT_LNG_ROUND = 6; + const MAPBOX_LAT_LNG_ROUND = 6; let myProviderKey = ''; let myUserLanguage = 'fr'; @@ -51,18 +70,14 @@ function newMapboxRouteProvider ( ) { myRoute.itinerary.hasProfile = false; myRoute.itinerary.ascent = ZERO; myRoute.itinerary.descent = ZERO; - response.routes [ ZERO ].geometry = - polyline.decode ( response.routes [ ZERO ].geometry, MY_POLYLINE_PRECISION ); - + polyline.decode ( response.routes [ ZERO ].geometry, MAPBOX_LAT_LNG_ROUND, false ); response.routes [ ZERO ].legs.forEach ( function ( leg ) { let lastPointWithDistance = ZERO; leg.steps.forEach ( function ( step ) { - step.geometry = polyline.decode ( step.geometry, MY_POLYLINE_PRECISION ); - - // bug Mapbox for car: geometry have 2 points for 'arrive' maneuver type + step.geometry = polyline.decode ( step.geometry, MAPBOX_LAT_LNG_ROUND, false ); if ( 'arrive' === step.maneuver.type && @@ -148,8 +163,8 @@ function newMapboxRouteProvider ( ) { wayPoint => { wayPointsString = wayPointsString ? wayPointsString + ';' : ''; wayPointsString += - wayPoint.lng.toFixed ( MY_LAT_LNG_ROUND ) + ',' + - wayPoint.lat.toFixed ( MY_LAT_LNG_ROUND ); + wayPoint.lng.toFixed ( LAT_LNG.fixed ) + ',' + + wayPoint.lat.toFixed ( LAT_LNG.fixed ); } ); @@ -176,78 +191,24 @@ function newMapboxRouteProvider ( ) { } /* - --- myGetXHRJsonPromise function ------------------------------------------------------------------------------ - - This function ... + --- myGetRoute function --------------------------------------------------------------------------------------- --------------------------------------------------------------------------------------------------------------- */ - function myGetXHRJsonPromise ( url, requestHeaders ) { - - /* - --- jsonRequest function ---------------------------------------------------------------------------------- - - ----------------------------------------------------------------------------------------------------------- - */ - - function jsonRequest ( onOk, onError ) { - - const READY_STATE_DONE = 4; - const HTTP_STATUS_OK = 200; - const HTTP_STATUS_ERR = 400; - const REQUEST_TIME_OUT = 15000; - - let xmlHttpRequest = new XMLHttpRequest ( ); - xmlHttpRequest.timeout = REQUEST_TIME_OUT; - - xmlHttpRequest.onreadystatechange = function ( ) { - if ( READY_STATE_DONE === xmlHttpRequest.readyState ) { - if ( HTTP_STATUS_OK === xmlHttpRequest.status ) { - let response = null; - try { - response = JSON.parse ( xmlHttpRequest.responseText ); - onOk ( response ); - } - catch ( err ) { - onError ( new Error ( 'JSON parsing error. File : ' + xmlHttpRequest.responseURL ) ); - } - } - else if ( HTTP_STATUS_ERR <= xmlHttpRequest.status ) { - onError ( - new Error ( 'Error HTTP ' + xmlHttpRequest.status + ' ' + xmlHttpRequest.statusText ) - ); + function myGetRoute ( onOk, onError ) { + fetch ( myGetUrl ( ) ) + .then ( + response => { + if ( HTTP_STATUS_OK === response.status && response.ok ) { + response.json ( ) + .then ( result => myParseResponse ( result, onOk, onError ) ); } else { - onError ( new Error ( 'Error XMLHttpRequest - File : ' + xmlHttpRequest.responseURL ) ); + onError ( new Error ( 'Invalid status ' + response.status ) ); } } - }; - xmlHttpRequest.open ( 'GET', url, true ); - if ( requestHeaders ) { - requestHeaders.forEach ( - header => xmlHttpRequest.setRequestHeader ( header.headerName, header.headerValue ) - ); - } - xmlHttpRequest.overrideMimeType ( 'application/json' ); - xmlHttpRequest.send ( null ); - } - - return new Promise ( jsonRequest ); - } - - /* - --- myGetRoute function --------------------------------------------------------------------------------------- - - --------------------------------------------------------------------------------------------------------------- - */ - - function myGetRoute ( onOk, onError ) { - - myGetXHRJsonPromise ( myGetUrl ( ) ) - .then ( response => myParseResponse ( response, onOk, onError ) ) - .catch ( err => onError ( err ) ); - + ); } /* diff --git a/src/mapzenValhallaRouteProvider/MapzenValhallaRouteProvider.js b/src/mapzenValhallaRouteProvider/MapzenValhallaRouteProvider.js index 266c29f2..a6d8d53a 100644 --- a/src/mapzenValhallaRouteProvider/MapzenValhallaRouteProvider.js +++ b/src/mapzenValhallaRouteProvider/MapzenValhallaRouteProvider.js @@ -16,13 +16,12 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -/* eslint camelcase: "off" */ - import { polyline } from '../polyline/Polyline.js'; +import { ZERO, HTTP_STATUS_OK } from '../util/Constants.js'; function newMapzenValhallaRouteProvider ( ) { - const ZERO = 0; + const MAPZEN_LAT_LNG_ROUND = 6; let myProviderKey = ''; let myUserLanguage = 'fr'; @@ -78,7 +77,6 @@ function newMapzenValhallaRouteProvider ( ) { function myParseResponse ( response, returnOnOk, returnOnError ) { - const POLYLINE_PRECISION = 6; const M_IN_KM = 1000; if ( ZERO === response.trip.legs.length ) { @@ -90,7 +88,7 @@ function newMapzenValhallaRouteProvider ( ) { response.trip.legs.forEach ( leg => { - leg.shape = polyline.decode ( leg.shape, POLYLINE_PRECISION ); + leg.shape = polyline.decode ( leg.shape, MAPZEN_LAT_LNG_ROUND, false ); let itineraryPoints = []; for ( let shapePointCounter = ZERO; shapePointCounter < leg.shape.length; shapePointCounter ++ ) { let itineraryPoint = window.L.travelNotes.itineraryPoint; @@ -137,8 +135,8 @@ function newMapzenValhallaRouteProvider ( ) { let request = { locations : [], costing : '', - directions_options : { language : myUserLanguage }, - costing_options : {} + directions_options : { language : myUserLanguage }, // eslint-disable-line + costing_options : {} // eslint-disable-line }; let wayPointsIterator = myRoute.wayPoints.iterator; @@ -156,24 +154,24 @@ function newMapzenValhallaRouteProvider ( ) { switch ( myRoute.itinerary.transitMode ) { case 'bike' : request.costing = 'bicycle'; - request.costing_options = { + request.costing_options = { // eslint-disable-line bicycle : { - maneuver_penalty : MANEUVER_PENALTY, - bicycle_type : 'Cross', - cycling_speed : '20.0', - use_roads : '0.25', - use_hills : '0.25' + maneuver_penalty : MANEUVER_PENALTY, // eslint-disable-line + bicycle_type : 'Cross', // eslint-disable-line + cycling_speed : '20.0', // eslint-disable-line + use_roads : '0.25', // eslint-disable-line + use_hills : '0.25' // eslint-disable-line } }; break; case 'pedestrian' : request.costing = 'pedestrian'; - request.costing_options = { pedestrian : { walking_speed : '4.0' } }; + request.costing_options = { pedestrian : { walking_speed : '4.0' } }; // eslint-disable-line break; case 'car' : request.costing = 'auto'; - request.costing_options = { auto : { country_crossing_cost : '60' } }; + request.costing_options = { auto : { country_crossing_cost : '60' } }; // eslint-disable-line break; default : break; @@ -183,78 +181,24 @@ function newMapzenValhallaRouteProvider ( ) { } /* - --- myGetXHRJsonPromise function ---------------------------------------------------------------------------------- - - This function ... + --- myGetRoute function ------------------------------------------------------------------------------------------- ------------------------------------------------------------------------------------------------------------------- */ - function myGetXHRJsonPromise ( url, requestHeaders ) { - - /* - --- jsonRequest function -------------------------------------------------------------------------------------- - - --------------------------------------------------------------------------------------------------------------- - */ - - function jsonRequest ( onOk, onError ) { - - const READY_STATE_DONE = 4; - const HTTP_STATUS_OK = 200; - const HTTP_STATUS_ERR = 400; - const REQUEST_TIME_OUT = 15000; - - let xmlHttpRequest = new XMLHttpRequest ( ); - xmlHttpRequest.timeout = REQUEST_TIME_OUT; - - xmlHttpRequest.onreadystatechange = function ( ) { - if ( READY_STATE_DONE === xmlHttpRequest.readyState ) { - if ( HTTP_STATUS_OK === xmlHttpRequest.status ) { - let response = null; - try { - response = JSON.parse ( xmlHttpRequest.responseText ); - onOk ( response ); - } - catch ( err ) { - onError ( new Error ( 'JSON parsing error. File : ' + xmlHttpRequest.responseURL ) ); - } - } - else if ( HTTP_STATUS_ERR <= xmlHttpRequest.status ) { - onError ( - new Error ( 'Error HTTP ' + xmlHttpRequest.status + ' ' + xmlHttpRequest.statusText ) - ); + function myGetRoute ( onOk, onError ) { + fetch ( myGetUrl ( ) ) + .then ( + response => { + if ( HTTP_STATUS_OK === response.status && response.ok ) { + response.json ( ) + .then ( result => myParseResponse ( result, onOk, onError ) ); } else { - onError ( new Error ( 'Error XMLHttpRequest - File : ' + xmlHttpRequest.responseURL ) ); + onError ( new Error ( 'Invalid status ' + response.status ) ); } } - }; - xmlHttpRequest.open ( 'GET', url, true ); - if ( requestHeaders ) { - requestHeaders.forEach ( - header => xmlHttpRequest.setRequestHeader ( header.headerName, header.headerValue ) - ); - } - xmlHttpRequest.overrideMimeType ( 'application/json' ); - xmlHttpRequest.send ( null ); - } - - return new Promise ( jsonRequest ); - } - - /* - --- myGetRoute function ------------------------------------------------------------------------------------------- - - ------------------------------------------------------------------------------------------------------------------- - */ - - function myGetRoute ( onOk, onError ) { - - myGetXHRJsonPromise ( myGetUrl ( ) ) - .then ( response => myParseResponse ( response, onOk, onError ) ) - .catch ( err => onError ( err ) ); - + ); } /* diff --git a/src/openRouteServiceRouteProvider/OpenRouteServiceRouteProvider.js b/src/openRouteServiceRouteProvider/OpenRouteServiceRouteProvider.js index 20759839..0d2af660 100644 --- a/src/openRouteServiceRouteProvider/OpenRouteServiceRouteProvider.js +++ b/src/openRouteServiceRouteProvider/OpenRouteServiceRouteProvider.js @@ -16,21 +16,12 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -/* eslint camelcase: "off" */ -/* eslint no-bitwise: "off" */ +import { polyline } from '../polyline/Polyline.js'; +import { ZERO, ONE, LAT_LNG, HTTP_STATUS_OK } from '../util/Constants.js'; function newOpenRouteServiceRouteProvider ( ) { - const ZERO = 0; - const ONE = 1; - - const NUMBER5 = 5; - const NUMBER31 = 0x1f; - const NUMBER32 = 0x20; - const NUMBER63 = 0x3f; - const NUMBER1emin5 = 1e-5; - const NUMBER100 = 100; - const MY_LAT_LNG_ROUND = 6; + const OPEN_ROUTE_LAT_LNG_ROUND = 5; const LAT = 0; const LNG = 1; const ELEV = 2; @@ -38,67 +29,6 @@ function newOpenRouteServiceRouteProvider ( ) { let myUserLanguage = 'fr'; let myRoute = null; - /* - --- myDecodePath function ----------------------------------------------------------------------------------------- - - Adapted from https://github.com/graphhopper/directions-api-js-client/blob/master/src/GHUtil.js - See GHUtil.prototype.decodePath - See also https://developers.google.com/maps/documentation/utilities/polylinealgorithm - Some adaptation for eslint and inverted lat and lng in the results... - - ------------------------------------------------------------------------------------------------------------------- - */ - - function myDecodePath ( encoded, is3D ) { - let len = encoded.length; - let index = ZERO; - let array = []; - let lat = ZERO; - let lng = ZERO; - let ele = ZERO; - - while ( index < len ) { - let byte = null; - let shift = ZERO; - let result = ZERO; - do { - byte = encoded.charCodeAt ( index ++ ) - NUMBER63; - result |= ( byte & NUMBER31 ) << shift; - shift += NUMBER5; - } while ( NUMBER32 <= byte ); - let deltaLat = ( ( result & ONE ) ? ~ ( result >> ONE ) : ( result >> ONE ) ); - lat += deltaLat; - - shift = ZERO; - result = ZERO; - do { - byte = encoded.charCodeAt ( index ++ ) - NUMBER63; - result |= ( byte & NUMBER31 ) << shift; - shift += NUMBER5; - } while ( NUMBER32 <= byte ); - let deltaLon = ( ( result & ONE ) ? ~ ( result >> ONE ) : ( result >> ONE ) ); - lng += deltaLon; - - if ( is3D ) { - shift = ZERO; - result = ZERO; - do { - byte = encoded.charCodeAt ( index ++ ) - NUMBER63; - result |= ( byte & NUMBER31 ) << shift; - shift += NUMBER5; - } while ( NUMBER32 <= byte ); - let deltaEle = ( ( result & ONE ) ? ~ ( result >> ONE ) : ( result >> ONE ) ); - ele += deltaEle; - array.push ( [ lat * NUMBER1emin5, lng * NUMBER1emin5, ele / NUMBER100 ] ); - } - else { - array.push ( [ lat * NUMBER1emin5, lng * NUMBER1emin5 ] ); - } - } - - return array; - } - /* --- myParseResponse function -------------------------------------------------------------------------------------- @@ -113,7 +43,7 @@ function newOpenRouteServiceRouteProvider ( ) { returnOnError ( new Error ( 'Route not found' ) ); } response.routes [ ZERO ].geometry = - myDecodePath ( response.routes [ ZERO ].geometry, true ); + polyline.decode ( response.routes [ ZERO ].geometry, OPEN_ROUTE_LAT_LNG_ROUND, true ); myRoute.itinerary.itineraryPoints.removeAll ( ); myRoute.itinerary.maneuvers.removeAll ( ); myRoute.itinerary.hasProfile = true; @@ -198,8 +128,8 @@ function newOpenRouteServiceRouteProvider ( ) { wayPoint => { wayPointsString = wayPointsString ? wayPointsString + ',' : '{"coordinates":['; wayPointsString += - '[' + wayPoint.lng.toFixed ( MY_LAT_LNG_ROUND ) + - ',' + wayPoint.lat.toFixed ( MY_LAT_LNG_ROUND ) + ']'; + '[' + wayPoint.lng.toFixed ( LAT_LNG.fixed ) + + ',' + wayPoint.lat.toFixed ( LAT_LNG.fixed ) + ']'; } ); wayPointsString += '],"elevation":"true","language":"' + myUserLanguage + '"}'; @@ -276,7 +206,6 @@ function newOpenRouteServiceRouteProvider ( ) { function jsonRequest ( onOk, onError ) { const READY_STATE_DONE = 4; - const HTTP_STATUS_OK = 200; const HTTP_STATUS_ERR = 400; const REQUEST_TIME_OUT = 15000; diff --git a/src/osrmRouteProvider/OSRMRouteProvider.js b/src/osrmRouteProvider/OSRMRouteProvider.js index c3d9e2cd..b2abf2e8 100644 --- a/src/osrmRouteProvider/OSRMRouteProvider.js +++ b/src/osrmRouteProvider/OSRMRouteProvider.js @@ -19,12 +19,11 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA import { polyline } from '../polyline/Polyline.js'; import { osrmTextInstructions } from '../providersUtil/OsrmTextInstructions.js'; import { theIconList } from '../providersUtil/IconList.js'; -import { ZERO, ONE } from '../util/Constants.js'; +import { ZERO, ONE, LAT_LNG, HTTP_STATUS_OK } from '../util/Constants.js'; function newOSRMRouteProvider ( ) { - const MY_POLYLINE_PRECISION = 6; - const MY_LAT_LNG_ROUND = 6; + const OSRM_ROUTE_LAT_LNG_ROUND = 6; let myUserLanguage = 'fr'; let myRoute = null; @@ -54,14 +53,14 @@ function newOSRMRouteProvider ( ) { myRoute.itinerary.descent = ZERO; response.routes [ ZERO ].geometry = - polyline.decode ( response.routes [ ZERO ].geometry, MY_POLYLINE_PRECISION ); + polyline.decode ( response.routes [ ZERO ].geometry, OSRM_ROUTE_LAT_LNG_ROUND, false ); response.routes [ ZERO ].legs.forEach ( function ( leg ) { let lastPointWithDistance = ZERO; leg.steps.forEach ( function ( step ) { - step.geometry = polyline.decode ( step.geometry, MY_POLYLINE_PRECISION ); + step.geometry = polyline.decode ( step.geometry, OSRM_ROUTE_LAT_LNG_ROUND, false ); let maneuver = window.L.travelNotes.maneuver; maneuver.iconName = @@ -139,8 +138,8 @@ function newOSRMRouteProvider ( ) { wayPoint => { wayPointsString = wayPointsString ? wayPointsString + ';' : ''; wayPointsString += - wayPoint.lng.toFixed ( MY_LAT_LNG_ROUND ) + ',' + - wayPoint.lat.toFixed ( MY_LAT_LNG_ROUND ); + wayPoint.lng.toFixed ( LAT_LNG.fixed ) + ',' + + wayPoint.lat.toFixed ( LAT_LNG.fixed ); } ); @@ -168,79 +167,24 @@ function newOSRMRouteProvider ( ) { } /* - --- myGetXHRJsonPromise function ------------------------------------------------------------------------------ - - This function ... + --- myGetRoute function --------------------------------------------------------------------------------------- --------------------------------------------------------------------------------------------------------------- */ - function myGetXHRJsonPromise ( url, requestHeaders ) { - - /* - --- jsonRequest function ---------------------------------------------------------------------------------- - - ----------------------------------------------------------------------------------------------------------- - */ - - function jsonRequest ( onOk, onError ) { - - const READY_STATE_DONE = 4; - const HTTP_STATUS_OK = 200; - const HTTP_STATUS_ERR = 400; - const REQUEST_TIME_OUT = 15000; - - let xmlHttpRequest = new XMLHttpRequest ( ); - xmlHttpRequest.timeout = REQUEST_TIME_OUT; - - xmlHttpRequest.onreadystatechange = function ( ) { - if ( READY_STATE_DONE === xmlHttpRequest.readyState ) { - if ( HTTP_STATUS_OK === xmlHttpRequest.status ) { - - let response = null; - try { - response = JSON.parse ( xmlHttpRequest.responseText ); - onOk ( response ); - } - catch ( err ) { - onError ( new Error ( 'JSON parsing error. File : ' + xmlHttpRequest.responseURL ) ); - } - } - else if ( HTTP_STATUS_ERR <= xmlHttpRequest.status ) { - onError ( - new Error ( 'Error HTTP ' + xmlHttpRequest.status + ' ' + xmlHttpRequest.statusText ) - ); + function myGetRoute ( onOk, onError ) { + fetch ( myGetUrl ( ) ) + .then ( + response => { + if ( HTTP_STATUS_OK === response.status && response.ok ) { + response.json ( ) + .then ( result => myParseResponse ( result, onOk, onError ) ); } else { - onError ( new Error ( 'Error XMLHttpRequest - File : ' + xmlHttpRequest.responseURL ) ); + onError ( new Error ( 'Invalid status ' + response.status ) ); } } - }; - xmlHttpRequest.open ( 'GET', url, true ); - if ( requestHeaders ) { - requestHeaders.forEach ( - header => xmlHttpRequest.setRequestHeader ( header.headerName, header.headerValue ) - ); - } - xmlHttpRequest.overrideMimeType ( 'application/json' ); - xmlHttpRequest.send ( null ); - } - - return new Promise ( jsonRequest ); - } - - /* - --- myGetRoute function --------------------------------------------------------------------------------------- - - --------------------------------------------------------------------------------------------------------------- - */ - - function myGetRoute ( onOk, onError ) { - - myGetXHRJsonPromise ( myGetUrl ( ) ) - .then ( response => myParseResponse ( response, onOk, onError ) ) - .catch ( err => onError ( err ) ); - + ); } /* diff --git a/src/polyline/Polyline.js b/src/polyline/Polyline.js index 3fee8682..588bc708 100644 --- a/src/polyline/Polyline.js +++ b/src/polyline/Polyline.js @@ -1,38 +1,35 @@ -/* eslint-disable */ +/* eslint no-bitwise: "off" */ -'use strict'; +const ZERO = 0; +const ONE = 1; -/** - * Based off of [the offical Google document](https://developers.google.com/maps/documentation/utilities/polylinealgorithm) - * - * Some parts from [this implementation](http://facstaff.unca.edu/mcmcclur/GoogleMaps/EncodePolyline/PolylineEncoder.js) - * by [Mark McClure](http://facstaff.unca.edu/mcmcclur/) - * - * @module polyline - */ - -let polyline = {}; +const NUMBER5 = 5; +const NUMBER10 = 10; +const NUMBER31 = 0x1f; +const NUMBER32 = 0x20; +const NUMBER63 = 0x3f; +const NUMBER100 = 100; -function py2_round ( value ) { +function python2Round ( value ) { // Google's polyline algorithm uses the same rounding strategy as Python 2, which is different from JS for negative values - return Math.floor ( Math.abs ( value ) + 0.5 ) * ( 0 <= value ? 1 : -1 ); + return Math.floor ( Math.abs ( value ) + 0.5 ) * ( ZERO <= value ? ONE : -ONE ); } function encode ( current, previous, factor ) { - current = py2_round ( current * factor ); - previous = py2_round ( previous * factor ); + current = python2Round ( current * factor ); + previous = python2Round ( previous * factor ); let coordinate = current - previous; - coordinate <<= 1; - if ( 0 > current - previous ) { + coordinate <<= ONE; + if ( ZERO > current - previous ) { coordinate = ~ coordinate; } let output = ''; - while ( 0x20 <= coordinate ) { - output += String.fromCharCode ( ( 0x20 | ( coordinate & 0x1f ) ) + 63 ); - coordinate >>= 5; + while ( NUMBER32 <= coordinate ) { + output += String.fromCharCode ( ( NUMBER32 | ( coordinate & NUMBER31 ) ) + NUMBER63 ); + coordinate >>= NUMBER5; } - output += String.fromCharCode ( coordinate + 63 ); + output += String.fromCharCode ( coordinate + NUMBER63 ); return output; } @@ -48,124 +45,87 @@ function encode ( current, previous, factor ) { * @see https://github.com/Project-OSRM/osrm-frontend/blob/master/WebContent/routing/OSRM.RoutingGeometry.js */ -polyline.decode = function ( str, precision ) { - let index = 0, - lat = 0, - lng = 0, - coordinates = [], - shift = 0, - result = 0, - byte = null, - latitude_change, - longitude_change, - factor = Math.pow ( 10, Number.isInteger ( precision ) ? precision : 5 ); - - // Coordinates have variable length when encoded, so just keep - // track of whether we've hit the end of the string. In each - // loop iteration, a single coordinate is decoded. - while ( index < str.length ) { - - // Reset shift, result, and byte - byte = null; - shift = 0; - result = 0; - - do { - byte = str.charCodeAt ( index ++ ) - 63; - result |= ( byte & 0x1f ) << shift; - shift += 5; - } while ( 0x20 <= byte ); - - latitude_change = ( ( result & 1 ) ? ~ ( result >> 1 ) : ( result >> 1 ) ); - - shift = result = 0; - - do { - byte = str.charCodeAt ( index ++ ) - 63; - result |= ( byte & 0x1f ) << shift; - shift += 5; - } while ( 0x20 <= byte ); - - longitude_change = ( ( result & 1 ) ? ~ ( result >> 1 ) : ( result >> 1 ) ); - - lat += latitude_change; - lng += longitude_change; - - coordinates.push ( [ lat / factor, lng / factor ] ); - } - - return coordinates; -}; - -/** - * Encodes the given [latitude, longitude] coordinates array. - * - * @param {Array.>} coordinates - * @param {Number} precision - * @returns {String} - */ - -polyline.encode = function ( coordinates, precision ) { - if ( ! coordinates.length ) { return ''; } - - let factor = Math.pow ( 10, Number.isInteger ( precision ) ? precision : 5 ), - output = encode ( coordinates[ 0 ][ 0 ], 0, factor ) + encode ( coordinates[ 0 ][ 1 ], 0, factor ); - - for ( let i = 1; i < coordinates.length; i ++ ) { - let a = coordinates[ i ], - b = coordinates[ i - 1 ]; - output += encode ( a[ 0 ], b[ 0 ], factor ); - output += encode ( a[ 1 ], b[ 1 ], factor ); - } - - return output; -}; - -function flipped ( coords ) { - let flipped = []; - for ( let i = 0; i < coords.length; i ++ ) { - let coord = coords[ i ].slice (); - flipped.push ( [ coord[ 1 ], coord[ 0 ] ] ); - } - return flipped; -} - -/** - * Encodes a GeoJSON LineString feature/geometry. - * - * @param {Object} geojson - * @param {Number} precision - * @returns {String} - */ - -polyline.fromGeoJSON = function ( geojson, precision ) { - if ( geojson && 'Feature' === geojson.type ) { - geojson = geojson.geometry; - } - if ( ! geojson || 'LineString' !== geojson.type ) { - throw new Error ( 'Input must be a GeoJSON LineString' ); +let polyline = { + + encode : function ( coordinates, precision ) { + if ( ! coordinates.length ) { + return ''; + } + + let factor = Math.pow ( NUMBER10, Number.isInteger ( precision ) ? precision : NUMBER5 ), + output = encode ( coordinates[ ZERO ][ ZERO ], ZERO, factor ) + encode ( coordinates[ ZERO ][ ONE ], ZERO, factor ); + + for ( let i = ONE; i < coordinates.length; i ++ ) { + let a = coordinates[ i ], + b = coordinates[ i - ONE ]; + output += encode ( a[ ZERO ], b[ ZERO ], factor ); + output += encode ( a[ ONE ], b[ ONE ], factor ); + } + + return output; + }, + + /* + --- myDecodePath function ----------------------------------------------------------------------------------------- + + Adapted from https://github.com/graphhopper/directions-api-js-client/blob/master/src/GHUtil.js + See GHUtil.prototype.decodePath + See also https://developers.google.com/maps/documentation/utilities/polylinealgorithm + Some adaptation for eslint and inverted lat and lng in the results... + + ------------------------------------------------------------------------------------------------------------------- + */ + + decode : function ( encodedString, precision, is3D = false ) { + + let index = ZERO; + let lat = ZERO; + let lng = ZERO; + let elev = ZERO; + let coordinates = []; + let factor = Math.pow ( NUMBER10, precision ); + + while ( index < encodedString.length ) { + let byte = null; + let shift = ZERO; + let result = ZERO; + do { + byte = encodedString.charCodeAt ( index ++ ) - NUMBER63; + result |= ( byte & NUMBER31 ) << shift; + shift += NUMBER5; + } while ( NUMBER32 <= byte ); + let deltaLat = ( ( result & ONE ) ? ~ ( result >> ONE ) : ( result >> ONE ) ); + lat += deltaLat; + + shift = ZERO; + result = ZERO; + do { + byte = encodedString.charCodeAt ( index ++ ) - NUMBER63; + result |= ( byte & NUMBER31 ) << shift; + shift += NUMBER5; + } while ( NUMBER32 <= byte ); + let deltaLon = ( ( result & ONE ) ? ~ ( result >> ONE ) : ( result >> ONE ) ); + lng += deltaLon; + + if ( is3D ) { + shift = ZERO; + result = ZERO; + do { + byte = encodedString.charCodeAt ( index ++ ) - NUMBER63; + result |= ( byte & NUMBER31 ) << shift; + shift += NUMBER5; + } while ( NUMBER32 <= byte ); + let deltaEle = ( ( result & ONE ) ? ~ ( result >> ONE ) : ( result >> ONE ) ); + elev += deltaEle; + coordinates.push ( [ lat / factor, lng / factor, elev / NUMBER100 ] ); + } + else { + coordinates.push ( [ lat / factor, lng / factor ] ); + } + } + + return coordinates; } - return polyline.encode ( flipped ( geojson.coordinates ), precision ); }; -/** - * Decodes to a GeoJSON LineString geometry. - * - * @param {String} str - * @param {Number} precision - * @returns {Object} - */ - -polyline.toGeoJSON = function ( str, precision ) { - let coords = polyline.decode ( str, precision ); - return { - type : 'LineString', - coordinates : flipped ( coords ) - }; -}; - -if ( 'object' === typeof module && module.exports ) { - module.exports = polyline; -} - export { polyline }; \ No newline at end of file diff --git a/src/polyline/Polyline.template b/src/polyline/Polyline.template deleted file mode 100644 index db4a9ae1..00000000 --- a/src/polyline/Polyline.template +++ /dev/null @@ -1,6 +0,0 @@ - -/*global module */ - -include "../../node_modules/@mapbox/polyline/src/Polyline.js" - -export { polyline }; diff --git a/src/util/Constants.js b/src/util/Constants.js index e8062464..7b9a5269 100644 --- a/src/util/Constants.js +++ b/src/util/Constants.js @@ -243,4 +243,6 @@ export const ONE = 1; export const TWO = 2; -export const SVG_NS = 'http://www.w3.org/2000/svg'; \ No newline at end of file +export const SVG_NS = 'http://www.w3.org/2000/svg'; + +export const HTTP_STATUS_OK = 200; \ No newline at end of file