Showing posts with label esri. Show all posts
Showing posts with label esri. Show all posts

Wednesday, December 9, 2009

Highlight Map from List Items

I was inspired by this posting on the ESRI ArcGIS Server Blog filed in the Flex tag, that linked your graphics on a map with a DataGrid. This is a useful function and one I thought could be encapsulated into it's own task. In my case, I just had a need to highlight a graphic on my map that was associated with a list. I did not need to highlight the list when I hovered over the map because I have designed my Graphics with tooltips and felt that two-way binding would be "too much" flash for business purposes. You certainly encapsulate that function and if I were to do so, would probably build it into a utility type of class. With that said, here is the code.
package net.odoe.model.graphic
{
import com.esri.ags.Graphic;
import com.esri.ags.geometry.Geometry;
import com.esri.ags.layers.GraphicsLayer;
import com.esri.ags.symbol.SimpleFillSymbol;
import com.esri.ags.symbol.SimpleLineSymbol;
import com.esri.ags.symbol.SimpleMarkerSymbol;
import com.esri.ags.symbol.Symbol;

public class HighlightGraphic extends Graphic
{
protected var _defaultSymbol : Symbol = new Symbol();

/**
* This function will save the default graphic symbology
* highlight the graphic for the currently selected item.
* @param data that holds attribute information; i.e. from a ListEvent (event.itemRenderer.data).
* @param graphicsLayer that holds the graphics that can be selected.
* @return a higlighted graphic.
*
*/
public function setHighlightGraphic( data : Object, graphicsLayer : GraphicsLayer ) : Graphic {
if( graphicsLayer ) {
_defaultSymbol = findGraphicByAttribute( data , graphicsLayer).symbol;
return featureHighlight( data, graphicsLayer );
}
return new Graphic();

}

/**
* This function will reset the previously selected graphic
* to its default symbology.
* @param data that holds attribute information; i.e. from a ListEvent (event.itemRenderer.data).
* @param graphicsLayer that holds the graphics that can be selected.
* @return default graphic.
*
*/
public function resetDefaultGraphic( data : Object, graphicsLayer : GraphicsLayer ) : Graphic {
if( graphicsLayer ) {
var _graphic : Graphic = findGraphicByAttribute( data, graphicsLayer );
_graphic.symbol = _defaultSymbol;
return _graphic;
}

return new Graphic();

}

//------------------------------------------------------------------------------------------------------
//----PROTECTED METHODS---------------------------------------------------------------------------------
//------------------------------------------------------------------------------------------------------
protected function findGraphicByAttribute( attributes : Object, graphicsLayer : GraphicsLayer ) : Graphic {
for each( var graphic : Graphic in graphicsLayer.graphicProvider ) {
if ( graphic.attributes == attributes )
{
return graphic;
}
}
return new Graphic();
}

protected function featureHighlight( data : Object, graphicsLayer : GraphicsLayer ) : Graphic {
if( graphicsLayer ) {
var _graphic : Graphic = findGraphicByAttribute( data, graphicsLayer );
_graphic.symbol = highLightSymbol( _graphic.geometry );
return _graphic;
}

return new Graphic();
}

protected function highLightSymbol( geometry : Geometry ) : Symbol {
if( geometry.type == Geometry.POLYLINE ) {
var _highlightLineSymbol : SimpleLineSymbol = new SimpleLineSymbol;
_highlightLineSymbol.color = 0xFF00FF;
_highlightLineSymbol.width = 10;

return _highlightLineSymbol;
}
if( geometry.type == Geometry.MAPPOINT ) {
var _outline : SimpleLineSymbol = new SimpleLineSymbol;
_outline.style = "solid";
_outline.color = 0x0000CD;
_outline.width = 2;

var _highlightPtSymbol : SimpleMarkerSymbol = new SimpleMarkerSymbol;
_highlightPtSymbol.style = "circle";
_highlightPtSymbol.color = 0xFF00FF;
_highlightPtSymbol.size = 15;
_highlightPtSymbol.alpha = 1;
_highlightPtSymbol.outline = _outline;

return _highlightPtSymbol;
}
if( geometry.type == Geometry.POLYGON ) {
var _outlinePoly : SimpleLineSymbol = new SimpleLineSymbol();
_outlinePoly.style = "solid";
_outlinePoly.color = 0x0000CD;
_outlinePoly.width = 2;

var _highlightPolySymbol : SimpleFillSymbol = new SimpleFillSymbol;
_highlightPolySymbol.style = "solid";
_highlightPolySymbol.color = 0x00FFFF;
_highlightPolySymbol.alpha = 0.3;
_highlightPolySymbol.outline = _outlinePoly;

return _highlightPolySymbol;
}

return new Symbol();
}

}
}


I have made the functions in here protected, as I found a need at a later time to extend this class and override the protected function findGraphicByAttribute to recognize a particular attribute field (i.e. graphic.attributes.Name == attributes.Name) and not just all attributes.

I made an example of the function just like the one on the ESRI ArcGIS Server Blog using my class.
It can be found here with View Source enabled. Hope this benefits someone.

Wednesday, November 4, 2009

