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

5 Comments

  • #1 M Datalizer on 11.07.12 at 3:51 pm

    I could try this code this on my website, thank you

  • #2 cyro on 03.07.13 at 3:39 pm

    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…

  • #3 Patrick Nichols on 03.08.13 at 6:08 am

    @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.

  • #4 Shaik on 02.25.14 at 11:54 pm

    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.

  • #5 Patrick Nichols on 02.26.14 at 10:53 am

    @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.

Leave a Comment