MapQuest Actionscript 3.0 Learning and Blogging

Just another WordPress.com weblog

Back to Mapping, YAY!

Well now that phase 1 has been complete, it is time to start the second phase of the mapping application that I have been blogging about.  So to do so, we have upgraded.  Not only from the older mapquest 5.2 API to the new MapQuest 5.3 API but also to Flex 3 from Flex 2!!  So today, I took my new flex 3 mapping project, empty canvas, and just threw the map on the screen.  Now, I am not running the swiftest computer out there… although that is soon to change, but it does good at getting the job done.  The first thing I noticed was how much faster the load time was to put the map on the screen.  It improved enough that I noticed it before looking at the other version I have out there.  I have to say, this next thing I am impressed with, I noticed that the map moved much more fluidly than it did before.  Same machine, same setup, except now using Flex 3 and MQ 5.3.  I don’t get that long loading grey screen of wait any longer, and those loading blocks have dwindled to few at the edges.  Before, the whole screen flashed, now just a couple blocks!!  Way to go MAPQUEST!  This is exciting to me.  My users will be able to get things much faster now than before.  I will be exploring the next couple of days what I can do with the new setup.  Thanks MapQuest for the new upgrades in performance.  Even now, just the little I have seen with the map alone, I am excited.

August 21, 2008 Posted by mqguru | mapping, mapquest | , , | No Comments

6 month revist

OK, well i want to spend a little time talking about the project I just finished with making MapQuest Flash Maps in flex.

Project Refresher:

This project was to bring in demographics data and other informational data per zip code from internal systems, and using those choice zip codes to display zip code polygons on the map, somewhere between 50 and 2100 zip codes, effectively.  The zip codes will be colored based on system or demographics data, whichever the user chooses, and displayed to the user like on might see a weather map on TV. 

Project Hardships:

Multiple Polygons:  Some of the hardships that were found early on while i was learning was displaying a large amount of zip codes.  We found out that we were not able to ask for a certain set of zip codes from MapQuest, so we needed a way to get all of the ones that we wanted to see quickly.  We determined that we should cache them on a local server so we can access them faster and more readily.  The only problem was figuring out how to grab the object once it was cached.  We soon found that using the Feature Collection XML for the code would be appropriate for the storage. 

We started development with that in mind, and it worked well, but it still took a lot of time to get the XML across the wire.  So we used gzip and ByteArrays.  I should mention we have a Java Back-end that makes many calls to cache our data, and then we have a flex front end that uses our chached data.  This data is taken and we had to use a XML processor to make the XML in JAVA, GZIP it and cache it until called.  Once the call is made we bring it in flex, unzip it and write it out.  This was fast but still took some time.  To make it use less time we used the Generalize function, which would then remove some points and make the polygon smaller, but we started getting some serious skew through the straight edges where the zips cross tile lines.  We found a cool project with called JTS(Java Topology Suite)and it would make a single polygon where polys share lines with one another (get rid of those pesky tile lines),so we iincorporated some of that idea in our project.  That turned out beatuiful.  We now can generalize with the JTS as well and get really nice results.  We are still tweaking some things but all in all, incorporating their ideas really saved us. 

Working with Multiple Polygons on the screen:  I had to figure out how to manipulate the zip code polygons on the screen by changing their color, and their outline color as well.  I found that instead of putting them just right on the map, if you use a OverLayCollection, you can just sift through that and change the ones you need.  That works well.

Lack of Polygon Info:  There are some things you just need to know about a polygon, like where it’s furthest edge points are.  I needed to find the north-most, south-most, east-most and west-most points of a poly, i wrote a function to do that, you can see it below in the Find Edges of Polygon posting I did.

Silly programming naming:  I do it to, programmers write names for functions that seem to make sense, and you really have to pay attention to the api, but if you want to get the XML for a object in Flex/Flash, you say object.saveXml(), and that will return the XML to you.  If you want to load an object up with some XML just do object.loadXml(myXmlObj).  Thinking back, that is really pretty clear, that is more of my error.

Not incorporating objects soon enough:  I actually wrote object that deal with a POI.  So if you have tons, instead of doing a batch of them, because they are not all the same probably, or if you have just one, you can fill this object up with an address, or something that resembles and address, and icon, and other information that you want the point to have and then let it go.  It will put itself on the map when it is done.  Also did the similar things to deal with the caching calls.  That way i can break them up and I make one return before the system sends the next one out.  Seems to work well. 

