Plotting Zip-Code Boundaries using ASP.Net AJAX and Microsoft Virtual Earth
During a recent project, I had the opportunity to play around with the Virtual Earth Map Control from Microsoft (http://dev.live.com/virtualearth/sdk/). The goal of the project was to display zip codes by outlining its boundary. In the end we decided to go a different route, but I thought I would share the prototype (~200 lines of code including markup).
The sample app is an asp.net web page with a drop down list that allows the user to select the zip-code they want shaded. When the search button is clicked, I make a webservice call to the ZipCodeSearch webservice (using ASP.Net AJAX), find the points that make up the latitude/longitudes for the provided zip-code, then hand these coordinates off the the Virtual Earth map control so it can plot them for me.
Download code | View live demo
[Update 10/11/2007]: If you are looking for the zip code data set I used for this post, you can read how to get it here. Also, Darrin Clement provided the following comment that is worth reading:
Everyone should note that the "ZIP Code" data provided by the census bureau, and referenced by a few people here, is NOT really ZIP Code data - it is ZCTA data. The difference is explained here:
http://www.maponics.com/GIS_Map_Data/ZIP_Code_and_Carrier_Route_GIS/ZCTAs_vs_ZIP_Code_Data/zctas_vs_zip_code_data.html
Also, here some of the sample code. Markup for the Default.aspx page (there is no code-behind required)
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"> <title>Untitled Page</title> <script src="http://dev.virtualearth.net/mapcontrol/v4/mapcontrol.js"></script> <script> var map; function LoadMap() { map = new VEMap('myMap'); map.LoadMap(); } </script> </head> <body onload="LoadMap();"> <form id="form" runat="server"> <asp:ScriptManager runat="server" ID="scriptManager"> <Services> <asp:ServiceReference Path="ZipCodeService.asmx" /> </Services> <Scripts> <asp:ScriptReference Path="js/ZipCode.js" /> </Scripts> </asp:ScriptManager> <select id="zipCodes"> <option value="32224" selected="selected">Jacksonville FL - 32224</option> <option value="32246">Jacksonville FL - 32246</option> <option value="58103">Fargo ND - 58103</option> <option value="58104">Fargo ND - 58104</option> </select> <input type="button" value="Search" onclick="FindZipCodeInfo(zipCodes.value); return false;" /> <div id="myMap" style="position:relative;width:600px;height:400px;" /> </form> </body> </html>
Here is the java script client ...
// Call the Web service method to get the lat/longs function FindZipCodeInfo(zipCode) { // Call the Web service method to get the lat/longs ZipCodeService.FindZipCodeInfo(zipCode, SucceededCallback, FailedCallback); } // Display any errors that occur function FailedCallback(result) { var message = error.get_message(); alert('An unhandled exception has occurred:\n' + message); } // This is the callback function that // processes the value returned by the Web service. function SucceededCallback(result) { var points = result; if(points.length > 0) { var latLongTokens = points.split('|'); var veLatLongs = new Array(latLongTokens.length - 1); var centerLatLong; for(index = 0; index < latLongTokens.length; index++) { // format= {0},{1}| var latitude = latLongTokens[index].split(',')[0]; var longitude = latLongTokens[index].split(',')[1]; if(index == 0) { // center point of the zipcode centerLatLong = new VELatLong(latitude, longitude); } else { // build the points array from the string veLatLongs[index - 1] = new VELatLong(latitude, longitude); } } var poly = new VEPolygon('polygon', veLatLongs, new VEColor(0,0,255,.2), new VEColor(0,0,255,1), 1); // clear any existing polygons map.DeleteAllPolygons(); // add our new polygon map.AddPolygon(poly); // set the view to these points map.SetMapView(veLatLongs); } } if (typeof(Sys) !== "undefined") Sys.Application.notifyScriptLoaded();
And finally, here is the webservice ...
Comments
If you don't mind, what root did you wind up going?
Posted by: Michael De Lorenzo | May 17, 2007 01:14 PM
thanks for the code... polygons over maps are always fun, :-)
Posted by: Stuart Allen | May 17, 2007 02:44 PM
Excellent sample!
Posted by: Denny Ferrassoli | May 17, 2007 02:58 PM
How to find out the longitude and latitude info for all zipcodes for this? I tried few sites like http://www.census.gov/tiger/tms/gazetteer/zcta5.txt and i find that there is only one longitude and latitude value for each zip code! Can you throw some light on this?
..Prasanth
Posted by: Prasanth | May 18, 2007 12:49 AM
Zip code boundaries are available from the census bureau at: http://www.census.gov/geo/www/cob/z52000.html. Check out the ASCII files. Each state has 2. One associates an index number with the zip code. The other has the boundary coordinates by index number. The first set of coordinates with the index number is the centroid of the zip code, I believe.
Posted by: Walt Cygan | May 18, 2007 10:38 AM
Hi,
How can I map map zipcodes with longitude and latitude .I need to map Us zip codes in google map.
Thanks and regards
Posted by: Venkat Rao | June 5, 2007 12:42 AM
How or from where did you find the latitude and longitude for 32224, 32246 etc.
Help needed
Posted by: Wahid | June 16, 2007 03:36 AM
// Uses PHP to query a website which gets latitude and longitude info from Google Maps Geocode; without needed an API code
$zip = 94043; // your input zipcode; but if you want to do an entire address, get the possible inputs from the queried website
$site = file_get_contents('http://geocoder.ca/?postal='.$zip, false, NULL, 1000, 1000); // get a large chunk of the output string that will contain the coordinates
$goods = strstr($site, 'GPoint('); // cut off the first part up until the coordinates are provided
$end = strpos($goods, ')'); // the ending parenthesis of the coordinate string
$cords = substr($goods, 7, $end - 7); // returns string with only the coordinates as 'latitude, longitude' (can stop here if string wanted)
$array = explode(', ',$cords); // convert string into array(0 => $latitude, 1 => $longitude)
print_r($array); // output the array to verify
Posted by: friend | September 14, 2007 01:26 PM
Zipcode Finder is a comprehensive tool to find the zip code of any USA city/state. Also, users can enter their zip code to find out the cities or zip codes within a given distance from their zip code.
Posted by: Zip Code Finder | September 25, 2007 01:32 AM
Everyone should note that the "ZIP Code" data provided by the census bureau, and referenced by a few people here, is NOT really ZIP Code data - it is ZCTA data. The difference is explained here:
http://www.maponics.com/GIS_Map_Data/ZIP_Code_and_Carrier_Route_GIS/ZCTAs_vs_ZIP_Code_Data/zctas_vs_zip_code_data.html
Posted by: Darrin Clement | October 11, 2007 09:19 AM
there is no code for asp.net why?
Posted by: lungile | October 12, 2007 04:52 AM
Great Blog
Great sample.
Posted by: ASP.NET applications | October 24, 2007 07:04 AM
I like your tool! We do something very similar using MapInfo, however we do not have an online viewer for it yet. I was looking into this program and was wondering how you would go about expanding this to offer EVERY zipcode? There is roughly 40,000 zipcodes in the U.S. and if each zipcode had (at a minimum) 6 boundaries, you are looking at 240,000+ records. How would you handle that data so a user could select and area (say a city) and it would plot all of the zipcodes within a certain radius?
Posted by: Jeff Lewis | October 30, 2007 08:48 AM
great tool ¡¡, to get a zip code in a fancy way ... really nice ajax app
Posted by: Arturo | December 7, 2007 03:40 PM
please show me zip code for albama, united states. thanks.
Posted by: tochukwu okorie | April 9, 2008 06:36 AM