@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 @@
1
+ export { default } from "./RvfSharedMobilityLayerGroup2";
@@ -1,17 +1,21 @@
1
+ import { GeoJSONSource } from "maplibre-gl";
1
2
  import { Feature, MapBrowserEvent } from "ol";
2
3
  import { GeoJSON } from "ol/format";
3
4
  import { unByKey } from "ol/Observable";
4
5
  import { toLonLat } from "ol/proj";
5
6
  import { useCallback, useEffect } from "preact/hooks";
6
7
 
8
+ import { PROVIDER_LOGOS_BY_FEED_ID } from "../utils/constants";
7
9
  import useMapContext from "../utils/hooks/useMapContext";
8
10
  import useRvfContext from "../utils/hooks/useRvfContext";
9
11
  import MobilityEvent from "../utils/MobilityEvent";
12
+ import { fetchSharingStation } from "../utils/sharingGraphqlUtils";
10
13
 
11
14
  const geojson = new GeoJSON();
12
15
 
13
16
  function SingleClickListener() {
14
17
  const {
18
+ baseLayer,
15
19
  map,
16
20
  realtimeLayer,
17
21
  setStationId,
@@ -21,7 +25,23 @@ function SingleClickListener() {
21
25
  tenant,
22
26
  trainId,
23
27
  } = useMapContext();
24
- const { setSelectedFeature, setSelectedFeatures } = useRvfContext();
28
+ const { selectedFeature, setSelectedFeature, setSelectedFeatures } =
29
+ useRvfContext();
30
+
31
+ // Send the selctedFEature to the parent window
32
+ useEffect(() => {
33
+ if (!map) {
34
+ return;
35
+ }
36
+
37
+ map.getTargetElement().dispatchEvent(
38
+ new MobilityEvent("selectedfeature", {
39
+ feature: selectedFeature
40
+ ? geojson.writeFeatureObject(selectedFeature)
41
+ : null,
42
+ }),
43
+ );
44
+ }, [map, selectedFeature]);
25
45
 
26
46
  const onPointerMove = useCallback(
27
47
  async (evt: MapBrowserEvent<PointerEvent>) => {
@@ -59,6 +79,9 @@ function SingleClickListener() {
59
79
 
60
80
  const onSingleClick = useCallback(
61
81
  async (evt: MapBrowserEvent<PointerEvent>) => {
82
+ if (!baseLayer.mapLibreMap) {
83
+ return;
84
+ }
62
85
  const [realtimeFeature] = evt.map.getFeaturesAtPixel(evt.pixel, {
63
86
  layerFilter: (l) => {
64
87
  return l === realtimeLayer;
@@ -95,26 +118,59 @@ function SingleClickListener() {
95
118
  return l.get("isQueryable");
96
119
  },
97
120
  }) as Feature[];
98
- evt.map.getTargetElement().dispatchEvent(
99
- new MobilityEvent("singleclick", {
100
- ...evt,
101
- features: geojson.writeFeaturesObject(features),
102
- lonlat: toLonLat(evt.coordinate),
103
- }),
104
- );
105
- // feature.get("form_factor"); //free float
106
- // feature.get("num_vehicles_available"); // wfs livedata
107
- // feature.get("provider_name"); // station sharing
108
-
109
- if (newStationId || newTrainId || !features.length) {
110
- setSelectedFeature(null);
111
- setSelectedFeatures([]);
112
- } else {
113
- setSelectedFeatures(features);
114
- setSelectedFeature(features[0]);
115
- }
121
+
122
+ // Append more infos about the features
123
+ const addMoreData = async (features) => {
124
+ for (const feature of features) {
125
+ const clusterId = feature.get("cluster_id");
126
+ if (clusterId) {
127
+ const vtFeat = feature.get("vectorTileFeature");
128
+ const sourceId = vtFeat.layer.source;
129
+ const leaves =
130
+ (await (
131
+ baseLayer.mapLibreMap.getSource(sourceId) as GeoJSONSource
132
+ )?.getClusterLeaves(clusterId, 1000, 0)) || [];
133
+
134
+ feature.set(
135
+ "features",
136
+ leaves.map((l) => {
137
+ return geojson.readFeature(l);
138
+ }),
139
+ );
140
+ }
141
+
142
+ // Sharing station
143
+ const sharingStationId = selectedFeature?.get("station_id");
144
+ if (sharingStationId) {
145
+ const sharingStationInfo =
146
+ await fetchSharingStation(sharingStationId);
147
+ selectedFeature.setProperties(sharingStationInfo);
148
+ selectedFeature.set(
149
+ "provider_logo",
150
+ PROVIDER_LOGOS_BY_FEED_ID[selectedFeature?.get("feed_id")],
151
+ );
152
+ }
153
+ }
154
+ evt.map.getTargetElement().dispatchEvent(
155
+ new MobilityEvent("singleclick", {
156
+ ...evt,
157
+ features: geojson.writeFeaturesObject(features),
158
+ lonlat: toLonLat(evt.coordinate),
159
+ }),
160
+ );
161
+
162
+ if (newStationId || newTrainId || !features.length) {
163
+ setSelectedFeature(null);
164
+ setSelectedFeatures([]);
165
+ } else {
166
+ setSelectedFeatures(features);
167
+ setSelectedFeature(features[0]);
168
+ }
169
+ };
170
+ addMoreData(features);
116
171
  },
117
172
  [
173
+ baseLayer?.mapLibreMap,
118
174
  stationId,
119
175
  trainId,
120
176
  realtimeLayer,
@@ -122,6 +178,7 @@ function SingleClickListener() {
122
178
  tenant,
123
179
  setStationId,
124
180
  setTrainId,
181
+ selectedFeature,
125
182
  setSelectedFeature,
126
183
  setSelectedFeatures,
127
184
  ],
package/src/index.tsx CHANGED
@@ -13,6 +13,7 @@ register(
13
13
  "extent",
14
14
  "maxextent",
15
15
  "geolocation",
16
+ "details",
16
17
  "layers",
17
18
  "layertree",
18
19
  "mapsurl",
@@ -23,7 +24,7 @@ register(
23
24
  "notificationbeforelayerid",
24
25
  "print",
25
26
  "realtime",
26
- "realtimeUrl",
27
+ "realtimeurl",
27
28
  "search",
28
29
  "share",
29
30
  "tenant",
@@ -1,4 +1,13 @@
1
- import { transformExtent } from "ol/proj";
1
+ import { fromLonLat, toLonLat, transformExtent } from "ol/proj";
2
+
3
+ import callBike from "../logos/callabike_logo.png";
4
+ import flinkster from "../logos/flinkster_logo.png";
5
+ import grueneFlotteLogo from "../logos/gruene_flotte_logo.png";
6
+ import lastenVeloLogo from "../logos/lasten_velo_freiburg.png";
7
+ import freloLogo from "../logos/logo_frelo_web_rgb.png";
8
+ import naturEnergieLogo from "../logos/natur_energie_logo.png";
9
+ import yoioLogo from "../logos/yoio_logo.png";
10
+ import zeusLogo from "../logos/zeus_logo.png";
2
11
 
3
12
  export const RVF_EXTENT_4326 = [7.5, 47.7, 8.45, 48.4];
4
13
 
@@ -8,6 +17,10 @@ export const RVF_EXTENT_3857 = transformExtent(
8
17
  "EPSG:3857",
9
18
  );
10
19
 
20
+ // @ts-expect-error - testsdsd sd
21
+ window.fromLonLat = fromLonLat;
22
+ // @ts-expect-error - testsdsd sd
23
+ window.toLonLat = toLonLat;
11
24
  export const LAYER_PROP_IS_EXPORTING = "isExporting";
12
25
 
13
26
  export const RVF_LAYERS_TITLES = {
@@ -27,7 +40,14 @@ export const RVF_LAYERS_TITLES = {
27
40
 
28
41
  export const RVF_LAYERS_NAMES = {
29
42
  auto: "auto",
43
+ bikeFrelo: "frelo",
44
+ bikeOthers: "bikeothers",
30
45
  cargobike: "cargobike",
46
+ cargobikeFrelo: "cargobikefrelo",
47
+ cargobikeOthers: "cargobikeothers",
48
+ carGrf: "grueneflotte",
49
+ carNatur: "naturenergie",
50
+ carOthers: "carothers",
31
51
  echtzeit: "echtzeit",
32
52
  eroller: "e-roller",
33
53
  fahrrad: "fahrrad",
@@ -91,3 +111,54 @@ export const PROVIDER_BY_FEED_ID = {
91
111
  // "carvelo",
92
112
  // "CarSharing"
93
113
  };
114
+
115
+ export const BIKE_FORM_FACTOR = "bicycle";
116
+ export const CAR_FORM_FACTOR = "car";
117
+ export const CARGOBIKE_FORM_FACTOR = "cargo_bicycle";
118
+ export const SCOOTER_FORM_FACTOR = "scooter";
119
+
120
+ // Station system ids
121
+ // "pickebike_basel",
122
+ // "dott_basel",
123
+ // "gruene-flotte_freiburg",
124
+ // "voi_ch",
125
+ // "nextbike_df",
126
+ // "carvelo2go_ch",
127
+ // "naturenergie_sharing",
128
+ // "lastenvelo_fr",
129
+ // "donkey_neuchatel",
130
+ // "flinkster_carsharing"
131
+ export const GRUNFLOTTE_FEED_ID = "gruene-flotte_freiburg";
132
+ export const NATURENERGIE_FEED_ID = "naturenergie_sharing";
133
+ export const CAR_OTHERS_FEED_IDS = ["flinkster_carsharing"];
134
+
135
+ export const FRELO_FEED_ID = "nextbike_df";
136
+ export const BIKE_OTHERS_FEED_IDS = [
137
+ "callabike_ice", // don't exist in graphql
138
+ "pickebike_basel",
139
+ "donkey_neuchatel",
140
+ ];
141
+
142
+ export const CARGOBIKE_FRELO_ID = "nextbike_df";
143
+ export const CARGOBIKE_OTHERS_FEED_IDS = ["lastenvelo_fr", "carvelo2go_ch"];
144
+
145
+ export const SCOOTER_OTHERS_FEED_IDS = ["voi_ch"];
146
+
147
+ export const PROVIDER_LOGOS_BY_FEED_ID = {
148
+ callabike_ice: callBike,
149
+ flinkster_carsharing: flinkster,
150
+ "gruene-flotte_freiburg": grueneFlotteLogo,
151
+ lastenvelo_fr: lastenVeloLogo,
152
+ naturenergie_sharing: naturEnergieLogo,
153
+ nextbike_df: freloLogo,
154
+ yoio_freiburg: yoioLogo,
155
+ zeus_freiburg: zeusLogo,
156
+ };
157
+
158
+ export const LINE_COLOR_BY_NAME = {
159
+ "1": "#E8001B",
160
+ "2": "#13A538",
161
+ "3": "#F59E00",
162
+ "4": "#EA5297",
163
+ "5": "#008BC5",
164
+ };
@@ -57,7 +57,7 @@ function createFreeFloatMobilityLayer(
57
57
  "MobiData-BW:" +
58
58
  name +
59
59
  "&" +
60
- "outputFormat=application/json&srsname=EPSG:3857&" +
60
+ "outputFormat=application/json" +
61
61
  "bbox=" +
62
62
  extent.join(",") +
63
63
  ",EPSG:3857";
@@ -72,7 +72,10 @@ function createFreeFloatMobilityLayer(
72
72
  if (xhr.status == 200) {
73
73
  const features = source
74
74
  .getFormat()
75
- .readFeatures(xhr.responseText)
75
+ .readFeatures(xhr.responseText, {
76
+ dataProjection: "EPSG:4326",
77
+ featureProjection: "EPSG:3857",
78
+ })
76
79
  ?.filter((feature) => {
77
80
  if (formFactor) {
78
81
  return feature.get("form_factor") === formFactor;
@@ -78,11 +78,14 @@ function createMobiDataBwWfsLayer(
78
78
  name: string,
79
79
  color: string,
80
80
  layerOptions: Options = {
81
- minZoom: 18,
81
+ minZoom: 0,
82
82
  },
83
83
  ): VectorLayer<Vector<Feature<Point>>> {
84
84
  const source = new Vector({
85
- format: new GeoJSON(),
85
+ format: new GeoJSON({
86
+ dataProjection: "EPSG:4326",
87
+ featureProjection: "EPSG:3857",
88
+ }),
86
89
  strategy: bboxStrategy,
87
90
  url: function (extent) {
88
91
  return (
@@ -94,7 +97,7 @@ function createMobiDataBwWfsLayer(
94
97
  "MobiData-BW:" +
95
98
  name +
96
99
  "&" +
97
- "outputFormat=application/json&srsname=EPSG:3857&" +
100
+ "outputFormat=application/json&" +
98
101
  "bbox=" +
99
102
  extent.join(",") +
100
103
  ",EPSG:3857"
@@ -1,3 +1,18 @@
1
1
  import { realtimeConfig } from "mobility-toolbox-js/ol";
2
2
 
3
- export default realtimeConfig.getBgColor;
3
+ import { LINE_COLOR_BY_NAME } from "./constants";
4
+
5
+ const getBgColor = (type, line) => {
6
+ if (type === "bus") {
7
+ return "#646363";
8
+ }
9
+ if (type === "tram") {
10
+ const lineColor = LINE_COLOR_BY_NAME[line?.name];
11
+ if (lineColor) {
12
+ return lineColor;
13
+ }
14
+ }
15
+ return realtimeConfig.getBgColor(type);
16
+ };
17
+
18
+ export default getBgColor;
@@ -2,18 +2,19 @@ import getDelayColor from "./getDelayColor";
2
2
 
3
3
  describe("getDelayColor", () => {
4
4
  it("returns green", () => {
5
- expect(getDelayColor(0)).toBe("#16a34a");
6
- expect(getDelayColor(2.49 * 60 * 1000)).toBe("#16a34a");
7
- });
8
- it("returns yellow", () => {
9
- expect(getDelayColor(3 * 60 * 1000)).toBe("#ca8a04");
10
- expect(getDelayColor(4.49 * 60 * 1000 - 1)).toBe("#ca8a04");
5
+ expect(getDelayColor(0)).toBe("transparent");
11
6
  });
7
+ // it("returns yellow", () => {
8
+ // expect(getDelayColor(3 * 60 * 1000)).toBe("#ca8a04");
9
+ // expect(getDelayColor(4.49 * 60 * 1000 - 1)).toBe("#ca8a04");
10
+ // });
12
11
  it("returns orange", () => {
12
+ expect(getDelayColor(0.5 * 60 * 1000)).toBe("#ea580c");
13
+ expect(getDelayColor(2.49 * 60 * 1000)).toBe("#ea580c");
13
14
  expect(getDelayColor(5 * 60 * 1000)).toBe("#ea580c");
14
- expect(getDelayColor(9.49 * 60 * 1000 - 1)).toBe("#ea580c");
15
15
  });
16
16
  it("returns red", () => {
17
+ expect(getDelayColor(9.49 * 60 * 1000 - 1)).toBe("#dc2626");
17
18
  expect(getDelayColor(10 * 60 * 1000)).toBe("#dc2626");
18
19
  expect(getDelayColor(180 * 60 * 1000)).toBe("#dc2626");
19
20
  });
@@ -2,22 +2,22 @@
2
2
  * Returns a color class to display the delay.
3
3
  * @param {Number} time Delay time in milliseconds.
4
4
  */
5
- const getDelayColor = (timeInMs: number) => {
5
+ const getDelayColor = (timeInMs: number, isText = false) => {
6
6
  // we use rounded value to fit the getDelayString method.
7
7
  const minutes = Math.round(timeInMs / 1000 / 60);
8
8
  // if (minutes >= 60) {
9
9
  // }
10
- if (minutes >= 10) {
10
+ if (minutes > 5) {
11
11
  return "#dc2626"; // "text-red-600";
12
12
  }
13
- if (minutes >= 5) {
13
+ if (minutes >= 1) {
14
14
  return "#ea580c"; // "text-orange-600";
15
15
  // return "#d97706"; // "text-amber-600";
16
16
  }
17
- if (minutes >= 3) {
18
- return "#ca8a04"; // "text-yellow-600";
19
- }
20
- return "#16a34a"; // "text-green-600";
17
+ // if (minutes >= 3) {
18
+ // return "#ca8a04"; // "text-yellow-600";
19
+ // }
20
+ return isText ? "#16a34a" : "transparent"; // "text-green-600";
21
21
  };
22
22
 
23
23
  export default getDelayColor;
@@ -6,22 +6,29 @@ describe("getDelayColorForVehicle", () => {
6
6
  expect(getDelayColorForVehicle(0, true, false)).toBe("#a0a0a0");
7
7
  });
8
8
  it("returns null delay (no realtime train) color", () => {
9
- expect(getDelayColorForVehicle(null)).toBe("#a0a0a0");
9
+ expect(getDelayColorForVehicle(null)).toBe("transparent");
10
10
  });
11
11
 
12
- it("returns green", () => {
13
- expect(getDelayColorForVehicle(0)).toBe("#16a34a");
14
- expect(getDelayColorForVehicle(2.49 * 60 * 1000)).toBe("#16a34a");
15
- });
16
- it("returns yellow", () => {
17
- expect(getDelayColorForVehicle(3 * 60 * 1000)).toBe("#ca8a04");
18
- expect(getDelayColorForVehicle(4.49 * 60 * 1000 - 1)).toBe("#ca8a04");
12
+ it("returns transparent", () => {
13
+ expect(getDelayColorForVehicle(0)).toBe("transparent");
14
+ expect(getDelayColorForVehicle(0.4 * 60 * 1000)).toBe("transparent");
19
15
  });
16
+ // it("returns green", () => {
17
+ // expect(getDelayColorForVehicle(0)).toBe("#16a34a");
18
+ // expect(getDelayColorForVehicle(2.49 * 60 * 1000)).toBe("#16a34a");
19
+ // });
20
+ // it("returns yellow", () => {
21
+ // expect(getDelayColorForVehicle(3 * 60 * 1000)).toBe("#ca8a04");
22
+ // expect(getDelayColorForVehicle(4.49 * 60 * 1000 - 1)).toBe("#ca8a04");
23
+ // });
20
24
  it("returns orange", () => {
25
+ expect(getDelayColorForVehicle(1 * 60 * 1000)).toBe("#ea580c");
26
+ expect(getDelayColorForVehicle(3 * 60 * 1000)).toBe("#ea580c");
27
+ expect(getDelayColorForVehicle(4.49 * 60 * 1000 - 1)).toBe("#ea580c");
21
28
  expect(getDelayColorForVehicle(5 * 60 * 1000)).toBe("#ea580c");
22
- expect(getDelayColorForVehicle(9.49 * 60 * 1000 - 1)).toBe("#ea580c");
23
29
  });
24
30
  it("returns red", () => {
31
+ expect(getDelayColorForVehicle(9.49 * 60 * 1000 - 1)).toBe("#dc2626");
25
32
  expect(getDelayColorForVehicle(10 * 60 * 1000)).toBe("#dc2626");
26
33
  expect(getDelayColorForVehicle(180 * 60 * 1000)).toBe("#dc2626");
27
34
  });
@@ -17,9 +17,9 @@ const getDelayColorForVehicle = (
17
17
  : "#a0a0a0"; // gray
18
18
  }
19
19
  if (delayInMs === null) {
20
- return "#a0a0a0";
20
+ return "transparent";
21
21
  }
22
- return getDelayColor(delayInMs);
22
+ return getDelayColor(delayInMs, isDelayText);
23
23
  };
24
24
 
25
25
  export default getDelayColorForVehicle;
@@ -10,12 +10,13 @@ import getBgColor from "./getBgColor";
10
10
 
11
11
  // This function returns the main color of a line using a line, trajectory, stopsequence or departure object.
12
12
  const getMainColorForVehicle = (object: unknown = null): string => {
13
- let color =
14
- (object as RealtimeTrajectory)?.properties?.line?.color ||
13
+ const line =
14
+ (object as RealtimeTrajectory)?.properties?.line ||
15
15
  // @ts-expect-error bad type definition
16
- (object as RealtimeStopSequence)?.line?.color ||
17
- (object as RealtimeLine)?.color;
16
+ (object as RealtimeStopSequence)?.line ||
17
+ (object as RealtimeLine);
18
18
 
19
+ let color = line?.color;
19
20
  if (!color) {
20
21
  let type: RealtimeMot =
21
22
  (object as RealtimeTrajectory)?.properties?.type ||
@@ -34,7 +35,7 @@ const getMainColorForVehicle = (object: unknown = null): string => {
34
35
  type = "rail";
35
36
  }
36
37
  }
37
- color = getBgColor(type) || getBgColor("rail");
38
+ color = getBgColor(type, line);
38
39
  }
39
40
 
40
41
  if (color && color[0] !== "#") {
@@ -0,0 +1,39 @@
1
+ import { realtimeConfig } from "mobility-toolbox-js/ol";
2
+
3
+ // mobility-portal config
4
+ // const trackerRadiusMapping = {
5
+ // 0: [0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 4, 4, 6, 7, 7, 7],
6
+ // 1: [0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 4, 4, 6, 7, 7, 7],
7
+ // 2: [0, 0, 0, 0, 0, 2, 2, 4, 4, 6, 6, 7, 7, 7, 12, 12, 15],
8
+ // 3: [0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 4, 6, 6, 6],
9
+ // 4: [0, 0, 0, 0, 0, 2, 2, 4, 4, 6, 6, 7, 7, 7, 12, 12, 15],
10
+ // 5: [0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 4, 4, 4, 7, 7, 7],
11
+ // 6: [0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 4, 4, 4, 7, 7, 7],
12
+ // 7: [0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 4, 4, 4, 7, 7, 7],
13
+ // 8: [0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 4, 6, 6, 6],
14
+ // 9: [0, 0, 0, 0, 0, 2, 2, 4, 4, 6, 6, 7, 7, 7, 12, 12, 15],
15
+ // };
16
+
17
+ const radiusMapping: number[][] = [
18
+ [0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7],
19
+ [0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7],
20
+ [0, 0, 0, 0, 0, 2, 2, 3, 7, 7, 7, 7, 7, 7, 12, 12, 15], // [0, 0, 0, 0, 0, 2, 2, 3, 7, 7, 7, 12, 15, 15, 15, 15, 15],
21
+ [0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7],
22
+ [0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7],
23
+ [0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7],
24
+ [0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7],
25
+ [0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7],
26
+ [0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7],
27
+ [0, 0, 0, 0, 0, 2, 2, 3, 7, 7, 7, 7, 7, 7, 12, 12, 15],
28
+ ];
29
+
30
+ export const getRadius = (type = 0, zoom = 0, cancelled = false) => {
31
+ try {
32
+ // @ts-expect-error - bad type definition
33
+ const typeIdx = realtimeConfig.getTypeIndex(type);
34
+ return radiusMapping[typeIdx][zoom] * (cancelled ? 2 : 1);
35
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
36
+ } catch (e) {
37
+ return 1;
38
+ }
39
+ };
@@ -0,0 +1,10 @@
1
+ import { realtimeConfig } from "mobility-toolbox-js/ol";
2
+
3
+ const getTextColor = (type) => {
4
+ if (type === "bus" || type === "tram") {
5
+ return "#fff";
6
+ }
7
+ return realtimeConfig.getTextColor(type);
8
+ };
9
+
10
+ export default getTextColor;