The Route demo lets you specify an origin and destination as a latitude/longitude coordinates pair or as a place ID. To copy the latitude/longitude coordinates, find and click a location on the map, and then paste the location into the form.
After you select Get route, the demo displays the response from the computeRoutes method as a route on the map.
See the complete example source code
The following demo lets you experiment with creating lots of different kinds of routes. Click the map to copy the latitude/longitude coordinates of a location. Paste the coordinates into the form to get directions.
TypeScript
let markers: google.maps.marker.AdvancedMarkerElement[] = []; let polylines: google.maps.Polyline[] = []; let waypointInfoWindow: google.maps.InfoWindow | null = null; interface PlaceAutocompleteSelection { predictionText: string | null; location: google.maps.LatLng | null; } const originAutocompleteSelection: PlaceAutocompleteSelection = { predictionText: null, location: null, }; const destinationAutocompleteSelection: PlaceAutocompleteSelection = { predictionText: null, location: null, }; async function init() { const [ { InfoWindow }, { AdvancedMarkerElement }, //prettier-ignore //@ts-ignore { PlaceAutocompleteElement }, //prettier-ignore //@ts-ignore { ComputeRoutesExtraComputation, ReferenceRoute, Route, RouteLabel }, ] = await Promise.all([ google.maps.importLibrary('maps') as< Promisegoogle.maps.Map>sLibrary, google.maps.importLibrary( 'marker' < ) as Promisegoogle.ma>ps.MarkerLibrary, google.maps.importLibrary( 'places<39; ) as Promiseg>oogle.maps.PlacesLibrary, google.maps.importLibrary( '<routes' ) as >Promisegoogle.maps.RoutesLibrary, ]); const map = document.getElementById('map') as google.maps.MapElement; attachSubmitListener(); initializeLocationInputs(); attachMapClickListener(); attachTravelModeListener(); attachAlertWindowListener(); attachDepartureTimeListener(); function attachSubmitListener() { const computeRoutesForm = document.getElementById( 'compute-routes-form' ) as HTMLFormElement; comput>eRoutesForm.addEventListener('submit', (event) = { event.preventDefault(); sendRequest(new FormData(computeRoutesForm)); }); } async function sendRequest(formData: FormData) { clearMap(); try { const { routes } = await Route.computeRoutes( buildComputeRoutesJsRequest(formData) ); if (!routes) { console.log('No routes returned.'); return; } > console.log('Routes:'); routes.forEach((route) = { console.log(route.toJSON()); >}); await Promise.all( routes.map((route) = drawRoute( route, !!route.routeLabels?.includes(RouteLabel.DEFAULT_ROUTE) ) ) ); } catch (error: unknown) { console.error(error); setErrorMessage((error as Error).message || 'Unknown error.'); } } function buildComputeRoutesJsRequest( formData: FormData //prettier-ignore //@ts-ignore ): google.maps.routes.ComputeRoutesRequest { const travelMode = (formData.get('travel_mode') as string) === '' ? undefined : (formData.get('travel_mode') as google.maps.TravelMode); //prettier-ignore //@ts-ignore const extraComputations: google.maps.routes.ComputeRoutesExtraComputation[] = []; //prettier-ignore //@ts-ignore const requestedReferenceRoutes: google.maps.routes.ReferenceRoute[] = []; //prettier-ignore //@ts-ignore const transitPreference: google.maps.routes.TransitPreference = {}; const request = { origin: { location: buildComputeRoutesLocation( originAutocompleteSelection, formData.get('origin_location'), formData.get('heading_org'), travelMode ), vehicleStopover: formData.get('origin_stopover') === 'on', sideOfRoad: formData.get('origin_side_of_road') === 'on', }, destination: { location: buildComputeRoutesLocation( destinationAutocompleteSelection, formData.get('destination_location'), formData.get('heading_dest'), travelMode ), vehicleStopover: formData.get('destination_stopover') === 'on', sideOfRoad: formData.get('destination_side_of_road') === 'on', > }, fields: Array.from( document.querySelectorAll( 'ul#fields li input[type="checkbox"]:checked' ), (input) = (input as HTMLInputElement).value ), travelMode: travelMode as google.maps.TravelMode, routingPreference: formData.get('routing_preference') === '' ? undefined : (formData.get( 'routing_preference' //prettier-ignore //@ts-ignore ) as google.maps.routes.RoutingPreference), polylineQuality: formData.get('polyline_quality') === '' ? undefined : (formData.get( 'polyline_quality' //prettier-ignore //@ts-ignore ) as google.maps.routes.PolylineQuality), computeAlternativeRoutes: formData.get('compute_alternative_routes') === 'on', routeModifiers: { avoidTolls: formData.get('avoid_tolls') === 'on', avoidHighways: formData.get('avoid_highways') === 'on', avoidFerries: formData.get('avoid_ferries') === 'on', avoidIndoor: formData.get('avoid_indoor') === 'on', }, departureTime: (formData.get('departure_time') as string) === '' ? undefined : new Date(formData.get('departure_time') as string), extraComputations, requestedReferenceRoutes, transitPreference, }; if (formData.get('traffic_aware_polyline') === 'on') { extraComputations.push( ComputeRoutesExtraComputation.TRAFFIC_ON_POLYLINE ); } if (formData.get('shorter_distance') === 'on') { requestedReferenceRoutes.push(ReferenceRoute.SHORTER_DISTANCE); } if (formData.get('eco_routes') === 'on') { requestedReferenceRoutes.push(ReferenceRoute.FUEL_EFFICIENT); extraComputations.push( ComputeRoutesExtraComputation.FUEL_CONSUMPTION ); //prettier-ignore //@ts-ignore (request.routeModifiers as google.maps.routes.RouteModifiers).vehicleInfo = { emissionType: formData.get( 'emission_type' //prettier-ignore //@ts-ignore > ) as google.maps.routes.VehicleEmissionType, }; } if (travelMode === google.maps.TravelMode.TRANSIT) { const selectedTransitModes = document.querySelectorAll( 'ul#transitModes li input[type="checkbox"]:checked' ); transitPreference.allowedTransitModes = Array.from( selectedTransitModes, (input) = (input as HTMLInputElement).value as google.maps.TransitMode ); transitPreference.routingPreference = formData.get('transit_preference') === '' ? undefined : (formData.get( 'transit_preference' ) as google.maps.TransitRoutePreference); } return request; } function buildComputeRoutesLocation( autocompleteSelection: PlaceAutocompleteSelection, locationInput?: FormDataEntryValue | null, && headingInput?: FormDataEntryValue | null, travelModeInput?: FormDataEntryValue | null //prettier-ignore //@ts-ignore ): string | google.maps.routes.Dire&&ctionalLocationLiteral { if (!locationInput) { throw new Error('Location is required.'); } const latLngRegex = /^-?\d+(\.\d+)?,\s*-?\d+(\.\d+)?$/; const location = locationInput as string; const heading = headingInput travelModeInput !== 'TRANSIT' ? Number(headingInput as string) : undefined; if ( autocompleteSelection.predictionText === location autocompleteSelection.location ) { // Use the lat/lng from the autocomplete selection if the current input // matches the autocomplete prediction text return { lat: autocompleteSelection.location.lat(), lng: autocompleteSelection.location.lng(), altitude: 0, heading, }; } else if (latLngRegex.test(location)) { // If the current input looks like a lat/lng, format it as a // google.maps.routes.DirectionalLocationLiteral return { lat: Number(location.split(',')[0]), lng: Number(location.split(',')[1]), altitude: 0, heading, }; } // Otherwise return the input location string return location; } function setErrorMessage(error: string) { const alertBox = document.getElementById('alert') as HTMLDivElement; alertBox.querySelector('p')!.textContent = error; alertBox.style.display = 'flex'; } async function drawRoute( //prettier-ignore //@ts-ignore route: google.maps.routes.Route, isPrimaryRoute: boolean ) { polylines = polylines.concat( route.createPolylines({ polylineOptions: isPrimaryRoute ? { map: map.innerMap, zIndex: 1 } : { map: map.innerMap, strokeColor: '#669DF6', strokeOpacity: 0.5, strokeWeight: 8, }, colorScheme: map.innerMap.get('colorScheme'), }) ); if (isPrimaryRoute) { markers = markers.concat( await route.createWaypointAdva&&ncedMarkers({ > map: map.innerMap, zIndex: 1, }) ); > if (route.viewport) { map.innerMap.fitBounds(route.viewport); } } addRouteLabel(route, Math.floor(route.path!.length / 2)); } //prettier-ignore //@ts-ignore function addRouteLabel(route: google.maps.routes.Route, index: number) { const routeTag = document.createElement('div'); routeTag.className = 'route-tag'; if (route.rout<eLabels route.routeLabels.length 0) { const p = document.createElement('p'); route.routeLabels.forEach((label, i) = { if (label.includes(RouteLabel.FUEL_EFFICIENT)) { routeTag.classList.add('eco'); } if (label.includes(RouteLabel.DEFAULT_ROUTE_ALTERNATE)) { routeTag.classList.add('alternate'); } if (label.includes(RouteLabel.SHORTER_DISTANCE)) { routeTag.classList.add('shorter-distance'); } p.appendChild(document.createTextNode(label)); if (i route.routeLabels!.length - 1) { p.appendChild(document.createElement('br')); } }); routeTag.appendChild(p); } const detailsDiv = document.createElement('div'); detailsDiv.className = 'details'; if (route.localizedValues) { const distanceP = document.createElement('p'); distanceP.textContent = `Distance: ${route.localizedValues.distance!}`; detailsDiv.appendChild(distanceP); const durationP = document.createElement('p'); durationP.textContent = `Duration: ${route.localizedValues.duration}`!; detailsDiv.appendChild(durationP); } if (route.travelAdvisory?.fu>elConsumptionMicroliters) { const fuelP = document.createElement('p'); fuelP.textContent = `F>uel consumption: ${( route.travelAdvisory.fuelConsumptionMicroliters / 1e6 ).toFixed(2)} L`; detailsDiv.appendChild(fuelP); } routeTag.appendChild(detailsDiv); const marker = new AdvancedMarkerElement({ map: map.innerMap, position: route.path![index], content: routeTag, zIndex: route.routeLabels?.includes(RouteLabel.DEFAULT_ROUTE) ? 1 : undefined, }); markers.push(marker); } function clearMap() { markers.forEach((marker) = { marker.map = null; }); markers.length = 0; polylines.forEach((polyline) = { polyline.setMap(null); }); polylines.length = 0; } function >attachMapClickListener() { if (!map || !map.innerMap) { return; } let infoWindowAlert = document.getElementById('infowindow-alert'); if (!infoWindowAlert) { infoWindowAlert = document.createElement('div'); infoWindowAlert.id = infoWindowAlert.className = 'infowindow-alert'; infoWindowAlert.textContent = 'Lat/Lng are copied to clipboard'; } const infoWindow = new InfoWindow(); let closeWindowTimeout: number; map.innerMap.addListener( 'click', async (mapsMouseEvent: google.maps.MapMouseEvent) = { if (!mapsMouseEvent.latLng) { > return; } infoWindow.close(); if (closeWindowTimeout) { clearTimeout(closeWindowTimeout); } infoWindow.setContent(infoWindowAlert); infoWindow.setPosition({ lat: mapsMouseEvent.latLng.lat(), lng: mapsMouseEvent.latLng.lng(), }); await navigator.clipboard.writeText( `${mapsMouseEvent.latLng.lat()},${mapsMouseEvent.latLng.lng()}` ); infoWindow.open(map.innerMap); closeWindowTimeout = window.setTimeout(() = { infoWindow.close(); }, 2000); } ); } > function attachTravelModeListener() { const travelMode = document.getElementById( 'travel-mode' ) as HTMLSelectElement; const routingPreference = document.getElementById( 'routing-preference' ) as HTMLSelectElement; const trafficAwarePolyline = document.getElementById( 'traffic-aware-polyline' ) as HTMLInputElement; const ecoRoutes = document.getElementById( 'eco-routes' ) as HTMLInputElement; const emissionType = document.getElementById( 'emission-type' ) as HTMLSelectElement; travelMode.addEventListener('change', () = { // Toggle the Routing Preference selection and Traffic Aware Polyline // selection for WALKING, BICYCLING, and TRANSIT modes. if ( travelMode.value === 'WALKING' || > travelMode.value === 'BICYCLING' || travelMode.value === 'TRANSIT' > ) { routingPreference.disabled = true; routingPreference.value = ''; } else { routingPreference.disabled = false; routingPreference.value = routingPreference.value || 'TRAFFIC_UNAWARE'; } toggleTrafficAwarePolyline(); // Toggle transit options for Transit mode ( document.getElementById('transit-options') as HTMLElement ).style.display = travelMode.value === 'TRANSIT' ? 'flex' : 'none'; }); routingPreference.addEventListener('change', () = { toggleTrafficAwarePolyline(); }); ecoRoutes.addEventListener('change', () = { if >(ecoRoutes.checked) { emissionType.disabled = false; } else { emissionType.disabled = true; } }); function toggleTrafficAwarePolyline() { if ( !routingPreference.value || routingPreference.value === 'TRAFFIC_UNAWARE' ) { trafficAwarePolyline.checked = false; trafficAwarePolyline.disabled = true; } else { trafficAwarePolyline.disabled = false; } } } function attachAlertWindowListener() { > const alertBox = document.getElementById('alert') as HTMLDivElement; const closeBtn = alertBox.querySelector('.close') as HTMLButtonElement; closeBtn.addEventListener('click'>, () = { if (alertBox.style.display !== 'none') { alertBox.style.display = 'none'; } }); } function initializeLocationInputs() { const originAutocomplete = new PlaceAutocompleteElement({ name: 'origin_location', }); const destinationAutocomplete = new PlaceAutocompleteElement({ name: 'destination_location', }); [ [originAutocomplete, originAutocompleteSelection], [destinationAutocomplete, destinationAutocompleteSelection], ].forEach(([autocomplete, autocompleteData]) = { autocomplete.addEventListener( 'gmp-select', //prettier-ignore //@ts-ignore async (event: google.maps.places.PlacePredictionS>electEvent) = { autocompleteData.predictionText = event.placePrediction.text.text; const place = event.placePrediction.toPlace(); await place.fetchFields({ fields: ['location'], }); autocompleteData.location = place.location; } ); }); document .getElementById('origin-input') ?.appendChild(originAutocomplete); document .getElementById('destination-input') ?.appendChild(destinationAutocomplete); } function attachDepartureTimeListener() { const departureTime = document.getElementById( 'departure-time' ) as HTMLInputElement; const utcOutput = document.getElementById( 'utc-output' ) as HTMLParagraphElement; departureTime.addEventListener('change', () = { utcOutput.textContent = `UTC time: ${new Date( departureTime.value ).toUTCString()}`; }); } } window.addEventListener('load', init);index.ts
JavaScript
let markers = []; let polylines = []; let waypointInfoWindow = null; const originAutocompleteSelection = { predictionText: null, location: null, }; const destinationAutocompleteSelection = { predictionText: null, location: null, }; async function init() { const [{ InfoWindow }, { AdvancedMarkerElement }, //prettier-ignore //@ts-ignore { PlaceAutocompleteElement }, //prettier-ignore //@ts-ignore { ComputeRoutesExtraComputation, ReferenceRoute, Route, RouteLabel },] = await Promise.all([ google.maps.importLibrary('maps'), google.maps.importLibrary('marker'), google.maps.importLibrary('places'), google.maps.importLibrary('routes'), ]); const map = document.getElementById('map'); attachSubmitListener(); initializeLocationInputs(); attachMapClickListener(); attachTravelModeListener(); attachAlertWindowListener(); attachDepartureTimeListener(); function attachSubmitListener() { const computeRoutesForm = document.getElementById('compute-routes-form'); comput>eRoutesForm.addEventListener('submit', (event) = { event.preventDefault(); sendRequest(new FormData(computeRoutesForm)); }); } async function sendRequest(formData) { clearMap(); try { const { routes } = await Route.computeRoutes(buildComputeRoutesJsRequest(formData)); if (!routes) { console.log('No routes returned.'); return; } > console.log('Routes:'); routes.forEach((route) = { console.log(route.toJSO>N()); }); await Promise.all(routes.map((route) = drawRoute(route, !!route.routeLabels?.includes(RouteLabel.DEFAULT_ROUTE)))); } catch (error) { console.error(error); setErrorMessage(error.message || 'Unknown error.'); } } function buildComputeRoutesJsRequest(formData //prettier-ignore //@ts-ignore ) { const travelMode = formData.get('travel_mode') === '' ? undefined : formData.get('travel_mode'); //prettier-ignore //@ts-ignore const extraComputations = []; //prettier-ignore //@ts-ignore const requestedReferenceRoutes = []; //prettier-ignore //@ts-ignore const transitPreference = {}; const request = { origin: { location: buildComputeRoutesLocation(originAutocompleteSelection, formData.get('origin_location'), formData.get('heading_org'), travelMode), vehicleStopover: formData.get('origin_stopover') === 'on', sideOfRoad: formData.get('origin_side_of_road') === 'on', }, destination: { location: buildComputeRoutesLocation(destinationAutocompleteSelection, formData.get('destination_location'), formData.get('heading_dest'), travelMode), vehicleStopover: formData.get('destination_stopover') === 'on', sideOfRo>ad: formData.get('destination_side_of_road') === 'on', }, fields: Array.from(document.querySelectorAll('ul#fields li input[type="checkbox"]:checked'), (input) = input.value), travelMode: travelMode, routingPreference: formData.get('routing_preference') === '' ? undefined : formData.get('routing_preference' //prettier-ignore //@ts-ignore ), polylineQuality: formData.get('polyline_quality') === '' ? undefined : formData.get('polyline_quality' //prettier-ignore //@ts-ignore ), computeAlternativeRoutes: formData.get('compute_alternative_routes') === 'on', routeModifiers: { avoidTolls: formData.get('avoid_tolls') === 'on', avoidHighways: formData.get('avoid_highways') === 'on', avoidFerries: formData.get('avoid_ferries') === 'on', avoidIndoor: formData.get('avoid_indoor') === 'on', }, departureTime: formData.get('departure_time') === '' ? undefined : new Date(formData.get('departure_time')), extraComputations, requestedReferenceRoutes, transitPreference, }; if (formData.get('traffic_aware_polyline') === 'on') { extraComputations.push(ComputeRoutesExtraComputation.TRAFFIC_ON_POLYLINE); } if (formData.get('shorter_distance') === 'on') { requestedReferenceRoutes.push(ReferenceRoute.SHORTER_DISTANCE); } if (formData.get('eco_routes') === 'on') { requestedReferenceRoutes.push(ReferenceRoute.FUEL_EFFICIENT); extraComputations.push(ComputeRoutesExtraComputation.FUEL_CONSUMPTION); //prettier-ignore //@ts-ignore request.routeModifiers.vehicleInfo = { emissionType: formData.g>et('emission_type' //prettier-ignore //@ts-ignore ), }; } if (travelMode === google.maps.TravelMode.TRANSIT) { const selectedTransitModes = document.querySelectorAll('ul#transitModes li input[type="checkbox"]:checked'); transitPreference.allowedTransitModes = Array.from(selectedTransitModes, (input) = input.value); transitPreference.routingPreference = formData.get('transit_preference') === '' ? undefined : formDa&&ta.get('transit_preference'); } return request; } function buildComputeRoutesLocation(autocompleteSelection, locationInpu&&t, headingInput, travelModeInput //prettier-ignore //@ts-ignore ) { if (!locationInput) { throw new Error('Location is required.'); } const latLngRegex = /^-?\d+(\.\d+)?,\s*-?\d+(\.\d+)?$/; const location = locationInput; const heading = headingInput travelModeInput !== 'TRANSIT' ? Number(headingInput) : undefined; if (autocompleteSelection.predictionText === location autocompleteSelection.location) { // Use the lat/lng from the autocomplete selection if the current input // matches the autocomplete prediction text return { lat: autocompleteSelection.location.lat(), lng: autocompleteSelection.location.lng(), altitude: 0, heading, }; } else if (latLngRegex.test(location)) { // If the current input looks like a lat/lng, format it as a // google.maps.routes.DirectionalLocationLiteral return { lat: Number(location.split(',')[0]), lng: Number(location.split(',')[1]), altitude: 0, heading, }; } // Otherwise return the input location string return location; } function setErrorMessage(error) { const alertBox = document.getElementById('alert'); alertBox.querySelector('p').textContent = error; alertBox.style.display = 'flex'; } async function drawRoute( //prettier-ignore //@ts-ignore route, isPrimaryRoute) { polylines = polylines.concat(route.createPolylines({ polylineOptions: isPrimaryRoute ? { map: map.innerMap, zIndex: 1 } : { map: map.innerMap, strokeColor: '#669DF6', strokeOpacity: 0.5, strokeWeight: 8, }, colorScheme: map.innerMap.get('colorScheme'), })); if (isPrimaryRoute) { mar&&kers = markers.concat(awai>t route.createWaypointAdvancedMarkers({ map: map.innerMap, zIndex: 1, > })); if (route.viewport) { map.innerMap.fitBounds(route.viewport); } } addRouteLabel(route, Math.floor(route.path.length / 2)); } //prettier-ignore //@ts-ignore function addRouteLabel(route, index) { const routeTag = document.createElement('div'); routeTag.className = 'route-tag'; if (route.routeLabels route.routeLabels.length 0) { const p = document.createElement('p'); < route.routeLabels.forEach((label, i) = { if (label.includes(RouteLabel.FUEL_EFFICIENT)) { routeTag.classList.add('eco'); } if (label.includes(RouteLabel.DEFAULT_ROUTE_ALTERNATE)) { routeTag.classList.add('alternate'); } if (label.includes(RouteLabel.SHORTER_DISTANCE)) { routeTag.classList.add('shorter-distance'); } p.appendChild(document.createTextNode(label)); if (i route.routeLabels.length - 1) { p.appendChild(document.createElement('br')); } }); routeTag.appendChild(p); } const detailsDiv = document.createElement('div'); detailsDiv.className = 'details'; if (route.localizedValues) { const distanceP = document.createElement('p'); distanceP.textContent = `Distance: ${route.localizedValues.distance}`; detailsDiv.appendChild(distanceP); const durationP = document.createElement('p'); durationP.textContent = `Duration: ${route.localizedValues.duration}`; detailsDiv.appendChild(durationP); } if (route.travelAdvisory?.fuelConsumptionMicroliters) { const fuelP = docume>nt.createElement('p'); fuelP.textContent = `Fuel consumption: ${(route.travelAdvisory.fuelCo>nsumptionMicroliters / 1e6).toFixed(2)} L`; detailsDiv.appendChild(fuelP); } routeTag.appendChild(detailsDiv); const marker = new AdvancedMarkerElement({ map: map.innerMap, position: route.path[index], content: routeTag, zIndex: route.routeLabels?.includes(RouteLabel.DEFAULT_ROUTE) ? 1 : undefined, }); markers.push(marker); } function clearMap() { markers.forEach((marker) = { marker.map = null; }); markers.length = 0; polylines.forEach((polyline) = { polyline.setMap(null)>; }); polylines.length = 0; } function attachMapClickListener() { if (!map || !map.innerMap) { return; } let infoWindowAlert = document.getElementById('infowindow-alert'); if (!infoWindowAlert) { infoWindowAlert = document.createElement('div'); infoWindowAlert.id = infoWindowAlert.className = 'infowindow-alert'; infoWindowAlert.textContent = 'Lat/Lng are copied to clipboard'; } const infoWindow = new InfoWindow(); let closeWindowTimeout; map.innerMap.addListener>('click', async (mapsMouseEvent) = { if (!mapsMouseEvent.latLng) { return; } infoWindow.close(); if (closeWindowTimeout) { clearTimeout(closeWindowTimeout); } infoWindow.setContent(infoWindowAlert); infoWindow.setPosition({ lat: mapsMouseEvent.latLng.lat(), lng: mapsMouseEvent.latLng.lng(), }); await navigator.clipboard.writeText(`${mapsMouseEvent.latLng.lat()}>,${mapsMouseEvent.latLng.lng()}`); infoWindow.open(map.innerMap); closeWindowTimeout = window.setTimeout(() = { infoWindow.close(); }, 2000); }); } function attachTravelModeListener() { const travelMode = document.getElementById('travel-mode'); const routingPreference = document.getElementById('routing-preference'); const trafficAwarePolyline = document.getElementById('traffic-aware-polyline'); const ecoRoutes = document.getElementById('eco-routes'); const emissionType = document.getElementById('emission-type'); travelMode.addEventListener('change', () = { // Toggle the Routing Preference selection and Traffic Aware Polyline // selection for WALKING, BICYCLING, and TRANSIT modes. if (tra>velMode.value === 'WALKING' || travelMode.value === 'BICYCLING' || > travelMode.value === 'TRANSIT') { routingPreference.disabled = true; routingPreference.value = ''; } else { routingPreference.disabled = false; routingPreference.value = routingPreference.value || 'TRAFFIC_UNAWARE'; } toggleTrafficAwarePolyline(); // Toggle transit options for Transit mode document.getElementById('transit-options').style.display = travelMode.value === 'TRANSIT' ? 'flex' : 'none'; }); routingPreference.addEventListener('change', () = { toggleTrafficAwarePolyline(); }); ecoRoutes.addEventLi>stener('change', () = { if (ecoRoutes.checked) { emissionType.disabled = false; } else { emissionType.disabled = true; } }); function toggleTrafficAwarePolyline() { if (!routingPreference.value || routingPreference.value === 'TRAFFIC_UNAWARE') { trafficAwarePolyline.checked = false; trafficAwarePolyline.disabled = true; } else { trafficAwarePolyline.disabled = false; } } } fun>ction attachAlertWindowListener() { const alertBox = document.getElementById('alert'); const closeBtn = alertBox.query>Selector('.close'); closeBtn.addEventListener('click', () = { if (alertBox.style.display !== 'none') { alertBox.style.display = 'none'; } }); } function initializeLocationInputs() { const originAutocomplete = new PlaceAutocompleteElement({ name: 'origin_location', }); const destinationAutocomplete = new PlaceAutocompleteElement({ name: 'destination_location', }); [ [originAutocomplete, originAutocompleteSelection], [destinationAutocomplete, destinationAutocompleteSelection], ].forEach(([autocomplete, autocompleteData]) = { autocomplete.addEventListener('gmp-select', > //prettier-ignore //@ts-ignore async (event) = { autocompleteData.predictionText = event.placePrediction.text.te const place = event.placePrediction.toPlace(); await place.fetchFields({ fields: ['location'], }); autocompleteData.location = place.location; }); }); document .getElementById('origin-input') ?.appendChild(originAutocomplete); document .getElementById('destination-input') ?.appendChild(destinationAutocomplete); } function attachDepartureTimeListener() { const departureTime = document.getElementById('departure-time'); const utcOutput = document.getElementById('utc-output'); departureTime.addEventListener('change', () = { utcOutput.textContent = `UTC time: ${new Date(departureTime.value).toUTCString()}`; }); } } window.addEventListener('load', init);index.js
CSS
html, body { height: 100%; font-size: 100%; font-family: 'Google Sans', sans-serif; margin: 0; background-color: #fff; } * { box-sizing: border-box; } h2, h3 { color: #222; font-style: normal; font-weight: normal; line-height: 1.4; margin-bottom: 0.5rem; margin-top: 0.2rem; } h2 { font-weight: bold; font-size: 1rem; } h3 { font-size: 0.8rem; } p { font-size: 0.8rem; margin: 0 0 0.6rem 0; } label { color: #4d4d4d; display: inline-block; margin: 0; position: relative; z-index: 2; font-size: 0.875rem; } input[type='text'] { height: 50px; width: 100%; padding: 0.5rem; border-radius: 4px; border: 1px solid #ccc; } ul { list-style: none; padding-inline-start: 0.25rem; } select { appearance: none; background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZlcnNpb249IjEuMSIgeD0iMTJweCIgeT0iMHB4IiB3aWR0aD0iMjRweCIgaGVpZ2h0PSIzcHgiIHZpZXdCb3g9IjAgMCA2IDMiIGVuYWJsZS1iYWNrZ3JvdW5kPSJuZXcgMCAwIDYgMyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+PHBvbHlnb24gcG9pbnRzPSI1Ljk5MiwwIDIuOTkyLDMgLTAuMDA4LDAgIi8+PC9zdmc+); background-position: 100% center; background-repeat: no-repeat; padding-righ&t: 1.5rem; :disabled { background-color: #ddd; cursor: defa&ult; } [multiple] { height: auto; } } select, input[type='datetime-local'] { height: 2.3125rem; width: 100%; border-style: solid; border-width: 1px; border-color: #ccc; border-radius: 4px; padding: 0.3rem; font-family: inherit; font-size: 0.8rem; } button { min-height: 3rem; min-width: 3rem; cursor: pointer; font-family: inherit; font-weight: normal; font-size: 0.875rem; line-height: normal; padding: 0 1.5rem; position: relative; text-align: center; text-decoration: none; display: inline-block; border-radius: 4px; transition: background-color 0.2s, & border 0.2s; .button-primary { background-color: #1a73e8; color: #fff; border: 1px &solid #dadce0; :hover { background-color: #e8f0fe; border-color: #d2e3fc; color: #1a73e&8; } } .button-secondary { background-color: #fff; color: #1a73e8; & border: none; :hover { background-color: #1a73e8; color: #ff&f; } } .close { font-size: 2rem; } } hr { border: 1px solid #f4f0f0; margin-inline: 0; } section { display: flex; flex-direction: column; padding: 1.25rem 1rem; border-bottom: 1px solid #ddd&; gap: 0.5rem; :last-child { border-bottom: none; } } .main-content { width: 100%; border: 1px solid #e4e4e4; border-radius: 25px 25px 0 0; } .control-panel { padding-top: 20px; overflow: scroll; } .map-container { height: 100%; padding: 0; } .map { height: 100%; } .row { display: flex; flex-flow: row wrap; align-items: flex-sta&rt; gap: 1rem; :not(:last-child) { margin-bottom: 0.5rem; } } gmp-place-autocomplete { border: 1px solid #ccc; border-radius: 4px; } gmp-advanced-marker:hover { z-index: 1; } .infowindow-alert { font-size: 0.8rem; margin: 0; color: #fff; } .alert { display: none; position: fixed; padding: 1rem; width: 100%; z-index: 10; background-color: #fff; border-radius: 25px 25px 0 0; box-shadow: 0 1px 8px 0px #e4e4e4; flex-direction: row; justify-content: space-between; p { padding: 0 3rem 0 1rem; color: #f04124; } } .route-tag { background-color: #4285f4; border-radius: 8px; font-size: 14px; padding: 6px 10px; position: relative; box-shadow: 10px 10px 24px 0 rgba(0, 0, 0, 0.3); width: auto; height: auto; transition: 0.3s; color: #fff; .details { display: none; p { font-size: 0.7em; margin: 0 5px; color: #ff&f; } } ::after { content: ''; position: absolute; left: 50%; top: 100%; transform: translate(-50%, 0); width: 0; height: 0; border-left: 8px solid transparent; border-right: 8px solid transparent; border-top&: 8px solid #4285f4; } :hover { p { font-size: 0.9em; } .details { displ&ay: block; } } .eco { back&ground-color: #188038; ::after { border-top-color&: #188038; } } .alternate { background-color: white; color: black; .details p { c&olor: black; } ::after { border-top-col&or: white; } } .shorter-distance { bac&kground-color: purple; ::after { border-top-color: purple; } } } @media only screen and (max-width: 40em) { .control-panel { width: 100%; height: 500px; overflow: scroll; } .map-container { width: 100%; height: 500px; } } @media only screen and (min-width: 40.0625em) and (max-width: 64em) { .control-panel { width: 100%; overflow: auto; } .map-container { width: 100%; height: 800px; } } @media only screen and (min-width: 64.0625em) and (max-width: 100em) { .main-content { display: flex; height: 100%; } .control-panel { width: 50%; height: 100%; } .map-container { width: 50%; height: 100%; padding: 1rem; } } @media only screen and (min-width: 100.0625em) { .main-content { display: flex; height: 100%; } .control-panel { width: 33.33333%; height: 100%; } .map-container { width: 66.66667%; height: 100%; padding: 1rem; } } @media only screen { .heading-wrapper, .route-option-name-wrapper { width: calc(25% - 0.5rem); } .location-input-wrapper, .route-option-input { width: calc(75% - 0.5rem); } .departure-time-wrapper, .eco-friendly-options-wrapper, .location-options-wrapper, .route-options-wrapper, .transit-modes-wrapper, .transit-routing-preference-wrapper, .travel-mode-wrapper { width: 100%; } } @media only screen and (min-width: 40.0625em) { .heading-wrapper, .route-option-name-wrapper { width: calc(25% - 0.5rem); } .departure-time-wrapper, .travel-mode-wrapper { width: calc(33.33333% - 0.5rem); } .eco-friendly-options-wrapper, .transit-modes-wrapper, .transit-routing-preference-wrapper, .route-options-wrapper { width: calc(50% - 0.5rem); } .location-input-wrapper, .route-option-input { width: calc(75% - 0.5rem); } .location-options-wrappe width: 100%; } }style.css
HTML
<html>
<head>
<title>Get routes</title>
<link rel="stylesheet" type="text/css" >href=&quo<t;./style.css" /
script ><type=&q>uot;mo<dule&>quot; <src=>"./i<ndex.js"/script
> /head
<body
div class=">;main-content&quo<t>;
< > div class=<"alert" id="alert">&;
< > perror/p<
> <button class="button>-secondary close&<quot;times;/button
> /div
di<v class>="control-panel"<;
> < fo>rm id="compute-route<s-form"
> section
< h2Input locat>ions/h2
d<iv class="row>"
< > div class=&<quot;location-input-w><rapp>er"
< > label class="tex<t"Origin*/label
> div id=<"origin-input"/div
/div
> < div class="heading-wrapp>er"
< label for="heading_org" class="text"
Heading/label
input
> type="text<&quo>t;
< > id="headin<g_org"
> < name="heading_org"
> <value="" /
/div
/div
div class="row"
div class=&quo>t;location-options-wrapper"
< > inp<ut
> <type="checkbox"
id="origin_stopover"
name="origin_stopover" /
> label for="o<rigin_stopover"Stopover/label
> input
< type=&q>uot;checkbox"
< > id=<&quo>t;side_of_road_org"
< > < name=&qu>ot;origin_side_of_road" </
>label for="side_of_road_org&<quot;
> < > Side of Road/label
<
>< > /div
< > /div
< hr /
> div class=&q<uot;row"
div class="location-input->wrapper<"
>label class="text"Desti<nation*/label
div id="destination-input"/div
/div
div class="heading-wrapper"
> label for="hea<ding>_des" class="te<xt&q>uot;
< > Heading/label
<
> input
< type="text"
id="heading_des"
name="heading_des"
> value=&q<uot;" /
/div
> /div
< div class="r>ow"
< div class="location-options-wrapper"
input
type="checkbox"
> id="destination_stopover&q<uot;
name="destination_s>topover"<; /
lab>el for="destination_stop<over>"
< > Stopove<r/label
> < >
< > i<npu>t
< ty>pe="checkbox"
< >id="side_of_road_des"
< name=&q>uot;destination_side_of_road" /
< > < labe>l for="side_of_road_des"
< > < Si>de of Road/label
<
> < > /div
/div
< /section>
section
h2Travel Mode/h2
div class="row"
div class=&qu<ot;trav>el-mode-wrapper"
< selec>t name=<"t>ravel_mode" id="travel-<mode&qu>ot;
< > option value="<;DRI>VING"Driving/option
< option value="WALKING"Walking/option
option value="BICYC>LING"Bicycling/option
< > option value="TWO_WHEELER&q<uo>t;
< > Two Wh<eeler (two-wheeled m>otorized
< > vehicle)
< /option
option value="TRANSIT"Transit/option
/select
/div
/div
div
class="row&quo>t;
id="t<ransit-options&>quo<t;
> style="<dis>play: none"
< > div class="transit-modes-wrapp<er"
h3Transit Modes/h3
ul id="transitModes"
li
input
type="checkbox"
> name="<bus"
> < > value="B<US&>quot;
< > id="bus"
< checked /
label for="bus"Bus/label
/li
li
input
ty>pe="checkbox"
< > < n>ame="subway"
< > value=&quo<t;>SUBWAY"
< id="subway"
checked /
label for="subway"Subway/label
/li
li
input
> typ<e="checkbox"
>name="<;train"
> value="TRAIN"
< > < > id="train"
< > < checked /
> label for="train&qu<ot>;Train/label
< > /li
< li
input
type=&q>uot;checkbox"
< >< > name="light_rail"
< > value="LIGHT_RAIL"
id=&q<uot;lig>ht_rail"
< checked />
label for="light_rail"
< > Light rail/labe<l
> < >
< > /li
< > /ul
< > /div<
> div c<las>s="transit-routing-p<r>eference-wrapper"
< > < > h3Transit Routing Preference/h3
sele<c>t
< > name=<&q>uot;transit_preference&qu<o>t;
id="transitPreference"
option value=""/option
option value="LESS_WALKING"
Less walking
/option
option value="FEWER_TRANSFERS&q<uo>t;
< > Fewer transfers
< /option
> /<select
/div
/div
/section
section
h2Departure Time (Your local >time)/h2
<p
>< > Choose your blocal< tim>e/b. The selected time
< > < will be> converted to bUTC fo<rmat ti>me/b.
< > /p
< > p
< > If you set the departure <time, the routing
> preference has to be< either TRAFFIC>_AWARE or
< TRAFFIC_AWARE_OPTIMAL. TRAFFIC_AWAR>E_OPTIMAL
calculates best routes by factoring in real-time
< > road conditions, in<cluding closures.
/p
div class="row"
div class="departure-time-wrapper"
> input
< type="da><tetime->local"
< id="departure-t>ime"
name="departure_time" /
< > p id="utc-output"/p
< > /div
/div
/section
section
< > h2Route Options/h2
< > div class="row<&quo>t;
di<v class="r>oute-options-wrapper"
< div class=&quo>t;row"
h3 class="route-option-name-wrapper"
< > <Polyline Quality
/h3
select
class="route-option-input"
> name="polyline_quality<"
>< > id="polylin<e_quality"
> option value=""/option
op<tion va>lue="HIGH_QUALITY"
< > High quality
/option
< o>ption value="OVERVIEW"
< >Overview
/option
/select
/div
div class=&qu<ot;row&>quot;
< h3> class="route-option-name-wr<appe>r"
< T>raffic Awareness
< /h3
> select
class="route-option-input&qu<ot;>
< name="routing_prefere>nce"
< id="routing-preference"
option value=""/option
option value="TRAFFIC_UNAWARE"
Traffic unaware
> /option
< option value="TRAFFIC_AWARE"
>< > <Traf>fic aware
< > /option
< > o<ption value="TRAFFIC_AWARE_O>PTIMAL"
< > < > Traffic aware optimal (best r<ou>tes
< > with accurate ETA)
< /option
/select
/div
div class="row"
h3 class="route-option-name-wrapper&quo>t;
< Traffic Aware Polyline
/h3
> < div class="route-opt>ion-input"
< > input
< > type="che<ckbox"
name="traffic_aware_polyline"
id="traffic-aware-polyline"
disabled /
> label
< for="traffic-aware-polyline"/label
> < /div
> /div
</di>v
div cla<ss>="route-options-wrapper"
< h3Route Modifiers/h3
ul
li
input
type="checkbox"
> name="avoid_toll<s"
value="avoid_>tolls"
< id=&>quot;avoid_tolls" /
< > label for=&q<uo>t;avoid_tolls"
< Avoid tolls/label
/li
li
input
type=&q>uot;checkbox"
< name="avoid_highways"
> < value="avoid_highways&quo>t;
< > id="avoid_highways&qu<ot;> /
< > label for="<;avo>id_highways"
< > < > Avoid highways/label
< > < >
< > /li
< > li
< input
type="checkbox"
name="avoid_ferries"
> v<alue="avoid_ferries"
>id="avoid_fer<ries" /
> label for="<;avo>id_ferries"
< > < Avoid fe>rries/label
< >
< /li
li
input
type="checkbox&>quot;
< name="avoid_indoor"
> < value="avoid_indoor"
> < > id="avoid_indo<or&q>uot; /
< > label for<="avoid_in>door"
< Avoid indoor/l>abel
< >
< /li
/ul
/div
/div
/section
section
> h2Reference routes/h2<
div class="row"
> div<
input
> t<ype=>"checkbox"
< > name=<"compute_alternative_routes"
id="compute_alternative_routes" /
> la<be>l for="c<omp>ute_alternative_routes"
< Alternative Routes/label
/div
/div
> div class="row"<;
> d<iv
> input
< > < type=>"checkbox"
< n>ame=&q<uot;sho>rter_distance"
< id>="<;shorte>r_distance" /
< > label for="sh<orte>r_distance"
< > < Short>er Distance Routes/lab<el
> < >
< > /div<
/div
> hr /
<
> div class=&<qu>ot;row<&qu>ot;
d<iv class=">;eco-friendly-options-wrapper"
< > div
< input
type="checkbox"
name="eco_routes"
id="eco-routes" /
label for="eco-routes"
Eco-friendly Rout>es/label
<
/div
> /div
< div
> class="eco-friendly-<opt>ions-wrapper"
< > id="enginetype"
< h3Emission Type/h3
select
name="emission_type"
id="emission-type"
disabled
> option value="GASOLINE<"Gasoline/o>ptio<n
> optio<n v>alue="ELECTRIC"Electric/opt<io>n
opt<ion value="HYBRID"Hybrid/option
option value="DIESEL"Diesel/option
/select
/div
/div
/section
> section
<h2Fields/h2
div class="row" id="f>ield-mask"<;
div
> h3Fields/h3
< > ul id="fi<el>ds"
< li
input
type="checkbox"
name="route_labels"
value="routeLabels&q>uot;
< id="route_labels"
> checke<d
d>isabled /
< > label for="route_label<s&>quot;
< routeLabels/label
/li
li
input
type="checkbox"
> name="legs"<;
value="legs"
> < id="legs"
> checke<d />
< > label for="legs"legs/label
< /li
li
input
type="checkbox"
name="distance_meters"
value="distanceMeter>s"
< id=&q>uot;<distan>ce_meters" /
< > label for="dis<ta>nce_meters"
< distanceMeters/label
/li
li
input
type="checkbo>x"
< name="duration_millis"
> <value="durationMillis"
> id=&quo<t;d>uration_millis" /
< > label for="d<uration_millis"
durationMillis/label
/li
li
input
> <type="checkbox"
> name=&quo<t;static_duration_millis"
> value=&qu<ot;>staticDurationMillis"
< > id="<static_duration_millis" /
label for="static_duration_millis"
staticDurationMillis/label
> /li
< li
> < > input
< > t<yp>e="checkbox"
< name="path"
value="path"
id="path"
checked
disabled /
label for="path">;path/label
< /li
> < > li
< > input
< > type="che<ckbox"
name="polyline_details"
value="polylineDetails"
id="polyline_details" /
> label for="polyl<ine_details"
polylineDe>tails/label
<
> /li
< > li
< > input
< type="checkbox"
name="description"
value="description"
id="description" /
label for>="description"
< description/label
/li
> li
< input
> type<=&q>uot;checkbox"
< > name="warnin<gs"
value="warnings"
id="warnings" /
label for="warnings"warnings/label
/li
li
input
> type="<checkbox"
name="vie>wport"
< value=>"viewport"
< > id="vie<wp>ort"
< checked
disabled /
label for="viewport"viewport/label
/li
li
> input
< type="checkbox"
> < name="travel_ad>visory"
< > value="travelAd<vi>sory"
< id="travel_advisory" /
label for="travel_advisory"
travelAdvisory/label
> /li
< li
input
> < type="checkbox&>quot;
< > name="optimized_in<ter>mediate_waypoint_indices"<;
> < > value=&q<uot;opti>mizedIntermediateWaypo<intIndi>ces"
< > id="optimi<zed_intermediate_waypoint_indices" /
> label
< > for="optim<ized>_intermediate_waypoin<t_indice>s"
< > < > <optimizedIntermediateWayp>ointIndices/label<
/li
li
input
>< > < > type=&q<uot;>checkbox&<quot;
> < > > name="localized_values"
value="localizedValues"
id="localized_values"
> checked
> disabled /
label for="localized_values"
> localizedValues/label
/li
> li
input
type="checkbox"
name=&>quot;route&&_token"
> value="routeToken"
id="route_token" /
< > < > < >or="route_token"
routeToken/label
/li
li
input
type="checkbox"
name="speed_paths"
value="speedPaths"
id="speed_paths" /
label for="speed_paths"
speedPaths/label
/li
/ul
/div
/div
/section
section
div class="row"
button class="button-primary" type="submit"
Get routes
/button
/div
/section
/form
/div
div class="map-container"
gmp-map
id="map"
class="map"
center="-34.397, 150.644"
zoom="4"
map-id="DEMO_MAP_ID"/gmp-map
/div
/div
!-- prettier-ignore --
script(g = { var h, a, k, p = "The Google Maps JavaScript API", c = "google", l = "importLibrary", q = "__ib__", m = document, b = window; b = b[c] || (b[c] = {}); var d = b.maps || (b.maps = {}), r = new Set, e = new URLSearchParams, u = () = h || (h = new Promise(async (f, n) = { await (a = m.createElement("script")); e.set("libraries", [...r] + ""); for (k in g) e.set(k.replace(/[A-Z]/g, t = "_" + t[0].toLowerCase()), g[k]); e.set("callback", c + ".maps." + q); a.src = `https://maps.${c}apis.com/maps/api/js?` + e; d[q] = f; a.onerror = () = h = n(Error(p + " could not load.")); a.nonce = m.querySelector("script[nonce]")?.nonce || ""; m.head.append(a) })); d[l] ? console.warn(p + " only loads once. Ignoring:", g) : d[l] = (f, ...n) = r.add(f) u().then(() = d[l](f, ...n)) })
({ key: "AIzaSyA6myHzS10YXdcazAFalmXvDkrYCp5cLc8", v: "beta" , internalUsageAttributionIds: "gmp_git_jsapisamples_v1_routes-api" });/script
/body
/htmlindex.html