Google Maps Api straight (shortest) route - google-maps

I am currently trying to find a way how to get a straight route with Google Maps Api V3.
I already managed it to use geocode and the directions service to get a route from point A to point B, including two alternative routes. I also experimented with "No highways" and "No tolls" but nothing appears to solve this problem entirely...
At the moment I check the three given routes for lowest miles but this has to be proven not really to be the shortest route.
I am not searching the fastest or quickest route but just a straight route with as low miles as possible.
As I did not find any thread by using google explaining something like I need I ask you. Maybe somebody has a solution here...
P.S.: I also can't use the "Pedestrian Mode" as this is used as a navigation help for our local fire trucks when our mounted navigation systems do not work again.
This is also the reason why we need as low kilometers as possible - when driving a firetruck round here the fastest route is 99% the one with lowest miles but the Api won't let me decide that and insist on using principal roads

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,
}
})
})
})
});
}
}

I use a solution, as I said here, that calls route service once and filters the results in a way that you find usefull. In my example, I'm calculating the shortest route.

Related

How to optimize route using the google direction API

I am using the google direction api to solve the travelling salesman problem.
Apparently the api takes a param called optimize:true and then return a "waypoint_order": [ 1, 0, 2, 3 ] telling you the best order of waypoints that optimizes the route.
Thing is, when you try to optimize the route, the API just does not work and you get NO_RESULTS.
For instance use this url to see how the API fails when the optimize:true| bit gets added.
NOT working (NO_RESULTS error):
https://maps.googleapis.com/maps/api/directions/json?origin=place_id:ChIJdd4hrwug2EcRmSrV3Vo6llI&destination=place_id:ChIJh1a5WhEMa0gRY1JU4PEam8Q&waypoints=optimize:true|place_id:ChIJPeqVDlONbEgRk4X1zrUsKDs|place_id:ChIJ_WegsaCYc0gRlCypaxXgLjs|&key=YOUR_KEY
WORKING (but not optimizing):
NOT optimizing url: https://maps.googleapis.com/maps/api/directions/json?origin=place_id:ChIJdd4hrwug2EcRmSrV3Vo6llI&destination=place_id:ChIJh1a5WhEMa0gRY1JU4PEam8Q&waypoints=place_id:ChIJPeqVDlONbEgRk4X1zrUsKDs|place_id:ChIJ_WegsaCYc0gRlCypaxXgLjs|&key=YOUR_KEY
Does anyone know if they stopped supporting routes optimization?
Thanks
Looks to me like that is a bug in the DirectionsService when you pass in PlaceIds. I replicated it with the Javascript API. Using addresses works:
waypts = [];
waypts.push({
location: "Plymouth, UK", // {placeId:"ChIJPeqVDlONbEgRk4X1zrUsKDs"},
stopover: true
});
waypts.push({
location: "Bournemouth, UK", // {placeId:"ChIJ_WegsaCYc0gRlCypaxXgLjs"},
stopover: true
});
var request = {
origin: "London, UK", //{placeId:"ChIJdd4hrwug2EcRmSrV3Vo6llI"},
destination: "Newquay, UK", //{placeId: "ChIJh1a5WhEMa0gRY1JU4PEam8Q"},
waypoints: waypts,
optimizeWaypoints: true,
travelMode: 'DRIVING'
};
fiddle using addresses (returns waypoint order=1,0)
But the same locations (I used these placeIds to get the addresses above) doesn't work using placeIds:
waypts = [];
waypts.push({
location: {placeId:"ChIJPeqVDlONbEgRk4X1zrUsKDs"},
stopover: true
});
waypts.push({
location: {placeId:"ChIJ_WegsaCYc0gRlCypaxXgLjs"},
stopover: true
});
var request = {
origin: {placeId:"ChIJdd4hrwug2EcRmSrV3Vo6llI"},
destination: {placeId: "ChIJh1a5WhEMa0gRY1JU4PEam8Q"},
waypoints: waypts,
optimizeWaypoints: true,
travelMode: 'DRIVING'
};
fiddle using placeId (returns ZERO_RESULTS)
might be related to this issue in the issue tracker: Issue 8979: Bug: Can't use combination of placeId and String for origin/destination

different results between map.google.com and google api for javascript

i'm making simple website that helps to find direction between 2 points.
and i found something strange.
if i search through map.google.com it returns exact results, but mine dose not.
for example, i set "New York University, New York, NY, United States" as origin and "260 Broadway New York NY 10007" as destination using map.google.com
using map.google.com
if i use my website using googleMap API->
using api
<script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyDs8SYxRh-pMXa9Qe-K1nVY0g3CLpmJ9mo&signed_in=true&libraries=places&callback=initMap" async defer></script>
function calculateAndDisplayRoute(directionsDisplay, directionsService,
markerArray, stepDisplay, map) {
for (var i = 0; i < markerArray.length; i++) {
markerArray[i].setMap(null);
}
directionsDisplay.setPanel(document.getElementById('panel'));
var selectedMode = document.getElementById('mode').value;
directionsService.route({
origin: document.getElementById('pac-input').value,
destination: document.getElementById('pac-input2').value,
travelMode: google.maps.TravelMode[selectedMode]
}, function(response, status) {
// Route the directions and pass the response to a function to create
// markers for each step.
if (status === google.maps.DirectionsStatus.OK) {
document.getElementById('warnings-panel').innerHTML =
'<b>' + response.routes[0].warnings + '</b>';
directionsDisplay.setDirections(response);
//showSteps(response, markerArray, stepDisplay, map);
} else {
window.alert('Directions request failed due to ' + status);
}
});
}
It looks like you have places autocomplete inputs and read value of these inputs in your code.
I can suggest using the place ID from places autocomplete in your directions service. This way you will be sure that you work with the address that was chosen.
Look at this example and type there your addresses http://jsbin.com/xuyisem/1/edit?html,output

