In a current project, I need to pass an array of locations in to my Google map, and have the API find the directions between them. Google Maps API v.3 limits each directions request to a start point, an end point, and 8 waypoints in between. I need to be able to route more than this. The solution, essentially, is to break my list of stops down into groups, make multiple requests to Google, and stitch the results together when they come back.

This was (of course) a bit more easily said than done. For one thing, you cannot simply split your array into groups of 10, because you need to include the last stop of one array as the first stop of the subsequent array, otherwise there will be gaps in your route. That is, given an array of stops like this (and assuming the Google API max is 4, not 10 to keep the numbers lower):

[a,b,c,d,e,f,g,h]

I need a result like this:

[[a,b,c,d],[d,e,f,g],[g,h]]

So I wrote the following to create a multidimensional array of waypoints, that I can later iterate through and make requests on:

In this sample, my ‘stops’ object is a rich object array, but as long as it contains your stops’ latitudes and longitudes, you’re set. Just update the location property above to match *your* stops object.

So at the end of this, we should have a two-dimensional array with a list of a list of waypoints. In the following method, we pass in this newly created multi-dimensional array (batches), a google.maps.DirectionsRenderer object (directionsDisplay), and a google.maps.DirectionsService object (directionsService). These latter two I have newed up in the calling code, and just send along references.

This route object is fairly rich, and contains a copyright notice, the bounds of the route (to update the bounds of the map), the actual path of the route, and more. In my case, I only need to display the path, and have the bounds updated (to show the entire route, not just one batch), so I created a results object, put the first set of results into it, and then manually update the properties of the object as the subsequent responses come back.

I then use this combinedResults object to render the route.

One potential issue with this that I haven’t accounted for: what happens if / when the results come back in the wrong order? I think your route will get messed up. A better approach might be to stuff the results into another array (or dictionary) and then build the combined object once all the results are back (?).

Of course comments, improvements, etc welcome.

UPDATE 29/Feb/2012

I have updated my code, and modified it so that is should now return the final list of results in the correct order. Essentially I did as I suggested above: I store the results in an intermediary object with an index value and then, when I know I have them all, sort them into their correct order and build up a new object from that. This new object is the one I use to draw the route.

UPDATE 25/Oct/2012

UPDATE 29/Dec/2015

Levillain asked how he/she could display multiple routes. The short answer is to change the ‘stops’ object into a multidimensional array (a collection of stops arrays), and then loop through each set of stops and process the route. You must make sure and new up a new DirectionsRenderer for each request; if you reuse the same one, each query will wipe out the previous one.

I am unable to get the map bounds to update correctly. If anyone knows how to do this, I’m all ears.

Also, I threw this together very quickly, I’m sure it can be optimized / refactored.

UPDATE 4/May/2016

Cesar Ulises Martinez Garcia in his comment below (May 3, 2016) has a workable solution to the 10 batch / OVER_QUERY_LIMIT problem. Essentially, when he hits an OVER_QUERY_LIMIT error, he pauses before sending another request. Thanks, Cesar!

— pass through your batches object, the new DirectionsService object and the new DirectionsDisplay object to my calcRoute function. You may want to edit the way the function is written so that it is “function calcRoute(batches, directionsService, directionsDisplay)” instead of “calcRoute: function”. This colon function notation is “better” because you can create better object-oriented code with it, but if your page is relatively simple, it may be easier to just have functions sitting loose on the page.
}

Thank you for your reply. It works! My two issues were 1) the “function” format you called out. It was really helpful. I always wonder why some of them have “:” on them.. now I know. 2) I did calcRoute(points, directionsService, directionsDisplay) instead of calcRoute(batches, directionsService, directionsDisplay).

Very helpful, thank you!! I had the problem of the mismatching order, and struggled to get it to work, because I return the combined results array to a custom marker generator. Unfortunately, this falls flat because of the asynchronous requests and I can’t quite get it right.

Any suggestions for returning a correct-orderered array that is then returnable?

