Simple shapefile drawing in ActionScript 3

Shapefile + magic = map in Flash!

Recently I’ve heard two friends independently inquire about some sort of basic guide for loading and drawing a shapefile in Flash. The only real tutorial/example I can recall is here, dealing with Google Maps. But these guys are looking for something more bare-bones. Being a regular user of Edwin van Rijkom‘s invaluable code libraries for reading shapefiles, and usually forgetting the process myself, I thought it would be a good idea to put together a very simple set of AS3 classes that load a shapefile and throw a map on screen.

So to get those jerks off my back, I wrote a little thing called ShpMap, which supplements van Rijkom’s classes by loading and drawing a shapefile. It’s nothing fancier than that. Sometimes all you need is to get your base map on screen. (Update: just to round it out a little more, I’ve added basic loading and parsing of a shapefile’s accompanying DBF file, which contains attribute data. This also uses classes by van Rijkom.)

I hope that this class (and the several associated classes) can both be directly usable for some projects and serve as a basic guide to using van Rijkom’s classes to load shapefiles.

Dig it:

  • An example that loads and displays a US states shapefile (and then puts a square on my house and colors the state of Wisconsin green). View the source code here.
  • Download the source code. (My classes plus van Rijkom’s, as well as a demo US States shapefile.)

Tagged ,


  1. Hi — thanks for helping out with these code libraries. I know they’re incredibly valuable, but I can’t seem to wrap my head around the entire process.

    What I’d really like is a way to us AS3 to scan a shapefile for a particular record, and draw that one with particular attributes. Most of the examples using the libraries to date involve drawing all records from the shapefile with the same format.

    Here’s an example of what I’d like to do with a set of county maps. I have data of some type for each county, and I’d like to shade each county based on that data, or only show certain counties.

    The process would work something like this, I think:

    1. Open the shapefile
    2. Find the corresponding county (would have to be a name or id number)
    3. Return a graphics instance of that county with line and fill settings that correspond to my data
    4. Add that graphics instance to a MovieClip or Sprite
    5. Add that MovieClip as an GroundOverlay on a Google Map.

    I’m getting lost in the classes, though. Any chance you could outline a general path for that?

    Thanks much!

    Michael Corey
    22 July 2009 @ 12:09pm

  2. Michael,

    The usual way to do anything data-related with the shapefile is of course with the corresponding DBF file, and it’s not too terribly complicated. I didn’t bother to include any of it in this example, but Edwin van Rijkom’s libraries also include classes for loading DBF files.

    From what I understand, the only link between the DBF and SHP is that the records are in the same order; the shapefile contains no information other than the geometry, and the DBF doesn’t contain any information on which geometry belongs to a data record.

    So, if you were to start from my ShpMap class (not necessarily the best option, but it’d work), I think the steps would be something like this:

    1. Have the ShpMap class load the DBF records in addition to the shapefile records. I think the loading works in a similar manner, but I would have to refresh my memory on that.
    2. In the resulting array of data records, each item belongs with the shape record in the same position in the “features” array that was created from the shapefile.
    3. To find a specific county, look for the correct name (or other identifier) in the data array; its index in the array will be the same index of the correct shape in the features array. Or to do it more nicely, of course, you add some sort of “data” property to my ShpFeature class and go through the data records first and actually attach each one to the correct feature.
    4. The ShpFeature (PointFeature, PolylineFeature, or PolygonFeature) is a Sprite, so you can color it as desired according to the data, and/or simply return it for outside use.
    5. I don’t recall how the Google Maps overlay works, but if this came from my classes there might have to be some sort of position adjustment. I have all the features with their origins at (0,0) lat/lon regardless of the coordinates of the actual shape.

    If for some reason you don’t have that DBF, it all can be less certain because you won’t necessarily know which shape is which. Chances are, perhaps, the shape records were created in some sort of logical order (such as alphabetically by county name), but that information isn’t in the shapefile.

    I’m sure trying to describe all that doesn’t help a whole lot, but maybe it’s worth something. I should add some basic DBF loading to these files, actually, and will try to get around to that in the next couple of days. That would at least take care of getting the geometry and data in the same place.

    Looking at some of your work, I don’t know that it’s quite appropriate for you, but I might as well mention that GeoCommons (specifically Maker) can facilitate thematic web mapping. As for more customized mapping in Flash, in the coming months my Axis Maps pals and I hope to release some tools as part of our indiemapper project.

    Oof, long comment! I’ll see if I can provide something clearer via code soon.

    Andy Woodruff
    22 July 2009 @ 1:12pm

  3. Thanks very much for the quick reply — that is helpful. (Of course, if you did actually post some new code as you mentioned, that would be bonus, but I wouldn’t expect you to.)

    My background is almost exclusively from the Web side, so shapefiles, though second-nature to most GIS people, are pretty unknown for me. (Also, I’m a Mac user, so that makes it harder as well.)

    I’m very interested in the indiemapper project (as well as Axis Maps — looks like right up my alley).

    There’s still only a pretty small group of people doing interactive maps in the journalism world, and like a lot of things we do, it’s a very “get stuff done fast and dirty” world, for good and for ill. We’re all bridging the journalism, programming and mapping worlds, and the solutions vary quite widely. Great to find some experts on the cartography side who are doing interactive stuff with mainstream Web tools!

    Michael Corey
    22 July 2009 @ 1:46pm

  4. All righty, I have updated this to include some basic stuff on the DBF end. Michael (and anyone), I hope this can provide a bit of insight while still keeping things simple and generic. I have it loading the DBF, attaching each data record to its corresponding shape record, and demonstrating a quick way to retrieve a particular shape by searching for an attribute key and value.

    I didn’t test these additions too hard, so running into an error isn’t out of the question. It seems to work for my example, though.

    Andy Woodruff
    27 July 2009 @ 11:22am

  5. Thanks much, Andy! I’ll try them out.

    Michael Corey
    29 July 2009 @ 1:04pm

  6. Hello again:

    I’ve modified your source a bit and have a polygon successfully added to a Google map as a GGroundOverlay (beside the point at the moment). But each state seems to be a bit off to the southeast. Perhaps a projection issue (though that doesn’t quite make sense). Do you remember what projection your shapefile is in?

    Will try to post code soon if I can’t figure it out.

    Thanks a ton — this got me past a wall I’ve been trying to break through for months.

    Michael Corey
    29 July 2009 @ 5:04pm

  7. Indeed there would be a projection issue if you were to just drop one of these polygons onto a Google map, as the shapefile data are just in a latitude/longitude projection (plate carrée, where latitude and longitude are simply y and x), and Google maps are in the Mercator projection. But the difference should only be on the north-south axis, not southeast. Could also have something to do with my code.

    Anyway, I’d think you would at least have to project all the points from the shapefile to Mercator, which is simply a matter of plugging each one into the projection formula.

    Andy Woodruff
    30 July 2009 @ 9:23am

  8. Apparently Google Maps uses not just Mercator, but an odd one. Spherical Mercator (EPSG:900913 or EPSG:3785). Am trying to find the correct formula, but haven’t found it yet.

    I tried using this as a custom CRS in QGIS, but it said it’s not valid: +proj=merc +latts=0 +lon0=0 +k=1.0 +x0=0 +y0=0+a=6378137.0 +b=6378137.0 +units=m

    Michael Corey
    30 July 2009 @ 10:27am

  9. In theory I’ve projected correctly now using this:

    +proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +no_defs

    But I’m still off. I tried adjusting the ScaleFactor in, and this seems to significantly affect the dimensions of each polygon. I’m also wondering if I have a precision issue, as the lat-long coordinates I’m ending up with are only shown to 2 decimal places.

    Here’s the code for my main .FLA. I believe the only thing I changed in the other .as files was to make geometry public in so I could grab it in the main app. I’m using the geometry as a bounding box — not sure how precise that is or if there’s a better way.

    import com.corey.shp.ShpFeature;
    import com.corey.shp.ShpMap;
    import com.corey.shp.RegisterGenericMap;


    var map1:RegisterGenericMap = new RegisterGenericMap(675,450);

    map1.x = 0;
    map1.y = 0;

    //var theMapLoaded:Boolean = false;

    function onMapReady(event:MapEvent):void {
    trace(“The Google map is ready”);
    map1.mymap.setCenter( new LatLng(44.40, -89.91), 4);

    var myZoomControlOptions:ZoomControlOptions = new ZoomControlOptions({
    hasScrollTrack: true,
    position: new ControlPosition(ControlPosition.ANCHOR_TOP_RIGHT, 15, 40)

    var myZoomControl = new ZoomControl(myZoomControlOptions);

    map1.mymap.addControl( new MapTypeControl() );


    * An example of drawing a simple map from a shapefile using my ShpMap class and Edwin van Rijkom’s library.
    * @author Andy Woodruff (
    var map : ShpMap;

    function ShapefileExample()
    map = new ShpMap(“data/IowaCounties2.shp”,”data/IowaCounties2.dbf”);
    map.addEventListener(“map loaded”,onMapLoaded);
    map.addEventListener(“attributes loaded”,onAttributesLoaded);

    // Need to wait for the map to finish loading/drawing before it can be resized correctly.
    function onMapLoaded(event:Event):void
    map.scaleX = map.scaleY = map.width > map.height ? stage.stageWidth/map.width : stage.stageHeight/map.height;

    // just for fun, add a marker to somewhere around my house!
    addMarkerAt( 42.36,-71.11 );
    trace(“the map is loaded”);

    // To demonstrate retrieving a particular feature and doing something to it. This colors Wisconsin green.
    function onAttributesLoaded(event:Event):void

    function drawState(whichstate:String) {
    var f : ShpFeature = map.getFeatureByAttribute(“NAME00”,whichstate);
    if (f != null){

    var stateclip:MovieClip = new MovieClip(); = whichstate;

    var cTrans : ColorTransform = new ColorTransform();
    cTrans.color = 0x009933;
    f.transform.colorTransform = cTrans;
    f.x = 0;
    f.y = 0;
    f.alpha = 0.5;

    trace(“I found ” + whichstate + “!”);
    //(x=-92.85, y=-46.95, w=5.949999999999989, h=4.5)

    var stateBounds:Object = new Object();
    stateBounds.swLat = Math.abs(f.bounds.y)-f.bounds.height;
    stateBounds.swLong = f.bounds.x;
    stateBounds.neLat = Math.abs(f.bounds.y);
    stateBounds.neLong = f.bounds.x + f.bounds.width;

    trace(“Bounding box of ” + whichstate + ” is SW:” + stateBounds.swLat + “, ” + stateBounds.swLong + ” NE: ” + stateBounds.neLat + “, ” + stateBounds.neLong);


    var stateoverlay:GroundOverlay = new GroundOverlay(stateclip,new LatLngBounds(new LatLng(stateBounds.swLat, stateBounds.swLong), new LatLng(stateBounds.neLat,stateBounds.neLong)));


    // Super basic method for adding a green box at a specified lat/long.
    function addMarkerAt( lat : Number, lon : Number ) : void
    var box : Sprite = new Sprite();,0,1,false,”none”);;,-.5,1,1);;


    Michael Corey
    30 July 2009 @ 11:04am

  10. Here’s a working example:

    Wisconsin and Iowa plot fairly close, but still off as you zoom in. Alaska, in contrast, is quite a bit off. I tried with a set of state borders projected in what I believe is the right way, and it doesn’t seem to change it much if at all. Of course it’s possible I’m not doing the projection correctly.

    Thanks once again!

    Michael Corey
    30 July 2009 @ 11:45am

  11. Hmmm. Not sure I have any brilliant suggestions. I was going to say that my scaleFactor thing might be messing with the precision, as I have noticed some issues with that under certain circumstances. However, if that’s the case I would expect that the polygons would be off in both the x and y directions. Looks like it’s just off on the y axis in your example. As such the best I can guess is that maybe there’s still something up with the projection. It looks a bit like things I’ve seen in the past when trying to fit something to a Mercator projection.

    Andy Woodruff
    30 July 2009 @ 3:17pm

  12. Perhaps then I should try to use a conversion formula where you suggest in Unfortunately this is the type of thing I’m clueless on — any idea what the formula would be to convert the points to Spherical Mercator?

    Or to go another direction, are you using the van Rijkom libraries to overlay the counties on your Ohio piano map? How are you making that line up?

    Michael Corey
    30 July 2009 @ 3:40pm

  13. Sure, the formula is simply the one you would find on Wikipedia or some other sites. (The “Spherical” part, as far as I know, just indicates that it assumes a spherical Earth, which is sort of the default case.) In generic code:

    y = Math.log( Math.tan(lat) + 1/Math.cos(lat) );

    Where that latitude is in radians, and the result is something radians-ish. That just means you’d either need to convert the y back, or also convert the longitude to radians. (Longitude/x-axis isn’t affected by the Mercator projection.)

    As for that Ohio map, the county map isn’t actually drawn dynamically. I manually imported graphics into Flash after bringing a shapefile into indieprojector and exporting to SVG. It’s basically just a MovieClip floating separately on top of the Google map, with some eyeballing and nudging to get it in approximately the right spot.

    Andy Woodruff
    30 July 2009 @ 4:30pm

  14. Hmm, that seems to make things worse, if I’m doing it right:

    Here’s the conversion I ran:

    geometry = (record.shape as ShpPolygon).rings;
    /* If a differen map projection were desired, then here
    we could run each point in geometry through a
    transformation formula. */

    //convert to Mercator
    for each ( var ring:Array in geometry ) {
    //convert lat to radians
    for ( var m : int = 0; m < ring.length; m ++ ) {
    ring[m].y = ring[m].y*(Math.PI/180);
    ring[m].y = Math.log( Math.tan(ring[m].y) + 1/Math.cos(ring[m].y) );
    //convert back to degrees
    ring[m].y = ring[m].y*(180/Math.PI);
    //y = Math.log( Math.tan(lat) + 1/Math.cos(lat) );


    Michael Corey
    30 July 2009 @ 5:01pm

  15. I would guess that the problem there has something to do with positioning and scaling the states on the Google map based on those projected coordinates, when the Google API still wants to know everything in the original latitude and longitude. The projection is necessary to do in order to get the shapes correct once they are in the right position and have the right scale, but you’d still need to know the lat/lon boundaries for working with Google Maps.

    At least, that’s what it looks like…

    Andy Woodruff
    31 July 2009 @ 2:56pm

  16. Yep, I finally cracked it this afternoon. As you say, the projection was necessary, but then getting the boundaries for the rectangular Google Maps overlay from the bounding box of the newly projected coordinates was bad.

    The scale factor weirdness I was getting was due to the loss of precision inherent in getBounds();. When I collected them earlier in the process, before the Mercator conversion and scaling down, it’s precise.

    Thanks again, I’m sure I will be using this quite a bit.

    Michael Corey
    31 July 2009 @ 4:23pm

  17. Just Hopped In To Say Biggest Thanks :)

    This Stuff Helped Me Alot.

    Thankie 😉

    8 September 2009 @ 1:41am

  18. First of all, thank you for posting this code. Being able to read shape files into Flash is preventing me from having to switch to Silverlight. I am trying to do something REALLY simple with all of this, import the shape file and dbf into Flash, create a movie clip for each County and give it a name. Importing the shapes and data wasn’t a problem, but as soon as I made them into movie clips it set the x and y coordinates to 0. Can anyone help me out?


    16 November 2009 @ 1:35pm

  19. Alycia,

    Without bothering just yet to look at the code to remind myself, I believe what’s going on is that in the code I posted, every shape actually is at (0,0) but the graphics are drawn within that shape at wherever the coordinates actually are. In other words, the x/y origin of the movie clip is not at the upper left corner of the shape but rather always at (0,0). This was done for some convenience (or perhaps laziness) in creating the shapes. You should be able to worth with the getBounds() method of a movie clip to get its actual coordinates and go from there.

    But I may be a) misinterpreting your problem and/or b) misremembering the code. Will look over it when I get a chance!

    Andy Woodruff
    17 November 2009 @ 10:07am

  20. Hi Andy,

    Many thanks for these classes, they are a tremendous help. To avoid reprojecting to Albers point-by-point in AS3, I first reprojected your States shapefile using MapWindow (I also tried QGIS). The projection works and will draw correctly on Matt Bloch’s MapShaper, but comes out garbled (or sometimes not at all) when I try to use your classes. Have you seen anything like this? Any help would be greatly appreciated.

    Jeremy Usher
    30 January 2010 @ 12:09pm

  21. Jeremy,

    I haven’t tried projected shapefiles with this particular code, but with similar classes in other projects I have indeed noticed problems, usually with the shapes not showing up at all. Maybe it has something to do with the crazy large or small numbers that the coordinates turn out to be? In my ShpFeature class there is a scaleFactor variable; my only suggestion at the moment is to try fiddling with that to see if it makes a difference. That number multiplies the coordinates and perhaps can bring the numbers into some range that Flash is happy with, if that even is the problem.

    Andy Woodruff
    30 January 2010 @ 1:16pm

  22. Hi, i´m actually working at a same problem. Including shapefiles into an existing flex3 project.

    Can someone show me the way, how to include this example into my project? I have no idea how to display this example or how to test it. Thank you

    Markus Wagner
    3 February 2010 @ 8:03am

  23. Good tutorial, thank you for sharing.

    3 February 2010 @ 11:46am

  24. Markus, are you working with Flex Builder? If so, you can simply test this example by creating a new ActionScript project, naming it ShapefileExample, and copying the contents of the zip file here into the src folder. That would allow you to publish the class, and hopefully you can go from there to include this code in your existing project. You would want to copy or import the classes to your project, and look at ShapefileExample for an example of how to use them.

    Andy Woodruff
    5 February 2010 @ 10:01am

  25. Thx a lot Andy !

    Markus Wagner
    8 February 2010 @ 1:33am

  26. Hi Andy,

    Your advice regarding map projections was right on target – the enormous numbers were killing the system. Thanks for the help. You can view the project that I made with this @ (I actually didn’t end up projecting this one as I discovered the solution late in the game).

    Jeremy Usher
    22 March 2010 @ 3:28pm

  27. If you want the freedom of chosing between over sixty map projections, you can use as3-proj, which is actually an object oriented port of the PROJ.4 projection library into actionscript3.

    you can download the as3-proj library from here:

    you can see a working example and some documentation in my related blog post:


    22 April 2010 @ 2:32am

  28. Its working fine for STATES.shp but not working some shape file I have. So What might be the problem with my shape files.

    Pls… looking forward for your answer

    21 July 2010 @ 1:50am

  29. Rasmikant, if your shapefile doesn’t draw, it may be because of the projection. When the coordinates are in meters, Flash sometimes doesn’t handle the large numbers well. In, look for the line:

    protected var scaleFactor : Number = 500;

    Instead of 500 try something much lower, perhaps simply 1. That has usually been the solution for me. Otherwise I’m not certain what the problem might be.

    Andy Woodruff
    21 July 2010 @ 10:29am

  30. Thank you Andy. You saved me some hassle.

    Is there a way to add a roll over event listener to each state?

    When I do click it works fine by state, but roll over includes the entire map.

    map.addEventListener(MouseEvent.CLICK, clickedMe);

    Doesn’t work
    map.addEventListener(MouseEvent.ROLL_OVER, rOver);

    And access each one’s properties in a loop. Is this through map (ShpMap class) or f (ShpFeature class)?

    27 August 2010 @ 9:07pm

  31. I am trying to convert your ShapefileExample into a component that I can use to display maps and then extend it.

    Being lazy, I thought I’d ask to see if you have already done this?

    23 January 2011 @ 2:13pm

  32. I guess I wasn’t that lazy, I have a working component. Would you,like what I came up with?

    23 January 2011 @ 8:43pm

  33. I’ve gotten to the point Omar got to, and could use some help.

    I would like the ability to tell when I’ve either rolled over or clicked on a region of the map.

    It would be nice if I could define an attribute of a feature that was returned on either event. Basically I would tell it to return State_name, and when I clicked on an area it might return “Iowa.”

    I will continue playing. I have a component that I can send the name of the shape & dbf file, and it creates a canvas with the map sized on it. I also implemented a generic colorchanger for a given feature, and a method that will return all of the features for a given attribute.

    Interactivity is my next goal.

    23 January 2011 @ 9:23pm

  34. Well, I probably didn’t do it the most efficient, but, I have the interactivity I wanted. I created a method that loops through each of the “features” for a particular “attribute” and adds mouse over, mouse out and click events. When the attribute changes I remove all of those eventlisteners and add a new set.

    I also changed the way the map draws to add a parent and glow filter for each feature, so that I can control the border, when changing the color.

    24 January 2011 @ 1:40am

  35. Ack. Paul, I’m sorry I never replied to your comments. These code posts have kind of sunk to the bottom of the pile lately. Glad to hear you got some things working, anyway.

    I do have at my disposal a lot of code for working with shapefiles and attributes, with interactivity and all, but I’m not entirely at liberty to disseminate it as it’s part of work done for clients and so forth. It’s also so wrapped up in a complicated system that it’s no simple matter to release useful bits of code. But hopefully things will evolve to a point where it’s possible to post some classes that can easily be used outside of my company’s particular projects.

    Andy Woodruff
    13 February 2011 @ 11:27pm

  36. Andy, I sent an e-mail to your gmail account, with what I have done to date, as well as a couple of questions. Is that the best way to contact you?

    23 February 2011 @ 12:22pm

  37. Hi Andy,

    Thanx for your effort on reading shapefiles into Flash. Im trying to work out a way to simplify shapes. Found some stuff:
    Gregor Aisch >>
    MapShaper >>

    I get a bitt lost when I try to combine your code with Gregor’s code. Do you have any experience simplifying shapes?

    Hope to hear from you. Thanx.

    4 October 2011 @ 9:40am

  38. Hi,

    First thank you for example. Very nice!

    I need to change color border, but you use:
    var cTrans : ColorTransform = new ColorTransform();
    cTrans.color = 0×009933;
    f.transform.colorTransform = cTrans;

    This case chage all shape color, but i need to change only border(or lineStyle). Who do i do?

    Thank you!

    9 October 2011 @ 11:42pm

  39. Hi Andy,

    This is a really nice sample. I was wondering if there is a way to know what my lat/long is based on my mouse x,y? For instance, if I had an ENTER_FRAME listener, could I convert the mouse x,y into a lat/long? I couldn’t find any function that does the math, converting shape file points into current x,y. I know there must be, because I can resize the map dynamically and the map still knows accurate lat/long. Any help would be greatly appreciated.



    16 September 2013 @ 1:41pm

  40. Hi Andy,

    could you please give an example of how we can modify the script to have Miller projection? or mercator projection?

    Many thanks

    18 October 2013 @ 1:26pm