Skip to content

Commit

Permalink
feat(ts/components/vehicleMarker): implement shuttle colors (#2860)
Browse files Browse the repository at this point in the history
* fix(ts/components/vehicleMarker): move vehicle marker classes onto svg

Right now if you were to pull out the icons into their own components, they wouldn't render correctly, so this fixes that the styling doesn't care if it's in a leaflet map or not.

* fix(ts/components/vehicleMarker): replace color classes with css var

* feat(ts/models/shuttle): create enum `ShuttleVariant`

* feat(ts/models/shuttle): create `RunId` to `ShuttleVariant` "mapper"

The `RunId` => `ShuttleVariant` relationship is "many to one", which makes this better suited for a function which returns the enum value from the `RunId`.
  • Loading branch information
firestack authored Oct 22, 2024
1 parent a5a8397 commit 181a732
Show file tree
Hide file tree
Showing 8 changed files with 231 additions and 62 deletions.
82 changes: 45 additions & 37 deletions assets/css/map/markers/_vehicle_marker.scss
Original file line number Diff line number Diff line change
@@ -1,53 +1,61 @@
.c-vehicle-map__icon {
path {
fill: $color-primary-legacy;
stroke: $color-bg-base;
stroke-width: 2;
// Vehicle doesn't fit in marker as is.
overflow: visible;

&.on-time {
fill: $color-vehicle-ontime;
}
fill: $color-primary-legacy;
stroke: $color-bg-base;
stroke-width: 2;

&.early.early-red {
fill: $color-vehicle-red;
}
&.early.early-blue {
fill: $color-vehicle-blue;
}
.on-time {
fill: $color-vehicle-ontime;
}

&.late.early-red {
fill: $color-vehicle-blue;
}
&.late.early-blue {
fill: $color-vehicle-red;
}
.early {
fill: var(--color-early);
}

&.off-course {
fill: $color-vehicle-off-course;
}
.late {
fill: var(--color-late);
}

&.logged-out {
fill: $color-gray-300;
stroke: $color-gray-600;
stroke-width: 1px;
}
.off-course {
fill: $color-vehicle-off-course;
}

&.selected {
stroke: $color-eggplant-600;
stroke-width: 1.5;
filter: drop-shadow(1px 1px 4px $color-eggplant-400);
}
.logged-out {
fill: $color-gray-300;
stroke: $color-gray-600;
stroke-width: 1px;
}

svg {
overflow: visible;
.selected {
stroke: $color-eggplant-600;
stroke-width: 1.5;
filter: drop-shadow(1px 1px 4px $color-eggplant-400);
}

&.c-vehicle-marker--shuttle {
// Shuttle Colors
&.c-vehicle-marker--blue {
fill: var(--color-blue-line);
}
&.c-vehicle-marker--orange {
fill: var(--color-orange-line);
}
&.c-vehicle-marker--green {
fill: var(--color-green-line);
}
&.c-vehicle-marker--red {
fill: var(--color-red-line);
}
&.c-vehicle-marker--cr {
fill: var(--color-cr-line);
}
}
}

.c-vehicle-map__label {
svg {
overflow: visible;
}
overflow: visible;

&.primary {
font-size: var(--font-size-s);
Expand Down
63 changes: 54 additions & 9 deletions assets/src/components/map/markers/vehicleMarker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,19 @@ import { LatLngExpression, Marker } from "leaflet"
import React, {
PropsWithChildren,
useContext,
useEffect,
useRef,
useState,
useEffect,
} from "react"

import { StateDispatchContext } from "../../../contexts/stateDispatchContext"
import { joinClasses } from "../../../helpers/dom"
import { vehicleLabel } from "../../../helpers/vehicleLabel"
import { statusClasses, drawnStatus } from "../../../models/vehicleStatus"

import {
shuttleVariantFromRunId,
ShuttleVariant,
} from "../../../models/shuttle"
import { drawnStatus, statusClasses } from "../../../models/vehicleStatus"
import { Vehicle } from "../../../realtime"
import { ReactMarker } from "../utilities/reactMarker"

Expand All @@ -24,6 +27,41 @@ interface VehicleMarkerProps extends PropsWithChildren {
onShouldShowPopupChange?: (newValue: boolean) => void
}

/**
* If the supplied {@linkcode vehicle} is a shuttle, returns
* classes to more specifically style shuttles matching certain conditions.
* For example, specific styles depending on Rapid Transit Line the shuttle is
* associated with.
*
* @param vehicle The vehicle to return styles for
* @returns Array of classes to add to a vehicle marker
*/
const stylesForShuttle = (vehicle: Vehicle) => {
// If this vehicle isn't a shuttle, return no styles
if (vehicle.isShuttle === false) {
return []
}

// Otherwise return a generic shuttle class and any more
// specific styles for the shuttle.
const classFor = (variant: string) => `c-vehicle-marker--${variant}`
const shuttleClasses = ["c-vehicle-marker--shuttle"]
switch (vehicle.runId && shuttleVariantFromRunId(vehicle.runId)) {
case ShuttleVariant.Blue:
return shuttleClasses.concat(classFor("blue"))
case ShuttleVariant.CommuterRail:
return shuttleClasses.concat(classFor("cr"))
case ShuttleVariant.Green:
return shuttleClasses.concat(classFor("green"))
case ShuttleVariant.Orange:
return shuttleClasses.concat(classFor("orange"))
case ShuttleVariant.Red:
return shuttleClasses.concat(classFor("red"))
default:
return shuttleClasses
}
}

export const VehicleMarker = ({
children,
vehicle,
Expand Down Expand Up @@ -90,10 +128,15 @@ export const VehicleMarker = ({
ref={markerRef}
divIconSettings={{
iconAnchor: [0, 0],
className: "c-vehicle-map__icon",
// Disable default leaflet marker class
className: "",
}}
icon={
<svg
className={joinClasses([
"c-vehicle-map__icon",
...stylesForShuttle(vehicle),
])}
height="24"
viewBox="0 0 24 24"
width="24"
Expand Down Expand Up @@ -124,14 +167,16 @@ export const VehicleMarker = ({
position={position}
divIconSettings={{
iconAnchor: [labelBackgroundWidth / 2, isPrimary ? -16 : -10],
className: joinClasses([
"c-vehicle-map__label",
isPrimary ? "primary" : "secondary",
isSelected && "selected",
]),
// Disable default leaflet marker class
className: "",
}}
icon={
<svg
className={joinClasses([
"c-vehicle-map__label",
isPrimary ? "primary" : "secondary",
isSelected && "selected",
])}
viewBox={`0 0 ${labelBackgroundWidth} ${labelBackgroundHeight}`}
width={labelBackgroundWidth}
height={labelBackgroundHeight}
Expand Down
35 changes: 34 additions & 1 deletion assets/src/models/shuttle.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,37 @@
import { Vehicle } from "../realtime"
import { RunId, Vehicle } from "../realtime"

export enum ShuttleVariant {
// Rapid Transit Lines
Blue,
Green,
Orange,
Red,

// Other Shuttle Types
CommuterRail,
Special,
}

export const shuttleVariantFromRunId = (
runId: RunId
): ShuttleVariant | null => {
switch (runId) {
case "999-0501":
return ShuttleVariant.Blue
case "999-0502":
return ShuttleVariant.Green
case "999-0503":
return ShuttleVariant.Orange
case "999-0504":
return ShuttleVariant.Red
case "999-0505":
return ShuttleVariant.CommuterRail
case "999-0555":
return ShuttleVariant.Special
default:
return null
}
}

export const formattedRunNumber = ({ runId }: Vehicle): string => {
if (runId === null) {
Expand Down
12 changes: 8 additions & 4 deletions assets/tests/components/__snapshots__/mapPage.test.tsx.snap
Original file line number Diff line number Diff line change
Expand Up @@ -1739,12 +1739,13 @@ exports[`<MapPage /> Snapshot renders vehicle data 1`] = `
</div>
</div>
<div
class="leaflet-marker-icon c-vehicle-map__icon leaflet-zoom-hide leaflet-interactive"
class="leaflet-marker-icon leaflet-zoom-hide leaflet-interactive"
role="button"
style="margin-left: 0px; margin-top: 0px; width: 12px; height: 12px; left: 223px; top: 27px; z-index: 1027;"
tabindex="0"
>
<svg
class="c-vehicle-map__icon"
height="24"
viewBox="0 0 24 24"
width="24"
Expand All @@ -1758,12 +1759,13 @@ exports[`<MapPage /> Snapshot renders vehicle data 1`] = `
</svg>
</div>
<div
class="leaflet-marker-icon c-vehicle-map__label primary selected leaflet-zoom-hide leaflet-interactive"
class="leaflet-marker-icon leaflet-zoom-hide leaflet-interactive"
role="button"
style="margin-left: -20px; margin-top: 16px; width: 12px; height: 12px; left: 223px; top: 27px; z-index: 1027;"
tabindex="0"
>
<svg
class="c-vehicle-map__label primary selected"
height="16"
viewBox="0 0 40 16"
width="40"
Expand All @@ -1787,12 +1789,13 @@ exports[`<MapPage /> Snapshot renders vehicle data 1`] = `
</svg>
</div>
<div
class="leaflet-marker-icon c-vehicle-map__icon leaflet-zoom-hide leaflet-interactive"
class="leaflet-marker-icon leaflet-zoom-hide leaflet-interactive"
role="button"
style="margin-left: 0px; margin-top: 0px; width: 12px; height: 12px; left: 223px; top: 27px; z-index: 27; z-index: 27;"
tabindex="0"
>
<svg
class="c-vehicle-map__icon"
height="24"
viewBox="0 0 24 24"
width="24"
Expand All @@ -1806,12 +1809,13 @@ exports[`<MapPage /> Snapshot renders vehicle data 1`] = `
</svg>
</div>
<div
class="leaflet-marker-icon c-vehicle-map__label secondary leaflet-zoom-hide leaflet-interactive"
class="leaflet-marker-icon leaflet-zoom-hide leaflet-interactive"
role="button"
style="margin-left: -15px; margin-top: 10px; width: 12px; height: 12px; left: 223px; top: 27px; z-index: 27; z-index: 27;"
tabindex="0"
>
<svg
class="c-vehicle-map__label secondary"
height="12"
viewBox="0 0 30 12"
width="30"
Expand Down
Loading

0 comments on commit 181a732

Please sign in to comment.