@David: I suppose instead of directly adding the results (concatting) to the combinedResults object, you could instead build up an intermediary object with 2 properties: the index of the request (ie “k”), and the results of the request.

And then, if (directionsResultsReturned == batches.length) (ie line 38), you would instead call another method to build up the combinedResults object in the right order (as defined in the intermediary object).

Let me know if you have any luck, and I’ll be happy to update the code above.

I wanted to extend the gratitude for the following code. I am in the process of learning javascript and tackling your code was definitely exciting! I now am stuck in the same boat as David W. was. I still havent grasped the ability to apply what I am learning (Head First Java, 2nd Edition by Kathy Sierra and Bert Bates) to my own projects. Can someone help me with a portion of code to help get me started? I only have at the most 3 batches of waypoints.
Thanks for your help and your time!

I messed about with it a day later and managed to get something working right. However, it was a while ago and I can’t remember much detail and am too lazy to read the mass of code to get it.

I’ve pastebinned a snippet from my code which essentially handles routes if they’re long. i create batches of waypoints in chunks, and then process them as individual requests, then match up the original batches to the batches as returned.

Disclaimer:
1) What i’ve pasted is obviously just copy-paste from my code so don’t expect it to work as is. Also, it’s messy as hell. Apologies for the indenting fails
2) It is probably not the most efficient / efficient at all way to do it
3) I am not responsible for any Javascript-related injuries this code may cause 😉

I looked at your code and it looks like you store the first location of each batch of points, and then compare the results as they come back against that, yes? I think that’s a pretty good approach. However, in my use case, it’s possible (though unlikely) that the user could enter the same point more than once in their route, so I’m a bit worried it could give bad results.

I revisited my code with the original approach I suggested, and have a new code snippet that should store the results in an indexed object as they come back. Then, when they are all back, sort the object and use that.

@Garrett: Good luck! If you improve it in any way, or solve any pitfalls I’ve overlooked (goodness knows they’re there), let me know.

Hello, don’t mean to spoil the party. But i don’t think this way of concatenating arrays can be considered route optimization because the aforementioned approach does not optimize the given route at all, seeing that it only combines the optimization results of each small segment of the route, which is not how route optimization should work in my opinion.

The sum of optimized segments is not equal to the entire route optimization simply because this approach fails to consider the route(all the waypoints) in its entirety.

Please let me know if i am wrong and i would be glad to hear from you. Thank you.

For my purposes, this was to find directions for an already optimized set of waypoints (found by utilizing ArcGIS Network Analyst). You’re right that if you provide waypoints in a non-optimal order, that route is likewise going to be non-optimal. Of course you still face the 8 waypoint limit in v.3 of the Google API.

That is of course correct. However this is not a TSP problem, nor a solution. Calculating TSP even for 8 waypoints is very expensive! In my case the purpose of the code was to visualise a route, and let the user alter the order. One could TSP the route as a whole beforehand, then chunk it up, but the post was merely a means to an end.

Well spotted though, and good to have as a comment so that false expectations are not raised. 🙂

A question:
Is splitting your list of locations into chunks using a from, to and a couple of waypoints more or less efficient than splitting it into simple From/to pairs with no waypoints?
I just wonder that, even though I am giving Google the waypoints in the order I have already optimised them, is Google doing some sort of TSP calculation on them anyway? If so, then is this calculation more expensive than multiple calls to a simple From/To route?

My understanding is that Google will not reorder the waypoints as you provide them. It *is* finding the most efficient route between any pair of waypoints, but the overall order won’t change. If this is the case, then the most efficient code would likely be that which makes the least number of calls to the external Google API, as I suspect that is the slowest part of the code. I suppose it may take more or less time on the Google end depending on the number of waypoints provided, but in my (non-scientific) experience, it doesn’t seem to matter (I’m guessing this is why they imposed the 8 waypoint limit)

If you did it in pairs, you would still need to include the second item in any pair as the first in the next to get a complete route. ie:

