Flex: UMap WMS Custom Provider Demo

Aint it the way. You wait for one map demo and three come along at once. I have been trying out the UMap component from AFComponents. Here is the latest demo.

IFrame Map App

The first thing to note is that this is not using Google or Microsoft to provide the map tiles. I have implemented a custom tile provider class ‘WMSTileProvider’ which talks to a mapping server using the WMS protocol.

The map is supplied from here.

This tiles are from here and have been generated by scanning out-of-copyright Ordnance Survey maps and stitching them together. Very clever.

The AS3 UMap component provides a means to hook your own custom tile provider into the underlying map mechanism. There is a partial explanation of this on the forum here and here.

The forum posts are more of a signpost as to how you could go about plugging in a Custom provider for the map. There was no downloadable code, until now.

I have spent a fair bit of time trying to get this working and I have adopted one technique. There may be others. The main trick is to override all the overridable methods in your ‘Provider’ subclass.


public class WMSTileProvider extends Provider
{
public function WMSTileProvider(defaultData:Boolean = false,
settings:URLRequest = null,
language:URLRequest = null,
copyright:URLRequest = null)
{
super(defaultData, settings, language, copyright);
}

override public function getDefaultLanguage():String
{
return “EN”;
}

override public function getDefaultCopyright():String
{
return “(c) – OS NPE (1940s) – Public Domain”;
}

override protected function parseSettings(data:String):Boolean
{
return true;
}

override protected function parseLanguage(data:String):Boolean
{
return true;
}

override protected function parseCopyright(data:String):void
{
trace(data);
}

}

The next trick is to supply dummy requests for the language and copyright strings. Normally these would be php requests but I just changed them into xml files. As long as you override all the methods in the Provider subclass you won’t get any annoying exceptions.


var settings:URLRequest = new URLRequest("settings.xml?rand=" + Math.random());
var language:URLRequest = new URLRequest("language.xml?rand=" + Math.random())
var copyright:URLRequest = new URLRequest("copyright.xml?rand=" + Math.random());

_map.control.provider = new WMSTileProvider(false, settings, language, copyright);

You have to put something into language.xml and copyright.xml they can’t be empty.

The settings.xml file only need contain the minumum definition:



http://www.afcomponents.com/components/umap_as3/GoogleLogo.png

Not so complicated when you know how but not easy to work out from the UMap forum posts.

An additional hurdle for me was that the WMS feed required the boundaries of the tile view to be supplied in British National Grid (Easting and Northing) values. I had some old javascript kicking around (which I thought I’d lost) which implements WGS84 to OSGB conversions. I had half created a AS3 version of this a while back and now it became quite handy (this is bundled into the source code for those of you who might need it).

Truly a pure geeky rush when I saw the map tiles burst into life. It was worth all the hassle. Right-click to view the source.

There is a pretty long list of other WMS data providers here if you want to try creating a different WMS tile layer. If you do it would be good form to post it up onto the UMap forum.

Bugs

– Resizing the map window sometimes makes the tile disappear. No idea as of now what’s going on but I think it’s linked to the resize.

About the dataset

The Avebury data is supplied as a KML file. This is fetched and parsed by the application and then displayed on the map and in the right-hand data grid. The data was downloaded from here.

This is the original drawing William Stukeley made of the Avebury complex.

IFrame Map App

His drawing shows the main complex and the two avenues to the left and right before time and other thieves destroyed most of it. You can see most of the same features on the map view.

For some more information head here.

Update #1

Update #2

Flex: IFrame Map Demo

As requested here is an IFrame map demo. It took me a bit of time as it’s not that easy to put together. The application looks like this:

IFrame Map App

You will need the full project to examine as it isn’t just encapsulated by the Flex code. There is a load of javascript and the magic of FABridge to get your head around.

This is currently only a FlexBuilder2 project. I haven’t got around to converting it to FB3. The reason for this is that there are hooks into the required javascript from all sorts of places including the ‘index.template.html’ file. Recreating the project from scratch means these are blasted by the new project option in FB3 and it’s a bit of chore to generate all the required includes that the project needs.

Here is a (rough) diagram of how the javscript is arranged.

IFrame Map App

The ‘MapClient.js’ component presents a generalised API to the FABridge layer, this abstracts the implementation details of the map down into the controller component ‘MapOSController.js’. The controller implements the real details of whichever map is plugged in to the client. In this case it is OpenLayers whereas in flexTraffic I have a similar component which implements the map interface for a Google map.

