I am new to Java Script and have a simple problem:
I do routing with Googlemaps API (TransitLayer).
The routing works, the direction panel is succesfully created,
but unfortunately the blue routing line doesn't appear on the map.
It probably has to do with my asynchronous initialsing of the map. (Callback function)
See below my javascript function
and here the link to my page:
My website (Tab 2: routing).
Any help is greatly appreciated.
var directionsDisplay;
var directionsService = new google.maps.DirectionsService();
routingcounter = 0;
var routingmap;
var mapOptions;
function initialize_routing() {
directionsDisplay = new google.maps.DirectionsRenderer();
mapOptions = {
zoom: 8,
mapTypeId: google.maps.MapTypeId.ROADMAP,
center: new google.maps.LatLng(51.510799, -0.134332)
};
routingmap = new google.maps.Map(document.getElementById('mycanvas'),
mapOptions);
directionsDisplay.setMap(routingmap);
directionsDisplay.setPanel(document.getElementById('directions-panel'));
var transitLayer = new google.maps.TransitLayer();
transitLayer.setMap(routingmap);
}
function loadScript() {
if(routingcounter == 0)
{
var script = document.createElement("script");
script.type = "text/javascript";
script.src = "https://maps.googleapis.com/maps/api/js?sensor=false&callback=initialize_routing";
document.body.appendChild(script);
routingcounter++;
}
}
function compute_route()
{
var start = $('from').value;
var over = $('over').value;
var waypts = [];
var end = $('to').value;
if ($('from').value == "" || $('to').value=="")
{
alert("Fill in From- and To-Textfields! Try again!");
return;
}
start += ",London"
end += ",London"
if($('over').value == "")
{
var request = {
origin: start,
destination: end,
travelMode: google.maps.TravelMode.TRANSIT
};
}
else
{
over += ",London"
waypts.push({
location:over,
stopover:true
});
var request = {
origin: start,
destination: end,
waypoints: waypts,
optimizeWaypoints: true,
travelMode: google.maps.TravelMode.TRANSIT
};
}
directionsService.route(request, function(response, status) {
if (status == google.maps.DirectionsStatus.OK)
{
directionsDisplay.setDirections(response);
}
else
{
alert("No matching places found. Retry please!");
$('from').value == "";
$('over').value == "";
$('to').value == "";
}
});
}
google.maps.event.addDomListener(window, 'load', initialize_routing);
Your answer may be with the options of the DirectionsRenderer. You can feed it options, and in most cases, you'll need this.
{
suppressPolylines: false,
polylineOptions: // polylineOptions object here
}
The suppressPolylines will enable polylines on your map. The options can then be set: fill, stroke, etc, using the second object, the same way you would configure a polyline.
Build a fiddle from your code and I'll edit it to implement it.
Edit: Corrected your code - fiddle http://tinker.io/14b5a .
Points to note:
it's $("#elementID"), not $("elementID")
it's $("#input").val(), not $("#input").value
Google Maps API does not take a callback (this is a very serious point as it prevents AMD loaders from loading it)
When all the points above are fixed, the line works all by itself.
Related
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);
}
}
I'm trying to calculate the shortest distance of coordinates taken from a database using Google Map API to a given address. The problem is not there, I managed to alert a shorter distance whenever one is found.But the div named 'duration' has its innerHTML set to the initial value..
I don't get it, I know how scope works..
I've been coding for hours, maybe I just can't see clear anymore.
var directionsService = new google.maps.DirectionsService();
var directionsDisplay = new google.maps.DirectionsRenderer();
var shortestDistance= 99999999;
var myOptions = {
zoom:7,
mapTypeId: google.maps.MapTypeId.ROADMAP
}
var positions = new Array();
<?php
while($row = mysqli_fetch_array($result)){
echo'positions.push(['.$row['latitude'].','.$row['longitude'].']);';
}
?>
for(var i=0;i<positions.length;i++){
var originTemp = "";
originTemp += positions[i][0] + "," + positions[i][1];
var request = {
origin: originTemp,
destination: "1 Ste-Catherine St.",
durationInTraffic: true,
travelMode: google.maps.DirectionsTravelMode.DRIVING
};
directionsService.route(request, function(response, status) {
if (status == google.maps.DirectionsStatus.OK) {
var newRoute = response.routes[0].legs[0].duration.value;
directionsDisplay.setDirections(response);
if(newRoute<shortestDistance){
shortestDistance=newRoute;
alert("New shorter distance: "+shortestDistance);
}
}
});
}
document.getElementById('duration').innerHTML += shortestDistance + " seconds";
</script>
You're doing ajax calls. They're asynchronous by default.
By the time the response from that call comes in and you actually do your "is it shorter" comparison, the rest of the JS code block, including the bit that sets your .innerHTML will already have executed, and set your distance to 9999999.
The driving directions service is asynchronous, set the value when it is detected inside the callback routine (when it runs).
var directionsService = new google.maps.DirectionsService();
var directionsDisplay = new google.maps.DirectionsRenderer();
var shortestDistance= 99999999;
var myOptions = {
zoom:7,
mapTypeId: google.maps.MapTypeId.ROADMAP
}
var positions = new Array();
<?php
while($row = mysqli_fetch_array($result)){
echo'positions.push(['.$row['latitude'].','.$row['longitude'].']);';
}
?>
for(var i=0;i<positions.length;i++){
var originTemp = "";
originTemp += positions[i][0] + "," + positions[i][1];
var request = {
origin: originTemp,
destination: "1 Ste-Catherine St.",
durationInTraffic: true,
travelMode: google.maps.DirectionsTravelMode.DRIVING
};
directionsService.route(request, function(response, status) {
if (status == google.maps.DirectionsStatus.OK) {
var newRoute = response.routes[0].legs[0].duration.value;
directionsDisplay.setDirections(response);
if(newRoute<shortestDistance){
shortestDistance=newRoute;
document.getElementById('duration').innerHTML += shortestDistance + " seconds";
alert("New shorter distance: "+shortestDistance);
}
}
});
}
</script>
Try assigning the contents of the div whenever a new shortestDistance is found:
if(newRoute<shortestDistance){
shortestDistance=newRoute;
alert("New shorter distance: "+shortestDistance);
document.getElementById('duration').innerHTML = shortestDistance + " seconds";
}
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
I am trying to add additional markers (custom icons) to my directional Google maps, but I cant seem to add these outside the initialize() function.
I need to add them outside the initialize() function, because I would like to icons to change based on the route. It's the ADD EXTRA MARKERS TEST which I'm having trouble with. All the rest of the script works perfectly.
Many thanks in advance for any help.
Code so far:
var directionDisplay;
var directionsService = new google.maps.DirectionsService();
var stepDisplay;
function initialize() {
var latlng = new google.maps.LatLng( <? echo $lat; ?> , <? echo $lon; ?> );
var rendererOptions = {draggable: true};
directionsDisplay = new google.maps.DirectionsRenderer(rendererOptions);
var myOptions = {zoom: 14,center: latlng,mapTypeId: google.maps.MapTypeId.ROADMAP,mapTypeControl: false};
var map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
directionsDisplay.setMap(map);
directionsDisplay.setPanel(document.getElementById("directionsPanel"));
}
//calcRoute
function calcRoute() {
var travelMode = 'DRIVING';
var start = $("#routeStart").val();
var via = $("#routeVia2").val();
var end = $("#routeVia").val();
var waypoints = [];
if (via != '') {waypoints.push({location: via,stopover: true});
}
var request = {
origin: start,
destination: end,
waypoints: waypoints,
unitSystem: google.maps.UnitSystem.IMPERIAL,
travelMode: google.maps.DirectionsTravelMode[travelMode]
};
//DISPLAY ROUTE AND PASS LATLNG TO PHP FILE FOR FURTHER PROCESSING
directionsService.route(request, function(response, status) {
if (status == google.maps.DirectionsStatus.OK) {
directionsDisplay.setDirections(response);
var myRoute = response.routes[0];
var txtDir = '';
for (var i=0; i<myRoute.legs[0].steps.length; i++) {
txtDir += myRoute.legs[0].steps[i].path+"";
}
var strLAT = "" + txtDir;
//SEND DATA TO URL PHP FILE
var xmlHttp = getXMLHttp();
xmlHttp.onreadystatechange = function() {
if (xmlHttp.readyState == 4) {
HandleResponse(xmlHttp.responseText);
}}
xmlHttp.open("POST",'MYPHPFILE',true);
xmlHttp.setRequestHeader("Content-type","application/x-www-form-urlencoded");
xmlHttp.send("LATLON="+strLAT);
//ALERT TEST TO ENSURE PHP PROCESSED DATA CORRECTLY
function HandleResponse(response) {
document.getElementById('ResponseDiv').innerHTML = response;
alert($('#ResponseDiv').text());
}
ADD EXTRA MARKERS TEST
var wxlatlng = new google.maps.LatLng( 52 , -1 );
var marker = new google.maps.Marker({
position: wxlatlng,
map: map,
icon: "http://nwsgeo.com/demo/images/pins/road-closed.jpg",
title: "test icon",
});
//ERROR MESSAGES
}else{
if (status == 'ZERO_RESULTS') {
alert('No route could be found between the origin and destination.');
}else if(status == 'INVALID_REQUEST') {
alert('The DirectionsRequest provided was invalid.');
}else{
alert("There was an unknown error in your request. Requeststatus: nn" + status);
}}});}
I am doing some js to get directions panel with asp.net
<!-- language: lang-js -->
var directionsDisplay;
var directionsService = new google.maps.DirectionsService();
var map;
function initialize() {
directionsDisplay = new google.maps.DirectionsRenderer();
var chicago = new google.maps.LatLng(41.850033, -87.6500523);
var mapOptions = {
zoom:7,
mapTypeId: google.maps.MapTypeId.ROADMAP,
center: chicago
}
map = new google.maps.Map(document.getElementById("map_canvas"), mapOptions);
directionsDisplay.setMap(map);
directionsDisplay.setPanel(document.getElementById("directionsPanel"));
}
function calcRoute(lat,lan) {
var InitialOrigin = document.getElementById('ctl00_ContentPlaceHolder1_FESearchListingControl1_txtHide').value;
//var InitialOrigin = document.getElementById("txtHide").Value;
var technopark = new google.maps.LatLng(8.5572357 ,76.87649310000006 );
var split = InitialOrigin.split(',');
var latFrom = parseFloat(split[0]);
var lanFrom = parseFloat(split[1]);
InitialOrigin= new google.maps.LatLng(latFrom,lanFrom);
var to = new google.maps.LatLng(lat,lan);
// var start = document.getElementById("start").value;
// var end = document.getElementById("end").value;
var request = {
origin:InitialOrigin,
destination:to,
travelMode: google.maps.TravelMode.DRIVING
};
directionsService.route(request, function(response, status) {
if (status == google.maps.DirectionsStatus.OK) {
directionsDisplay.setDirections(response);
}
else
{
console.log('something went wrong',status);
}
});
}
I debugged with crome browser and could find that the the line
directionsService.route(request, function(response, status) {
did not return anything,the debugger just jumped to the last closing brace.
The debugger never entered this if statement
if (status == google.maps.DirectionsStatus.OK) {
directionsDisplay.setDirections(response);
}
else
{
console.log('something went wrong',status);
}
This was working before,and i was getting the directions panel before,is there some restrictions with google ?