I am making a taxi fare calculator. One of the business requirements is that, the company wants the shortest and fastest route options. I know Google directionService by def
See http://codepen.io/jasonmayes/pen/DupCH.
var shortestDistance = function() {
var directionsDisplay;
var directionsService = new google.maps.DirectionsService();
var map;
var size = 0;
var currentPosition;
// An array of interesting places we want to potentially visit.
var interestingPlaces = [
{'title': 'Regents Park', 'latLng': new google.maps.LatLng(51.530686, -0.154753)},
{'title': 'Hyde Park', 'latLng': new google.maps.LatLng(51.507293, -0.164022)},
{'title': 'Green Park', 'latLng': new google.maps.LatLng(51.504088, -0.141706)},
{'title': 'Regents Park', 'latLng': new google.maps.LatLng(51.479185, -0.159903)}
];
// An array to store results from Google routing API.
var routeResults = [];
// Call this upon page load to set everything in motion!
function initialize(currentLat, currentLng) {
currentPosition = new google.maps.LatLng(currentLat, currentLng);
directionsDisplay = new google.maps.DirectionsRenderer();
var mapOptions = {
zoom: 13,
center: currentPosition
};
map = new google.maps.Map(document.getElementById('map-canvas'), mapOptions);
directionsDisplay.setMap(map);
var marker = new google.maps.Marker({
position: currentPosition,
map: map,
title: 'Currrently location.'
});
var i = interestingPlaces.length;
while (i--) {
interestingPlaces[i].marker = new google.maps.Marker({
position: interestingPlaces[i].latLng,
map: map,
title: interestingPlaces[i].title,
icon: 'http://maps.google.com/mapfiles/ms/icons/green.png'
});
}
findNearestPlace();
}
// Loops through all inteesting places to calculate route between our current position
// and that place.
function findNearestPlace() {
var i = interestingPlaces.length;
size = interestingPlaces.length;
routeResults = [];
while (i--) {
calcRoute(interestingPlaces[i].latLng, storeResult);
}
}
// A function to calculate the route between our current position and some desired end point.
function calcRoute(end, callback) {
var request = {
origin: currentPosition,
destination: end,
travelMode: google.maps.TravelMode.DRIVING
};
directionsService.route(request, function(response, status) {
if (status == google.maps.DirectionsStatus.OK) {
callback(response);
} else {
size--;
}
});
}
// Stores a routing result from the API in our global array for routes.
function storeResult(data) {
routeResults.push(data);
if (routeResults.length === size) {
findShortest();
}
}
// Goes through all routes stored and finds which one is the shortest. It then
// sets the shortest route on the map for the user to see.
function findShortest() {
var i = routeResults.length;
var shortestIndex = 0;
var shortestLength = routeResults[0].routes[0].legs[0].distance.value;
while (i--) {
if (routeResults[i].routes[0].legs[0].distance.value < shortestLength) {
shortestIndex = i;
shortestLength = routeResults[i].routes[0].legs[0].distance.value;
}
}
directionsDisplay.setDirections(routeResults[shortestIndex]);
}
// Expose the initialize function publicly as "init".
return {
init: initialize
};
}();
// Upon page load, lets start the process!
google.maps.event.addDomListener(window, 'load', shortestDistance.init(51.489554, -0.12969));
THIS IS NOT MY PEN!!! I AM JUST REFERRING TO A USEFUL RESOURCE THAT MIGHT HELP
First of all, sorry for my solution being in TS, you can easily convert it to JS.
The "avoidhighways" attribute is not there to get the fastest or shortest route, it's there for what the name suggests, avoiding highways.
I've made my own solution by always getting multiple routs with this attribute:
directionsService.route({
[...]
provideRouteAlternatives: true
[...]
}, (response, status) => {
if (status === google.maps.DirectionsStatus.OK) {
var shortest: google.maps.DirectionsResult = this.shortestRoute(response);
this.directionsDisplay.setDirections(shortest);
[...]
And I made this function that returns the DirectionsResult with just the one route. In this case it's the shortest, but you can tweek it so it returns what ever route suits your needs.
shortestRoute = (routeResults: google.maps.DirectionsResult): google.maps.DirectionsResult => {
var shortestRoute: google.maps.DirectionsRoute = routeResults.routes[0];
var shortestLength = shortestRoute.legs[0].distance.value;
for (var i = 1; i < routeResults.routes.length; i++) {
if (routeResults.routes[i].legs[0].distance.value < shortestLength) {
shortestRoute = routeResults.routes[i];
shortestLength = routeResults.routes[i].legs[0].distance.value;
}
}
routeResults.routes = [shortestRoute];
return routeResults;
}
I took code from Soldeplata Saketos answer and edited it since it wasn't working. Added params so you can just call it with it like.
shortestRoute(origin, destination, map);
Works for me all though I'm not sure how correct it is.
Here:
function shortestRoute(origin, destination, map) {
directionsService = new google.maps.DirectionsService();
var routesResponses = [];
//avoiding tolls
directionsService.route({
origin: origin,
destination: destination,
provideRouteAlternatives: true,
avoidTolls: true,
travelMode: google.maps.TravelMode.DRIVING
}, function (response, status) {
if (status === google.maps.DirectionsStatus.OK) {
routesResponses.push(response);
} else {
window.alert('Directions request failed due to ' + status);
}
});
//avoiding highways
directionsService.route({
origin: origin,
destination: destination,
provideRouteAlternatives: true,
avoidHighways: true,
travelMode: google.maps.TravelMode.DRIVING
}, function (response, status) {
if (status === google.maps.DirectionsStatus.OK) {
routesResponses.push(response);
} else {
window.alert('Directions request failed due to ' + status);
}
//Results analysis and drawing of routes
var fastest = Number.MAX_VALUE,
shortest = Number.MAX_VALUE;
routesResponses.forEach(function (res) {
res.routes.forEach(function (rou, index) {
console.log("distance of route " + index + ": ", rou.legs[0].distance.value);
console.log("duration of route " + index + ": ", rou.legs[0].duration.value);
if (rou.legs[0].distance.value < shortest) shortest = rou.legs[0].distance.value;
if (rou.legs[0].duration.value < fastest) fastest = rou.legs[0].duration.value;
})
})
console.log("shortest: ", shortest);
console.log("fastest: ", fastest);
//painting the routes in green blue and red
routesResponses.forEach(function (res) {
res.routes.forEach(function (rou, index) {
new google.maps.DirectionsRenderer({
map: map,
directions: res,
routeIndex: index,
polylineOptions: {
strokeColor: rou.legs[0].duration.value == fastest ? "red" : rou.legs[0].distance.value == shortest ? "darkgreen" : "blue",
strokeOpacity: rou.legs[0].duration.value == fastest ? 0.8 : rou.legs[0].distance.value == shortest ? 0.9 : 0.5,
strokeWeight: rou.legs[0].duration.value == fastest ? 9 : rou.legs[0].distance.value == shortest ? 8 : 3,
}
});
});
});
});
}
To obtain the shortest route from A to B I would suggest to make different queries with the “alternatives=true” parameter, playing with the “avoid” parameter between avoid=toll, avoid=highways, and then I would compare all results to pick the shortest route.
directionsService = new google.maps.DirectionsService;
//avoiding tolls
directionsService.route({
origin: {
'placeId': originId
},
destination: {
'placeId': destinationId
},
provideRouteAlternatives: true,
avoidTolls: true,
travelMode: google.maps.TravelMode.DRIVING
}, function(response, status) {
if (status === google.maps.DirectionsStatus.OK) {
routesResponses.push(response);
}
else {
window.alert('Directions request failed due to ' + status);
}
});
//avoiding highways
directionsService.route({
origin: {
'placeId': originId
},
destination: {
'placeId': destinationId
},
provideRouteAlternatives: true,
avoidHighways: true,
travelMode: google.maps.TravelMode.DRIVING
}, function(response, status) {
if (status === google.maps.DirectionsStatus.OK) {
routesResponses.push(response);
}
else {
window.alert('Directions request failed due to ' + status);
}
//Results analysis and drawing of routes
var fastest = Number.MAX_VALUE,
shortest = Number.MAX_VALUE;
routesResponses.forEach(function(res) {
res.routes.forEach(function(rou, index) {
console.log("distance of route " +index+": " , rou.legs[0].distance.value);
console.log("duration of route " +index+": " , rou.legs[0].duration.value);
if (rou.legs[0].distance.value < shortest) shortest = rou.legs[0].distance.value ;
if (rou.legs[0].duration.value < fastest) fastest = rou.legs[0].duration.value ;
})
})
console.log("shortest: ", shortest);
console.log("fastest: ", fastest);
//painting the routes in green blue and red
routesResponses.forEach(function(res) {
res.routes.forEach(function(rou, index) {
new google.maps.DirectionsRenderer({
map:map,
directions:res,
routeIndex:index,
polylineOptions:{
strokeColor: rou.legs[0].duration.value == fastest? "red":rou.legs[0].distance.value == shortest?"darkgreen":"blue",
strokeOpacity: rou.legs[0].duration.value == fastest? 0.8:rou.legs[0].distance.value == shortest? 0.9: 0.5,
strokeWeight: rou.legs[0].duration.value == fastest? 9:rou.legs[0].distance.value == shortest? 8: 3,
}
})
})
})
});
}
}
You get three options with the alternatives=true
option set. You can then search through those for both the shortest and fastest of the routes returned.
Use optimizeWaypoints: true in Request perameter. See below code snippet var request ={ origin: sStartLatLng, destination: sStartLatLng, waypoints: waypts, optimizeWaypoints: true, travelMode: google.maps.DirectionsTravelMode.DRIVING };