Flex

Map communication from the Flex side takes the form of generating events which the ‘MapClient’ has registered listeners for (through FABridge). The advantage of this over using ‘ExternalInterface’ calls is that FABridge marshalls the objects across the Flex/Javascript layer and turns the Plain Old Flex Objects (POFO’s) into javascript objects complete with getters and setters for member variables. This is an extremely powerful mechanism.


flexApp.addEventListener("ResizeFrameEvent", function(event) {self.controller.resizeFrame(event.getWidth()-self.offset, event.getHeight()-self.offset)});
flexApp.addEventListener("CentreFrameEvent", function(event) {self.controller.centerOn(event.getLatitude(), event.getLongitude())});

See the ‘getWidth’ and ‘getHeight’ functions? These are generated automatically by Fabridge from the Flex event which the listener registered.


public class ResizeFrameEvent extends Event
{
public static const EVENT_RESIZE_FRAME:String = "ResizeFrameEvent"

public var width:Number;
public var height:Number;

public function ResizeFrameEvent(width:Number, height:Number):void
{
super (EVENT_RESIZE_FRAME, true);

this.width = width;
this.height = height;
}
}

Javascript

The javscript side communicates with the Flex app by calling Flex methods directly. The method function must be declared in the application mxml at the same level as the FABridge controller definition. Note that the functions which perform this direct communication are abstracted further by making them plugin functions to the controller at the client level.

self.controller.addMapViewChangedHandler(function(a,b,c,d)
{
var flexApp = self.frame.FABridge.flash.root();
flexApp.onMapViewChanged(a,b,c,d);
});

This application exhibits all of the tricks I have invented to embed an html page into a Flex application. If you are interested in using the Flex IFrame then I suggest if you understand this you will have mastered all of the techniques required to make something like flexTraffic. The demo doesn’t have that much of a wow factor but all of the magic is in the code. There is no quick dropin code to acheive this kind of thing, it takes a bit of inventiveness and graft.

Flex: UMap simple Flex demo

The UMap is a AS3 map which you can use with Flex. This is a simple demo.

Sample UMap App

I found myself playing around with this instead of having a clear idea of what I wanted to do. This is always a sign that I should just post it up. It’s lacking a few features like the ability to click on the datagrid row and make the infowindow for the target event popup.

The Flex application embeds the component in a wrapper called DisplayObjectWrapper from here.

I am working on some other mapping related demos including a full IFrame example which should show off the techniques I developed for flexTraffic.

I can’t seem to get the source view to work for some reason. You can download the full Flexbuilder3 project from here.

I noticed a post on the UMap forum talking about memory leaks when using UMap with Flex but I haven’t had a good chance to test this out. If anyone can confirm this it would be a bit of a downer as I was hoping to use this component more.

Update #1

I have made a few ‘improvements’ to the demo application. The marker class ‘EventMarker’ is has been redesigned to subclass from a new ‘CustomMarker’.


public class EventMarker extends CustomMarker
{
private var trafficEvent:EventVO = null;
private var infoWindowStyle:InfoWindowStyle = null;
...
}

This now stores a reference to it’s associated Traffic event object as well as a default style for the infowindow.

The ‘CustomMarker’ class implements

– Custom embedded icon (no shadows). This overlays the underlying Sprite which it makes invisible. The Flex marker doesn’t support the ‘style.icon = ‘ so this is a bit of a hack to get around this. The icons looks clipped I think because of the edges of the map tiles. Weirdly Modest Maps does this as well.

– Icon as a local path. There is a bug somewhere here. If you activate this you will see that the number of icons reported is double what it should be. Also the images appear and disappear as you zoom in and out of the map. Shadows work though!

– Tooltips have been added. The styling for these is the bog-standard Flex styling for tooltips.

As well as this CustomMarker I have tried to link the grid clicks to the markers by a kind of double-latch mechanism (can’t remember the proper name for this). Basically the data object gets a reference to it’s associated marker. When you click on a row in the grid it generates a marker click and the appropriate infowindow should open. Alas, there is yet another bug here. I have placed a trace statement into the point at which the infowindow gets opened.


public function openMarkerInfoWindow():void
{
// Open infowindow
trace(trafficEvent.summary);

// infowindow.
this.openInfoWindow(
{ title:trafficEvent.category, content:trafficEvent.summary },
infoWindowStyle);
}

The trace reports the summary correctly but the infowindow does not always display the correct string. It appears to get stuck on a previous value.

