diff --git a/src/pages/components/map-related/MapContent.tsx b/src/pages/components/map-related/MapContent.tsx new file mode 100644 index 00000000..04bf9397 --- /dev/null +++ b/src/pages/components/map-related/MapContent.tsx @@ -0,0 +1,94 @@ +import { Marker, Polyline, Popup, TileLayer } from 'react-leaflet' +import { Icon, IconOptions } from 'leaflet' +import { useAgencyList } from 'src/api/agencyList' +import { busIcon, busIconPath } from '../utils/BusIcon' +import { BusToolTip } from './MapLayers/BusToolTip' +import { t } from 'i18next' +import '../../Map.scss' +import { MapProps } from './map-types' +import { useRecenterOnDataChange } from './useRecenterOnDataChange' +import { MapIndex } from './MapIndex' + +export function MapContent({ positions, plannedRouteStops }: MapProps) { + useRecenterOnDataChange({ positions, plannedRouteStops }) + + const agencyList = useAgencyList() + + const getIcon = (path: string, width: number = 10, height: number = 10): Icon => { + return new Icon({ + iconUrl: path, + iconSize: [width, height], + }) + } + // configs for planned & actual routes - line color & marker icon + const actualRouteStopMarkerPath = '/marker-dot.png' + const plannedRouteStopMarkerPath = '/marker-bus-stop.png' + const actualRouteLineColor = 'orange' + const plannedRouteLineColor = 'black' + const actualRouteStopMarker = getIcon(actualRouteStopMarkerPath, 20, 20) + const plannedRouteStopMarker = getIcon(plannedRouteStopMarkerPath, 20, 25) + + return ( + <> + +
+ + +
+ {positions.map((pos, i) => { + const icon = + i === 0 + ? busIcon({ + operator_id: pos.operator?.toString() || 'default', + name: agencyList.find((agency) => agency.operator_ref === pos.operator) + ?.agency_name, + }) + : actualRouteStopMarker + return ( + + + + + + ) + })} + + {plannedRouteStops?.length && ( + [ + stop.location.latitude, + stop.location.longitude, + ])} + /> + )} + {plannedRouteStops?.length && + plannedRouteStops.map((stop) => { + const { latitude, longitude } = stop.location + return ( + + ) + })} + {positions.length && ( + position.loc)} + /> + )} + + ) +} diff --git a/src/pages/components/map-related/MapIndex.tsx b/src/pages/components/map-related/MapIndex.tsx new file mode 100644 index 00000000..d5f7bd72 --- /dev/null +++ b/src/pages/components/map-related/MapIndex.tsx @@ -0,0 +1,23 @@ +export function MapIndex({ + lineColor, + imgSrc, + title, +}: { + lineColor: string + imgSrc: string + title: string +}) { + return ( +
+
+

+

+ {/* planned route stop icon */} +

+
+
+

{title}

+
+
+ ) +} diff --git a/src/pages/components/map-related/MapWithLocationsAndPath.tsx b/src/pages/components/map-related/MapWithLocationsAndPath.tsx index 8febf75d..e8001b0e 100644 --- a/src/pages/components/map-related/MapWithLocationsAndPath.tsx +++ b/src/pages/components/map-related/MapWithLocationsAndPath.tsx @@ -1,56 +1,21 @@ -import { MapContainer, Marker, Polyline, Popup, TileLayer, useMap } from 'react-leaflet' -import { Icon, IconOptions, LatLngTuple } from 'leaflet' -import { useAgencyList } from 'src/api/agencyList' +import { MapContainer } from 'react-leaflet' import { Point } from 'src/pages/timeBasedMap' -import { busIcon, busIconPath } from '../utils/BusIcon' -import { BusToolTip } from './MapLayers/BusToolTip' -import { VehicleLocation } from 'src/model/vehicleLocation' -import { useCallback, useEffect, useState } from 'react' +import { MapProps } from './map-types' +import { useCallback, useState } from 'react' import { Button } from 'antd' import { ExpandAltOutlined } from '@ant-design/icons' -import { BusStop } from 'src/model/busStop' -import { t } from 'i18next' import '../../Map.scss' -import { useTheme } from 'src/layout/ThemeContext' -import cn from 'classnames' +import { MapContent } from './MapContent' const position: Point = { loc: [32.3057988, 34.85478613], // arbitrary default value... Netanya - best city to live & die in color: 0, } -export interface Path { - locations: VehicleLocation[] - lineRef: number - operator: number - vehicleRef: number -} - -interface MapProps { - positions: Point[] - plannedRouteStops: BusStop[] -} - export function MapWithLocationsAndPath({ positions, plannedRouteStops }: MapProps) { - const { isDarkTheme } = useTheme() - const agencyList = useAgencyList() const [isExpanded, setIsExpanded] = useState(false) const toggleExpanded = useCallback(() => setIsExpanded((expanded) => !expanded), []) - const getIcon = (path: string, width: number = 10, height: number = 10): Icon => { - return new Icon({ - iconUrl: path, - iconSize: [width, height], - }) - } - // configs for planned & actual routes - line color & marker icon - const actualRouteStopMarkerPath = '/marker-dot.png' - const plannedRouteStopMarkerPath = '/marker-bus-stop.png' - const actualRouteLineColor = 'orange' - const plannedRouteLineColor = 'black' - const actualRouteStopMarker = getIcon(actualRouteStopMarkerPath, 20, 20) - const plannedRouteStopMarker = getIcon(plannedRouteStopMarkerPath, 20, 25) - return (
) } - -export function MapIndex({ - lineColor, - imgSrc, - title, -}: { - lineColor: string - imgSrc: string - title: string -}) { - return ( -
-
-

-

- {/* planned route stop icon */} -

-
-
-

{title}

-
-
- ) -} - -function RecenterOnDataChange({ positions, plannedRouteStops }: MapProps) { - const map = useMap() - - useEffect(() => { - const positionsSum = positions.reduce( - (acc, { loc }) => [acc[0] + loc[0], acc[1] + loc[1]], - [0, 0], - ) - const mean: LatLngTuple = [ - positionsSum[0] / positions.length || position.loc[0], - positionsSum[1] / positions.length || position.loc[1], - ] - - map.setView(mean, map.getZoom(), { animate: true }) - }, [positions, plannedRouteStops]) - - return null -} diff --git a/src/pages/components/map-related/map-types.ts b/src/pages/components/map-related/map-types.ts new file mode 100644 index 00000000..9ac8e679 --- /dev/null +++ b/src/pages/components/map-related/map-types.ts @@ -0,0 +1,15 @@ +import { Point } from 'src/pages/timeBasedMap' +import { BusStop } from 'src/model/busStop' +import { VehicleLocation } from 'src/model/vehicleLocation' + +export interface Path { + locations: VehicleLocation[] + lineRef: number + operator: number + vehicleRef: number +} + +export interface MapProps { + positions: Point[] + plannedRouteStops: BusStop[] +} diff --git a/src/pages/components/map-related/useRecenterOnDataChange.ts b/src/pages/components/map-related/useRecenterOnDataChange.ts new file mode 100644 index 00000000..f6ca9579 --- /dev/null +++ b/src/pages/components/map-related/useRecenterOnDataChange.ts @@ -0,0 +1,19 @@ +import { useEffect } from 'react' +import { LatLngTuple } from 'leaflet' +import { useMap } from 'react-leaflet' +import { MapProps } from './map-types' + +export function useRecenterOnDataChange({ positions }: MapProps) { + const map = useMap() + const positionsSum = positions.reduce( + (acc, { loc }) => [acc[0] + loc[0], acc[1] + loc[1]], + [0, 0], + ) + const mean: LatLngTuple = [positionsSum[0] / positions.length, positionsSum[1] / positions.length] + console.log('mean: ', mean) + useEffect(() => { + if (mean[0] || mean[1]) { + map.setView(mean, map.getZoom(), { animate: true }) + } + }, [mean]) +}