Use locations with google distance matrix - javascript

I am a newbie ith google maps distance matrix. But I need it to calculate most effecient route between several locations.
However using a jsfiddle example I can even make it create a route with locations in my region:
My Js fiddle
Example js Fiddle tha I used as base
Basically changed destinations to:
var origin = "Aeroporto da Madeira"
var destinations = [
"Hotel Four Views Baía, Rua das Maravilhas, Funchal",
"R. José Joaquim da Costa 112, 9325-031 Estreito De Câmara, Portugal",
"Q.ta de São João, 2735-521, Portugal"];
These places exist and if I search at google maps appear.
This maybe a very stupid question but what am I doing wrong?

The fact that an address may be geocoded must not mean that a route may be calculated to another location.
In your case the origin is on madeira(an island), but the last destination isn't placed on madeira(a driving route may not be calculated....obviously there are no ferries available...., your function stops running because of the attempt to access a undefined variable routes.elements[i].duration.value)
check the status of the element before you access it's properties
var map;
var geocoder;
var origin = "Aeroporto da Madeira"
var destinations = [
"Hotel Four Views Baía, Rua das Maravilhas, Funchal",
"R. José Joaquim da Costa 112, 9325-031 Estreito De Câmara, Portugal",
"Q.ta de São João, 2735-521, Portugal"
];
var directionsDisplay;
var directionsService = new google.maps.DirectionsService();
function calculateDistances() {
var service = new google.maps.DistanceMatrixService();
service.getDistanceMatrix({
origins: [origin], //array of origins
destinations: destinations, //array of destinations
travelMode: google.maps.TravelMode.DRIVING,
unitSystem: google.maps.UnitSystem.METRIC,
avoidHighways: false,
avoidTolls: false
}, callback);
}
function callback(response, status) {
if (status != google.maps.DistanceMatrixStatus.OK) {
alert('Error was: ' + status);
} else {
//we only have one origin so there should only be one row
var routes = response.rows[0];
//need to find the shortest
var lowest = Number.POSITIVE_INFINITY;
var tmp;
var shortestRouteIdx = -1;
var resultText = "Possible Routes: <br/>";
for (var i = routes.elements.length - 1; i >= 0; i--) {
//do we got a result for the element?
if (routes.elements[i].status === google.maps.DistanceMatrixElementStatus.OK) {
tmp = routes.elements[i].duration.value;
resultText += "Route " + destinations[i] + ": " + tmp + "<br/>";
if (tmp < lowest) {
lowest = tmp;
shortestRouteIdx = i;
}
}
}
//log the routes and duration.
document.getElementById('results').innerHTML = resultText;
if (shortestRouteIdx > -1) {
//get the shortest route
var shortestRoute = destinations[shortestRouteIdx];
//now we need to map the route.
calculateRoute(origin, shortestRoute)
} else {
alert('no route available');
}
}
}
//Calculate the route of the shortest distance we found.
function calculateRoute(start, end) {
var request = {
origin: start,
destination: end,
travelMode: google.maps.TravelMode.DRIVING
};
directionsService.route(request, function(result, status) {
if (status == google.maps.DirectionsStatus.OK) {
directionsDisplay.setDirections(result);
}
});
}
function initialize() {
directionsDisplay = new google.maps.DirectionsRenderer();
var centerPosition = new google.maps.LatLng(32.670159, -16.978268);
var options = {
zoom: 12,
center: centerPosition,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
map = new google.maps.Map(document.getElementById('map'), options);
directionsDisplay.setMap(map);
calculateDistances();
}
google.maps.event.addDomListener(window, 'load', initialize);
html,
body,
#map {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}
#results {
position: fixed;
top: 0;
right: 0;
background: gold;
}
<div id="map"></div>
<div id="results"></div>
<script src="https://maps.googleapis.com/maps/api/js?v=3"></script>

Related

How do I match destinations in the google maps Distance Matrix

