1////////////////////////////////////////////////////////////////////////////////
2//
3//  ADOBE SYSTEMS INCORPORATED
4//  Copyright 2009 Adobe Systems Incorporated
5//  All Rights Reserved.
6//
7//  NOTICE: Adobe permits you to use, modify, and distribute this file
8//  in accordance with the terms of the license agreement accompanying it.
9//
10////////////////////////////////////////////////////////////////////////////////
11
12package mx.charts
13{
14
15import flash.display.DisplayObject;
16import flash.filters.DropShadowFilter;
17import flash.system.ApplicationDomain;
18
19import mx.charts.chartClasses.CartesianChart;
20import mx.charts.chartClasses.CartesianTransform;
21import mx.charts.chartClasses.DataTip;
22import mx.charts.chartClasses.DataTransform;
23import mx.charts.chartClasses.IChartElement;
24import mx.charts.chartClasses.NumericAxis;
25import mx.charts.chartClasses.Series;
26import mx.charts.series.BarSeries;
27import mx.charts.series.BarSet;
28import mx.charts.series.items.BarSeriesItem;
29import mx.charts.styles.HaloDefaults;
30import mx.core.IFlexModuleFactory;
31import mx.core.mx_internal;
32import mx.graphics.SolidColor;
33import mx.graphics.SolidColorStroke;
34import mx.graphics.Stroke;
35import mx.styles.CSSStyleDeclaration;
36
37use namespace mx_internal;
38
39//--------------------------------------
40//  Styles
41//--------------------------------------
42
43/**
44 *  Specifies how wide to draw the bars relative to the category width,
45 *  as a percentage in the range of 0 to 1.
46 *  A value of 1 uses the entire space, while a value of 0.6
47 *  uses 60% of the bar's available space.
48 *  The actual bar width used is the smaller of the
49 *  <code>barWidthRatio</code> property and the
50 *  <code>maxbarWidth</code> property
51 *  Clustered bars divide this space proportionally
52 *  among the bars in each cluster.
53 *  The default value is 0.65.
54 *
55 *  @langversion 3.0
56 *  @playerversion Flash 9
57 *  @playerversion AIR 1.1
58 *  @productversion Flex 3
59 */
60[Style(name="barWidthRatio", type="Number", inherit="no")]
61
62/**
63 *  Specifies how wide to draw the bars, in pixels.
64 *  The actual bar width used is the smaller of this property
65 *  and the <code>barWidthRatio</code> property.
66 *  Clustered bars divide this space proportionally
67 *  among the bars in each cluster.
68 *
69 *  @langversion 3.0
70 *  @playerversion Flash 9
71 *  @playerversion AIR 1.1
72 *  @productversion Flex 3
73 */
74[Style(name="maxBarWidth", type="Number", format="Length", inherit="no")]
75
76/**
77 *  The class that is used by this component to render labels.
78 *
79 *  <p>It can be set to either the mx.controls.Label class
80 *  or the spark.components.Label class.</p>
81 *
82 *  @default spark.components.Label
83 *
84 *  @langversion 3.0
85 *  @playerversion Flash 10.2
86 *  @playerversion AIR 2.0
87 *  @productversion Flex 4
88 */
89[Style(name="labelClass", type="Class", inherit="no")]
90
91//--------------------------------------
92//  Other metadata
93//--------------------------------------
94
95[DefaultBindingProperty(destination="dataProvider")]
96
97[DefaultTriggerEvent("itemClick")]
98
99[IconFile("BarChart.png")]
100
101/**
102 *  The BarChart control represents data as a series of horizontal bars
103 *  whose length is determined by values in the data.
104 *  A BarChart control can represent different chart variations,
105 *  including simple bars, clustered bars, stacked, 100% stacked, and high/low.
106 *
107 *  <p>The BarChart control expects its <code>series</code> property
108 *  to contain an array of BarSeries objects.</p>
109 *
110 *  <p>Stacked and 100% bar charts override the <code>minField</code>
111 *  property of their BarSeries objects.</p>
112 *
113 *  @mxml
114 *
115 *  <p>The <code>&lt;mx:BarChart&gt;</code> tag inherits all the properties
116 *  of its parent classes, and adds the following properties:</p>
117 *
118 *  <pre>
119 *  &lt;mx:BarChart
120 *    <strong>Properties</strong>
121 *    type="clustered|overlaid|stacked|100%"
122 *
123 *    <strong>Styles</strong>
124 *    barWidthRatio=".65"
125 *    maxBarWidth="<i>No default</i>"
126 *  /&gt;
127 *  </pre>
128 *
129 *  @includeExample examples/Column_BarChartExample.mxml
130 *
131 *  @see mx.charts.series.BarSeries
132 *
133 *  @langversion 3.0
134 *  @playerversion Flash 9
135 *  @playerversion AIR 1.1
136 *  @productversion Flex 3
137 */
138public class BarChart extends CartesianChart
139{
140    include "../core/Version.as";
141
142    //--------------------------------------------------------------------------
143    //
144    //  Class initialization
145    //
146    //--------------------------------------------------------------------------
147
148    //--------------------------------------------------------------------------
149    //
150    //  Class constants
151    //
152    //--------------------------------------------------------------------------
153
154    /**
155     *  @private
156     */
157    private static var INVALIDATING_STYLES:Object =
158    {
159        barWidthRatio: 1,
160        maxBarWidth: 1
161    }
162
163    //--------------------------------------------------------------------------
164    //
165    //  Constructor
166    //
167    //--------------------------------------------------------------------------
168
169    /**
170     *  Constructor.
171     *
172     *  @langversion 3.0
173     *  @playerversion Flash 9
174     *  @playerversion AIR 1.1
175     *  @productversion Flex 3
176     */
177    public function BarChart()
178    {
179        super();
180
181        LinearAxis(verticalAxis).autoAdjust = false;
182
183        dataTipMode = "single";
184
185        seriesFilters = [ new DropShadowFilter(2, 45, 0.2 * 0xFFFFFF)];
186    }
187
188    //--------------------------------------------------------------------------
189    //
190    //  Variables
191    //
192    //--------------------------------------------------------------------------
193
194    /**
195     *  @private
196     */
197    private var _moduleFactoryInitialized:Boolean = false;
198
199    /**
200     *  @private
201     */
202    private var _perSeriesBarWidthRatio:Number;
203
204    /**
205     *  @private
206     */
207    private var _perSeriesMaxBarWidth:Number;
208
209    /**
210     *  @private
211     */
212    private var _rightOffset:Number;
213
214    /**
215     *  @private
216     */
217    private var _wasStacked:Boolean = false;
218
219    /**
220     * @private
221     */
222    mx_internal var allLabelsMeasured:Boolean = false;
223
224    /**
225     * @private
226     */
227    private var _allItems:Array /* of ChartItem */ = [];
228
229    /**
230     * @private
231     */
232    private var _barSeriesLen:Number;
233
234    /**
235     * @private
236     */
237    private var _needLabels:Boolean = false;
238
239    /**
240     * @private
241     */
242    private var _tempField:Object;
243
244    //--------------------------------------------------------------------------
245    //
246    //  Properties
247    //
248    //--------------------------------------------------------------------------
249
250    //----------------------------------
251    //  type
252    //----------------------------------
253
254    /**
255     *  @private
256     *  Storage for the type property.
257     */
258    private var _type:String = "clustered";
259
260    [Inspectable(category="General", enumeration="stacked,100%,clustered,overlaid", defaultValue="clustered")]
261
262    /**
263     *  The type of bar chart to render. Possible values are:
264     *  <ul>
265     *    <li><code>"clustered"</code>:
266     *    Bars are grouped by category.
267     *    This is the default value.</li>
268     *
269     *    <li><code>"overlaid"</code>:
270     *    Multiple bars are rendered on top of each other by category,
271     *    with the last series specified on top.</li>
272     *
273     *    <li><code>"stacked"</code>:
274     *    Bars are stacked end to end and grouped by category.
275     *    Each bar represents the cumulative value of the values beneath it.</li>
276     *
277     *    <li><code>"100%"</code>:
278     *    Bars are stacked end to end, adding up to 100%.
279     *    Each bar represents the percent that it contributes
280     *    to the sum of the values for that category.</li>
281     *  </ul>
282     *
283     *  @langversion 3.0
284     *  @playerversion Flash 9
285     *  @playerversion AIR 1.1
286     *  @productversion Flex 3
287     */
288    public function get type():String
289    {
290        return _type;
291    }
292
293    /**
294     *  @private
295     */
296    public function set type(value:String):void
297    {
298        _type = value;
299
300        invalidateSeries();
301        invalidateData();
302    }
303
304    //--------------------------------------------------------------------------
305    //
306    //  Overridden methods: UIComponent
307    //
308    //--------------------------------------------------------------------------
309
310
311    /**
312     *  @private
313     */
314    private function initStyles():Boolean
315    {
316        HaloDefaults.init(styleManager);
317		var barChartStyle:CSSStyleDeclaration = styleManager.getStyleDeclaration("mx.charts.BarChart");
318		barChartStyle.setStyle("chartSeriesStyles", HaloDefaults.chartBaseChartSeriesStyles);
319		barChartStyle.setStyle("fill", new SolidColor(0xFFFFFF, 0));
320		barChartStyle.setStyle("calloutStroke", new SolidColorStroke(0x888888,2));
321		barChartStyle.setStyle("horizontalAxisStyleNames", ["blockNumericAxis"]);
322		barChartStyle.setStyle("verticalAxisStyleNames", ["blockCategoryAxis"]);
323        return true;
324    }
325
326
327    /**
328     *   A module factory is used as context for using embedded fonts and for finding the style manager that controls the styles for this component.
329     *
330     *  @langversion 3.0
331     *  @playerversion Flash 9
332     *  @playerversion AIR 1.1
333     *  @productversion Flex 3
334     */
335    override public function set moduleFactory(factory:IFlexModuleFactory):void
336    {
337        super.moduleFactory = factory;
338
339        if (_moduleFactoryInitialized)
340            return;
341
342        _moduleFactoryInitialized = true;
343
344        // our style settings
345        initStyles();
346    }
347
348    /**
349     * @private
350     */
351    override protected function createChildren():void
352    {
353        super.createChildren();
354        var labelClass:Class = getLabelClass();
355        _tempField = new labelClass();
356        _tempField.visible = false;
357        _tempField.text="W...";
358        _tempField.toolTip = "";
359        addChild(_tempField as DisplayObject);
360        _tempField.validateNow();
361    }
362
363    private function getLabelClass():Class
364    {
365        var labelClass:Class = getStyle("labelClass");
366        if(labelClass == null)
367        {
368            try{
369                labelClass = Class(ApplicationDomain.currentDomain.
370                    getDefinition("spark.components::Label"));
371            }
372            catch(e:Error)
373            {
374                labelClass = Class(ApplicationDomain.currentDomain.
375                    getDefinition("mx.controls::Label"));
376            }
377        }
378        return labelClass;
379    }
380
381
382    /**
383     *  @private
384     */
385    override public function styleChanged(styleProp:String):void
386    {
387        if (styleProp == null || INVALIDATING_STYLES[styleProp] != undefined)
388            invalidateSeries();
389
390        super.styleChanged(styleProp);
391    }
392
393    //--------------------------------------------------------------------------
394    //
395    //  Overridden methods: ChartBase
396    //
397    //--------------------------------------------------------------------------
398
399    /**
400     *  @private
401     */
402    override protected function customizeSeries(seriesGlyph:Series, i:uint):void
403    {
404        if ((seriesGlyph is BarSeries) || (seriesGlyph is BarSet))
405        {
406            var series:Object = seriesGlyph;
407
408            if (!isNaN(_perSeriesBarWidthRatio))
409                series.barWidthRatio = _perSeriesBarWidthRatio;
410
411            if (!isNaN(_perSeriesMaxBarWidth))
412                series.maxBarWidth = _perSeriesMaxBarWidth;
413
414            if (_type == "overlaid")
415                series.offset = 0;
416            else
417                series.offset = _rightOffset - i * _perSeriesBarWidthRatio;
418
419            if (series is BarSeries)
420            {
421                series.stacker = null;
422                series.stackTotals = null;
423            }
424        }
425    }
426
427    /**
428     *  @private
429     */
430    override protected function applySeriesSet(seriesSet:Array /* of Series */,
431                                               transform:DataTransform):Array /* of Series */
432    {
433
434        var barWidthRatio:Number = getStyle("barWidthRatio");
435        var maxBarWidth:Number = getStyle("maxBarWidth");
436        var g:IChartElement;
437        var n:int = seriesSet.length;
438
439        switch (_type)
440        {
441            case "stacked":
442            case "100%":
443            {
444                _wasStacked = true;
445
446                for (var i:int = 0; i < n; i++)
447                {
448                    seriesSet[i].offset = 0;
449                }
450
451                var newSeriesGlyph:BarSet = new BarSet();
452                newSeriesGlyph.series = seriesSet;
453                for (i = 0; i < n; i++)
454                {
455                    g = seriesSet[i] as IChartElement;
456                    if (!g)
457                        continue;
458                    if (g.labelContainer)
459                        newSeriesGlyph.labelContainer.addChild(seriesSet[i].labelContainer);
460                }
461
462                if (!isNaN(barWidthRatio))
463                    newSeriesGlyph.barWidthRatio = barWidthRatio;
464
465                if (!isNaN(maxBarWidth))
466                    newSeriesGlyph.maxBarWidth = maxBarWidth;
467
468                newSeriesGlyph.type = _type;
469
470                invalidateData();
471                return [ newSeriesGlyph ];
472            }
473
474            case "clustered":
475            default:
476            {
477
478                var barSeriesCount:int = 0;
479                for each(var series:Series in seriesSet) {
480                    if(series is BarSet || series is BarSeries)
481                        barSeriesCount++;
482                }
483
484                _perSeriesBarWidthRatio = barWidthRatio / barSeriesCount;
485                _perSeriesMaxBarWidth = maxBarWidth / barSeriesCount;
486                _rightOffset = barWidthRatio / 2 - _perSeriesBarWidthRatio / 2;
487                n = seriesSet.length;
488                var count:int = 0;
489                for (i = 0; i < n; i++)
490                {
491                    var newSeries:IChartElement = seriesSet[i];
492                    if (newSeries is BarSeries || newSeries is BarSet)
493                    {
494                        customizeSeries(Series(seriesSet[i]), count);
495                        count++;
496                    }
497                }
498
499                return seriesSet;
500            }
501
502            case "overlaid":
503            {
504                _perSeriesBarWidthRatio = barWidthRatio;
505                _perSeriesMaxBarWidth = maxBarWidth;
506
507                _rightOffset = 0;
508                super.applySeriesSet(seriesSet, transform);
509                break;
510            }
511        }
512
513        return seriesSet;
514    }
515
516    //--------------------------------------------------------------------------
517    //
518    //  Overridden methods: CartesianChart
519    //
520    //--------------------------------------------------------------------------
521
522    /**
523     * Determines positions and dimensions of labels for all series in the chart
524     *
525     *  @langversion 3.0
526     *  @playerversion Flash 9
527     *  @playerversion AIR 1.1
528     *  @productversion Flex 3
529     */
530    override mx_internal function measureLabels():Object
531    {
532        getSeriesLabelPosSet();
533        if (!_needLabels)
534            return null;
535        var n:int = series.length;
536        var allSeriesTransform:Boolean = true;
537
538        if (type == "stacked" || type == "overlaid" || type == "100%")
539            allLabelsMeasured = false;
540
541        _allItems = [];
542        _barSeriesLen = 0;
543        for (var i:int = 0; i < n; i++)
544        {
545            findChartItems(series[i]);
546        }
547        _allItems.sort(sortOnY);    //sort all items with respect to thier position along Y-axis
548        var itemsLen:Number = _allItems.length;
549        for (i = itemsLen - 1; i >= 0; i--)
550        {
551            var v:BarSeriesItem = _allItems[i];
552            var barSeries:BarSeries = BarSeries(BarSeriesItem(_allItems[i]).element);
553            var labelPosition:String = barSeries.labelPos;
554
555            if (labelPosition == "inside" || labelPosition == "outside")
556            {
557
558                var base:Number = barSeries.seriesRenderData.renderedBase;
559                var size:Number = barSeries.getStyle('fontSize');
560                if (barSeries.labelFunction != null)
561                    barSeries.measuringField.text = v.labelText = barSeries.labelFunction(v, barSeries);
562                else if (barSeries.labelField != null)
563                    barSeries.measuringField.text = v.labelText = v.item[barSeries.labelField];
564                else if (barSeries.dataFunction != null)
565                    barSeries.measuringField.text = v.labelText = barSeries.dataFunction(barSeries, v.item, 'xNumber');
566                else
567                    barSeries.measuringField.text = v.labelText = v.item[barSeries.xField];
568
569                barSeries.measuringField.validateNow();
570
571                var labelRotation:Number = barSeries.labelAngle;
572                var labelSizeLimit:Number = barSeries.maxLabelSize;
573                if (labelPosition == "outside" && (type == "stacked" || type == "overlaid" || type == "100%"))
574                {
575                    labelPosition = "inside";
576                    barSeries.labelPos = 'inside';
577                        //today, labelPosition = inside is only supported for stacked, 100% and overlaid
578                }
579
580
581                if (labelPosition == 'outside')
582                {
583                    v.labelHeight = 2 * barSeries.seriesRenderData.renderedHalfWidth;
584                    if (!(isNaN(labelRotation)) && labelRotation != 0 && barSeries.measuringField.embedFonts)
585                    {
586                        var r:Number = -labelRotation / Math.PI * 180;
587                                //for future enhancement
588                                //check for type of chart if we need to support labelPosition = outside for all types of charts
589                        if (type == "clustered")
590                        {
591                            if (i > n - 1)
592                                v.labelWidth = Math.abs((_allItems[i - i%n - 1].y + BarSeries(_allItems[i - i%n - 1].element).seriesRenderData.renderedYOffset
593                                               + BarSeries(_allItems[i - i%n - 1].element).seriesRenderData.renderedHalfWidth -
594                                               (v.y + barSeries.seriesRenderData.renderedYOffset -
595                                               barSeries.seriesRenderData.renderedHalfWidth))/ Math.cos(r));
596                            else
597                                v.labelWidth = Math.abs((_allItems[0].y + BarSeries(_allItems[0].element).seriesRenderData.renderedYOffset
598                                               - BarSeries(_allItems[0].element).seriesRenderData.renderedHalfWidth -
599                                               (v.y + barSeries.seriesRenderData.renderedYOffset -
600                                               barSeries.seriesRenderData.renderedHalfWidth))/ Math.cos(r));
601                        }
602                        else
603                        {
604                            if (i > n - 1)
605                                v.labelWidth = Math.abs((_allItems[i - n].y + BarSeries(_allItems[i - n].element).seriesRenderData.renderedYOffset
606                                               + BarSeries(_allItems[i - n].element).seriesRenderData.renderedHalfWidth -
607                                               (v.y + barSeries.seriesRenderData.renderedYOffset -
608                                               barSeries.seriesRenderData.renderedHalfWidth))/ Math.cos(r));
609                            else
610                                v.labelWidth = Math.abs((_allItems[0].y + BarSeries(_allItems[0].element).seriesRenderData.renderedYOffset
611                                               - BarSeries(_allItems[0].element).seriesRenderData.renderedHalfWidth -
612                                               (v.y + barSeries.seriesRenderData.renderedYOffset -
613                                               barSeries.seriesRenderData.renderedHalfWidth))/ Math.cos(r));
614                        }
615                        v.labelY=v.y + barSeries.seriesRenderData.renderedYOffset + barSeries.seriesRenderData.renderedHalfWidth;
616                    }
617                    else
618                    {
619                        if (v.x > (isNaN(v.min) ? base : v.min))
620                        {
621                            v.labelWidth = barSeries.dataToLocal(NumericAxis(barSeries.dataTransform.getAxis(CartesianTransform.HORIZONTAL_AXIS)).computedMaximum,0).x - barSeries.dataToLocal(v.xNumber,0).x;
622                            v.labelX = v.x;
623                            if (v.labelWidth == 0)
624                            {
625                                v.labelWidth = Math.abs(v.x -(isNaN(v.min) ? base : v.min));
626                                v.labelX = isNaN(v.min) ? base : v.min;
627                            }
628                        }
629                        else
630                        {
631                            v.labelWidth = barSeries.dataToLocal(v.xNumber,0).x - barSeries.dataToLocal(NumericAxis(barSeries.dataTransform.getAxis(CartesianTransform.HORIZONTAL_AXIS)).computedMinimum,0).x;
632                            v.labelX = v.x - v.labelWidth;
633                            if (v.labelWidth == 0)
634                            {
635                                v.labelWidth = Math.abs(v.x -(isNaN(v.min) ? base : v.min));
636                                v.labelX = v.x;
637                            }
638                        }
639                        v.labelY=v.y + barSeries.seriesRenderData.renderedYOffset - barSeries.seriesRenderData.renderedHalfWidth;
640                    }
641                    var labelScale:Number = 1;
642                    if (barSeries.measuringField.textWidth > v.labelWidth || barSeries.measuringField.textHeight > v.labelHeight)
643                    {
644                        labelScale = v.labelWidth / barSeries.measuringField.textWidth;
645                        labelScale = Math.min(labelScale, v.labelHeight / barSeries.measuringField.textHeight);
646                        if (size * labelScale > labelSizeLimit)
647                            barSeries.seriesRenderData.labelScale = Math.min(labelScale,barSeries.seriesRenderData.labelScale);
648                        else
649                        {
650                            _tempField.setStyle('fontSize',size);
651                            _tempField.validateNow();
652                            if (_tempField.measuredWidth > v.labelWidth || _tempField.measuredHeight > v.labelHeight)
653                            {
654                                labelScale = v.labelWidth / _tempField.measuredWidth;
655                                labelScale = Math.min(labelScale, v.labelHeight / _tempField.measuredHeight);
656                                if (size * labelScale > labelSizeLimit)
657                                    barSeries.seriesRenderData.labelScale = Math.min(labelScale,barSeries.seriesRenderData.labelScale);
658                                else
659                                {
660                                    v.labelText = "";
661                                    v.labelWidth = 1;
662                                }
663                            }
664                        }
665                    }
666
667                    if (!isNaN(labelRotation) && labelRotation!=0 && barSeries.measuringField.embedFonts)
668                    {
669                        v.labelHeight = barSeries.measuringField.textHeight + 2;
670                        if (v.x > (isNaN(v.min) ? base : v.min))
671                            v.labelX = v.x + v.labelHeight;
672                        else
673                            v.labelX = v.x - 2 * v.labelHeight;
674                        v.labelY = v.labelY - v.labelHeight;
675                        v.labelWidth = v.labelWidth - v.labelHeight;
676                    }
677                }
678                else if (labelPosition == "inside")
679                {
680                    v.labelWidth = Math.abs(v.x -(isNaN(v.min) ? base : v.min));
681                    v.labelHeight = 2 * barSeries.seriesRenderData.renderedHalfWidth;
682                    v.labelY=v.y + barSeries.seriesRenderData.renderedYOffset - barSeries.seriesRenderData.renderedHalfWidth;
683
684                    if (v.x > (isNaN(v.min) ? base : v.min))
685                        v.labelX = isNaN(v.min) ? base : v.min;
686                    else
687                        v.labelX = v.x;
688                    labelScale = 1;
689                    if (barSeries.measuringField.textWidth > v.labelWidth || (barSeries.measuringField.textHeight) > v.labelHeight)
690                    {
691                        labelScale = v.labelWidth / barSeries.measuringField.textWidth;
692                        labelScale = Math.min(labelScale, v.labelHeight / barSeries.measuringField.textHeight);
693                        if (size * labelScale > labelSizeLimit)
694                            barSeries.seriesRenderData.labelScale = Math.min(labelScale,barSeries.seriesRenderData.labelScale);
695                        else
696                        {
697                            _tempField.setStyle('fontSize',size);
698                            _tempField.validateNow();
699                            if (_tempField.measuredWidth > v.labelWidth || _tempField.measuredHeight + 2 > v.labelHeight)
700                            {
701                                labelScale = v.labelWidth / _tempField.measuredWidth;
702                                labelScale = Math.min(labelScale, v.labelHeight / _tempField.measuredHeight);
703                                if (size * labelScale > labelSizeLimit)
704                                    barSeries.seriesRenderData.labelScale = Math.min(labelScale,barSeries.seriesRenderData.labelScale);
705                                else
706                                {
707                                    v.labelText = "";
708                                    v.labelWidth = 1;
709                                }
710                            }
711                        }
712                    }
713                    var prevItemsCount:int =_barSeriesLen - 1 - (i % _barSeriesLen);
714                    for (var j:int = 1; j <= prevItemsCount; j++)
715                            //test for overlaps with previous labels
716                    {
717                        var tempItem:BarSeriesItem = _allItems[i + j];
718                        if (v.labelY == tempItem.labelY)
719                        {
720                            if (((v.labelX >= tempItem.labelX) && (v.labelX < (tempItem.labelX + tempItem.labelWidth))) ||
721                                    ((v.labelX <= tempItem.labelX) && ((v.labelX + v.labelWidth) > tempItem.labelX)))
722                            {
723                                v.labelText = "";
724                                v.labelWidth = 1;
725                            }
726                        }
727                    }
728                }
729            }
730            else
731            {
732                barSeries.seriesRenderData.labelData = null;
733                barSeries.labelCache.count = 0;
734            }
735        }
736        allLabelsMeasured = true;
737        for (i = 0; i < n; i++)
738        {
739            invalidateDisplay(series[i]);
740        }
741        return null;
742    }
743
744    //------------------------------------------------------------------------------------
745    //
746    // Methods
747    //
748    //------------------------------------------------------------------------------------
749
750    mx_internal function getSeriesLabelPos(series:Series):void
751    {
752        if (series is BarSeries)
753        {
754            var barSeries:BarSeries = BarSeries(series);
755            var position:String = barSeries.labelPos;
756            if (position == "inside" || position == "outside" || position == "none")
757                _needLabels = true;
758        }
759        else if (series is BarSet)
760        {
761            var setSeries:Array /* of Series */ = BarSet(series).series;
762            var n:int = setSeries.length;
763            for (var i:int = 0; i < n; i++)
764            {
765                getSeriesLabelPos(setSeries[i]);
766            }
767        }
768    }
769
770    mx_internal function getSeriesLabelPosSet():void
771    {
772        var n:int = series.length;
773        _needLabels = false;
774        for (var i:int = 0; i < n; i++)
775        {
776            if (_needLabels)
777                return;
778            getSeriesLabelPos(series[i]);
779        }
780    }
781
782    /**
783     * @private
784     */
785     private function sortOnY(a:BarSeriesItem,b:BarSeriesItem):int
786     {
787        var offset1:Number = BarSeries(a.element).seriesRenderData.renderedYOffset;
788        var offset2:Number = BarSeries(b.element).seriesRenderData.renderedYOffset;
789        if (a.y + offset1 > b.y + offset2)
790            return 1;
791        else if (a.y + offset1 < b.y + offset2)
792            return -1;
793        else
794        {
795            if (a.xNumber > b.xNumber)
796                return 1;
797            else if (a.xNumber < b.xNumber)
798                return -1;
799            else
800                return 0;
801        }
802     }
803
804    /**
805     * @private
806     */
807     private function findChartItems(series:Series):void
808     {
809        var n:int;
810        var i:int;
811        if (series is BarSeries)
812        {
813            _barSeriesLen = _barSeriesLen + 1;
814            var barSeries:BarSeries = BarSeries(series);
815            var seriesItems:Array /* of BarSeriesItem */ = barSeries.seriesRenderData.filteredCache;
816            n = seriesItems.length;
817            barSeries.labelCache.count = n;
818            barSeries.seriesRenderData.labelScale = 1;
819
820            for (i = 0; i < n; i++)
821            {
822                _allItems.push(BarSeriesItem(seriesItems[i]));
823            }
824        }
825        else if (series is BarSet)
826        {
827            var setSeries:Array /* of Series */ = BarSet(series).series;
828            n = setSeries.length;
829            for (i = 0; i < n; i++)
830            {
831                findChartItems(setSeries[i]);
832            }
833        }
834     }
835    /**
836     * @private
837     */
838     private function invalidateDisplay(series:Series):void
839     {
840        if (series is BarSeries)
841            BarSeries(series).updateLabels();
842        else if (series is BarSet)
843        {
844            var setSeries:Array /* of Series */ = BarSet(series).series;
845            var n:int = setSeries.length;
846            for (var i:int = 0; i < n; i++)
847            {
848                invalidateDisplay(setSeries[i]);
849            }
850        }
851     }
852
853}
854
855}
856