Plotting more than 8 waypoints in Google Maps v3

Migrating code from Javascript API 2 to 3. I have a list of locations which i need to plot in the form of a driving directions. This was done in v2 using the following code
directions = new GDirections(map);
directions.loadFromWaypoints(waypoints, {preserveViewport: true});
Here is my attempt at converting this to V3
var request = {
origin: startLoc,
destination: endLoc,
waypoints: waypoints,
optimizeWaypoints: true,
travelMode: google.maps.TravelMode.DRIVING
};
directionsService.route(request, function(response, status) {
if (status == google.maps.DirectionsStatus.OK) {
directionsDisplay.setDirections(response);
}
});
Not the whole code, but the general idea. Seems to work fine, with one little issue. When there are more than 8 waypoints, the call fails. This is expected since Google Maps API v3 Docs states
The maximum allowed waypoints is 8, plus the origin, and destination. Maps API for Business customers are allowed 23 waypoints, plus the origin, and destination. Waypoints are not supported for transit directions.
Since i didn't run in to this issue in v2, is this a new restriction with v3? I wonder if i am using something that was not designed for what i need. This is a very lightly used applicaton with 2 users, so i am not sure if an expensive business license is worth the return. Emails to Google maps team have not yet been returned. Any workarounds/pointers will be of great help. Thanks.
One possible work around (particularly for a lightly used site) is to use multiple DirectionsService requests.
example 1 (addresses)
example 2 (coordinates)
Use Should need to Use array concept like these...
directionsService[i].route({
'origin': start,
'destination': end
'waypoints': waypts,
'travelMode': 'DRIVING'
},
function (directions, status){
if (status == google.maps.DirectionsStatus.OK) {
directionsDisplay[j].setDirections(directions);
}
});
in these directionservice and directiondisplay are should be in array logic
and using looping concepts use should need to assign start,end and waypoints dynamically and
try sending multiple request means u ll get the route for n number of latlon's ...but the markers ll be repeat with same name after 8 waypoints for that we remove the default markers by using supressmarkers false property...
As others said, it's imposable to do it using Google's JavaScript API. However, Google does allow up to 23 waypoints with a server-side request. So using PHP and JavaScript, I was able to make a workaround.
What you have to do is get the "waypoint order" from the server side request and then have JavaScript give you directions between each location.
<?php
$startLocation = "40.713,-74.0135";
$endLocation = "40.75773,-73.985708";
$waypoints = array("40.748433,-73.985656|", "40.689167,-74.044444|");
$apiKey = "";
$routeData = json_decode(file_get_contents("https://maps.googleapis.com/maps/api/directions/json?origin=".$startLoc."&destination=".$endLoc."&waypoints=optimize:true|".$waypoints."&key=".$apiKey));
echo "var waypointsOrder = ". json_encode($routeData->routes[0]->waypoint_order) . ";\n";
?>
var startLocation = {lat: 40.713, lng: -74.0135};
var endLocation = {lat: 40.75773, lng: -73.985708};
//get directions from the origin to the first waypoint
var request = {
origin: startLocation,
destination: JSON.parse(places[waypointsOrder[0]][1]),
travelMode: google.maps.TravelMode.DRIVING
};
directionsService.route(request, function (result, status) {
if (status == google.maps.DirectionsStatus.OK) {
renderDirections(result, map);
}
});
//get directions from the last waypoint to the destination
var request = {
origin: JSON.parse(places[waypointsOrder[waypointsOrder.length-1]][1]),
destination: endLocation,
travelMode: google.maps.TravelMode.DRIVING
};
directionsService.route(request, function (result, status) {
if (status == google.maps.DirectionsStatus.OK) {
renderDirections(result, map);
}
});
//get directions between each waypoint
for (i = 1; i < waypointsOrder.length; i++) {
var request = {
origin: JSON.parse(places[waypointsOrder[i-1]][1]),
destination: JSON.parse(places[waypointsOrder[i]][1]),
travelMode: google.maps.TravelMode.DRIVING
};
directionsService.route(request, function (result, status) {
if (status == google.maps.DirectionsStatus.OK) {
renderDirections(result, map);
}
});
}
function renderDirections(result, map) {
var directionsDisplay = new google.maps.DirectionsRenderer ({
map: map
});
directionsDisplay.setMap(map);
directionsDisplay.setDirections(result);
}

Is it possible to put a marker after some "km" from the start point in a DirectionsService's route?

This is my code :
var request = {
origin: start,
destination: end,
travelMode: google.maps.DirectionsTravelMode.DRIVING
};
directionsService.route(request, function (response, status) {
if (status == google.maps.DirectionsStatus.OK) {
directionsDisplay.setDirections(response);
}
});
now, I'd like to put a marker after 200km from the point origin: start : is it possible?
Here is an example that puts two markers on a route (one at 9.5km and one at 64.8km):
http://www.geocodezip.com/v3_GoogleEx_directions-waypoints_kmmarkersC.html
(so, yes, it is possible)
This example was created before the geometry library was released, and might be able to be re-written to use that.

An elegant way to find shortest and fastest route in Google Maps API v3?

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 default searched for the fastest route. I set the "avoidhighways" option in request parameter to true in order to get the shortest route, but I am not quite happy with the result.
Anyone have a better solution than that??
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.
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));
DISCLAIMER
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,
}
});
});
});
});
}