@geops/rvf-mobility-web-component 0.1.23 → 0.1.24-beta.0

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,740 @@
1
+ import type { Options } from "ol/layer/Group";
2
+
3
+ import { FeatureCollection, Point } from "geojson";
4
+ import { GeoJSONSource } from "maplibre-gl";
5
+ import { MaplibreStyleLayer } from "mobility-toolbox-js/ol";
6
+ import { Extent } from "ol/extent";
7
+ import { Group } from "ol/layer";
8
+ import { unByKey } from "ol/Observable";
9
+ import { transformExtent } from "ol/proj";
10
+ import { memo } from "preact/compat";
11
+ import { useCallback, useEffect, useMemo, useState } from "preact/hooks";
12
+
13
+ import Bicycle from "../icons/Bike";
14
+ import Car from "../icons/Car";
15
+ import CargoBike from "../icons/CargoBike";
16
+ import Ride from "../icons/Ride";
17
+ import Scooter from "../icons/Scooter";
18
+ import {
19
+ BIKE_FORM_FACTOR,
20
+ BIKE_OTHERS_FEED_IDS,
21
+ CAR_FORM_FACTOR,
22
+ CAR_OTHERS_FEED_IDS,
23
+ CARGOBIKE_FORM_FACTOR,
24
+ CARGOBIKE_FRELO_ID,
25
+ CARGOBIKE_OTHERS_FEED_IDS,
26
+ FRELO_FEED_ID,
27
+ GRUNFLOTTE_FEED_ID,
28
+ NATURENERGIE_FEED_ID,
29
+ RVF_LAYERS_NAMES,
30
+ RVF_LAYERS_TITLES,
31
+ SCOOTER_FORM_FACTOR,
32
+ } from "../utils/constants";
33
+ import useMapContext from "../utils/hooks/useMapContext";
34
+ import useRvfContext from "../utils/hooks/useRvfContext";
35
+ import {
36
+ getSharingClusterStyleLayers,
37
+ getSharingStyleLayers,
38
+ } from "../utils/sharingStylesUtils";
39
+ import {
40
+ fetchSharingWFS,
41
+ SharingStationWFS,
42
+ SharingVehicleWFS,
43
+ } from "../utils/sharingWFSUtils";
44
+
45
+ const BIKE_FRELO_SOURCE_ID = "bikeFrelo";
46
+ const BIKE_OTHERS_SOURCE_ID = "bikeOthers";
47
+ const CARGOBIKE_FRELO_SOURCE_ID = "cargobikeFrelo";
48
+ const CARGOBIKE_OTHERS_SOURCE_ID = "cargobikeOthers";
49
+ const CAR_GRF_SOURCE_ID = "carGrf";
50
+ const CAR_NATUR_SOURCE_ID = "carNature";
51
+ const CAR_OTHERS_SOURCE_ID = "carOthers";
52
+ const SCOOTER_SOURCE_ID = "scooter";
53
+ // const HITCHHIKING_SOURCE_ID = "hitchhiking";
54
+
55
+ export type GroupOptions = Options & Record<string, unknown>;
56
+
57
+ const fetchStations = async (
58
+ typeName: string,
59
+ feedIds: string[],
60
+ abortController: AbortController,
61
+ ) => {
62
+ const stations = (await fetchSharingWFS(
63
+ typeName,
64
+ abortController,
65
+ )) as FeatureCollection<Point, SharingStationWFS>;
66
+
67
+ const featureCollection = {
68
+ features: stations.features.filter((feature) => {
69
+ return feedIds ? feedIds.includes(feature.properties.feed_id) : true;
70
+ }),
71
+ type: "FeatureCollection",
72
+ };
73
+
74
+ return featureCollection as FeatureCollection<Point, SharingStationWFS>;
75
+ };
76
+
77
+ const fetchVehicles = async (
78
+ formFactor: string,
79
+ feedIds: string[],
80
+ extent4326: Extent,
81
+ abortController: AbortController,
82
+ ) => {
83
+ const freeFloat = (await fetchSharingWFS(
84
+ "sharing_vehicles",
85
+ abortController,
86
+ extent4326,
87
+ )) as FeatureCollection<Point, SharingVehicleWFS>;
88
+
89
+ const featureCollection = {
90
+ features: freeFloat.features.filter((feature) => {
91
+ return (
92
+ (feedIds ? feedIds.includes(feature.properties.feed_id) : true) &&
93
+ feature.properties.form_factor === formFactor
94
+ );
95
+ }),
96
+ type: "FeatureCollection",
97
+ };
98
+
99
+ return featureCollection as FeatureCollection<Point, SharingVehicleWFS>;
100
+ };
101
+
102
+ let cacheStations = new Map<
103
+ string,
104
+ FeatureCollection<Point, SharingStationWFS>
105
+ >();
106
+
107
+ const fetchLayerData = async (
108
+ typeName: string,
109
+ formFactor: string,
110
+ feedIds: string[],
111
+ extent: Extent,
112
+ abortController: AbortController,
113
+ ) => {
114
+ const cacheKey = typeName + feedIds?.toString();
115
+ const stations =
116
+ cacheStations[cacheKey] ||
117
+ (await fetchStations(typeName, feedIds, abortController));
118
+ const freeFloat = await fetchVehicles(
119
+ formFactor,
120
+ feedIds,
121
+ extent,
122
+ abortController,
123
+ );
124
+
125
+ if (!cacheStations[cacheKey]) {
126
+ cacheStations[cacheKey] = stations;
127
+ }
128
+ return {
129
+ features: [...stations.features, ...freeFloat.features],
130
+ type: "FeatureCollection",
131
+ } as FeatureCollection<Point, SharingStationWFS | SharingVehicleWFS>;
132
+ };
133
+
134
+ function RvfSharedMobilityLayerGroup2(props: GroupOptions) {
135
+ const { baseLayer, map } = useMapContext();
136
+ const { setSharedMobilityLayerGroup } = useRvfContext();
137
+
138
+ // Layers
139
+ const [bikeFreloLayer, setBikeFreloLayer] = useState<MaplibreStyleLayer>();
140
+ const [bikeOthersLayer, setBikeOthersLayer] = useState<MaplibreStyleLayer>();
141
+ const [cargobikeFreloLayer, setCargobikeFreloLayer] =
142
+ useState<MaplibreStyleLayer>();
143
+ const [cargobikeOthersLayer, setCargobikeOthersLayer] =
144
+ useState<MaplibreStyleLayer>();
145
+ const [carGrfLayer, setCarGrfLayer] = useState<MaplibreStyleLayer>();
146
+ const [carNaturLayer, setCarNaturLayer] = useState<MaplibreStyleLayer>();
147
+ const [carOthersLayer, setCarOthersLayer] = useState<MaplibreStyleLayer>();
148
+ const [scooterLayer, setScooterLayer] = useState<MaplibreStyleLayer>();
149
+
150
+ // GeoJSON data
151
+ const [bikeFreloData, setBikeFreloData] =
152
+ useState<FeatureCollection<Point, SharingStationWFS | SharingVehicleWFS>>();
153
+ const [bikeOthersData, setBikeOthersData] =
154
+ useState<FeatureCollection<Point, SharingStationWFS | SharingVehicleWFS>>();
155
+ const [cargobikeFreloData, setCargobikeFreloData] =
156
+ useState<FeatureCollection<Point, SharingStationWFS | SharingVehicleWFS>>();
157
+ const [cargobikeOthersData, setCargobikeOthersData] =
158
+ useState<FeatureCollection<Point, SharingStationWFS | SharingVehicleWFS>>();
159
+ const [carGrfData, setCarGrfData] =
160
+ useState<FeatureCollection<Point, SharingStationWFS | SharingVehicleWFS>>();
161
+ const [carNaturData, setCarNaturData] =
162
+ useState<FeatureCollection<Point, SharingStationWFS | SharingVehicleWFS>>();
163
+ const [carOthersData, setCarOthersData] =
164
+ useState<FeatureCollection<Point, SharingStationWFS | SharingVehicleWFS>>();
165
+ const [scooterData, setScooterData] =
166
+ useState<FeatureCollection<Point, SharingStationWFS | SharingVehicleWFS>>();
167
+
168
+ const updateData = useCallback(() => {
169
+ const abortController = new AbortController();
170
+ const extent = transformExtent(
171
+ map.getView().calculateExtent(),
172
+ "EPSG:3857",
173
+ "EPSG:4326",
174
+ );
175
+
176
+ const fetchData = async () => {
177
+ const bikeFreloData = await fetchLayerData(
178
+ "sharing_stations_bicycle",
179
+ BIKE_FORM_FACTOR,
180
+ [FRELO_FEED_ID],
181
+ extent,
182
+ abortController,
183
+ );
184
+ setBikeFreloData(bikeFreloData);
185
+ const bikeOthersData = await fetchLayerData(
186
+ "sharing_stations_bicycle",
187
+ BIKE_FORM_FACTOR,
188
+ BIKE_OTHERS_FEED_IDS,
189
+ extent,
190
+ abortController,
191
+ );
192
+ setBikeOthersData(bikeOthersData);
193
+
194
+ const cargobikeFreloData = await fetchLayerData(
195
+ "sharing_stations_cargo_bicycle",
196
+ CARGOBIKE_FORM_FACTOR,
197
+ [CARGOBIKE_FRELO_ID],
198
+ extent,
199
+ abortController,
200
+ );
201
+ setCargobikeFreloData(cargobikeFreloData);
202
+
203
+ const cargobikeOthersData = await fetchLayerData(
204
+ "sharing_stations_cargo_bicycle",
205
+ CARGOBIKE_FORM_FACTOR,
206
+ CARGOBIKE_OTHERS_FEED_IDS,
207
+ extent,
208
+ abortController,
209
+ );
210
+ setCargobikeOthersData(cargobikeOthersData);
211
+
212
+ const carGrfData = await fetchLayerData(
213
+ "sharing_stations_car",
214
+ CAR_FORM_FACTOR,
215
+ [GRUNFLOTTE_FEED_ID],
216
+ extent,
217
+ abortController,
218
+ );
219
+ setCarGrfData(carGrfData);
220
+
221
+ const carNaturData = await fetchLayerData(
222
+ "sharing_stations_car",
223
+ CAR_FORM_FACTOR,
224
+ [NATURENERGIE_FEED_ID],
225
+ extent,
226
+ abortController,
227
+ );
228
+ setCarNaturData(carNaturData);
229
+
230
+ const carOthers = await fetchLayerData(
231
+ "sharing_stations_car",
232
+ CAR_FORM_FACTOR,
233
+ CAR_OTHERS_FEED_IDS,
234
+ extent,
235
+ abortController,
236
+ );
237
+ setCarOthersData(carOthers);
238
+
239
+ const scooterData = await fetchLayerData(
240
+ "sharing_stations_scooters_standing",
241
+ SCOOTER_FORM_FACTOR,
242
+ null,
243
+ extent,
244
+ abortController,
245
+ );
246
+ // console.log("scooterData", scooterData);
247
+ setScooterData(scooterData);
248
+ };
249
+
250
+ fetchData();
251
+
252
+ return () => {
253
+ abortController.abort();
254
+ };
255
+ }, [map]);
256
+
257
+ // Request all stations and vehicleson each moveend event
258
+ useEffect(() => {
259
+ const key = map?.on("moveend", updateData);
260
+ const key2 = map?.once("rendercomplete", updateData);
261
+ return () => {
262
+ unByKey(key);
263
+ unByKey(key2);
264
+ };
265
+ }, [map, updateData]);
266
+
267
+ useEffect(() => {
268
+ const mbMap = bikeFreloLayer?.maplibreLayer?.mapLibreMap;
269
+ if (!mbMap || !bikeFreloData) {
270
+ return;
271
+ }
272
+ const source = mbMap.getSource(BIKE_FRELO_SOURCE_ID);
273
+ (source as GeoJSONSource)?.setData(bikeFreloData);
274
+ }, [bikeFreloData, bikeFreloLayer?.maplibreLayer?.mapLibreMap]);
275
+
276
+ useEffect(() => {
277
+ const mbMap = bikeOthersLayer?.maplibreLayer?.mapLibreMap;
278
+ if (!mbMap || !bikeOthersData) {
279
+ return;
280
+ }
281
+ const source = mbMap.getSource(BIKE_OTHERS_SOURCE_ID);
282
+ (source as GeoJSONSource)?.setData(bikeOthersData);
283
+ }, [bikeOthersData, bikeOthersLayer?.maplibreLayer?.mapLibreMap]);
284
+
285
+ useEffect(() => {
286
+ const mbMap = cargobikeFreloLayer?.maplibreLayer?.mapLibreMap;
287
+ if (!mbMap || !cargobikeFreloData) {
288
+ return;
289
+ }
290
+ const source = mbMap.getSource(CARGOBIKE_FRELO_SOURCE_ID);
291
+ (source as GeoJSONSource)?.setData(cargobikeFreloData);
292
+ }, [cargobikeFreloData, cargobikeFreloLayer?.maplibreLayer?.mapLibreMap]);
293
+
294
+ useEffect(() => {
295
+ const mbMap = cargobikeOthersLayer?.maplibreLayer?.mapLibreMap;
296
+ if (!mbMap || !cargobikeOthersData) {
297
+ return;
298
+ }
299
+ const source = mbMap.getSource(CARGOBIKE_OTHERS_SOURCE_ID);
300
+ (source as GeoJSONSource)?.setData(cargobikeOthersData);
301
+ }, [cargobikeOthersData, cargobikeOthersLayer?.maplibreLayer?.mapLibreMap]);
302
+
303
+ useEffect(() => {
304
+ const mbMap = carGrfLayer?.maplibreLayer?.mapLibreMap;
305
+ if (!mbMap || !carGrfData) {
306
+ return;
307
+ }
308
+ const source = mbMap.getSource(CAR_GRF_SOURCE_ID);
309
+ (source as GeoJSONSource)?.setData(carGrfData);
310
+ }, [carGrfData, carGrfLayer?.maplibreLayer?.mapLibreMap]);
311
+ useEffect(() => {
312
+ const mbMap = carNaturLayer?.maplibreLayer?.mapLibreMap;
313
+ if (!mbMap || !carNaturData) {
314
+ return;
315
+ }
316
+ const source = mbMap.getSource(CAR_NATUR_SOURCE_ID);
317
+ (source as GeoJSONSource)?.setData(carNaturData);
318
+ }, [carNaturData, carNaturLayer?.maplibreLayer?.mapLibreMap]);
319
+
320
+ useEffect(() => {
321
+ const mbMap = carOthersLayer?.maplibreLayer?.mapLibreMap;
322
+ if (!mbMap || !carOthersData) {
323
+ return;
324
+ }
325
+ const source = mbMap.getSource(CAR_OTHERS_SOURCE_ID);
326
+ (source as GeoJSONSource)?.setData(carOthersData);
327
+ }, [carOthersData, carOthersLayer?.maplibreLayer?.mapLibreMap]);
328
+
329
+ useEffect(() => {
330
+ const mbMap = scooterLayer?.maplibreLayer?.mapLibreMap;
331
+ if (!mbMap || !scooterData) {
332
+ return;
333
+ }
334
+ const source = mbMap.getSource(SCOOTER_SOURCE_ID);
335
+ (source as GeoJSONSource)?.setData(scooterData);
336
+ }, [scooterData, scooterLayer?.maplibreLayer?.mapLibreMap]);
337
+
338
+ const group = useMemo(() => {
339
+ if (!baseLayer) {
340
+ return null;
341
+ }
342
+
343
+ const sharingBicycle = new Group({
344
+ layers: [
345
+ new MaplibreStyleLayer({
346
+ // isQueryable: true,
347
+ layersFilter: ({ metadata }) => {
348
+ return metadata?.["rvf.filter"] === "bike";
349
+ },
350
+ maplibreLayer: baseLayer,
351
+ maxZoom: 18,
352
+ visible: false,
353
+ }),
354
+ // createMobiDataBwWfsLayer(
355
+ // API_REQUEST_FEATURE_TYPE.stations.bike,
356
+ // "green",
357
+ // ),
358
+ // createFreeFloatMobilityLayer(
359
+ // API_REQUEST_FEATURE_TYPE.freeFloat.bike,
360
+ // "green",
361
+ // "bicycle",
362
+ // ),
363
+ ],
364
+ name: RVF_LAYERS_NAMES.fahrrad,
365
+ // title: (
366
+ // <div className="flex items-center justify-between gap-2">
367
+ // {RVF_LAYERS_TITLES.fahrrad}
368
+ // <Bicycle />
369
+ // </div>
370
+ // ),
371
+ } as GroupOptions);
372
+
373
+ const sharingCar = new Group({
374
+ layers: [
375
+ new MaplibreStyleLayer({
376
+ // isQueryable: true,
377
+ layersFilter: ({ metadata }) => {
378
+ return metadata?.["rvf.filter"] === "car";
379
+ },
380
+ maplibreLayer: baseLayer,
381
+ maxZoom: 18,
382
+ visible: false,
383
+ }),
384
+ // createMobiDataBwWfsLayer(
385
+ // API_REQUEST_FEATURE_TYPE.stations.car,
386
+ // "green",
387
+ // ),
388
+ // createFreeFloatMobilityLayer(
389
+ // API_REQUEST_FEATURE_TYPE.freeFloat.car,
390
+ // "green",
391
+ // "car",
392
+ // ),
393
+ ],
394
+ // name: RVF_LAYERS_NAMES.auto,
395
+ // title: (
396
+ // <div className="flex items-center justify-between gap-2">
397
+ // {RVF_LAYERS_TITLES.auto}
398
+ // <Car />
399
+ // </div>
400
+ // ),
401
+ } as GroupOptions);
402
+
403
+ const sharingCargoBicycle = new Group({
404
+ layers: [
405
+ new MaplibreStyleLayer({
406
+ // isQueryable: true,
407
+ layersFilter: ({ metadata }) => {
408
+ return metadata?.["rvf.filter"] === "cargo_bike";
409
+ },
410
+ maplibreLayer: baseLayer,
411
+ maxZoom: 18,
412
+ visible: false,
413
+ }),
414
+ // createMobiDataBwWfsLayer(
415
+ // API_REQUEST_FEATURE_TYPE.stations.cargoBike,
416
+ // "green",
417
+ // ),
418
+ // createFreeFloatMobilityLayer(
419
+ // API_REQUEST_FEATURE_TYPE.freeFloat.cargoBike,
420
+ // "green",
421
+ // "cargo_bicycle",
422
+ // ),
423
+ ],
424
+ // name: RVF_LAYERS_NAMES.cargobike,
425
+ // title: (
426
+ // <div className="flex items-center justify-between gap-2">
427
+ // {RVF_LAYERS_TITLES.cargobike}
428
+ // <CargoBike />
429
+ // </div>
430
+ // ),
431
+ } as GroupOptions);
432
+
433
+ // const sharingScooter = new Group({
434
+ // layers: [
435
+ // No scooter station data available
436
+ // new MaplibreStyleLayer({
437
+ // isQueryable: true,
438
+ // layersFilter: ({ metadata }) => {
439
+ // return metadata?.["rvf.filter"] === "scooter";
440
+ // },
441
+ // maplibreLayer: baseLayer,
442
+ // }),
443
+ // https://www.mobidata-bw.de/dataset/escootch
444
+ // createMobiDataBwWfsLayer(
445
+ // API_REQUEST_FEATURE_TYPE.stations.scooter,
446
+ // "green",
447
+ // ),
448
+ // createFreeFloatMobilityLayer(
449
+ // API_REQUEST_FEATURE_TYPE.freeFloat.scooter,
450
+ // "green",
451
+ // "scooter",
452
+ // ),
453
+ // ],
454
+ // name: RVF_LAYERS_NAMES.eroller,
455
+ // title: (
456
+ // <div className="flex items-center justify-between gap-2">
457
+ // {RVF_LAYERS_TITLES.eroller}
458
+ // <Scooter />
459
+ // </div>
460
+ // ),
461
+ // } as GroupOptions);
462
+
463
+ const sharingHitchHiking = new MaplibreStyleLayer({
464
+ isQueryable: true,
465
+ layersFilter: ({ metadata }) => {
466
+ return metadata?.["rvf.filter"] === "hitchhiking";
467
+ },
468
+ maplibreLayer: baseLayer,
469
+ name: RVF_LAYERS_NAMES.mitfahrpunkte,
470
+ title: (
471
+ <div className="flex items-center justify-between gap-2">
472
+ {RVF_LAYERS_TITLES.mitfahrpunkte}
473
+ <Ride />
474
+ </div>
475
+ ),
476
+ visible: false,
477
+ });
478
+
479
+ const bikeFrelo = new MaplibreStyleLayer({
480
+ isQueryable: true,
481
+ maplibreLayer: baseLayer,
482
+ name: RVF_LAYERS_NAMES.bikeFrelo,
483
+ sources: {
484
+ [BIKE_FRELO_SOURCE_ID]: {
485
+ data: { features: [], type: "FeatureCollection" },
486
+ promoteId: "id",
487
+ type: "geojson",
488
+ },
489
+ },
490
+ styleLayers: getSharingStyleLayers(BIKE_FRELO_SOURCE_ID),
491
+
492
+ title: (
493
+ <div className="flex items-center justify-between gap-2">
494
+ {"Frelo"}
495
+ <Bicycle />
496
+ </div>
497
+ ),
498
+ });
499
+ setBikeFreloLayer(bikeFrelo);
500
+
501
+ const bikeOthers = new MaplibreStyleLayer({
502
+ isQueryable: true,
503
+ maplibreLayer: baseLayer,
504
+ name: RVF_LAYERS_NAMES.bikeOthers,
505
+ sources: {
506
+ [BIKE_OTHERS_SOURCE_ID]: {
507
+ data: { features: [], type: "FeatureCollection" },
508
+ promoteId: "id",
509
+ type: "geojson",
510
+ },
511
+ },
512
+ styleLayers: getSharingStyleLayers(BIKE_OTHERS_SOURCE_ID),
513
+ title: (
514
+ <div className="flex items-center justify-between gap-2">
515
+ {"Fahrrad, andere Anbieter"}
516
+ <Bicycle />
517
+ </div>
518
+ ),
519
+ });
520
+ setBikeOthersLayer(bikeOthers);
521
+
522
+ const cargobikeFrelo = new MaplibreStyleLayer({
523
+ isQueryable: true,
524
+ maplibreLayer: baseLayer,
525
+ name: RVF_LAYERS_NAMES.cargobikeFrelo,
526
+ sources: {
527
+ [CARGOBIKE_FRELO_SOURCE_ID]: {
528
+ data: { features: [], type: "FeatureCollection" },
529
+ promoteId: "id",
530
+ type: "geojson",
531
+ },
532
+ },
533
+ styleLayers: getSharingStyleLayers(
534
+ CARGOBIKE_FRELO_SOURCE_ID,
535
+ "rvf_shared_cargo_bike",
536
+ ),
537
+ title: (
538
+ <div className="flex items-center justify-between gap-2">
539
+ {"Lastenfrelo"}
540
+ <CargoBike />
541
+ </div>
542
+ ),
543
+ });
544
+ setCargobikeFreloLayer(cargobikeFrelo);
545
+
546
+ const cargobikeOthers = new MaplibreStyleLayer({
547
+ isQueryable: true,
548
+ maplibreLayer: baseLayer,
549
+ name: RVF_LAYERS_NAMES.cargobikeOthers,
550
+ sources: {
551
+ [CARGOBIKE_OTHERS_SOURCE_ID]: {
552
+ data: { features: [], type: "FeatureCollection" },
553
+ promoteId: "id",
554
+ type: "geojson",
555
+ },
556
+ },
557
+ styleLayers: getSharingStyleLayers(
558
+ CARGOBIKE_OTHERS_SOURCE_ID,
559
+ "rvf_shared_cargo_bike",
560
+ ),
561
+ title: (
562
+ <div className="flex items-center justify-between gap-2">
563
+ {"Lastenrad, andere Anbieter"}
564
+ <CargoBike />
565
+ </div>
566
+ ),
567
+ });
568
+ setCargobikeOthersLayer(cargobikeOthers);
569
+
570
+ const carGrf = new MaplibreStyleLayer({
571
+ isQueryable: true,
572
+ maplibreLayer: baseLayer,
573
+ name: RVF_LAYERS_NAMES.carGrf,
574
+ sources: {
575
+ [CAR_GRF_SOURCE_ID]: {
576
+ data: { features: [], type: "FeatureCollection" },
577
+ promoteId: "id",
578
+ type: "geojson",
579
+ },
580
+ },
581
+ styleLayers: getSharingStyleLayers(CAR_GRF_SOURCE_ID, "rvf_shared_car"),
582
+ title: (
583
+ <div className="flex items-center justify-between gap-2">
584
+ {"Grüne Flotte"}
585
+ <Car />
586
+ </div>
587
+ ),
588
+ });
589
+ setCarGrfLayer(carGrf);
590
+
591
+ const carNatur = new MaplibreStyleLayer({
592
+ isQueryable: true,
593
+ maplibreLayer: baseLayer,
594
+ name: RVF_LAYERS_NAMES.carNatur,
595
+ sources: {
596
+ [CAR_NATUR_SOURCE_ID]: {
597
+ data: { features: [], type: "FeatureCollection" },
598
+ promoteId: "id",
599
+ type: "geojson",
600
+ },
601
+ },
602
+ styleLayers: getSharingStyleLayers(CAR_NATUR_SOURCE_ID, "rvf_shared_car"),
603
+ title: (
604
+ <div className="flex items-center justify-between gap-2">
605
+ {"Naturenergie-Sharing"}
606
+ <Car />
607
+ </div>
608
+ ),
609
+ });
610
+ setCarNaturLayer(carNatur);
611
+
612
+ const carOthers = new MaplibreStyleLayer({
613
+ isQueryable: true,
614
+ maplibreLayer: baseLayer,
615
+ name: RVF_LAYERS_NAMES.carOthers,
616
+ sources: {
617
+ [CAR_OTHERS_SOURCE_ID]: {
618
+ data: { features: [], type: "FeatureCollection" },
619
+ promoteId: "id",
620
+ type: "geojson",
621
+ },
622
+ },
623
+ styleLayers: getSharingStyleLayers(
624
+ CAR_OTHERS_SOURCE_ID,
625
+ "rvf_shared_car",
626
+ ),
627
+ title: (
628
+ <div className="flex items-center justify-between gap-2">
629
+ {"Auto, andere Anbieter"}
630
+ <Car />
631
+ </div>
632
+ ),
633
+ });
634
+ setCarOthersLayer(carOthers);
635
+
636
+ const scooter = new MaplibreStyleLayer({
637
+ isQueryable: true,
638
+ maplibreLayer: baseLayer,
639
+ name: RVF_LAYERS_NAMES.eroller,
640
+ sources: {
641
+ [SCOOTER_SOURCE_ID]: {
642
+ cluster: true,
643
+ clusterRadius: 40,
644
+ data: { features: [], type: "FeatureCollection" },
645
+ generateId: true,
646
+ maxzoom: 21,
647
+ type: "geojson",
648
+ },
649
+ },
650
+ styleLayers: getSharingClusterStyleLayers(
651
+ SCOOTER_SOURCE_ID,
652
+ "rvf_shared_scooter",
653
+ ),
654
+ title: (
655
+ <div className="flex items-center justify-between gap-2">
656
+ {RVF_LAYERS_TITLES.eroller}
657
+ <Scooter />
658
+ </div>
659
+ ),
660
+ });
661
+ setScooterLayer(scooter);
662
+
663
+ // const hitchhiking = new MaplibreStyleLayer({
664
+ // maplibreLayer: baseLayer,
665
+ // name: RVF_LAYERS_NAMES.mitfahrpunkte,
666
+ // sources: {
667
+ // [HITCHHIKING_SOURCE_ID]: {
668
+ // data: { features: [], type: "FeatureCollection" },
669
+ // type: "geojson",
670
+ // },
671
+ // },
672
+ // styleLayers: getStyleLayers(HITCHHIKING_SOURCE_ID, "rvf_shared_car"),
673
+ // title: "E-Roller",
674
+ // });
675
+ // setHitchhikingLayer(hitchhiking);
676
+
677
+ return new Group({
678
+ layers: [
679
+ sharingBicycle,
680
+ sharingCargoBicycle,
681
+ sharingCar,
682
+ bikeFrelo,
683
+ bikeOthers,
684
+ cargobikeFrelo,
685
+ cargobikeOthers,
686
+ carGrf,
687
+ carNatur,
688
+ carOthers,
689
+ scooter,
690
+ sharingHitchHiking,
691
+ // hitchhiking,
692
+ ],
693
+ ...props,
694
+ } as GroupOptions);
695
+ }, [baseLayer, props]);
696
+
697
+ // Reload features every minute
698
+ useEffect(() => {
699
+ const interval = window.setInterval(() => {
700
+ // group.getLayers().forEach((layer: Group) => {
701
+ // layer.getLayers?.().forEach((layer: MaplibreStyleLayer | Vector) => {
702
+ // const source = layer.getSource();
703
+ // source?.refresh();
704
+
705
+ // // For cluster source
706
+ // (
707
+ // (source as Cluster<Feature<Point>>)?.getSource?.() as VectorSource<
708
+ // Feature<Point>
709
+ // >
710
+ // )?.refresh();
711
+ // });
712
+ // });
713
+ // Redo the request to get the latest data abou vhicle available
714
+ // @ts-expect-error - type issue
715
+ cacheStations = {};
716
+ updateData();
717
+ }, 60000);
718
+ return () => {
719
+ window.clearInterval(interval);
720
+ };
721
+ }, [group, updateData]);
722
+
723
+ useEffect(() => {
724
+ setSharedMobilityLayerGroup(group);
725
+ }, [group, setSharedMobilityLayerGroup]);
726
+
727
+ useEffect(() => {
728
+ if (!map || !group) {
729
+ return;
730
+ }
731
+ map.addLayer(group);
732
+
733
+ return () => {
734
+ map.removeLayer(group);
735
+ };
736
+ }, [map, group]);
737
+
738
+ return null;
739
+ }
740
+ export default memo(RvfSharedMobilityLayerGroup2);