一般情况下需要组件重写都是由于以下2个原因: 
1、在FLEX已有组件无法满足业务需求,或是需要更改其可视化外观等特性时,直接进行继承扩展。 
2、为了模块化设计或进一步重用,需要对FLEX组件进行组合。 
而Flex组件开发有2种方式: AS方式和MXML方式。对于上述第一个原因我一般采用AS方式,通过继承 UIComponent来开发,而针对原因2我一般使用的是 MXML方式。本文主要讲的是AS开发方式。 
重写一个组件依次调用的方法 : 
1)Constructor构造方法,初始化属性,默认值 在这个方法中使用最好。 
2)createChildren() 创建子对象,在组件中添加子对象。是使用addChild方法添加子对象  
3)commitProperties 用在处理属性值和更新。(多个属性值更新后统一处理入口和单值多次修改后处理入口)  
4)measure()设置组件的默认大小(以便Flex布局管理器能正确知道该组件的大小,给其分配适当空间)  
5)updateDisplayList()用来重绘组件,子对象布局逻辑等  
我们通过这样一个例子来讲解。

 
首先是 Constructor方法:

public function MultilayerHorizontalBarChart()
{super();
}

由于该例不需要在构造初始化属性(一般简单数据类型在定义的时候就已经赋值),所以构造方法没内容;