Thanks, Lemon,
That’s what I thought it did until I saw the replies to this post with chaps talking about the traveling salesman problem being the reason for the limit (it being computationally expensive, and all)
I will have to experiment next week and give it an obviously reversed set of waypoints to see if it changes the order.
I will report back!

Hi,
Thanks for this great post. I added it to my software. I use .net with the webbrowser control. In this web browerscontrol i loaded the html with the javascript.
I seed the route but i noticed 2 things:
1. I see gaps between the directionsparts
2. Sometimes unwanted loops in the route is shown
I did what you wrote [[a,b,c,d][d,e,f,g]]

For the gaps, I’m really not sure. I’m using the code with long and short collections of stops (3 – 100), and I don’t experience gaps between sets.

As for loops, are you optimizing your route before sending off to Google? This code will not resort / optimize your stops for you, it will only find the best route *between each pair of stops*. Maybe your route is not optimized?

Actually – I just realized there was an error in the first bit of javascript (the code that takes the stops and breaks them up into sub-batches). Basically, when I copied and pasted, “itemsCounter–;” was moved up to the previous line (with a comment) and so was effectively commented out. That would indeed cause the gaps.

Hi,
I found the bug for the gaps, was my error 🙂
What do you mean by optimize the route.
I import and xml with about 2500 gps coordinates and break them in peaces of 1 start 1 end and 8 waypoints.
Can you give me an hint.
What is the e.g. the effect of set the stopover option to false?

Hi ,
Thanks a lot,I have implemented your solution and its working fine but I am facing an issue.Sometimes the route is not getting displayed on map, I noticed that issue when I am trying to load the routes one after the other within seconds.But when I debugged, the code was getting executed till the end but only route is not getting displayed on map.

Hi Deepika,
Are you sure that you are sending through a “newed up” directionsDisplay object? ie, before you call calcRoute, you have to: directionsDisplay = new window.google.maps.DirectionsRenderer();

I have tried out your code for more than 8 waypoints on Google map its working fine,I am facing one issue,if I am having count upto 100 waypoints then the route is getting displayed,if more than 100 waypoints then only map is getting displayed without route.what might be the problem?

Hmmm… I’m not sure why this is happening, but I can confirm I see it as well. In fact, with me, I can display 91 waypoints, and then the 92nd fails.

I don’t have time to investigate this any further at the moment, but if you find anything out, please post back here and I will update the code.

One thing I can think of: we’re breaking the waypoints into 10-stop groups, but the first waypoint of each group equals the last waypoint of the previous group. Therefore waypoints are broken down to:
1-10
10-19
19-28
28-37
37-46
46-55
55-64
64-73
73-82
82-91
91-100 <— this is where it's failing

You'll see that it accepts exactly 10 groups (which is a strangely round number: 0 to 9? only a single digit?), and that failure is happening exactly on the "seam" (I can get 91 waypoints, but not 92). So that's where I would look in the code first.

Well, there is only one event that you can capture something is changed on route is ; ‘directions_changed’ .
this is the last place that you can take action before google trims extra route points. However I couldn’t solve the issue of tracing change/new point via this event. And I don’t know how to cut-off google’s trim action and keep “stops” as intact.

If Ruben Romao’s example code solves the 91 point limit, I don’t see what it is that’s making the difference.
Where is lemonharpy’s code failing?

I tried my hand at some debugging, but failed. My (lack of) javascript expertise is just not sufficient to solve this.

But, the ten-batch limit seemed correct, irrespective of the batch size. That is, with a batch size of, say, 5, the total number of points that are processed is 41 (this is 10 * 5 – 10 + 1).
That is, it seemed so until I put in a few alerts to monitor counters, which resulted in more points being processed… Sometimes.

i am having one more problem with my map.
I have 10 points, i can get directions for 1 to 10,
Now for i need to show 1 to 5 points, from 5 to 6 it should show , walk to 6 , then 6 to 10 with get direction points.

if you click the below link or copy paste the link. you can see the walking informations for one point to another point, i want this in my middle points.

Situation:
Start = A
Destination = A
Waypoints more than 8, eg. B1-B55

