-
Notifications
You must be signed in to change notification settings - Fork 88
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
refactor: create MapContent component #743
Changes from 5 commits
5c816e7
2d98093
3f04867
e95eb84
4f71c21
1d441e1
3510433
5cda4c1
bc828d2
b6ee0c8
93fcfab
e5e5a0c
1874267
a7abd6e
69b2250
6057c37
d7de572
f5ca0f6
b1d1ddd
2173a6b
193f615
a360e02
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 './MapWithLocationsAndPath' | ||
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<IconOptions> => { | ||
return new Icon<IconOptions>({ | ||
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 ( | ||
<> | ||
<TileLayer | ||
attribution='© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors' | ||
url="https://tile-a.openstreetmap.fr/hot/{z}/{x}/{y}.png" | ||
/> | ||
<div className="map-index"> | ||
<MapIndex | ||
lineColor={actualRouteLineColor} | ||
imgSrc={actualRouteStopMarkerPath} | ||
title={t('actualRoute')} | ||
/> | ||
<MapIndex | ||
lineColor={plannedRouteLineColor} | ||
imgSrc={plannedRouteStopMarkerPath} | ||
title={t('plannedRoute')} | ||
/> | ||
</div> | ||
{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 ( | ||
<Marker position={pos.loc} icon={icon} key={i}> | ||
<Popup minWidth={300} maxWidth={700}> | ||
<BusToolTip position={pos} icon={busIconPath(pos.operator!)} /> | ||
</Popup> | ||
</Marker> | ||
) | ||
})} | ||
|
||
{plannedRouteStops?.length && ( | ||
<Polyline | ||
pathOptions={{ color: plannedRouteLineColor }} | ||
positions={plannedRouteStops.map((stop) => [ | ||
stop.location.latitude, | ||
stop.location.longitude, | ||
])} | ||
/> | ||
)} | ||
{plannedRouteStops?.length && | ||
plannedRouteStops.map((stop) => { | ||
const { latitude, longitude } = stop.location | ||
return ( | ||
<Marker | ||
key={'' + latitude + longitude} | ||
position={[latitude, longitude]} | ||
icon={plannedRouteStopMarker}></Marker> | ||
) | ||
})} | ||
{positions.length && ( | ||
<Polyline | ||
pathOptions={{ color: actualRouteLineColor }} | ||
positions={positions.map((position) => position.loc)} | ||
/> | ||
)} | ||
</> | ||
) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
export function MapIndex({ | ||
lineColor, | ||
imgSrc, | ||
title, | ||
}: { | ||
lineColor: string | ||
imgSrc: string | ||
title: string | ||
}) { | ||
return ( | ||
<div className="map-index-item"> | ||
<div className="map-index-item-config"> | ||
<p className="map-index-item-line" style={{ backgroundColor: lineColor }}></p> | ||
<p className="map-index-item-icon" style={{ backgroundImage: `url(${imgSrc})` }}> | ||
{/* <img src={imgSrc} alt="planned route stop icon" /> */} | ||
</p> | ||
</div> | ||
<div className="map-index-item-title"> | ||
<h3>{title}</h3> | ||
</div> | ||
</div> | ||
) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,18 +1,15 @@ | ||
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 { MapContent } from './MapContent' | ||
|
||
import { VehicleLocation } from 'src/model/vehicleLocation' | ||
import { useCallback, useEffect, useState } from 'react' | ||
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' | ||
|
||
const position: Point = { | ||
export const position: Point = { | ||
loc: [32.3057988, 34.85478613], // arbitrary default value... Netanya - best city to live & die in | ||
color: 0, | ||
} | ||
|
@@ -24,30 +21,15 @@ export interface Path { | |
vehicleRef: number | ||
} | ||
|
||
interface MapProps { | ||
export interface MapProps { | ||
positions: Point[] | ||
plannedRouteStops: BusStop[] | ||
} | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. exporting this to a different file ( There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ok |
||
export function MapWithLocationsAndPath({ positions, plannedRouteStops }: MapProps) { | ||
const agencyList = useAgencyList() | ||
const [isExpanded, setIsExpanded] = useState<boolean>(false) | ||
const toggleExpanded = useCallback(() => setIsExpanded((expanded) => !expanded), []) | ||
|
||
const getIcon = (path: string, width: number = 10, height: number = 10): Icon<IconOptions> => { | ||
return new Icon<IconOptions>({ | ||
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 ( | ||
<div className={`map-info ${isExpanded ? 'expanded' : 'collapsed'}`}> | ||
<Button | ||
|
@@ -58,110 +40,27 @@ export function MapWithLocationsAndPath({ positions, plannedRouteStops }: MapPro | |
icon={<ExpandAltOutlined />} | ||
/> | ||
<MapContainer center={position.loc} zoom={13} scrollWheelZoom={true}> | ||
<TileLayer | ||
attribution='© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors' | ||
url="https://tile-a.openstreetmap.fr/hot/{z}/{x}/{y}.png" | ||
/> | ||
<div className="map-index"> | ||
<MapIndex | ||
lineColor={actualRouteLineColor} | ||
imgSrc={actualRouteStopMarkerPath} | ||
title={t('actualRoute')} | ||
/> | ||
<MapIndex | ||
lineColor={plannedRouteLineColor} | ||
imgSrc={plannedRouteStopMarkerPath} | ||
title={t('plannedRoute')} | ||
/> | ||
</div> | ||
{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 ( | ||
<Marker position={pos.loc} icon={icon} key={i}> | ||
<Popup minWidth={300} maxWidth={700}> | ||
<BusToolTip position={pos} icon={busIconPath(pos.operator!)} /> | ||
</Popup> | ||
</Marker> | ||
) | ||
})} | ||
|
||
{plannedRouteStops?.length && ( | ||
<Polyline | ||
pathOptions={{ color: plannedRouteLineColor }} | ||
positions={plannedRouteStops.map((stop) => [ | ||
stop.location.latitude, | ||
stop.location.longitude, | ||
])} | ||
/> | ||
)} | ||
{plannedRouteStops?.length && | ||
plannedRouteStops.map((stop) => { | ||
const { latitude, longitude } = stop.location | ||
return ( | ||
<Marker | ||
key={'' + latitude + longitude} | ||
position={[latitude, longitude]} | ||
icon={plannedRouteStopMarker}></Marker> | ||
) | ||
})} | ||
{positions.length && ( | ||
<Polyline | ||
pathOptions={{ color: actualRouteLineColor }} | ||
positions={positions.map((position) => position.loc)} | ||
/> | ||
)} | ||
<RecenterOnDataChange positions={positions} plannedRouteStops={plannedRouteStops} /> | ||
<MapContent positions={positions} plannedRouteStops={plannedRouteStops} /> | ||
</MapContainer> | ||
</div> | ||
) | ||
} | ||
|
||
export function MapIndex({ | ||
lineColor, | ||
imgSrc, | ||
title, | ||
}: { | ||
lineColor: string | ||
imgSrc: string | ||
title: string | ||
}) { | ||
return ( | ||
<div className="map-index-item"> | ||
<div className="map-index-item-config"> | ||
<p className="map-index-item-line" style={{ backgroundColor: lineColor }}></p> | ||
<p className="map-index-item-icon" style={{ backgroundImage: `url(${imgSrc})` }}> | ||
{/* <img src={imgSrc} alt="planned route stop icon" /> */} | ||
</p> | ||
</div> | ||
<div className="map-index-item-title"> | ||
<h3>{title}</h3> | ||
</div> | ||
</div> | ||
) | ||
} | ||
// export function RecenterOnDataChange({ positions, plannedRouteStops }: MapProps) { | ||
// const map = useMap() | ||
|
||
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], | ||
// ] | ||
|
||
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]) | ||
|
||
map.setView(mean, map.getZoom(), { animate: true }) | ||
}, [positions, plannedRouteStops]) | ||
|
||
return null | ||
} | ||
// return null | ||
// } |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import { useEffect } from 'react' | ||
import { LatLngTuple } from 'leaflet' | ||
import { useMap } from 'react-leaflet' | ||
import { MapProps, position } from './MapWithLocationsAndPath' | ||
|
||
export function useRecenterOnDataChange({ positions, plannedRouteStops }: 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 || position.loc[0], | ||
positionsSum[1] / positions.length || position.loc[1], | ||
NoamGaash marked this conversation as resolved.
Show resolved
Hide resolved
|
||
] | ||
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], | ||
// ] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. great! let's just remove the comments |
||
|
||
map.setView(mean, map.getZoom(), { animate: true }) | ||
}, [positions, plannedRouteStops]) | ||
NoamGaash marked this conversation as resolved.
Show resolved
Hide resolved
NoamGaash marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this cause a circular dependency error -