@geops/rvf-mobility-web-component 0.1.23 → 0.1.24

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,312 @@
1
+ import { FeatureCollection, Point } from "geojson";
2
+ import { gql, GraphQLClient } from "graphql-request";
3
+ import { Extent } from "ol/extent";
4
+
5
+ import { RVF_EXTENT_4326 } from "./constants";
6
+
7
+ const GQL_URL = "https://api.mobidata-bw.de/sharing/graphql";
8
+
9
+ export interface SharingStation {
10
+ id: string;
11
+ lat: number;
12
+ lon: number;
13
+ name: {
14
+ translation: {
15
+ language: string;
16
+ value: string;
17
+ };
18
+ };
19
+ numVehiclesAvailable: number;
20
+ system: {
21
+ id: string;
22
+ name: {
23
+ translation: {
24
+ language: string;
25
+ value: string;
26
+ };
27
+ };
28
+ operator: {
29
+ id: string;
30
+ name: {
31
+ translation: {
32
+ language: string;
33
+ value: string;
34
+ };
35
+ };
36
+ };
37
+ shortName: {
38
+ translation: {
39
+ language: string;
40
+ value: string;
41
+ };
42
+ };
43
+ };
44
+ }
45
+
46
+ const queryStation = gql`
47
+ query station($id: String!) {
48
+ station(id: $id) {
49
+ name {
50
+ translation {
51
+ language
52
+ value
53
+ }
54
+ }
55
+ shortName {
56
+ translation {
57
+ language
58
+ value
59
+ }
60
+ }
61
+ lat
62
+ lon
63
+ region {
64
+ id
65
+ }
66
+ rentalUris {
67
+ android
68
+ ios
69
+ web
70
+ }
71
+ isVirtualStation
72
+ rentalMethods
73
+ parkingHoop
74
+ parkingType
75
+ contactPhone
76
+ address
77
+ rentalMethods
78
+ capacity
79
+ vehicleTypesAvailable {
80
+ count
81
+ vehicleType {
82
+ id
83
+ formFactor
84
+ riderCapacity
85
+ cargoVolumeCapacity
86
+ cargoLoadCapacity
87
+ propulsionType
88
+ ecoLabels {
89
+ countryCode
90
+ ecoSticker
91
+ }
92
+ maxRangeMeters
93
+ name {
94
+ translation {
95
+ language
96
+ value
97
+ }
98
+ }
99
+ description {
100
+ translation {
101
+ language
102
+ value
103
+ }
104
+ }
105
+ vehicleAccessories
106
+ gCO2km
107
+ vehicleImage
108
+ make
109
+ model
110
+ color
111
+ wheelCount
112
+ maxPermittedSpeed
113
+ ratedPower
114
+ defaultReserveTime
115
+ returnConstraint
116
+ vehicleAssets {
117
+ iconUrl
118
+ iconUrlDark
119
+ iconLastModified
120
+ }
121
+ defaultReserveTime
122
+ defaultPricingPlan {
123
+ id
124
+ url
125
+ currency
126
+ isTaxable
127
+ description {
128
+ translation {
129
+ language
130
+ value
131
+ }
132
+ }
133
+ perKmPricing {
134
+ start
135
+ rate
136
+ interval
137
+ end
138
+ }
139
+ perMinPricing {
140
+ start
141
+ rate
142
+ interval
143
+ end
144
+ }
145
+ surgePricing
146
+ }
147
+ }
148
+ count
149
+ }
150
+ vehicleDocksCapacity {
151
+ vehicleTypes {
152
+ id
153
+ }
154
+ count
155
+ }
156
+ numVehiclesAvailable
157
+ numDocksDisabled
158
+ numVehiclesDisabled
159
+ numDocksAvailable
160
+ isInstalled
161
+ isRenting
162
+ isReturning
163
+ pricingPlans {
164
+ id
165
+ url
166
+ currency
167
+ isTaxable
168
+ description {
169
+ translation {
170
+ language
171
+ value
172
+ }
173
+ }
174
+ perKmPricing {
175
+ start
176
+ rate
177
+ interval
178
+ end
179
+ }
180
+ perMinPricing {
181
+ start
182
+ rate
183
+ interval
184
+ end
185
+ }
186
+ surgePricing
187
+ }
188
+ }
189
+ }
190
+ `;
191
+ const queryStations = gql`
192
+ query stations(
193
+ $ids: [String!]
194
+ $minimumLatitude: Float
195
+ $minimumLongitude: Float
196
+ $maximumLatitude: Float
197
+ $maximumLongitude: Float
198
+ $systems: [System!]
199
+ $operators: [Operator!]
200
+ $availableFormFactors: [FormFactor!]
201
+ ) {
202
+ stations(
203
+ ids: $ids
204
+ minimumLatitude: $minimumLatitude
205
+ minimumLongitude: $minimumLongitude
206
+ maximumLatitude: $maximumLatitude
207
+ maximumLongitude: $maximumLongitude
208
+ operators: $operators
209
+ availableFormFactors: $availableFormFactors
210
+ ) {
211
+ lon
212
+ id
213
+ lat
214
+ name {
215
+ translation {
216
+ language
217
+ value
218
+ }
219
+ }
220
+ numVehiclesAvailable
221
+ system {
222
+ id
223
+ name {
224
+ translation {
225
+ language
226
+ value
227
+ }
228
+ }
229
+ shortName {
230
+ translation {
231
+ language
232
+ value
233
+ }
234
+ }
235
+ operator {
236
+ id
237
+ name {
238
+ translation {
239
+ language
240
+ value
241
+ }
242
+ }
243
+ }
244
+ }
245
+ }
246
+ }
247
+ `;
248
+
249
+ export const fetchSharingStation = async (id: string) => {
250
+ const client = new GraphQLClient(GQL_URL, {
251
+ method: "GET",
252
+ });
253
+ const { station }: { station: unknown } = await client.request(queryStation, {
254
+ __operation: "station",
255
+ id: id,
256
+ });
257
+ return station;
258
+ };
259
+
260
+ export const fetchSharingStations = async (
261
+ ids: null | string[],
262
+ extent: Extent = RVF_EXTENT_4326,
263
+ operators: null | string[] = null,
264
+ abortController: AbortController,
265
+ ) => {
266
+ const client = new GraphQLClient(
267
+ "https://api.mobidata-bw.de/sharing/graphql",
268
+ {
269
+ method: "GET",
270
+ signal: abortController.signal,
271
+ },
272
+ );
273
+ const { stations }: { stations: SharingStation[] } = await client.request(
274
+ queryStations,
275
+ {
276
+ // availableFormFactors: ["BICYCLE"],
277
+ // id: "NBK:Station:33269707",
278
+ ids: ids,
279
+ maximumLatitude: extent?.[3],
280
+ maximumLongitude: extent?.[2],
281
+ minimumLatitude: extent?.[1],
282
+ minimumLongitude: extent?.[0],
283
+ operators: operators, //["BK:Operator:nextbike"],
284
+ },
285
+ );
286
+ const featureCollection: FeatureCollection<Point, SharingStation> = {
287
+ features: stations.map((station: SharingStation) => {
288
+ return {
289
+ geometry: {
290
+ coordinates: [station.lon, station.lat],
291
+ type: "Point",
292
+ },
293
+ properties: {
294
+ ...station,
295
+ num_vehicles_available: station.numVehiclesAvailable,
296
+ provider_name: station.system.name.translation[0].value.replace(
297
+ "Freiburg",
298
+ "",
299
+ ),
300
+ station_id: station.id,
301
+ },
302
+ type: "Feature",
303
+ };
304
+ }),
305
+ type: "FeatureCollection",
306
+ };
307
+ return featureCollection;
308
+ };
309
+
310
+ export default {
311
+ fetchSharingStations,
312
+ };
@@ -0,0 +1,222 @@
1
+ export const getSharingStyleLayers = (
2
+ sourceId: string,
3
+ image = "rvf_shared_bike",
4
+ ) => {
5
+ return [
6
+ {
7
+ id: sourceId + "_circle",
8
+ maxZoom: 16,
9
+ minzoom: 11,
10
+ paint: {
11
+ "circle-color": "#00973b",
12
+ "circle-radius": 4,
13
+ "circle-stroke-color": "rgba(255, 255, 255, 1)",
14
+ "circle-stroke-width": 0.5,
15
+ },
16
+ source: sourceId,
17
+ type: "circle",
18
+ },
19
+ {
20
+ id: sourceId + "_image_text",
21
+ layout: {
22
+ "icon-image": image,
23
+ "icon-size": 1,
24
+ "symbol-z-order": "auto",
25
+ "text-anchor": "top",
26
+ "text-field": {
27
+ stops: [
28
+ [15, ""],
29
+ [16, "{provider_name}"],
30
+ ],
31
+ },
32
+ "text-font": ["SourceSansPro-Bold"],
33
+ "text-justify": "center",
34
+ "text-letter-spacing": 0.04,
35
+ "text-line-height": 1.1,
36
+ "text-max-width": 6,
37
+ "text-optional": true,
38
+ "text-radial-offset": 1.5,
39
+ "text-size": 12,
40
+ visibility: "visible",
41
+ },
42
+ minzoom: 14,
43
+ paint: {
44
+ "text-color": "rgba(6, 76, 10, 1)",
45
+ "text-halo-blur": 0.5,
46
+ "text-halo-color": "rgba(255, 255, 255, 1)",
47
+ "text-halo-width": 2,
48
+ },
49
+ source: sourceId,
50
+ type: "symbol",
51
+ },
52
+ {
53
+ filter: ["==", "is_free_float", false],
54
+ id: sourceId + "_availability",
55
+ layout: {
56
+ "icon-allow-overlap": true,
57
+ "icon-anchor": "center",
58
+ "icon-ignore-placement": true,
59
+ "icon-image": "10-contour-big-grey",
60
+ "icon-offset": [20, -18],
61
+ "icon-overlap": "always",
62
+ "icon-size": 0.6,
63
+ "symbol-z-order": "auto",
64
+ "text-allow-overlap": true,
65
+ "text-field": {
66
+ stops: [
67
+ [15, ""],
68
+ [16, "{num_vehicles_available}"],
69
+ ],
70
+ },
71
+ "text-font": ["SourceSansPro-Bold"],
72
+ "text-ignore-placement": true,
73
+ "text-justify": "center",
74
+ "text-offset": [1.2, -1],
75
+ "text-overlap": "always",
76
+ "text-size": 10,
77
+ visibility: "visible",
78
+ },
79
+ minzoom: 16,
80
+ paint: {
81
+ "text-color": "rgba(6, 76, 10, 1)",
82
+ },
83
+ source: sourceId,
84
+ type: "symbol",
85
+ },
86
+ // freefloat style
87
+ {
88
+ filter: ["==", "is_free_float", true],
89
+ id: sourceId + "_availability_freefloat",
90
+ layout: {
91
+ "icon-allow-overlap": true,
92
+ "icon-anchor": "center",
93
+ "icon-ignore-placement": true,
94
+ "icon-image": "10-contour-big-grey",
95
+ "icon-offset": [-20, -18],
96
+ "icon-overlap": "always",
97
+ "icon-size": 0.6,
98
+ "symbol-z-order": "auto",
99
+ "text-allow-overlap": true,
100
+ "text-field": "1",
101
+ "text-font": ["SourceSansPro-Bold"],
102
+ "text-ignore-placement": true,
103
+ "text-justify": "center",
104
+ "text-offset": [-1.2, -1],
105
+ "text-overlap": "always",
106
+ "text-size": 10,
107
+ visibility: "visible",
108
+ },
109
+ minzoom: 16,
110
+ paint: {
111
+ "text-color": "rgba(6, 76, 10, 1)",
112
+ },
113
+ source: sourceId,
114
+ type: "symbol",
115
+ },
116
+ ];
117
+ };
118
+
119
+ export const getSharingClusterStyleLayers = (
120
+ sourceId: string,
121
+ image = "rvf_shared_bike",
122
+ ) => {
123
+ return [
124
+ {
125
+ id: sourceId + "_image_text",
126
+ layout: {
127
+ "icon-allow-overlap": true,
128
+ "icon-ignore-placement": true,
129
+ "icon-image": image,
130
+ "icon-size": 1,
131
+ "symbol-z-order": "auto",
132
+ "text-allow-overlap": true,
133
+ "text-anchor": "top",
134
+ "text-field": {
135
+ stops: [
136
+ [15, ""],
137
+ [16, "{provider_name}"],
138
+ ],
139
+ },
140
+ "text-font": ["SourceSansPro-Bold"],
141
+ "text-ignore-placement": true,
142
+ "text-justify": "center",
143
+ "text-letter-spacing": 0.04,
144
+ "text-line-height": 1.1,
145
+ "text-max-width": 6,
146
+ "text-optional": true,
147
+ "text-radial-offset": 1.5,
148
+ "text-size": 12,
149
+ visibility: "visible",
150
+ },
151
+ minzoom: 14,
152
+ paint: {
153
+ "text-color": "rgba(6, 76, 10, 1)",
154
+ "text-halo-blur": 0.5,
155
+ "text-halo-color": "rgba(255, 255, 255, 1)",
156
+ "text-halo-width": 2,
157
+ },
158
+ source: sourceId,
159
+ type: "symbol",
160
+ },
161
+ // cluster style
162
+ {
163
+ filter: ["has", "point_count"],
164
+ id: sourceId + "_availability2",
165
+ layout: {
166
+ "icon-allow-overlap": true,
167
+ "icon-anchor": "center",
168
+ "icon-ignore-placement": true,
169
+ "icon-image": "10-contour-big-grey",
170
+ "icon-offset": [-20, -18],
171
+ "icon-overlap": "always",
172
+ "icon-size": 0.6,
173
+ "symbol-z-order": "auto",
174
+ "text-allow-overlap": true,
175
+ "text-field": "{point_count}",
176
+ "text-font": ["SourceSansPro-Bold"],
177
+ "text-ignore-placement": true,
178
+ "text-justify": "center",
179
+ "text-offset": [-1.2, -1],
180
+ "text-overlap": "always",
181
+ "text-size": 10,
182
+ visibility: "visible",
183
+ },
184
+ minzoom: 16,
185
+ paint: {
186
+ "text-color": "rgba(6, 76, 10, 1)",
187
+ },
188
+ source: sourceId,
189
+ type: "symbol",
190
+ },
191
+ // non cluster style
192
+ {
193
+ filter: ["!", ["has", "point_count"]],
194
+ id: sourceId + "_availability3",
195
+ layout: {
196
+ "icon-allow-overlap": true,
197
+ "icon-anchor": "center",
198
+ "icon-ignore-placement": true,
199
+ "icon-image": "10-contour-big-grey",
200
+ "icon-offset": [-20, -18],
201
+ "icon-overlap": "always",
202
+ "icon-size": 0.6,
203
+ "symbol-z-order": "auto",
204
+ "text-allow-overlap": true,
205
+ "text-field": "1",
206
+ "text-font": ["SourceSansPro-Bold"],
207
+ "text-ignore-placement": true,
208
+ "text-justify": "center",
209
+ "text-offset": [-1.2, -1],
210
+ "text-overlap": "always",
211
+ "text-size": 10,
212
+ visibility: "visible",
213
+ },
214
+ minzoom: 16,
215
+ paint: {
216
+ "text-color": "rgba(6, 76, 10, 1)",
217
+ },
218
+ source: sourceId,
219
+ type: "symbol",
220
+ },
221
+ ];
222
+ };
@@ -0,0 +1,74 @@
1
+ import { Feature, FeatureCollection, Point } from "geojson";
2
+ import { Extent } from "ol/extent";
3
+
4
+ import { PROVIDER_BY_FEED_ID, RVF_EXTENT_4326 } from "./constants";
5
+
6
+ export interface SharingStationWFS {
7
+ capacity: string;
8
+ feed_id: string;
9
+ id: string; // added dynamically same as station_id
10
+ is_free_float: false; // added dynamically
11
+ last_reported: string;
12
+ name: string;
13
+ num_vehicles_available: number;
14
+ provider_name: string; // added dynamically
15
+ rental_uris_android: string;
16
+ rental_uris_ios: string;
17
+ rental_uris_web: string;
18
+ station_id: string;
19
+ }
20
+ export interface SharingVehicleWFS {
21
+ current_fuel_percent: number;
22
+ current_range_meters: number;
23
+ feed_id: string;
24
+ form_factor: string;
25
+ id: string; // added dynamically station_id or vehicle_id
26
+ is_free_float: true; // added dynamically
27
+ last_reported: string;
28
+ max_range_meters: number;
29
+ name: null;
30
+ propulsion_type: string;
31
+ provider_name: string; // added dynamically
32
+ rental_uris_android: null;
33
+ rental_uris_ios: null;
34
+ rental_uris_web: null;
35
+ station_id: string;
36
+ vehicle_id: string;
37
+ }
38
+
39
+ export const fetchSharingWFS = async (
40
+ wfsTypeName: string,
41
+ abortController: AbortController,
42
+ extent4326: Extent = RVF_EXTENT_4326,
43
+ ) => {
44
+ // use WFS
45
+ const url =
46
+ "https://api.mobidata-bw.de/geoserver/MobiData-BW/" +
47
+ wfsTypeName +
48
+ "/ows" +
49
+ "?service=WFS&" +
50
+ "version=1.1.0&request=GetFeature&typename=" +
51
+ "MobiData-BW:" +
52
+ wfsTypeName +
53
+ "&" +
54
+ "outputFormat=application/json&" +
55
+ "bbox=" +
56
+ extent4326.toString() +
57
+ ",EPSG:4326";
58
+ const response = await fetch(url, { signal: abortController.signal });
59
+ const data = await response.json();
60
+
61
+ data?.features.forEach(
62
+ (feature: Feature<Point, SharingStationWFS | SharingVehicleWFS>) => {
63
+ const vehicleId = (feature.properties as SharingVehicleWFS).vehicle_id;
64
+ feature.properties.id = vehicleId || feature.properties.station_id;
65
+ feature.properties.is_free_float = !!vehicleId;
66
+ feature.properties.provider_name =
67
+ PROVIDER_BY_FEED_ID[feature.properties.feed_id];
68
+ },
69
+ );
70
+ return data as FeatureCollection<
71
+ Point,
72
+ SharingStationWFS | SharingVehicleWFS
73
+ >;
74
+ };