Во-первых, извините за действительно длинный вопрос. Я пытаюсь реализовать Org.Chart
, используя spark DataGrid
. Данные для Org.Chart
не меняются, и поэтому я жестко кодирую значения. Я должен был реализовать это Org.Chart
, так как мне нужно иметь плавающее Nodes
, а также соединительные линии должны быть нарисованы немного иначе по сравнению с использованием внешнего компонента. Пожалуйста, найдите следующее изображение, которого я пытаюсь достичь:
Вот идея:
Каждая ячейка DataGrid
может быть либо connecting lines
, либо actor
. У меня есть пользовательский компонент MyOrgChartNode
, который имеет два состояния: chartLinesState
и chartActorState
. Этот компонент используется как ItemRenderer
для DataGrid
. Вот код 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>
В приведенном выше коде я использую valueObject
CellRendererVO
, который содержит необходимую информацию для отображения ячейки, такую как видимость различных HRules
и VRule
присутствующих. Код для CellRendererVO
здесь:
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;
}
}
}
Как видите, существуют разные логические переменные, используемые для получения соединительных линий, и есть другая valueObject
ActorVO
, которая имеет actor
данные. Вот код:
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;
}
}
}
А вот код DataGrid
из 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>
DataProvider
для этого DataGrid
- это ArrayCollection
, который содержит 10 Objects
со свойствами col1
- col10
, где каждое свойство имеет тип CellRendererVO
.
Вот вывод этой реализации:
Теперь вот беда
У меня есть кнопка Hide Images
, как видно на изображении выше. Что нужно сделать, это то, что при нажатии на эту кнопку все изображения, показанные в Org.Chart, должны быть скрыты. Но подождите, я просто застрял с чем-то другим, а пока забудьте об этом.
Обработчик щелчка для этой кнопки выглядит следующим образом:
private function hideImagesBtn_clickHandler(event:Event):void
{
orgChartDP.refresh();
}
Но при нажатии на эту кнопку я вижу странное поведение. Смотрите вывод Org.Chart при нажатии на Hide Images
:
Я не могу понять, почему это так меняется. Как вы можете видеть, делается только refresh
из ArrayCollection
. Почему вся структура Org.Chart
меняется?
Я провел некоторое исследование по этому поводу, и одна причина, о которой я могу подумать, это только reusable
функция ItemRenderer
с. Но, однако, эта причина по-прежнему не распространяется на изменение Org.Chart
.
Буду признателен за любую помощь в решении этой проблемы, также спасибо, что пришли сюда.
Спасибо,
Анжи