Some sort of limiting factor:  We had something that was going on and when we made a call to mapquest it would return partial XML, not sure why, but it would.  We changed some of the specifics of the call(radius call) like the radius and the number of results, but that didn’t help too much.  We were still a an impass with that.  Having a way to handle it would have been great other than it crashing our systems.

Batch Geocoding:  You can only do a hundred at a time, but i don’t really care now, i do them all one at a time.  I can put about 350 on a screen in around a min.  I wouldn’t want to do this with too many more, but 350 is abnormal for us.  But 350 polygons isn’t, kinda funny.

Seriously Easy Tasks

Getting a map up and running is a breeze, just throw on the tilemap component and that is it.

GeoLocation calls are a breeze, getting that setup and working is also really easy.  I would write a object to do it, one for batches that manages a group of the same type of objects too if that is needed.

TIPS

Connecting to their servers:  When you connect to their server make sure you are using the right password and username.  They are both listed in the account managment part of TRC.  But make sure you use the Registry Passwordnot the password to log into TRC. 

Getting the correct x and y position of the click on the map:  myMap.mouseX,myMap.mouseY  others will work, but only in certain situations, these work constantly.

Items under clicked spot:  myMap.getObjectsUnderPoint(myPnt) as Array  Use that to try to find the type of object you are looking for under your click.  You might need to set a key or some sort of identifier to make sure that you can pick the object contents out of the lineup.

My Wishlist:

Mapquest accept a single call for a zip code.  I can live without it now, but that would make life a lot easier.  Especially when some zip codes are very large, like over 100 shape items, and take up a lot of resource power get get two that might be on different sides of the country.

MapQuest data implement JTS solution to get rid of tile lines, but i do that now too.  It save a lot of time.  Also let us pass in how generalized we might want to get the polys back and generalize them for us before return, that would save MapQuest gigs perhaps.

Lables for Polygons, like where you could see it blended into the polygon.

Summary

Spending the last 8 months working with MapQuest and 6 months on a project, i found that working with the product is really good.  The support is out of this world, and they get back with you on a really quick basis.  Also, I find the map to usually render in a relatively quick time.  Getting the program tweaked to display the items quickly was a difficult 2 month task, i mean really, 2100 zip code polygons is a lot.  Lots of exploration on our part, using gzip bringing it in with Java and out into Flex/Flash.  Having the multiple API accessibility was great, we have a talented group in our office and they saved me some work, and i got to learn some Java in the midst of the project.

 

May 16, 2008 Posted by mqguru | flash mapping, mapquest | | No Comments

A new friend called JTS!

Well, we found something new today.  This guy will actually do tons of work to clean up polygons.  It is what PostGres GIS was modeled after and converted from and is a live project.  Here is a link http://www.vividsolutions.com/jts/discussion.htm .  As it is a Java app and i have some java backend stuff to do some pulling, it can easily be added into the project and serve up hot data, either on the fly or store it to something.  Just a easy conversion to a different format polygon to join the polygons then convert them back and Whammo Bammo you got a untiled looking polygon.  Great for on the go lookin good maps.  I will post more on this later, just really excited and it works, even on multiple part zips.

April 25, 2008 Posted by mqguru | mapping, polygons | | No Comments

Less expensive Polygons

As i grow to love this software more and more, i find different things that can take away from the user experience.  I have found that putting polygons on the screen(mostly zip code polygons) is expensive if you use oh about 250 or more.  I am working on ways around this and we are figuring some things out.  One reason why a polygon is expensive is that in flash a polygon is simple correct… yes correct.  Zip Code polygons are a little troublesome because of the number of points.  They have great detail which is awesome when you gotta see where an exact measurement is located, but if you just need some round abouts, well, it hurts the client.  By putting many of them on the screen at once your clients computers memory grows and grows.  We are thinking that if we can remove about half the points, it should put them on the screen quicker, reduce the amount of memory the take up and provide the quickness that we are looking for.  With that said, we are not completely sure about it.  It is a good theory, but it has not been practiced to date, at least not by us.

So what i am looking to do is perhaps find a less precise data set, or rip up the current one in real time while at a certain zoom level.  This should enable the XML to drop in size so the memory is not so full, and also kick up the coolness of the program.  The biggest concern i have is leaving holes in the area.  If i make the change to one, i have to find anyone that is using that same line and change his as well, so either my ripping algorithm must be killer, or i must be able to decipher who is using a common point.  Please post your thoughts, knowledge or expertise about this topic.  I am interested in hearing it.  I hope that there are still some people paying attention.  ;)

March 26, 2008 Posted by mqguru | flash mapping, mapping, polygons | | 3 Comments