I've got a web app that needs 'distance from me' information for properties displayed on a map.
I'm using googles Distance Matrix Service
distanceService = new google.maps.DistanceMatrixService();
I'm calling the service with one origin and multiple destinations.
var params = {
origins: [currentLocation],
destinations: endPoints,
travelMode: google.maps.TravelMode.DRIVING
}
distanceService.getDistanceMatrix(params, saveDistances);
My endPoints are an array of google.maps.LatLng objects taken from my properties. However when the results are returned they've changed these to addresses, and there's no longer any reference to the LatLng's.
Does anyone know if the Distance Matrix Service guarantees to return results in the same order I sent them? I couldn't see anything in the docs. I really don't want to start calling the geocoding services just to match back to my properties (especially as the LatLng's return won't be an exact match)
They are returned in the same order they are sent.
That isn't specifically stated, but the way I read the documentation it is implied.
quick test fiddle
code snippet:
var service = new google.maps.DistanceMatrixService();
var places = [{
address: "New York, NY",
lat: 40.7143528,
lng: -74.0059731
}, {
address: "Tampa, FL",
lat: 27.950575,
lng: -82.4571776
}, {
address: "Newark, NJ",
lat: 40.735657,
lng: -74.1723667
}, {
address: "Boston, MA",
lat: 42.3584308,
lng: -71.0597732
}, {
address: "Baltimore, MD",
lat: 39.2903848,
lng: -76.6121893
}];
var foundlatlng = new google.maps.LatLng(40.65, -73.95); // Brooklyn, NY
var gotoLoc = [];
for (var i = 0; i < places.length; i++) {
gotoLoc.push(new google.maps.LatLng(places[i].lat, places[i].lng));
}
var service = new google.maps.DistanceMatrixService(); //request distance matrix
var outputdiv = document.getElementById('info');
// var goto = new google.maps.LatLng(places[i].lat, places[i].lng);
function callback(response, status) {
var distancefield = distancefield;
if (status == google.maps.DistanceMatrixStatus.OK) {
var origins = response.originAddresses;
var destinations = response.destinationAddresses;
var htmlString = "<table border='1'>";
var bounds = new google.maps.LatLngBounds();
for (var c = 0; c < response.rows.length; c++) {
var results = response.rows[c].elements;
for (var r = 0; r < results.length; r++) {
var element = results[r];
var distancetext = element.distance.text;
var durationtext = element.duration.text;
var to = destinations[r];
htmlString += "<tr><td>" + (r + 1) + "</td><td>" + places[r].address + "</td><td>" + response.originAddresses[c] + "</td><td>" + to + "</td><td>" + distancetext + "</td><td>" + durationtext + "</td></tr>";
var marker = new google.maps.Marker({
icon: 'http://gmaps-samples.googlecode.com/svn/trunk/markers/blue/marker' + (r + 1) + '.png',
position: {
lat: places[r].lat,
lng: places[r].lng
},
map: map
});
bounds.extend(marker.getPosition());
} //end for r
} // end for c
map.fitBounds(bounds);
htmlString += "</table>";
document.getElementById('info').innerHTML = htmlString;
} //end if status=ok
} //end callback
// console.log(places);
var map;
var geocoder = new google.maps.Geocoder();
function initialize() {
var mapOptions = {
zoom: 8,
center: foundlatlng,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
map = new google.maps.Map(document.getElementById('map_canvas'),
mapOptions);
service.getDistanceMatrix({
origins: ["San Diego, CA", foundlatlng],
destinations: gotoLoc,
travelMode: google.maps.TravelMode.WALKING,
unitSystem: google.maps.UnitSystem.IMPERIAL,
avoidHighways: false,
avoidTolls: false,
}, callback); //end service.getdistancematrix()
}
google.maps.event.addDomListener(window, 'load', initialize);
html,
body {
margin: 0;
padding: 0;
height: 100%;
width: 100%
}
#map_canvas {
height: 400px;
width: 100%;
}
tr,
td,
tbody,
table {
height: 100%;
width: 100%;
}
}
<script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk"></script>
<table border="1">
<tr>
<td>
<div id="map_canvas"></div>
</td>
</tr>
<tr>
<td>
<div id="info"></div>
</td>
</tr>
</table>
Wouldn't it be so much more helpful if you could provide an Index/ID with each Origin and Destination that would be returned in the API response?
If the order is guaranteed to be the exact same as sent, I agree that this should work fine. But this is not stated as guaranteed and it seems to arbitrarily limit Google's ability to order the results in a way that suits them better.

Google Places not returning complete results with RouteBoxer

