Select to view content in your preferred language

Creating Component/Widget Libary without MapViewer

704
3
11-01-2010 09:22 AM
DylanRoy
Emerging Contributor
Hello,

I would like to create a component library that can interface with the ESRI ArcGIS library. I have already added some actionscript components that allow for the user to drag visual components onto the mxml in the design view. I am unable to create a custom component that can retrieve data from ESRI's map widget. I don't want to be forced make handlers for the ESRI components that are already there.

Deliverable:
A library that can interface with ArcGIS library and allows for components to be dropped into the mxml when in the design view of Flash Builder like ESRI's already existing Map components.

A sample workflow for this would be:
1. Drop Esri's Map component and set the source.
2. Drop custom component(i.e. latlog detector)

If anything is unclear please let me know.

Thanks!
Tags (2)
0 Kudos
3 Replies
Drew
by
Frequent Contributor
dkroy,

As you may know you can create a custom lib in Flex/Flash Builder by going to File->New Flex Lib Project.

The build action of this type of file is a SWC and this is how other projects can reuse your components.

No matter what each component will have to have a "Map" property so you know about the map and can work with its properties and events. An example of this might be:

 <Coordinates:Viewer MapControl="{myMap}" left="10" right="10" top="10">
 </Coordinates:Viewer>


A quick sample of the code for this component would be:

<?xml version="1.0" encoding="utf-8"?>
<mx:VBox creationComplete="creationCompleteHandler(event)"
      xmlns:fx="http://ns.adobe.com/mxml/2009" 
   xmlns:s="library://ns.adobe.com/flex/spark" 
   xmlns:mx="library://ns.adobe.com/flex/mx" 
   width="400" 
   height="58" 
   paddingLeft="10" paddingTop="10" paddingBottom="10" paddingRight="10" backgroundColor="#606060">
 
 <fx:Script>
  <![CDATA[
   import com.esri.ags.Map;
   import com.esri.ags.geometry.MapPoint;
   import mx.events.FlexEvent;
   import mx.events.MoveEvent;
   
   public var MapControl:Map;
   
   [Bindable]
   public var X:Number = 0;
   
   [Bindable]
   public var Y:Number = 0;

   protected function creationCompleteHandler(event:FlexEvent):void
   {
    this.MapControl.addEventListener(MouseEvent.MOUSE_MOVE, onMapMouseMove);
   }
   
   private function onMapMouseMove(event:MouseEvent):void{
    var screenPoint:Point = new Point(event.localX, event.localY);
    var mapPoint:MapPoint =  this.MapControl.toMap(screenPoint);
    this.X = mapPoint.x;
    this.Y = mapPoint.y;
   }

  ]]>
 </fx:Script>
 
 <s:Label text="{this.X}" id="lblX"/>
 <s:Label text="{this.Y}" id="lblY"/>
</mx:VBox>



Once you have your custom component somewhat built you can add a SWC Project to a new Flex Project to test. You can add your newly created library to a new Flex Project by going to:

- Right click on your test project
- Select properties
- Navigate to "Flex Build Path"
- Select the "Library Path" tab
- Choose "Add Project" and chose your new custom library

Attached is a custom component library with the sample i showed above - download, unzip and then import into your workspace.

Hope this helps in some way..

Drew
0 Kudos
DylanRoy
Emerging Contributor
Thanks Drew,

That is exactly what I was looking for. For some reason it didn't click with me that I could add the map as a Bindable data-source and just link it like you did so well. I was hoping to not be forced into having the user of the components type in any code, but what they have to input is necessary and very minimal they would just have to add the attribute MapControl="{map}".

If anyone else would like to test this, and some example code for your flex application could be:
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
      xmlns:s="library://ns.adobe.com/flex/spark" 
      xmlns:mx="library://ns.adobe.com/flex/mx" 
      minWidth="955" minHeight="600" 
      xmlns:esri="http://www.esri.com/2008/ags" 
      xmlns:Coordinates="Coordinates.*">
 <fx:Declarations>
  <!-- Place non-visual elements (e.g., services, value objects) here -->
 </fx:Declarations>
 <esri:Map id="map">        
  <esri:ArcGISTiledMapServiceLayer            
                  url="http://server.arcgisonline.com/ArcGIS/rest/services/ESRI_StreetMap_World_2D/MapServer"
  />

 </esri:Map>
 <Coordinates:Viewer MapControl="{map}" bottom="0" right="0">
 </Coordinates:Viewer>
</s:Application>


Everything but the attributes for the Viewer and the url for the Map were generated by dragging and dropping components, which are highlighted in red.

Once again, thanks Drew.

dkroy
0 Kudos
Drew
by
Frequent Contributor
dkroy,

Glad it worked so well.

If you wanted to take it one step further you could create a base component that contains the map as a default property and have some error checking built in place to ensure its added at runtime.

Then you would simply extend that base class for each new component you build. This would save you some time creating new components and ensure each components checked for the map property to be set and is named the same across your entire library.

An example of a base component might be:
package
{
 import com.esri.ags.Map;
 import mx.controls.Alert;
 import mx.events.FlexEvent;
 
 import spark.components.Group;
 
 public class BaseMapComponent extends Group
 {
  private var _map:Map;
  public function get map():Map
  {
   return _map;
  }
  
  public function set map(value:Map):void
  {
   _map = value;
  }
  
  public function BaseMapComponent()
  {
   super();
   this.addEventListener(FlexEvent.CREATION_COMPLETE, onCreationComplete);
  }
  
  private function onCreationComplete(event:FlexEvent) :void
  {
   validateMapPropertyIsSet();
  }

  private function validateMapPropertyIsSet():void
  {
   if (map == null)
   {
    Alert.show("Map property for  (" + this.className + ") is not set. This tool may not work coorectly");
   }
  }
 }
}


If you wanted to get even more fancy you could check if the map property is set and if not try and find the map component by looping through the applications children recursively.  This functionality would not be good if you were planning on having more than one map on the stage though... and it could be problematic, but may be worth a test.

Attached is a new sample that contains the base map component i described above. I would suggest going this way and extend it  as needed.. It may be helpful too because if you are into skinning it might save time on that end too.

Good luck,

Drew
0 Kudos