Find Edges of Polygon

Ok so over the last couple of days we have come up with a solution to grab information to do some caching.  One of the things that I am doing is figuring out where i need to move to grab the next set of data.  Well i wrote a little something i will post as a comment in a bit that will give the coords of Northern, Southern, Eastern and Western most portions of the zip code.

With this now i will be able to do a little math a populate a center point for my zip codes that is not listed in my feature collection.  I am sure there is more that one could do as well.

     getting bounds of zip

//this function will get you the most nortern, southern, eastern and western lat/lng of the feature collection you pass it and will also give you the center 

public function findBoundsPointsAndCenter(fc:FeatureCollection):LatLngCollection
{
//get init value so we can have
     var TempLLC:LatLngCollection = PolygonFeature(fc.getAt(0)).getLatLngs();
     var WestLatLng:LatLng = new LatLng(0,0);
     var EastLatLng:LatLng = new LatLng(0,0);
     var NorthLatLng:LatLng = new LatLng(0,0);
     var SouthLatLng:LatLng = new LatLng(0,0);
//going to fill them with values because they didn’t set right above for some reason??
     NorthLatLng = LatLng(TempLLC.getAt(0));
     SouthLatLng = LatLng(TempLLC.getAt(0));
     WestLatLng = LatLng(TempLLC.getAt(0));
     EastLatLng = LatLng(TempLLC.getAt(0));
//loop through each poly and find most extreme point
     for(var a:int = 0;a < fc.getSize();a++)
     {
          var PolyLLC:LatLngCollection = PolygonFeature(fc.getAt(a)).getLatLngs();
          for(var b:int = 0; b < PolyLLC.getSize();b++)
          {
               if(LatLng(PolyLLC.getAt(b)).lat > NorthLatLng.lat)
                    NorthLatLng = LatLng(PolyLLC.getAt(b));
               if(LatLng(PolyLLC.getAt(b)).lat < SouthLatLng.lat)
                    SouthLatLng = LatLng(PolyLLC.getAt(b));
               if(LatLng(PolyLLC.getAt(b)).lng > EastLatLng.lng)
                    EastLatLng = LatLng(PolyLLC.getAt(b));
               if(LatLng(PolyLLC.getAt(b)).lng < WestLatLng.lng)
                    WestLatLng = LatLng(PolyLLC.getAt(b));
               }
          }
//get the Average Lat Lng which is the amount of variance + lat or lng
var AvgLat:Number = EastLatLng.lat + ((WestLatLng.lat - EastLatLng.lat)/2);
var AvgLng:Number = NorthLatLng.lng + ((SouthLatLng.lng - NorthLatLng.lng )/2);
var centerLatLng:LatLng = new LatLng(AvgLat,AvgLng);
var FourEdgePointsLLC:LatLngCollection = new LatLngCollection;
FourEdgePointsLLC.add(NorthLatLng);
FourEdgePointsLLC.add(SouthLatLng);
FourEdgePointsLLC.add(WestLatLng);
FourEdgePointsLLC.add(EastLatLng);
//throw the info on the screen to make sure it works
var CenterPOI:Poi = new Poi(centerLatLng);
var NorthPOI:Poi = new Poi(NorthLatLng);
var SouthPOI:Poi = new Poi(SouthLatLng);
var EastPOI:Poi = new Poi(EastLatLng);
var WestPOI:Poi = new Poi(WestLatLng);
NorthPOI.setLabel(
‘North’);
SouthPOI.setLabel(
‘South’);
EastPOI.setLabel(
‘East’);
WestPOI.setLabel(
‘West’);
myMap.addPoi(NorthPOI);
myMap.addPoi(SouthPOI);
myMap.addPoi(EastPOI);
myMap.addPoi(WestPOI);
myMap.addPoi(CenterPOI);
return FourEdgePointsLLC;
}

February 7, 2008 Posted by mqguru | mapping, polygons | | No Comments

Distance and Bearing

Something i just found that i would love to have is for my LatLng to give me another LatLng with taking distance and bearing(by degree).  This would be an awesome addition to be able to draw other features, but for now i will have to settle for doing the calcs myself.  I am now looking up the functions in Flex to see if i can, but here is the formula as i got from http://www.movable-type.co.uk/scripts/latlong.html

 Formula:   

lat2 = asin(sin(lat1)*cos(d/R) + cos(lat1)*sin(d/R)*cos(brng))
    

lon2 = lon1 + atan2(sin(brng)*sin(d/R)*cos(lat1), cos(d/R)−sin(lat1)*sin(lat2))