EDIT: It seems that I'm hitting the query limit, but I'm not being returned a full 200 results. So upon further research it looks like the Google API will let me query 10 boxes, return those results, and then smacks me with an OVER_QUERY_LIMIT status for the rest. So I figure I now have two options: slow my queries, or broaden my distance to create fewer boxes along the route.
I'm currently fooling around building a little web app that provides a details about places along a route (like gas stations and coffee on a road trip). I'm using the Google Maps API with the Places Library and RouteBoxer. I'm generating all the appropriate boxes with RouteBoxer, but when the boxes are passed to the Places Library I'm only getting back some of the places. Usually I'll get the first half of the route (on shorter routes) or a few random chunks (for longer routes). San Francisco to Seattle returns me gas stations around Seattle and around Medford, OR only.
Initially I thought maybe I was hitting the results cap of 200, but it's making a separate request for each box, and my total results often aren't hitting 200. Results returned are generally pretty consistent from what I can see. When looking at the details of my network requests and responses, it seems that the script is moving through the boxes making requests with the Places library, and suddenly it stops part way through.
The live app where you can see results and boxes is on Heroku.
My JavaScript isn't the strongest by any means. That's part of why I wanted to work with this API, so please pardon my ignorance if I'm making a trivial mistake. The full script is below. Any direction is tremendously appreciated!
var infowindow = new google.maps.InfoWindow();
var map;
var routeBoxer;
var service;
function initialize() {
directionsDisplay = new google.maps.DirectionsRenderer();
var mapOptions = {
zoom: 4,
center: new google.maps.LatLng(39, -98),
mapTypeId: google.maps.MapTypeId.ROADMAP,
};
map = new google.maps.Map(document.getElementById('map-canvas'), mapOptions);
service = new google.maps.places.PlacesService(map);
routeBoxer = new RouteBoxer();
directionService = new google.maps.DirectionsService();
directionsRenderer = new google.maps.DirectionsRenderer({ map: map })
directionsDisplay.setMap(map);
directionsDisplay.setPanel(document.getElementById('directions-panel'));
}
function calcRoute() {
var start = document.getElementById('start').value;
var end = document.getElementById('end').value;
var waypt1 = document.getElementById('waypoint1').value;
var waypt2 = document.getElementById('waypoint2').value;
var waypts = []
if (waypt1) {
waypts.push({
location:waypt1,
stopover:true});
}
if (waypt2) {
waypts.push({
location:waypt2,
stopover:true});
}
var request = {
origin: start,
destination: end,
waypoints: waypts,
optimizeWaypoints: true,
travelMode: google.maps.TravelMode.DRIVING
};
directionService.route(request, function(response, status) {
if (status == google.maps.DirectionsStatus.OK) {
directionsDisplay.setDirections(response);
// Build boxes around route
var path = response.routes[0].overview_path;
var boxes = routeBoxer.box(path, 2); // distance in km from route
drawBoxes(boxes);
for (var i=0; i < boxes.length; i++) {
var bounds = boxes[i];
findPlaces(bounds);
findPlacesByText(bounds);
}
} else {
alert("Directions query failed: " + status);
}
});
}
function findPlaces(bounds) {
var selectedTypes = [];
var inputElements = document.getElementsByClassName('placeOption');
for (var i=0; inputElements[i]; i++) {
if (inputElements[i].checked) {
selectedTypes.push(inputElements[i].value)
}
}
var request = {
bounds: bounds,
types: selectedTypes
};
if (selectedTypes.length > 0) {
service.radarSearch(request, callback);
}
}
function findPlacesByText(bounds) {
var selectedTypes = '';
var inputElements = document.getElementsByClassName('textOption');
for (var i=0; inputElements[i]; i++) {
if (inputElements[i].checked) {
selectedTypes += inputElements[i].value + ', '
}
}
var request = {
bounds: bounds,
query: selectedTypes
};
if (selectedTypes.length > 0) {
service.textSearch(request, callback);
}
}
function callback(results, status) {
if (status == google.maps.places.PlacesServiceStatus.OK) {
for (var i = 0; i < results.length; i++) {
createMarker(results[i]);
}
}
}
function createMarker(place) {
var marker = new google.maps.Marker({
map: map,
position: place.geometry.location
});
var request = {
reference: place.reference
};
google.maps.event.addListener(marker,'click',function(){
service.getDetails(request, function(place, status) {
if (status == google.maps.places.PlacesServiceStatus.OK) {
var contentStr = '<h5>' + place.name + '</h5><p>' + place.formatted_address;
if (!!place.formatted_phone_number) contentStr += '<br />' + place.formatted_phone_number;
if (!!place.website) contentStr += '<br /><a target="_blank" href="' + place.website + '">' + place.website + '</a>';
contentStr += '<br />' + place.types + '</p>';
infowindow.setContent(contentStr);
infowindow.open(map,marker);
} else {
var contentStr = "<h5>No Result, status=" + status + "</h5>";
infowindow.setContent(contentStr);
infowindow.open(map,marker);
}
});
});
}
google.maps.event.addDomListener(window, 'load', initialize);
After much experimentation and further research, I decided to try to slow my queries. The way I handled that was to write a new function that calls my query function, and then recursively calls itself with a delay for the next route box. If an OVER_QUERY_LIMIT status is returned, it recalls that box with an increased delay. So far it seems to be working great, but it quickly increases the delay to nearly a half second (or more) between calls, which can take a while if you have a long route with many boxes. My new function that seems to have solves the problem is below. It'll take some more fine-tuning to really get it right, but it's close!
var delay = 100;
...
function queryPlaces(boxes, searchIndex) {
// delay calls to Places API to prevent going over query limit (10/sec)
var bounds = boxes[searchIndex];
findPlaces(bounds);
findPlacesByText(bounds);
if (searchIndex > 0) {
searchIndex--;
setTimeout(queryPlaces, delay, boxes, searchIndex);
}
}

