1 | /* |
2 | Copyright - 2017 2023 - wwwouaiebe - Contact: https://www.ouaie.be/ |
3 | |
4 | This program is free software; |
5 | you can redistribute it and/or modify it under the terms of the |
6 | GNU General Public License as published by the Free Software Foundation; |
7 | either version 3 of the License, or any later version. |
8 | |
9 | This program is distributed in the hope that it will be useful, |
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
12 | GNU General Public License for more details. |
13 | |
14 | You should have received a copy of the GNU General Public License |
15 | along with this program; if not, write to the Free Software |
16 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
17 | */ |
18 | /* |
19 | Changes: |
20 | - v4.0.0: |
21 | - created from v3.6.0 |
22 | Doc reviewed 202208 |
23 | */ |
24 | |
25 | import { ZERO, LAT_LNG, HTTP_STATUS_OK } from '../main/Constants.js'; |
26 | import { SelectOptionData, SelectDialog } from '../dialogs/selectDialog/SelectDialog.js'; |
27 | import PublicTransportRouteBuilder from '../routeProviders/PublicTransportRouteBuilder.js'; |
28 | import BaseRouteProvider from '../routeProviders/BaseRouteProvider.js'; |
29 | |
30 | /* ------------------------------------------------------------------------------------------------------------------------- */ |
31 | /** |
32 | This class implements the BaseRouteProvider for PublicTransport. It's not possible to instanciate |
33 | this class because the class is not exported from the module. Only one instance is created and added to the list |
34 | of Providers of TravelNotes |
35 | */ |
36 | /* ------------------------------------------------------------------------------------------------------------------------- */ |
37 | |
38 | class PublicTransportRouteProvider extends BaseRouteProvider { |
39 | |
40 | /** |
41 | A reference to the edited route |
42 | @type {Route} |
43 | */ |
44 | |
45 | #route; |
46 | |
47 | /** |
48 | Parse the response from the provider and add the received itinerary to the route itinerary |
49 | @param {Object} waysNodes The ways and nodes received from OSM |
50 | @param {function} onOk a function to call when the response is parsed correctly |
51 | @param {function} onError a function to call when an error occurs |
52 | */ |
53 | |
54 | #parseResponse ( waysNodes, onOk, onError ) { |
55 | new PublicTransportRouteBuilder ( this.#route ).buildRoute ( waysNodes, onOk, onError ); |
56 | } |
57 | |
58 | /** |
59 | Get the url to obtains the ways and node Osm elements for the relation |
60 | @param {Number} relationId The osm relation id |
61 | @return {String} The complete url |
62 | */ |
63 | |
64 | #getWaysNodesUrl ( relationId ) { |
65 | return window.TaN.overpassApiUrl + '?data=[out:json];rel(' + |
66 | relationId.toFixed ( ZERO ) + |
67 | ');way(r)->.e;way.e["railway"="rail"];(._;>;rel(' + |
68 | relationId.toFixed ( ZERO ) + |
69 | '););out;'; |
70 | } |
71 | |
72 | /** |
73 | Show a SelectDialog with all the train relations between the start point and end point |
74 | @param {Array.<Object>} relations The relations received from OSM |
75 | @return {Promise} The Promise created by the selectDialog.show ( ) |
76 | */ |
77 | |
78 | #getDialogPromise ( relations ) { |
79 | |
80 | if ( ZERO === relations.elements.length ) { |
81 | return Promise.reject ( new Error ( 'No relations found' ) ); |
82 | } |
83 | |
84 | const selectOptionsData = []; |
85 | relations.elements.forEach ( |
86 | relationElement => { |
87 | selectOptionsData.push ( new SelectOptionData ( relationElement.tags.name, relationElement.id ) ); |
88 | } |
89 | ); |
90 | |
91 | const selectDialog = new SelectDialog ( |
92 | { |
93 | title : 'Relations', |
94 | text : 'select a relation : ', |
95 | selectOptionsData : selectOptionsData |
96 | } |
97 | ); |
98 | |
99 | // baseDialog.show ( ) return a Promise... |
100 | return selectDialog.show ( ); |
101 | |
102 | } |
103 | |
104 | /** |
105 | The url to use to have the relations between the start point and end point |
106 | @type {String} |
107 | */ |
108 | |
109 | get #relationsUrl ( ) { |
110 | return window.TaN.overpassApiUrl + |
111 | '?data=[out:json];node["public_transport"="stop_position"]["train"="yes"](around:400.0,' + |
112 | this.#route.wayPoints.first.lat.toFixed ( LAT_LNG.fixed ) + |
113 | ',' + |
114 | this.#route.wayPoints.first.lng.toFixed ( LAT_LNG.fixed ) + |
115 | ')->.s;rel(bn.s)->.s;node["public_transport"="stop_position"]["train"="yes"](around:400.0,' + |
116 | this.#route.wayPoints.last.lat.toFixed ( LAT_LNG.fixed ) + |
117 | ',' + |
118 | this.#route.wayPoints.last.lng.toFixed ( LAT_LNG.fixed ) + |
119 | ')->.e;rel(bn.e)->.e;rel.e.s;out tags;'; |
120 | } |
121 | |
122 | /** |
123 | call the provider, wait for the response and then parse the provider response. Notice that we have two calls to the |
124 | Provider: one for the relation list and one for the ways and nodes. Notice also the dialog box between the 2 calls. |
125 | @param {function} onOk a function to pass to the ourParseResponse |
126 | @param {function} onError a function to pass to ourParseResponse or to call when an error occurs |
127 | */ |
128 | |
129 | #getRoute ( onOk, onError ) { |
130 | fetch ( this.#relationsUrl ) |
131 | .then ( |
132 | responseRelations => { |
133 | if ( HTTP_STATUS_OK === responseRelations.status && responseRelations.ok ) { |
134 | responseRelations.json ( ) |
135 | .then ( relations => this.#getDialogPromise ( relations ) ) |
136 | .then ( relationId => fetch ( this.#getWaysNodesUrl ( relationId ) ) ) |
137 | .then ( |
138 | responseWaysNodes => { |
139 | if ( HTTP_STATUS_OK === responseWaysNodes.status && responseWaysNodes.ok ) { |
140 | responseWaysNodes.json ( ) |
141 | .then ( waysNodes => this.#parseResponse ( waysNodes, onOk, onError ) ); |
142 | } |
143 | else { |
144 | onError ( new Error ( 'An error occurs...' ) ); |
145 | } |
146 | } |
147 | ) |
148 | .catch ( ( ) => onError ( new Error ( 'An error occurs...' ) ) ); |
149 | } |
150 | else { |
151 | onError ( new Error ( 'An error occurs...' ) ); |
152 | } |
153 | } |
154 | ) |
155 | .catch ( |
156 | |
157 | // calling onError without parameters because fetch don't accecpt to add something as parameter :-(... |
158 | ( ) => { onError ( ); } |
159 | ); |
160 | |
161 | } |
162 | |
163 | /** |
164 | The constructor |
165 | */ |
166 | |
167 | constructor ( ) { |
168 | super ( ); |
169 | } |
170 | |
171 | /** |
172 | Call the provider, using the waypoints defined in the route and, on success, |
173 | complete the route with the data from the provider |
174 | @param {Route} route The route to witch the data will be added |
175 | @return {Promise} A Promise. On success, the Route is completed with the data given by the provider. |
176 | */ |
177 | |
178 | getPromiseRoute ( route ) { |
179 | this.#route = route; |
180 | return new Promise ( ( onOk, onError ) => this.#getRoute ( onOk, onError ) ); |
181 | } |
182 | |
183 | /** |
184 | The icon used in the ProviderToolbarUI. |
185 | Overload of the base class icon property |
186 | @type {String} |
187 | */ |
188 | |
189 | get icon ( ) { |
190 | return 'data:image/svg+xml;utf8,' + |
191 | '<svg viewBox="-3 -3 20 20" xmlns="http://www.w3.org/2000/svg"> <g fill="rgb(128,0,0)">' + |
192 | '<path d="M 5,0 C 3.025911,-0.0084 1,3 1,7 l 0,2 c 0,1 1,2 2,2 l 8,0 c 1,0 2,-1 2,-2 L 13,7 C 13,3 11,0 9,0 z m ' + |
193 | '-1,3 6,0 c 0,0 1,1 1,3 L 3.03125,6 C 2.994661,3.9916 4,3 4,3 z M 3,8 6,8 6,9 3,9 z m 5,0 3,0 0,1 -3,0 z m -6,4 ' + |
194 | '-1,2 3,0 1,-2 z m 7,0 1,2 3,0 -1,-2 z"/></g></svg>'; |
195 | } |
196 | |
197 | /** |
198 | The provider name. |
199 | Overload of the base class name property |
200 | @type {String} |
201 | */ |
202 | |
203 | get name ( ) { return 'PublicTransport'; } |
204 | |
205 | /** |
206 | The title to display in the ProviderToolbarUI button. |
207 | Overload of the base class title property |
208 | @type {String} |
209 | */ |
210 | |
211 | get title ( ) { return 'Public Transport on OpenStreetMap'; } |
212 | |
213 | /** |
214 | The possible transit modes for the provider. |
215 | Overload of the base class transitModes property |
216 | Must be a subarray of [ 'bike', 'pedestrian', 'car', 'train', 'line', 'circle' ] |
217 | @type {Array.<String>} |
218 | */ |
219 | |
220 | get transitModes ( ) { return [ 'train' ]; } |
221 | |
222 | /** |
223 | A boolean indicating when a provider key is needed for the provider. |
224 | Overload of the base class providerKeyNeeded property |
225 | @type {Boolean} |
226 | */ |
227 | |
228 | get providerKeyNeeded ( ) { return false; } |
229 | } |
230 | |
231 | window.TaN.addProvider ( PublicTransportRouteProvider ); |
232 | |
233 | /* --- End of file --------------------------------------------------------------------------------------------------------- */ |
234 |