A demonstração de rota permite especificar uma origem e um destino como um par de coordenadas de latitude/longitude ou como um ID de lugar. Para copiar as coordenadas de latitude/longitude, encontre e clique em um local no mapa e cole no formulário.
Depois de selecionar Receber trajeto, a demonstração vai mostrar a resposta do método computeRoutes como um trajeto no mapa.
Confira o código-fonte de exemplo completo
A demonstração a seguir permite testar a criação de vários tipos de rotas. Clique no mapa para copiar as coordenadas de latitude/longitude de um local. Cole as coordenadas no formulário para receber rotas.
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"
< > < > < >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
/htmlindex.html