接着是 createChildren方法:

  
  override protected function createChildren():void
{super.createChildren();
if (_mXis == null)
{
_mXis = new Group();
addChild(_mXis);
}
if (_mYis == null)
{
_mYis = new Group();
addChild(_mYis);
}
if (_mHBarIDLable == null )
{
_mHBarIDLable = new Group();
addChild(_mHBarIDLable);
}
if (_gridLines == null)
{
_gridLines = new Group();
addChild(_gridLines);
}
if (_mMainHDraw == null)
{
_mMainHDraw = new Group();
addChild(_mMainHDraw);
}
if (_mEventGroup == null){
_mEventGroup = new Group();
addChild(_mEventGroup); _mEventGroup.addEventListener(MouseEvent.MOUSE_OUT, deleDataHandler);
_mEventGroup.addEventListener(MouseEvent.MOUSE_MOVE,showDataHandler); }
if (mFloatIsShow)
{
if (floatDataPanel == null)
{
floatDataPanel = new BorderContainer();
floatInerPanel = new BorderContainer();
floatDataPanel.setStyle("cornerRadius",15);
floatInerPanel.setStyle("cornerRadius",15);
var vs:SolidColor = new SolidColor();
vs.color = 0x6A726B;
vs.alpha = 0.3;
floatDataPanel.backgroundFill = vs;
floatDataPanel.visible = false;
_mEventGroup.addElement(floatDataPanel);
}
}
}
这里涉及到组件 子对象的划分,本例子中,具有的子对象有 _mXis X轴容器对象,_mYis Y轴容器对象, _mHBarIDLable 柱子标签容器对象(最上方月份提示那个), _gridLines 网格容器对象, _mMainHDraw 主画布对象(用来画柱状图的容器), _mEventGroup 鼠标事件监听容器对象, floatDataPanel、 floatInerPanel 是显示数据的浮动框容器对象 。在该方法里我们初始化这些子对象并把他们添加到组件容器中。 接下来是 commitProperties 用在处理属性值和更新,本例子中这些事情都在updateDisplayList处理,重点掌握 updateDisplayList方法的重写。 接着是 measure方法的重写(本例中,重绘的时候都会重新调整自对象的位置和大小,所以该方法的重写也可以省略):     override protected function measure():void
{super.measure();
measuredMinHeight = measuredHeight = DEFAULT_HEIGHT;
measuredMinWidth = measuredWidth = DEFAULT_WIDTH;
}
接下来是本例的重头戏, updateDisplayList方法的重写:     override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
{if (_isReflash)
{
super.updateDisplayList(unscaledWidth, unscaledHeight);
if (dataProvider == null)
{
return;
}
for (var i:int = 0; i < dataProvider.ColumnName.length; i++)
{
//如果存在空数据就设定标识退出循环
if (null == dataProvider.Data[dataProvider.ColumnName[i]])
{
_checkData = false;
break;
}
}
if (_checkData)
{
drawLayouts(unscaledWidth,unscaledHeight);
drawXAxis();
drawYAxis();
drawGrid();
legendHBarLine();
drawHBar();
}
_isReflash = false;
}
}
该方法中,先对数据源进行检验,只有但数据源不为空并且是新的数据源才进行重绘,否则不作处理。重绘做的事情主要是: drawLayouts(unscaledWidth,unscaledHeight)子对象布局,子对象位置和大小的确定; drawXAxis()重绘X轴容器自对象; drawYAxis()重绘Y轴容器子对象;legendHBarLine()重绘数据标签提示自对象; drawGrid()、 drawHBar()主画布区域子对象重绘,画网格和柱状图; drawLayouts方法:     protected function drawLayouts(pW:Number, pH:Number):void
{this._mXis.setActualSize(pW - this.mYAxisWidth, this.mXAxisHeight);
_mXis.move(this.mYAxisWidth, pH - this.mXAxisHeight);
this._mYis.setActualSize(this.mYAxisWidth, pH - this.mXAxisHeight - this.mHBarIDLableHeight);
this._mYis.move(0,this.mHBarIDLableHeight); //X轴标签位置
this._mHBarIDLable.setActualSize(pW - this.mYAxisWidth, this.mHBarIDLableHeight);
this._mHBarIDLable.move(this.mYAxisWidth, -10); this._gridLines.setActualSize(pW - this.mYAxisWidth, pH - this.mXAxisHeight - this.mHBarIDLableHeight);
this._gridLines.move(this.mYAxisWidth, this.mHBarIDLableHeight); this._mMainHDraw.setActualSize(pW - this.mYAxisWidth, pH - this.mXAxisHeight - this.mHBarIDLableHeight);
this._mMainHDraw.move(this.mYAxisWidth, this.mHBarIDLableHeight); this._mEventGroup.setActualSize(pW - this.mYAxisWidth, pH - this.mXAxisHeight - this.mHBarIDLableHeight);
this._mEventGroup.move(this.mYAxisWidth, this.mHBarIDLableHeight);
}
确定各子对象的宽高和x,y坐标,对整个组件容器区域进行划分。 drawXAxis方法:     protected function drawXAxis():void
{var _mXMaxValue:Number =100;
// TODO Auto Generated method stub var vGroup:Group = this._mXis;
var vG:Graphics = vGroup.graphics; vGroup.removeAllElements();
vG.clear();
vG.lineStyle(1, 0x000000,0.8);
vG.moveTo(0, 0);
vG.lineTo(vGroup.width,0);
_mXCachedTicks = new Vector.<Number>();
_mXCacheValueTicks = new Vector.<Number>();
//将X轴分成xbisectNum等份 默认为10
var vCount:int = xBisectNum;
var vGap:Number = vGroup.width / vCount;
var vGapValue:Number = _mXMaxValue / vCount;
var vNum:Number;
var vX:Number
for(var i:int=0; i <= vCount; i++){
vX = i * vGap;
vG.moveTo(vX, 0);
vG.lineTo(vX,6);
_mXCachedTicks.push(vX); var vTextField:Text = new Text();
vNum = i*vGapValue;
vTextField.text = vNum.toString() + "%";
var vTlm:TextLineMetrics = measureText(vTextField.text);
vTextField.move( vX - vTlm.width / 2, 10);
vGroup.addElement(vTextField);
}
vGroup = null;
vG = null;
}
画坐标轴并添加上刻度值数据标签。 drawYAxis方法:     protected function drawYAxis():void
{var vGroup:Group = this._mYis;
var vG:Graphics = vGroup.graphics;
vGroup.removeAllElements();
vG.clear();
vG.lineStyle(1, 0x000000,0.8);
vG.moveTo(vGroup.width, 0);
vG.lineTo(vGroup.width, vGroup.height);
_mYCachedTicks = new Vector.<Number>();
//Y轴数据的个数
var vCount:int = this.dataProvider.RowCount;
var vGap:Number = vGroup.height / vCount;
//存储Y轴刻度高度,供之后画图使用
this._mYGap = vGap; vG.moveTo(vGroup.width - 6, 0);
vG.lineTo(vGroup.width, 0); for (var i:int = 0; i <= vCount; i++) {
var vY:Number = (i) * vGap;
vG.moveTo(vGroup.width-6, vY);
vG.lineTo(vGroup.width, vY);
_mYCachedTicks.push(vY);
var vTextField:Label = new Label();
if (i < vCount)
{
//把Y轴的显示的标签加上
vTextField.text = this.dataProvider.Data[categoryField][i];
var vTlm:TextLineMetrics = measureText(vTextField.text);
vTextField.move(vGroup.width - vTlm.width - 20, vY + vGap/2 - vTlm.height / 2);
vGroup.addElement(vTextField);
}
}
vGroup = null;
vG = null;
}
画Y轴坐标轴并添加数据指标标签。 legendHBarLine方法:     protected function legendHBarLine():void
{var vGroup:Group = this._mHBarIDLable;
var vIDLableLen:Number = vGroup.width/this._mHBarCenNum;
var vGap:Number = vIDLableLen / 6;
var vHLineLen:Number = vGap*0.6; var vHY:Number = vGroup.height /2;
var vG:Graphics =vGroup.graphics;
_mHBarIDLable.removeAllElements();
vG.clear();
var vLBuffef:Number = 0;
for(var i:int=0; i < this._mHBarCenNum; i++)
{
var vName:Label = new Label();
vG.lineStyle(0.2, this.mHBarColorArray[i%this.mHBarColorArray.length]); //对颜色数组取余可防止颜色数组不足时index越界
vG.beginFill(mHBarColorArray[i]);
vG.drawRect(vLBuffef,vHY,vHLineLen,vHLineLen);
vG.endFill();
vName.text = this.dataProvider.ColumnName[i+1];
vName.x = vLBuffef + vHLineLen;
vName.y = vHY/2;
_mHBarIDLable.addElement(vName);
vLBuffef += vIDLableLen;
}
vGroup = null;
vG = null;
}
容器内顶部画添加数据提示标签。 drawGrid方法:     protected function drawGrid():void
{
var vGroup:Group = _gridLines;
var vG:Graphics = vGroup.graphics;
vG.clear();
var vColor:uint = 0xBFBFBF;
var vAlpha:Number = 0.3;
vG.lineStyle(1, vColor, vAlpha);
var vLen:Number;
var vPoint:Point;
var i:int;
var pos:int; //画横线
if (_mYCachedTicks && _mYCachedTicks.length > 0)
{
vLen = vGroup.width / 10;
var vgHeight:Number;
for (i = 0; i < _mYCachedTicks.length - 1; i++)
{
vgHeight = _mYCachedTicks[i];
for (pos = 0; pos < vLen; pos++)
{
vG.moveTo(pos * 10, vgHeight);
vG.lineTo(pos * 10 + 6, vgHeight);
}
}
} //画竖线
if (_mXCachedTicks && _mXCachedTicks.length > 0) {
vLen = vGroup.height / 10;
var vMax:int = _mXCachedTicks.length;
for (i = 1; i < vMax; i++) {
var vWidth:Number = _mXCachedTicks[i];
for (pos = 0; pos < vLen; pos++) {
vG.moveTo(vWidth, pos * 10);
vG.lineTo(vWidth, pos * 10 + 6);
}
}
}
}
画网格,虚线,这里以10个像素为单位,画6个像素点,空4个像素点也就成了虚线。 drawHBar方法:     protected function drawHBar():void
{
//矩形高度
var vHBarHeight:Number = this._mYGap * 2 / 5;
_mMainHDraw.removeAllElements(); var vGroup:Group = this._mMainHDraw;
vGroup.removeAllElements();
var vG:Graphics = vGroup.graphics;
vG.clear();
var vColumnNameTemp:String = null;
//从左到右从上到下画矩形
var columnLen:int = this.dataProvider.ColumnName.length;
//用来存放遍历到的主要数据
var vValue:Number = 0;
for(var vIndex:int = 0; vIndex < this.dataProvider.RowCount; vIndex++)
{
//累积的矩形宽度,最长不能超过100%
var vSumWidth:Number = 0;
//第一个数组0放的是Y轴标签,直接略过
for(var vColumnIndex:int = 1; vColumnIndex < columnLen; vColumnIndex++)
{
vColumnNameTemp = this.dataProvider.ColumnName[vColumnIndex];
//vColumnIndex是从1开始的,跳过“yAxisData”字段,这里要减去1
var vColor:uint = this.mHBarColorArray[(vColumnIndex-1) % this.mHBarColorArray.length];
vValue = Number(this._mPercentData[vColumnNameTemp][vIndex]);
if( vSumWidth>1)
{
vSumWidth = 1;
}
vG.beginFill(vColor);
vG.drawRect(vSumWidth*this._mMainHDraw.width, this._mYCachedTicks[vIndex] + this._mYGap/2 - vHBarHeight/2 ,
vValue*this._mMainHDraw.width, vHBarHeight);
vG.endFill();
vSumWidth += vValue;
}
}
vGroup = null;
vG = null;
}
根据数据源计算出个柱子的位置和大小并在主画布区域画出来。 还有鼠标事件处理方法就不一一列出,具体看完整代码。 MultilayerHorizontalBarChart.as文件: package LineChartTableTest
{
import DataEntity.DataTable; import flash.display.Graphics;
import flash.events.MouseEvent;
import flash.geom.Point;
import flash.text.TextLineMetrics;
import flash.utils.Dictionary; import mx.controls.Label;
import mx.controls.Text;
import mx.core.UIComponent;
import mx.graphics.SolidColor; import spark.components.BorderContainer;
import spark.components.Group;
import spark.layouts.VerticalLayout;
/**
* 水平叠柱状图
* @author haojie.wang
* @date 2013-4-27
* @version 1.0
* <b>
* X轴为百分比,Y轴为各指标\n
* 这里必须注意的是categoryField的设置,dataTable的column[0]必须是_categoryField的值
* </b>
*/
public class MultilayerHorizontalBarChart extends UIComponent
{
protected static const DEFAULT_HEIGHT:Number = 300;
protected static const DEFAULT_WIDTH:Number = 960; //===========================
// 可通过外部属性定义从而改变控件属性start
//===========================
/**
* X轴的高度
*/
protected var _mXAxisHeight:Number = 50;
/**
* Y轴宽度
*/
protected var _mYAxisWidth:Number = 100;
/**
* 等分值,把X轴设成多少等分,默认为10
*/
private var _xBisectNum:int = 10;
/**
* X轴单位
*/
private var _mXUnit:String;
/**
* Y轴单位
*/
private var _mYUnit:String;
/**
* 图表名称
*/
private var _mChartName:String;
/**
* 是否显示悬浮框
*/
protected var _mFloatIsShow:Boolean = true; //===========================
// 可通过外部属性定义从而改变控件属性end
//=========================== //===========================
// 接收控件所需要的数据参数start
//=========================== /**
* 主要数据源
*/
protected var _dataProvider:DataTable;
/**
* 字段参数 ,默认为“yAxisData”
*/
protected var _categoryField:String ="yAxisData"; /**
* 颜色数组
*/
protected var _mHBarColorArray:Array;
//===========================
// 接收控件所需要的数据参数end
//=========================== //===========================
// 控件内部使用属性,不需要外部传值start
//===========================
/**
* 每行的总和数组,统计每行各数值的和
*/
protected var _mRowSumArray:Array;
/**
* 存放DataTable里data数据的百分比格式
*/
protected var _mPercentData:Dictionary;
/**
*需要画的柱子的层数,默认为6
*/
protected var _mHBarCenNum:int = 6;
/**
* X轴度量值间隔
*/
protected var _mXGap:Number;
/**
* Y轴度量值间隔
*/
protected var _mYGap:Number;
/**
* 暂存X轴刻度数据
*/
protected var _mXCachedTicks:Vector.<Number> /* 数字 */ = null;
/**
* 暂存X轴数据,累计刻度值
*/
protected var _mXCacheValueTicks:Vector.<Number> /* 数字 */ = null;
/**
* X轴刻度相关,距离为1像素,暂时不给外部输入,无关紧要,setter和getter方法注销掉了
*/
protected var _mPadding:Number = 1;
/**
* Y刻度缓存数组
*/
protected var _mYCachedTicks:Vector.<Number> = null;
/**
* Y轴的最大值
*/
protected var _mYMaxValue:Number;
/**
* 当前Y轴光标索引
*/
protected var _countIndexY:int = 0;
/**
* 检查数据是否为空,true表示数据不为空
*/
protected var _checkData:Boolean = true;
/**
* 直方图数量
*/
protected var _mHBarNum:int;
/**
* X轴
*/
private var _mXis:Group;
/**
* Y轴
*/
private var _mYis:Group; /**
* 直方图上方的数据刷新显示区域
*/
private var _mHBarIDLable:Group;
/**
* Y轴上ID标签的高度
*/
protected var _mHBarIDLableHeight:int = 25;
/**
* 网格
*/
private var _gridLines:Group;
/**
* 主要数据显示区域
*/
private var _mMainHDraw:Group;
/**
* 事件监听层
*/
private var _mEventGroup:Group;
/**
* 是否为刷新
*/
protected var _isReflash:Boolean = true;
/**
* 浮动框外层
*/
private var floatDataPanel:BorderContainer;
/**
* 浮动框内层
*/
private var floatInerPanel:BorderContainer;
/**
* 浮动框内层显示的内容
*/
private var vLabel1: Text= new Text(); //===========================
// 控件内部使用属性,不需要外部传值end
//=========================== public function MultilayerHorizontalBarChart()
{
super();
} override protected function createChildren():void
{
super.createChildren();
if (_mXis == null)
{
_mXis = new Group();
addChild(_mXis);
}
if (_mYis == null)
{
_mYis = new Group();
addChild(_mYis);
}
if (_mHBarIDLable == null )
{
_mHBarIDLable = new Group();
addChild(_mHBarIDLable);
}
if (_gridLines == null)
{
_gridLines = new Group();
addChild(_gridLines);
}
if (_mMainHDraw == null)
{
_mMainHDraw = new Group();
addChild(_mMainHDraw);
}
if (_mEventGroup == null){
_mEventGroup = new Group();
addChild(_mEventGroup);
_mEventGroup.addEventListener(MouseEvent.MOUSE_OUT, deleDataHandler);
_mEventGroup.addEventListener(MouseEvent.MOUSE_MOVE,showDataHandler);
}
if (mFloatIsShow)
{
if (floatDataPanel == null)
{
floatDataPanel = new BorderContainer();
floatInerPanel = new BorderContainer();
floatDataPanel.setStyle("cornerRadius",15);
floatInerPanel.setStyle("cornerRadius",15);
var vs:SolidColor = new SolidColor();
vs.color = 0x6A726B;
vs.alpha = 0.3;
floatDataPanel.backgroundFill = vs;
floatDataPanel.visible = false;
_mEventGroup.addElement(floatDataPanel);
}
}
} override protected function commitProperties():void
{
super.commitProperties();
//显示浮动窗口
if (mFloatIsShow)
{
var vsIner:SolidColor = new SolidColor();
vsIner.color = 0x000000;
vsIner.alpha = 0.8; var vver:VerticalLayout = new VerticalLayout();
vver.paddingBottom = 2;
vver.paddingLeft = 2;
vver.paddingRight = 2;
vver.paddingTop =2; floatDataPanel.layout = vver;
floatInerPanel.backgroundFill = vsIner;
floatInerPanel.setStyle("color",0xFFFFFF);
floatInerPanel.addElement(vLabel1);
vLabel1.horizontalCenter = 0;
floatDataPanel.addElement(floatInerPanel);
floatInerPanel.move(2,2);
floatDataPanel.setActualSize(200,vLabel1.height+50);
floatInerPanel.setActualSize(vLabel1.width,vLabel1.height);
} }
override protected function measure():void
{
super.measure();
measuredMinHeight = measuredHeight = DEFAULT_HEIGHT;
measuredMinWidth = measuredWidth = DEFAULT_WIDTH;
}
override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
{
if (_isReflash)
{
super.updateDisplayList(unscaledWidth, unscaledHeight);
if (dataProvider == null)
{
return;
}
for (var i:int = 0; i < dataProvider.ColumnName.length; i++)
{
//如果存在空数据就设定标识退出循环
if (null == dataProvider.Data[dataProvider.ColumnName[i]])
{
_checkData = false;
break;
}
}
if (_checkData)
{
drawLayouts(unscaledWidth,unscaledHeight);
drawXAxis();
drawYAxis();
drawGrid();
legendHBarLine();
drawHBar();
}
_isReflash = false;
}
} /**
* 安排布局
*/
protected function drawLayouts(pW:Number, pH:Number):void
{
this._mXis.setActualSize(pW - this.mYAxisWidth, this.mXAxisHeight);
_mXis.move(this.mYAxisWidth, pH - this.mXAxisHeight);
this._mYis.setActualSize(this.mYAxisWidth, pH - this.mXAxisHeight - this.mHBarIDLableHeight);
this._mYis.move(0,this.mHBarIDLableHeight); //X轴标签位置
this._mHBarIDLable.setActualSize(pW - this.mYAxisWidth, this.mHBarIDLableHeight);
this._mHBarIDLable.move(this.mYAxisWidth, -10); this._gridLines.setActualSize(pW - this.mYAxisWidth, pH - this.mXAxisHeight - this.mHBarIDLableHeight);
this._gridLines.move(this.mYAxisWidth, this.mHBarIDLableHeight); this._mMainHDraw.setActualSize(pW - this.mYAxisWidth, pH - this.mXAxisHeight - this.mHBarIDLableHeight);
this._mMainHDraw.move(this.mYAxisWidth, this.mHBarIDLableHeight); this._mEventGroup.setActualSize(pW - this.mYAxisWidth, pH - this.mXAxisHeight - this.mHBarIDLableHeight);
this._mEventGroup.move(this.mYAxisWidth, this.mHBarIDLableHeight);
} /**
* 画百分比X轴
*/
protected function drawXAxis():void
{
var _mXMaxValue:Number =100;
// TODO Auto Generated method stub var vGroup:Group = this._mXis;
var vG:Graphics = vGroup.graphics; vGroup.removeAllElements();
vG.clear();
vG.lineStyle(1, 0x000000,0.8);
vG.moveTo(0, 0);
vG.lineTo(vGroup.width,0);
_mXCachedTicks = new Vector.<Number>();
_mXCacheValueTicks = new Vector.<Number>();
//将X轴分成xbisectNum等份 默认为10
var vCount:int = xBisectNum;
var vGap:Number = vGroup.width / vCount;
var vGapValue:Number = _mXMaxValue / vCount;
var vNum:Number;
var vX:Number
for(var i:int=0; i <= vCount; i++){
vX = i * vGap;
vG.moveTo(vX, 0);
vG.lineTo(vX,6);
_mXCachedTicks.push(vX); var vTextField:Text = new Text();
vNum = i*vGapValue;
vTextField.text = vNum.toString() + "%";
var vTlm:TextLineMetrics = measureText(vTextField.text);
vTextField.move( vX - vTlm.width / 2, 10);
vGroup.addElement(vTextField);
}
vGroup = null;
vG = null;
} /**
* 画Y轴
*/
protected function drawYAxis():void
{
var vGroup:Group = this._mYis;
var vG:Graphics = vGroup.graphics;
vGroup.removeAllElements();
vG.clear();
vG.lineStyle(1, 0x000000,0.8);
vG.moveTo(vGroup.width, 0);
vG.lineTo(vGroup.width, vGroup.height);
_mYCachedTicks = new Vector.<Number>();
//Y轴数据的个数
var vCount:int = this.dataProvider.RowCount;
var vGap:Number = vGroup.height / vCount;
//存储Y轴刻度高度,供之后画图使用
this._mYGap = vGap; vG.moveTo(vGroup.width - 6, 0);
vG.lineTo(vGroup.width, 0); for (var i:int = 0; i <= vCount; i++) {
var vY:Number = (i) * vGap;
vG.moveTo(vGroup.width-6, vY);
vG.lineTo(vGroup.width, vY);
_mYCachedTicks.push(vY);
var vTextField:Label = new Label();
if (i < vCount)
{
//把Y轴的显示的标签加上
vTextField.text = this.dataProvider.Data[categoryField][i];
var vTlm:TextLineMetrics = measureText(vTextField.text);
vTextField.move(vGroup.width - vTlm.width - 20, vY + vGap/2 - vTlm.height / 2);
vGroup.addElement(vTextField);
}
}
vGroup = null;
vG = null;
} /**
* 画网格
*/
protected function drawGrid():void
{
var vGroup:Group = _gridLines;
var vG:Graphics = vGroup.graphics;
vG.clear();
var vColor:uint = 0xBFBFBF;
var vAlpha:Number = 0.3;
vG.lineStyle(1, vColor, vAlpha);
var vLen:Number;
var vPoint:Point;
var i:int;
var pos:int; //画横线
if (_mYCachedTicks && _mYCachedTicks.length > 0)
{
vLen = vGroup.width / 10;
var vgHeight:Number;
for (i = 0; i < _mYCachedTicks.length - 1; i++)
{
vgHeight = _mYCachedTicks[i];
for (pos = 0; pos < vLen; pos++)
{
vG.moveTo(pos * 10, vgHeight);
vG.lineTo(pos * 10 + 6, vgHeight);
}
}
} //画竖线
if (_mXCachedTicks && _mXCachedTicks.length > 0) {
vLen = vGroup.height / 10;
var vMax:int = _mXCachedTicks.length;
for (i = 1; i < vMax; i++) {
var vWidth:Number = _mXCachedTicks[i];
for (pos = 0; pos < vLen; pos++) {
vG.moveTo(vWidth, pos * 10);
vG.lineTo(vWidth, pos * 10 + 6);
}
}
}
} /**
* 画数据标签提示
*/
protected function legendHBarLine():void
{
var vGroup:Group = this._mHBarIDLable;
var vIDLableLen:Number = vGroup.width/this._mHBarCenNum;
var vGap:Number = vIDLableLen / 6;
var vHLineLen:Number = vGap*0.6; var vHY:Number = vGroup.height /2;
var vG:Graphics =vGroup.graphics;
_mHBarIDLable.removeAllElements();
vG.clear();
var vLBuffef:Number = 0;
for(var i:int=0; i < this._mHBarCenNum; i++)
{
var vName:Label = new Label();
vG.lineStyle(0.2, this.mHBarColorArray[i%this.mHBarColorArray.length]); //对颜色数组取余可防止颜色数组不足时index越界
vG.beginFill(mHBarColorArray[i]);
vG.drawRect(vLBuffef,vHY,vHLineLen,vHLineLen);
vG.endFill();
vName.text = this.dataProvider.ColumnName[i+1];
vName.x = vLBuffef + vHLineLen;
vName.y = vHY/2;
_mHBarIDLable.addElement(vName);
vLBuffef += vIDLableLen;
}
vGroup = null;
vG = null;
} /**
* 画直方图
*/
protected function drawHBar():void
{
//矩形高度
var vHBarHeight:Number = this._mYGap * 2 / 5;
_mMainHDraw.removeAllElements(); var vGroup:Group = this._mMainHDraw;
vGroup.removeAllElements();
var vG:Graphics = vGroup.graphics;
vG.clear();
var vColumnNameTemp:String = null;
//从左到右从上到下画矩形
var columnLen:int = this.dataProvider.ColumnName.length;
//用来存放遍历到的主要数据
var vValue:Number = 0;
for(var vIndex:int = 0; vIndex < this.dataProvider.RowCount; vIndex++)
{
//累积的矩形宽度,最长不能超过100%
var vSumWidth:Number = 0;
//第一个数组0放的是Y轴标签,直接略过
for(var vColumnIndex:int = 1; vColumnIndex < columnLen; vColumnIndex++)
{
vColumnNameTemp = this.dataProvider.ColumnName[vColumnIndex];
//vColumnIndex是从1开始的,跳过“yAxisData”字段,这里要减去1
var vColor:uint = this.mHBarColorArray[(vColumnIndex-1) % this.mHBarColorArray.length];
vValue = Number(this._mPercentData[vColumnNameTemp][vIndex]);
if( vSumWidth>1)
{
vSumWidth = 1;
}
vG.beginFill(vColor);
vG.drawRect(vSumWidth*this._mMainHDraw.width, this._mYCachedTicks[vIndex] + this._mYGap/2 - vHBarHeight/2 ,
vValue*this._mMainHDraw.width, vHBarHeight);
vG.endFill();
vSumWidth += vValue;
}
}
vGroup = null;
vG = null;
} /**
* 显示数据处理
* @param pEvent
*
*/
protected function showDataHandler(pEvent:MouseEvent):void
{
countIndexY = int(pEvent.localY / this._mYGap); //第几个柱子
if (countIndexY >= this._mHBarNum)
{
return;
}
//鼠标光标在柱子上时候,柱子高度占刻度值的1/3
if (pEvent.localY > (countIndexY+1.5/5) * this._mYGap && pEvent.localY < (countIndexY + 3.5 / 5) * this._mYGap)
{
//如果显示浮动框,要设置好位置,防止出界
if (mFloatIsShow)
{
// trace("Y:" + pEvent.localY + "X:" + pEvent.localX);
if (pEvent.localY > this._mMainHDraw.height - floatDataPanel.height- 10 )
{
if (pEvent.localX > this._mMainHDraw.width - floatDataPanel.width)
{
floatDataPanel.move(pEvent.localX - floatDataPanel.width, pEvent.localY -floatDataPanel.height-10);
}
else
{
floatDataPanel.move(pEvent.localX , pEvent.localY -floatDataPanel.height-10);
}
}
else
{
if (pEvent.localX > this._mMainHDraw.width - floatDataPanel.width)
{
floatDataPanel.move(pEvent.localX - floatDataPanel.width, pEvent.localY + 10);
}
else
{
floatDataPanel.move(pEvent.localX, pEvent.localY +10);
}
}
updHBarLabelData(countIndexY,pEvent.localX);
}
}
else
{
updHBarLabelData(-1,0); }
} /**
* 更新显示数据
* @param mHBarIndexY 当前是第几个柱子
* @param pMouseX 鼠标的位置
*/
protected function updHBarLabelData(mHBarIndexY:int, pMouseX:Number):void
{
if (mHBarIndexY == -1)
{
if(mFloatIsShow)
{
floatDataPanel.visible = false;
}
}
else
{
//防止数组越界
if (mHBarIndexY < this.dataProvider.RowCount)
{
var vDataString:String = "XXX";
var vSourceDataString:String = "XX";
var vColumnName:String = "OO";
var vSumNum:Number = 0; //累计柱子各段长百分比
var vSumNumArr:Array = new Array(); //累计柱子各段长百分比数组,用来判断光标在那段柱子上
vSumNumArr[0] = vSumNum;
var vIndex:int = 1;
for each(var vItem:String in this.dataProvider.ColumnName)
{
//categoryField字段是Y轴标签,这里跳过
if (categoryField != vItem)
{
vSumNum += this._mPercentData[vItem][mHBarIndexY];
vSumNumArr[vIndex] = vSumNum;
//找到对应的区间
if (vSumNumArr[vIndex - 1] * this._mMainHDraw.width < pMouseX && pMouseX <= vSumNumArr[vIndex] * this._mMainHDraw.width)
{
vColumnName = vItem;
vSourceDataString = this.dataProvider.Data[vItem][mHBarIndexY].toString();
vDataString = percentDataFormatter(this._mPercentData[vItem][mHBarIndexY] * 100);
break;
}
vIndex++;
} } if (mFloatIsShow)
{
if (this.mChartName != null && this._mYUnit != null)
{
vLabel1.text = this.dataProvider.Data[categoryField][mHBarIndexY] + this._mYUnit + " "
+vColumnName + " " + this.mChartName + " : "
+vDataString + "(" + vSourceDataString + "/" + this._mRowSumArray[mHBarIndexY] + ")";
}
else
{
vLabel1.text = this.dataProvider.Data[categoryField][mHBarIndexY] + " : "
+vDataString + "(" + vSourceDataString + "/" + this._mRowSumArray[mHBarIndexY] + ")";
} vLabel1.horizontalCenter = 0;
vLabel1.verticalCenter = 0;
//获取鼠标所在的柱子的颜色
var vHFloatColor:uint = this.mHBarColorArray[(this.dataProvider.ColumnName.indexOf(vColumnName)-1)%this.mHBarColorArray.length];
changeFloatBackColor(vHFloatColor);
floatDataPanel.visible = true;
}
}
}
} /**
*
* 鼠标移除事件
*/
protected function deleDataHandler(pEvent:MouseEvent):void
{
removeEventListener(MouseEvent.MOUSE_MOVE,showDataHandler);
if (mFloatIsShow)
{
floatDataPanel.visible = false;
}
} /**
* 动态改变浮动框背景
**/
protected function changeFloatBackColor(pColor:uint):void
{
var vs:SolidColor = new SolidColor();
vs.color = pColor;
vs.alpha = 0.8;
floatInerPanel.backgroundFill = vs;
} /**
* 将传入的数值格式化为百分比形式
* @param pNumber 要格式化的数值
* @return 以百分比形式显示的字符串
*
*/
protected function percentDataFormatter(pNumber:Number):String
{
var vNumber:Number = pNumber; return vNumber.toFixed(2) + "%";
} //===========================
// 属性定义的setter和getter方法start
//===========================
/**
* X轴的高度
*/
public function get mXAxisHeight():Number
{
return _mXAxisHeight;
} public function set mXAxisHeight(value:Number):void
{
_mXAxisHeight = value;
} /**
* Y轴宽度
* @return
*/
public function get mYAxisWidth():Number
{
return _mYAxisWidth;
} public function set mYAxisWidth(value:Number):void
{
_mYAxisWidth = value;
} /**
* 当前光标Y轴索引
* @return
*/
public function get countIndexY():int
{
return _countIndexY;
} public function set countIndexY(value:int):void
{
_countIndexY = value;
}
/**
* 直方图上方标签的高度
* @return _mHBarIDLableHeight;
*/
public function get mHBarIDLableHeight():int
{
return _mHBarIDLableHeight;
} public function set mHBarIDLableHeight(value:int):void
{
_mHBarIDLableHeight = value;
}
/**
* 数据源
* @return _dataProvider;
*/
public function get dataProvider():DataTable
{
return _dataProvider;
}
public function set dataProvider(value:DataTable):void
{
this._dataProvider = value;
this._mHBarNum = this.dataProvider.RowCount;
this._mHBarCenNum = this.dataProvider.ColumnName.length -1; this._mRowSumArray = new Array(this._mHBarNum);
var vIndex:int = 0;
//统计个行数据的和,并把它存放进总和数组
for (var i:int = 0; i < this.dataProvider.RowCount; i++)
{
var vSum:Number = 0;
for each (var vItem:String in this.dataProvider.ColumnName)
{
//统计各行数据的和
if (vItem != this.categoryField)
{
vSum += Number(this.dataProvider.Data[vItem][i]) ;
}
}
this._mRowSumArray[vIndex] = vSum;
vIndex ++;
} //把dataTable的Data数据转换成相对应的百分比
this._mPercentData = new Dictionary();
for each (var vItem1:String in this.dataProvider.ColumnName)
{
if (vItem1 != this.categoryField)
{
this._mPercentData[vItem1] = new Array();
for (var j:int = 0; j < this.dataProvider.RowCount; j++)
{
this._mPercentData[vItem1][j] = Number(this.dataProvider.Data[vItem1][j]) / this._mRowSumArray[j];
}
}
} this.invalidateDisplayList();
} /**
* 字段参数 默认为“yAxisData”
* @return _categoryField;
*/
public function get categoryField():String
{
return _categoryField;
} public function set categoryField(value:String):void
{
_categoryField = value;
} /**
* 是否显示悬浮框
* @return _mFloatIsShow;
*/
public function get mFloatIsShow():Boolean
{
return _mFloatIsShow;
} /**
* @private
*/
public function set mFloatIsShow(value:Boolean):void
{
_mFloatIsShow = value;
}
/**
* X轴单位
* @return _mXUnit;
*/
public function get mXUnit():String
{
return _mXUnit;
}
/**
* @private
*/
public function set mXUnit(value:String):void
{
_mXUnit = value;
}
/**
* 左边Y轴单位
* @return _mYUnit;
*/
public function get mYUnit():String
{
return _mYUnit;
}
/**
* @private
*/
public function set mYUnit(value:String):void
{
_mYUnit = value;
}
/**
* 等分值,把X轴设成多少等分,默认为10
*/
public function get xBisectNum():int
{
return _xBisectNum;
}
/**
* @private
*/
public function set xBisectNum(value:int):void
{
_xBisectNum = value;
}
/**
* 图标名称
*/
public function get mChartName():String
{
return _mChartName;
}
/**
* @private
*/
public function set mChartName(value:String):void
{
_mChartName = value;
}
/**
* 颜色数组
*/
public function get mHBarColorArray():Array
{
return _mHBarColorArray;
}
/**
* @private
*/
public function set mHBarColorArray(value:Array):void
{
_mHBarColorArray = value;
}
//===========================
// 属性定义的setter和getter方法end
//===========================
}
}

