Calculating the Distance between Zip Codes Using the Google Maps API – Part 2
Last week, we went over the basics for accessing the Google Maps API and calculating mileage between zip codes with Google's Distance Matrix service. The problem is that the service only lets us work with 25 origin and 25 destination points at a time. A custom solution is needed to go beyond that.
Introduction
As before, we need to access the Google Maps API before using the Distance Matrix service.
<html>
<head>
<title>Distance Matrix Example #2</title>
<script type="text/javascript">
//FUNCTION THAT DOES MOST OF THE WORK
function initialize() {
//CONVERT THE MAP DIV TO A FULLY-FUNCTIONAL GOOGLE MAP
var mapOptions = {
zoom: 8,
center: new google.maps.LatLng(-34.397, 150.644),
mapTypeId: google.maps.MapTypeId.ROADMAP
}
var map = new google.maps.Map(document.getElementById("map_canvas"), mapOptions);
//...the new code from this post will go here...//
}
//FUNCTION TO LOAD THE GOOGLE MAPS API
function loadScript() {
var script = document.createElement("script");
script.type = "text/javascript";
script.src = "http://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&sensor=false&callback=initialize";
document.body.appendChild(script);
}
//START THE SCRIPT (AFTER THE PAGE LOADS)
window.onload = loadScript;
</script>
</head>
<body>
<div id="zip_code_output"></div>
<div id="map_canvas" style="width:650px; height:600px;"></div>
</body>
</html>
An explanation of the code is available in the previous post titled "Calculating the Distance between Zip Codes Using the Google Maps API - Part 1." Note that the <div> tags have also been brought over for displaying the map and output.
Now let's initialize some variables to use throughout the program. We'll create an array for the origin zip code(s) and another for the destination(s). For the sake of simplicity, let's generate them manually.
var originArray = new Array('05001', '10002', '10457');
var destinationArray = new Array('05001', '10002', '10457');
A few extra variables will also be needed to store the program's output, the origin zip code currently being processed, and an array pointer to the destination zip code being processed.
var output = '<tr><th scope="col">From</th><th scope="col">To</th><th scope="col">Miles</th></tr>';
var currZipCode = '';
var currIndex = 0;
Next we'll take the arrays, figure out which comparisons to make, and calculate the distance between each origin and destination. However, the code needs to be written slightly different than what we may be used to since the Google Maps API uses asynchronous code. Instead of processing the zip codes with a loop, functions will be created to do the following:
- get next origin
- get next destination
- calculate mileage
- display the results
The Functions
The first function checks for the next origin zip code. If one exists, it stores the zip code, resets the pointer for the destination zip code array, and calls the function for the next destination zip code. Otherwise, if there are no more origin zip codes, the function to display the output is called.
//FUNCTION TO GET THE NEXT ORIGIN ZIP CODE
function getNextOrigin() {
//IF THERE ARE MORE ORIGIN ZIP CODES, GET THE NEXT ONE AND START THE COMPARISON PROCESS
if(originArray.length != 0) {
currZipCode = originArray.pop();
currIndex = 0;
getNextDestination();
//ELSE...WE'RE DONE, DISPLAY THE RESULTS
} else {
displayResults();
}
}
The next destination function checks if the pointer for the destination array is valid. We'll come back to the code for when it is. If the index is invalid, we've gone through all the destinations. So it's time to get another origin point.
//FUNCTION TO GET THE NEXT DESTINATION ZIP CODE
function getNextDestination() {
//IF THE INDEX FOR THE DESTINATION ZIP CODE ARRAY IS VALID, CONTINUE
if(currIndex < destinationArray.length) {
//...more code will be added here...//
//ELSE...GET THE NEXT ORIGIN ZIP CODE
} else {
getNextOrigin();
}
}
Now back to the part if the pointer is valid. If the index is pointing to a destination zip code that's different from the current origin point, call the function to calculate mileage. Otherwise, we can skip the destination zip code since we don't need to know how far a zip code is from itself. We'll update the pointer and get the next destination point.
//FUNCTION TO GET THE NEXT DESTINATION ZIP CODE
function getNextDestination() {
//IF THE INDEX FOR THE DESTINATION ZIP CODE ARRAY IS VALID, CONTINUE
if(currIndex < destinationArray.length) {
//IF CURRENT ORIGIN IS DIFFERENT THAN CURRENT DESTINATION, CALCULATE MILEAGE
if(currZipCode != destinationArray[currIndex]) {
calcMileage();
//ELSE...GET THE NEXT DESTINATION ZIP CODE
} else {
currIndex++;
getNextDestination();
}
//ELSE...GET THE NEXT ORIGIN ZIP CODE
} else {
getNextOrigin();
}
}
The function for calculating mileage is where the interactions with the Distance Matrix service happen. The service needs the current origin and destination zip codes and some information on how the results should be returned. In this example, we're looking for the distance to be measured in driving miles.
//FUNCTION WHICH CALLS THE DISTANCE MATRIX SERVICE TO CALCULATE MILEAGE
function calcMileage() {
var service = new google.maps.DistanceMatrixService();
service.getDistanceMatrix({
origins: [ currZipCode ],
destinations: [ destinationArray[currIndex] ],
travelMode: google.maps.TravelMode.DRIVING,
unitSystem: google.maps.UnitSystem.IMPERIAL
}, function(response, status) {
//...more code will be added here...//
});
}
The inline callback function gets the mileage between the two zip codes...or an error. The result is added to the output variable, the next destination pointer is updated, and the next destination function is called.
//FUNCTION WHICH CALLS THE DISTANCE MATRIX SERVICE TO CALCULATE MILEAGE
function calcMileage() {
var service = new google.maps.DistanceMatrixService();
service.getDistanceMatrix({
origins: [ currZipCode ],
destinations: [ destinationArray[currIndex] ],
travelMode: google.maps.TravelMode.DRIVING,
unitSystem: google.maps.UnitSystem.IMPERIAL
}, function(response, status) {
if(status == google.maps.DistanceMatrixStatus.OK) {
var tempDistance = response.rows[0].elements[0].distance.text;
} else {
var tempDistance = 'ERROR';
}
//STORE CURRENT OUTPUT AND GET THE NEXT DESTINATION
output += '<tr><td>' + currZipCode + '</td><td>' + destinationArray[currIndex] + '</td><td>' + tempDistance + '</td></tr>';
currIndex++;
getNextDestination();
});
}
The final function is fairly straight forward. It takes the output variable and places the value into the corresponding <div> tag.
//FUNCTION TO DISPLAY THE FINAL RESULTS
function displayResults() {
document.getElementById('zip_code_output').innerHTML = '<table cellpadding="5">' + output + '</table>';
}
The code is almost done. We just need to kick everything off by calling the function to get the first origin point.
//INITIALIZE THE ZIP CODE LOOKUP SCRIPT
getNextOrigin();
Final Code
Here's the stripped-down version of the code to show all the pieces put together. Note: you'll need to obtain a Google Maps API key which is freely available. Your API key should replace the "YOUR_API_KEY" value below.
<html>
<head>
<title>Distance Matrix Example #2</title>
<script type="text/javascript">
//FUNCTION THAT DOES MOST OF THE WORK
function initialize() {
//CONVERT THE MAP DIV TO A FULLY-FUNCTIONAL GOOGLE MAP
var mapOptions = {
zoom: 8,
center: new google.maps.LatLng(-34.397, 150.644),
mapTypeId: google.maps.MapTypeId.ROADMAP
}
var map = new google.maps.Map(document.getElementById("map_canvas"), mapOptions);
//INITIALIZE VARIABLES
var originArray = new Array('05001', '10002', '10457');
var destinationArray = new Array('05001', '10002', '10457');
var output = '<tr><th scope="col">From</th><th scope="col">To</th><th scope="col">Miles</th></tr>';
var currZipCode = '';
var currIndex = 0;
//FUNCTION TO GET THE NEXT ORIGIN ZIP CODE
function getNextOrigin() {
//IF THERE ARE MORE ORIGIN ZIP CODES, GET THE NEXT ONE AND START THE COMPARISON PROCESS
if(originArray.length != 0) {
currZipCode = originArray.pop();
currIndex = 0;
getNextDestination();
//ELSE...WE'RE DONE, DISPLAY THE RESULTS
} else {
displayResults();
}
}
//FUNCTION TO GET THE NEXT DESTINATION ZIP CODE
function getNextDestination() {
//IF THE INDEX FOR THE DESTINATION ZIP CODE ARRAY IS VALID, CONTINUE
if(currIndex < destinationArray.length) {
//IF CURRENT ORIGIN IS DIFFERENT THAN CURRENT DESTINATION, CALCULATE MILEAGE
if(currZipCode != destinationArray[currIndex]) {
calcMileage();
//ELSE...GET THE NEXT DESTINATION ZIP CODE
} else {
currIndex++;
getNextDestination();
}
//ELSE...GET THE NEXT ORIGIN ZIP CODE
} else {
getNextOrigin();
}
}
//FUNCTION WHICH CALLS THE DISTANCE MATRIX SERVICE TO CALCULATE MILEAGE
function calcMileage() {
var service = new google.maps.DistanceMatrixService();
service.getDistanceMatrix({
origins: [ currZipCode ],
destinations: [ destinationArray[currIndex] ],
travelMode: google.maps.TravelMode.DRIVING,
unitSystem: google.maps.UnitSystem.IMPERIAL
}, function(response, status) {
if(status == google.maps.DistanceMatrixStatus.OK) {
var tempDistance = response.rows[0].elements[0].distance.text;
} else {
var tempDistance = 'ERROR';
}
//STORE CURRENT OUTPUT AND GET THE NEXT DESTINATION
output += '<tr><td>' + currZipCode + '</td><td>' + destinationArray[currIndex] + '</td><td>' + tempDistance + '</td></tr>';
currIndex++;
getNextDestination();
});
}
//FUNCTION TO DISPLAY THE FINAL RESULTS
function displayResults() {
document.getElementById('zip_code_output').innerHTML = '<table cellpadding="5">' + output + '</table>';
}
//INITIALIZE THE ZIP CODE LOOKUP SCRIPT
getNextOrigin();
}
//FUNCTION TO LOAD THE GOOGLE MAPS API
function loadScript() {
var script = document.createElement("script");
script.type = "text/javascript";
script.src = "http://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&sensor=false&callback=initialize";
document.body.appendChild(script);
}
//START THE SCRIPT (AFTER THE PAGE LOADS)
window.onload = loadScript;
</script>
</head>
<body>
<div id="zip_code_output"></div>
<div id="map_canvas" style="width:650px; height:600px;"></div>
</body>
</html>
Example Output
The following is the output from the completed code. Note that the table slightly stylized to match the formatting of this blog.
From | To | Miles |
---|---|---|
10457 | 05001 | 258 mi |
10457 | 10002 | 13.1 mi |
10002 | 05001 | 266 mi |
10002 | 10457 | 13.4 mi |
05001 | 10002 | 272 mi |
05001 | 10457 | 261 mi |
Conclusion
With the custom code, we're no longer limited to the 25 origin and 25 destination points. The arrays can essentially be as large as needed. Of course, Google does have other limitations in place to prevent the service from being overused. However, the average program probably won't reach those limitations.
If you have any questions about the code mentioned above, feel free to post a comment below. After all, that was a lot of code. I'll do my best to provide an answer.
Related Posts
- Calculate Distance Between Zip Codes Part 2: Build the Search Engine
- Calculate Distance Between Zip Codes Part 1: Geocode Database Entries with the Google Maps API
- End PHP Scripts Gracefully After a Failed Database Connection
- Calculating the Distance between Zip Codes Using the Google Maps API – Part 1
5 Comments
@Shaik – My experiment with using the Google Maps API to calculate the distance between zip codes was placed on the back burner a while ago. So my knowledge of the API is a little rusty. Sorry I can't be of more help.
I have a excel with more than 3000 different origin and destination zipcodes. I want to calculate the distance between all these zipcodes. I want to automate it in excel using this api. can you please suggest how can we achieve this.
@cryo – As you mentioned, there doesn't seem to be a way to break down the miles traveled by state. Do you know if there's a way grab the exit and entry points for each state along the route? Having that data may get you closer to the desired response.
As for the other service providers (Bing, Yahoo!, MapQuest), I'm not as familiar with those APIs.
I would like to know if it is possible to get the total miles traveled (via road/interstate) in each state instead of the total miles only.
For example: From Chicago, IL to Atlanta, GA the total miles traveled in each state would be: IL=16 miles IN=284 miles KY=137 miles TN=152 miles GA=128 miles
From what I understand this is not possible in google maps api but I wanted to see if it is possible using anything else, Bing, YAhoo, Mapquest ???
Thanks for any help…
I could try this code this on my website, thank you
Leave a Comment