Thursday, August 7, 2008

WMS Overlays in Google Maps for Flash

While working on BiodiversityAtlas I thought on overlaying distributions using a Geoserver WMS server together with Google Maps for Flash. Well, actually I started working on Umap but then moved to Google Maps. At this moment there were no examples of overlaying WMS with this mapping engines so I worked on it. Now you can find a much better work than mine for Umap here, and in this post I do the same for Google Maps.

Here is the link to the demo with source code view enabled if you just want to see and get the code:

http://biodiversityatlas.com.s3.amazonaws.com/gmapwms/GoogleMapsWMSOverlay.html


Basically it extends Google TileLayerBase and in the loadTile method it generates a WMS Url request converting the x,y,z parameters of tiles to ESPG:900913 . This ESPG has been created to overlay WMS in Google maps so it is aware of the different projections of Google Maps at different zoom levels, so probably you get the best overlay possible.
The trickiest part of the class was converting the x,y,z parameters into coordinates because it involves some reprojection of coordinates that I never really undertood, but that is available from different Javascript Map clients.

Still the support of WMS in Google is quite poor because of the lack of a TileLayerOverlay class on the library. So right now you have to bind your overlay to one maptype and if the user changes it then it disappear. There are hacks to emulate all basic Google MapTypes toegther with the overlay but it is a very poor solution. If you change your MapType you dont want your Overlay to ge trefreshed too. But... hopefully it will be solved soon.

The other missing thing I see is the lack of a method to enforce a redraw of the overlay. In my case the WMS overlay requests include a filter in the URL. My WMS overlay is not static, it is a database of species data, so it only make sense to visualize it with a filter specifying which species you want to see. In the application I let the user choose a species and then I change dynamically the filter in the overlayed class. Of course then I need a refresh of the Overlay but there is no way to do it through the google library. Now I am using a hack as simple as changing 1 pixel the size of the map and therefore enforcing a refresh of the layers on the map. But this is not optimal for several reasons:
  1. Resizing the map is SLOOOOW and the performance is horrible.
  2. When the map refreshed it refreshes all layers, including the ones from google that I dont want to get refreshed, I only want mines to get refreshed! The result is an ugly effect for the user.
Additionally would be great if there is a way to get noticed on when tiles had finished being
loaded for a certain Layer. This would allow to display notifications to the user on when all the
data is ready on the map. In the case of Google Tiles it is pretty obvious for the user when the
data has been loaded. You see the map or not. But in custom TileLayers with little information
on them that overlay over the map, it can be hard for the user to notice if he is seeing all the
data coming from the server.

Hey but I am very happy in general with the Google Maps for Flash API, these guys are doing a great job and Pamela Fox (Google Employee) is very nice on the mailing list solving questions. I just wish Google would spend a little bit more resources so we get new features quicker :)

I still haven't talked about how I solved drawing thousands of polygons efficiently on the map dynamically from user input and lot of curious stuff I am doing for the BiodiversityAtlas Editor. Other thing I am working is on Heat Maps, this should be finished by the end of the week :) Keep tune!

11 comments:

Unknown said...

Hi,

I am experimenting with your class. I am using a local geoserver wms.
I am stuck in a point and I cannot manage to go forward. The map look like :
http://www.flickr.com/photos/giil_taws/2807753093/sizes/o/

Could you give me a hint on a solution ?

Thanks a lot
Gilles

Javier de la Torre said...

Hi gilles,

Thats weird. It looks like if you are always performing the same WMS request to the server. Have you changed something from the class I posted?
Other thing you can check out is if you are using Google Maps for Flash 1.5 as in the example. They have introduced modifications on 1.6 that might change the behaviour.

I will not update the example until 1.7 as they are promising new classes that will do the same job in a much nicer way.

If you still have problems send me the code and I'll see what i can do (jatorre[at]gmail.com)

Anonymous said...

Thank you very much for posting this code Javier !

I have adapted it to work with our Demis WMS product using simply lat-lon, which works pretty good when zoomed in further then level 4 or 5.
In tandem with a specific tile caching script on the server, the performance is just amazing.

You can see the demo online here:

http://www4.demis.nl/gwms/

After some more testing we will be releasing our version of the code on our support site, just let me know if you are interested to see what we did to your code ;-)

Javier de la Torre said...

Hey Bart,

Sure I am interested! I will have to come back to use WMS overlay in Google Maps for Flash in the next weeks so I was thinking in spending a little bit more of time on this.

One thing I am very interested is in trying the new TileLayerOverlay class in the Google API.

Anonymous said...

Hi Javier.

Using the tile overlay is simple, you just create a class to extend TileLayerOverlay, then in the constructor pass on your existing custom TileLayer to super() ;-)

Please send me a note at support@demis.nl and I'll send you my version of the WMS classes.

You may want to cook up a server caching script like I did, that will work just great for any WMS server but yours will have to be a .JSP ?

Cheers, Bart

Anonymous said...

your example is very nice .

Anonymous said...

your code is really good work fine for more than 4 zoom level but I want code that work for all zoom level could you suggest which changes I make in code so it works fine.

Javier de la Torre said...

It is an issue with projection. If you aré using geoserver as wms then you can use srs 900913 but the formulas in the class change as this make use of pixels to define the bounding box. If you are on arcgis then the srs is different, I don't remember it, but I can check.

The issue is that from zoom level 4 google is using almost 4326 but with lower zoom levels it changes to something else, simple Mercator?. In any case. I should probably do another blog post about it with the different code I have been using to connect to multiple wms servers.

Anonymous said...

Hi Javier,
Thanks for your response.
I am using geoserver1.7.4 and I registered all layers using 4326 srs.
I am setting tiles on google map using getmap request .Now deviation of tiles at lower zoom level is a big problem for me as I have to show tiles at every zoom level.

Rasmikant said...

I am using this script but unable to show my wms layer on googlemap. I am using geoserver WMS service. When Compiling its showing [SWF] /geoserver/wms - 0 bytes after decompression, in flex builder.

I dont know What I am doing wrong. Pls Guide me.

Javier de la Torre said...

Hey,

This code now is way too old.

There is some examples I believe on the mailing list. But basically the idea is to create a class that extend TileLayerBase and include in the loadtile method the same code in this example. Then you can add this layer to the map by using a TileLayerOverlay.

If you don't find your way doing so, let me know and I will try to post an example.