Skip to content

Commit 6d879f5

Browse files
committed
Map: Handle TrunkLine, SpeedTram & multimodal stops
1 parent ea50455 commit 6d879f5

10 files changed

Lines changed: 176 additions & 73 deletions

File tree

ui/src/components/map/markers/StopMarker.tsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ type StopMarkerBaseProps = {
1919
readonly size?: number;
2020
readonly borderWidth?: number;
2121
readonly fillColor?: string;
22+
readonly secondaryFillColor?: string | null;
2223
readonly borderColor?: string;
2324
readonly strokeDashArray?: number;
2425
readonly centerDot?: boolean;
@@ -47,6 +48,7 @@ type StopMarkerProps = PlaceholderStopMarkerProps | ExistingStopMarkerProps;
4748
export const StopMarker: FC<StopMarkerProps> = ({
4849
testId,
4950
fillColor = 'white',
51+
secondaryFillColor = null,
5052
borderColor = 'black',
5153
strokeDashArray = 0,
5254
centerDot = false,
@@ -122,6 +124,11 @@ export const StopMarker: FC<StopMarkerProps> = ({
122124
strokeWidth={1}
123125
fill={fillColor}
124126
/>
127+
128+
{secondaryFillColor && (
129+
<path fill={secondaryFillColor} d="M 7 1 A 6 6 0 0 1 7 13 Z" />
130+
)}
131+
125132
{!inSelection && (centerDot || isMouseHovering) && (
126133
<circle cx={7} cy={7} r={3} fill={borderColor} />
127134
)}

ui/src/components/map/queries/useGetMapStops.ts

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import { Viewport } from '../../../redux/types';
1111
import { parseDate } from '../../../time';
1212
import { Priority } from '../../../types/enums';
1313
import { StopPlaceState } from '../../../types/stop-registry';
14-
import { parseVehicleMode } from '../../../utils';
14+
import { parseStopRegistryTransportModeJsonArray } from '../../../utils';
1515
import { useMapDataLayerSimpleQueryLoader } from '../../common/hooks/useLoader';
1616
import { filtersAndResultSelectionToQueryVariables } from '../../stop-registry/search/by-stop/filtersToQueryVariables';
1717
import { mapCompactOrNull } from '../../stop-registry/utils';
@@ -43,10 +43,10 @@ const GQL_GET_MAP_STOPS = gql`
4343
centroid
4444
functional_area
4545
46-
stop_place {
47-
id
48-
transport_mode
49-
}
46+
transport_modes
47+
active_transport_modes
48+
trunk_line_stop
49+
speed_tram_stop
5050
}
5151
`;
5252

@@ -115,9 +115,6 @@ function mapRawStopToMapStop(
115115
return null;
116116
}
117117

118-
const vehicleMode =
119-
parseVehicleMode(rawStop.stop_place?.transport_mode) ?? undefined;
120-
121118
return {
122119
label: rawStop.label,
123120
location: rawStop.centroid,
@@ -127,8 +124,15 @@ function mapRawStopToMapStop(
127124
validity_start: parseDate(rawStop.validity_start),
128125
validity_end: parseDate(rawStop.validity_end),
129126
functional_area: parseValidNumber(rawStop.functional_area),
130-
vehicle_mode: vehicleMode,
131127
stop_state: rawStop.stop_state as StopPlaceState,
128+
transport_modes: parseStopRegistryTransportModeJsonArray(
129+
rawStop.transport_modes,
130+
),
131+
active_transport_modes: parseStopRegistryTransportModeJsonArray(
132+
rawStop.active_transport_modes,
133+
),
134+
trunk_line_stop: !!rawStop.trunk_line_stop,
135+
speed_tram_stop: !!rawStop.speed_tram_stop,
132136
};
133137
}
134138

ui/src/components/map/stops/EditStopLayer.tsx

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,11 @@ import {
2121
toggleStopSelectionAction,
2222
} from '../../../redux';
2323
import { EnrichedStopPlace, Point } from '../../../types';
24-
import { parseVehicleMode, showSuccessToast } from '../../../utils';
24+
import {
25+
mapVehicleModeToTransportMode,
26+
parseVehicleMode,
27+
showSuccessToast,
28+
} from '../../../utils';
2529
import { useMapDataLayerLoader } from '../../common/hooks';
2630
import {
2731
StopFormState,
@@ -279,7 +283,9 @@ export const EditStopLayer = forwardRef<EditStoplayerRef, EditStopLayerProps>(
279283
latitude={draftLocation.latitude}
280284
mapStopViewState={mapStopViewState}
281285
selected
282-
vehicleMode={draftVehicleMode}
286+
activeTransportModes={[
287+
mapVehicleModeToTransportMode(draftVehicleMode),
288+
]}
283289
/>
284290
)}
285291

ui/src/components/map/stops/Stop.tsx

Lines changed: 89 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import type { PointLike } from 'maplibre-gl';
22
import { FC } from 'react';
33
import { Marker } from 'react-map-gl/maplibre';
4-
import { ReusableComponentsVehicleModeEnum } from '../../../generated/graphql';
4+
import { StopRegistryTransportModeType } from '../../../generated/graphql';
55
import { theme } from '../../../generated/theme';
66
import { MapEntityEditorViewState } from '../../../redux';
77
import { StopMarker } from '../markers';
@@ -13,6 +13,38 @@ const { colors } = theme;
1313
// Needed to align the stop correctly, when the stop label is or isn't shown.
1414
const offset: PointLike = [-13, 0];
1515

16+
function determineTransportModeColor(
17+
mode: StopRegistryTransportModeType,
18+
isTrunkLineStop: boolean,
19+
isSpeedTramStop: boolean,
20+
) {
21+
if (mode === StopRegistryTransportModeType.Bus) {
22+
return isTrunkLineStop ? colors.hslTrunkLineOrange : colors.tweakedBrand;
23+
}
24+
25+
if (mode === StopRegistryTransportModeType.Tram) {
26+
return isSpeedTramStop
27+
? colors.hslSpeedTramTurquoise
28+
: colors.hslTramDarkGreen;
29+
}
30+
31+
if (mode === StopRegistryTransportModeType.Metro) {
32+
return colors.hslMetroOrange;
33+
}
34+
35+
if (mode === StopRegistryTransportModeType.Water) {
36+
return colors.hslFerryBlue;
37+
}
38+
39+
if (mode === StopRegistryTransportModeType.Rail) {
40+
return colors.hslFerryBlue;
41+
}
42+
43+
throw new Error(
44+
`No color specified for StopRegistryTransportModeType(${mode})!`,
45+
);
46+
}
47+
1648
/** Stop map markers border color is determined in this function. There are
1749
* different aspects which are affecting this determination. These are
1850
* * isPlaceholder: when moving a stop we have a placeholder for the stop's
@@ -28,7 +60,9 @@ function determineBorderColor(
2860
asMemberStop: boolean,
2961
isSelected: boolean,
3062
isPlaceholder: boolean,
31-
stopVehicleMode: ReusableComponentsVehicleModeEnum | undefined,
63+
activeTransportModes: ReadonlyArray<StopRegistryTransportModeType>,
64+
isTrunkLineStop: boolean,
65+
isSpeedTramStop: boolean,
3266
inSelection: boolean,
3367
) {
3468
if (inSelection) {
@@ -51,8 +85,13 @@ function determineBorderColor(
5185
return colors.selectedMapItem;
5286
}
5387

54-
if (stopVehicleMode) {
55-
return colors.stops[stopVehicleMode] ?? colors.hslDark80;
88+
const primaryMode = activeTransportModes.at(0);
89+
if (primaryMode) {
90+
return determineTransportModeColor(
91+
primaryMode,
92+
isTrunkLineStop,
93+
isSpeedTramStop,
94+
);
5695
}
5796

5897
return colors.hslDark80;
@@ -63,18 +102,43 @@ function determineFillColor(
63102
isSelected: boolean,
64103
inSelection: boolean,
65104
shouldBeGray: boolean,
105+
activeTransportModes: ReadonlyArray<StopRegistryTransportModeType>,
66106
) {
67107
if (isSelected || asMemberStop || inSelection) {
68108
return 'white';
69109
}
70110

71-
if (shouldBeGray) {
111+
if (shouldBeGray || activeTransportModes.length === 0) {
72112
return colors.lightGrey;
73113
}
74114

75115
return 'white';
76116
}
77117

118+
function determineSecondaryFillColor(
119+
asMemberStop: boolean,
120+
isSelected: boolean,
121+
inSelection: boolean,
122+
activeTransportModes: ReadonlyArray<StopRegistryTransportModeType>,
123+
isTrunkLineStop: boolean,
124+
isSpeedTramStop: boolean,
125+
) {
126+
if (isSelected || asMemberStop || inSelection) {
127+
return null;
128+
}
129+
130+
if (activeTransportModes.length >= 2) {
131+
const secondaryMode = activeTransportModes[1];
132+
return determineTransportModeColor(
133+
secondaryMode,
134+
isTrunkLineStop,
135+
isSpeedTramStop,
136+
);
137+
}
138+
139+
return null;
140+
}
141+
78142
type BaseStopProps = {
79143
readonly longitude: number;
80144
readonly latitude: number;
@@ -84,7 +148,9 @@ type BaseStopProps = {
84148
readonly mapStopViewState: MapEntityEditorViewState;
85149
readonly selected?: boolean;
86150
readonly testId?: string;
87-
readonly vehicleMode?: ReusableComponentsVehicleModeEnum;
151+
readonly activeTransportModes: ReadonlyArray<StopRegistryTransportModeType>;
152+
readonly isTrunkLineStop?: boolean;
153+
readonly isSpeedTramStop?: boolean;
88154
readonly shouldBeGray?: boolean;
89155
readonly showLabel?: boolean;
90156
};
@@ -114,7 +180,9 @@ export const Stop: FC<StopProps> = ({
114180
mapStopViewState,
115181
selected = false,
116182
testId,
117-
vehicleMode,
183+
activeTransportModes,
184+
isTrunkLineStop = false,
185+
isSpeedTramStop = false,
118186
shouldBeGray = false,
119187
onClick,
120188
onResolveTitle,
@@ -130,7 +198,9 @@ export const Stop: FC<StopProps> = ({
130198
asMemberStop,
131199
selected,
132200
isPlaceholder,
133-
vehicleMode,
201+
activeTransportModes,
202+
isTrunkLineStop,
203+
isSpeedTramStop,
134204
inSelection,
135205
);
136206

@@ -139,6 +209,16 @@ export const Stop: FC<StopProps> = ({
139209
selected,
140210
inSelection,
141211
shouldBeGray,
212+
activeTransportModes,
213+
);
214+
215+
const secondaryFillColor = determineSecondaryFillColor(
216+
asMemberStop,
217+
selected,
218+
inSelection,
219+
activeTransportModes,
220+
isTrunkLineStop,
221+
isSpeedTramStop,
142222
);
143223

144224
return (
@@ -153,6 +233,7 @@ export const Stop: FC<StopProps> = ({
153233
testId={testId}
154234
borderColor={iconBorderColor}
155235
fillColor={iconFillColor}
236+
secondaryFillColor={secondaryFillColor}
156237
borderWidth={3}
157238
strokeDashArray={isPlaceholder ? 2 : 0}
158239
centerDot={selected}

ui/src/components/map/stops/Stops.tsx

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -116,12 +116,9 @@ export const StopsImpl: ForwardRefRenderFunction<StopsRef, StopsProps> = (
116116

117117
const { setIsLoading: setIsLoadingSaveStop } = useLoader(Operation.SaveStop);
118118

119-
const { getStopVehicleMode, getStopHighlighted, getStopShouldBeGray } =
119+
const { getStopHighlighted, getStopShouldBeGray } =
120120
useMapStops(displayedRouteIds);
121-
const filterStopsByVehicleMode = useFilterStopsByVehicleMode(
122-
getStopVehicleMode,
123-
showRoute,
124-
);
121+
const filterStopsByVehicleMode = useFilterStopsByVehicleMode(showRoute);
125122

126123
const { setLoadingState: setFetchStopsLoadingState } = useLoader(
127124
Operation.FetchStops,
@@ -253,7 +250,9 @@ export const StopsImpl: ForwardRefRenderFunction<StopsRef, StopsProps> = (
253250
? testIds.memberStop(item.label)
254251
: testIds.stopMarker(item.label, item.priority)
255252
}
256-
vehicleMode={getStopVehicleMode(item)}
253+
activeTransportModes={item.active_transport_modes}
254+
isTrunkLineStop={item.trunk_line_stop}
255+
isSpeedTramStop={item.speed_tram_stop}
257256
shouldBeGray={getStopShouldBeGray(item)}
258257
/>
259258
);
Lines changed: 18 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,40 @@
11
import { useCallback } from 'react';
2-
import { ReusableComponentsVehicleModeEnum } from '../../../../generated/graphql';
2+
import { StopRegistryTransportModeType } from '../../../../generated/graphql';
33
import { useAppSelector } from '../../../../hooks';
44
import { FilterType, selectMapFilter } from '../../../../redux';
5-
import { parseVehicleMode } from '../../../../utils';
65
import { MapStop } from '../../types';
76
import { useVisibleRouteStops } from './useVisibleRouteStops';
87

9-
export function useFilterStopsByVehicleMode(
10-
getStopVehicleMode: (
11-
stop: MapStop,
12-
) => ReusableComponentsVehicleModeEnum | undefined,
13-
showRoute: boolean,
14-
) {
8+
export function useFilterStopsByVehicleMode(showRoute: boolean) {
159
const { stopFilters } = useAppSelector(selectMapFilter);
1610
const { visibleRouteStopLabels } = useVisibleRouteStops();
1711

1812
return useCallback(
1913
(stops: ReadonlyArray<MapStop>): ReadonlyArray<MapStop> =>
2014
stops.filter((stop) => {
21-
const vehicleMode = parseVehicleMode(getStopVehicleMode(stop));
2215
const isStopInVisibleRoutes =
2316
showRoute && visibleRouteStopLabels.includes(stop.label);
2417

25-
if (vehicleMode === ReusableComponentsVehicleModeEnum.Bus) {
26-
return (
27-
stopFilters[FilterType.ShowAllBusStops] || isStopInVisibleRoutes
28-
);
18+
if (isStopInVisibleRoutes) {
19+
return true;
2920
}
3021

31-
if (vehicleMode === ReusableComponentsVehicleModeEnum.Tram) {
32-
return (
33-
stopFilters[FilterType.ShowAllTramStops] || isStopInVisibleRoutes
34-
);
22+
if (
23+
stop.transport_modes.includes(StopRegistryTransportModeType.Bus) &&
24+
stopFilters[FilterType.ShowAllBusStops]
25+
) {
26+
return true;
3527
}
3628

37-
return (
38-
stopFilters[FilterType.ShowAllBusStops] ||
39-
stopFilters[FilterType.ShowAllTramStops] ||
40-
isStopInVisibleRoutes
41-
);
29+
if (
30+
stop.transport_modes.includes(StopRegistryTransportModeType.Tram) &&
31+
stopFilters[FilterType.ShowAllTramStops]
32+
) {
33+
return true;
34+
}
35+
36+
return false;
4237
}),
43-
[getStopVehicleMode, showRoute, stopFilters, visibleRouteStopLabels],
38+
[showRoute, stopFilters, visibleRouteStopLabels],
4439
);
4540
}

ui/src/components/map/stops/hooks/useMapStops.ts

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -103,17 +103,9 @@ export const useMapStops = (displayedRouteIds: ReadonlyArray<string>) => {
103103
[editedRouteIncludedStops, stopLabelToVehicleMode],
104104
);
105105

106-
const getStopVehicleMode = useCallback(
107-
(stop: MapStop): ReusableComponentsVehicleModeEnum | undefined =>
108-
stop.vehicle_mode ?? stopLabelToVehicleMode[stop.label],
109-
[stopLabelToVehicleMode],
110-
);
111-
112106
const getStopShouldBeGray = useCallback(
113107
(stop: MapStop): boolean =>
114108
(!!selectedRouteId && !usedStopLabels.includes(stop.label)) ||
115-
(stop.stop_state !== null &&
116-
stop.stop_state !== StopPlaceState.InOperation) ||
117109
!isCurrentEntity(observationDate, stop),
118110
[selectedRouteId, observationDate, usedStopLabels],
119111
);
@@ -133,5 +125,5 @@ export const useMapStops = (displayedRouteIds: ReadonlyArray<string>) => {
133125
[highlightedStopIds, selectedStopId, selectedStopAreaId],
134126
);
135127

136-
return { getStopVehicleMode, getStopHighlighted, getStopShouldBeGray };
128+
return { getStopHighlighted, getStopShouldBeGray };
137129
};

0 commit comments

Comments
 (0)