February 4, 2008 Posted by mqguru | please add | | No Comments

A lesson learned

OK, today was one of the most awesome days since my mapQuest experience has begun.  Thanks to Ant who has posted comments here a few times i was able to speak with Kevin who has intimate knowledge of the system and was informed about how they do things.  I was going in a good direction with caching( using XML ) but when I want to Hydrate a MqObject i can just say

MqObject:MqObject = new MqObject();
MqObject.loadXML(myXML);

BAM!  there is your object all ready to go.  * not actual code i used

That right there is pretty now.  I thought i had tried this once before but not yielding the results I had hoped, evidentally not using the right syntax or thought of the object so i had wrote a convaluted process to hydrate it, “Took the long Road”.   

So if we cache the XML which is how it was suggested to me to do, it will be easy to create, and wow it is.  I save a ton of time now with the way we are doing things.  Just gotta make the caching utility i need now. 

Kudos to Ant and Kevin.  Ant is awesome for taking care of me.  In my company that is something to be expected of each and every one of us.  Exceptional customer service even if you are not someone who usually does customer service.  Not sure if you have read the QBQ book or not but that is required reading in my company and it was definatly used this fine day.  If you wanna check out the book here it is.  http://www.qbq.com/

Thanks Hope you all have a great night!

January 29, 2008 Posted by mqguru | caching, mapquest | | 1 Comment

Good programming practice with mapquest fuctions & Freebies (Merry Christmas)

So when i started writing the mapquest functions i have, i wrote the same ones over and over again until i got familiar.  I the broke out my own file and just called it mapQuest something or other and put all my mapquest functions in it.  Once i did that I made it where you can pass in listener functions to the functions that way i am not tied down to one particular function.  I am sure this Loose Coupling idea has gone through all your heads, but how about this.  I am gonna give you some code that can do some cool stuff for you.

 Here are some that i will share, perhaps later i will give you some cooler ones:

public function configGeocodeExecObject():Exec
{
 var exec:Exec = new Exec(”geocode.access.mapquest.com”, MQServerPath, MQServerPort);
 exec.addEventListener(Exec.EVENT_DO_TRANSACTION_ERROR, onSearchError);
 exec.setClientId(MQServerClientId);
 exec.setPassword(MQServerPassword);
 return exec;
}
//This function will configure an EXEC object for the map server of Mapquest
public function configMapExecObject():Exec
{
 var exec:Exec = new Exec(”map.access.mapquest.com”, MQServerPath, MQServerPort);
 exec.addEventListener(Exec.EVENT_DO_TRANSACTION_ERROR, onSearchError);
 exec.setClientId(MQServerClientId);
 exec.setPassword(MQServerPassword);
 return exec;
}

public function geocodeZipCode(zipcode:String,listenerEvent:Function):void 
{
  var address:Address = new Address();
 address.setPostalCode(zipcode);
 address.setCountry(’US’);
 var exec:Exec = configGeocodeExecObject();
 exec.addEventListener(Exec.TRANS_TYPE_GEOCODE, listenerEvent);
 exec.addEventListener(Exec.EVENT_DO_TRANSACTION_ERROR, onSearchError);
 exec.geocode(address);
}

/*This is the function call to make the call to the function below.  Make sure that you call the mouseX and mouseY position items because if you don’t then you are gonna have issues with getting the wrong zip code show up.  I worked on this problem for over 5 days.  There are about 4 different X/Y position items you can use but the only proper one for the whole map is the mouseX/mouseY.  The event.x or something like that works on just the polygons spots but not the non-poly spots.
 reverseGeoXnYPoints(myMap.mouseX,myMap.mouseY,getZipInfo,onSearchError);*/
 
