vis4.net

Hi, I'm Gregor, welcome to my blog where I mostly write about data visualization, cartography, colors, data journalism and some of my open source software projects.

Tutorial: Reading ESRI Shapefiles in ActionScript

This tutorial is the second part of a tutorial series about customized map projection in flash/actionscript. It shows how to import a shapefile into ActionScript via the SHP library by Edwin van Rijkom. [1 Reading Shapefiles in PHP](http://vis4.net/blog/2010/04/reading-esri-shapefiles-in-php), 2 Reading Shapefiles in ActionScript.

So, after Zachary Forest Johnson told me that he changed is mind about server-side reading of shapefiles, I decided to create another tutorial showing the client-side method using Edwin van Rijkom’s SHP library.

Step 1: Downloading the shapefiles

This is obviosly exactly the same as in the first tutorial: We start by downloading a shapefile from finder.geocommons.com which is a large portal for free map datasets. I decided to use the dataset World Countries Boundary File, World, 2002 because it includes not only information about the country boundaries but also some useful meta information like ISO codes etc. Here is a direct link to the zip-file containing the shapefiles. The zip-package contains three files, one shp-file containing all shape coordinates, one dbf-file containing all shape meta data and one shx-file containing the shape index file. You find more information on the structure shapefiles in the wikipedia.

Step 2: Importing the shapefiles into flash

At first we have to load the shapefile data into the flash movie. I chose to do this using the excellent BulkLoader library, but you can also do this by hand by using the native URLLoader class instead.

var b: BulkLoader = new BulkLoader(BulkLoader.getUniqueName());
b.add('5961.dbf', { id: 'dbf', type: 'binary' });
b.add('5961.shp', { id: 'shp', type: 'binary' });
b.add('5961.shx', { id: 'shx', type: 'binary' });
b.addEventListener(BulkProgressEvent.COMPLETE, run);
b.start();

This is the part where Edwin van Rijkom’s SHP library comes into the game. I first tried to extract the shape records using the class ShpTools:

private function run(e:BulkProgressEvent):void
{
    var shp:ByteArray, bl:BulkLoader = e.target as BulkLoader
    shp = bl.getBinary('shp');
    trace(ShpTools.readRecords(shp));
}

This attempt resulted in an exception. After a while I figured out that one has to create an instance of ShpHeader before the parsing of the records works.

private function run(e:BulkProgressEvent):void
{
    var shp:ByteArray, bl:BulkLoader = e.target as BulkLoader
    shp = bl.getBinary('shp');
    // we must create a shape header first!
    var head:ShpHeader = new ShpHeader(shp);
    trace(ShpTools.readRecords(shp));
}

Now we got an array full of ShpRecord instances. Since our shapefile contains only polygons we can access the information by casting the ShpObject instances to ShpPolygon.

var records:Array = ShpTools.readRecords(shp_raw);
for each (var record:ShpRecord in records) {
    if (record.shapeType == ShpType.SHAPE_POLYGON) {
        var poly:ShpPolygon = record.shape as ShpPolygon;
        // now we can access the array poly.rings which contains
        //  all coordinates as ShpPoint instances
    }
}

Step 3: Reading the meta information

The access to the shape meta information (which are stored in the dbf file) can be done using the class DbfTools. But just to be sure I created a DbfHeader instance at first.

// bl is our BulkLoader instance from the code examples above
var dbf: ByteArray = bl.getBinary('dbf');
var dbfHead: DbfHeader = new DbfHeader(dbf);

We can allocate the right dbf record to a shape record by using the number property. We have to decrease it by one since the getRecord method starts the counting by zero while the counting of number starts by one (seems to be a little inconsistent at this point).

var records:Array = ShpTools.readRecords(shp);
for each (var rec:ShpRecord in records) {
    if (rec.shapeType == ShpType.SHAPE_POLYGON) {
        var poly:ShpPolygon = rec.shape as ShpPolygon;

        // accessing dbf information using the record index, decreased by one
        var dbfRec:DbfRecord = DbfTools.getRecord(dbf, dbfHead, rec.number-1);
        var meta:Dictionary = dbfRec.values;

        var coords:String = poly.rings[0][0].x + ',' +  poly.rings[0][0].y + ';'
            + poly.rings[0][1].x + ',' + poly.rings[0][1].y + '...';
        trace(meta.ISO_3_CODE, meta.ISO_2_CODE, meta.NAME, coords);
    }
}

So that’s it! The trace output will look something like this:

AFG	AF	Afghanistan	65.6272,37.3331;65.6469,37.4588;...
ALB	AL	Albania		19.3973,42.3170;19.4697,42.3999;...
DZA	DZ	Algeria		-1.2538,32.2147;-1.25,32.3269;...
AND	AD	Andorra		1.7109,42.4734;1.5333,42.4361;...
AGO	AO	Angola		12.0100,-5.0206;12.1663,-4.8958;...

You can again download a zip file containing the full actionscript class and the shapefiles used in this tutorial.

In the next tutorial I’ll show how to project and display a static map out of these coordinates.

Comments

lionlancer (Jun 03, 2011)

Thanks a lot! I was looking all over the web for this! I have absolutely no idea on how to use the library. ^__^’

Great work!

suresh (Feb 24, 2012)

how to display a static map out of these coordinates?

Alex (Mar 07, 2012)

Hi!

Great job, very useful :) Only one problem, I couldn’t find the DbfTools and DbfHeader classes in the lib… Do you know what happend to it? If you have it, could you post it on your blog?

Cheers,

Alex

Alex (Mar 07, 2012)

OK, I found it, I forgot to checkout it from SVN… Thanks again!