ESRI Flex Application using Presentation Model Pattern with Swiz

So continuing on my quest to be a better developer, I have really dived in deep to the Swiz framework.I have learned quite a bit since my last postings and I think I have gotten a really solid grasp on how to leverage the framework to meet my needs. Inspired by Ben Clinkinbeard's Presentation Model Pattern using Swiz, I set out to try and build an ESRI web mapping sample in the same manner.

So, I read through some of this in addition to Ben's example above and this how I interpreted using the Presentation Model Pattern.

( I prefer yellow sticky notes for complex explanations )

What I liked about this pattern was that I'm able to keep the view as dumb as possible, so less can go wrong from here. The Presentation Model represents what happens in the view including values and events. The Presentation Model is responsible for dispatching events you would normally dispatch from the view. Controller does the work, utilizing delegates when needed and updating Autowired values to the model. If you look at the source for my example, you'll see I made some comments about having issues with a couple of Autowired items that I could not get to update directly in the Controller, I had to set custom setValues(value:Object) setters for the model and use that. I would prefer the Controller not even be aware of the model, and I think I may be able to accomplish this with an IEventDispatcher and using the Controller as a Protocol in my SwizConfig, but for the points I was trying to illustrate, I don't think it was really needed here.

You may also notice I am using FlexUnit 4 to do some testing. I am just now starting to utilize unit testing as I build my applications and FlexUnit 4 has some nice features I am playing with. Testing is part of the reason I want to try and keep my Presentation Models and my Controllers as independent of each other as much as I can, to prevent any funny business from occurring when I try to maintain my tests as an application grows.

This is just another of my experiments in my quest to be a better developer. As I have said before, I just kind of fell into this, so a lot of these concepts are still new to me. I'm fairly comfortable with the ESRI Flex API at this point. Now, I'm trying to really grasp how to use design patterns and testing practices to improve my work.

Friday, October 23, 2009

Swiz and the ESRI API, we meet again.

So, I spent quite a bit of time this week really trying to wrap my head around using the Swiz framework with the ESRI Flex API. I found the actual Swiz website, which somehow never came up in all my earlier research. It gave me some details on things I wasn't clear on before.

I also found this video by Joe Rinehart, Swiz in 20 minutes.
Videos like this are great, because it just helps to hear and see someone go through it from start to finish. With my new found information, I was ready to tackle a new version of the application I posted earlier. What I have found, is the Swiz framework really gives you a lot of freedom in how you actually want to write your code. How I use it in my style, may not work for someone else's style. I really like that. You can also get a good explanation of the framework and metadata here.

So, rewrote my previous example, to incorporate a tighter distinction between views and controllers. Found here (source available).
I now make liberal use of the Autowire metadata, which links all my functions and variables through my beans. I'm also making good use of the Mediate tag, that will capture events.

For example, in my Controller, I have this.
public static const QUERY_LAYER : String = "queryLayer";

Then, from any other view or controller, I can use this.
Swiz.dispatchEvent( new Event( LayerController.QUERY_LAYER ) );

In my Controller, I have this.
[Mediate( event="queryLayer" )]
public function queryStateLayer() : void {
trace( "begin queryStateLayer" );
Swiz.dispatchEvent( new Event( LayerController.LOAD_STARTED ) );
var query:Query = new Query();
query.returnGeometry = false;
query.outFields = [ "STATE_NAME", "AREA" ]
query.where = "STATE_NAME <> ''";
AsyncToken( stateDelegate.execute( query ).addResponder( new Responder( state_results, state_fault ) ) );
}

Using the Mediate metadata, telling it to watch for the "queryLayer" event, it will fire this function whenever that occurs.

As can be seen above, I am using the AsynToken function to call a delegate that will execute my query task. You don't need to use a delegate. You could execute your task directly in the controller. I like to keep my delegates separate only because it makes sense to me, as my first framework was Cairngorm and that was pretty standard. I also think it keeps the controller a little cleaner.

My biggest hurdles were trying to interpret many of the Swiz tutorials to fit into an application with an ESRI Map control, where you want interaction between the map, the layers and your controls. Swiz now supports adding Views to your beans, although from what I have read, you may want to do so only in special circumstances. But that could be another option, is to add the Map into your beans and open it up to all controllers and functions in your application.

One big hurdle that I have not been able to figure out is Unit Testing with the Swiz framework. I have tried with Fluint and Flex Unit to no avail, although I have heard that the Autowire and separation of controllers should really make this a simple task, especially in Fluint. When I try in Fluint, I load my beans in override setUp. I Autowire my controller and models as I think I should. I can dispatch an event to my controller and my trace show that my app runs just as it should, but when I check an Autowired value such as an ArrayCollection, it's null, even though it should not be. It's driving me nuts. I'm having the same issue with Flex Unit, my application traces show everything runs, but at the end, my Autowire values are still null.

If someone could look at my example and maybe write a quick Fluint or Flex Unit test for say the StateListCollection, I would be eternally grateful as it would really just push me in the right direction. I was hoping to incorporate unit testing from the very beginning of all my future applications, but this is really just killing me now.