diff options
-rw-r--r-- | modern/src/MainPage.js | 5 | ||||
-rw-r--r-- | modern/src/map/LiveRoutesMap.js | 80 |
2 files changed, 85 insertions, 0 deletions
diff --git a/modern/src/MainPage.js b/modern/src/MainPage.js index ebd739d2..ccb3f83f 100644 --- a/modern/src/MainPage.js +++ b/modern/src/MainPage.js @@ -26,6 +26,8 @@ import MapPadding from './map/MapPadding'; import StatusCard from './map/StatusCard'; import { devicesActions } from './store'; import DefaultCameraMap from './map/DefaultCameraMap'; +import usePersistedState from './common/usePersistedState'; +import LiveRoutesMap from './map/LiveRoutesMap'; const useStyles = makeStyles((theme) => ({ root: { @@ -120,6 +122,8 @@ const MainPage = () => { const isTablet = useMediaQuery(theme.breakpoints.down('md')); const isPhone = useMediaQuery(theme.breakpoints.down('xs')); + const [mapLiveRoutes] = usePersistedState('mapLiveRoutes', false); + const selectedDeviceId = useSelector((state) => state.devices.selectedId); const [searchKeyword, setSearchKeyword] = useState(''); @@ -138,6 +142,7 @@ const MainPage = () => { <CurrentLocationMap /> <GeofenceMap /> <AccuracyMap /> + {mapLiveRoutes && <LiveRoutesMap />} <CurrentPositionsMap /> <DefaultCameraMap /> <SelectedDeviceMap /> diff --git a/modern/src/map/LiveRoutesMap.js b/modern/src/map/LiveRoutesMap.js new file mode 100644 index 00000000..3cc89774 --- /dev/null +++ b/modern/src/map/LiveRoutesMap.js @@ -0,0 +1,80 @@ +import { useEffect, useState } from 'react'; + +import { useSelector } from 'react-redux'; +import { map } from './Map'; +import { usePrevious } from '../reactHelper'; + +const LiveRoutesMap = () => { + const id = 'liveRoute'; + + const selectedDeviceId = useSelector((state) => state.devices.selectedId); + const currentDeviceId = usePrevious(selectedDeviceId); + + const position = useSelector((state) => state.positions.items[selectedDeviceId]); + + const [route, setRoute] = useState([]); + + useEffect(() => { + map.addSource(id, { + type: 'geojson', + data: { + type: 'Feature', + geometry: { + type: 'LineString', + coordinates: [], + }, + }, + }); + map.addLayer({ + source: id, + id, + type: 'line', + layout: { + 'line-join': 'round', + 'line-cap': 'round', + }, + paint: { + 'line-color': '#3bb2d0', + 'line-width': 2, + }, + }); + + return () => { + if (map.getLayer(id)) { + map.removeLayer(id); + } + if (map.getSource(id)) { + map.removeSource(id); + } + }; + }, []); + + useEffect(() => { + if (selectedDeviceId !== currentDeviceId) { + if (!selectedDeviceId) { + setRoute([]); + } else if (position) { + setRoute([position]); + } + } else if (position) { + const last = route.at(-1); + if (!last || (last.latitude !== position.latitude && last.longitude !== position.longitude)) { + setRoute([...route.slice(-9), position]); + } + } + }, [selectedDeviceId, currentDeviceId, position, route]); + + useEffect(() => { + map.getSource(id).setData({ + type: 'Feature', + geometry: { + type: 'LineString', + coordinates: route.map((item) => [item.longitude, item.latitude]), + }, + }); + }, [route]); + + return null; +}; + +export default LiveRoutesMap; |