Monday, July 26, 2010

Merging Table Of Content and Legend Info

Initially, while working on Gulf Of Mexico Response Map, the legend and table-of-content were two separate windows. That took too much real-estate, and a TOC layer was hard to correlate with the legend swatch by name only. So I set upon merging the legend window and the table-of-content into one window. There is plenty of TOC code as a visual tree component, but it is the legend UI that causes us trouble as there is no REST endpoint to get the layer swatch information. Well with the advent of FeatureLayer somebody can argue that this could be done. But you still have to go back and forth for each layer and get the rendering information. BTW, this will be remedied in 10.1, as a new REST endpoint will be introduced to get _all_ rendering information of a map service. In the meantime, I had to do something. As you can imagine the project map services were very dynamic and the layer content was changing constantly, so having a static legend is out of the question. There were attempts to create an ArcObject proxy, where the client application connects to that proxy who issues a SOAP request to an ArcGIS server for the legend info. The SOAP result is converted to JSON and forwarded back to the client for decoding and rendering. The code was written in .Net and have a Java based server. I wanted to be platform independent and have a two tier architecture (at least from a 10,000 feet perspective) and the introduction of a proxy was out of the question. So....I have to issue SOAP calls directly from the client to ArcGIS server. This is where the advent of FlashBuilder with its data connectivity option was a blessing. FlashBuilder can generate correctly stub code for ArcGIS SOAP methods based on a map service WSDL. This was impossible in FlexBuilder. Yes, it does bloat the code base a bit, but it is a small price to pay for such a dynamic system. The TOC code is based on the FlexViewer TOC code. I modified the item renderer to be of variable height to accommodate the renderer swatches as child elements. You can see the application in action here. And like usual, you can download the source code from here. Small note: First time through, it take a few seconds to get the swatches, so if you open the tree, it will look “plain” and somehow AGS returns blank swatches for tiled map services. not sure why ! have to ask the core team about that. Oh one more thing, in addition to adding the Flex API for AGS swc, make sure to include the Adobe provided fiber swcs. Until 10.1 (hopefully soon) hope this can help.
PS: If you have a 10 server - there is a REST way to get all the layers published in a map server that could be used to create swatches from the rendering information.

28 comments:

Harold said...

Sweet, I have not gotten around to merging all the TOC/Legend code out there and a collegue of mine implemented the combo for SL, and I did one for JS, now the circle is complete. This worked fast too. I have not upgraded to FlashBuilder yet, but will do so soon just to implement this on my pages. Thanks again for sharing your hard work
-hbostic

ThunderHead said...

U R Welcome

zach said...

I love you man. You are great..Thanks for sharing

gallod5 said...

My viewer allows map services to be added at run-time. The new service shows up in the toc but erros out bacause the images are not produced. Any help on what I need to call if a new service is added would be helpful. I also have made changes to how group layers work. By default when a group layer is turned on all child layers are turned on. I have made changes to the code that only turns on the child layers that should be visible based on the map service. When a user changes the child layers it remembers which ones were visible so when they turn off the parent group layer than turn it back on it only turns on the child layer that were turned on before turing parent off.

Brenden Galluzzo said...

I was able to fix my problem.

Added check on

if(legendGroup.LegendClasses)

to: getImageResult():ImageResult
and addLegendClasses(vbox:VBox):void


legendGroup.LegendClasses was returning null sometimes when adding service at runtime

Thanks this code rocks!!!!!!

Loved they way you presented at the ESRI conference.

xiaoming said...

I just imported the project in Flash Builder 4. Changed the Flex API library reference pointing to my local one. When compiling, there's an error in line "super(wsdl,service);" in the MapServer.as file. The error message is "Incorrect number of arguments. Expected no more than 0." Any clue about anything else I need to do?

thanks
xiaoming

zach said...

where can you download fiber.swc and all the other swc? can somebody please provide the URL?

ThunderHead said...

u can find the fiber swc under the FlashBuilder plugin folder

David Galluzzo said...

xiaoming the code in the zip for some resaon does not match the code in the source code viewer.
I copied two files from the source code viewer and replaced it.
MapServer.as
and _Super_Mapserver.as
you will notice in _Super_Mapserver
the constructor is set to take two arrguments

public function _Super_MapServer(wsdlURL:String, service:String)

Chih-Yu Lai said...

I do appreciate your kindly sharing. It's great.
But where could we change the fonts to let it be “Layers” instead of “Lavers”?
Thanks again.

ThunderHead said...

U r welcome - but where do u see this "laver" - working on a new version that is spark compatible !

Harold said...

Hello, do you have an update as to why tiled map services return blank images?

Thanks

ThunderHead said...

Not sure why the SOAP does that - however - all this will be deprecated as of AGS 10.1 there will be a new REST endpoint that does the same - but much lighter.

Ed said...

Has anyone tried using this with a color ramp? When I do the checkbox next to the layer which uses color ramp disappears?

Ed said...

Update: Colour ramp seems not to be the issue, the problem is I can not scroll through the list properly. The scroll bar keeps jumping around.

ThunderHead said...

Yeap - not sure what I'm doing wrong with the item renderer measure - I've even use the new Spark version and still having issues - have to revisit it one day - in the mean time - as a solution - make the tree height huge and put it in a hbox and I use the hbox to scroll - not pretty - but works for now.

tanerkoka said...

I still couldnt get the legend infos. Application works great without legends. I've got an error (agslib-snapshot.swc). How can i fix this error ?? Thanks...

ThunderHead said...

Please use the released swc - sorry !

Ed said...

I see in the TocLayerItem class you declare a lot of consts rather than vars? I am curious to know why you do this?

ThunderHead said...

Just defensive programming :-)

Dilip Wagh said...

I read this with interest, but need help in implementing the toc with swatches into a bespoke Flex Viewer as we are not using the ESRI Flex Viewer. As I have never coded before, therefore I would appreciate all the help I can get.

ThunderHead said...

Not sure I understand - Are you or are you not using the FlexViewer ?

Dilip Wagh said...

Hi, yes we are using Flex, but building our own app, as I mentioned I do not understand the legend application, as it states you need to add it into the Flex Viewer application, I cannot get it to work in ours.

Dilip Wagh said...

Hello again, at the bottom of your blog, you say there is a rest way to get a legend, have you such code and instruction to get it working, again any help is very much appreciated.

ThunderHead said...

Di you are ArcGIS 10 ? this new feature was added to the REST endpoint.

Ed said...

Update (again): a colleague found a fix for the resize issue.
Add the following in TOC class:

override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
{
this.width= measureWidthOfItems();
this.height= measureHeightOfItems();

super.updateDisplayList(unscaledWidth, unscaledHeight);
}

Tanya said...

Hi I am facing the same error which people have already posted in the comments..I am unable to find snapshot.swc and because of that I beleive I am not able to get the legends.. plus the arguments error..

I read all the posts but unable to find the solution

ThunderHead said...

Here is an updated version using the latest REST GetLegendInfo API - http://dl.dropbox.com/u/2193160/GetLegendInfoApp.zip