• Flex自定义组件开发


    一般情况下需要组件重写都是由于以下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轴为各指标
    
         *  这里必须注意的是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
            //===========================
        }
    }

     附上另一作品,有想法的话欢迎交流,qq:719810496

  • 相关阅读:
    hadoop 2.6.0 LightWeightGSet源码分析
    推断扫描后的内容是否是URL
    Merge Sorted Array
    带条件的分页【重点】
    第8章2节《MonkeyRunner源代码剖析》MonkeyRunner启动执行过程-解析处理命令行參数
    php持续集成环境笔记
    hdu5137 How Many Maos Does the Guanxi Worth(单源最短路径)
    求最长公共子序列
    集团公司(嵌入ETL工具)財务报表系统解决方式
    ADT+NDK搭建jni编译环境
  • 原文地址:https://www.cnblogs.com/jackyWHJ/p/3615882.html
Copyright © 2020-2023  润新知