Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add to single line map arrowa to navigate between points #798

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 31 additions & 7 deletions src/pages/components/map-related/MapContent.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Marker, Polyline, Popup, TileLayer } from 'react-leaflet'
import { Icon, IconOptions } from 'leaflet'
import { useRef } from 'react'
import { Marker, Polyline, Popup, TileLayer, useMap } from 'react-leaflet'
import { Icon, IconOptions, Marker as LeafletMarker } from 'leaflet'
import { useAgencyList } from 'src/api/agencyList'
import { busIcon, busIconPath } from '../utils/BusIcon'
import { BusToolTip } from './MapLayers/BusToolTip'
Expand All @@ -8,12 +9,13 @@ import '../../Map.scss'
import { MapProps } from './map-types'
import { useRecenterOnDataChange } from './useRecenterOnDataChange'
import { MapIndex } from './MapIndex'
import MapFooterButtons from './MapFooterButtons/MapFooterButtons'

export function MapContent({ positions, plannedRouteStops }: MapProps) {
export function MapContent({ positions, plannedRouteStops, showNavigationButtons }: MapProps) {
useRecenterOnDataChange({ positions, plannedRouteStops })

const markerRef = useRef<{ [key: number]: LeafletMarker | null }>({})
const map = useMap()
const agencyList = useAgencyList()

const getIcon = (path: string, width: number = 10, height: number = 10): Icon<IconOptions> => {
return new Icon<IconOptions>({
iconUrl: path,
Expand All @@ -28,6 +30,16 @@ export function MapContent({ positions, plannedRouteStops }: MapProps) {
const actualRouteStopMarker = getIcon(actualRouteStopMarkerPath, 20, 20)
const plannedRouteStopMarker = getIcon(plannedRouteStopMarkerPath, 20, 25)

const navigateMarkers = (positionId: number) => {
const loc = positions[positionId]?.loc
if (!map || !loc) return
const marker = markerRef?.current && markerRef?.current[positionId]
if (marker) {
map.flyTo(loc, map.getZoom())
marker.openPopup()
}
}

return (
<>
<TileLayer
Expand Down Expand Up @@ -56,9 +68,21 @@ export function MapContent({ positions, plannedRouteStops }: MapProps) {
})
: actualRouteStopMarker
return (
<Marker position={pos.loc} icon={icon} key={i}>
<Marker
ref={(ref) => (markerRef.current[i] = ref)}
position={pos.loc}
icon={icon}
key={i}>
<Popup minWidth={300} maxWidth={700}>
<BusToolTip position={pos} icon={busIconPath(pos.operator!)} />
<BusToolTip position={pos} icon={busIconPath(pos.operator!)}>
{showNavigationButtons && (
<MapFooterButtons
index={i}
positions={positions}
navigateMarkers={navigateMarkers}
/>
)}
</BusToolTip>
</Popup>
</Marker>
)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
.map-footer-buttons {
display: flex;
justify-content: space-between;

.disabled {
pointer-events: none;
opacity: 0.5;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { LeftOutlined, RightOutlined } from '@ant-design/icons'
import { Point } from 'src/pages/timeBasedMap'
import './MapFooterButtons.scss'

type TMapFooterButtons = {
index: number
positions: Point[]
navigateMarkers: (id: number) => void
}

function MapFooterButtons({ index, positions, navigateMarkers }: TMapFooterButtons) {
const rightStep = index + 1
const leftStep = index - 1

const checkIfValidStep = (i: number) => {
return Boolean(positions.at(i))
}

return (
<div className="map-footer-buttons">
<RightOutlined
title={'right-chevron'}
className={`${checkIfValidStep(rightStep) ? '' : 'disabled'}`}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just an idea - we can hide the button if it's not relevant for this data point

onClick={() => navigateMarkers(rightStep)}
/>
<LeftOutlined
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can add a "title" attribute for hover ("prev" / "next")

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I choose to use right/left-chevron instead cuz 'prev' 'next' depend on the direction
image

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the title attribute is visible to users, and should help them understand whether right will indicate the previous or the next item of the list.
In RTL website, it's common to see right arrows serving as "next" buttons, while on LTR website it's the opposite, that's why I feel having this title can be significant to the user experience

image

title={'left-chevron'}
className={`${checkIfValidStep(leftStep) ? '' : 'disabled'}`}
onClick={() => navigateMarkers(leftStep)}
/>
</div>
)
}

export default MapFooterButtons
7 changes: 4 additions & 3 deletions src/pages/components/map-related/MapLayers/BusToolTip.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useEffect, useState } from 'react'
import { ReactNode, useEffect, useState } from 'react'
import { Link } from 'react-router-dom'
import { Point } from 'src/pages/timeBasedMap'
import { Button } from '@mui/material'
Expand All @@ -11,9 +11,9 @@ import CircularProgress from '@mui/material/CircularProgress'
import cn from 'classnames'
import CustomTreeView from '../../CustomTreeView'

export type BusToolTipProps = { position: Point; icon: string }
export type BusToolTipProps = { position: Point; icon: string; children?: ReactNode }

export function BusToolTip({ position, icon }: BusToolTipProps) {
export function BusToolTip({ position, icon, children }: BusToolTipProps) {
const [siriRide, setSiriRide] = useState<SiriRideWithRelatedPydanticModel | undefined>()
const [isLoading, setIsLoading] = useState(false)
const [showJson, setShowJson] = useState(false)
Expand Down Expand Up @@ -110,6 +110,7 @@ export function BusToolTip({ position, icon }: BusToolTipProps) {
</div>
)}
</div>
{children}
</>
)}
</div>
Expand Down
12 changes: 10 additions & 2 deletions src/pages/components/map-related/MapWithLocationsAndPath.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,11 @@ const position: Point = {
color: 0,
}

export function MapWithLocationsAndPath({ positions, plannedRouteStops }: MapProps) {
export function MapWithLocationsAndPath({
positions,
plannedRouteStops,
showNavigationButtons,
}: MapProps) {
const [isExpanded, setIsExpanded] = useState<boolean>(false)
const toggleExpanded = useCallback(() => setIsExpanded((expanded) => !expanded), [])

Expand All @@ -23,7 +27,11 @@ export function MapWithLocationsAndPath({ positions, plannedRouteStops }: MapPro
</IconButton>

<MapContainer center={position.loc} zoom={13} scrollWheelZoom={true}>
<MapContent positions={positions} plannedRouteStops={plannedRouteStops} />
<MapContent
positions={positions}
plannedRouteStops={plannedRouteStops}
showNavigationButtons={showNavigationButtons}
/>
</MapContainer>
</div>
)
Expand Down
1 change: 1 addition & 0 deletions src/pages/components/map-related/map-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,5 @@ export interface Path {
export interface MapProps {
positions: Point[]
plannedRouteStops: BusStop[]
showNavigationButtons?: boolean
}
1 change: 1 addition & 0 deletions src/pages/singleLineMap/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ const SingleLineMapPage = () => {
<MapWithLocationsAndPath
positions={filteredPositions}
plannedRouteStops={plannedRouteStops}
showNavigationButtons
/>
</PageContainer>
)
Expand Down
Loading