I am trying to have a function for calculating routes for google maps be dynamically changed based on data retrieved from a .getJSON. I have tried including the bulk of the function calcRoute() under a .done function, but I am receiving an error in property waypoints in the javascript console. I am at a loss as what to do, because when I don't include the bulk of the function under the .done, the array remains blank (asynchronous call with the .getJSON. Here is the code to give you a better idea:
function calcRoute() {
var start = document.getElementById('start').value;
var end = document.getElementById('end').value;
var waypts = [];
var data = $.getJSON("/westcoast_map.php", {
westcoast_id: $('.opener').data('westcoast_id')
}, function(json) {
return json[1];
});
data.done(function(theData) {
waypts = theData[1];
console.log(waypts); //this spits out the array in the proper format, i.e. {location:city, state, stopover:true},...etc...
var request = {
origin: start,
destination: end,
waypoints: waypts,
optimizeWaypoints: true,
travelMode: google.maps.DirectionsTravelMode.DRIVING
};
directionsService.route(request, function(response, status) {
if (status == google.maps.DirectionsStatus.OK) {
directionsDisplay.setDirections(response);
var route = response.routes[0];
var summaryPanel = document.getElementById('directions_panel');
summaryPanel.innerHTML = '';
// For each route, display summary information.
for (var i = 0; i < route.legs.length; i++) {
var routeSegment = i + 1;
summaryPanel.innerHTML += '<b>Route Segment: ' + routeSegment + '</b><br>';
summaryPanel.innerHTML += route.legs[i].start_address + ' to ';
summaryPanel.innerHTML += route.legs[i].end_address + '<br>';
summaryPanel.innerHTML += route.legs[i].distance.text + '<br><br>';
}
}
});
});
}
i'm still not sure what you problem is, because the code pared you show, should at least work from the logical part. but there are parts where it is not clear what you try to achive:
var data = $.getJSON("/westcoast_map.php", {
westcoast_id: $('.opener').data('westcoast_id')
}, function(json) {
return json[1];
});
if you expect here that data will become json[1], then your assumption is wrong.
$.getJSON returns always jQuery XHR. the callback function will be called later when the browser received the data.
Here a little example to understand how async works:
the callback functions 1 and 2 are called when the client gets the response for the request, but not before the original script was completely executed, so doSomethingElse() will be always called before the callback function 1 and 2 are executed.
the order in which callback function 1 and 2 are executed depends on which response arrives first.
var test = [];
preparesSomeStuff();
$.getJSON("someurl1",{},function() {
//Callback Function 1
});
doSomething();
$.getJSON("someurl2",{},function() {
//Callback Function 2
});
doSomethingElse();
//<<END OF SCRIPT>>
if you don't want to have your whole code inside of the callback function (e.g. because of readability) you could do it the following way:
function calcRoute() {
var start = document.getElementById('start').value;
var end = document.getElementById('end').value;
var waypts = [];
$.getJSON("/westcoast_map.php", {
westcoast_id: $('.opener').data('westcoast_id')
}, function(theData) {
calcualteRoute(theData[1], start, end);
});
//if you place code here it will be executed before displayResult will be called because getJSON is async
}
function calcualteRoute(waypts, start, end) {
console.log(waypts); //this spits out the array in the proper format, i.e. {location:city, state, stopover:true},...etc...
var request = {
origin: start,
destination: end,
waypoints: waypts,
optimizeWaypoints: true,
travelMode: google.maps.DirectionsTravelMode.DRIVING
};
directionsService.route(request, function(response, status) {
if (status == google.maps.DirectionsStatus.OK) {
displayResult(response,status);
}
});
//if you place some code here it will be executed BEFORE displayResult will be called, because
//directionsService.route is async
}
function displayResult(response, status) {
directionsDisplay.setDirections(response);
var route = response.routes[0];
var summaryPanel = document.getElementById('directions_panel');
summaryPanel.innerHTML = '';
// For each route, display summary information.
for (var i = 0; i < route.legs.length; i++) {
var routeSegment = i + 1;
summaryPanel.innerHTML += '<b>Route Segment: ' + routeSegment + '</b><br>';
summaryPanel.innerHTML += route.legs[i].start_address + ' to ';
summaryPanel.innerHTML += route.legs[i].end_address + '<br>';
summaryPanel.innerHTML += route.legs[i].distance.text + '<br><br>';
}
}
Related
I'm new to javascript, i wanted to check some data using google maps api but this asynchronuous execution of function is killing me, and i don't really understand how callbacks work. Tried to do it but doesn't work.
function initMap(a, callback) {
var service = new google.maps.DistanceMatrixService();
service.getDistanceMatrix({
origins: [punktpocz[a], punktpocz[a + 1]],
destinations: [punktkonc[a], punktkonc[a + 1]],
travelMode: 'DRIVING',
unitSystem: google.maps.UnitSystem.METRIC,
avoidHighways: false,
avoidTolls: false
}, function (response, status) {
if (status !== 'OK') {
alert('Error was: ' + status);
} else {
var originList = response.originAddresses;
var destinationList = response.destinationAddresses;
for (var i = 0; i < originList.length; i++) {
var results = response.rows[i].elements;
for (var j = 0; j < results.length; j++) {
theDiv.innerHTML += originList[i] + ' to ' + destinationList[j] +
': ' + results[j].distance.text + ' in ' +
results[j].duration.text + '<br>';
wynik.push({ odl: results[j].distance.text, czas: results[j].duration.text });
}
}
callback();
}
});
}
and in the second function:
for(i=0;i<czasmax;i++){
...
punktpocz.push(kie[id-1]);
punktkonc.push(biz[parseInt(zleceniajava[z+1])]);
punktpocz.push(biz[parseInt(zleceniajava[z+1])]);
punktkonc.push( zle[ parseInt(zleceniajava[z])] );
initMap(i*2,function(){
console.log('huzzah, I\'m done!');
});
...
}
and i want for the script to wait until initmap is finished to continue but it doesn't seem to work.
You might look into using promises (I had a similar question before: Javascript Promise/Then Example) or use async.js
(Node.js | MongoDB count(): Getting Count Before and After Inserting Data)
I' m having this problem , when I load my page and insert Origin and Destination, after clicking the button "locate" it doesn't show anything in the google map, because it says Response is not an object , so I tried to stamp it with console.log and it says Response=null , but if I reload the page and click fast on Locate , then it draws the route.
Here's the code
function init(){
var latlng = new google.maps.LatLng(40.635636, 17.942414);
var mapOptions = { zoom: 12, center: latlng };
map = new google.maps.Map(document.getElementById('map-canvas'), mapOptions);
}
function updateMap(){
init();
var originGeocoder = new google.maps.Geocoder();
var destinationGeocoder = new google.maps.Geocoder();
var origin = document.getElementById( "origin" ).value + " Brindisi 72100";
var destination = document.getElementById( "destination" ).value + " Brindisi 72100";
var directionsService2 = new google.maps.DirectionsService();
originGeocoder.geocode( { 'address': origin }, function(results, status) {
if ( status == google.maps.GeocoderStatus.OK ) {
var startLatLng = results[0].geometry.location;
var oLat = startLatLng.lat();
var oLng = startLatLng.lng();
document.getElementById('cStart').innerHTML = oLat + " " + oLng;
}
else{
alert("Geocode was not successful for the following reason: " + status);
}
});
//Chiamata asincrona alle API per ottenere Lat e Lng dell' indirizzo di destinazione
destinationGeocoder.geocode( { 'address': destination }, function(results, status) {
if ( status == google.maps.GeocoderStatus.OK ) {
var destLatLng = results[0].geometry.location;
var dLat = destLatLng.lat();
var dLng = destLatLng.lng();
document.getElementById('cDestination').innerHTML = typeof dLat;
document.getElementById('cDestination').innerHTML = dLat + " " + dLng;
}
else{
alert("Geocode was not successful for the following reason: " + status);
}
});
//Salva in req[] le varie distanze tra le paline e la destinazione
singleObjToStop(origin,destination,function(paline,req,reqO){
console.log("1");
//Trova la palina piĆ¹ vicina alla destinazione
calcSingleDis(paline,req,reqO,function(w2,w1){
console.log("2");
//Disegna i waypoints(?)
reqEnd(origin,destination,w1,w2,function(request){
console.log("3");
directionsService2.route(request, function(response, status) {
console.log("4");
console.log(response);
if (status == google.maps.DirectionsStatus.OK) {
directionsDisplay.setDirections(response);
var route = response.routes[0];
var summaryPanel = document.getElementById("distance");
summaryPanel.innerHTML = "";
// For each route, display summary information.
for (var i = 0; i < route.legs.length; i++) {
var routeSegment = i + 1;
summaryPanel.innerHTML += "<b>Route Segment: " + routeSegment + "</b><br />";
summaryPanel.innerHTML += route.legs[i].start_address + " to ";
summaryPanel.innerHTML += route.legs[i].end_address + "<br />";
summaryPanel.innerHTML += route.legs[i].distance.text + " ";
summaryPanel.innerHTML += route.legs[i].duration.text + "<br /><br />" ;
}
computeTotalDistance(response);
}
else{
console.log("ENTRA QUA STRONZO");
console.log("Fermata partenza = " + w1);
console.log("Fermata arrivo = " + w2);
}
});
directionsDisplay.setMap(map);
});
});
});
}
function singleObjToStop(origin,destination,callback){
var data=<?php echo $data; ?>;
var a,b,i=0;
var paline = new Array();
var req = new Array();
var reqO = new Array();
var num = <?php echo $n; ?>;
$.each(data, function(fieldName, fieldValue) {
a=fieldValue.geoLat;
b=fieldValue.geoLong;
a=parseFloat(a);
b=parseFloat(b);
paline[i]=new google.maps.LatLng(a,b);
req[i] = {
origin:paline[i],
destination:destination,
travelMode: google.maps.TravelMode.WALKING
};
reqO[i] = {
origin:origin,
destination:paline[i],
travelMode: google.maps.TravelMode.WALKING
};
i++;
if(i==num){
callback(paline,req,reqO);
}
});
}
function calcSingleDis(paline, req, reqO, callback) {
var directionsService = new google.maps.DirectionsService();
var c = 10000000;
var w2 = new google.maps.LatLng(0, 0);
var w1 = new google.maps.LatLng(0, 0);
var num = <?php echo $n; ?>;
var j = (num - 1);
var t;
var cO = 10000000;
var numO = <?php echo $n; ?>;
var jO = 0;
for (j = 0; j < num; j++) {
t = 0;
directionsService.route(req[j], function(response, status) {
if (status == google.maps.DirectionsStatus.OK) {
//directionsDisplay.setDirections(response);
var troute = response.routes[0];
var dis = parseFloat((troute.legs[0].distance.text).replace(",", "."));
document.getElementById('test').innerHTML = dis;
//se distanza minore di quella minore trovata fin ora la cambia
if (dis < c) {
w2 = paline[j - num];
c = dis;
}
if (t == (num - 1)) {
console.log("QUA ENTRA LOL");
for (jO = 0; jO < numO; jO++) {
console.log("E NON ENTRA MANNAC");
t = 0;
directionsService.route(reqO[jO], function(response, status) {
if (status == google.maps.DirectionsStatus.OK) {
console.log("E NON ENTRA MANNAC22222");
//directionsDisplay.setDirections(response);
var troute = response.routes[0];
var disO = parseFloat((troute.legs[0].distance.text).replace(",", "."));
document.getElementById('test').innerHTML = dis;
//se distanza minore di quella minore trovata fin ora la cambia
if (disO < cO) {
w1 = paline[jO - numO];
cO = disO;
}
if (t == (numO - 1)) {
console.log("W1 = " + w1);
console.log(response);
callback(w2, w1);
}
}
jO++;
t++;
});
}
}
}
j++;
t++;
});
}
}
function reqEnd(origin,destination,w1,w2,callback){
var request = {
origin:origin,
destination:destination,
waypoints: [{location: w1} , {location: w2}],
//waypoints: [{location: w2}],
optimizeWaypoints: true,
travelMode: google.maps.DirectionsTravelMode.WALKING
};
callback(request);
}
function computeTotalDistance(result) {
var totalDist = 0;
var totalTime = 0;
var myroute = result.routes[0];
for (i = 0; i < myroute.legs.length; i++) {
totalDist += myroute.legs[i].distance.value;
totalTime += myroute.legs[i].duration.value;
}
totalDist = totalDist / 1000.
document.getElementById("total").innerHTML = "total distance is: "+ totalDist + " km<br>total time is: " + (totalTime / 60).toFixed(2) + " minutes";
}
google.maps.event.addDomListener( window, 'load', init );
The problem is related to the limit of query that you can use with Google Maps API v3.
You can take a look here: https://developers.google.com/maps/documentation/business/faq#google_maps_api_services
You probably do lots of requests to the API with your program, while you have quite restrictive limits as you can see from google Q&A.
Applications should throttle requests to avoid exceeding usage limits,
bearing in mind these apply to each client ID regardless of how many
IP addresses the requests are sent from.
You can throttle requests by putting them through a queue that keeps
track of when are requests sent. With a rate limit or 10 QPS (queries
per second), on sending the 11th request your application should check
the timestamp of the first request and wait until 1 second has passed.
The same should be applied to daily limits.
Even if throttling is implemented correctly applications should watch
out for responses with status code OVER_QUERY_LIMIT. If such response
is received, use the pause-and-retry mechanism explained in the Usage
limits exceeded section above to detect which limit has been exceeded.
You could find useful: How do I Geocode 20 addresses without receiving an OVER_QUERY_LIMIT response?
The Google Maps API provides a geocoder class for geocoding and reverse geocoding dynamically from user input. read more check Geolocation demo here and more HTML5 Geolocation to check here
Let's say you have a map to display KmlLayer objects on it, with toggle checkbox for each KmlLayer object, located in a panel.
var Province = new google.maps.LatLng(47.112754, -70.815223);
var map = new google.maps.Map( document.getElementById('map'), {zoom:7,center:Province} );
And you store in KML files a limited number of routes, to optimize the speed of the map.
Direction's requests are made using Google Maps API v3.
And let's say you have a page containing a Google Map in a hidden div, and you make Direction requests through this API.
The array 'waypoints' holds the coordinates of each start and end point of each polyline needed.
var geo_coords = ''; // holds the results
var y; // counter
var delay_per_request = 1000; // default delay in milliseconds between requests
var current_delay = delay_per_request; // current delay between requests
function calcRoute(start,end) {
setTimeout(function(){
var directionsService = new google.maps.DirectionsService();
var request = {
origin: start,
destination: end,
travelMode: google.maps.TravelMode.DRIVING
};
directionsService.route(request, function(response, status) {
// Error?
if (status == google.maps.GeocoderStatus.OVER_QUERY_LIMIT) {
document.getElementById('error_text').innerHTML += "<br>" + start + "/" + end
+ "("+status+") :: Interval:"+current_delay+"ms";
window.scrollTo(0, document.body.scrollHeight);
if (current_delay < 2600) {
current_delay += 200;
}
if (current_delay >= 1600) {
delay_per_request = 1600;
}
retry++;
if (retry < 20) {
calcRoute(start,end);
} else {
document.getElementById('error_text').innerHTML += "<br>The script stopped running after "+retry+" retries"
+ " sur " + start + "/" + end + "("+status+") :: Interval:"+current_delay+"ms";
}
// Positive result?
} else if (status == google.maps.DirectionsStatus.OK) {
var myRoute = response.routes[0].overview_path;
for (i in myRoute) {
if (myRoute[i] != undefined) {
geo_coords += myRoute[i].lat() + "," + myRoute[i].lng() + "_";
}
}
geo_coords += "!";
document.getElementById('error_text').innerHTML += "<br><font color=\"green\">" + start + "/" + end
+ "("+status+") :: Interval:"+current_delay+"ms</font>";
window.scrollTo(0, document.body.scrollHeight);
current_delay = delay_per_request;
retry = 0;
Next();
}
});
},current_delay);
}
function Next() {
if (y <= waypoints.length) {
destination = "from:" + waypoints[y] + " to:" + waypoints[y + 1];
geo_desc += description[y] + " => " + description[y+1] + "|";
calcRoute(waypoints[y],waypoints[y+1]);
y = y +2;
} else {
document.getElementById("information").setAttribute('value',geo_coords);
document.getElementById("show_debug_text").setAttribute('value',geo_desc);
document.getElementById("error").setAttribute('value',document.getElementById('error_text').innerHTML);
document.forms["kml"].submit();
}
}
Next();
My question is the following:
Has anyone noticed that Google lower the priority of your requests after you made some request in batch?
The more request you do, the bigger is the number of OVER_QUERY_LIMIT response you get, the bigger is the delay between requests before you have a successful result, and the bigger is the number of requests before you have a successful result.
Is there any workaround or any reason?
(I know I should use the Direction API Webservice to make my requests.)
Thank you!
I have the following code for directions from google maps apiv3. This part is working good. If i have waypoints in my trip, at the top of each trip, it is showing the time as well as distance for the trip.
I used a variable totadistance to add the distance from all the legs but, it does nothing. I do not see a alert message when i run the application.
I want to see the total time and distance for all the trips. How can i get that information?
function calcRoute(startaddr, endaddr) {
var start = document.getElementById(startaddr).value;
var end = document.getElementById(endaddr).value;
var waypts = [];
var waypointstring;
var waypoint1 = document.getElementById('txtWaypoint').value;
waypointstring= waypoint1.split(";");
//alert("Waypoint Length:" + waypointstring.length)
for (var i = 0; i < waypointstring.length; i++) {
waypts.push({location:waypointstring[i], stopover:true});
}
var request = {
origin: start,
destination: end,
waypoints: waypts,
optimizeWaypoints: true,
travelMode: google.maps.TravelMode.DRIVING };
var totaldistance=0;
directionsService.route(request, function(response, status) {
if (status == google.maps.DirectionsStatus.OK) {
directionsDisplay.setDirections(response);
var route = response.routes[0];
var summaryPanel = document.getElementById('directions_panel');
summaryPanel.innerHTML = "";
// For each route, display summary information.
for (var i = 0; i < route.legs.length; i++) {
var routeSegment = i + 1;
summaryPanel.innerHTML += '<b>Route Segment: ' + routeSegment + '</b><br>';
summaryPanel.innerHTML += route.legs[i].start_address + ' to ';
summaryPanel.innerHTML += route.legs[i].end_address + '<br>';
summaryPanel.innerHTML += route.legs[i].distance.text + '<br><br>';
totaldistance = totaldistance + route.legs[i].distance.text ;
}
alert(totaldistance);
}
});
}
Thank you
This is not a number:
totaldistance = totaldistance + route.legs[i].distance.text;
This works to give me the total distance in km:
totaldistance = totaldistance + route.legs[i].distance.value;
working example
I have set an onclick with a variable on a link that calls the calcRoute function for Google maps, and everytime I click the link it says the following Uncaught ReferenceError: NE461UL is not defined The parameter is a postcode by the way.
I have been trying for a while and I can't figure out why it is showing an error.
I have a jquery file with the following line
var distLink = "<a onclick=\"calcRoute(" + postcode + "); return false;\" datalat=" + lat + " datalng=" + lng + " id=\"get-directions\" class=\"directions" + letter +"\">Directions<\/a>";
The calcRoute is in my header
function calcRoute(postcode) {
console.log(marker);
var start = document.getElementById("address").value;
var end = document.getElementById("get-directions").name;
$('get-directions').click(function(){
console.log('click!');
});
var request = {
origin:start,
destination:end,
travelMode: google.maps.TravelMode.DRIVING
};
console.log(JSON.stringify(request));
directionsService.route(request, function(response, status) {
if (status == google.maps.DirectionsStatus.OK) {
directionsDisplay.setDirections(response);
}
});
}
postcode must be passed as a string (extra pair of quotation marks around it):
distLink = "<a onclick=\"calcRoute('" + postcode + "'); return false;\" datalat=" + lat + " datalng=" + lng + " id=\"get-directions\" class=\"directions" + letter +"\">Directions<\/a>";