1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | |
18 | |
19 | |
20 | |
21 | |
22 | |
23 | |
24 | |
25 | import PolylineEncoder from '../core/lib/PolylineEncoder.js'; |
26 | import ItineraryPoint from '../data/ItineraryPoint.js'; |
27 | import Maneuver from '../data/Maneuver.js'; |
28 | import BaseRouteProvider from '../routeProviders/BaseRouteProvider.js'; |
29 | |
30 | import { ZERO, TWO, LAT, LNG, ELEVATION, LAT_LNG, HTTP_STATUS_OK, DISTANCE } from '../main/Constants.js'; |
31 | |
32 | |
33 | |
34 | |
35 | |
36 | |
37 | |
38 | class GraphHopperRouteProvider extends BaseRouteProvider { |
39 | |
40 | |
41 | |
42 | |
43 | |
44 | |
45 | #providerKey; |
46 | |
47 | |
48 | |
49 | |
50 | |
51 | |
52 | #route; |
53 | |
54 | |
55 | |
56 | |
57 | |
58 | |
59 | static get #ROUND_VALUE ( ) { return 5; } |
60 | |
61 | |
62 | |
63 | |
64 | |
65 | |
66 | static get #ICON_LIST ( ) { |
67 | return [ |
68 | 'kUndefined', |
69 | 'kTurnSharpLeft', |
70 | 'kTurnLeft', |
71 | 'kTurnSlightLeft', |
72 | 'kContinueStraight', |
73 | 'kTurnSlightRight', |
74 | 'kTurnRight', |
75 | 'kTurnSharpRight', |
76 | 'kArriveDefault', |
77 | 'kArriveDefault', |
78 | 'kRoundaboutRight' |
79 | ]; |
80 | } |
81 | |
82 | |
83 | |
84 | |
85 | |
86 | |
87 | |
88 | |
89 | #parseResponse ( response, onOk, onError ) { |
90 | |
91 | if ( ZERO === response.paths.length ) { |
92 | onError ( 'Route not found' ); |
93 | return; |
94 | } |
95 | |
96 | const polylineEncoder = new PolylineEncoder ( ); |
97 | this.#route.itinerary.itineraryPoints.removeAll ( ); |
98 | this.#route.itinerary.maneuvers.removeAll ( ); |
99 | this.#route.itinerary.hasProfile = true; |
100 | this.#route.itinerary.ascent = ZERO; |
101 | this.#route.itinerary.descent = ZERO; |
102 | response.paths.forEach ( |
103 | path => { |
104 | path.points = polylineEncoder.decode ( |
105 | path.points, |
106 | [ GraphHopperRouteProvider.#ROUND_VALUE, GraphHopperRouteProvider.#ROUND_VALUE, TWO ] |
107 | ); |
108 | |
109 | path.snapped_waypoints = polylineEncoder.decode ( |
110 | path.snapped_waypoints, |
111 | [ GraphHopperRouteProvider.#ROUND_VALUE, GraphHopperRouteProvider.#ROUND_VALUE, TWO ] |
112 | ); |
113 | const itineraryPoints = []; |
114 | for ( let pointsCounter = ZERO; pointsCounter < path.points.length; pointsCounter ++ ) { |
115 | const itineraryPoint = new ItineraryPoint ( ); |
116 | itineraryPoint.lat = path.points [ pointsCounter ] [ LAT ]; |
117 | itineraryPoint.lng = path.points [ pointsCounter ] [ LNG ]; |
118 | itineraryPoint.elev = path.points [ pointsCounter ] [ ELEVATION ]; |
119 | itineraryPoints.push ( itineraryPoint ); |
120 | this.#route.itinerary.itineraryPoints.add ( itineraryPoint ); |
121 | } |
122 | |
123 | let previousIconName = ''; |
124 | path.instructions.forEach ( |
125 | instruction => { |
126 | const maneuver = new Maneuver ( ); |
127 | |
128 | maneuver.iconName = GraphHopperRouteProvider.#ICON_LIST [ instruction.sign + 4 || ZERO ]; |
129 | if ( 'kArriveDefault' === previousIconName && 'kContinueStraight' === maneuver.iconName ) { |
130 | maneuver.iconName = 'kDepartDefault'; |
131 | } |
132 | previousIconName = maneuver.iconName; |
133 | maneuver.instruction = instruction.text || ''; |
134 | maneuver.duration = instruction.time / DISTANCE.metersInKm; |
135 | maneuver.distance = instruction.distance; |
136 | maneuver.itineraryPointObjId = itineraryPoints [ instruction.interval [ ZERO ] ].objId; |
137 | this.#route.itinerary.maneuvers.add ( maneuver ); |
138 | |
139 | } |
140 | ); |
141 | |
142 | const wayPointsIterator = this.#route.wayPoints.iterator; |
143 | path.snapped_waypoints.forEach ( |
144 | latLngElev => { |
145 | if ( ! wayPointsIterator.done ) { |
146 | wayPointsIterator.value.lat = latLngElev [ LAT ]; |
147 | wayPointsIterator.value.lng = latLngElev [ LNG ]; |
148 | } |
149 | } |
150 | ); |
151 | } |
152 | ); |
153 | |
154 | onOk ( this.#route ); |
155 | } |
156 | |
157 | |
158 | |
159 | |
160 | |
161 | |
162 | #getUrl ( ) { |
163 | let wayPointsString = null; |
164 | this.#route.wayPoints.forEach ( |
165 | wayPoint => { |
166 | wayPointsString = wayPointsString ? wayPointsString + '&' : ''; |
167 | wayPointsString += |
168 | 'point=' + |
169 | wayPoint.lat.toFixed ( LAT_LNG.fixed ) + ',' + |
170 | wayPoint.lng.toFixed ( LAT_LNG.fixed ); |
171 | } |
172 | ); |
173 | |
174 | let vehicle = ''; |
175 | switch ( this.#route.itinerary.transitMode ) { |
176 | case 'bike' : |
177 | vehicle = 'bike'; |
178 | break; |
179 | case 'pedestrian' : |
180 | vehicle = 'foot'; |
181 | break; |
182 | case 'car' : |
183 | vehicle = 'car'; |
184 | break; |
185 | default : |
186 | break; |
187 | } |
188 | |
189 | return 'https://graphhopper.com/api/1/route?' + wayPointsString + |
190 | '&instructions=true&elevation=true&type=json&key=' + this.#providerKey + '&locale=' + this.userLanguage + |
191 | '&vehicle=' + vehicle; |
192 | } |
193 | |
194 | |
195 | |
196 | |
197 | |
198 | |
199 | |
200 | #getRoute ( onOk, onError ) { |
201 | fetch ( this.#getUrl ( ) ) |
202 | .then ( |
203 | response => { |
204 | if ( HTTP_STATUS_OK === response.status && response.ok ) { |
205 | response.json ( ) |
206 | .then ( result => this.#parseResponse ( result, onOk, onError ) ); |
207 | } |
208 | else { |
209 | onError ( new Error ( 'Invalid status ' + response.status ) ); |
210 | } |
211 | } |
212 | ) |
213 | .catch ( |
214 | |
215 | |
216 | ( ) => { onError ( ); } |
217 | ); |
218 | } |
219 | |
220 | |
221 | |
222 | |
223 | |
224 | constructor ( ) { |
225 | super ( ); |
226 | this.#providerKey = ''; |
227 | } |
228 | |
229 | |
230 | |
231 | |
232 | |
233 | |
234 | |
235 | |
236 | getPromiseRoute ( route ) { |
237 | this.#route = route; |
238 | return new Promise ( ( onOk, onError ) => this.#getRoute ( onOk, onError ) ); |
239 | } |
240 | |
241 | |
242 | |
243 | |
244 | |
245 | |
246 | |
247 | get icon ( ) { |
248 | return '' + |
249 | 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAeCAIAAAC0Ujn1AAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3' + |
250 | 'RJTUUH4AocDyYTxtPEYwAABGtJREFUSMedVU1MXFUUPue+9+bNAMMUZrCFVAsiDEGpJlpdtCY0sTU1xIA1QNSNIcYGuyAuxBp1oU' + |
251 | '1DYu2iNlKsJopVYy2lkpiyoCCptLWF1DKFkpb/YShvmBmYX97/dUECw5sBpj2r97577pdzv3vud/BLzw8XF3s5ZGG9QAQA0CggAE' + |
252 | 'GgFDYLRVffsu/HUlcNAyQ5J0NApzGXXxwLKvNLhCNcbrqlNJvfYaWavjE7hyzLIUuTFYIskd2RByduRfu9im9pBed3ZG79oCzr9Q' + |
253 | 'KqrMtOgXLIrquDOBqcONQjeyIGXJoKTX/URyUtu6aIStoGhZOk4mpBeeL97kTelXB/dj3QPoYseThq5HD6yFV5Npq4xMadcvZof8' + |
254 | 'zlRwZTpUYTE7w0Fb4ya8CLi4vb2toGBgZ6enpqa2sBQAvLvtYRLaauR52gNaW+s/cMWGFhYUdHh9PpXP4tLy/Pz89vamqSugXze7' + |
255 | 'r8JJMCNcGl4YDkDq/BCGloaHA6nVPy3GnvhZvRYQdrq/n0QFrzqVgw8sQV03gh6lTfRBBEEO8F1YAYD9rt9sP1hyflB4cmm9oDPY' + |
256 | 'Lsd8XGjkyfsrxgB4DB367tztipUHUTaqqDNBMxNGxlZSUQOOO96JG9PDERJCwyZjSpqAPAqGd898xTKtE2o1Z1bUE0ZFRUVLiptz' + |
257 | '96FyC+GVAcCy5/3fnr5nO2Ei1BE2K4w8Q3VlJSMhpzT8tzGHclakCUJkLLf5c6O19z7EnUhBhMg8ngDBnhaOSuOBlvBsTC+n9d7a' + |
258 | 'KhoaFnYAcibkjNoml7BqzNOd92PsyKqzsJKt6Y7+eRlQRZlsNTC9t4OwW6vtYULE9ncw5LPPj18eOuvluEEkAABH1Jnfn8XzUsx+' + |
259 | 'f4Zrx55hy6UV/rNG2nw7onN9A+vmq+kvLLmydyDjotpVm6rC92TkWuzxnOHvWHHivNAqDxV218jVSneY3PZ4+yo664N7lE58+ObO' + |
260 | 'T9MdnGWuka5kR70qmeTvb9/u6B8lch5WCBSSPmzTwEgAWmV/3vWPsnb5w72NxyWhAERVEopQzD8DwviqIgCIYtNmtmAOQU/BqARe' + |
261 | 'bY7I+Z7xQODAy4+m/3Xv67u6v7Wt9V1+3B6urqxPxtubmJNoLP3nk76QBbHkIFfN5e264XM0rzTA4GiFvwvOJ8ORQJGZIDiwsnY2' + |
262 | '1/+LoYJMt704h53QGGgCrV7ovu+6L7O+HC8rQUml2JvEVFRVm2LYvBEKYiSLKZgap/Sfh2MHGlvr4+CpJXCcDaB5kqNTEznqP9VD' + |
263 | 'VKl5OTU1dXJ8i+McnziFVTSdtaXwZ5vAFvaWmxWq03wsMLagjhkaqmGiX56Sdv/PTxh422TBvP8w6Ho7W1taqqSqHKGV+7CblUOy' + |
264 | 'RpZLOZXxU3lGkF8x5he/7jAKBQ9YvZ78/5u8yEj++uNGLGUlcNC0yK1DpQC5r2btm13/ZSHueYleb/XOi9HOpnkVnbuGBCBhvd33' + |
265 | 'Qs/MMhAw8TPHIssirVJConsRSq1tr3/Q+O4QqEHeMWIQAAAABJRU5ErkJggg=='; |
266 | } |
267 | |
268 | |
269 | |
270 | |
271 | |
272 | |
273 | |
274 | get name ( ) { return 'GraphHopper'; } |
275 | |
276 | |
277 | |
278 | |
279 | |
280 | |
281 | |
282 | get title ( ) { return 'GraphHopper'; } |
283 | |
284 | |
285 | |
286 | |
287 | |
288 | |
289 | |
290 | |
291 | get transitModes ( ) { return [ 'bike', 'pedestrian', 'car' ]; } |
292 | |
293 | |
294 | |
295 | |
296 | |
297 | |
298 | |
299 | get providerKeyNeeded ( ) { return true; } |
300 | |
301 | |
302 | |
303 | |
304 | |
305 | |
306 | set providerKey ( providerKey ) { this.#providerKey = providerKey; } |
307 | } |
308 | |
309 | window.TaN.addProvider ( GraphHopperRouteProvider ); |
310 | |
311 | |
312 | |