@geops/rvf-mobility-web-component 0.1.54 → 0.1.56

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.
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@geops/rvf-mobility-web-component",
3
3
  "license": "UNLICENSED",
4
4
  "description": "Web components for rvf in the domains of mobility and logistics.",
5
- "version": "0.1.54",
5
+ "version": "0.1.56",
6
6
  "homepage": "https://rvf-mobility-web-component-geops.vercel.app/",
7
7
  "type": "module",
8
8
  "main": "index.js",
@@ -13,7 +13,7 @@ import {
13
13
  // const geopsMapsApiLink = `<a href="https://developer.geops.io/apis/maps">geOps Maps API</a>`;
14
14
  // const geopsStopsApiLink = `<a href="https://developer.geops.io/apis/stops">geOps Stops API</a>`;
15
15
  const geopsMocoApiLink = `<a href="https://geops.com/en/solution/disruption-information">geOps MOCO API</a>`;
16
- const geopsRealtimeApiLink = `<a href="https://developer.geops.io/apis/realtime">geOps Realtime API</a>`;
16
+ // const geopsRealtimeApiLink = `<a href="https://developer.geops.io/apis/realtime">geOps Realtime API</a>`;
17
17
 
18
18
  export interface WebComponentAttributeDoc {
19
19
  defaultValue?: string;
@@ -125,14 +125,26 @@ const attrs: MobilityMapAttributes = {
125
125
  The layers available are : ${LAYERS_WITH_LINK}.<br/>
126
126
  Definition for a layer :
127
127
  <pre style="font-size: 12px; overflow: auto;">{
128
- liniennetz: { // The layer name, here the liniennetz layer.
129
- link: { // Define the link to display int footer of the details view, if not defined no link is displayed.
130
- text: "Zu den Liniennetzplänen", // The text of the link, if not defined the title is used.
131
- href: "https://www.rvf.de/fahrtinfo/netzplan", // The url of the link, if not defined no link is displayed.
128
+ "liniennetz": {
129
+ "link": {
130
+ "href": "https://www.rvf.de/fahrtinfo/netzplan",
131
+ "show": true,
132
+ "text": "Zu den Liniennetzplänen"
132
133
  },
133
- title: "Liniennetzpläne", // Text displayed on the layer tree and in the header of the details view.
134
+ "title": "Liniennetzpläne"
134
135
  }
135
- </pre>}`,
136
+ </pre>}
137
+ <br/>
138
+ where:
139
+ <ul style="list-style-type: disc; padding-left: 20px;">
140
+ <li><i>link</i> defined a external link displayed at the bottom of the detail view</li>
141
+ <ul style="list-style-type: disc; padding-left: 40px;">
142
+ <li><i>href</i> is the target of the link. The <i>href</i> can be template, for example for the meldungen layer you can use {{id}} to insert the id of the notification in the url.</li
143
+ <li><i>text</i> is the text display as a link</li>
144
+ <li><i>show</i> show/hide the link in the details view</li>
145
+ </ul>
146
+ <li><i>title</i> is the title of the layer used in the details view header and in the layer tree, if not defined the layer name will be used.</li>
147
+ </ul>`,
136
148
  },
137
149
  layertree: {
138
150
  defaultValue: "true",
@@ -168,7 +180,7 @@ const attrs: MobilityMapAttributes = {
168
180
  // "Commas separated list of mots to display on the Realtime layer.<br/>Ex: rail,bus,coach,foot,tram,subway,gondola,funicular,ferry,car .",
169
181
  },
170
182
  notification: {
171
- defaultValue: "false",
183
+ defaultValue: "true",
172
184
  description: `Add the notification layer to the map. This layer will display informations about disruptions on the network. Data comes from
173
185
  our ${geopsMocoApiLink} .`,
174
186
  type: "boolean",
@@ -183,7 +195,7 @@ const attrs: MobilityMapAttributes = {
183
195
  },
184
196
  notificationurl: {
185
197
  defaultValue: "https://moco.geops.io/api/v2/",
186
- description: `The ${geopsMocoApiLink} url to use.`,
198
+ description: null, // `The ${geopsMocoApiLink} url to use.`,
187
199
  },
188
200
  permalink: {
189
201
  defaultValue: "false",
@@ -203,7 +215,7 @@ const attrs: MobilityMapAttributes = {
203
215
  },
204
216
  realtime: {
205
217
  defaultValue: "true",
206
- description: `Add the realtime layer to the map. Data comes from the ${geopsRealtimeApiLink} .`,
218
+ description: null, //`Add the realtime layer to the map. Data comes from the ${geopsRealtimeApiLink} .`,
207
219
  type: "boolean",
208
220
  },
209
221
  realtimebboxparameters: {
@@ -3,7 +3,7 @@ import { memo, useId, useState } from "preact/compat";
3
3
  import RvfCheckbox from "../RvfCheckbox";
4
4
  import RvfSelect from "../RvfSelect";
5
5
  import Button from "../ui/Button";
6
- import { LAYER_PROP_IS_EXPORTING } from "../utils/constants";
6
+ import { LAYER_PROP_IS_EXPORTING, RVF_EXTENT_3857 } from "../utils/constants";
7
7
  import exportPdf from "../utils/exportPdf";
8
8
  import getAllLayers from "../utils/getAllLayers";
9
9
  import useMapContext from "../utils/hooks/useMapContext";
@@ -66,6 +66,8 @@ function RvfExportMenu({ ...props }: RvfExportMenuButtonProps) {
66
66
  map,
67
67
  { format },
68
68
  {
69
+ maxExtent: useMaxExtent ? RVF_EXTENT_3857 : undefined,
70
+
69
71
  onAfter: (mapp, layers) => {
70
72
  if (
71
73
  realtimeLayer &&
@@ -78,7 +80,6 @@ function RvfExportMenu({ ...props }: RvfExportMenuButtonProps) {
78
80
  });
79
81
  mapp.set(LAYER_PROP_IS_EXPORTING, false);
80
82
  },
81
-
82
83
  onBefore: (mapp, layers) => {
83
84
  mapp.set(LAYER_PROP_IS_EXPORTING, true);
84
85
  if (realtimeLayer) {
@@ -91,7 +92,6 @@ function RvfExportMenu({ ...props }: RvfExportMenuButtonProps) {
91
92
  layer.set(LAYER_PROP_IS_EXPORTING, true);
92
93
  });
93
94
  },
94
- useMaxExtent,
95
95
  },
96
96
  );
97
97
  setTimeout(() => {
@@ -703,7 +703,7 @@ function RvfMobilityMap(props: RvfMobilityMapProps) {
703
703
  hasLayerTree={hasLayerTree}
704
704
  hasPrint={hasPrint}
705
705
  hasRealtime={hasRealtime}
706
- hasSearch={false}
706
+ hasSearch={false} // The search could be in the overlay but we decide to put it in the toolbar for better UX
707
707
  hasShare={hasShare}
708
708
  />
709
709
  </Overlay>
@@ -22,9 +22,7 @@ import {
22
22
  SOURCE_FREE_FLOAT_CAR,
23
23
  SOURCE_FREE_FLOAT_CARGO_BIKE,
24
24
  SOURCE_FREE_FLOAT_SCOOTER,
25
- SOURCE_STATIONS_BIKE,
26
- SOURCE_STATIONS_CAR,
27
- SOURCE_STATIONS_CARGO_BIKE,
25
+ SOURCE_SHARING_STATIONS,
28
26
  WFS_FREE_FLOAT_TYPE,
29
27
  WFS_STATIONS_TYPE,
30
28
  } from "../utils/constants";
@@ -82,11 +80,7 @@ function RvfSharedMobilityLayerGroup(props: GroupOptions) {
82
80
  // const [scooterLayer, setScooterLayer] = useState<MaplibreStyleLayer>();
83
81
 
84
82
  // GeoJSON data
85
- const [bikeStationsData, setBikeStationsData] =
86
- useState<FeatureCollection<Point, SharingStationWFS>>();
87
- const [cargoBikeStationsData, setCargoBikeStationsData] =
88
- useState<FeatureCollection<Point, SharingStationWFS>>();
89
- const [carStationsData, setCarStationsData] =
83
+ const [stationsData, setStationsData] =
90
84
  useState<FeatureCollection<Point, SharingStationWFS>>();
91
85
  const [bikeFreeFloatData, setBikeFreeFloatData] =
92
86
  useState<FeatureCollection<Point, SharingVehicleWFS>>();
@@ -111,46 +105,13 @@ function RvfSharedMobilityLayerGroup(props: GroupOptions) {
111
105
 
112
106
  const fetchData = async () => {
113
107
  // Fill stations data
108
+ // The stations are also loaded in the style to have them displayed during export
114
109
  const stations = await fetchStations(
115
110
  WFS_STATIONS_TYPE,
116
111
  abortController,
117
112
  extent,
118
113
  );
119
- const bikeStationsDatas: FeatureCollection<Point, SharingStationWFS> = {
120
- features: [],
121
- type: "FeatureCollection",
122
- };
123
- const cargoBikeStationsDatas: FeatureCollection<
124
- Point,
125
- SharingStationWFS
126
- > = {
127
- features: [],
128
- type: "FeatureCollection",
129
- };
130
- const carStationsDatas: FeatureCollection<Point, SharingStationWFS> = {
131
- features: [],
132
- type: "FeatureCollection",
133
- };
134
-
135
- stations?.features.forEach((station) => {
136
- if (station.properties.num_bicycles_available !== null) {
137
- station.properties.num_vehicles_available =
138
- station.properties.num_bicycles_available;
139
- bikeStationsDatas.features.push(station);
140
- } else if (station.properties.num_cargo_bicycles_available !== null) {
141
- station.properties.num_vehicles_available =
142
- station.properties.num_cargo_bicycles_available;
143
- cargoBikeStationsDatas.features.push(station);
144
- } else if (station.properties.num_cars_available !== null) {
145
- station.properties.num_vehicles_available =
146
- station.properties.num_cars_available;
147
- carStationsDatas.features.push(station);
148
- }
149
- });
150
-
151
- setBikeStationsData(bikeStationsDatas);
152
- setCargoBikeStationsData(cargoBikeStationsDatas);
153
- setCarStationsData(carStationsDatas);
114
+ setStationsData(stations);
154
115
 
155
116
  // Fill free float data
156
117
  const freeFloatData = (await fetchSharingWFS(
@@ -219,28 +180,12 @@ function RvfSharedMobilityLayerGroup(props: GroupOptions) {
219
180
  }, [map, updateData, mbMap]);
220
181
 
221
182
  useEffect(() => {
222
- if (!mbMap || !bikeStationsData) {
223
- return;
224
- }
225
- const source = mbMap.getSource(SOURCE_STATIONS_BIKE);
226
- (source as GeoJSONSource)?.setData(bikeStationsData);
227
- }, [bikeStationsData, mbMap]);
228
-
229
- useEffect(() => {
230
- if (!mbMap || !cargoBikeStationsData) {
231
- return;
232
- }
233
- const source = mbMap.getSource(SOURCE_STATIONS_CARGO_BIKE);
234
- (source as GeoJSONSource)?.setData(cargoBikeStationsData);
235
- }, [mbMap, cargoBikeStationsData]);
236
-
237
- useEffect(() => {
238
- if (!mbMap || !carStationsData) {
183
+ if (!mbMap || !stationsData) {
239
184
  return;
240
185
  }
241
- const source = mbMap.getSource(SOURCE_STATIONS_CAR);
242
- (source as GeoJSONSource)?.setData(carStationsData);
243
- }, [mbMap, carStationsData]);
186
+ const source = mbMap.getSource(SOURCE_SHARING_STATIONS);
187
+ (source as GeoJSONSource)?.setData(stationsData);
188
+ }, [stationsData, mbMap]);
244
189
 
245
190
  useEffect(() => {
246
191
  if (!mbMap || !bikeFreeFloatData) {
@@ -289,7 +234,6 @@ function RvfSharedMobilityLayerGroup(props: GroupOptions) {
289
234
  }
290
235
 
291
236
  const bikeFrelo = new MaplibreStyleLayer({
292
- isQueryable: true,
293
237
  maplibreLayer: baseLayer,
294
238
  name: RVF_LAYERS_NAMES.bikeFrelo,
295
239
  styleLayersFilter: ({ metadata }) => {
@@ -306,7 +250,6 @@ function RvfSharedMobilityLayerGroup(props: GroupOptions) {
306
250
  // setBikeFreloLayer(bikeFrelo);
307
251
 
308
252
  const bikeOthers = new MaplibreStyleLayer({
309
- isQueryable: true,
310
253
  maplibreLayer: baseLayer,
311
254
  name: RVF_LAYERS_NAMES.bikeOthers,
312
255
  styleLayersFilter: ({ metadata }) => {
@@ -322,7 +265,6 @@ function RvfSharedMobilityLayerGroup(props: GroupOptions) {
322
265
  // setBikeOthersLayer(bikeOthers);
323
266
 
324
267
  const cargobikeFrelo = new MaplibreStyleLayer({
325
- isQueryable: true,
326
268
  layersFilter: ({ metadata }) => {
327
269
  return metadata?.["rvf.filter"] === "cargo_bike.frelo";
328
270
  },
@@ -338,7 +280,6 @@ function RvfSharedMobilityLayerGroup(props: GroupOptions) {
338
280
  // setCargobikeFreloLayer(cargobikeFrelo);
339
281
 
340
282
  const cargobikeOthers = new MaplibreStyleLayer({
341
- isQueryable: true,
342
283
  layersFilter: ({ metadata }) => {
343
284
  return metadata?.["rvf.filter"] === "cargo_bike.other";
344
285
  },
@@ -354,7 +295,6 @@ function RvfSharedMobilityLayerGroup(props: GroupOptions) {
354
295
  // setCargobikeOthersLayer(cargobikeOthers);
355
296
 
356
297
  const carGrf = new MaplibreStyleLayer({
357
- isQueryable: true,
358
298
  layersFilter: ({ metadata }) => {
359
299
  return metadata?.["rvf.filter"] === "car.grueneflotte";
360
300
  },
@@ -370,7 +310,6 @@ function RvfSharedMobilityLayerGroup(props: GroupOptions) {
370
310
  // setCarGrfLayer(carGrf);
371
311
 
372
312
  const carNatur = new MaplibreStyleLayer({
373
- isQueryable: true,
374
313
  layersFilter: ({ metadata }) => {
375
314
  return metadata?.["rvf.filter"] === "car.naturenergy";
376
315
  },
@@ -386,7 +325,6 @@ function RvfSharedMobilityLayerGroup(props: GroupOptions) {
386
325
  // setCarNaturLayer(carNatur);
387
326
 
388
327
  const carOthers = new MaplibreStyleLayer({
389
- isQueryable: true,
390
328
  layersFilter: ({ metadata }) => {
391
329
  return metadata?.["rvf.filter"] === "car.other";
392
330
  },
@@ -402,7 +340,6 @@ function RvfSharedMobilityLayerGroup(props: GroupOptions) {
402
340
  // setCarOthersLayer(carOthers);
403
341
 
404
342
  const scooter = new MaplibreStyleLayer({
405
- isQueryable: true,
406
343
  layersFilter: ({ metadata }) => {
407
344
  return metadata?.["rvf.filter"] === "scooter";
408
345
  },
@@ -418,7 +355,6 @@ function RvfSharedMobilityLayerGroup(props: GroupOptions) {
418
355
  // setScooterLayer(scooter);
419
356
 
420
357
  const hitchHiking = new MaplibreStyleLayer({
421
- isQueryable: false,
422
358
  layersFilter: ({ metadata }) => {
423
359
  return metadata?.["rvf.filter"] === "hitchhiking";
424
360
  },
@@ -99,9 +99,7 @@ export const WFS_STATIONS_TYPE = "sharing_stations";
99
99
 
100
100
  export const WFS_FREE_FLOAT_TYPE = "sharing_vehicles";
101
101
 
102
- export const SOURCE_STATIONS_BIKE = WFS_BIKE_TYPE;
103
- export const SOURCE_STATIONS_CARGO_BIKE = WFS_CARGO_BIKE_TYPE;
104
- export const SOURCE_STATIONS_CAR = WFS_CAR_TYPE;
102
+ export const SOURCE_SHARING_STATIONS = "sharing_stations";
105
103
 
106
104
  export const SOURCE_FREE_FLOAT_BIKE = "sharing_freefloat_bicycle";
107
105
  export const SOURCE_FREE_FLOAT_CARGO_BIKE = "sharing_freefloat_cargo_bicycle";
@@ -4,8 +4,6 @@ import { Map } from "ol";
4
4
  import { getBottomRight, getTopLeft } from "ol/extent";
5
5
  import View from "ol/View";
6
6
 
7
- import { RVF_EXTENT_3857 } from "./constants";
8
-
9
7
  import type { jsPDFOptions } from "jspdf";
10
8
  import type { Coordinate } from "ol/coordinate";
11
9
  import type { Extent } from "ol/extent";
@@ -532,12 +530,12 @@ export interface CopyrightExportOptions {
532
530
 
533
531
  export interface MapExportOptions {
534
532
  copyrightOptions?: CopyrightExportOptions;
533
+ maxExtent?: number[];
535
534
  onAfter?: (map: Map, layers: BaseLayer[]) => void;
536
535
  onBefore?: (map: Map, layers: BaseLayer[]) => void;
537
536
  pixelRatio?: number;
538
537
  text?: string;
539
538
  useCopyright?: boolean;
540
- useMaxExtent?: boolean;
541
539
  usePlaceholder?: boolean;
542
540
  }
543
541
 
@@ -547,11 +545,11 @@ async function exportPdf(
547
545
  mapExportOptions: MapExportOptions = {},
548
546
  ): Promise<boolean> {
549
547
  const {
548
+ maxExtent,
550
549
  onAfter,
551
550
  onBefore,
552
551
  pixelRatio = 3,
553
552
  useCopyright = true,
554
- useMaxExtent = false,
555
553
  usePlaceholder = true,
556
554
  } = mapExportOptions;
557
555
 
@@ -560,7 +558,7 @@ async function exportPdf(
560
558
  const size = sizePt.map((n) => {
561
559
  return (n * 96) / 72;
562
560
  });
563
- const extent = useMaxExtent ? RVF_EXTENT_3857 : null; //map.getView().calculateExtent();
561
+ const extent = maxExtent;
564
562
 
565
563
  // Save current pixel ratio
566
564
  const actualPixelRatio = window.devicePixelRatio;
@@ -22,7 +22,7 @@ export type SharingStationWFS = {
22
22
  num_cars_available: null | number;
23
23
  num_mopeds_available: null | number;
24
24
  num_scooters_standing_available: null | number;
25
- // Backward compatibility with style
25
+ // Backward compatibility for the select style
26
26
  num_vehicles_available: number;
27
27
  rental_uris_android: string;
28
28
  rental_uris_ios: string;
@@ -79,8 +79,6 @@ export const fetchSharingWFS = async (
79
79
 
80
80
  // for select style we always set mot and num_vehicles_available
81
81
  const formFactor = (feature.properties as SharingVehicleWFS).form_factor;
82
- let numVehiclesAvailable = (feature.properties as SharingStationWFS)
83
- .num_vehicles_available;
84
82
  let mot = formFactor || wfsTypeName.split("_").pop();
85
83
  if (mot === "bicycle") {
86
84
  mot = "bike";
@@ -88,12 +86,26 @@ export const fetchSharingWFS = async (
88
86
  mot = "cargo_bike";
89
87
  }
90
88
 
91
- if ((feature.properties as SharingVehicleWFS).vehicle_id) {
92
- numVehiclesAvailable = 1;
89
+ if (mot === "stations") {
90
+ const props: SharingStationWFS =
91
+ feature.properties as SharingStationWFS;
92
+ if (props.num_bicycles_available !== null) {
93
+ mot = "bike";
94
+ feature.properties.num_vehicles_available =
95
+ props.num_bicycles_available;
96
+ } else if (props.num_cars_available !== null) {
97
+ mot = "car";
98
+ feature.properties.num_vehicles_available = props.num_cars_available;
99
+ } else if (props.num_cargo_bicycles_available !== null) {
100
+ mot = "cargo_bike";
101
+ feature.properties.num_vehicles_available =
102
+ props.num_cargo_bicycles_available;
103
+ }
104
+ } else {
105
+ feature.properties.num_vehicles_available = 1;
93
106
  }
94
-
107
+ // mot property is used for the select styles
95
108
  feature.properties.mot = mot;
96
- feature.properties.num_vehicles_available = numVehiclesAvailable;
97
109
  feature.properties.display_num_vehicles_available = true;
98
110
  },
99
111
  );