Google Maps API OVER_QUERY_LIMIT 10 Destinations [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
I've been researching this all day and still haven't come across a solution that works. I'm using the Google Maps Distance Matrix Service with 1 origin and 14 destinations. I modified the sample code from Google (https://developers.google.com/maps/documentation/javascript/examples/distance-matrix) and just added more destinations to test it out. With anything over 10 destinations, the OVER_QUERY_LIMIT error occurs and mis-places a marker.
From the usage limits I found (100 elements per 10 seconds), I shouldn't be hitting the limit at all. I have also tried inserting my API Key in this line, to no avail:
src="https://maps.googleapis.com/maps/api/js?v=3.exp"
Any help would be appreciated! Thanks.
Code changes to the sample code from Google:
var destinationA = new google.maps.LatLng(45.465422,9.185924);
var destinationB = new google.maps.LatLng(41.385064,2.173403);
var destinationC = new google.maps.LatLng(40.416775,-3.70379);
var destinationD = new google.maps.LatLng(51.507351,-0.127758);
var destinationE = new google.maps.LatLng(48.856614,2.352222);
var destinationF = new google.maps.LatLng(41.902784,12.496366);
var destinationG = new google.maps.LatLng(50.85034,4.35171);
var destinationH = new google.maps.LatLng(46.198392,6.142296);
var destinationI = new google.maps.LatLng(47.36865,8.539183);
var destinationJ = new google.maps.LatLng(53.408371,-2.991573);
var destinationK = new google.maps.LatLng(37.389092,-5.984459);
var destinationL = new google.maps.LatLng(53.349805,-6.26031);
var destinationM = new google.maps.LatLng(55.864237,-4.251806);
var destinationN = new google.maps.LatLng(51.92442,4.477733);
function calculateDistances() {
var service = new google.maps.DistanceMatrixService();
service.getDistanceMatrix(
{
origins: [origin],
destinations: [destinationA, destinationB,destinationC, destinationD,destinationE, destinationF,destinationG, destinationH,destinationI, destinationJ,destinationK, destinationL, destinationM, destinationN],
travelMode: google.maps.TravelMode.DRIVING,
unitSystem: google.maps.UnitSystem.METRIC,
avoidHighways: false,
avoidTolls: false
}, callback);
}
The OVER_QUERY_ERROR is coming from the geocoder, not the DistanceMatrix call. Remove this line:
addMarker(destinations[j], true);
(you don't need the geocoder, you already have the coordinates for the markers)
working code snippet:
var map;
var geocoder;
var bounds = new google.maps.LatLngBounds();
var markersArray = [];
var origin = new google.maps.LatLng(55.930, -3.118);
var origin2 = 'Greenwich, England';
var destinationA = new google.maps.LatLng(45.465422, 9.185924);
var destinationB = new google.maps.LatLng(41.385064, 2.173403);
var destinationC = new google.maps.LatLng(40.416775, -3.70379);
var destinationD = new google.maps.LatLng(51.507351, -0.127758);
var destinationE = new google.maps.LatLng(48.856614, 2.352222);
var destinationF = new google.maps.LatLng(41.902784, 12.496366);
var destinationG = new google.maps.LatLng(50.85034, 4.35171);
var destinationH = new google.maps.LatLng(46.198392, 6.142296);
var destinationI = new google.maps.LatLng(47.36865, 8.539183);
var destinationJ = new google.maps.LatLng(53.408371, -2.991573);
var destinationK = new google.maps.LatLng(37.389092, -5.984459);
var destinationL = new google.maps.LatLng(53.349805, -6.26031);
var destinationM = new google.maps.LatLng(55.864237, -4.251806);
var destinationN = new google.maps.LatLng(51.92442, 4.477733);
var destinationIcon = 'https://chart.googleapis.com/chart?chst=d_map_pin_letter&chld=D|FF0000|000000';
var originIcon = 'https://chart.googleapis.com/chart?chst=d_map_pin_letter&chld=O|FFFF00|000000';
function initialize() {
var opts = {
center: new google.maps.LatLng(55.53, 9.4),
zoom: 10
};
map = new google.maps.Map(document.getElementById('map-canvas'), opts);
geocoder = new google.maps.Geocoder();
}
function calculateDistances() {
deleteOverlays();
var destinations = [destinationA, destinationB, destinationC, destinationD, destinationE, destinationF, destinationG, destinationH, destinationI, destinationJ, destinationK, destinationL, destinationM, destinationN];
for (var i = 0; i < destinations.length; i++) {
bounds.extend(destinations[i]);
var marker = new google.maps.Marker({
map: map,
position: destinations[i],
icon: destinationIcon
});
markersArray.push(marker);
}
map.fitBounds(bounds);
var service = new google.maps.DistanceMatrixService();
service.getDistanceMatrix({
origins: [origin],
destinations: destinations,
travelMode: google.maps.TravelMode.DRIVING,
unitSystem: google.maps.UnitSystem.METRIC,
avoidHighways: false,
avoidTolls: false
}, callback);
}
function callback(response, status) {
if (status != google.maps.DistanceMatrixStatus.OK) {
alert('Error was: ' + status);
} else {
var origins = response.originAddresses;
var destinations = response.destinationAddresses;
var outputDiv = document.getElementById('outputDiv');
outputDiv.innerHTML = '';
for (var i = 0; i < origins.length; i++) {
var results = response.rows[i].elements;
addMarker(origins[i], false);
for (var j = 0; j < results.length; j++) {
// addMarker(destinations[j], true);
outputDiv.innerHTML += "<b>"+j+":</b>"+origins[i] + ' to ' + destinations[j] + ': ' + results[j].distance.text + ' in ' + results[j].duration.text + '<br>';
}
}
}
}
function addMarker(location, isDestination) {
var icon;
if (isDestination) {
icon = destinationIcon;
} else {
icon = originIcon;
}
geocoder.geocode({
'address': location
}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
bounds.extend(results[0].geometry.location);
map.fitBounds(bounds);
var marker = new google.maps.Marker({
map: map,
position: results[0].geometry.location,
icon: icon
});
markersArray.push(marker);
} else {
alert('Geocode was not successful for the following reason: ' + status);
}
});
}
function deleteOverlays() {
for (var i = 0; i < markersArray.length; i++) {
markersArray[i].setMap(null);
}
markersArray = [];
}
google.maps.event.addDomListener(window, 'load', initialize);
html,
body {
height: 100%;
margin: 0;
padding: 0;
}
#map-canvas {
height: 100%;
width: 50%;
}
#content-pane {
float: right;
width: 48%;
padding-left: 2%;
}
#outputDiv {
font-size: 11px;
}
<script src="https://maps.googleapis.com/maps/api/js"></script>
<p>
<button type="button" onclick="calculateDistances();">Calculate distances</button>
</p>
</div>
<div id="outputDiv"></div>
</div>
<div id="map-canvas"></div>