I will keep plugging away.

Update #2

I have discovered that most of the flaky behaviour goes away if you remove the MarkerManager from controlling the marker layer.

– Infowindows popup correctly all the time from grid row clicks.
– You can use the image urls for images and the icons behave correctly (and with cool shadows).

This is a step forward but it’s a shame as the MarkerManager is kind of an essential feature for something like a traffic map where the volume of markers can get quite large.

Update #3

I have switched off the problematic code for now.

– Custom image markers loaded from local disk.
– Click on a marker and the appropriate row in the grid is highlighted.

Blog: Opera

I am looking at this blog in Opera 9.25 and I have to say it looks miles better that Firefox or IE8. The screenshots are way sharper and it’s actually rendering the bullet points which Firefox seems to have stopped doing. My spelling is no beter though.

I like Opera but it doesn’t render Google Maps very well (slow). Also I have had some flaky experiences with Flash 9 although it was pretty zippy when I tried out the Modest Maps demo.

I have updates to make to the iFrame courtesy of ‘Max’ who has added the ability to render to a div (thanks Max). Also I recieved an email saying the Modest Maps demo wasn’t deleting markers which I discovered is a bug in the MM code. I fixed this but if you have access to Flex Builder you will discover it anyway You have to change:


public function putMarker(id:String, location:Location, marker:DisplayObject=null):void
{
if (marker)
{
marker.name = id; // ***THIS IS MISSING LINE***
//if (marker.name != id) throw new Error("marker name must match id");
markerClip.attachMarker(marker, location); // calls grid.putMarker as well
}
else {
grid.putMarker(id, __mapProvider.locationCoordinate(location),
location);
}
}

According to Sinisa the deletion is ‘dog’ slow which is not good news if you need to plot and replot lots of markers.

Merry Christmas to everyone who reads this blog. I know there are a few who drop in from time to time as I look at the stats.

gTraffic is due an update maybe I’ll find the get up and go to get back into GWT and fix it’s shortcomings.

flexTraffic was a bit of an experiment. I would retire the GWT version of the site if the web stats weren’t so high. What I need to do is to recompile with a link to the Flash version. I spent a lot of time on the Python scripts..lots of time..being totally bloody minded and attempting to wrestle the TPEG xml down to something usable. More time than I spent writing the sites (html initially).

Python was my first exposure to a dynamic scripting language. I had used javascript before but I was using it in a way like a glue around what I was doing with html. If you are a java only or C++ programmer time to steer away from the shore and find yourself a project to try this stuff out. I may expand on this mibbe on later posts.

gwt-yui-ext is to be retired (as in deleted from Google Code) on 1st Jan 2008. It was fun and a good learning experience but it quickly turned into land of the ‘edge-case’ nightmares. My advice…don’t try and wrap a large javascript library with GWT it can’t be done successfully without a massive effort to chase a moving target. Better to try a small component like the Simile timeline. Good luck to the next guy. You will need it.

GWT: Flex integration

Well done to Christian Voigt for putting GWT and Flex together in a way that works. He has written a small library and demo plus a clear explanation on his blog page for those interested here.

I have had a look at his solution and it makes mine look horribly over-engineered which I guess it is (plus it didn’t work properly). It’s been a while since I looked at this stuff and I haven’t a clue what I was thinking with my fancy controllers and such!

Flex: GWT: Developer Experience – Part 1

This is the start of a three part article focusing on my experience of using GWT and then Adobe Flex to implement versions of my UK traffic information site gTraffic.

You can compare the two by looking at the GWT version and the Flex version.

As an inital primer I will talk about the original website the GWT and Flex version were based on before getting into description of my experience of the technologies of GWT and Flex.

The intial version of the site was written using a combination of javascript and html with some AJAX to fetch and parse the data from the server side. It seems strange to contemplate that seems pretty ‘old-hat’ now but at the time it was really cutting edge. It was only just over a year ago really but how things have moved on!

The data was intially supplied from the BBC TPEG data feed which was later moved to the BBC backstage site which provides a place for mashups using the BBC data. The traffic data in TPEG format was downloaded and massaged into a simpler form using a number of Python scripts.

My intial thought was to use Java to parse the traffic data but it turned out that my ISP didn’t support this.

Instead I tried Perl but the experience was so awful I switched to Python even though my desktop developer mentality screamed against using tabs to act and formatting for block statements. The Python IDE bundled with the development kit it usable but having experience of Eclipse I settled with Pydev which had a great debugger and integrates into Eclipse really well.

