diff --git a/examples/directions/README.md b/examples/directions/README.md index 8de64737..7a0a8507 100644 --- a/examples/directions/README.md +++ b/examples/directions/README.md @@ -1,19 +1,14 @@ -# Google Maps Directions API Example +# Google Maps Routes API Example ![image](https://raw.githubusercontent.com/visgl/react-google-maps/main/website/static/images/examples/directions.jpg) -This is an example which shows how to use `useMapsLibrary` to load the `routes` library, and then use `DirectionsService` and `DirectionsRenderer` to find and display a route on a map. +This is an example which shows how to use `useMapsLibrary` to load the `routes` library, and then use the modern `Route` class to compute and render routes on a map. -It allows the user to choose alternative routes, updating the route being rendered on the map. - -Users can also drag the markers around the map to change the route. The route is updated in real-time. +It utilizes the modern client-side `Route.computeRoutes()` method combined with `createPolylines()` and `createWaypointAdvancedMarkers()` for rendering routes and markers on the map, completely avoiding legacy services and CORS restrictions. > [!IMPORTANT] > -> This example is only compatible with the -> Directions API Legacy Service. Using this Services requires enabling the -> API on your Google Cloud project by following the direct links: -> [Directions API (Legacy)][gcp-directions-api] +> This example uses the new [Routes API (Recommended)][gcp-routes-api] which is the modern and current way to calculate directions. If you are using the [Directions API (Legacy)][gcp-directions-api] Service, consider switching to this implementation of Routes API. ## Google Maps Platform API Key @@ -47,3 +42,4 @@ The regular `npm start` task is only used for the standalone versions of the exa [get-api-key]: https://developers.google.com/maps/documentation/javascript/get-api-key [gcp-directions-api]: https://console.cloud.google.com/apis/library/directions-backend.googleapis.com +[gcp-routes-api]: https://console.cloud.google.com/apis/library/routes.googleapis.com diff --git a/examples/directions/src/app.tsx b/examples/directions/src/app.tsx index 7f551002..95edd61a 100644 --- a/examples/directions/src/app.tsx +++ b/examples/directions/src/app.tsx @@ -1,11 +1,11 @@ -import React, {useEffect, useState} from 'react'; +import React, {useEffect, useRef} from 'react'; import {createRoot} from 'react-dom/client'; import { APIProvider, Map, - useMapsLibrary, - useMap + useMap, + useMapsLibrary } from '@vis.gl/react-google-maps'; import ControlPanel from './control-panel'; @@ -15,106 +15,111 @@ const API_KEY = const App = () => ( - + ); -function Directions() { +interface DirectionsProps { + origin: string; + destination: string; + travelMode?: google.maps.TravelModeString; +} + +export function Directions({ + origin, + destination, + travelMode = 'DRIVING' +}: DirectionsProps) { const map = useMap(); - const routesLibrary = useMapsLibrary('routes'); - const [directionsService, setDirectionsService] = - useState(); - const [directionsRenderer, setDirectionsRenderer] = - useState(); - const [routes, setRoutes] = useState([]); - const [routeIndex, setRouteIndex] = useState(0); - const selected = routes[routeIndex]; - const leg = selected?.legs[0]; - - // Initialize directions service and renderer - useEffect(() => { - if (!routesLibrary || !map) return; - setDirectionsService(new routesLibrary.DirectionsService()); - setDirectionsRenderer( - new routesLibrary.DirectionsRenderer({ - draggable: true, // Only necessary for draggable markers - map - }) - ); - }, [routesLibrary, map]); + const routesLib = useMapsLibrary('routes'); + + // refs for the polylines and markers created with the Routes API + const polylinesRef = useRef([]); + const markersRef = useRef([]); - // Add the following useEffect to make markers draggable - useEffect(() => { - if (!directionsRenderer) return; - - // Add the listener to update routes when directions change - const listener = directionsRenderer.addListener( - 'directions_changed', - () => { - const result = directionsRenderer.getDirections(); - if (result) { - setRoutes(result.routes); - } - } - ); - - return () => google.maps.event.removeListener(listener); - }, [directionsRenderer]); - - // Use directions service useEffect(() => { - if (!directionsService || !directionsRenderer) return; - - directionsService - .route({ - origin: '100 Front St, Toronto ON', - destination: '500 College St, Toronto ON', - travelMode: google.maps.TravelMode.DRIVING, - provideRouteAlternatives: true + if (!routesLib || !map || !origin || !destination) return; + + // cancel async operations on unmount (no AbortSignal support in Routes API) + let isCancelled = false; + + // Clean up previous polylines & markers + polylinesRef.current.forEach(p => p.setMap(null)); + polylinesRef.current = []; + markersRef.current.forEach(m => { + m.map = null; + }); + markersRef.current = []; + + const request: google.maps.routes.ComputeRoutesRequest = { + origin, + destination, + travelMode, + fields: ['path', 'distanceMeters', 'durationMillis', 'viewport', 'legs'] + }; + + routesLib.Route.computeRoutes(request) + .then(async ({routes}) => { + if (isCancelled) return; + if (!routes || routes.length === 0) return; + + const route = routes[0]; + + // Render and append polylines + const newPolylines = route.createPolylines(); + newPolylines.forEach(polyline => { + polyline.setOptions({ + strokeColor: '#3b82f6', + strokeOpacity: 0.85, + strokeWeight: 6 + }); + polyline.setMap(map); + }); + polylinesRef.current = newPolylines; + + // Render waypoint advanced markers + const newMarkers = await route.createWaypointAdvancedMarkers(); + + if (isCancelled) return; + + newMarkers.forEach(marker => { + marker.map = map; + }); + markersRef.current = newMarkers; + + if (route.viewport) map.fitBounds(route.viewport); }) - .then(response => { - directionsRenderer.setDirections(response); - setRoutes(response.routes); + .catch(err => { + if (isCancelled) return; + console.error('Error computing routes:', err); }); - return () => directionsRenderer.setMap(null); - }, [directionsService, directionsRenderer]); + return () => { + isCancelled = true; - // Update direction route - useEffect(() => { - if (!directionsRenderer) return; - directionsRenderer.setRouteIndex(routeIndex); - }, [routeIndex, directionsRenderer]); - - if (!leg) return null; - - return ( -
-