Challenge: As opposed to above examples (where e.g. the order of bus stops is known), the logic must calculate the optimal route. This is possible with the parameter “waypoints=optimize:true”. Example: A person must deliver goods and needs to find the optimal route. Task is achieved when all goods are delivered and the person is back at the start.

Hi kilinho. Here’s a jsfiddle that shows that: http://jsfiddle.net/ZyHnk/124/ Basically, you want to promote the DirectionsDisplay object up to the page so that you can reference it, and then run setMap(null) on it. Note that I set the value down in the calcRoute() function.

Hello. First thanks for this great piece of code that really helps me !
I’m stuck in the 91 limit of waypoints and can’t find a way to introduce a tempo to not get the “reach limit” from Google. Does someone know how to do that ?

Also is there a way to display the route without markers ? I have 260 markers on my map and it does not look so nice as if all were removed

I added optimizeWaypoints: true to the request, and my trace route has more logic than before, many thanks for your algorithm i had some problems to adapt it, if you can or someone can.. maybe separate the functions can solve many problems for others… thanks

Hi, probably a stupid question but is there a way to reset/clear the map to redraw? i have a list of waypoints that i want the map to reflect when i change them. at the moment it keeps all the original waypoints on the map. so if there was 20 waypoints and i reduced it to 3 i want the refresh to only show the 3! help!

Hi, first i want to say that this is a great code.
I’m making a project with google maps and i used this code (hope you dont mind) and i am trying to take out the google original markers but i cant find where is the code of the original google marker. Can you please help me with that? I have some icons that i want to insert as the markers.. I’ve allready insert the icons as markers and is working fine but the problem is that those original google markers (the ones with the letters) dont disapear ..
please help!
Thanks

Just wanted to say thanks heaps, this code is great! I have noticed you have said you don’t mind if people use it in their projects, but if you want me to include a comments of thanks with something specific please let me know!

Hi ! Thanks a lot for this
I was wondering how can I do to have more than one road ?
If i have one road like : [[a,b,c,d],[d,e,f,g],[g,h]] and one : [[i,j,k,l],[l,m,n]] do those 2 roads while be separated ?

Hi Lemonharpy! im from Argentina, sorry for my regular english. I appreciate your tutorial. I need your opinion with my project. I want to create a map with different routes/traces from the buses of my city. I dont need directions, i just need to draw the route with polyline or somethig. Can you suggest me the solution more simple? Thanks a lot

First, sorry for the bad english, I’m a spanish speaker.
Thanks for the advices that are in this blog. That helped me a lot to reach a final solution to the limitations on google maps, not only the 8 points, also the limitation about OVER_QUERY_LIMIT (10 querys per second). For that this aproach only serves for 91 waypoints.

In this case, I created around 250 points to show the route between them. Also I use the plugin jquery Pace to show an appropiate loading indicator because the time is relative to the points in the route.

Hello everybody, first of all tjank you for your solution and your suggests.
A question: this solution works also with more than 500 waypoints?
I’m trying to use with a route that has 569 waypoints but I don’t see anything and at the same time don’t receive a limit usage error from google maps api?

hi, This is work for me. But i got problem if the way point moret than 230. IN myd atabase each vehicles has almost 8000 waypoints. I have the premium Key, but i don’t know how to modified this code to be match with morethan 1000 waypoints.
thanks

he Cesar Ulises Martinez Garcia. It is working good. Do you have any idea with additional data? example: each point has an information (local time or Speed). How do I appear the information in maker after the directionsDisplay.setMap(map).
thanks

Hi Cesar i am not sure i fully understand how this is meant to work, you set an error variable inside an asynchronous function and check for the error with in the main function, doesnt this mean you are checking for the error before the function has completed, am i missing something.

@lemonharpy & @Cesar Ulises Martinez Garcia : thanks for reply my msg.
I tried use “http://rubenromao.com/google-maps-api-v3-waypoints-limit-workaround.php” but i did not find the Delay.
I tried to download the script but this link dosn’t work. “https://mega.nz/#!TgYmhT7R”