The hardship of using CSS to layout the original site was a real pain. Although it looked okay it didn’t have great deal of appeal in terms of look and feel (you will have to take my word for this). I think my vision was sound as both the GWT and Flex versions adopt a similar layout but it was clearly a web page type of look and I was trying for something slicker.

The original site was written off the back of the experience I had gained in developing a few few sites using JSP and Tomcat for my employer. I had enough knowledge of html and javascript to develop a Google Maps site which took the traffic feeds from the BBC and plot traffic events on a map, plus put in a few nice touches for navigation. Struggling with CSS and layout issues didn’t make for a straightforward experience though and I suspect this is the view of more then a few developers who come initially from a background in development for desktop applications.

GWT came along at just the right time. I was looking for something that offered the ability to write an ‘application’ with real GUI controls and which ran in the browser. The added bonus was that it was using java which I already knew pretty well so it was tailor-made for my needs.

gTraffic: Problems

Aaaargh. I have just checked out gTraffic and there seems to be a problem. There are no events on the map! The weekend is upon us so I hope to find time to see what the problem is. In the meantime if you want to know what’s happening with UK traffic then checkout this.

Simile Timeline : Update

Well it’s been a while but I have finally got around to making an update to the gwt simile timeline. I had a request back in Dec last year (06) to add in the ability to load XML directly from a text string instead of having to use the AJAX loading mechanism. I thought it would be easy but when I went to look at it it turned out to be a bit involved.

Basically the event source object, which is the object which holds the data for a timeline, expects an XML document object to be supplied to load the data from. The AJAX call back mechanism automatically generates such an object in the request.responseStream of HTTPRequest object. Generating one of these from xml text isn’t straightforward as each browser has a different way to do it and you don’t have access to whatever magic the HTTPRequest is doing under the covers to create one.

I have had to add in a couple utility functions (see TimelineHelper.js in the code). This has been tested with Firefox, IE7 and Opera. I have no idea if it will work with Safari, I suspect not.

So, there are new calls to the EventSource object


public void loadXMLText(String xmlText)
{
    EventSourceImpl.loadXMLText(xmlText, GWT.getModuleBaseURL(), this);
}

and


public void loadJSON(String json) 
{
    EventSourceImpl.loadJSON(json, GWT.getModuleBaseURL(),this);
}

The loadJSON was a user contrubution from the Google Code site (thanks jdwyah whoever you are).

I started off writing a fancy JSON callback implementation then I realised that there are enough AJAX callback frameworks out there to handle however you want to get your data into the application so I haven’t put anything like that in. It just clutters up the interface anyway.

Look at the function processTextData in the DataHandler.java class to see an example of calling loadXMLText. It really couldn’t be easier.

I have bundled the latest MIT Simile timeline javascript code in with the source code zip. Keeping this locally makes the timeline boot up faster. Just be aware of this in case you have your own altered version.

gwt-yui-ext #3

I see that there are a number of issues building up around the gwt-yui-ext library. I am going to try and spend some time this weekend addressing them.

I am going to stop working on the edit grid for now as I can’t find a way to implement the localised editor functions for the cells. Not a way that GWT can do it in a java fashion anyway. This is most annoying as there is a fair bit of the usage done.

There is a push on just now over at the yui-ext site to get Ext out the door. I have recieved requests as to whether I will be wrapping this and I have to say for now, no. It will have to get to a stable condition before I could attempt it and even then I think it will be too much work for me to take on.

The existing yui-ext library as far as gwt-yui-ext is concerned will forever be 0.3.3. This doesn’t discount it’s usefulness though there are limitations which I am starting to see now that people have been using the trunk code.

Learning Flex

I have implemented the majority of the edit grid functionality for gwt-yui-ext. I have a hit a snag though and keep meaning to get back to it.

For now, I have been working my way through Adobe Flex 2: Training from the Source. I’m about a quarter of the way through so far and reckon it will take me another two weeks to finish since I am only getting about an hour each evening to look at this.

The reason I started to look at Flex was because of my trial implementation of the Flex/GWT integration through FABridge. I figured I’d be better off knowing it well before I tried to skin some of the actionscript classes using GWT. Whether I’ll ever try this or not is debatable but in the meantime Flex has caught my interest. My only gripe so far is that FlexBuilder 2 is horrendously expensive! Particularly in the UK. I can’t afford it, so once the trial is up it’s back to the command line for me.

← Previous PageNext Page →