SPRINT 4 ‐ Routes - BlueJayBird11/UniJet GitHub Wiki
The goal for this user story is to create routes that highlight the path the driver should take in order to pick the rider up and the path to deliver them to their destination. To do this, several steps must be taken.
First, you must create an account at mapbox.com and obtain an access token. Once completed, you must also install the Mapbox SDK using npm install @mapbox/mapbox-sdk
and use necessary imports.
Next, we will initialize the state variables and set up the map component. State variables routeToDestination
and routeToUser
are used to hold the coordinates of the routes to the destination and from the driver's location to the user's location. The useEffect
hook ensures that the code inside it runs only once when the component mounts. We will go over this more later.
const [routeToDestination, setRouteToDestination] = useState<[number, number][] | null>(null);
const [routeToUser, setRouteToUser] = useState<[number, number][] | null>(null);
useEffect(() => {
// Fetch user's current location and routes on component mount
}, []);
Thirdly, we will use the fetchRoute
function to make an asynchronous HTTP request to the Mapbox API to fetch route data between two sets of coordinates. It constructs the URL with start and end coordinates and the Mapbox access token. The route coordinates are extracted from the Mapbox API JSON response, and the routes are updated.
const fetchRoute = async (startLat: number, startLng: number, endLat: number, endLng: number, setRoute: React.Dispatch<React.SetStateAction<[number, number][] | null>>) => {
// Construct URL for Mapbox API
const url = `https://api.mapbox.com/directions/v5/mapbox/driving/${startLng},${startLat};${endLng},${endLat}?geometries=geojson&access_token=${mapboxAccessToken}`;
try {
// Fetch route data from Mapbox API
const response = await fetch(url);
const data = await response.json();
// Extract route coordinates from response data
const routeCoordinates = data.routes[0].geometry.coordinates;
// Update route state with converted coordinates
setRoute(routeCoordinates.map(([lng, lat]) => [lat, lng])); // Convert to Leaflet's format
} catch (error) {
console.error('Failed to fetch route:', error);
}
};
Now, we will add to the useEffect
hook that we touched on briefly earlier. navigator.geolocation.watchPosition
is used to continuously monitor the user's position. When a new position is obtained, the position
state is updated, and the fetchRoute
function fetches routes to the destinations. A cleanup function is then returned to clear the geolocation watch when the component unomounts.
useEffect(() => {
// Watch user's geolocation
const watchId = navigator.geolocation.watchPosition(
(position) => {
const { latitude, longitude } = position.coords;
setPosition([latitude, longitude]);
// Fetch route to destination
fetchRoute(latitude, longitude, placeholderLocation[0], placeholderLocation[1], setRouteToDestination);
// Fetch reverse route (from driver's location to user's location)
fetchRoute(driverLocation[0], driverLocation[1], latitude, longitude, setRouteToUser);
},
(error) => console.error('Error watching position:', error),
{ enableHighAccuracy: true, maximumAge: 0 }
);
return () => navigator.geolocation.clearWatch(watchId);
}, []);
Finally, we must display the lines of the defined routes. routeToDestination
and routeToUser
states are checked to make sure they are not null, then the corresponding polylines are rendered.
return (
<div className="h-screen">
<MapContainer style={{ width: '100%', height: '90.5%' }} center={position} zoom={13} scrollWheelZoom={true}>
{/* OpenStreetMap Tile Layer */}
<TileLayer
attribution='© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
/>
{/* Marker for user's current location */}
<Marker position={position}>
<Popup>You are here</Popup>
</Marker>
{/* Polyline for route to destination */}
{routeToDestination && <Polyline positions={routeToDestination} color="blue" />}
{/* Polyline for route from driver's location to user's location */}
{routeToUser && <Polyline positions={routeToUser} color="red" />}
</MapContainer>
</div>
);
After all these steps have been taken, your map should look something like this:
The red route goes from the a placeholder driver location to the rider's location, and the blue route goes from the rider's location to the rider's placeholder destination.