{selected.summary}

-

- {leg.start_address.split(',')[0]} to {leg.end_address.split(',')[0]} -

-

Distance: {leg.distance?.text}

-

Duration: {leg.duration?.text}

- -

Other Routes

-
    - {routes.map((route, index) => ( -
  • - -
  • - ))} -
-
- ); + // clear polylines and markers + polylinesRef.current.forEach(p => p.setMap(null)); + polylinesRef.current = []; + + markersRef.current.forEach(marker => { + marker.map = null; + }); + markersRef.current = []; + }; + }, [routesLib, map, origin, destination, travelMode]); + + return null; } export default App; diff --git a/examples/directions/src/control-panel.tsx b/examples/directions/src/control-panel.tsx index 5b3a75db..49166140 100644 --- a/examples/directions/src/control-panel.tsx +++ b/examples/directions/src/control-panel.tsx @@ -4,23 +4,29 @@ import './control-panel.css'; const GCP_DIRECTIONS_API = 'https://console.cloud.google.com/apis/library/directions-backend.googleapis.com'; +const GCP_ROUTES_API = + 'https://console.cloud.google.com/apis/library/routes.googleapis.com'; + function ControlPanel() { return (
-

Directions

+

Routes API

- Loading the routes library to render directions on the map using - DirectionsService and DirectionsRenderer. + Loading the routes library to compute and render routes on the map using + the modern Route.computeRoutes service.

- Important: This example is only compatible with the - Directions API Legacy Service. Using this Services requires enabling the - API on your Google Cloud project by following the direct links:{' '} + Important: This example uses the new{' '} + + Routes API (Recommended) + {' '} + , the modern and current way to calculate directions. If you are using + the{' '} Directions API (Legacy) - - . + {' '} + Service, switch to this implementation of Routes API.

diff --git a/website/static/images/examples/directions.jpg b/website/static/images/examples/directions.jpg index dfa152ad..461c63ff 100644 Binary files a/website/static/images/examples/directions.jpg and b/website/static/images/examples/directions.jpg differ