File : routeProviders/PublicTransportRouteProvider.js

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