Javascript, set variable from contents of text box

I am trying to adapt this Google Maps distance calculator to my needs, but am not overly familiar with plain Javascript, and only Jquery.
I am trying to modify one of the destination variables so that it pulls it from a text box instead.
Usually the line reads :
var destinationA = 'pe219px';
But I am trying to change it to the following, usually I would do this with a keyup function to update the value as the person types in jquery, but im not sure what im doing in plain javascript. This is what I have come up with so far, but it doesn't appear to do a lot :
function setValue() {
destinationA=parseInt(document.getElementById('deliverypostcode').value);
}
This is the example I am trying to modify
https://developers.google.com/maps/documentation/javascript/examples/distance-matrix
This is the whole code :
<!DOCTYPE html>
<html>
<head>
<title>Distance Matrix service</title>
<script src="https://maps.googleapis.com/maps/api/js?v=3.exp&sensor=false"></script>
<style>
html, body {
height: 100%;
margin: 0;
padding: 0;
}
#map-canvas {
height: 100%;
width: 50%;
}
#content-pane {
float:right;
width:48%;
padding-left: 2%;
}
#outputDiv {
font-size: 11px;
}
</style>
<script>
var map;
var geocoder;
var bounds = new google.maps.LatLngBounds();
var markersArray = [];
var origin1 = new google.maps.LatLng(53.003604, -0.532764);
var origin2 = 'pe219px';
function setValue() {
destinationA=parseInt(document.getElementById('deliverypostcode').value);
}
var destinationB = new google.maps.LatLng(53.003604, -0.532764);
var destinationIcon = 'https://chart.googleapis.com/chart?chst=d_map_pin_letter&chld=D|FF0000|000000';
var originIcon = 'https://chart.googleapis.com/chart?chst=d_map_pin_letter&chld=O|FFFF00|000000';
function initialize() {
var opts = {
center: new google.maps.LatLng(53.003604, -0.532764),
zoom: 8
};
map = new google.maps.Map(document.getElementById('map-canvas'), opts);
geocoder = new google.maps.Geocoder();
}
function calculateDistances() {
var service = new google.maps.DistanceMatrixService();
service.getDistanceMatrix(
{
origins: [origin1, origin2],
destinations: [destinationA, destinationB],
travelMode: google.maps.TravelMode.DRIVING,
unitSystem: google.maps.UnitSystem.IMPERIAL,
avoidHighways: false,
avoidTolls: false
}, callback);
}
function callback(response, status) {
if (status != google.maps.DistanceMatrixStatus.OK) {
alert('Error was: ' + status);
} else {
var origins = response.originAddresses;
var destinations = response.destinationAddresses;
var outputDiv = document.getElementById('outputDiv');
outputDiv.innerHTML = '';
deleteOverlays();
for (var i = 0; i < origins.length; i++) {
var results = response.rows[i].elements;
addMarker(origins[i], false);
for (var j = 0; j < results.length; j++) {
addMarker(destinations[j], true);
outputDiv.innerHTML += origins[i] + ' to ' + destinations[j]
+ ': ' + results[j].distance.text + '<br>';
}
}
}
}
function addMarker(location, isDestination) {
var icon;
if (isDestination) {
icon = destinationIcon;
} else {
icon = originIcon;
}
geocoder.geocode({'address': location}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
bounds.extend(results[0].geometry.location);
map.fitBounds(bounds);
var marker = new google.maps.Marker({
map: map,
position: results[0].geometry.location,
icon: icon
});
markersArray.push(marker);
} else {
alert('Geocode was not successful for the following reason: '
+ status);
}
});
}
function deleteOverlays() {
for (var i = 0; i < markersArray.length; i++) {
markersArray[i].setMap(null);
}
markersArray = [];
}
google.maps.event.addDomListener(window, 'load', initialize);
</script>
</head>
<body>
<div id="content-pane">
<div id="inputs">
<form name="form1" method="post" action="">
<label for="deliverypostcode">Your Postcode</label>
<input type="text" name="deliverypostcode" id="deliverypostcode">
</form>
<p><button type="button" onclick="calculateDistances();">Calculate
distances</button></p>
</div>
<div id="outputDiv"></div>
</div>
<div id="map-canvas"></div>
</body>
</html>
Your function setValue is never called.
What if you delete it and just place the following line at the begining of calculateDistances ?
var destinationA= document.getElementById('deliverypostcode').value;
This works for me. Also, you don't need to parseInt your text input. Geocoding converts strings to a lat/long coordinates.

