Route demo
Stay organized with collections
Save and categorize content based on your preferences.
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
letmarkers:google.maps.marker.AdvancedMarkerElement[]=[]; letpolylines:google.maps.Polyline[]=[]; letwaypointInfoWindow:google.maps.InfoWindow|null=null; interfacePlaceAutocompleteSelection{ predictionText:string|null; location:google.maps.LatLng|null; } constoriginAutocompleteSelection:PlaceAutocompleteSelection={ predictionText:null, location:null, }; constdestinationAutocompleteSelection:PlaceAutocompleteSelection={ predictionText:null, location:null, }; asyncfunctioninit(){ const[ {InfoWindow}, {AdvancedMarkerElement}, //prettier-ignore //@ts-ignore {PlaceAutocompleteElement}, //prettier-ignore //@ts-ignore {ComputeRoutesExtraComputation,ReferenceRoute,Route,RouteLabel}, ]=awaitPromise.all([ google.maps.importLibrary('maps')asPromise<google.maps.MapsLibrary>, google.maps.importLibrary( 'marker' )asPromise<google.maps.MarkerLibrary>, google.maps.importLibrary( 'places' )asPromise<google.maps.PlacesLibrary>, google.maps.importLibrary( 'routes' )asPromise<google.maps.RoutesLibrary>, ]); constmap=document.getElementById('map')asgoogle.maps.MapElement; attachSubmitListener(); initializeLocationInputs(); attachMapClickListener(); attachTravelModeListener(); attachAlertWindowListener(); attachDepartureTimeListener(); functionattachSubmitListener(){ constcomputeRoutesForm=document.getElementById( 'compute-routes-form' )asHTMLFormElement; computeRoutesForm.addEventListener('submit',(event)=>{ event.preventDefault(); sendRequest(newFormData(computeRoutesForm)); }); } asyncfunctionsendRequest(formData:FormData){ clearMap(); try{ const{routes}=awaitRoute.computeRoutes( buildComputeRoutesJsRequest(formData) ); if(!routes){ console.log('No routes returned.'); return; } console.log('Routes:'); routes.forEach((route)=>{ console.log(route.toJSON()); }); awaitPromise.all( routes.map((route)=> drawRoute( route, !!route.routeLabels?.includes(RouteLabel.DEFAULT_ROUTE) ) ) ); }catch(error:unknown){ console.error(error); setErrorMessage((errorasError).message||'Unknown error.'); } } functionbuildComputeRoutesJsRequest( formData:FormData //prettier-ignore //@ts-ignore ):google.maps.routes.ComputeRoutesRequest{ consttravelMode= (formData.get('travel_mode')asstring)==='' ?undefined :(formData.get('travel_mode')asgoogle.maps.TravelMode); //prettier-ignore //@ts-ignore constextraComputations:google.maps.routes.ComputeRoutesExtraComputation[]= []; //prettier-ignore //@ts-ignore constrequestedReferenceRoutes:google.maps.routes.ReferenceRoute[]=[]; //prettier-ignore //@ts-ignore consttransitPreference:google.maps.routes.TransitPreference={}; constrequest={ 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)=>(inputasHTMLInputElement).value ), travelMode:travelModeasgoogle.maps.TravelMode, routingPreference: formData.get('routing_preference')==='' ?undefined :(formData.get( 'routing_preference' //prettier-ignore //@ts-ignore )asgoogle.maps.routes.RoutingPreference), polylineQuality: formData.get('polyline_quality')==='' ?undefined :(formData.get( 'polyline_quality' //prettier-ignore //@ts-ignore )asgoogle.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')asstring)==='' ?undefined :newDate(formData.get('departure_time')asstring), 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.routeModifiersasgoogle.maps.routes.RouteModifiers).vehicleInfo= { emissionType:formData.get( 'emission_type' //prettier-ignore //@ts-ignore )asgoogle.maps.routes.VehicleEmissionType, }; } if(travelMode===google.maps.TravelMode.TRANSIT){ constselectedTransitModes=document.querySelectorAll( 'ul#transitModes li input[type="checkbox"]:checked' ); transitPreference.allowedTransitModes=Array.from( selectedTransitModes, (input)=> (inputasHTMLInputElement).valueasgoogle.maps.TransitMode ); transitPreference.routingPreference= formData.get('transit_preference')==='' ?undefined :(formData.get( 'transit_preference' )asgoogle.maps.TransitRoutePreference); } returnrequest; } functionbuildComputeRoutesLocation( autocompleteSelection:PlaceAutocompleteSelection, locationInput?:FormDataEntryValue|null, headingInput?:FormDataEntryValue|null, travelModeInput?:FormDataEntryValue|null //prettier-ignore //@ts-ignore ):string|google.maps.routes.DirectionalLocationLiteral{ if(!locationInput){ thrownewError('Location is required.'); } constlatLngRegex=/^-?\d+(\.\d+)?,\s*-?\d+(\.\d+)?$/; constlocation=locationInputasstring; constheading= headingInput && travelModeInput!=='TRANSIT' ?Number(headingInputasstring) :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, }; }elseif(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 returnlocation; } functionsetErrorMessage(error:string){ constalertBox=document.getElementById('alert')asHTMLDivElement; alertBox.querySelector('p')!.textContent=error; alertBox.style.display='flex'; } asyncfunctiondrawRoute( //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( awaitroute.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 functionaddRouteLabel(route:google.maps.routes.Route,index:number){ constrouteTag=document.createElement('div'); routeTag.className='route-tag'; if(route.routeLabels && route.routeLabels.length > 0){ constp=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); } constdetailsDiv=document.createElement('div'); detailsDiv.className='details'; if(route.localizedValues){ constdistanceP=document.createElement('p'); distanceP.textContent=`Distance: ${route.localizedValues.distance!}`; detailsDiv.appendChild(distanceP); constdurationP=document.createElement('p'); durationP.textContent=`Duration: ${route.localizedValues.duration}`!; detailsDiv.appendChild(durationP); } if(route.travelAdvisory?.fuelConsumptionMicroliters){ constfuelP=document.createElement('p'); fuelP.textContent=`Fuel consumption: ${( route.travelAdvisory.fuelConsumptionMicroliters/1e6 ).toFixed(2)} L`; detailsDiv.appendChild(fuelP); } routeTag.appendChild(detailsDiv); constmarker=newAdvancedMarkerElement({ map:map.innerMap, position:route.path![index], content:routeTag, zIndex:route.routeLabels?.includes(RouteLabel.DEFAULT_ROUTE) ?1 :undefined, }); markers.push(marker); } functionclearMap(){ markers.forEach((marker)=>{ marker.map=null; }); markers.length=0; polylines.forEach((polyline)=>{ polyline.setMap(null); }); polylines.length=0; } functionattachMapClickListener(){ if(!map||!map.innerMap){ return; } letinfoWindowAlert=document.getElementById('infowindow-alert'); if(!infoWindowAlert){ infoWindowAlert=document.createElement('div'); infoWindowAlert.id=infoWindowAlert.className='infowindow-alert'; infoWindowAlert.textContent='Lat/Lng are copied to clipboard'; } constinfoWindow=newInfoWindow(); letcloseWindowTimeout: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(), }); awaitnavigator.clipboard.writeText( `${mapsMouseEvent.latLng.lat()},${mapsMouseEvent.latLng.lng()}` ); infoWindow.open(map.innerMap); closeWindowTimeout=window.setTimeout(()=>{ infoWindow.close(); },2000); } ); } functionattachTravelModeListener(){ consttravelMode=document.getElementById( 'travel-mode' )asHTMLSelectElement; constroutingPreference=document.getElementById( 'routing-preference' )asHTMLSelectElement; consttrafficAwarePolyline=document.getElementById( 'traffic-aware-polyline' )asHTMLInputElement; constecoRoutes=document.getElementById( 'eco-routes' )asHTMLInputElement; constemissionType=document.getElementById( 'emission-type' )asHTMLSelectElement; 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')asHTMLElement ).style.display=travelMode.value==='TRANSIT'?'flex':'none'; }); routingPreference.addEventListener('change',()=>{ toggleTrafficAwarePolyline(); }); ecoRoutes.addEventListener('change',()=>{ if(ecoRoutes.checked){ emissionType.disabled=false; }else{ emissionType.disabled=true; } }); functiontoggleTrafficAwarePolyline(){ if( !routingPreference.value|| routingPreference.value==='TRAFFIC_UNAWARE' ){ trafficAwarePolyline.checked=false; trafficAwarePolyline.disabled=true; }else{ trafficAwarePolyline.disabled=false; } } } functionattachAlertWindowListener(){ constalertBox=document.getElementById('alert')asHTMLDivElement; constcloseBtn=alertBox.querySelector('.close')asHTMLButtonElement; closeBtn.addEventListener('click',()=>{ if(alertBox.style.display!=='none'){ alertBox.style.display='none'; } }); } functioninitializeLocationInputs(){ constoriginAutocomplete=newPlaceAutocompleteElement({ name:'origin_location', }); constdestinationAutocomplete=newPlaceAutocompleteElement({ name:'destination_location', }); [ [originAutocomplete,originAutocompleteSelection], [destinationAutocomplete,destinationAutocompleteSelection], ].forEach(([autocomplete,autocompleteData])=>{ autocomplete.addEventListener( 'gmp-select', //prettier-ignore //@ts-ignore async(event:google.maps.places.PlacePredictionSelectEvent)=>{ autocompleteData.predictionText=event.placePrediction.text.text; constplace=event.placePrediction.toPlace(); awaitplace.fetchFields({ fields:['location'], }); autocompleteData.location=place.location; } ); }); document .getElementById('origin-input') ?.appendChild(originAutocomplete); document .getElementById('destination-input') ?.appendChild(destinationAutocomplete); } functionattachDepartureTimeListener(){ constdepartureTime=document.getElementById( 'departure-time' )asHTMLInputElement; constutcOutput=document.getElementById( 'utc-output' )asHTMLParagraphElement; departureTime.addEventListener('change',()=>{ utcOutput.textContent=`UTC time: ${newDate( departureTime.value ).toUTCString()}`; }); } } window.addEventListener('load',init);
JavaScript
letmarkers=[]; letpolylines=[]; letwaypointInfoWindow=null; constoriginAutocompleteSelection={ predictionText:null, location:null, }; constdestinationAutocompleteSelection={ predictionText:null, location:null, }; asyncfunctioninit(){ const[{InfoWindow},{AdvancedMarkerElement}, //prettier-ignore //@ts-ignore {PlaceAutocompleteElement}, //prettier-ignore //@ts-ignore {ComputeRoutesExtraComputation,ReferenceRoute,Route,RouteLabel},]=awaitPromise.all([ google.maps.importLibrary('maps'), google.maps.importLibrary('marker'), google.maps.importLibrary('places'), google.maps.importLibrary('routes'), ]); constmap=document.getElementById('map'); attachSubmitListener(); initializeLocationInputs(); attachMapClickListener(); attachTravelModeListener(); attachAlertWindowListener(); attachDepartureTimeListener(); functionattachSubmitListener(){ constcomputeRoutesForm=document.getElementById('compute-routes-form'); computeRoutesForm.addEventListener('submit',(event)=>{ event.preventDefault(); sendRequest(newFormData(computeRoutesForm)); }); } asyncfunctionsendRequest(formData){ clearMap(); try{ const{routes}=awaitRoute.computeRoutes(buildComputeRoutesJsRequest(formData)); if(!routes){ console.log('No routes returned.'); return; } console.log('Routes:'); routes.forEach((route)=>{ console.log(route.toJSON()); }); awaitPromise.all(routes.map((route)=>drawRoute(route,!!route.routeLabels?.includes(RouteLabel.DEFAULT_ROUTE)))); } catch(error){ console.error(error); setErrorMessage(error.message||'Unknown error.'); } } functionbuildComputeRoutesJsRequest(formData //prettier-ignore //@ts-ignore ){ consttravelMode=formData.get('travel_mode')==='' ?undefined :formData.get('travel_mode'); //prettier-ignore //@ts-ignore constextraComputations=[]; //prettier-ignore //@ts-ignore constrequestedReferenceRoutes=[]; //prettier-ignore //@ts-ignore consttransitPreference={}; constrequest={ 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.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 :newDate(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.get('emission_type' //prettier-ignore //@ts-ignore ), }; } if(travelMode===google.maps.TravelMode.TRANSIT){ constselectedTransitModes=document.querySelectorAll('ul#transitModes li input[type="checkbox"]:checked'); transitPreference.allowedTransitModes=Array.from(selectedTransitModes,(input)=>input.value); transitPreference.routingPreference= formData.get('transit_preference')==='' ?undefined :formData.get('transit_preference'); } returnrequest; } functionbuildComputeRoutesLocation(autocompleteSelection,locationInput,headingInput,travelModeInput //prettier-ignore //@ts-ignore ){ if(!locationInput){ thrownewError('Location is required.'); } constlatLngRegex=/^-?\d+(\.\d+)?,\s*-?\d+(\.\d+)?$/; constlocation=locationInput; constheading=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, }; } elseif(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 returnlocation; } functionsetErrorMessage(error){ constalertBox=document.getElementById('alert'); alertBox.querySelector('p').textContent=error; alertBox.style.display='flex'; } asyncfunctiondrawRoute( //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){ markers=markers.concat(awaitroute.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 functionaddRouteLabel(route,index){ constrouteTag=document.createElement('div'); routeTag.className='route-tag'; if(route.routeLabels && route.routeLabels.length > 0){ constp=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); } constdetailsDiv=document.createElement('div'); detailsDiv.className='details'; if(route.localizedValues){ constdistanceP=document.createElement('p'); distanceP.textContent=`Distance: ${route.localizedValues.distance}`; detailsDiv.appendChild(distanceP); constdurationP=document.createElement('p'); durationP.textContent=`Duration: ${route.localizedValues.duration}`; detailsDiv.appendChild(durationP); } if(route.travelAdvisory?.fuelConsumptionMicroliters){ constfuelP=document.createElement('p'); fuelP.textContent=`Fuel consumption: ${(route.travelAdvisory.fuelConsumptionMicroliters/1e6).toFixed(2)} L`; detailsDiv.appendChild(fuelP); } routeTag.appendChild(detailsDiv); constmarker=newAdvancedMarkerElement({ map:map.innerMap, position:route.path[index], content:routeTag, zIndex:route.routeLabels?.includes(RouteLabel.DEFAULT_ROUTE) ?1 :undefined, }); markers.push(marker); } functionclearMap(){ markers.forEach((marker)=>{ marker.map=null; }); markers.length=0; polylines.forEach((polyline)=>{ polyline.setMap(null); }); polylines.length=0; } functionattachMapClickListener(){ if(!map||!map.innerMap){ return; } letinfoWindowAlert=document.getElementById('infowindow-alert'); if(!infoWindowAlert){ infoWindowAlert=document.createElement('div'); infoWindowAlert.id=infoWindowAlert.className='infowindow-alert'; infoWindowAlert.textContent='Lat/Lng are copied to clipboard'; } constinfoWindow=newInfoWindow(); letcloseWindowTimeout; 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(), }); awaitnavigator.clipboard.writeText(`${mapsMouseEvent.latLng.lat()},${mapsMouseEvent.latLng.lng()}`); infoWindow.open(map.innerMap); closeWindowTimeout=window.setTimeout(()=>{ infoWindow.close(); },2000); }); } functionattachTravelModeListener(){ consttravelMode=document.getElementById('travel-mode'); constroutingPreference=document.getElementById('routing-preference'); consttrafficAwarePolyline=document.getElementById('traffic-aware-polyline'); constecoRoutes=document.getElementById('eco-routes'); constemissionType=document.getElementById('emission-type'); 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').style.display=travelMode.value==='TRANSIT'?'flex':'none'; }); routingPreference.addEventListener('change',()=>{ toggleTrafficAwarePolyline(); }); ecoRoutes.addEventListener('change',()=>{ if(ecoRoutes.checked){ emissionType.disabled=false; } else{ emissionType.disabled=true; } }); functiontoggleTrafficAwarePolyline(){ if(!routingPreference.value|| routingPreference.value==='TRAFFIC_UNAWARE'){ trafficAwarePolyline.checked=false; trafficAwarePolyline.disabled=true; } else{ trafficAwarePolyline.disabled=false; } } } functionattachAlertWindowListener(){ constalertBox=document.getElementById('alert'); constcloseBtn=alertBox.querySelector('.close'); closeBtn.addEventListener('click',()=>{ if(alertBox.style.display!=='none'){ alertBox.style.display='none'; } }); } functioninitializeLocationInputs(){ constoriginAutocomplete=newPlaceAutocompleteElement({ name:'origin_location', }); constdestinationAutocomplete=newPlaceAutocompleteElement({ 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.text; constplace=event.placePrediction.toPlace(); awaitplace.fetchFields({ fields:['location'], }); autocompleteData.location=place.location; }); }); document .getElementById('origin-input') ?.appendChild(originAutocomplete); document .getElementById('destination-input') ?.appendChild(destinationAutocomplete); } functionattachDepartureTimeListener(){ constdepartureTime=document.getElementById('departure-time'); constutcOutput=document.getElementById('utc-output'); departureTime.addEventListener('change',()=>{ utcOutput.textContent=`UTC time: ${newDate(departureTime.value).toUTCString()}`; }); } } window.addEventListener('load',init);
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:000.6rem0; } 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:1pxsolid#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-right:1.5rem; &:disabled{ background-color:#ddd; cursor:default; } &[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:01.5rem; position:relative; text-align:center; text-decoration:none; display:inline-block; border-radius:4px; transition: background-color0.2s, border0.2s; &.button-primary{ background-color:#1a73e8; color:#fff; border:1pxsolid#dadce0; &:hover{ background-color:#e8f0fe; border-color:#d2e3fc; color:#1a73e8; } } &.button-secondary{ background-color:#fff; color:#1a73e8; border:none; &:hover{ background-color:#1a73e8; color:#fff; } } &.close{ font-size:2rem; } } hr{ border:1pxsolid#f4f0f0; margin-inline:0; } section{ display:flex; flex-direction:column; padding:1.25rem1rem; border-bottom:1pxsolid#ddd; gap:0.5rem; &:last-child{ border-bottom:none; } } .main-content{ width:100%; border:1pxsolid#e4e4e4; border-radius:25px25px00; } .control-panel{ padding-top:20px; overflow:scroll; } .map-container{ height:100%; padding:0; } .map{ height:100%; } .row{ display:flex; flex-flow:rowwrap; align-items:flex-start; gap:1rem; &:not(:last-child){ margin-bottom:0.5rem; } } gmp-place-autocomplete{ border:1pxsolid#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:25px25px00; box-shadow:01px8px0px#e4e4e4; flex-direction:row; justify-content:space-between; p{ padding:03rem01rem; color:#f04124; } } .route-tag{ background-color:#4285f4; border-radius:8px; font-size:14px; padding:6px10px; position:relative; box-shadow:10px10px24px0rgba(0,0,0,0.3); width:auto; height:auto; transition:0.3s; color:#fff; .details{ display:none; p{ font-size:0.7em; margin:05px; color:#fff; } } &::after{ content:''; position:absolute; left:50%; top:100%; transform:translate(-50%,0); width:0; height:0; border-left:8pxsolidtransparent; border-right:8pxsolidtransparent; border-top:8pxsolid#4285f4; } &:hover{ p{ font-size:0.9em; } .details{ display:block; } } &.eco{ background-color:#188038; &::after{ border-top-color:#188038; } } &.alternate{ background-color:white; color:black; .detailsp{ color:black; } &::after{ border-top-color:white; } } &.shorter-distance{ background-color:purple; &::after{ border-top-color:purple; } } } @mediaonlyscreenand(max-width:40em){ .control-panel{ width:100%; height:500px; overflow:scroll; } .map-container{ width:100%; height:500px; } } @mediaonlyscreenand(min-width:40.0625em)and(max-width:64em){ .control-panel{ width:100%; overflow:auto; } .map-container{ width:100%; height:800px; } } @mediaonlyscreenand(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; } } @mediaonlyscreenand(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; } } @mediaonlyscreen{ .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%; } } @mediaonlyscreenand(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-wrapper{ width:100%; } }
HTML
<html>
<head>
<title>Get routes</title>
<link rel="stylesheet" type="text/css" href="./style.css" />
<script type="module" src="./index.js"></script>
</head>
<body>
<div class="main-content">
<div class="alert" id="alert">
<p>error</p>
<button class="button-secondary close">×</button>
</div>
<div class="control-panel">
<form id="compute-routes-form">
<section>
<h2>Input locations</h2>
<div class="row">
<div class="location-input-wrapper">
<label class="text">Origin*</label>
<div id="origin-input"></div>
</div>
<div class="heading-wrapper">
<label for="heading_org" class="text"
>Heading</label
>
<input
type="text"
id="heading_org"
name="heading_org"
value="" />
</div>
</div>
<div class="row">
<div class="location-options-wrapper">
<input
type="checkbox"
id="origin_stopover"
name="origin_stopover" />
<label for="origin_stopover">Stopover</label>
<input
type="checkbox"
id="side_of_road_org"
name="origin_side_of_road" />
<label for="side_of_road_org"
>Side of Road</label
>
</div>
</div>
<hr />
<div class="row">
<div class="location-input-wrapper">
<label class="text">Destination*</label>
<div id="destination-input"></div>
</div>
<div class="heading-wrapper">
<label for="heading_des" class="text"
>Heading</label
>
<input
type="text"
id="heading_des"
name="heading_des"
value="" />
</div>
</div>
<div class="row">
<div class="location-options-wrapper">
<input
type="checkbox"
id="destination_stopover"
name="destination_stopover" />
<label for="destination_stopover"
>Stopover</label
>
<input
type="checkbox"
id="side_of_road_des"
name="destination_side_of_road" />
<label for="side_of_road_des"
>Side of Road</label
>
</div>
</div>
</section>
<section>
<h2>Travel Mode</h2>
<div class="row">
<div class="travel-mode-wrapper">
<select name="travel_mode" id="travel-mode">
<option value="DRIVING">Driving</option>
<option value="WALKING">Walking</option>
<option value="BICYCLING">Bicycling</option>
<option value="TWO_WHEELER">
Two Wheeler (two-wheeled motorized
vehicle)
</option>
<option value="TRANSIT">Transit</option>
</select>
</div>
</div>
<div
class="row"
id="transit-options"
style="display: none">
<div class="transit-modes-wrapper">
<h3>Transit Modes</h3>
<ul id="transitModes">
<li>
<input
type="checkbox"
name="bus"
value="BUS"
id="bus"
checked />
<label for="bus">Bus</label>
</li>
<li>
<input
type="checkbox"
name="subway"
value="SUBWAY"
id="subway"
checked />
<label for="subway">Subway</label>
</li>
<li>
<input
type="checkbox"
name="train"
value="TRAIN"
id="train"
checked />
<label for="train">Train</label>
</li>
<li>
<input
type="checkbox"
name="light_rail"
value="LIGHT_RAIL"
id="light_rail"
checked />
<label for="light_rail"
>Light rail</label
>
</li>
</ul>
</div>
<div class="transit-routing-preference-wrapper">
<h3>Transit Routing Preference</h3>
<select
name="transit_preference"
id="transitPreference">
<option value=""></option>
<option value="LESS_WALKING">
Less walking
</option>
<option value="FEWER_TRANSFERS">
Fewer transfers
</option>
</select>
</div>
</div>
</section>
<section>
<h2>Departure Time (Your local time)</h2>
<p>
Choose your <b>local time</b>. The selected time
will be converted to <b>UTC format time</b>.
</p>
<p>
If you set the departure time, the routing
preference has to be either TRAFFIC_AWARE or
TRAFFIC_AWARE_OPTIMAL. TRAFFIC_AWARE_OPTIMAL
calculates best routes by factoring in real-time
road conditions, including closures.
</p>
<div class="row">
<div class="departure-time-wrapper">
<input
type="datetime-local"
id="departure-time"
name="departure_time" />
<p id="utc-output"></p>
</div>
</div>
</section>
<section>
<h2>Route Options</h2>
<div class="row">
<div class="route-options-wrapper">
<div class="row">
<h3 class="route-option-name-wrapper">
Polyline Quality
</h3>
<select
class="route-option-input"
name="polyline_quality"
id="polyline_quality">
<option value=""></option>
<option value="HIGH_QUALITY">
High quality
</option>
<option value="OVERVIEW">
Overview
</option>
</select>
</div>
<div class="row">
<h3 class="route-option-name-wrapper">
Traffic Awareness
</h3>
<select
class="route-option-input"
name="routing_preference"
id="routing-preference">
<option value=""></option>
<option value="TRAFFIC_UNAWARE">
Traffic unaware
</option>
<option value="TRAFFIC_AWARE">
Traffic aware
</option>
<option value="TRAFFIC_AWARE_OPTIMAL">
Traffic aware optimal (best routes
with accurate ETA)
</option>
</select>
</div>
<div class="row">
<h3 class="route-option-name-wrapper">
Traffic Aware Polyline
</h3>
<div class="route-option-input">
<input
type="checkbox"
name="traffic_aware_polyline"
id="traffic-aware-polyline"
disabled />
<label
for="traffic-aware-polyline"></label>
</div>
</div>
</div>
<div class="route-options-wrapper">
<h3>Route Modifiers</h3>
<ul>
<li>
<input
type="checkbox"
name="avoid_tolls"
value="avoid_tolls"
id="avoid_tolls" />
<label for="avoid_tolls"
>Avoid tolls</label
>
</li>
<li>
<input
type="checkbox"
name="avoid_highways"
value="avoid_highways"
id="avoid_highways" />
<label for="avoid_highways"
>Avoid highways</label
>
</li>
<li>
<input
type="checkbox"
name="avoid_ferries"
value="avoid_ferries"
id="avoid_ferries" />
<label for="avoid_ferries"
>Avoid ferries</label
>
</li>
<li>
<input
type="checkbox"
name="avoid_indoor"
value="avoid_indoor"
id="avoid_indoor" />
<label for="avoid_indoor"
>Avoid indoor</label
>
</li>
</ul>
</div>
</div>
</section>
<section>
<h2>Reference routes</h2>
<div class="row">
<div>
<input
type="checkbox"
name="compute_alternative_routes"
id="compute_alternative_routes" />
<label for="compute_alternative_routes"
>Alternative Routes</label
>
</div>
</div>
<div class="row">
<div>
<input
type="checkbox"
name="shorter_distance"
id="shorter_distance" />
<label for="shorter_distance"
>Shorter Distance Routes</label
>
</div>
</div>
<hr />
<div class="row">
<div class="eco-friendly-options-wrapper">
<div>
<input
type="checkbox"
name="eco_routes"
id="eco-routes" />
<label for="eco-routes"
>Eco-friendly Routes</label
>
</div>
</div>
<div
class="eco-friendly-options-wrapper"
id="enginetype">
<h3>Emission Type</h3>
<select
name="emission_type"
id="emission-type"
disabled>
<option value="GASOLINE">Gasoline</option>
<option value="ELECTRIC">Electric</option>
<option value="HYBRID">Hybrid</option>
<option value="DIESEL">Diesel</option>
</select>
</div>
</div>
</section>
<section>
<h2>Fields</h2>
<div class="row" id="field-mask">
<div>
<h3>Fields</h3>
<ul id="fields">
<li>
<input
type="checkbox"
name="route_labels"
value="routeLabels"
id="route_labels"
checked
disabled />
<label for="route_labels"
>routeLabels</label
>
</li>
<li>
<input
type="checkbox"
name="legs"
value="legs"
id="legs"
checked />
<label for="legs">legs</label>
</li>
<li>
<input
type="checkbox"
name="distance_meters"
value="distanceMeters"
id="distance_meters" />
<label for="distance_meters"
>distanceMeters</label
>
</li>
<li>
<input
type="checkbox"
name="duration_millis"
value="durationMillis"
id="duration_millis" />
<label for="duration_millis"
>durationMillis</label
>
</li>
<li>
<input
type="checkbox"
name="static_duration_millis"
value="staticDurationMillis"
id="static_duration_millis" />
<label for="static_duration_millis"
>staticDurationMillis</label
>
</li>
<li>
<input
type="checkbox"
name="path"
value="path"
id="path"
checked
disabled />
<label for="path">path</label>
</li>
<li>
<input
type="checkbox"
name="polyline_details"
value="polylineDetails"
id="polyline_details" />
<label for="polyline_details"
>polylineDetails</label
>
</li>
<li>
<input
type="checkbox"
name="description"
value="description"
id="description" />
<label for="description"
>description</label
>
</li>
<li>
<input
type="checkbox"
name="warnings"
value="warnings"
id="warnings" />
<label for="warnings">warnings</label>
</li>
<li>
<input
type="checkbox"
name="viewport"
value="viewport"
id="viewport"
checked
disabled />
<label for="viewport">viewport</label>
</li>
<li>
<input
type="checkbox"
name="travel_advisory"
value="travelAdvisory"
id="travel_advisory" />
<label for="travel_advisory"
>travelAdvisory</label
>
</li>
<li>
<input
type="checkbox"
name="optimized_intermediate_waypoint_indices"
value="optimizedIntermediateWaypointIndices"
id="optimized_intermediate_waypoint_indices" />
<label
for="optimized_intermediate_waypoint_indices"
>optimizedIntermediateWaypointIndices</label
>
</li>
<li>
<input
type="checkbox"
name="localized_values"
value="localizedValues"
id="localized_values"
checked
disabled />
<label for="localized_values"
>localizedValues</label
>
</li>
<li>
<input
type="checkbox"
name="route_token"
value="routeToken"
id="route_token" />
<label for="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" });</script>
</body>
</html>