UNPKG

react-native-maps-directions-routes-api

Version:
799 lines (741 loc) 26.2 kB
import React, { useState, useEffect, useRef } from 'react'; import PropTypes from 'prop-types'; import MapView, { Polyline, Marker } from "react-native-maps"; import isEqual from 'lodash.isequal'; import polyline from "polyline"; import { View, Text, Image, StyleSheet } from 'react-native'; // Constants const MapViewDirectionsRoutesAPI = ({ origin: initialOrigin, destination: initialDestination, waypoints: initialWaypoints = [], apikey, onStart, onReady, onError, onSelectRoute, mode = 'DRIVE', languageCode = 'en-US', resetOnChange = true, optimizeWaypoints = false, splitWaypoints = false, computeAlternativeRoutes = false, directionsServiceBaseUrl = 'https://routes.googleapis.com/directions/v2:computeRoutes', units = "IMPERIAL", region = '', precision = 'low', timePrecision = 'none', channel, fieldMask = 'routes.duration,routes.distanceMeters,routes.polyline.encodedPolyline', routingPreference = "TRAFFIC_AWARE_OPTIMAL", intermediates = null, polylineQuality = "OVERVIEW", polylineEncoding = "ENCODED_POLYLINE", departureTime = null, arrivalTime = null, routeModifiers = {}, regionCode = null, //optimizeWaypointOrder = true, requestedReferenceRoutes = null, extraComputations = ["FUEL_CONSUMPTION", "TOLLS"], // trafficModel = BEST_GUESS, transitPreferences = {}, fitToCoordinates = { edgePadding: { top: 90, right: 50, bottom: 100, left: 50 }, animated: true, }, extraMarkers = null, selectedRouteColor = "blue", notselectedRouteColor = "gray", ...props }) => { const [coordinates, setCoordinates] = useState(null); const [distance, setDistance] = useState(null); const [duration, setDuration] = useState(null); const [routes, setroutes] = useState(null) const [selectedRouteIndex, setSelectedRouteIndex] = useState(0); const [extraMarkers_, setextraMarkers_] = useState(extraMarkers) const prevPropsRef = useRef(); const mapRef = useRef(null); const extractLatLng = (marker) => { if (!marker) return null; if ('latitude' in marker && 'longitude' in marker) { return { latitude: marker.latitude, longitude: marker.longitude }; } if (marker?.location?.latLng) { return { latitude: marker.location.latLng.latitude, longitude: marker.location.latLng.longitude }; } return null; }; const allMarkers = [ extractLatLng(initialOrigin), ...(Array.isArray(intermediates) ? intermediates.map(extractLatLng) : []), extractLatLng(initialDestination), ...(Array.isArray(extraMarkers) ? extraMarkers.map(extractLatLng) : []), ].filter(Boolean); // Removes null values useEffect(() => { onSelectRoute && onSelectRoute(selectedRouteIndex) }, [selectedRouteIndex]) useEffect(() => { setextraMarkers_(extraMarkers) }, [extraMarkers]) // Automatically fit the map to show all markers useEffect(() => { if (mapRef.current && allMarkers.length > 1) { setTimeout(async () => { try { const allMarkersFrames = await mapRef.current.getMarkersFrames(); console.log('All markers frames:', allMarkersFrames); } catch (error) { //console.log('Error getting marker frames:', error); } mapRef.current.fitToCoordinates(allMarkers, fitToCoordinates); }, 2000); // 2s delay } }, [allMarkers]); // Reset state function const resetState = (cb = null) => { setCoordinates(null); setDistance(null); setDuration(null); setroutes(null) if (cb) cb(); }; // Fetch route from Google Maps API const fetchRoute = async (directionsServiceBaseUrl, origin, waypoints, destination, apikey, mode, languageCode, region, precision, timePrecision, channel, computeAlternativeRoutes, units, fieldMask, routingPreference, intermediates, polylineQuality, polylineEncoding, departureTime, arrivalTime, routeModifiers, regionCode, optimizeWaypointOrder, requestedReferenceRoutes, extraComputations, transitPreferences,) => { // Define the URL to call. Only add default parameters to the URL if it's a string. let url = directionsServiceBaseUrl; if (typeof (directionsServiceBaseUrl) === 'string') { url += `?key=${apikey}`; } const body = { origin: { location: { latLng: { latitude: origin.latitude, longitude: origin.longitude, }, }, }, destination: { location: { latLng: { latitude: destination.latitude, longitude: destination.longitude, }, }, }, travelMode: mode, routingPreference: routingPreference, computeAlternativeRoutes: computeAlternativeRoutes, languageCode: languageCode, units: units, }; if (routingPreference) body.routingPreference = routingPreference; if (intermediates && intermediates.length > 0) { body.intermediates = intermediates.map(intermediate => ({ location: { latLng: { latitude: intermediate.location.latLng.latitude, longitude: intermediate.location.latLng.longitude } } })); } if (polylineQuality) body.polylineQuality = polylineQuality; if (polylineEncoding) body.polylineEncoding = polylineEncoding; if (departureTime) body.departureTime = departureTime; if (arrivalTime) body.arrivalTime = arrivalTime; if (routeModifiers && Object.keys(routeModifiers).length > 0) body.routeModifiers = routeModifiers; if (regionCode) body.regionCode = regionCode; if (optimizeWaypointOrder !== undefined) body.optimizeWaypointOrder = optimizeWaypoints; if (requestedReferenceRoutes) body.requestedReferenceRoutes = requestedReferenceRoutes; if (extraComputations && extraComputations.length > 0) body.extraComputations = extraComputations; if (transitPreferences && Object.keys(transitPreferences).length > 0) body.transitPreferences = transitPreferences; if (optimizeWaypoints) { fieldMask += ",routes.optimized_intermediate_waypoint_index" } return fetch(url, { method: "POST", headers: { "Content-Type": "application/json", "x-goog-FieldMask": fieldMask, }, body: JSON.stringify(body), }) .then(response => response.json()) .then(json => { if (json?.routes?.length) { return json } else { return Promise.reject('No routes found!'); } }) .catch(err => { return Promise.reject(`Error on GMAPS route request : ${err}`); }); }; // Main function to fetch and render route const fetchAndRenderRoute = async () => { if (!apikey) { console.warn(`MapViewDirectionsRoutesAPI Error: Missing API Key`); // eslint-disable-line no-console return; } if (!initialOrigin || !initialDestination) { return; } try { let origin = initialOrigin let destination = initialDestination return await fetchRoute( directionsServiceBaseUrl, origin, null, destination, apikey, mode, languageCode, region, precision, null, channel, computeAlternativeRoutes, units, fieldMask, routingPreference, intermediates, polylineQuality, polylineEncoding, departureTime, arrivalTime, routeModifiers, regionCode, optimizeWaypoints, requestedReferenceRoutes, extraComputations, transitPreferences, ) .then(result => { if (result?.routes) { const modifiedRoutes = result.routes.map((route, index) => { const decodedCoordinates = polyline.decode(route.polyline.encodedPolyline).map(([latitude, longitude]) => ({ latitude, longitude, })); return { ...route, key: `route-${index}`, coordinates: decodedCoordinates, }; }); setroutes(modifiedRoutes); // Update state onReady && onReady(modifiedRoutes); } return }) .catch(errorMessage => { resetState(); console.warn(`MapViewDirectionsRoutesAPI Error: ${errorMessage}`); // eslint-disable-line no-console onError && onError(errorMessage); }); } catch (errorMessage) { resetState(); console.warn(`MapViewDirectionsRoutesAPI Catch Error: ${errorMessage}`); // eslint-disable-line no-console onError && onError(errorMessage); }; }; // ComponentDidMount equivalent useEffect(() => { fetchAndRenderRoute(); // eslint-disable-next-line react-hooks/exhaustive-deps }, []); // ComponentDidUpdate equivalent useEffect(() => { const prevProps = prevPropsRef.current; if (prevProps && ( !isEqual(prevProps.initialOrigin, initialOrigin) || !isEqual(prevProps.initialDestination, initialDestination) || !isEqual(prevProps.initialWaypoints, initialWaypoints) || !isEqual(prevProps.mode, mode) || !isEqual(prevProps.precision, precision) || !isEqual(prevProps.splitWaypoints, splitWaypoints) )) { if (resetOnChange === false) { fetchAndRenderRoute(); } else { resetState(() => { fetchAndRenderRoute(); }); } } prevPropsRef.current = { initialOrigin, initialDestination, initialWaypoints, mode, precision, splitWaypoints }; // eslint-disable-next-line react-hooks/exhaustive-deps }, [initialOrigin, initialDestination, initialWaypoints, mode, precision, splitWaypoints]); if (!routes || !routes[0]?.coordinates) { return null; } const AnimatedTextMarker = ({ text, style = {} }) => { return ( <View style={[styles.container, style.container]}> <View style={[styles.bubble, style.bubble]}> <Text style={[styles.text, style.text]}>{text}</Text> </View> <View style={[styles.arrowBorder, style.arrowBorder]} /> <View style={[styles.arrow, style.arrow]} /> </View> ); }; const styles = StyleSheet.create({ container: { flexDirection: 'column', alignSelf: 'flex-start', }, bubble: { flexDirection: 'row', alignSelf: 'flex-start', backgroundColor: '#38902f', // Static Red Color padding: 4, borderRadius: 60, borderWidth: 0, }, text: { color: '#fff', fontSize: 12, }, arrow: { width: 0, height: 0, borderLeftWidth: 10, borderRightWidth: 10, borderTopWidth: 10, borderBottomWidth: 15, borderStyle: 'solid', borderLeftColor: 'transparent', borderRightColor: 'transparent', borderTopColor: '#38902f', borderBottomColor: 'transparent', alignSelf: 'center', marginTop: -1, }, }); return ( <View style={{ flex: 1 }}> <MapView ref={mapRef} style={{ flex: 1 }} initialRegion={{ latitude: initialOrigin.latitude, longitude: initialOrigin.longitude, latitudeDelta: 0.5, longitudeDelta: 0.5, }} > {/* Origin Marker */} <Marker coordinate={initialOrigin} pinColor={initialOrigin?.customMarker?.pinColor ?? 'red'} anchor={initialOrigin?.customMarker?.image ? { x: initialOrigin?.customMarker?.anchorX ?? 0.5, y: initialOrigin?.customMarker?.anchorY ?? 0.25 } : undefined} centerOffset={initialOrigin?.customMarker?.image ? { x: initialOrigin?.customMarker?.centerOffsetX ?? 0, y: initialOrigin?.customMarker?.centerOffsetY ?? 0 } : undefined} title={initialOrigin?.customMarker?.title ?? 'origin'} rotation={initialOrigin?.heading ?? 0}> {initialOrigin?.customMarker?.image ? ( <Image source={initialOrigin.customMarker.image} style={{ width: initialOrigin?.customMarker?.width || 30, height: initialOrigin?.customMarker?.height || 30, }} resizeMode="contain" /> ) : initialOrigin?.customMarker?.customText ? ( <AnimatedTextMarker text={initialOrigin.customMarker.customText} style={initialOrigin?.customMarker?.style} /> ) : null} </Marker> {/* Destination Marker */} <Marker coordinate={initialDestination} pinColor={initialDestination?.customMarker?.pinColor ?? 'red'} anchor={initialDestination?.customMarker?.image ? { x: initialDestination?.customMarker?.anchorX ?? 0.5, y: initialDestination?.customMarker?.anchorY ?? 0.25 } : undefined} centerOffset={initialDestination?.customMarker?.image ? { x: initialDestination?.customMarker?.centerOffsetX ?? 0, y: initialDestination?.customMarker?.centerOffsetY ?? 0 } : undefined} title={initialDestination?.customMarker?.title ?? 'origin'} rotation={initialDestination?.heading ?? 0}> {initialDestination?.customMarker?.image ? ( <Image source={initialDestination.customMarker.image} style={{ width: initialDestination?.customMarker?.width || 30, height: initialDestination?.customMarker?.height || 30, }} resizeMode="contain" /> ) : initialDestination?.customMarker?.customText ? ( <AnimatedTextMarker text={initialDestination.customMarker.customText} style={initialDestination?.customMarker?.style} /> ) : null} </Marker> {/* Intermediate Markers */} {intermediates && intermediates.map((intermediate, index) => ( <Marker key={`intermediate-${index}`} coordinate={intermediate?.location?.latLng} pinColor={intermediate?.location?.latLng?.customMarker?.pinColor ?? 'red'} anchor={intermediate?.location?.latLng?.customMarker?.image ? { x: intermediate?.location?.latLng?.customMarker?.anchorX ?? 0.5, y: intermediate?.location?.latLng?.customMarker?.anchorY ?? 0.25 } : undefined} centerOffset={intermediate?.location?.latLng?.customMarker?.image ? { x: intermediate?.location?.latLng?.customMarker?.centerOffsetX ?? 0, y: intermediate?.location?.latLng?.customMarker?.centerOffsetY ?? 0 } : undefined} title={intermediate?.location?.latLng?.customMarker?.title ?? 'origin'} rotation={intermediate?.location?.latLng?.heading ?? 0}> {intermediate?.location?.latLng?.customMarker?.image ? ( <Image source={intermediate.location?.latLng?.customMarker.image} style={{ width: intermediate?.location?.latLng?.customMarker?.width || 30, height: intermediate?.location?.latLng?.customMarker?.height || 30, }} resizeMode="contain" /> ) : intermediate?.location?.latLng?.customMarker?.customText ? ( <AnimatedTextMarker text={intermediate.location?.latLng?.customMarker.customText} style={intermediate?.location?.latLng?.customMarker?.style} /> ) : null} </Marker> ))} {/* EXTRA Markers */} {extraMarkers_ && extraMarkers_.map((extraMarker, index) => { return ( <Marker coordinate={extraMarker} key={`extraMarker-${index}`} pinColor={extraMarker?.customMarker?.pinColor ?? 'red'} anchor={extraMarker?.customMarker?.image ? { x: extraMarker?.customMarker?.anchorX ?? 0.5, y: extraMarker?.customMarker?.anchorY ?? 0.25 } : undefined} centerOffset={extraMarker?.customMarker?.image ? { x: extraMarker?.customMarker?.centerOffsetX ?? 0, y: extraMarker?.customMarker?.centerOffsetY ?? 0 } : undefined} title={extraMarker?.customMarker?.title ?? 'origin'} rotation={extraMarker?.heading ?? 0}> {extraMarker?.customMarker?.image ? ( <Image source={extraMarker.customMarker.image} style={{ width: extraMarker?.customMarker?.width || 30, height: extraMarker?.customMarker?.height || 30, }} resizeMode="contain" /> ) : extraMarker?.customMarker?.customText ? ( <AnimatedTextMarker text={extraMarker.customMarker.customText} style={extraMarker?.customMarker?.style} /> ) : null} </Marker> ) })} {routes.filter((route, index) => index !== selectedRouteIndex).map((route, index) => ( <Polyline key={routes.indexOf(route)} coordinates={route.coordinates} strokeWidth={4} strokeColor={notselectedRouteColor} tappable onPress={() => { setSelectedRouteIndex(routes.indexOf(route)); }} /> ))} <Polyline key={selectedRouteIndex} coordinates={routes[selectedRouteIndex].coordinates} strokeWidth={4} strokeColor={selectedRouteColor} /> </MapView> </View> ); }; MapViewDirectionsRoutesAPI.propTypes = { origin: PropTypes.shape({ latitude: PropTypes.number.isRequired, longitude: PropTypes.number.isRequired, }), destination: PropTypes.shape({ latitude: PropTypes.number.isRequired, longitude: PropTypes.number.isRequired, }), intermediates: PropTypes.arrayOf( PropTypes.shape({ latitude: PropTypes.number.isRequired, longitude: PropTypes.number.isRequired, }), ).isRequired, intermediates: (props, propName, componentName) => { if (props[propName] && props[propName].length > 25) { return new Error(`Invalid prop '${propName}' supplied to '${componentName}'. Maximum 25 elements allowed.`); } }, extraMarkers: PropTypes.arrayOf( PropTypes.shape({ latitude: PropTypes.number.isRequired, longitude: PropTypes.number.isRequired, }), ), fitToCoordinates: PropTypes.shape({ edgePadding: PropTypes.shape({ top: PropTypes.number.isRequired, right: PropTypes.number.isRequired, bottom: PropTypes.number.isRequired, left: PropTypes.number.isRequired, }).isRequired, animated: PropTypes.bool.isRequired, }), apikey: PropTypes.string.isRequired, onStart: PropTypes.func, onReady: PropTypes.func, onError: PropTypes.func, onSelectRoute: PropTypes.func, mode: PropTypes.oneOf(['DRIVE', 'WALK', 'TWO_WHEELER', 'BICYCLE', 'TRANSIT']), languageCode: PropTypes.string, resetOnChange: PropTypes.bool, optimizeWaypoints: PropTypes.bool, // splitWaypoints: PropTypes.bool, directionsServiceBaseUrl: PropTypes.string, region: PropTypes.string, selectedRouteColor: PropTypes.string, notselectedRouteColor: PropTypes.string, precision: PropTypes.oneOf(['high', 'low']), timePrecision: PropTypes.string, channel: PropTypes.string, fieldMask: PropTypes.string, computeAlternativeRoutes: PropTypes.bool, routingPreference: PropTypes.oneOf(['TRAFFIC_AWARE', 'TRAFFIC_UNAWARE', 'TRAFFIC_AWARE_OPTIMAL']), units: PropTypes.oneOf(['METRIC', 'IMPERIAL']), // optimizeWaypointOrder: PropTypes.bool, polylineQuality: PropTypes.oneOf(['OVERVIEW', 'HIGH_QUALITY']), polylineEncoding: PropTypes.oneOf(['ENCODED_POLYLINE', 'GEO_JSON_LINESTRING']), requestedReferenceRoutes: PropTypes.oneOf(['FUEL_EFFICIENT', 'SHORTER_DISTANCE']), extraComputations: PropTypes.arrayOf(PropTypes.oneOf([ 'TOLLS', 'FUEL_CONSUMPTION', 'TRAFFIC_ON_POLYLINE', 'HTML_FORMATTED_NAVIGATION_INSTRUCTIONS', 'FLYOVER_INFO_ON_POLYLINE', 'NARROW_ROAD_INFO_ON_POLYLINE', ])), // trafficModel: PropTypes.oneOf(['BEST_GUESS', 'PESSIMISTIC', 'OPTIMISTIC']), transitPreferences: PropTypes.shape({ allowedTravelModes: PropTypes.arrayOf(PropTypes.oneOf([ 'BUS', 'SUBWAY', 'TRAIN', 'LIGHT_RAIL', 'RAIL', ])), routingPreference: PropTypes.oneOf([ 'TRANSIT_ROUTING_PREFERENCE_UNSPECIFIED', 'LESS_WALKING', 'FEWER_TRANSFERS', ]), }), routeModifiers: PropTypes.shape({ avoidTolls: PropTypes.bool, avoidHighways: PropTypes.bool, avoidFerries: PropTypes.bool, avoidIndoor: PropTypes.bool, vehicleInfo: PropTypes.shape({ emissionType: PropTypes.oneOf([ 'GASOLINE', 'ELECTRIC', 'HYBRID', 'DIESEL', ]), }), tollPasses: PropTypes.arrayOf(PropTypes.oneOf([ 'AU_ETOLL_TAG', 'AU_EWAY_TAG', 'AU_LINKT', 'AR_TELEPASE', 'BR_AUTO_EXPRESO', 'BR_CONECTCAR', 'BR_MOVE_MAIS', 'BR_PASSA_RAPIDO', 'BR_SEM_PARAR', 'BR_TAGGY', 'BR_VELOE', 'CA_US_AKWASASNE_SEAWAY_CORPORATE_CARD', 'CA_US_AKWASASNE_SEAWAY_TRANSIT_CARD', 'CA_US_BLUE_WATER_EDGE_PASS', 'CA_US_CONNEXION', 'CA_US_NEXUS_CARD', 'ID_E_TOLL', 'IN_FASTAG', 'IN_LOCAL_HP_PLATE_EXEMPT', 'JP_ETC', 'JP_ETC2', 'MX_IAVE', 'MX_PASE', 'MX_QUICKPASS', 'MX_SISTEMA_TELEPEAJE_CHIHUAHUA', 'MX_TAG_IAVE', 'MX_TAG_TELEVIA', 'MX_TELEVIA', 'MX_VIAPASS', 'US_AL_FREEDOM_PASS', 'US_AK_ANTON_ANDERSON_TUNNEL_BOOK_OF_10_TICKETS', 'US_CA_FASTRAK', 'US_CA_FASTRAK_CAV_STICKER', 'US_CO_EXPRESSTOLL', 'US_CO_GO_PASS', 'US_DE_EZPASSDE', 'US_FL_BOB_SIKES_TOLL_BRIDGE_PASS', 'US_FL_DUNES_COMMUNITY_DEVELOPMENT_DISTRICT_EXPRESSCARD', 'US_FL_EPASS', 'US_FL_GIBA_TOLL_PASS', 'US_FL_LEEWAY', 'US_FL_SUNPASS', 'US_FL_SUNPASS_PRO', 'US_IL_EZPASSIL', 'US_IL_IPASS', 'US_IN_EZPASSIN', 'US_KS_BESTPASS_HORIZON', 'US_KS_KTAG', 'US_KS_NATIONALPASS', 'US_KS_PREPASS_ELITEPASS', 'US_KY_RIVERLINK', 'US_LA_GEAUXPASS', 'US_LA_TOLL_TAG', 'US_MA_EZPASSMA', 'US_MD_EZPASSMD', 'US_ME_EZPASSME', 'US_MI_AMBASSADOR_BRIDGE_PREMIER_COMMUTER_CARD', 'US_MI_BCPASS', 'US_MI_GROSSE_ILE_TOLL_BRIDGE_PASS_TAG', 'US_MI_IQ_TAG', 'US_MI_MACKINAC_BRIDGE_MAC_PASS', 'US_MI_NEXPRESS_TOLL', 'US_MN_EZPASSMN', 'US_NC_EZPASSNC', 'US_NC_PEACH_PASS', 'US_NC_QUICK_PASS', 'US_NH_EZPASSNH', 'US_NJ_DOWNBEACH_EXPRESS_PASS', 'US_NJ_EZPASSNJ', 'US_NY_EXPRESSPASS', 'US_NY_EZPASSNY', 'US_OH_EZPASSOH', 'US_PA_EZPASSPA', 'US_RI_EZPASSRI', 'US_SC_PALPASS', 'US_TX_AVI_TAG', 'US_TX_BANCPASS', 'US_TX_DEL_RIO_PASS', 'US_TX_EFAST_PASS', 'US_TX_EAGLE_PASS_EXPRESS_CARD', 'US_TX_EPTOLL', 'US_TX_EZ_CROSS', 'US_TX_EZTAG', 'US_TX_FUEGO_TAG', 'US_TX_LAREDO_TRADE_TAG', 'US_TX_PLUSPASS', 'US_TX_TOLLTAG', 'US_TX_TXTAG', 'US_TX_XPRESS_CARD', 'US_UT_ADAMS_AVE_PARKWAY_EXPRESSCARD', 'US_VA_EZPASSVA', 'US_WA_BREEZEBY', 'US_WA_GOOD_TO_GO', 'US_WV_EZPASSWV', 'US_WV_MEMORIAL_BRIDGE_TICKETS', 'US_WV_MOV_PASS', 'US_WV_NEWELL_TOLL_BRIDGE_TICKET', ])), }) }; //TOLL PASSES EXTENDED INFO /** * * AU_ETOLL_TAG Sydney toll pass. See additional details at https://www.myetoll.com.au. AU_EWAY_TAG Sydney toll pass. See additional details at https://www.tollpay.com.au. AU_LINKT Australia-wide toll pass. See additional details at https://www.linkt.com.au/. AR_TELEPASE Argentina toll pass. See additional details at https://telepase.com.ar BR_AUTO_EXPRESO Brazil toll pass. See additional details at https://www.autoexpreso.com BR_CONECTCAR Brazil toll pass. See additional details at https://conectcar.com. BR_MOVE_MAIS Brazil toll pass. See additional details at https://movemais.com. BR_PASSA_RAPIDO Brazil toll pass. See additional details at https://pasorapido.gob.do/ BR_SEM_PARAR Brazil toll pass. See additional details at https://www.semparar.com.br. BR_TAGGY Brazil toll pass. See additional details at https://taggy.com.br. BR_VELOE Brazil toll pass. See additional details at https://veloe.com.br/site/onde-usar. CA_US_AKWASASNE_SEAWAY_CORPORATE_CARD Canada to United States border crossing. CA_US_AKWASASNE_SEAWAY_TRANSIT_CARD Canada to United States border crossing. CA_US_BLUE_WATER_EDGE_PASS Ontario, Canada to Michigan, United States border crossing. CA_US_CONNEXION Ontario, Canada to Michigan, United States border crossing. CA_US_NEXUS_CARD Canada to United States border crossing. ID_E_TOLL Indonesia. E-card provided by multiple banks used to pay for tolls. All e-cards via banks are charged the same so only one enum value is needed. E.g. - Bank Mandiri https://www.bankmandiri.co.id/e-money - BCA https://www.bca.co.id/flazz - BNI https://www.bni.co.id/id-id/ebanking/tapcash IN_FASTAG India. IN_LOCAL_HP_PLATE_EXEMPT India, HP state plate exemption. JP_ETC Japan ETC. Electronic wireless system to collect tolls. https://www.go-etc.jp/ JP_ETC2 Japan ETC2.0. New version of ETC with further discount and bidirectional communication between devices on vehicles and antennas on the road. https://www.go-etc.jp/etc2/index.html MX_IAVE Mexico toll pass. https://iave.capufe.gob.mx/#/ MX_PASE Mexico https://www.pase.com.mx MX_QUICKPASS Mexico https://operadoravial.com/quick-pass/ MX_SISTEMA_TELEPEAJE_CHIHUAHUA http://appsh.chihuahua.gob.mx/transparencia/?doc=/ingresos/TelepeajeFormato4.pdf MX_TAG_IAVE Mexico MX_TAG_TELEVIA Mexico toll pass company. One of many operating in Mexico City. See additional details at https://www.televia.com.mx. MX_TELEVIA Mexico toll pass company. One of many operating in Mexico City. https://www.televia.com.mx MX_VIAPASS Mexico toll pass. See additional details at https://www.viapass.com.mx/viapass/web_home.aspx. US_AL_FREEDOM_PASS AL, USA. US_AK_ANTON_ANDERSON_TUNNEL_BOOK_OF_10_TICKETS AK, USA. US_CA_FASTRAK CA, USA. US_CA_FASTRAK_CAV_STICKER Indicates driver has any FasTrak pass in addition to the DMV issued Clean Air Vehicle (CAV) sticker. https://www.bayareafastrak.org/en/guide/doINeedFlex.shtml US_CO_EXPRESSTOLL CO, USA. US_CO_GO_PASS CO, USA. US_DE_EZPASSDE DE, USA. US_FL_BOB_SIKES_TOLL_BRIDGE_PASS FL, USA. US_FL_DUNES_COMMUNITY_DEVELOPMENT_DISTRICT_EXPRESSCARD FL, USA. US_FL_EPASS FL, USA. US_FL_GIBA_TOLL_PASS FL, USA. US_FL_LEEWAY FL, USA. US_FL_SUNPASS FL, USA. US_FL_SUNPASS_PRO FL, USA. US_IL_EZPASSIL IL, USA. US_IL_IPASS IL, USA. US_IN_EZPASSIN IN, USA. US_KS_BESTPASS_HORIZON KS, USA. US_KS_KTAG KS, USA. US_KS_NATIONALPASS KS, USA. US_KS_PREPASS_ELITEPASS KS, USA. US_KY_RIVERLINK KY, USA. US_LA_GEAUXPASS LA, USA. US_LA_TOLL_TAG LA, USA. US_MA_EZPASSMA MA, USA. US_MD_EZPASSMD MD, USA. US_ME_EZPASSME ME, USA. US_MI_AMBASSADOR_BRIDGE_PREMIER_COMMUTER_CARD MI, USA. US_MI_BCPASS MI, USA. US_MI_GROSSE_ILE_TOLL_BRIDGE_PASS_TAG MI, USA. US_MI_IQ_PROX_CARD MI, USA. Deprecated as this pass type no longer exists. This item is deprecated! US_MI_IQ_TAG MI, USA. US_MI_MACKINAC_BRIDGE_MAC_PASS MI, USA. US_MI_NEXPRESS_TOLL MI, USA. US_MN_EZPASSMN MN, USA. US_NC_EZPASSNC NC, USA. US_NC_PEACH_PASS NC, USA. US_NC_QUICK_PASS NC, USA. US_NH_EZPASSNH NH, USA. US_NJ_DOWNBEACH_EXPRESS_PASS NJ, USA. US_NJ_EZPASSNJ NJ, USA. US_NY_EXPRESSPASS NY, USA. US_NY_EZPASSNY NY, USA. US_OH_EZPASSOH OH, USA. US_PA_EZPASSPA PA, USA. US_RI_EZPASSRI RI, USA. US_SC_PALPASS SC, USA. US_TX_AVI_TAG TX, USA. US_TX_BANCPASS TX, USA. US_TX_DEL_RIO_PASS TX, USA. US_TX_EFAST_PASS TX, USA. US_TX_EAGLE_PASS_EXPRESS_CARD TX, USA. US_TX_EPTOLL TX, USA. US_TX_EZ_CROSS TX, USA. US_TX_EZTAG TX, USA. US_TX_FUEGO_TAG TX, USA. US_TX_LAREDO_TRADE_TAG TX, USA. US_TX_PLUSPASS TX, USA. US_TX_TOLLTAG TX, USA. US_TX_TXTAG TX, USA. US_TX_XPRESS_CARD TX, USA. US_UT_ADAMS_AVE_PARKWAY_EXPRESSCARD UT, USA. US_VA_EZPASSVA VA, USA. US_WA_BREEZEBY WA, USA. US_WA_GOOD_TO_GO WA, USA. US_WV_EZPASSWV WV, USA. US_WV_MEMORIAL_BRIDGE_TICKETS WV, USA. US_WV_MOV_PASS WV, USA US_WV_NEWELL_TOLL_BRIDGE_TICKET WV, USA. */ export default MapViewDirectionsRoutesAPI;