not able to access global variable while using google maps api js

In the below code, I am not able to access the value of variable distances . I think that is because of asynchronous call directionsService.route. How can I get the value variable distances ?
var totalDistance;
var distances = new Array();
var directionsDisplay;
var directionsService = new google.maps.DirectionsService();
var map;
var start = "ABC XYZ";
var end ;
var points = new Array("Location ABC", "Location PQR", "Location XYZ", "Location more", "And Some other location");
function initialize() {
directionsDisplay = new google.maps.DirectionsRenderer();
var mapOptions = {
center: new google.maps.LatLng(13.0604220, 80.2495830),
zoom: 10,
mapTypeId: google.maps.MapTypeId.ROADMAP,
draggableCursor: "crosshair"
};
map = new google.maps.Map(document.getElementById("map-canvas"),
mapOptions);
directionsDisplay.setMap(map);
}
function calcRoute() {
for(var j=0;j<points.length;j++)
{
end = points[j];
var waypoints = new Array();
for(var i=0; i<points.length;i++)
{
if(i!=j)
{
waypoints.push({location:points[i], stopover: true});
}
}
var request = {
origin: start,
destination: end,
waypoints: waypoints,
optimizeWaypoints: true,
travelMode: google.maps.TravelMode.DRIVING
};
directionsService.route(request, function(response, status) {
if (status == google.maps.DirectionsStatus.OK) {
var route = response.routes[0];
totalDistance = 0;
for ( var i=0;i<route.legs.length;i++)
{
totalDistance+=route.legs[i].distance.value;
}
distances.push(totalDistance);
}
});
}
/*Now I want my distances value to be accessed from here i.e outside for loop.*/
/*So that I can compare all the distances obtained */
}
google.maps.event.addDomListener(window, 'load', initialize);
Edit: I have updated complete code.
What I am trying to do : I have fixed start point and some waypoints (order not fixed), I am trying to optimize waypoints, my end point is not fixed, it can be any so that to optimize the path, but it is necessary to provide end point while calling directionsService.route method , so I am taking one of the waypoints as end point and keeping rest other in waypoints only and then calculating total distance of the route. So each of the waypoint will become end point one by one , and others will remain waypoint. I will calculate total distance of all the combinations and then I will show only the directions of the route which has minimum distance.
I would avoid calling asynchronous functions from inside a loop. It can be a pain keeping track of everything.
From what I understand of the question you are trying to find the shortest route with an arbitrary number of destinations. Instead of looping through each waypoint, pass the starting address and all of the destinations to the DistanceMatrix service which returns all of the route lengths from the origin to each waypoint. When the results return sort from shortest to longest. The longest destination will be the end address. Then pass the start address, end address, and remaining waypoints to the DirectionService with the optimizeWaypoints turned on.
Demo: http://jsfiddle.net/bryan_weaver/snYJ2/
Relavent Code:
var map;
var origin = "4100 Ashby Road, St. Ann, MO 63074"
var destinations = [
"2033 Dorsett Village, Maryland Heights, MO 63043",
"1208 Tamm Avenue, St. Louis, MO 63139",
"1964 S Old Highway 94 St Charles, MO 63303"];
var directionsDisplay;
var directionsService = new google.maps.DirectionsService();
function calculateDistances() {
var service = new google.maps.DistanceMatrixService();
service.getDistanceMatrix({
origins: [origin], //array of origins
destinations: destinations, //array of destinations
travelMode: google.maps.TravelMode.DRIVING,
unitSystem: google.maps.UnitSystem.METRIC,
avoidHighways: false,
avoidTolls: false
}, callback);
}
function callback(response, status) {
if (status != google.maps.DistanceMatrixStatus.OK) {
alert('Error was: ' + status);
} else {
//we only have one origin so there should only be one row
var routes = response.rows[0];
var sortable = [];
var resultText = "Origin: <b>" + origin + "</b><br/>";
resultText += "Possible Routes: <br/>";
for (var i = routes.elements.length - 1; i >= 0; i--) {
var rteLength = routes.elements[i].duration.value;
resultText += "Route: <b>" + destinations[i] + "</b>, "
+ "Route Length: <b>" + rteLength + "</b><br/>";
sortable.push([destinations[i], rteLength]);
}
//sort the result lengths from shortest to longest.
sortable.sort(function (a, b) {
return a[1] - b[1];
});
//build the waypoints.
var waypoints = [];
for (j = 0; j < sortable.length - 1; j++) {
console.log(sortable[j][0]);
waypoints.push({
location: sortable[j][0],
stopover: true
});
}
//start address == origin
var start = origin;
//end address is the furthest desitnation from the origin.
var end = sortable[sortable.length - 1][0];
//calculate the route with the waypoints
calculateRoute(start, end, waypoints);
//log the routes and duration.
$('#results').html(resultText);
}
}
//Calculate the route of the shortest distance we found.
function calculateRoute(start, end, waypoints) {
var request = {
origin: start,
destination: end,
waypoints: waypoints,
optimizeWaypoints: true,
travelMode: google.maps.TravelMode.DRIVING
};
directionsService.route(request, function (result, status) {
if (status == google.maps.DirectionsStatus.OK) {
directionsDisplay.setDirections(result);
}
});
}
function initialize() {
directionsDisplay = new google.maps.DirectionsRenderer();
var centerPosition = new google.maps.LatLng(38.713107, -90.42984);
var options = {
zoom: 12,
center: centerPosition,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
map = new google.maps.Map($('#map')[0], options);
geocoder = new google.maps.Geocoder();
directionsDisplay.setMap(map);
calculateDistances();
}
google.maps.event.addDomListener(window, 'load', initialize);
The request is asynchronous.
You have got to wait until the request completes before you check your global variable.
See this answer
Is there any way to wait until the DirectionsService returns results?
EDIT
If you really in a fix you can try making a Synchronous call with
jQuery.ajaxSetup({async:false});
making sure you turn it on again after the method completes
jQuery.ajaxSetup({async:true});
This comes with huge warning however as it can cause your browser to lock up use with
caution
Your alert is firing before the callback has been fired. I'd suggest you create another function and call that from your directionsService.route success callback e.g
var totalDistance; /*Global Variable */
var distances = new Array();
var directionsService = new google.maps.DirectionsService();
/* Some request */
directionsService.route(request, function(response, status) {
if (status == google.maps.DirectionsStatus.OK) {
directionsDisplay.setDirections(response);
var route = response.routes[0];
totalDistance = 0;
for ( var i=0;i<route.legs.length;i++)
{
totalDistance+=route.legs[i].distance.value;
}
distances.push(totalDistance);
}
afterComplete();// New function call moved outside for loop
});
function afterComplete(){
alert(distances); //Will display null
}
You could then also remove the global variable and actually pass it into the afterComplete function, thus eliminating the need for a global (unless of course it is needed elsewhere)
The DirectionsService is asynchronous. You need to use the results inside the call back function:
function calcRoute() {
for(var j=0;j<points.length;j++)
{
end = points[j];
var waypoints = new Array();
for(var i=0; i<points.length;i++)
{
if(i!=j)
{
waypoints.push({location:points[i], stopover: true});
}
}
var request = {
origin: start,
destination: end,
waypoints: waypoints,
optimizeWaypoints: true,
travelMode: google.maps.TravelMode.DRIVING
};
directionsService.route(request, function(response, status) {
if (status == google.maps.DirectionsStatus.OK) {
var route = response.routes[0];
totalDistance = 0;
for ( var i=0;i<route.legs.length;i++)
{
totalDistance+=route.legs[i].distance.value;
}
distances.push(totalDistance);
}
else { alert("Distance Service request not successful:"+status); }
if (distances.length == points.length){
alert(distances);
}
});
}
The global variable will be available after the data comes back from the server and the callback function finishes running. If you need to do something with it once it is available, do that in the call back function.
example

Categories