Flex自定义组件开发 - jackyWHJ的更多相关文章

  1. Flex自定义组件开发之日周月日期选择日历控件

    原文:Flex自定义组件开发之日周月日期选择日历控件         使用过DateField的我们都知道,DateField 控件是用于显示日期的文本字段,字段右侧带有日历图标.当用户在控件边框内的 ...

  2. Flex自定义组件开发

    一般情况下需要组件重写都是由于以下2个原因:1.在FLEX已有组件无法满足业务需求,或是需要更改其可视化外观等特性时,直接进行继承扩展.2.为了模块化设计或进一步重用,需要对FLEX组件进行组合.而F ...

  3. Flex自定义组件、皮肤,并调用

    标签:Flex  自定义组件  自定义皮肤  主应用调用模块 本程序样例学习自flex 实战教程.但因原教程代码不全,且根据个人需求有更改. 1文件列表 自定义as类Reveal.as,该类实现组件的 ...

  4. flex 自定义组件的编写

    使用flex也很久了,也改过别人写的flex自定义组件,但是就是没有系统的研究下flex组件的编写步骤,和要注意的东西,在这里我参照一本书中的例子,好好的理解下,也为了巩固下自己对flex的理解! 1 ...

  5. 在Vue前端项目中,附件展示的自定义组件开发

    在Vue前端界面中,自定义组件很重要,也很方便,我们一般是把一些通用的界面模块进行拆分,创建自己的自定义组件,这样操作可以大大降低页面的代码量,以及提高功能模块的开发效率,本篇随笔继续介绍在Vue&a ...

  6. 自定义组件开发:使用v-model封装el-pagination组件

    1.前言 通过封装el-pagination组件开发自定义分页组件的类似文章网上已经有很多了,但看了一圈,总是不如意,于是决定还是自己动手搞一个. 2.背景 2.1.常规分页处理方法 利用el-pag ...

  7. jquery自定义组件开发

    jquery的组件已经有很多,但是有可能找不到符合我们需求的组件,所以我们可以动手自己封装一个jquery组件. 第一步要知道封装jquery组件的基本语法 (function ($) { $.fn. ...

  8. 使用vue的extend自定义组件开发

    index.js import Vue from 'vue' import tip from './tip.vue' const Constructor = Vue.extend(tip); cons ...

  9. 微信小程序自定义组件实现

    官方从 1.6.3 开始对于自定义组件这一块有了比较大的变动,首先比较明显的感觉就是文档比以前全多了,有木有!,现在小程序支持简洁的组件化编程,可以将页面内的功能模块抽象成自定义组件,以便在不同的页面 ...

随机推荐

  1. gitlab 启用HTTPS

    NGINX设置 启用HTTPS 警告 Nginx配置会告诉浏览器和客户端,只需在未来24个月通过安全连接与您的GitLab实例进行通信.通过启用HTTPS,您需要至少在24个月内为您的实例提供安全连接 ...

  2. Promise 初步

    在JavaScript的世界中,所有代码都是单线程执行的. 由于这个“缺陷”,导致JavaScript的所有网络操作,浏览器事件,都必须是异步执行.异步执行可以用回调函数实现: function ca ...

  3. XML与DataSet的相互转换的类

    一.XML与DataSet的相互转换的类 using System; using System.Collections.Generic; using System.Text; using System ...

  4. SQL Server 索引知识-应用,维护

    创建聚集索引 a索引键最好唯一(如果不唯一会隐形建立uniquier列(4字节)确保唯一,也就是这列都会复制到所有非聚集索引中) b聚集索引列所占空间应尽量小(否则也会使非聚集索引的空间变大) c聚集 ...

  5. 使用 PowerShell 创建 Linux 虚拟机

    Azure PowerShell 模块用于从 PowerShell 命令行或脚本创建和管理 Azure 资源. 本指南详细介绍了如何使用 Azure PowerShell 模块部署运行 Ubuntu ...

  6. npm install时报错“Unexpected end of JSON input while parsing near...”解决方法

    执行:npm cache clean --force 即可解决此问题

  7. 如何获取UITableView中cell的frame值

    如何获取UITableView中cell的frame值 这个可以用来处理UITableView弹出键盘的问题 本人视频教程系类   iOS中CALayer的使用 效果: 源码: // // ViewC ...

  8. [C++] 用Xcode来写C++程序[5] 函数的重载与模板

    用Xcode来写C++程序[5] 函数的重载与模板 此节包括函数重载,隐式函数重载,函数模板,带参数函数模板 函数的重载 #include <iostream> using namespa ...

  9. Hadoop HBase概念学习系列之hbase shell中执行java方法(高手必备)(二十五)

    hbase shell中执行java方法(高手必备),务必掌握! 1. 2. 3. 4. 更多命令,见scan help.在实际工作中,多用这个!!! API参考: http://hbase.apac ...

  10. VS2015 无法启动IIS Express Web服务器(已解决)

    VS2015 无法启动IIS Express Web服务器 首先说一下我遇到问题的情况.这个项目是在公司电脑创建的,运行一直是正常的.今天把项目拷贝回来做. 可是到自己的电脑上,运行就提示 无法启动I ...