Wednesday, March 10, 2010
State of the Coast
So after 7 months we have finally put out the State of the Coast website.
I created 13 visualizations for it, using flex and a highly modified version of the
esri flex api.
Here is a zip file of the visualizations.
Friday, May 29, 2009
Direct use of Polygon Shape File in Layer for ESRI
So I went to the Flex 360 Conference and saw some great presentations.
But the two I liked the most were the ESRI mapping session by Mansour
Raad and the Array's one by Michael Labriola. Mansour talked about
building a custom layer that used sprites for the graphics and a spatial
index. Then in the Array's session Michael talked about how to improve
performance by using byte array's and vectors. So I combined both and
have a custom shapefile layer that never converts the data from the
raw byte array and I use the spatial index to speed the draw times also.
It needs some work still but it works pretty well already and is pretty
easy. So here is the code and since I am using vectors you will need flash player 10.
Tuesday, April 14, 2009
Function Pointers to parse XML/KML
So I wrote a XML Parser for KML. I decided to try doing it using
function poiters because of the results of earlier testing I had done.
In the test the function pointers were faster as both the number
of possible xml tags increased and the total number of tags increased.
You also end up with generic functions that do most of your work (ie
parseInt, parseString, parseHexNumber and so on) which makes the code
much more extensible.
The way this code works requires some up front work in the constructor.
First we have to create the function pointers object.
As you can see the kml object has three possible children: Document, Folder, and Placemark. Each of these have a func(Function) assigned to them. So if we are in the kml tag and find a Document the this.parseXML function will be executed. This parseXML function looks like this:
If you notice there are two other variables in the this._validParseKids object, attrName and attrType. Here is an example of both:
So the attrName is the name of the object that any returned values from the function that was called may return. The attrType is only used to say that there will be multiple objects that return data to the given attrName. So for example the when in the ExtendedData tag you can have an unlimited number of Data tags that are to be stored in an array. As a final example here are a couple of the basic parse functions:
this._validParseKids.kml = { Document : { func: this.parseXML } , Folder : { func : this.parseFolder } , Placemark : { func : this.parsePlacemark } }; this._validParseKids.Document = { Folder : { func : this.parseFolder } , Placemark : { func : this.parsePlacemark } , Style: { func : this.parseStyle } , StyleMap: { func : this.parseStyleMap } }; this._validParseKids.Folder = { Folder : { func : this.parseFolder } , Placemark : { func : this.parsePlacemark } };
As you can see the kml object has three possible children: Document, Folder, and Placemark. Each of these have a func(Function) assigned to them. So if we are in the kml tag and find a Document the this.parseXML function will be executed. This parseXML function looks like this:
protected function parseXML( x:XML ) : Object { var returnObject:Object = new Object(); var validKids:Object = this._validParseKids[x.name().localName]; if( validKids != null ){ var kids:XMLList = x.children() for each( var node:XML in kids ){ var validKid:Object = validKids[node.name().localName]; if( validKid != null && validKid.func is Function ){ validKid.attrName = ( validKid.attrName == null ) ? node.name().localName : validKid.attrName; if( validKid.attrType == "Array" ){ if( returnObject[validKid.attrName] is Array == false ){ returnObject[validKid.attrName] = new Array(); } returnObject[validKid.attrName].push( validKid.func( node ) ); } else{ returnObject[validKid.attrName] = validKid.func( node ); } } } } else{ returnObject = "Not Found in Valid Kids Object"; } return returnObject; }
If you notice there are two other variables in the this._validParseKids object, attrName and attrType. Here is an example of both:
this._validParseKids.Placemark = { Point : { attrName: "_shape" , func : this.parsePoint} , LineString : { attrName: "_shape" , func : this.parseLineString } , LinearRing : { attrName: "_shape" , func : this.parseLinearRing } , Polygon : { attrName: "_shape" , func : this.parsePolygon } , name : { attrName: "name" , func : this.parseString } , address : { attrName: "address" , func : this.parseString } , phoneNumber : { attrName: "phoneNumber", func : this.parseString } , Snippet : { attrName: "Snippet" , func : this.parseString } , description : { attrName: "description", func : this.parseString } , styleUrl : { attrName: "_style" , func : this.parseStyleUrl } , ExtendedData : { attrName: "_data" , func : this.parseExtendedData } }; this._validParseKids.ExtendedData = { Data : { attrName : "kvPairs" , attrType : "Array" , func : this.parseData } };
So the attrName is the name of the object that any returned values from the function that was called may return. The attrType is only used to say that there will be multiple objects that return data to the given attrName. So for example the when in the ExtendedData tag you can have an unlimited number of Data tags that are to be stored in an array. As a final example here are a couple of the basic parse functions:
protected function parseString( text:XML ) : String { return text.toString(); } protected function parseInt( i:XML ) : int { var s:String = i.toString(); var n:Number = Number( s ); if( isNaN( n ) ){ n = this.stringToHex( s ); } return int( n ); } protected function parseNumber( n:XML ) : Number { return Number( n.toString() ); } protected function parseBoolean( b:XML ) : Boolean { var value:String = b.toString(); if( value.match( /(1|true)/ ) ){ return true; } return false; }
Labels:
ActionScript,
AS,
Flex,
Function Pointers,
KML,
parse
Friday, March 6, 2009
ESRI vs. Google, Flex API Load Times Compared. Part 2
In an effort to be fair I decided to rerun the test I had done earlier, but this time using polygons. Part of the reasoning is that I feel that Google's Marker has a lot of crap that it has to draw, like the shadow and just the balloon shape alone would add time. The polygon in Google is just that a polygon and nothing extra. So I created 2000 different bounding boxes and let both ESRI and Google load them. As suspected Google's performance was much better but ESRI was still faster.
So the moral of the story is don't use Google's Marker if you want to go fast.
ESRI | |
---|---|
3.828 sec. | 3.032 sec. |
3.891 sec. | 2.875 sec. |
3.953 sec. | 2.969 sec. |
So the moral of the story is don't use Google's Marker if you want to go fast.
Thursday, March 5, 2009
Try catch vs if statements
Many might already know this but I wanted to know for sure. Is it faster to use a try catch block or if statement. So I ran a simple test to find out. I created this function to run the try catch test;
I then wrote an identical function except that it had an if( o[y] != null ) statement where the try was. Now what I found was that the if statement times did not change it took 0.57 seconds in all the tests. However, the try catch statements did not preform quite as well. As the number of exceptions are thrown the amount of time increases rapidly. Here is a table of times for the percentage of exceptions thrown over a million iterations.
I ran the function without the try catch/if statement and it took 0.422 seconds. If I subtract that from the times and then divide the number of exceptions thrown by the time you end up about 90,000 for each of the times. To put it another way, on my computer I can throw 90,000 exceptions per second.
So it seems like unless you are really do not like if statements it would be faster to use them.
private function testTryCatch() : void { var adder:Function = function a( x: int ) : int { return (x + 1); }; var x:int = 0; var o:Object = { 0 : adder }; for( var i:int = 0; i < 1000000; i++ ){ var y:int = i % 2; try{ x = o[y]( x ); } catch( except:Object ){ x = adder(x); } } }
I then wrote an identical function except that it had an if( o[y] != null ) statement where the try was. Now what I found was that the if statement times did not change it took 0.57 seconds in all the tests. However, the try catch statements did not preform quite as well. As the number of exceptions are thrown the amount of time increases rapidly. Here is a table of times for the percentage of exceptions thrown over a million iterations.
0% | 33% | 50% | 90% |
---|---|---|---|
0.5 | 4.219 | 6.031 | 10.422 |
I ran the function without the try catch/if statement and it took 0.422 seconds. If I subtract that from the times and then divide the number of exceptions thrown by the time you end up about 90,000 for each of the times. To put it another way, on my computer I can throw 90,000 exceptions per second.
So it seems like unless you are really do not like if statements it would be faster to use them.
Wednesday, March 4, 2009
ESRI vs. Google, Flex API Load Times Compared
I have been writing a set of several parsers (Shapefile, Shapefile DBF, KML, CSV, and Tab Delimited) that work for both ESRI and Google. The parsers format the data and pass it to an overlays factory class. The factory class has the map you are working with and also a set of default shape builder classes, that know how to build the appropriate shape for your map. This is the setup that I used to test the speed of loading points into both ESRI and Google maps.
First, I tested loading a kml with 1297 points. To get a baseline I commented out the call to the factory class and got an average parse time of 0.178. I have subtracted this time out of the times below.
Google's default Marker is slower, so in all fairness I set the marker options to { hasShadow: false , radius: 1 , icon : "none" }, this dramatically increased the load times for google.
As you can see the default ESRI point is considerably faster (8-9 times) than the default Google point. If you compare more the ESRI point to the modified Google point it is still faster (3-4 times).
I then ran the same tests for loading a shapefile with 1297 points. The baseline time for the shpfile parser was 0.11 (however the dbf took 4.01 seconds) and has been subtracted out of the times below.
The times are essentially the same as those in the last test. One interesting note though is that reading data from the dbf file makes using a shapefile prohibitevly slow as the amount of data grows.
So I would suggest parsing kml and putting it on a ESRI map for your best results.
First, I tested loading a kml with 1297 points. To get a baseline I commented out the call to the factory class and got an average parse time of 0.178. I have subtracted this time out of the times below.
Google's default Marker is slower, so in all fairness I set the marker options to { hasShadow: false , radius: 1 , icon : "none" }, this dramatically increased the load times for google.
Default Google | Modified Google | ESRI |
---|---|---|
3.697 | 1.462 | 0.416 |
3.651 | 1.447 | 0.384 |
3.665 | 1.462 | 0.385 |
As you can see the default ESRI point is considerably faster (8-9 times) than the default Google point. If you compare more the ESRI point to the modified Google point it is still faster (3-4 times).
I then ran the same tests for loading a shapefile with 1297 points. The baseline time for the shpfile parser was 0.11 (however the dbf took 4.01 seconds) and has been subtracted out of the times below.
Default Google | Modified Google | ESRI |
---|---|---|
3.947 | 1.703 | 0.562 |
3.838 | 1.577 | 0.468 |
3.796 | 1.656 | 0.453 |
The times are essentially the same as those in the last test. One interesting note though is that reading data from the dbf file makes using a shapefile prohibitevly slow as the amount of data grows.
So I would suggest parsing kml and putting it on a ESRI map for your best results.
Monday, March 2, 2009
Parsing KML with ActionScript XML e4x
I spent some time trying to figure out why I could not get the ActionScript XML object to properly parse a KML file and found out that the problem was in the namespace of the KML. KML sets its global namespace to whichever version of KML
you are using. The problem is that when you try to access the tags using the e4x methods it does not work. So to fix the problem you need to then set the default namespace.
default xml namespace = new Namespace("http://www.opengis.net/kml/2.2");
Subscribe to:
Posts (Atom)