Firstly sorry for the really lengthy question. I am trying to implement an Org.Chart
using spark DataGrid
. The data for the Org.Chart
does not change and hence I am hard coding the values. I had to implement this Org.Chart
as I need to have floating Nodes
and also the connecting lines should be drawn a bit different when compared to using an external component. Please find the following image of which Im trying to achieve:
Here is the idea:
Each cell of the DataGrid
can be either connecting lines
or an actor
. I have a custom component MyOrgChartNode
which has two states: chartLinesState
and chartActorState
. This component is used as ItemRenderer
for DataGrid
. Here is the code of MyOrgChartNode
:
<fx:Script>
<![CDATA[
import mx.controls.Alert;
import scripts.valueObjects.ActorVO;
import scripts.valueObjects.CellRendererVO;
[Bindable]
private var _cellRenderer:CellRendererVO;
[Bindable]
private var _lineColor:uint = 0xFF0000;
[Bindable]
private var _lineWidth:int = 1;
override public function prepare(hasBeenRecycled:Boolean):void
{
if (data != null)
{
this.height = parseInt(data['cellHeight']);
if (columnIndex == 1 || columnIndex == 3)
{
this.width = 50;
}
currentState = (data[column.dataField] as CellRendererVO).stateName;
}
}
protected function orgChartNode_clickHandler(event:MouseEvent):void
{
// TODO Auto-generated method stub
}
]]>
</fx:Script>
<s:states>
<s:State name="chartLinesState" />
<s:State name="chartActorState" />
</s:states>
<s:VGroup width="100%" height="100%" includeIn="chartActorState">
<myOrgChart:OrgChartNode id="orgChartNode" width="100%" height="100%" click="orgChartNode_clickHandler(event)"
nodeActor="{(data[column.dataField] as CellRendererVO).nodeActor}" />
</s:VGroup>
<s:VGroup width="100%" height="100%" includeIn="chartLinesState">
<s:HGroup width="100%" height="100%"
gap="0" horizontalAlign="center" verticalAlign="middle">
<s:VGroup id="horizontalLeftLine" height="100%" width="100%"
horizontalAlign="center" verticalAlign="middle"
visible="{(data[column.dataField] as CellRendererVO).hasHorizontalLeftLine}">
<mx:HRule width="100%" strokeWidth="{_lineWidth}" strokeColor="{_lineColor}"
opaqueBackground="{_lineColor}"/>
</s:VGroup>
<s:VGroup height="100%" gap="0" horizontalAlign="center"
verticalAlign="middle"
includeInLayout="{(data[column.dataField] as CellRendererVO).hasVerticalTopLine || (data[column.dataField] as CellRendererVO).hasVerticalBottomLine}">
<s:VGroup id="verticalTopLine" height="50%" verticalAlign="middle"
visible="{(data[column.dataField] as CellRendererVO).hasVerticalTopLine}">
<mx:VRule height="100%" strokeWidth="{_lineWidth}" strokeColor="{_lineColor}"
opaqueBackground="{_lineColor}"/>
</s:VGroup>
<s:VGroup id="verticalBottomLine" height="50%" verticalAlign="middle"
visible="{(data[column.dataField] as CellRendererVO).hasVerticalBottomLine}">
<mx:VRule height="100%" strokeWidth="{_lineWidth}" strokeColor="{_lineColor}"
opaqueBackground="{_lineColor}"/>
</s:VGroup>
</s:VGroup>
<s:VGroup id="horizontalRightLine" height="100%" width="100%"
horizontalAlign="center" verticalAlign="middle"
visible="{(data[column.dataField] as CellRendererVO).hasHorizontalRightLine}">
<mx:HRule width="100%" strokeWidth="{_lineWidth}" strokeColor="{_lineColor}"
opaqueBackground="{_lineColor}"/>
</s:VGroup>
</s:HGroup>
</s:VGroup>
In the above code I am using a valueObject
CellRendererVO
which contains the required information for the display of the cell such as visibility of the different HRules
and VRule
present. Code for CellRendererVO
is here:
package scripts.valueObjects
{
public class CellRendererVO extends Object
{
private var _hasVerticalTopLine:Boolean;
private var _hasVerticalBottomLine:Boolean;
private var _hasHorizontalLeftLine:Boolean;
private var _hasHorizontalRightLine:Boolean;
private var _nodeActor:ActorVO;
private var _stateName:String;
public function CellRendererVO(hasVerticalTopLine:Boolean = false, hasVerticalBottomLine:Boolean = false,
hasHorizontalLeftLine:Boolean = false, hasHorizontalRightLine:Boolean = false,
nodeActor:ActorVO = null, stateName:String = "chartLinesState"
)
{
this.hasVerticalTopLine = hasVerticalTopLine;
this.hasVerticalBottomLine = hasVerticalBottomLine;
this.hasHorizontalLeftLine = hasHorizontalLeftLine;
this.hasHorizontalRightLine = hasHorizontalRightLine;
this.nodeActor = nodeActor;
this.stateName = stateName;
}
public function get hasVerticalTopLine():Boolean
{
return _hasVerticalTopLine;
}
public function set hasVerticalTopLine(value:Boolean):void
{
_hasVerticalTopLine = value;
}
public function get hasVerticalBottomLine():Boolean
{
return _hasVerticalBottomLine;
}
public function set hasVerticalBottomLine(value:Boolean):void
{
_hasVerticalBottomLine = value;
}
public function get hasHorizontalLeftLine():Boolean
{
return _hasHorizontalLeftLine;
}
public function set hasHorizontalLeftLine(value:Boolean):void
{
_hasHorizontalLeftLine = value;
}
public function get hasHorizontalRightLine():Boolean
{
return _hasHorizontalRightLine;
}
public function set hasHorizontalRightLine(value:Boolean):void
{
_hasHorizontalRightLine = value;
}
public function get nodeActor():ActorVO
{
return _nodeActor;
}
public function set nodeActor(value:ActorVO):void
{
_nodeActor = value;
}
public function get stateName():String
{
return _stateName;
}
public function set stateName(value:String):void
{
_stateName = value;
}
}
}
As you can see, there are different boolean variables used to get the connecting lines and there is another valueObject
ActorVO
which has actor
data. Here is the code:
package scripts.valueObjects
{
public class ActorVO extends Object
{
private var _id:int;
private var _fullName:String;
private var _imageSource:String;
private var _beta1:Number;
private var _beta2:Number;
private var _beta3:Number;
private var _nationality:String;
private var _education:String;
private var _gender:String;
private var _displayName:String;
private var _progress:Number;
private var _showImage:Boolean;
public function ActorVO(id:int = -1, fullName:String = "Full Name", imageSource:String = "",
beta1:Number = -1, beta2:Number = -1, beta3:Number = -1, nationality:String = "India",
gender:String = "M", progress:Number = 10, education:String = "", showImage:Boolean = true)
{
this.id = id;
this.fullName = fullName;
this.imageSource = imageSource;
this.beta1 = beta1;
this.beta2 = beta2;
this.beta3 = beta3;
this.nationality = nationality;
this.gender = gender;
this.progress = progress;
this.education = education;
this.showImage = showImage;
}
public function copyData(actor:ActorVO):void
{
this.id = actor.id;
this.fullName = actor.fullName;
this.imageSource = actor.imageSource;
this.beta1 = actor.beta1;
this.beta2 = actor.beta2;
this.beta3 = actor.beta3;
this.nationality = actor.nationality;
this.gender = actor.gender;
this.progress = actor.progress;
this.education = actor.education;
this.showImage = showImage
}
public function get id():int
{
return _id;
}
public function set id(value:int):void
{
_id = value;
}
public function get fullName():String
{
return _fullName;
}
public function set fullName(value:String):void
{
_fullName = value;
displayName = value.substring(value.lastIndexOf(" ") + 1); //return the last name in the string
}
public function get imageSource():String
{
return _imageSource;
}
public function set imageSource(value:String):void
{
/**
* When copyData function is used, value is ./assets/images/people/
* and hence imageSouce will be prepended with ./assets/images/people
* hence first check if there exists path
* */
_imageSource = "./assets/images/people/" + value;
if (value.indexOf("./") != -1)
{
_imageSource = value;
}
}
public function get beta1():Number
{
return _beta1;
}
public function set beta1(value:Number):void
{
_beta1 = value;
}
public function get beta2():Number
{
return _beta2;
}
public function set beta2(value:Number):void
{
_beta2 = value;
}
public function get beta3():Number
{
return _beta3;
}
public function set beta3(value:Number):void
{
_beta3 = value;
}
public function get nationality():String
{
return _nationality;
}
public function set nationality(value:String):void
{
_nationality = value;
}
public function get education():String
{
return _education;
}
public function set education(value:String):void
{
_education = value;
}
public function get gender():String
{
return _gender;
}
public function set gender(value:String):void
{
_gender = value;
}
public function get displayName():String
{
return _displayName;
}
public function set displayName(value:String):void
{
_displayName = value;
}
public function get progress():Number
{
return _progress;
}
public function set progress(value:Number):void
{
_progress = value;
}
public function get showImage():Boolean
{
return _showImage;
}
public function set showImage(value:Boolean):void
{
_showImage = value;
}
}
}
And here is the DataGrid
code from the Application
:
<s:DataGrid id="orgChartDG" borderVisible="false" skinClass="skins.OrgChartDataGridSkin"
dataProvider="{orgChartDP}" variableRowHeight="true">
<s:columns>
<s:ArrayList>
<s:GridColumn dataField="col1" itemRenderer="customComponents.myOrgChart.TestIR" />
<s:GridColumn dataField="col2" itemRenderer="customComponents.myOrgChart.TestIR" />
<s:GridColumn dataField="col3" itemRenderer="customComponents.myOrgChart.TestIR" />
<s:GridColumn dataField="col4" itemRenderer="customComponents.myOrgChart.TestIR" />
<s:GridColumn dataField="col5" itemRenderer="customComponents.myOrgChart.TestIR" />
<s:GridColumn dataField="col6" itemRenderer="customComponents.myOrgChart.TestIR" />
<s:GridColumn dataField="col7" itemRenderer="customComponents.myOrgChart.TestIR" />
<s:GridColumn dataField="col8" itemRenderer="customComponents.myOrgChart.TestIR" />
<s:GridColumn dataField="col9" itemRenderer="customComponents.myOrgChart.TestIR" />
<s:GridColumn dataField="col10" itemRenderer="customComponents.myOrgChart.TestIR" />
</s:ArrayList>
</s:columns>
</s:DataGrid>
The DataProvider
for this DataGrid
is an ArrayCollection
which contains 10 Objects
with properties col1
- col10
, where each property is of type CellRendererVO
.
Here is the output of this implementation:
Now, here is the trouble
I have button Hide Images
as seen in the above image. What needs to be done is, when clicked on this button, all the images shown in the Org.Chart must be hidden. But wait, Im just stuck with something else and for now forget about this implementation.
The click handler for this button is as follows:
private function hideImagesBtn_clickHandler(event:Event):void
{
orgChartDP.refresh();
}
But, when clicked on this button, I see a weird behavior. See the output of the Org.Chart when clicked on Hide Images
:
I am not able to figure it out why it is changing so. As you can see there is only a refresh
of ArrayCollection
being done. Why is the whole structure of the Org.Chart
is getting changed?
I did some research about this and one reason I can think of is only reusable
feature of ItemRenderer
s. But, however this reason still does not apply for change of Org.Chart
.
Any kind of help to solve this issue is appreciated also thanks for coming till here.
Thanks, Anji