Flex: UMap WMS Custom Provider Traffic Demo

Here is another UMap WMS Provider demo

This is the Glasgow traffic data from here and applied to a WMS feed from here.

This uses the UMap component from AFComponents.

IFrame Map App

Right-click to view the source.

The WMS feed is defined in the ‘DataModel.as’ class.

public static var WMS_TILE_URL:String = “http://www2.demis.nl/wms/wms.ashx”;

public static var WMS_TILE_LAYERS:String =
“Topography,Builtup%20areas,Coastlines,Waterbodies,Inundated,Rivers,Streams,
Railroads,Highways,Roads,Trails,Borders,Cities,Settlements,
Spot%20elevations,Airports,Ocean%20features”;

public static var WMS_LAYER_FORMAT:String = “Image/png”;

This doesn’t use the OSGR conversions of the previous demo and instead uses the straight WGS84 projection “EPSG:4326”.

Update #1

Updated to new version of UMap control 1.1 02/08/08. See here.

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.