//this function will take two x y points and hit mapquest to find out what zip code the location belongs.
public function reverseGeoXnYPoints(x:Number,y:Number,listenerOkEvent:Function,listenerFailEvent:Function):void
{
 var myPnt: IPointLL = myMap.pixToLL(new PointXY(x,y));
 var myLatLng: LatLng = new LatLng();
 myLatLng.setLatLng(myPnt.lat,myPnt.lng);
 var exec:Exec = configMapExecObject();
 exec.addEventListener(Exec.TRANS_TYPE_REVERSE_GEOCODE, listenerOkEvent);
 exec.addEventListener(Exec.EVENT_DO_TRANSACTION_ERROR, listenerFailEvent);
 exec.reverseGeocode(myLatLng, “tana”);
}
//the following function will parse an XML object that pertains
//to a FeatureCollection and make a featureCollection so you can then put it on your map
private function makeFc(newXML:XML):FeatureCollection
{
 var fc:FeatureCollection = new FeatureCollection;
 var fltFeatureCount:Number = Number(newXML.attribute(’Count’));
 //the following will make the object for each polygon portion of the feature collection
 for(var a:int = 0;a < fltFeatureCount;a++)
 {
  var FeatureItem:XML = newXML.PolygonFeature[a];
  var llc:LatLngCollection = new LatLngCollection();
  var formatStyleLat:Number = Number(.000001);
  var formatStyleLng:Number = Number(.000001);
  var j:Number = Number(FeatureItem.LatLngs.attribute(’Count’));
  var BaseLatLng:LatLng = new LatLng();
  BaseLatLng.setLatLng(Number(FeatureItem.LatLngs.Lat[0])*formatStyleLat,Number(FeatureItem.LatLngs.Lng[0])*formatStyleLng);
  llc.add(BaseLatLng);
  for(var i:Number = 1;i<j;i++)
  {
   llc.add(revDeltas(llc.getAt(i-1),Number(FeatureItem.LatLngs.Lat[i])*formatStyleLat,Number(FeatureItem.LatLngs.Lng[i])*formatStyleLng));
  }
  var pf:PolygonFeature = new PolygonFeature;
  llc.loadXml(llc.saveXml());
  pf.setLatLngs(llc);
  pf.loadXml(pf.saveXml());
  fc.add(pf);
 }
 fc.loadXml(fc.saveXml());
 return fc;
}
//This function will return you a latlng from the deltaLatLng items
private function revDeltas(baseLatLng:LatLng,deltaLat:Number,deltaLng:Number):LatLng
{
 var retLatLng:LatLng = new LatLng();
 retLatLng.setLatLng(deltaLat + baseLatLng.getLatitude(),deltaLng + baseLatLng.getLongitude());
 return retLatLng;
}

December 21, 2007 Posted by mqguru | Uncategorized | | No Comments

Polygons and labels

So there is more to report when it comes to throwing Poly’s on the screen.  Well, it looks like there is not a great way to do labels for your poly’s which stinks, but there are work arounds i am sure.  I posted something on this in the forums on MapQuest site with a response which will be the first solution since someone actually did it.

 What I would like:  I would love to have a label attribute for a polygon overlay, or any type of overlay on a map, and if that label attribute is assigned a value, it should be shown on the screen.  I understand there is a lot to think about, colors and what not, but that is what i am looking for.

Solution 1:  Find a point, preferably the center of the poly, throw a POI on that point with an invisible image and give it a label.  Poof you are done.  Easy enough and POI’s go on quick. 

Possible solution to a crazy guy:  So i was dreaming of a possible solution and thought of this one.  What it i gathered all the points under the polygon, and threw in a text item on top of that array of items, i am sure it problably would not work, but it was a thought i guess.  POI’s would probably go much faster.

December 21, 2007 Posted by mqguru | POI, flash mapping, polygons | | No Comments

Back to school on Polygons and map placement, (HI OverlayCollection)

Ok, so i am back to working on the UI for the map so my customers can really be effective with the way it sits.  Until today whenever i put a polygon on the screen i just wrote it straight to the map, so something like

myMap.addOverlay(myOverlay);

This is good and all, but here is the problem.  If you were to have more than one overlay that was realted and you wanted to manipulate it, you would have an extreamly hard time with it written directly to the map.  Try this proposal. 

Use an overlayCollection(olc)!  This is the coolest thing because now you have all the polygons that relate to one another, you can just throw them in this thing, make sure you assign a key to all of them and now whenever you want to manupluate the way one looks just loop through the overlayCollection, find the key of the item that you are looking for and make the change, then that is it.  It will write it out on the screen for you. 

 One issue you might encounter is if your polygons share a border, if so the last border laid goes on top. 

  • solution 1:  remove the polygon and add it back, this will happen after the map redraws the polys initially and your borders will appear all cool and such, here is the code:
    myMap.removeOverlay(PolygonOverlay(olc.get(a)));
    myMap.addOverlay(PolygonOverlay(olc.
    get(a)));
  • Possible solution 2:  make your other borders as transparent as possible, this will allow the black to bleed through?  have not tried this though

So in summary i think that you should never put a polygon on the map straight away unless you plan on destroying it and never manipulating it.  Put it in the overlayCollection then add them to the map from it.

That’s all for now, come back soon and i will try to impart some more wisdom in your skull!

December 20, 2007 Posted by mqguru | flash mapping, mapquest, polygons | | No Comments