Skip to content

Instantly share code, notes, and snippets.

@odoe
Created July 12, 2010 22:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save odoe/473165 to your computer and use it in GitHub Desktop.
Save odoe/473165 to your computer and use it in GitHub Desktop.
<?xml version="1.0" encoding="utf-8"?>
<s:ItemRenderer xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
autoDrawBackground="true">
<fx:Metadata>
[Event(name="visibleLayerID", type="org.lacsd.events.LayerInfoDetailsEvent")]
</fx:Metadata>
<fx:Script>
<![CDATA[
import org.lacsd.events.LayerInfoDetailsEvent;
protected function onCheckBoxClicked_handler(e:MouseEvent):void {
var v:Boolean = e.currentTarget.selected;
var d:int = int(data.id);
dispatchEvent(new LayerInfoDetailsEvent(LayerInfoDetailsEvent.VISIBLE_LAYER_ID, d, v));
}
]]>
</fx:Script>
<s:CheckBox left="0"
selected="{data.defaultVisibility}"
label="{data.name}"
click="onCheckBoxClicked_handler(event)"/>
</s:ItemRenderer>
package org.lacsd.components {
import com.esri.ags.layers.ArcGISDynamicMapServiceLayer;
import com.esri.ags.layers.ArcGISTiledMapServiceLayer;
import com.esri.ags.layers.Layer;
import com.esri.ags.layers.supportClasses.LayerInfo;
import mx.collections.ArrayCollection;
import mx.logging.ILogger;
import org.lacsd.events.LayerInfoDetailsEvent;
import org.lacsd.util.LogUtil;
import spark.components.List;
import spark.components.supportClasses.SkinnableComponent;
/**
* This component holds detailed information on all layers within a given service.
* @author rrubalcava
*/
public class LayerInfoDetails extends SkinnableComponent {
private static const logger:ILogger = LogUtil.getLogger(LayerInfoDetails);
/**
* Constructor
*/
public function LayerInfoDetails() {
super();
}
[SkinPart(required="true")]
/**
* List that will display the <code>LayerInfos</code> data.
* @default
*/
public var layerControl:List;
[Bindable]
/**
* Backing variable for ready-only property <code>layer</code>.
* @default
*/
protected var _layer:Layer;
/**
* Collection that will contain the <code>LayerInfos</code> data.
* @default
*/
protected var infos:ArrayCollection;
/**
* Function will be verify that defaultVisibility value will match the vivisbleLayers of an <code>ArcGISDynamicMapServiceLayer</code>.
* @param layerInfo
*/
protected function cleanLayerInfos(layerInfo:LayerInfo):void {
var ac:ArrayCollection = (_layer as ArcGISDynamicMapServiceLayer).visibleLayers;
layerInfo.defaultVisibility = ac.contains(String(layerInfo.id));
}
/**
* Function will extract LayerInfos data from the given service.
*/
protected function findLayerDetails():void {
var layerInfos:Array;
if (_layer is ArcGISDynamicMapServiceLayer)
layerInfos = ArcGISDynamicMapServiceLayer(_layer).layerInfos;
else if (_layer is ArcGISTiledMapServiceLayer)
layerInfos = ArcGISTiledMapServiceLayer(_layer).layerInfos;
else
logger.warn("Not a layer I care about, do nothing");
if (layerInfos) {
var rootLayers:Array = this.findRootLayers(layerInfos);
for each (var layerInfo:LayerInfo in rootLayers) {
logger.debug("check layerInfo: {0}", layerInfo);
this.cleanLayerInfos(layerInfo);
infos.addItem(layerInfo);
}
}
}
/**
* Function to find the root layers of a LayerInfos Array.
* @param layerInfos
* @return
*/
protected function findRootLayers(layerInfos:Array):Array {
var roots:Array = [];
for each (var layerInfo:LayerInfo in layerInfos) {
// ArcGIS: parentLayerId is -1
// ArcIMS: parentLayerId is NaN
if (isNaN(layerInfo.parentLayerId) || layerInfo.parentLayerId == -1) {
roots.push(layerInfo);
}
}
return roots;
}
/**
* Function will adjust the visible layers of a Layer based on changes made in <code>layerControl</code>
* @param strIndex
*/
protected function layerVisibility(strIndex:String):void {
var ac:ArrayCollection = (_layer as ArcGISDynamicMapServiceLayer).visibleLayers;
if (ac.contains(strIndex))
ac.removeItemAt(ac.getItemIndex(strIndex));
else
ac.addItem(strIndex);
// once a visible layer has been added or removed, need to refresh the service
_layer.refresh();
}
/**
* Function to process any changes made in <code>layerControl</code>.
* @param e
*/
protected function onLayerInfoDetailsUpdated(e:LayerInfoDetailsEvent):void {
logger.debug("layer info details updated, layer id = {0} | visible = {1}", e.layerID, e.visible);
e.stopImmediatePropagation();
for each (var item:LayerInfo in infos) {
if (item.id == e.layerID) {
logger.debug("layer found, set visibility, layer id = {0} | visible = {1}", e.layerID, e.visible);
item.defaultVisibility = e.visible;
}
}
if (_layer is ArcGISDynamicMapServiceLayer) {
var ac:ArrayCollection = (_layer as ArcGISDynamicMapServiceLayer).visibleLayers;
var strIndex:String = String(e.layerID);
this.layerVisibility(strIndex);
}
}
override protected function partAdded(partName:String, instance:Object):void {
super.partAdded(partName, instance);
logger.debug("adding part to skinnable component: {0}", instance);
if (instance == layerControl) {
infos = new ArrayCollection();
layerControl.dataProvider = infos;
layerControl.addEventListener(LayerInfoDetailsEvent.VISIBLE_LAYER_ID, onLayerInfoDetailsUpdated);
}
}
override protected function partRemoved(partName:String, instance:Object):void {
super.partRemoved(partName, instance);
logger.debug("remove part to skinnable component: {0}", instance);
if (instance == layerControl)
layerControl.removeEventListener(LayerInfoDetailsEvent.VISIBLE_LAYER_ID, onLayerInfoDetailsUpdated);
}
/**
* Clean up function for this object.
*/
public function dispose():void {
logger.debug("set object properties to null");
if (infos)
infos = null;
if (_layer)
_layer = null;
}
/**
* Read-only setter for Layer object.
* @param value
*/
public function set layer(value:Layer):void {
if (_layer != value) {
_layer = value;
logger.warn("Setting layer");
this.findLayerDetails();
}
}
}
}
<?xml version="1.0" encoding="utf-8"?>
<s:Skin xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx">
<!-- host component -->
<fx:Metadata>
[HostComponent("org.lacsd.components.LayerInfoDetails")]
</fx:Metadata>
<!-- SkinParts
name=layerControl, type=spark.components.CheckBox, required=true
-->
<s:VGroup width="100%">
<s:List id="layerControl" width="100%"
itemRenderer="org.lacsd.components.itemRenderers.LayerInfoDetailItemRenderer"/>
</s:VGroup>
</s:Skin>
<?xml version="1.0" encoding="utf-8"?>
<s:ItemRenderer xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
autoDrawBackground="true"
xmlns:components="org.lacsd.components.*"
width="150"
creationComplete="onCreationComplete_handler(event)">
<fx:Metadata>
[Event(name="layerDetailsRemoved", type="flash.events.Event")]
[Event(name="detailsAdded", type="flash.events.Event")]
[Event(name="detailsRemoved", type="flash.events.Event")]
</fx:Metadata>
<s:states>
<s:State name="normal"/>
<s:State name="hovered"/>
<s:State name="selected"/>
</s:states>
<s:Rect left="0"
right="0"
top="0"
bottom="0">
<s:fill>
<s:SolidColor color="#F0F8FF"
alpha="0.6"/>
</s:fill>
</s:Rect>
<s:Rect left="0"
right="0"
top="0"
bottom="0">
<s:fill>
<s:SolidColor color="#F0FFFF"
alpha="0.6"/>
</s:fill>
</s:Rect>
<s:Group id="vGroup"
left="0"
right="0"
top="0"
bottom="0"
width="100%">
<s:layout>
<s:VerticalLayout gap="2"
paddingBottom="2"
paddingLeft="2"
paddingRight="2"
paddingTop="2"/>
</s:layout>
<s:CheckBox left="0"
selected="{data.visible}"
label="{data.id}"
click="onCheckBoxClicked_handler(event)"/>
<s:HSlider width="100%"
value="{data.alpha}"
minimum="0"
maximum="1"
snapInterval="0"
change="onAlphaChanged(event)"/>
</s:Group>
<fx:Script>
<![CDATA[
import com.esri.ags.layers.ArcGISDynamicMapServiceLayer;
import com.esri.ags.layers.Layer;
import org.lacsd.components.LayerInfoDetails;
import spark.components.Button;
protected var details:LayerInfoDetails;
protected function onCheckBoxClicked_handler(e:MouseEvent):void {
data.visible = e.currentTarget.selected;
}
protected function onAlphaChanged(e:Event):void {
data.alpha = e.currentTarget.value;
}
protected function onCreationComplete_handler(e:Event):void {
if (data is ArcGISDynamicMapServiceLayer) {
var btn:Button = new Button();
btn.width = 10;
btn.height = 10;
btn.addEventListener(MouseEvent.CLICK, onDetailsButtonClicked_handler, false, 0, true);
vGroup.addElement(btn);
}
}
protected function onDetailsButtonClicked_handler(e:MouseEvent):void {
if (details) {
vGroup.removeElement(details);
details.removeEventListener(Event.ADDED_TO_STAGE, onDetailsIsReady_handler);
details.dispose();
details = null;
dispatchEvent(new Event("detailsRemoved", true));
}
else {
details = new LayerInfoDetails();
details.addEventListener(Event.ADDED_TO_STAGE, onDetailsIsReady_handler, false, 0, true);
details.width = this.width - 4;
vGroup.addElement(details);
details.layer = data as Layer;
}
}
protected function onDetailsIsReady_handler(e:Event):void {
dispatchEvent(new Event("detailsAdded", true));
}
]]>
</fx:Script>
</s:ItemRenderer>
package org.lacsd.components {
import com.esri.ags.Map;
import com.esri.ags.events.MapEvent;
import com.esri.ags.layers.Layer;
import flash.events.Event;
import mx.collections.ArrayCollection;
import mx.core.IVisualElement;
import mx.logging.ILogger;
import org.lacsd.events.LayerInfoDetailsEvent;
import org.lacsd.util.LogUtil;
import spark.components.List;
import spark.components.SkinnableContainer;
/**
* MapLayerList is a component that will add Layers from the Map object
* into a custom List for various Layer control
* @author rrubalcava
*/
public class MapLayerList extends SkinnableContainer {
private static const logger:ILogger = LogUtil.getLogger(MapLayerList);
/**
* Constructor
*/
public function MapLayerList() {
super();
}
[SkinPart(required="true")]
/**
* Required List that must be in Skin
* @default
*/
public var layerList:List;
/**
* Backing variable for <code>map</code> object
* @default
*/
protected var _map:Map;
[Bindable]
/**
* Collection hold Map Layers, used to control what layers are listed
* @default
*/
protected var layers:ArrayCollection;
/**
* Regular Expression to prevent random GraphicsLayers from being added to List.
* Using regular expression, because there may be cases where you want
* a user to control a GraphicsLayer, in which case you should give it a
* distinctive name.
* @default
*/
protected var reg1:RegExp = /GraphicsLayer\w/;
/**
* Regular Expression to prevent random FeatureLayers from being added to List.
* Using regular expression, because there may be cases where you want
* a user to control a FeatureLayer, in which case you should give it a
* distinctive name.
* @default
*/
protected var reg2:RegExp = /FeatureLayer\w/;
/**
* Load the current contents of Map object
*/
protected function initialListLoad():void {
layers = new ArrayCollection();
for each (var lyr:Layer in map.layers) {
if (!reg1.test(lyr.id) && !reg2.test(lyr.id)) {
layers.addItem(lyr);
logger.info("Adding layer to list: {0}", lyr);
}
}
}
/**
* Adjust height of the <code>layerList</code> when details are closed.
* @param e
*/
protected function onDetailsHide_handler(e:Event):void {
e.stopPropagation();
var h:Number = 0;
var x:Number = layerList.dataGroup.numElements;
var v:IVisualElement = layerList.dataGroup.getElementAt(0);
if (v) {
h = v.height;
layerList.height = (h * x) + (x * 2);
}
}
/**
* Adjust height of the <code>layerList</code> when details are shown.
* @param e
*/
protected function onDetailsShow_handler(e:Event):void {
e.stopPropagation();
layerList.percentHeight = 100;
}
/**
* Load any new layers that get added to Map object
* @param event
*/
protected function onMapLayerAdded(e:MapEvent):void {
if (!reg1.test(e.layer.id) && !reg2.test(e.layer.id))
layers.addItem(e.layer);
}
/**
* Remove Layers from List that get removed from Map object
* @param e
*/
protected function onMapLayerRemoved(e:MapEvent):void {
layers.removeItemAt(layers.getItemIndex(e.layer));
}
override protected function partAdded(partName:String, instance:Object):void {
super.partAdded(partName, instance);
if (instance == layerList) {
layerList.dataProvider = layers;
layerList.addEventListener("detailsAdded", onDetailsShow_handler, true, 0, true);
layerList.addEventListener("detailsRemoved", onDetailsHide_handler, true, 0, true);
}
}
override protected function partRemoved(partName:String, instance:Object):void {
super.partRemoved(partName, instance);
if (instance == layerList) {
layerList.removeEventListener("detailsAdded", onDetailsShow_handler, true);
layerList.removeEventListener("detailsRemoved", onDetailsHide_handler, true);
}
}
/**
* Clean up when component is closed.
*/
public function dispose():void {
logger.debug("Dispose of listeners and properties, prepare for gc: {0}", this);
layerList.removeEventListener("detailsAdded", onDetailsShow_handler, true);
layerList.removeEventListener("detailsRemoved", onDetailsHide_handler, true);
_map.removeEventListener(MapEvent.LAYER_ADD, onMapLayerAdded);
reg1 = null;
reg2 = null;
layerList = null;
layers = null;
_map = null;
}
[Bindable("mapChanged")]
/**
* Target Map object that contains Layers
* @return
*/
public function get map():Map {
return _map;
}
/**
* When Map object is set, add listeners and load initial Layers
* @param value
*/
public function set map(value:Map):void {
if (_map != value) {
_map = value;
_map.addEventListener(MapEvent.LAYER_ADD, onMapLayerAdded, false, 0, true);
this.initialListLoad();
dispatchEvent(new Event("mapChanged"));
}
}
}
}
<?xml version="1.0" encoding="utf-8"?>
<s:Skin xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:comps="org.lacsd.components.*">
<!-- host component -->
<fx:Metadata>
[HostComponent("org.lacsd.components.MapLayerList")]
</fx:Metadata>
<s:states>
<s:State name="disabled"/>
<s:State name="normal" />
</s:states>
<!-- SkinParts
name=layerList, type=mx.controls.List, required=true
-->
<s:List id="layerList" width="100%"
itemRenderer="org.lacsd.components.itemRenderers.LayerListItemRenderer"/>
</s:Skin>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment