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.series
13{
14
15import flash.display.DisplayObject;
16import flash.display.Graphics;
17import flash.display.Sprite;
18import flash.geom.Point;
19import flash.geom.Rectangle;
20import flash.system.ApplicationDomain;
21import flash.utils.Dictionary;
22
23import mx.charts.ColumnChart;
24import mx.charts.DateTimeAxis;
25import mx.charts.HitData;
26import mx.charts.chartClasses.CartesianChart;
27import mx.charts.chartClasses.CartesianTransform;
28import mx.charts.chartClasses.DataDescription;
29import mx.charts.chartClasses.GraphicsUtilities;
30import mx.charts.chartClasses.IAxis;
31import mx.charts.chartClasses.IColumn;
32import mx.charts.chartClasses.IStackable;
33import mx.charts.chartClasses.IStackable2;
34import mx.charts.chartClasses.InstanceCache;
35import mx.charts.chartClasses.LegendData;
36import mx.charts.chartClasses.NumericAxis;
37import mx.charts.chartClasses.Series;
38import mx.charts.chartClasses.StackedSeries;
39import mx.charts.renderers.BoxItemRenderer;
40import mx.charts.series.items.ColumnSeriesItem;
41import mx.charts.series.renderData.ColumnSeriesRenderData;
42import mx.charts.styles.HaloDefaults;
43import mx.collections.CursorBookmark;
44import mx.core.ClassFactory;
45import mx.core.IDataRenderer;
46import mx.core.IFactory;
47import mx.core.IFlexDisplayObject;
48import mx.core.IFlexModuleFactory;
49import mx.core.IUITextField;
50import mx.core.LayoutDirection;
51import mx.core.UIComponent;
52import mx.core.UITextField;
53import mx.core.mx_internal;
54import mx.graphics.IFill;
55import mx.graphics.SolidColor;
56import mx.styles.CSSStyleDeclaration;
57import mx.styles.ISimpleStyleClient;
58
59use namespace mx_internal;
60
61include "../styles/metadata/FillStrokeStyles.as"
62include "../styles/metadata/ItemRendererStyles.as"
63include "../styles/metadata/TextStyles.as"
64
65/**
66 *  Specifies an Array of fill objects that define the fill for
67 *  each item in the series. This takes precedence over the <code>fill</code> style property.
68 *  If a custom method is specified by the <code>fillFunction</code> property, that takes precedence over this Array.
69 *  If you do not provide enough Array elements for every item,
70 *  Flex repeats the fill from the beginning of the Array.
71 *
72 *  <p>To set the value of this property using CSS:
73 *   <pre>
74 *    ColumnSeries {
75 *      fills:#CC66FF, #9966CC, #9999CC;
76 *    }
77 *   </pre>
78 *  </p>
79 *
80 *  <p>To set the value of this property using MXML:
81 *   <pre>
82 *    &lt;mx:ColumnSeries ... &gt;
83 *     &lt;mx:fills&gt;
84 *      &lt;mx:SolidColor color="0xCC66FF"/&gt;
85 *      &lt;mx:SolidColor color="0x9966CC"/&gt;
86 *      &lt;mx:SolidColor color="0x9999CC"/&gt;
87 *     &lt;/mx:fills&gt;
88 *    &lt;/mx:ColumnSeries&gt;
89 *   </pre>
90 *  </p>
91 *
92 *  <p>
93 *  If you specify the <code>fills</code> property and you
94 *  want to have a Legend control, you must manually create a Legend control and
95 *  add LegendItems to it.
96 *  </p>
97 *
98 *  @langversion 3.0
99 *  @playerversion Flash 9
100 *  @playerversion AIR 1.1
101 *  @productversion Flex 3
102 */
103[Style(name="fills", type="Array", arrayType="mx.graphics.IFill", inherit="no")]
104
105/**
106 * Determines the alignment of the label. Considered only
107 * when labelPosition is <code>inside</code> and label is shown vertically.
108 * Possible values are <code>center</code>, <code>top</code>, and <code>bottom</code>.
109 *
110 * @default "center"
111 *
112 *  @langversion 3.0
113 *  @playerversion Flash 9
114 *  @playerversion AIR 1.1
115 *  @productversion Flex 3
116 */
117[Style(name="labelAlign", type="String", enumeration="top,center,bottom", inherit="no")]
118
119/**
120 *  The class that is used by this component to render labels.
121 *
122 *  <p>It can be set to either the mx.controls.Label class
123 *  or the spark.components.Label class.</p>
124 *
125 *  @default spark.components.Label
126 *
127 *  @langversion 3.0
128 *  @playerversion Flash 10.2
129 *  @playerversion AIR 2.0
130 *  @productversion Flex 4
131 */
132[Style(name="labelClass", type="Class", inherit="no")]
133
134/**
135 * Determines the position of labels
136 * Possible values are <code>none</code> , <code>outside</code>
137 * and <code>inside</code>.
138 *
139 * @default "none"
140 *
141 *  @langversion 3.0
142 *  @playerversion Flash 9
143 *  @playerversion AIR 1.1
144 *  @productversion Flex 3
145 */
146[Style(name="labelPosition", type="String", enumeration="none,outside,inside", inherit="no")]
147
148/**
149 *  @private
150 *  Specifies the label rotation.
151 *  Considered only if labelPosition is outside.
152 */
153[Style(name="labelRotation", type="Number", inherit="no")]
154
155/**
156 *  Specifies the font size threshold, in points,
157 *  below which labels are considered illegible.
158 *  Below this threshold, Flex truncates the label.
159 *
160 *  @langversion 3.0
161 *  @playerversion Flash 9
162 *  @playerversion AIR 1.1
163 *  @productversion Flex 3
164 */
165[Style(name="labelSizeLimit", type="Number", inherit="no")]
166
167/**
168 *  Defines a data series for a ColumnChart control. By default, this class uses the BoxItemRenderer class.
169 *  Optionally, you can define a custom itemRenderer for the
170 *  data series. The custom itemRenderer must implement the IDataRenderer interface.
171 *
172 *  @mxml
173 *  <p>
174 *  The <code>&lt;mx:ColumnSeries&gt;</code> tag inherits all the properties of its parent classes, and
175 *  the following properties:
176 *  </p>
177 *  <pre>
178 *  &lt;mx:ColumnSeries
179 *    <strong>Properties</strong>
180 *    columnWidthRatio=".65"
181 *    fillFunction="<i>Internal fill function</i>"
182 *    horizontalAxis="<i>No default</i>"
183 *    labelField="<i>No default</i>"
184 *    labelFunction="<i>No default</i>"
185 *    legendData="<i>No default</i>"
186 *    maxColumnWidth="<i>No default</i>"
187 *    minField="null"
188 *    offset="<i>No default</i>"
189 *    sortOnXField="false|true"
190 *    stacker="<i>No default</i>"
191 *    stackTotals="<i>No default</i>"
192 *    verticalAxis="<i>No default</i>"
193 *    xField="null"
194 *    yField="null"
195 *
196 *
197 *    <strong>Styles</strong>
198 *    fill="<i>IFill; no default</i>"
199 *    fills="<i>IFill; no default</i>"
200 *    fontFamily="Verdana"
201 *    fontSize="10"
202 *    fontStyle="italic|normal"
203 *    fontWeight="bold|normal"
204 *    labelAlign="center|left|right"
205 *    labelPosition="none|inside|outside"
206 *    labelSizeLimit="9"
207 *    itemRenderer="<i>BoxItemRenderer</i>"
208 *    legendMarkerRenderer="<i>Defaults to series's itemRenderer</i>"
209 *    stroke="<i>Stroke; no default</i>"
210 *    textDecoration="underline|none"
211 *  /&gt;
212 *  </pre>
213 *  </p>
214 *
215 *  @see mx.charts.ColumnChart
216 *
217 *  @includeExample ../examples/Column_BarChartExample.mxml
218 *
219 *
220 *  @langversion 3.0
221 *  @playerversion Flash 9
222 *  @playerversion AIR 1.1
223 *  @productversion Flex 3
224 */
225public class ColumnSeries extends Series implements IColumn,IStackable2
226{
227    include "../../core/Version.as";
228
229    //--------------------------------------------------------------------------
230    //
231    //  Class initialization
232    //
233    //--------------------------------------------------------------------------
234
235    //--------------------------------------------------------------------------
236    //
237    //  Constructor
238    //
239    //--------------------------------------------------------------------------
240
241    /**
242     *  Constructor.
243     *
244     *  @langversion 3.0
245     *  @playerversion Flash 9
246     *  @playerversion AIR 1.1
247     *  @productversion Flex 3
248     */
249    public function ColumnSeries()
250    {
251        super();
252
253        _instanceCache = new InstanceCache(null,this);
254        _instanceCache.creationCallback = applyItemRendererProperties;
255
256        _labelLayer = new UIComponent();
257        _labelLayer.styleName = this;
258
259        labelCache = new InstanceCache(getLabelClass(),_labelLayer);
260        labelCache.discard = true;
261        labelCache.properties =
262        {
263            styleName: this
264        };
265
266        dataTransform = new CartesianTransform();
267    }
268
269    private function getLabelClass():Class
270    {
271        var labelClass:Class = getStyle("labelClass");
272
273        if(labelClass == null)
274        {
275            try{
276                labelClass = Class(ApplicationDomain.currentDomain.
277                    getDefinition("spark.components::Label"));
278            }
279            catch(e:Error)
280            {
281                labelClass = Class(ApplicationDomain.currentDomain.
282                    getDefinition("mx.controls::Label"));
283            }
284        }
285        return labelClass;
286    }
287
288
289    //--------------------------------------------------------------------------
290    //
291    //  Variables
292    //
293    //--------------------------------------------------------------------------
294
295    /**
296     *  @private
297     */
298    private var _moduleFactoryInitialized:Boolean = false;
299
300    /**
301     *  @private
302     */
303    private var _instanceCache:InstanceCache;
304
305    /**
306     *  @private
307     */
308    mx_internal var labelCache:InstanceCache;
309
310    /**
311     *  @private
312     */
313    private var _labelLayer:UIComponent;
314
315    /**
316     *  @private
317     */
318    mx_internal var measuringField:IUITextField;
319
320    /**
321     *  @private
322     */
323    private var _renderData:ColumnSeriesRenderData;
324
325    /**
326     *  @private
327     */
328    private var _localFills:Array /* of IFill */;
329
330
331    /**
332     *  @private
333     */
334    private var _fillCount:int;
335
336   /**
337    * @private
338    */
339    mx_internal var labelPos:String = "none";
340
341   /**
342    * @private
343    */
344    mx_internal var labelAngle:Number;
345
346   /**
347    * @private
348    */
349    mx_internal var maxLabelSize:Number;
350
351    /**
352     * @private
353     */
354    private var _bAxesDirty:Boolean = false;
355
356    //--------------------------------------------------------------------------
357    //
358    //  Overridden Properties
359    //
360    //--------------------------------------------------------------------------
361
362    //-----------------------------------
363    // items
364    //-----------------------------------
365    /**
366     *  @inheritDoc
367     *
368     *  @langversion 3.0
369     *  @playerversion Flash 9
370     *  @playerversion AIR 1.1
371     *  @productversion Flex 3
372     */
373    override public function get items():Array /* of ColumnSeriesItem */
374    {
375        return _renderData ? _renderData.filteredCache : null;
376    }
377
378    //----------------------------------
379    //  labelContainer
380    //----------------------------------
381
382    /**
383     *  @private
384     */
385    override public function get labelContainer():Sprite
386    {
387        return _labelLayer;
388    }
389
390    //-----------------------------------
391    // legendData
392    //-----------------------------------
393    /**
394     *  @private
395     */
396
397    override public function get legendData():Array /* of LegendData */
398    {
399        if ((fillFunction!=defaultFillFunction) || _fillCount!=0)
400        {
401            var keyItems:Array /* of LegendData */ = [];
402            return keyItems;
403        }
404        var ld:LegendData = new LegendData();
405        var marker:IFlexDisplayObject;
406        var markerFactory:IFactory = getStyle("legendMarkerRenderer");
407        ld.element = this;
408        if (!markerFactory)
409            markerFactory = getStyle("itemRenderer");
410        if (markerFactory)
411        {
412            marker = markerFactory.newInstance();
413            if (marker as ISimpleStyleClient)
414                (marker as ISimpleStyleClient).styleName = this;
415        }
416        ld.marker = marker;
417        ld.label = displayName;
418
419        return [ld];
420
421    }
422
423    //---------------------------------------------------------------------
424    //
425    // Properties
426    //
427    //---------------------------------------------------------------------
428
429    //----------------------------------
430    //  columnWidthRatio
431    //----------------------------------
432
433    /**
434     *  @private
435     */
436    private var _columnWidthRatio:Number = 0.65;
437
438    [Inspectable(category="General", defaultValue="0.65")]
439
440    /**
441     *  Specifies the width of columns relative to the category width. A value of 1 uses the entire space, while a value of .6
442     *  uses 60% of the column's available space.
443     *  You typically do not set this property directly.
444     *  The actual column width used is the smaller of <code>columnWidthRatio</code> and the <code>maxColumnWidth</code> property.
445     *
446     *  @default 0.65
447     *
448     *  @langversion 3.0
449     *  @playerversion Flash 9
450     *  @playerversion AIR 1.1
451     *  @productversion Flex 3
452     */
453    public function get columnWidthRatio():Number
454    {
455        return _columnWidthRatio;
456    }
457
458    /**
459     *  @private
460     */
461    public function set columnWidthRatio(value:Number):void
462    {
463        _columnWidthRatio = value;
464
465        invalidateTransform();
466    }
467
468    //-----------------------------------
469    // fillFunction
470    //-----------------------------------
471
472    [Bindable]
473    [Inspectable(category="General")]
474
475    /**
476     * @private
477     * Storage for fillFunction property
478     */
479    private var _fillFunction:Function = defaultFillFunction;
480
481    /**
482     * Specifies a method that returns the fill for the current chart item in the series.
483     * If this property is set, the return value of the custom fill function takes precedence over the
484     * <code>fill</code> and <code>fills</code> style properties.
485     * But if it returns null, then <code>fills</code> and <code>fill</code> will be
486     * prefered in that order.
487     *
488     * <p>The custom <code>fillFunction</code> has the following signature:
489     *
490     * <pre>
491     * <i>function_name</i> (item:ChartItem, index:Number):IFill { ... }
492     * </pre>
493     *
494     * <code>item</code> is a reference to the chart item that is being rendered.
495     * <code>index</code> is the index of the chart item in the renderData's cache. This is different
496     * from the index of the chart's data provider because it is sorted based on the x, y, and z values.
497     * This function returns an object that implements the <code>IFill</code> interface.
498     * </p>
499     *
500     * <p>An example usage of a customized <code>fillFunction</code> is to return a fill
501     * based on some threshold.</p>
502     *
503     * @example
504     * <pre>
505     * public function myFillFunction(item:ChartItem, index:Number):IFill {
506     *      var curItem:ColumnSeriesItem = ColumnSeriesItem(item);
507     *      if (curItem.yNumber > 10)
508     *          return(new SolidColor(0x123456, .75));
509     *      else
510     *          return(new SolidColor(0x563412, .75));
511     * }
512     * </pre>
513     *
514     * <p>
515     *  If you specify a custom fill function for your chart series and you
516     *  want to have a Legend control, you must manually create a Legend control and
517     *  add LegendItems to it.
518     *  </p>
519     *
520     *  @langversion 3.0
521     *  @playerversion Flash 9
522     *  @playerversion AIR 1.1
523     *  @productversion Flex 3
524     */
525    public function get fillFunction():Function
526    {
527        return _fillFunction;
528    }
529
530    /**
531     * @private
532     */
533    public function set fillFunction(value:Function):void
534    {
535        if (value != null)
536            _fillFunction = value;
537
538        else
539            _fillFunction = defaultFillFunction;
540
541        invalidateProperties();
542        invalidateDisplayList();
543
544        legendDataChanged();
545    }
546
547    //----------------------------------
548    //  horizontalAxis
549    //----------------------------------
550
551    /**
552     *  @private
553     *  Storage for the horizontalAxis property.
554     */
555    private var _horizontalAxis:IAxis;
556
557    [Inspectable(category="Data")]
558
559    /**
560     *  Defines the labels, tick marks, and data position
561     *  for items on the x-axis.
562     *  Use either the LinearAxis class or the CategoryAxis class
563     *  to set the properties of the horizontalAxis as a child tag in MXML
564     *  or create a LinearAxis or CategoryAxis object in ActionScript.
565     *
566     *  @langversion 3.0
567     *  @playerversion Flash 9
568     *  @playerversion AIR 1.1
569     *  @productversion Flex 3
570     */
571    public function get horizontalAxis():IAxis
572    {
573        return _horizontalAxis;
574    }
575
576    /**
577     *  @private
578     */
579    public function set horizontalAxis(value:IAxis):void
580    {
581        _horizontalAxis = value;
582        _bAxesDirty = true;
583
584        invalidateData();
585        invalidateProperties();
586    }
587
588    //----------------------------------
589    //  itemType
590    //----------------------------------
591
592    [Inspectable(environment="none")]
593
594    /**
595     *  The subtype of ChartItem used by this series to represent individual items.
596     *  Subclasses can override and return a more specialized class if they need to store additional information in the items
597     *
598     *  @langversion 3.0
599     *  @playerversion Flash 9
600     *  @playerversion AIR 1.1
601     *  @productversion Flex 3
602     */
603    protected function get itemType():Class
604    {
605        return ColumnSeriesItem;
606    }
607
608    //---------------------------------
609    // labelField
610    //---------------------------------
611
612    /**
613     * @private
614     * Storage for labelField property
615     */
616    private var _labelField:String;
617
618    [Inspectable(category="General")]
619
620    /**
621     * Name of a field in the data provider whose value appears as the label.
622     * This property is ignored if the <code>labelFunction</code> property is specified.
623     *
624     *  @langversion 3.0
625     *  @playerversion Flash 9
626     *  @playerversion AIR 1.1
627     *  @productversion Flex 3
628     */
629    public function get labelField():String
630    {
631        return _labelField;
632    }
633
634    /**
635     * @private
636     */
637    public function set labelField(value:String):void
638    {
639        _labelField = value;
640        invalidateLabels();
641    }
642
643    //----------------------------------
644    //  labelFunction
645    //----------------------------------
646
647    /**
648     *  @private
649     *  Storage for the labelFunction property.
650     */
651    private var _labelFunction:Function;
652
653    [Inspectable(category="General")]
654
655    /**
656     *  Specifies a callback function used to render each label
657     *  of the Series.
658     *
659     *  A labelFunction must have the following signature:
660     *
661     * <pre>
662     * function <i>function_name</i>(<i>element</i>:ChartItem, <i>series</i>:Series):String { ... }
663     * </pre>
664     *
665     * <code><i>element</i></code> is the chart item that is being rendered.
666     *
667     * <code><i>series</i></code> is the series to which the chart item belongs.
668     *
669     * The returned String is the label of the current item.
670     *
671     * <p>An example usage of a customized labelFunction is as follows:</p>
672     * <pre>
673     * private function myLabelFunction(element:ChartItem, series:Series):String {
674     *      var item:ColumnSeriesItem = ColumnSeriesItem(element);
675     *      var ser:ColumnSeries = ColumnSeries(series);
676     *      return(item.item.Country + ":" +"" + ser.yField.toString() +":"+ item.yNumber);
677     * }
678     * </pre>
679     *
680     *
681     *  @langversion 3.0
682     *  @playerversion Flash 9
683     *  @playerversion AIR 1.1
684     *  @productversion Flex 3
685     */
686    public function get labelFunction():Function
687    {
688        return _labelFunction;
689    }
690
691    /**
692     *  @private
693     */
694    public function set labelFunction(value:Function):void
695    {
696        _labelFunction = value;
697
698        invalidateLabels();
699    }
700
701    //----------------------------------
702    //  maxColumnWidth
703    //----------------------------------
704
705    /**
706     *  @private
707     */
708    private var _maxColumnWidth:Number;
709
710    [Inspectable(category="General")]
711
712    /**
713     *  Specifies the width of the columns, in pixels. The actual column width used is the smaller
714     *  of this style and the <code>columnWidthRatio</code> property.
715     *  Clustered columns divide this space proportionally among the columns in each cluster.
716     *
717     *  @langversion 3.0
718     *  @playerversion Flash 9
719     *  @playerversion AIR 1.1
720     *  @productversion Flex 3
721     */
722    public function get maxColumnWidth():Number
723    {
724        return _maxColumnWidth;
725    }
726
727    /**
728     *  @private
729     */
730    public function set maxColumnWidth(value:Number):void
731    {
732        _maxColumnWidth = value;
733
734        invalidateTransform();
735    }
736
737    //----------------------------------
738    //  minField
739    //----------------------------------
740
741    /**
742     *  @private
743     */
744    private var _minField:String = "";
745
746    /**
747     *  @private
748     */
749    private var _userMinField:String = "";
750
751    [Inspectable(category="General")]
752
753    /**
754     *  Specifies the field of the data provider that determines the y-axis location of the bottom of a column.
755     *  If <code>null</code>, the columns are based at the range minimum (or maximum, if the field value is negative).
756     *  The default value is <code>null</code>.
757     *
758     *  @langversion 3.0
759     *  @playerversion Flash 9
760     *  @playerversion AIR 1.1
761     *  @productversion Flex 3
762     */
763    public function get minField():String
764    {
765        return _userMinField;
766    }
767
768    /**
769     *  @private
770     */
771    public function set minField(value:String):void
772    {
773        _userMinField = value;
774        _minField = value;
775
776        dataChanged();
777    }
778
779    //----------------------------------
780    //  offset
781    //----------------------------------
782
783    /**
784     *  @private
785     */
786    private var _offset:Number = 0;
787
788    [Inspectable(category="General", defaultValue="0")]
789
790    /**
791     *  Specifies how far to offset the center of the columns from the center of the available space, relative to the category width.
792     *  At the value of default 0, the columns are centered on the space.
793     *  Set to -50 to center the column at the beginning of the available space.
794     *  You typically do not set this property directly. The ColumnChart control manages this value based on
795     *  its <code>columnWidthRatio</code> property.
796     *
797     *  @langversion 3.0
798     *  @playerversion Flash 9
799     *  @playerversion AIR 1.1
800     *  @productversion Flex 3
801     */
802    public function get offset():Number
803    {
804        return _offset;
805    }
806
807    /**
808     *  @private
809     */
810    public function set offset(value:Number):void
811    {
812        _offset = value;
813
814        invalidateTransform();
815    }
816
817    //----------------------------------
818    //  renderDataType
819    //----------------------------------
820
821    [Inspectable(environment="none")]
822
823    /**
824     *  The subtype of ChartRenderData used by this series to store all data necessary to render.
825     *  Subclasses can override and return a more specialized class if they need to store additional information for rendering.
826     *
827     *  @langversion 3.0
828     *  @playerversion Flash 9
829     *  @playerversion AIR 1.1
830     *  @productversion Flex 3
831     */
832    protected function get renderDataType():Class
833    {
834        return ColumnSeriesRenderData;
835    }
836
837    //----------------------------------
838    //  sortOnXField
839    //----------------------------------
840
841    /**
842     *  @private
843     */
844    private var _sortOnXField:Boolean = false;
845
846    [Inspectable]
847
848    /**
849     *  Requests the columns be sorted from left to right before rendering. By default, the
850     *  ColumnSeries renders columns in the order they appear in the data provider.
851     *
852     *  <p>If you use the <code>xField</code> property to determine the position of each column,
853     *  columns can appear in a different order on the screen. Columns can be rendered in
854     *  any order. However, some custom columns might rely on the columns being rendered
855     *  from left to right.</p>
856     *
857     *  @default false
858     *
859     *  @langversion 3.0
860     *  @playerversion Flash 9
861     *  @playerversion AIR 1.1
862     *  @productversion Flex 3
863     */
864    public function get sortOnXField():Boolean
865    {
866        return _sortOnXField;
867    }
868
869    /**
870     *  @private
871     */
872    public function set sortOnXField(value:Boolean):void
873    {
874        if (_sortOnXField == value)
875            return;
876
877        _sortOnXField = value;
878
879        invalidateMapping();
880    }
881
882    //----------------------------------
883    //  stacker
884    //----------------------------------
885
886    /**
887     *  @private
888     */
889    private var _stacker:StackedSeries;
890
891    /**
892     *  @private
893     */
894    private var _stacked:Boolean = false;
895
896    /**
897     *  The StackedSeries associated with this BarSeries.
898     *  The stacker manages the series's stacking behavior.
899     *
900     *  @langversion 3.0
901     *  @playerversion Flash 9
902     *  @playerversion AIR 1.1
903     *  @productversion Flex 3
904     */
905    public function get stacker():StackedSeries
906    {
907        return _stacker;
908    }
909
910    /**
911     *  @private
912     */
913    public function set stacker(value:StackedSeries):void
914    {
915        _stacker = value;
916    }
917
918    //----------------------------------
919    //  verticalAxis
920    //----------------------------------
921
922    /**
923     *  @private
924     *  Storage for the verticalAxis property.
925     */
926    private var _verticalAxis:IAxis;
927
928    [Inspectable(category="Data")]
929
930    /**
931     *  Defines the labels, tick marks, and data position
932     *  for items on the y-axis.
933     *  Use either the LinearAxis class or the CategoryAxis class
934     *  to set the properties of the verticalAxis as a child tag in MXML
935     *  or create a LinearAxis or CategoryAxis object in ActionScript.
936     *
937     *  @langversion 3.0
938     *  @playerversion Flash 9
939     *  @playerversion AIR 1.1
940     *  @productversion Flex 3
941     */
942    public function get verticalAxis():IAxis
943    {
944        return _verticalAxis;
945    }
946
947    /**
948     *  @private
949     */
950    public function set verticalAxis(value:IAxis):void
951    {
952        _verticalAxis = value;
953        _bAxesDirty = true;
954
955        invalidateData();
956        //invalidateChildOrder();
957        invalidateProperties();
958    }
959
960    //----------------------------------
961    //  xField
962    //----------------------------------
963
964    /**
965     *  @private
966     */
967    private var _xField:String = "";
968
969    [Inspectable(category="General")]
970
971    /**
972     *  Specifies the field of the data provider that determines the x-axis location of the column.
973     *  If <code>null</code>, Flex renders the columns in the order they appear in the data provider.
974     *  The default value is <code>null</code>.
975     *
976     *  @langversion 3.0
977     *  @playerversion Flash 9
978     *  @playerversion AIR 1.1
979     *  @productversion Flex 3
980     */
981    public function get xField():String
982    {
983        return _xField;
984    }
985
986    /**
987     *  @private
988     */
989    public function set xField(value:String):void
990    {
991        _xField = value;
992
993        dataChanged();
994    }
995
996    //----------------------------------
997    //  yField
998    //----------------------------------
999
1000    /**
1001     *  @private
1002     */
1003    private var _yField:String = "";
1004
1005    [Inspectable(category="General")]
1006
1007    /**
1008     *  Specifies the field of the data provider that determines the y-axis location of the top of a column.
1009     *  If <code>null</code>, the ColumnSeries assumes the data provider is an Array of numbers and uses the numbers as values.
1010     *  The default value is <code>null</code>.
1011     *
1012     *  @langversion 3.0
1013     *  @playerversion Flash 9
1014     *  @playerversion AIR 1.1
1015     *  @productversion Flex 3
1016     */
1017    public function get yField():String
1018    {
1019        return _yField;
1020    }
1021
1022    /**
1023     *  @private
1024     */
1025    public function set yField(value:String):void
1026    {
1027        _yField = value;
1028
1029        dataChanged();
1030    }
1031
1032    //--------------------------------------------------------------------------
1033    //
1034    //  Overridden methods: UIComponent
1035    //
1036    //--------------------------------------------------------------------------
1037
1038    /**
1039     *  @private
1040     */
1041    private function initStyles():Boolean
1042    {
1043        HaloDefaults.init(styleManager);
1044
1045		var columnSeriesStyle:CSSStyleDeclaration = styleManager.getStyleDeclaration("mx.charts.series.ColumnSeries");
1046		columnSeriesStyle.setStyle("itemRenderer", new ClassFactory(mx.charts.renderers.BoxItemRenderer));
1047		columnSeriesStyle.setStyle("fill", new SolidColor(0x000000));
1048		columnSeriesStyle.setStyle("fills", []);
1049		columnSeriesStyle.setStyle("stroke", HaloDefaults.emptyStroke);
1050
1051        return true;
1052    }
1053
1054    /**
1055     *  @inheritDoc
1056     *
1057     *  @langversion 3.0
1058     *  @playerversion Flash 9
1059     *  @playerversion AIR 1.1
1060     *  @productversion Flex 3
1061     */
1062    override public function set moduleFactory(factory:IFlexModuleFactory):void
1063    {
1064        super.moduleFactory = factory;
1065
1066        if (_moduleFactoryInitialized)
1067            return;
1068
1069        _moduleFactoryInitialized = true;
1070
1071        // our style settings
1072        initStyles();
1073    }
1074
1075    /**
1076     *  @inheritDoc
1077     *
1078     *  @langversion 3.0
1079     *  @playerversion Flash 9
1080     *  @playerversion AIR 1.1
1081     *  @productversion Flex 3
1082     */
1083    override protected function createChildren():void
1084    {
1085        super.createChildren();
1086        measuringField = IUITextField(createInFontContext(UITextField));
1087        measuringField.visible = false;
1088        measuringField.styleName = this;
1089        addChild(DisplayObject(measuringField));
1090    }
1091
1092    /**
1093     *  @inheritDoc
1094     *
1095     *  @langversion 3.0
1096     *  @playerversion Flash 9
1097     *  @playerversion AIR 1.1
1098     *  @productversion Flex 3
1099     */
1100    override protected function commitProperties():void
1101    {
1102        super.commitProperties();
1103
1104        if (dataTransform)
1105        {
1106            if (_horizontalAxis)
1107            {
1108                _horizontalAxis.chartDataProvider = dataProvider;
1109                CartesianTransform(dataTransform).setAxis(
1110                    CartesianTransform.HORIZONTAL_AXIS,_horizontalAxis);
1111            }
1112
1113            if (_verticalAxis)
1114            {
1115                _verticalAxis.chartDataProvider = dataProvider;
1116                CartesianTransform(dataTransform).setAxis(
1117                    CartesianTransform.VERTICAL_AXIS, _verticalAxis);
1118            }
1119        }
1120
1121        var c:CartesianChart = CartesianChart(chart);
1122        if (c)
1123        {
1124            if (!_horizontalAxis)
1125            {
1126               if (dataTransform.axes[CartesianTransform.HORIZONTAL_AXIS] != c.horizontalAxis)
1127                        CartesianTransform(dataTransform).setAxis(
1128                            CartesianTransform.HORIZONTAL_AXIS,c.horizontalAxis);
1129            }
1130
1131            if (!_verticalAxis)
1132            {
1133                if (dataTransform.axes[CartesianTransform.VERTICAL_AXIS] != c.verticalAxis)
1134                        CartesianTransform(dataTransform).setAxis(
1135                            CartesianTransform.VERTICAL_AXIS, c.verticalAxis);
1136            }
1137        }
1138        dataTransform.elements = [this];
1139    }
1140
1141    /**
1142     *   @private
1143     */
1144     override public function stylesInitialized():void
1145     {
1146		_localFills = getStyle('fills');
1147        if (_localFills != null)
1148            _fillCount = _localFills.length;
1149        else
1150            _fillCount = 0;
1151        labelPos = getStyle('labelPosition');
1152        if (labelPos == "none")
1153            labelPos = "";
1154        labelAngle = getStyle('labelRotation');
1155        maxLabelSize = getStyle('labelSizeLimit');
1156        super.stylesInitialized();
1157     }
1158    /**
1159     *  @inheritDoc
1160     *
1161     *  @langversion 3.0
1162     *  @playerversion Flash 9
1163     *  @playerversion AIR 1.1
1164     *  @productversion Flex 3
1165     */
1166    override protected function invalidateData(invalid:Boolean=true):void
1167    {
1168        if (_stacker)
1169            _stacker.invalidateStacking();
1170        super.invalidateData(invalid);
1171    }
1172
1173    /**
1174     *  @inheritDoc
1175     *
1176     *  @langversion 3.0
1177     *  @playerversion Flash 9
1178     *  @playerversion AIR 1.1
1179     *  @productversion Flex 3
1180     */
1181    override protected function invalidateMapping(invalid:Boolean=true):void
1182    {
1183        if (_stacker)
1184            _stacker.invalidateStacking();
1185        super.invalidateMapping(invalid);
1186    }
1187
1188    /**
1189     *  @private
1190     */
1191    override protected function updateData():void
1192    {
1193        if (_stacker)
1194        {
1195            _stacker.stack();
1196            super.updateData();
1197            return;
1198        }
1199        _stacked = false;
1200
1201        var renderDataType:Class = this.renderDataType;
1202        _renderData= new renderDataType();
1203        _renderData.cache = [];
1204
1205        var i:uint = 0;
1206        var itemClass:Class = itemType;
1207        var v:ColumnSeriesItem;
1208        if (cursor)
1209        {
1210            cursor.seek(CursorBookmark.FIRST);
1211            while (!cursor.afterLast)
1212            {
1213                _renderData.cache[i] = v = new itemClass(this,cursor.current,i);
1214                i++;
1215                cursor.moveNext();
1216
1217            }
1218
1219        }
1220        cacheIndexValues(_xField,_renderData.cache,"xValue");
1221        cacheDefaultValues(_yField,_renderData.cache,"yValue");
1222
1223        if (_minField != "")
1224        {
1225            cacheNamedValues(_minField,_renderData.cache,"minValue");
1226            _renderData.renderedBase = NaN;
1227        }
1228        if(dataTransform && dataTransform.getAxis(CartesianTransform.VERTICAL_AXIS) is NumericAxis &&
1229            !(dataTransform.getAxis(CartesianTransform.VERTICAL_AXIS) is DateTimeAxis) &&
1230            (dataTransform.getAxis(CartesianTransform.VERTICAL_AXIS) as NumericAxis).direction == "inverted")
1231            _renderData.cache = reverseYValues(_renderData.cache);
1232        if(dataTransform && dataTransform.getAxis(CartesianTransform.HORIZONTAL_AXIS) is NumericAxis &&
1233            !(dataTransform.getAxis(CartesianTransform.HORIZONTAL_AXIS) is DateTimeAxis) &&
1234            (dataTransform.getAxis(CartesianTransform.HORIZONTAL_AXIS) as NumericAxis).direction == "inverted")
1235            _renderData.cache = reverseXValues(_renderData.cache);
1236        super.updateData();
1237    }
1238
1239    /**
1240     *  @private
1241     */
1242    override protected function updateMapping():void
1243    {
1244        dataTransform.getAxis(CartesianTransform.HORIZONTAL_AXIS).mapCache(_renderData.cache,"xValue","xNumber",(_xField == ""));
1245        dataTransform.getAxis(CartesianTransform.VERTICAL_AXIS).mapCache(_renderData.cache,"yValue","yNumber");
1246        if (_minField != "" || _stacked)
1247        {
1248            dataTransform.getAxis(CartesianTransform.VERTICAL_AXIS).mapCache(_renderData.cache,"minValue","minNumber");
1249        }
1250
1251        // now convert
1252        if (_xField != "" && _sortOnXField)
1253            _renderData.cache.sortOn("xNumber",Array.NUMERIC);
1254        super.updateMapping();
1255
1256    }
1257
1258
1259    /**
1260     *  @private
1261     */
1262    override protected function updateFilter():void
1263    {
1264        _renderData.filteredCache = filterFunction(_renderData.cache);
1265        super.updateFilter();
1266    }
1267
1268    /**
1269     *  @private
1270     */
1271    override protected function updateTransform():void
1272    {
1273        var n:int;
1274        var i:int;
1275
1276        if (_minField != "" || _stacked)
1277            dataTransform.transformCache(_renderData.filteredCache,null,null,"minNumber","min");
1278        else
1279        {
1280            var baseVal:Number = dataTransform.getAxis(CartesianTransform.VERTICAL_AXIS).baseline;
1281            var stub:Array /* of Object */ = [ { yNumber:baseVal } ];
1282            dataTransform.transformCache(stub,null,null,"yNumber","y");
1283            n = _renderData.filteredCache.length;
1284            _renderData.renderedBase = stub[0].y;
1285            for (i = 0; i < n; i++)
1286            {
1287                _renderData.filteredCache[i].min=_renderData.renderedBase;
1288            }
1289        }
1290        dataTransform.transformCache(_renderData.filteredCache,"xNumber","x","yNumber","y");
1291
1292
1293        var unitSize:Number = dataTransform.getAxis(CartesianTransform.HORIZONTAL_AXIS).unitSize;
1294
1295        var params:Array /* of Object */ = [{ xNumber:0 }, { xNumber:_columnWidthRatio*unitSize/2 },{ xNumber:_offset*unitSize }];
1296        dataTransform.transformCache(params,"xNumber","x",null,null);
1297
1298        if (!isNaN(_maxColumnWidth) && (_maxColumnWidth <= 0 || _columnWidthRatio <= 0))
1299            return;
1300
1301        if(params[1].x < params[0].x)   //direction is reverse for X-axis
1302        {
1303            params[0].x = - (params[0].x);
1304            params[1].x = - (params[1].x);
1305            params[2].x = - (params[2].x);
1306        }
1307        _renderData.renderedHalfWidth = (params[1].x -  params[0].x);
1308
1309        if (_offset == 0)
1310        {
1311            _renderData.renderedXOffset = 0;
1312        }
1313        else
1314        {
1315            _renderData.renderedXOffset = (params[2].x -  params[0].x);
1316        }
1317        if (!isNaN(_maxColumnWidth) && _maxColumnWidth < _renderData.renderedHalfWidth)
1318        {
1319            _renderData.renderedXOffset *=   _maxColumnWidth/_renderData.renderedHalfWidth;
1320            _renderData.renderedHalfWidth = _maxColumnWidth;
1321        }
1322
1323        labelPos = getStyle('labelPosition');
1324        var temp:IUITextField = IUITextField(createInFontContext(UITextField));
1325        temp.text = "W";
1326        if (labelPos=="inside")
1327        {
1328            if (temp.textWidth > 2 * _renderData.renderedHalfWidth)
1329            {
1330                if (measuringField.embedFonts)
1331                {
1332                    if (temp.textHeight > 2 * renderData.renderedHalfWidth)
1333                    {
1334                        labelPos = "";
1335                        labelCache.count = 0;
1336                    }
1337                }
1338                else
1339                {
1340                    labelPos = "";
1341                    labelCache.count = 0;
1342                }
1343            }
1344        }
1345        else if (labelPos=="outside")
1346        {
1347            if (chart  && chart is ColumnChart)
1348            {
1349                if (!(ColumnChart(chart).showLabelVertically))
1350                {
1351                    if (temp.textWidth / 2 > 2 * _renderData.renderedHalfWidth) // .25% of column width
1352                    {
1353                        labelPos = "";
1354                        labelCache.count = 0;
1355                    }
1356                }
1357                else
1358                {
1359                    if (temp.textWidth > 2 * _renderData.renderedHalfWidth) // .25% of column width
1360                    {
1361                        if (measuringField.embedFonts)
1362                        {
1363                            if (temp.textHeight > 2 * renderData.renderedHalfWidth)
1364                            {
1365                                labelPos = "";
1366                                labelCache.count = 0;
1367                            }
1368                        }
1369                        else
1370                        {
1371                            labelPos = "";
1372                            labelCache.count = 0;
1373                        }
1374                    }
1375                }
1376            }
1377        }
1378        super.updateTransform();
1379        allSeriesTransform = true;
1380        if (chart && chart is CartesianChart)
1381        {
1382            var cChart:CartesianChart = CartesianChart(chart);
1383            n = cChart.series.length;
1384
1385            for (i = 0; i < n; i++)
1386            {
1387                if (cChart.getSeriesTransformState(cChart.series[i]))
1388                    allSeriesTransform = false;
1389            }
1390
1391            if (allSeriesTransform)
1392                cChart.measureLabels();
1393        }
1394    }
1395
1396
1397    /**
1398     *  @private
1399     */
1400    override protected function updateDisplayList(unscaledWidth:Number,
1401                                                  unscaledHeight:Number):void
1402    {
1403        super.updateDisplayList(unscaledWidth, unscaledHeight);
1404
1405        if (!dataTransform)
1406        {
1407            labelCache.count=0;
1408            return;
1409        }
1410
1411        var g:Graphics = graphics;
1412        g.clear();
1413
1414        _labelLayer.graphics.clear();
1415
1416        if (!dataProvider)
1417        {
1418            labelCache.count=0;
1419            return;
1420        }
1421
1422        if (!isNaN(_maxColumnWidth) && (_maxColumnWidth <= 0 || _columnWidthRatio <= 0))
1423            return;
1424
1425        var renderData:ColumnSeriesRenderData = (transitionRenderData == null)? _renderData:ColumnSeriesRenderData(transitionRenderData);
1426        var activeCount:Array /* of ColumnSeriesItem */ = renderData.filteredCache;
1427
1428        var i:uint;
1429        var sampleCount:uint = activeCount.length;
1430
1431        var rc:Rectangle;
1432        var instances:Array /* of IFlexDisplayObject */;
1433        var inst:IFlexDisplayObject;
1434        var v:ColumnSeriesItem;
1435
1436        _instanceCache.factory = getStyle("itemRenderer");
1437        _instanceCache.count = sampleCount;
1438
1439        instances = _instanceCache.instances;
1440
1441        var bSetData:Boolean = (sampleCount > 0 && (instances[0] is IDataRenderer))
1442
1443        if (renderData.length == 0)
1444        {
1445            labelCache.count = 0;
1446            _instanceCache.count = 0;
1447            if (chart && (chart.showAllDataTips || chart.dataTipItemsSet))
1448                chart.updateAllDataTips();
1449            return;
1450        }
1451
1452        if (transitionRenderData && transitionRenderData.elementBounds)
1453        {
1454            var elementBounds:Array /* of Rectangle */ = transitionRenderData.elementBounds;
1455            labelCache.count = 0;
1456            for (i = 0; i < sampleCount; i++)
1457            {
1458                inst = instances[i];
1459                v = activeCount[i];
1460                v.fill = fillFunction(v,i);
1461                if (!(v.fill))
1462                    v.fill = defaultFillFunction(v,i);
1463                v.itemRenderer = inst;
1464                if ((v.itemRenderer as Object).hasOwnProperty('invalidateDisplayList'))
1465                    (v.itemRenderer as Object).invalidateDisplayList();
1466                if (bSetData)
1467                    (inst as IDataRenderer).data = v;
1468                rc = elementBounds[i];
1469                inst.move(rc.left,rc.top);
1470                inst.setActualSize(rc.width,rc.height);
1471            }
1472        }
1473        else
1474        {
1475            var ro:Number = renderData.renderedHalfWidth + renderData.renderedXOffset;
1476            var lo:Number = - renderData.renderedHalfWidth + renderData.renderedXOffset;
1477
1478            rc = new Rectangle();
1479            rc.bottom = Number((_minField == "")? - renderData.renderedBase : 0);
1480
1481            for (i = 0; i < sampleCount; i++)
1482            {
1483                v = activeCount[i];
1484
1485                rc.left = v.x + lo;
1486                rc.right = v.x + ro;
1487                rc.top = v.y;
1488                if (!isNaN(v.min))
1489                    rc.bottom = v.min;
1490                else
1491                    rc.bottom = renderData.renderedBase;
1492                inst = instances[i];
1493                v.fill = fillFunction(v,i);
1494                if (!(v.fill))
1495                    v.fill = defaultFillFunction(v,i);
1496                v.itemRenderer = inst;
1497                if ((v.itemRenderer as Object).hasOwnProperty('invalidateDisplayList'))
1498                    (v.itemRenderer as Object).invalidateDisplayList();
1499
1500                if (bSetData)
1501                    (inst as IDataRenderer).data = v;
1502
1503                inst.move(rc.left,rc.top);
1504                inst.setActualSize(rc.width,rc.height);
1505            }
1506
1507            if (chart && allSeriesTransform && chart.chartState == 0)
1508                chart.updateAllDataTips();
1509        }
1510    }
1511
1512    /**
1513     *  @private
1514     */
1515    override public function describeData(dimension:String, requiredFields:uint) :Array /* of DataDescription */
1516    {
1517        validateData();
1518
1519        if (_renderData.cache.length == 0)
1520            return [];
1521
1522        var description:DataDescription = new DataDescription();
1523        description.boundedValues = null;
1524
1525        if (dimension == CartesianTransform.VERTICAL_AXIS)
1526        {
1527            extractMinMax(_renderData.cache,"yNumber",description);
1528            if (_minField != "")
1529                extractMinMax(_renderData.cache,"minNumber",description);
1530
1531        }
1532        else if (dimension == CartesianTransform.HORIZONTAL_AXIS)
1533        {
1534            if (_xField != "")
1535            {
1536                if (_sortOnXField == false && (requiredFields & DataDescription.REQUIRED_MIN_INTERVAL) != 0)
1537                {
1538                    // if we need to know the min interval, then we rely on the cache being in order. So we need to sort it if it
1539                    // hasn't already been sorted
1540                    var sortedCache:Array /* of ColumnSeriesItem */ = _renderData.cache.concat();
1541                    sortedCache.sortOn("xNumber",Array.NUMERIC);
1542                    extractMinMax(sortedCache,"xNumber",description, (requiredFields & DataDescription.REQUIRED_MIN_INTERVAL) != 0);
1543                }
1544                else
1545                {
1546                    extractMinMax(_renderData.cache,"xNumber",description, (requiredFields & DataDescription.REQUIRED_MIN_INTERVAL) != 0);
1547                }
1548            }
1549            else
1550            {
1551                description.min = _renderData.cache[0].xNumber;
1552                description.max = _renderData.cache[_renderData.cache.length-1].xNumber;
1553                if ((requiredFields & DataDescription.REQUIRED_MIN_INTERVAL) != 0)
1554                {
1555                    extractMinInterval(_renderData.cache,"xNumber",description);
1556                }
1557            }
1558
1559            description.padding = .5;
1560        }
1561        else
1562            return [];
1563
1564        return [description];
1565    }
1566
1567    /**
1568     *  @private
1569     */
1570    override public function getAllDataPoints():Array /* of HitData */
1571    {
1572        if (!_renderData)
1573            return [];
1574        if (!(_renderData.filteredCache))
1575            return [];
1576
1577        var itemArr:Array /* of ColumnSeriesItem */ = [];
1578        if (chart && chart.dataTipItemsSet && dataTipItems)
1579            itemArr = dataTipItems;
1580        else if (chart  && chart.showAllDataTips && _renderData.filteredCache)
1581            itemArr = _renderData.filteredCache;
1582        else
1583            itemArr = [];
1584
1585        var n:uint = itemArr.length;
1586        var i:uint;
1587        var right:Number = unscaledWidth;
1588        var result:Array /* of HitData */ = [];
1589
1590        for (i = 0; i < n; i++)
1591        {
1592            var v:ColumnSeriesItem = itemArr[i];
1593            if (_renderData.filteredCache.indexOf(v) == -1)
1594            {
1595                var itemExists:Boolean = false;
1596                var m:int  = _renderData.filteredCache.length;
1597                for (var j:int = 0; j < m; j++)
1598                {
1599                    if (v.item == _renderData.filteredCache[j].item)
1600                    {
1601                        v = _renderData.filteredCache[j];
1602                        itemExists = true;
1603                        break;
1604                    }
1605                }
1606                if (!itemExists)
1607                    continue;
1608            }
1609            if (v.x + _renderData.renderedXOffset + _renderData.renderedHalfWidth <= 0)
1610                continue;
1611            if (v.x + _renderData.renderedXOffset - _renderData.renderedHalfWidth >= right)
1612                continue;
1613
1614            var base:Number = ((isNaN(v.min))? _renderData.renderedBase : v.min);
1615
1616            if (v)
1617            {
1618                var ypos:Number;
1619                if (v.yNumber >= 0)
1620                    ypos = (isNaN(v.min))? v.y : Math.min(v.y,v.min);
1621                else
1622                    ypos = (isNaN(v.min))? v.y : Math.max(v.y,v.min);
1623                var id:uint = v.index;
1624                var hd:HitData = new HitData(createDataID(id),Math.sqrt(0),v.x + _renderData.renderedXOffset,ypos,v);
1625                hd.dataTipFunction = formatDataTip;
1626                var fill:IFill = ColumnSeriesItem(hd.chartItem).fill;
1627                hd.contextColor = GraphicsUtilities.colorFromFill(fill);
1628                result.push(hd);
1629            }
1630        }
1631        return result;
1632    }
1633
1634    /**
1635     *  @private
1636     */
1637    override public function findDataPoints(x:Number,y:Number,sensitivity:Number):Array /* of HitData */
1638    {
1639        // esg, 8/7/06: if your mouse is over a series when it gets added and displayed for the first time, this can get called
1640        // before updateData, and before and render data is constructed. The right long term fix is to make sure a stubbed out
1641        // render data is _always_ present, but that's a little disruptive right now.
1642        if (interactive == false || !_renderData)
1643            return [];
1644
1645
1646
1647        var minDist:Number = _renderData.renderedHalfWidth + sensitivity;
1648        var minItem:ColumnSeriesItem;
1649
1650        var n:uint = _renderData.filteredCache.length;
1651        var i:uint;
1652        var right:Number = unscaledWidth;
1653
1654        for (i = 0; i < n; i++)
1655        {
1656            var v:ColumnSeriesItem = _renderData.filteredCache[i];
1657
1658            if (v.x + _renderData.renderedXOffset + _renderData.renderedHalfWidth <= 0)
1659                continue;
1660            if (v.x + _renderData.renderedXOffset - _renderData.renderedHalfWidth >= right)
1661                continue;
1662
1663            var dist:Number = Math.abs((v.x + _renderData.renderedXOffset) - x);
1664            if (dist > minDist)
1665                continue;
1666
1667            var base:Number = ((isNaN(v.min))? _renderData.renderedBase : v.min);
1668            var max:Number = Math.max(v.y,base);
1669            var min:Number = Math.min(v.y,base);
1670
1671
1672            if (min - y > sensitivity)
1673                continue;
1674
1675            if (y - max > sensitivity)
1676                continue;
1677
1678            minDist = dist;
1679            minItem = v;
1680            if (dist < _renderData.renderedHalfWidth)
1681            {
1682                // we're actually inside the column, so go no further.
1683                break;
1684            }
1685        }
1686
1687        if (minItem)
1688        {
1689            var ypos:Number
1690            if (minItem.yNumber >= 0)
1691                ypos = (isNaN(minItem.min))? minItem.y : Math.min(minItem.y,minItem.min);
1692            else
1693                ypos = (isNaN(minItem.min))? minItem.y : Math.max(minItem.y,minItem.min);
1694            var id:uint = minItem.index;
1695            var hd:HitData = new HitData(createDataID(id),Math.sqrt(minDist),minItem.x + _renderData.renderedXOffset,ypos,minItem);
1696            hd.dataTipFunction = formatDataTip;
1697            var fill:IFill = ColumnSeriesItem(hd.chartItem).fill;
1698            hd.contextColor = GraphicsUtilities.colorFromFill(fill);
1699            return [hd];
1700        }
1701        return [];
1702    }
1703
1704    /**
1705     *  @private
1706     */
1707    override public function dataToLocal(... dataValues):Point
1708    {
1709        var data:Object = {};
1710        var da:Array /* of Object */ = [ data ];
1711        var n:int = dataValues.length;
1712
1713        if (n > 0)
1714        {
1715            data["d0"] = dataValues[0];
1716            dataTransform.getAxis(CartesianTransform.HORIZONTAL_AXIS).
1717                mapCache(da, "d0", "v0");
1718        }
1719
1720        if (n > 1)
1721        {
1722            data["d1"] = dataValues[1];
1723            dataTransform.getAxis(CartesianTransform.VERTICAL_AXIS).
1724                mapCache(da, "d1", "v1");
1725        }
1726
1727        dataTransform.transformCache(da,"v0","s0","v1","s1");
1728
1729        return new Point(data.s0 + this.x,
1730                         data.s1 + this.y);
1731    }
1732
1733    /**
1734     *  @private
1735     */
1736    override public function localToData(v:Point):Array /* of Object */
1737    {
1738        var values:Array /* of Object */ = dataTransform.invertTransform(
1739                                            v.x - this.x,
1740                                            v.y - this.y);
1741        return values;
1742    }
1743
1744    /**
1745     *  @private
1746     */
1747    override public function getItemsInRegion(r:Rectangle):Array /* of ColumnSeriesItem */
1748    {
1749        // esg, 8/7/06: if your mouse is over a series when it gets added and displayed for the first time, this can get called
1750        // before updateData, and before and render data is constructed. The right long term fix is to make sure a stubbed out
1751        // render data is _always_ present, but that's a little disruptive right now.
1752        if (interactive == false || !_renderData)
1753            return [];
1754
1755        var arrItems:Array /* of ColumnSeriesItem */ = [];
1756        var rc:Rectangle = new Rectangle();
1757        var localRectangle:Rectangle = new Rectangle();
1758        var n:uint = _renderData.filteredCache.length;
1759
1760        localRectangle.topLeft = globalToLocal(r.topLeft);
1761        localRectangle.bottomRight = globalToLocal(r.bottomRight);
1762
1763
1764        for (var i:int = 0; i < n; i++)
1765        {
1766            var v:ColumnSeriesItem = _renderData.filteredCache[i];
1767
1768            var ro:Number = renderData.renderedHalfWidth + renderData.renderedXOffset;
1769            var lo:Number = - renderData.renderedHalfWidth + renderData.renderedXOffset;
1770
1771
1772            rc.left = v.x + lo;
1773            rc.right = v.x + ro;
1774            rc.top = v.y;
1775            if (!isNaN(v.min))
1776                rc.bottom = v.min;
1777            else
1778                rc.bottom = _renderData.renderedBase;
1779
1780            // Handle cases when width and height are -ve.
1781            if (rc.right < rc.left || rc.bottom < rc.top)
1782            {
1783                var rcTemp:Rectangle = new Rectangle(rc.x,rc.y,rc.width,rc.height);
1784                if (rc.right < rc.left)
1785                {
1786                    rcTemp.left = rc.right;
1787                    rcTemp.right = rc.left;
1788                }
1789                if (rc.bottom < rc.top)
1790                {
1791                    rcTemp.top = rc.bottom;
1792                    rcTemp.bottom = rc.top;
1793                }
1794                rc = rcTemp;
1795            }
1796
1797            if (rc.intersects(localRectangle))
1798                arrItems.push(v);
1799        }
1800        return arrItems;
1801    }
1802
1803    /**
1804     *  @private
1805     */
1806    override public function styleChanged(styleProp : String) : void
1807    {
1808        super.styleChanged(styleProp);
1809        var style1:String = "stroke fill";
1810        var style2:String = "fills";
1811
1812        if (styleProp == null || styleProp == "" || style1.indexOf(styleProp) != -1)
1813        {
1814            invalidateDisplayList();
1815            legendDataChanged();
1816        }
1817        else if (styleProp == "itemRenderer")
1818        {
1819            _instanceCache.remove = true;
1820            _instanceCache.discard = true;
1821            _instanceCache.count = 0;
1822            _instanceCache.discard = false;
1823            _instanceCache.remove = false;
1824        }
1825        else if (styleProp == "labelAlign")
1826        {
1827           invalidateLabels();
1828        }
1829
1830        else if (styleProp == "labelPosition")
1831        {
1832            labelPos = getStyle('labelPosition');
1833            invalidateLabels();
1834        }
1835
1836        else if (styleProp == "labelSizeLimit")
1837        {
1838            maxLabelSize = getStyle('labelSizeLimit');
1839            invalidateLabels();
1840        }
1841
1842        else if (styleProp == "labelRotation")
1843        {
1844            labelAngle = getStyle('labelRotation');
1845            invalidateLabels();
1846        }
1847
1848        else if (style2.indexOf(styleProp)!=-1)
1849        {
1850            _localFills = getStyle('fills');
1851            if (_localFills != null)
1852                _fillCount = _localFills.length;
1853            else
1854                _fillCount = 0;
1855            invalidateDisplayList();
1856            legendDataChanged();
1857        }
1858    }
1859
1860    /**
1861     *  @private
1862     *  since the labels aren't a decendant of the PieSeries, changes aren't propogating down.
1863     *  They should, since the PieSeries is the styleName of the labelLayer, but there seems
1864     *  to be a bug. It's been logged, but I'm fixing it specifically in PieSeries for now
1865     *  by explciitly passing change notifications to the label layer.
1866     */
1867     override public function notifyStyleChangeInChildren(
1868                        styleProp:String, recursive:Boolean):void
1869    {
1870        super.notifyStyleChangeInChildren(styleProp,recursive);
1871
1872        _labelLayer.styleChanged(styleProp);
1873        if (recursive)
1874        {
1875            _labelLayer.notifyStyleChangeInChildren(styleProp, recursive);
1876        }
1877    }
1878
1879    /**
1880     *  @private
1881     */
1882    override protected function get renderData():Object
1883    {
1884        if (!_renderData)
1885        {
1886            var renderDataType:Class = this.renderDataType;
1887            var rv:ColumnSeriesRenderData = new renderDataType();
1888            rv.cache = rv.filteredCache = [];
1889            rv.renderedHalfWidth = 0;
1890            rv.renderedXOffset = 0;
1891            rv.renderedBase = 0;
1892
1893            return rv;
1894        }
1895
1896        return _renderData;
1897    }
1898
1899    /**
1900     *  @private
1901     */
1902    override public function beginInterpolation(sourceRenderData:Object,destRenderData:Object):Object
1903    {
1904        var idata:Object = initializeInterpolationData(
1905            sourceRenderData.cache, destRenderData.cache,
1906            { x: true, y: true, min: true }, itemType,
1907            { sourceRenderData: sourceRenderData,
1908              destRenderData: destRenderData });
1909
1910        var interpolationRenderData:ColumnSeriesRenderData = ColumnSeriesRenderData(destRenderData.clone());
1911
1912        interpolationRenderData.cache = idata.cache;
1913        interpolationRenderData.filteredCache = idata.cache;
1914
1915        transitionRenderData = interpolationRenderData;
1916        return idata;
1917    }
1918
1919
1920    /**
1921     *  @private
1922     */
1923    override protected function getMissingInterpolationValues(sourceProps:Object,
1924                                        srcCache:Array /* of ColumnSeriesItem */,
1925                                        destProps:Object,destCache:Array /* of ColumnSeriesItem */,
1926                                        index:Number,customData:Object):void
1927    {
1928        for (var p:String in sourceProps)
1929        {
1930            var src:Number = sourceProps[p];
1931            var dst:Number = destProps[p];
1932
1933            if (p == "y" || p == "min")
1934            {
1935                if (isNaN(src))
1936                {
1937                    src = customData.destRenderData.renderedBase;
1938                }
1939                if (isNaN(dst))
1940                {
1941                    dst = customData.sourceRenderData.renderedBase;
1942                }
1943            }
1944            else if (p == "x")
1945            {
1946                if (isNaN(src))
1947                {
1948                    src = dst;
1949                }
1950                if (isNaN(dst))
1951                {
1952                    dst = src;
1953                }
1954            }
1955            sourceProps[p] = src;
1956            destProps[p] = dst;
1957        }
1958    }
1959
1960
1961    /**
1962     *  @private
1963     */
1964    override public function getElementBounds(renderData:Object):void
1965    {
1966        var cache :Array /* of ColumnSeriesItem */ = renderData.filteredCache;
1967        var rb :Array /* of Rectangle */ = [];
1968        var sampleCount:uint = cache.length;
1969
1970        if (sampleCount)
1971        {
1972            var ro:Number = renderData.renderedHalfWidth + renderData.renderedXOffset;
1973            var lo:Number = - renderData.renderedHalfWidth + renderData.renderedXOffset;
1974
1975            var v:Object = cache[0];
1976            var maxBounds:Rectangle = new Rectangle(v.x, v.y,0,0);
1977            for (var i:uint = 0; i < sampleCount; i++)
1978            {
1979                v = cache[i];
1980                var top:Number = Math.min(v.y,v.min);
1981                var b:Rectangle = new Rectangle(v.x+lo, top,ro-lo, Math.max(v.y,v.min) - top);
1982                maxBounds.left = Math.min(maxBounds.left,b.left);
1983                maxBounds.top = Math.min(maxBounds.top,b.top);
1984                maxBounds.right = Math.max(maxBounds.right,b.right);
1985                maxBounds.bottom = Math.max(maxBounds.bottom,b.bottom);
1986                rb[i] = b;
1987            }
1988        }
1989        else
1990        {
1991            maxBounds = new Rectangle();
1992        }
1993        renderData.elementBounds = rb;
1994        renderData.bounds =  maxBounds;
1995    }
1996
1997    /**
1998     * @private
1999     */
2000    override protected function defaultFilterFunction(cache:Array /*of ColumnSeriesItem */ ):Array /*of ColumnSeriesItem*/
2001    {
2002        var filteredCache:Array /*of ColumnSeriesItem*/ = [];
2003        if (filterDataValues == "outsideRange")
2004        {
2005            filteredCache = cache.concat();
2006
2007            dataTransform.getAxis(CartesianTransform.HORIZONTAL_AXIS).filterCache(filteredCache,"xNumber","xFilter");
2008            dataTransform.getAxis(CartesianTransform.VERTICAL_AXIS).filterCache(filteredCache,"yNumber","yFilter");
2009            if (_minField != "" || _stacked)
2010            {
2011                dataTransform.getAxis(CartesianTransform.VERTICAL_AXIS).filterCache(filteredCache,"minNumber","minFilter");
2012            }
2013
2014            stripNaNs(filteredCache,"yFilter");
2015            stripNaNs(filteredCache,"xFilter");
2016            if (_minField != "" || _stacked)
2017            {
2018                stripNaNs(filteredCache,"minFilter");
2019            }
2020
2021        }
2022        else if (filterDataValues == "nulls")
2023        {
2024            filteredCache = cache.concat();
2025
2026            stripNaNs(filteredCache,"yNumber");
2027            stripNaNs(filteredCache,"xNumber");
2028            if (_minField != "" || _stacked)
2029            {
2030                stripNaNs(filteredCache,"minNumber");
2031            }
2032
2033        }
2034        else if (filterDataValues == "none")
2035        {
2036            filteredCache = cache;
2037        }
2038        return filteredCache;
2039    }
2040
2041    //--------------------------------------------------------------------------
2042    //
2043    //  Methods
2044    //
2045    //--------------------------------------------------------------------------
2046
2047    /**
2048     * @private
2049     */
2050    private function defaultFillFunction(element:ColumnSeriesItem,i:Number):IFill
2051    {
2052        if (_fillCount!=0)
2053            return(GraphicsUtilities.fillFromStyle(_localFills[i % _fillCount]));
2054        else
2055            return(GraphicsUtilities.fillFromStyle(getStyle("fill")));
2056    }
2057
2058    /**
2059     * @inheritDoc
2060     *
2061     *  @langversion 3.0
2062     *  @playerversion Flash 9
2063     *  @playerversion AIR 1.1
2064     *  @productversion Flex 3
2065     */
2066    public function stack(stackedXValueDictionary:Dictionary, previousElement:IStackable):Number
2067    {
2068        var i:uint = 0;
2069        var itemClass:Class = itemType;
2070        var chartItem:ColumnSeriesItem;
2071        var haveYField:Boolean = (_yField != null && _yField != "");
2072        var haveXField:Boolean = (_xField != null && _xField != "");
2073        var maxValue:Number = 0;
2074
2075        var renderDataType:Class = this.renderDataType;
2076        _renderData= new renderDataType();
2077        _renderData.cache = [];
2078        _renderData.filteredCache = [];
2079
2080        if (cursor)
2081        {
2082            cursor.seek(CursorBookmark.FIRST);
2083            while (!cursor.afterLast)
2084            {
2085                var dataItem:* = cursor.current;
2086                _renderData.cache[i] = chartItem = new itemClass(this,dataItem,i);
2087
2088                var xValue:*;
2089                var yValue:Number;
2090                if (dataFunction != null)
2091                {
2092                    xValue = dataFunction(this,dataItem,'xValue');
2093                    yValue = dataFunction(this,dataItem,'yValue');
2094                }
2095                else
2096                {
2097                    xValue = (haveXField)? dataItem[_xField]:i;
2098                    yValue = Number((haveYField)? dataItem[_yField]:dataItem);
2099                }
2100                if(dataTransform && dataTransform.getAxis(CartesianTransform.VERTICAL_AXIS) is NumericAxis &&
2101                    (dataTransform.getAxis(CartesianTransform.VERTICAL_AXIS) as NumericAxis).direction == "inverted")
2102                    yValue = -yValue;
2103                if (xValue == null)
2104                {
2105                    i++;
2106                    cursor.moveNext();
2107                    continue;
2108                }
2109                // accessing a property on an XML node always returns a new XMLList. Which means
2110                // that using hte XMLList as a dictionary key to store and retrieve
2111                // values in a dictionary won't work.  So we need to convert XMLLists to string values
2112                // first.
2113                if (xValue is XMLList)
2114                    xValue = xValue.toString();
2115
2116                if (isNaN(yValue))
2117                    yValue = 0;
2118                var stackedValue:Object = stackedXValueDictionary[xValue];
2119                if (stackedValue == null)
2120                {
2121                    stackedValue = 0;
2122                }
2123				if (yValue != 0)
2124				{
2125					chartItem.yValue = yValue + stackedValue;
2126					chartItem.minValue = stackedValue;
2127
2128					yValue += stackedValue;
2129					stackedXValueDictionary[xValue] = yValue;
2130					chartItem.xValue = xValue;
2131					maxValue = Math.max(maxValue,yValue);
2132				}
2133                i++;
2134                cursor.moveNext();
2135            }
2136        }
2137
2138        _stacked = (previousElement != null);
2139        invalidateMapping(true);
2140        invalidateData(false);
2141        return maxValue;
2142    }
2143
2144    /**
2145     *  @inheritDoc
2146     *
2147     *  @langversion 3.0
2148     *  @playerversion Flash 9
2149     *  @playerversion AIR 1.1
2150     *  @productversion Flex 3
2151     */
2152    public function stackAll(stackedPosXValueDictionary:Dictionary, stackedNegXValueDictionary:Dictionary, previousElement:IStackable2):Object
2153    {
2154        var i:uint = 0;
2155        var itemClass:Class = itemType;
2156        var chartItem:ColumnSeriesItem;
2157        var haveYField:Boolean = (_yField != null && _yField != "");
2158        var haveXField:Boolean = (_xField != null && _xField != "");
2159        var maxValue:Number = 0;
2160        var minValue:Number = 0;
2161
2162        var renderDataType:Class = this.renderDataType;
2163        _renderData= new renderDataType();
2164        _renderData.cache = [];
2165        _renderData.filteredCache = [];
2166
2167        if (cursor)
2168        {
2169            cursor.seek(CursorBookmark.FIRST);
2170            while (!cursor.afterLast)
2171            {
2172                var dataItem:* = cursor.current;
2173                _renderData.cache[i] = chartItem = new itemClass(this,dataItem,i);
2174
2175                var xValue:*;
2176                var yValue:Number;
2177                if (dataFunction != null)
2178                {
2179                    xValue = dataFunction(this,dataItem,'xValue');
2180                    yValue = dataFunction(this,dataItem,'yValue');
2181                }
2182                else
2183                {
2184                    xValue = (haveXField)? dataItem[_xField]:i;
2185                    yValue = Number((haveYField)? dataItem[_yField]:dataItem);
2186                }
2187                if(dataTransform && dataTransform.getAxis(CartesianTransform.VERTICAL_AXIS) is NumericAxis &&
2188                    (dataTransform.getAxis(CartesianTransform.VERTICAL_AXIS) as NumericAxis).direction == "inverted")
2189                    yValue = -yValue;
2190                if (xValue == null)
2191                {
2192                    i++;
2193                    cursor.moveNext();
2194                    continue;
2195                }
2196                // accessing a property on an XML node always returns a new XMLList. Which means
2197                // that using hte XMLList as a dictionary key to store and retrieve
2198                // values in a dictionary won't work.  So we need to convert XMLLists to string values
2199                // first.
2200                if (xValue is XMLList)
2201                    xValue = xValue.toString();
2202
2203                if (isNaN(yValue))
2204                    yValue = 0;
2205                var stackedValue:Object
2206                if (yValue >= 0)
2207                     stackedValue = stackedPosXValueDictionary[xValue];
2208                else
2209                    stackedValue = stackedNegXValueDictionary[xValue];
2210                if (stackedValue == null)
2211                {
2212                    stackedValue = 0;
2213                }
2214
2215                if (yValue == 0)
2216                {
2217                   // Do nothing
2218                }
2219                else
2220                {
2221                    chartItem.yValue = yValue + stackedValue;
2222                    chartItem.minValue = stackedValue;
2223                }
2224
2225                yValue += stackedValue;
2226                if (yValue >= 0)
2227                {
2228                    stackedPosXValueDictionary[xValue] = yValue;
2229                    maxValue = Math.max(maxValue,yValue);
2230                }
2231                else if (yValue < 0)
2232                {
2233                    stackedNegXValueDictionary[xValue] = yValue;
2234                    minValue = Math.min(minValue, yValue);
2235                }
2236                chartItem.xValue = xValue;
2237                i++;
2238                cursor.moveNext();
2239            }
2240        }
2241
2242        _stacked = (previousElement != null);
2243        invalidateMapping(true);
2244        invalidateData(false);
2245        return ({ maxValue:maxValue, minValue:minValue });
2246    }
2247
2248
2249    /**
2250     *  The stack totals for the series.
2251     *
2252     *  @param totals The totals to set.
2253     *
2254     *  @langversion 3.0
2255     *  @playerversion Flash 9
2256     *  @playerversion AIR 1.1
2257     *  @productversion Flex 3
2258     */
2259    public function set stackTotals(value:Dictionary):void
2260    {
2261        if (value)
2262        {
2263            var cache:Array /* of ColumnSeriesItem */ = _renderData.cache;
2264            var n:int = _renderData.cache.length;
2265            for (var i:int = 0; i < n; i++)
2266            {
2267                var item:ColumnSeriesItem = cache[i];
2268                var total:Number = value[item.xValue];
2269                item.yValue = Math.min(100, Number(item.yValue) / total * 100);
2270                item.minValue =
2271                    Math.min(100, Number(item.minValue) / total * 100);
2272            }
2273        }
2274    }
2275
2276   /**
2277    *  @private
2278    */
2279    mx_internal function updateLabels():void
2280    {
2281        if (!dataTransform)
2282        {
2283            labelCache.count=0;
2284            return;
2285        }
2286
2287        _labelLayer.graphics.clear();
2288
2289        if (!dataProvider)
2290        {
2291            labelCache.count=0;
2292            return;
2293        }
2294        var renderData:ColumnSeriesRenderData = (transitionRenderData == null)? _renderData:ColumnSeriesRenderData(transitionRenderData);
2295        var activeCount:Array /* of ColumnSeriesItem */ = renderData.filteredCache;
2296        if (renderData.length == 0)
2297        {
2298            labelCache.count = 0;
2299            _instanceCache.count = 0;
2300            return;
2301        }
2302
2303        if (chart && chart is ColumnChart && ColumnChart(chart).allLabelsMeasured)
2304        {
2305            var labelPosition:String = labelPos;
2306            if (labelPosition=="outside")
2307                renderExternalLabels(renderData,activeCount);
2308            else if (labelPosition=="inside")
2309                renderInternalLabels(renderData,activeCount);
2310            else
2311                labelCache.count = 0;
2312        }
2313    }
2314
2315    /**
2316     * @private
2317     */
2318    private function renderInternalLabels(renderData:ColumnSeriesRenderData,activeCount:Array /* of ColumnSeriesItem */):void
2319    {
2320        var n:int=activeCount.length;
2321        labelCache.count = n;
2322
2323        var labels:Array /* of Label */ = labelCache.instances;
2324
2325        var dataTransform:CartesianTransform=CartesianTransform(dataTransform);
2326
2327        var label:Object;
2328        var size:Number = getStyle('fontSize');
2329        var align:String = getStyle('labelAlign');
2330        for (var i:int = 0; i < n; i++)
2331        {
2332            var v:ColumnSeriesItem =activeCount[i];
2333            label = labels[i];
2334            label.x=v.labelX+2;
2335            label.y=v.labelY+4;
2336            label.width=v.labelWidth;
2337            label.height=v.labelHeight;
2338            label.setStyle('fontSize',size * renderData.labelScale);
2339            label.text = v.labelText;
2340            if (v.labelIsHorizontal)
2341            {
2342                if (v.y == (isNaN(v.min) ? renderData.renderedBase : v.min))
2343                    label.text = "";
2344                else
2345                {
2346                    label.setStyle('textAlign','center');
2347                    label.rotation = 0;
2348                }
2349            }
2350            else
2351            {
2352                if (align == "bottom")
2353                {
2354                    if (v.y < (isNaN(v.min) ? renderData.renderedBase : v.min))
2355                        label.setStyle('textAlign','left');
2356                    else if (v.y > (isNaN(v.min) ? renderData.renderedBase : v.min))
2357                        label.setStyle('textAlign','right');
2358                    else
2359                        label.text = "";
2360                }
2361                else if (align=="top")
2362                {
2363                    if (v.y < (isNaN(v.min) ? renderData.renderedBase : v.min))
2364                        label.setStyle('textAlign','right');
2365                    else if (v.y > (isNaN(v.min) ? renderData.renderedBase : v.min))
2366                        label.setStyle('textAlign','left');
2367                    else
2368                        label.text = "";
2369                }
2370                else
2371                {
2372                    if (v.y == (isNaN(v.min) ? renderData.renderedBase : v.min))
2373                        label.text = "";
2374                    else
2375                        label.setStyle('textAlign','center');
2376                }
2377
2378                label.rotation = -90;
2379            }
2380            label.validateNow();
2381        }
2382    }
2383
2384    /**
2385     * @private
2386     */
2387    private function renderExternalLabels(renderData:ColumnSeriesRenderData,activeCount:Array /* of ColumnSeriesItem */):void
2388    {
2389        var n:int=activeCount.length;
2390        labelCache.count = n;
2391        var labels:Array /* of Label */ = labelCache.instances;
2392        var label:Object;
2393        var size:Number = getStyle('fontSize');
2394
2395        for (var i:int = 0; i < n; i++)
2396        {
2397            var v:ColumnSeriesItem =activeCount[i];
2398            label=labels[i];
2399
2400            label.x=v.labelX+2;
2401            label.y=v.labelY+4;
2402            label.width=v.labelWidth;
2403            label.height=v.labelHeight;
2404            label.setStyle('fontSize',size * renderData.labelScale);
2405            label.text = v.labelText;
2406            var rotation:Number = getStyle('labelRotation');
2407
2408            if (v.labelIsHorizontal)
2409            {
2410                if (v.y == (isNaN(v.min) ? renderData.renderedBase : v.min))
2411                    label.text = "";
2412                else if (chart && !(ColumnChart(chart).showLabelVertically))
2413                {
2414                    if(chart && chart.layoutDirection == LayoutDirection.RTL)       //Align labels to right of the item in rtl layout
2415                        label.setStyle('textAlign','right');
2416                    else                                            //Align them to left of the column in ltr layout
2417                        label.setStyle('textAlign','left');
2418                    label.setStyle('paddingLeft',0);
2419                    label.rotation = 0;
2420                }
2421                else
2422                {
2423                    label.setStyle('textAlign','center');
2424                    label.rotation = 0;
2425                }
2426            }
2427            else
2428            {
2429                if (v.y < (isNaN(v.min) ? renderData.renderedBase : v.min))
2430                    label.setStyle('textAlign','left');
2431                else if (v.y > (isNaN(v.min) ? renderData.renderedBase : v.min))
2432                {
2433                    if (!(isNaN(rotation)))
2434                        label.setStyle('textAlign','left');
2435                    else
2436                        label.setStyle('textAlign','right');
2437                }
2438                else
2439                    label.text = "";
2440                if (!(isNaN(rotation)))
2441                    label.rotation = rotation;
2442                else
2443                    label.rotation = -90;
2444            }
2445            label.validateNow();
2446        }
2447    }
2448
2449   /**
2450    * @private
2451    */
2452    public function invalidateLabels():void
2453    {
2454        labelPos = getStyle('labelPosition');
2455        var temp:IUITextField = IUITextField(createInFontContext(UITextField));
2456        temp.text = "W";
2457        if (labelPos=="inside")
2458        {
2459            if (temp.textWidth > 2 * _renderData.renderedHalfWidth)
2460            {
2461                if (measuringField.embedFonts)
2462                {
2463                    if (temp.textHeight > 2 * renderData.renderedHalfWidth)
2464                    {
2465                        labelPos = "";
2466                        labelCache.count = 0;
2467                    }
2468                }
2469                else
2470                {
2471                    labelPos = "";
2472                    labelCache.count = 0;
2473                }
2474            }
2475        }
2476        else if (labelPos=="outside")
2477        {
2478            if (chart && chart is ColumnChart)
2479            {
2480                if (!(ColumnChart(chart).showLabelVertically))
2481                {
2482                    if (temp.textWidth / 2 > 2 * _renderData.renderedHalfWidth) // .25% of column width
2483                    {
2484                        labelPos = "";
2485                        labelCache.count = 0;
2486                    }
2487                }
2488                else
2489                {
2490                    if (temp.textWidth > 2 * _renderData.renderedHalfWidth) // .25% of column width
2491                    {
2492                        if (measuringField.embedFonts)
2493                        {
2494                            if (temp.textHeight > 2 * renderData.renderedHalfWidth)
2495                            {
2496                                labelPos = "";
2497                                labelCache.count = 0;
2498                            }
2499                        }
2500                        else
2501                        {
2502                            labelPos = "";
2503                            labelCache.count = 0;
2504                        }
2505                    }
2506                }
2507            }
2508        }
2509        if (chart && chart is ColumnChart)
2510        {
2511            var c:ColumnChart = ColumnChart(chart);
2512            c.measureLabels();
2513        }
2514    }
2515
2516    /**
2517     *  Customizes the item renderer instances that are used to represent the chart.
2518     *  This method is called automatically whenever a new item renderer is needed
2519     *  while the chart is being rendered.
2520     *  You can override this method to add your own customization as necessary.
2521     *
2522     *  @param instance The new item renderer instance that is being created.
2523     *  @param cache The InstanceCache that is used to manage the item renderer instances.
2524     *
2525     *  @langversion 3.0
2526     *  @playerversion Flash 9
2527     *  @playerversion AIR 1.1
2528     *  @productversion Flex 3
2529     */
2530    protected function applyItemRendererProperties(instance:DisplayObject,cache:InstanceCache):void
2531    {
2532        if (instance is ISimpleStyleClient)
2533            ISimpleStyleClient(instance).styleName = this;
2534    }
2535
2536    /**
2537     *  @private
2538     */
2539    private function formatDataTip(hd:HitData):String
2540    {
2541        var dt:String = "";
2542        var n:String = displayName;
2543        if (n != null && n.length>0)
2544        dt += "<b>" + n + "</b><BR/>";
2545
2546        var xName:String = dataTransform.getAxis(CartesianTransform.HORIZONTAL_AXIS).displayName;
2547        if (xName != "")
2548            dt += "<i>" + xName + ":</i> ";
2549        dt += dataTransform.getAxis(CartesianTransform.HORIZONTAL_AXIS).formatForScreen(ColumnSeriesItem(hd.chartItem).xValue) + "\n";
2550
2551
2552        var yName:String = dataTransform.getAxis(CartesianTransform.VERTICAL_AXIS).displayName;
2553        if (_minField == "")
2554        {
2555            if (yName != "")
2556                dt += "<i>" + yName + ":</i> ";
2557            dt += dataTransform.getAxis(CartesianTransform.VERTICAL_AXIS).formatForScreen(ColumnSeriesItem(hd.chartItem).yValue) + "\n";
2558        }
2559        else
2560        {
2561            if (yName != "")
2562                dt += "<i>" + yName + " (high):</i> ";
2563            else
2564                dt += "<i>high:</i> ";
2565            dt += dataTransform.getAxis(CartesianTransform.VERTICAL_AXIS).formatForScreen(ColumnSeriesItem(hd.chartItem).yValue) + "\n";
2566
2567            if (yName != "")
2568                dt += "<i>" + yName + " (low):</i> ";
2569            else
2570                dt += "<i>low:</i> ";
2571            dt += dataTransform.getAxis(CartesianTransform.VERTICAL_AXIS).formatForScreen(ColumnSeriesItem(hd.chartItem).minValue) + "\n";
2572        }
2573
2574        return dt;
2575    }
2576
2577    private function reverseYValues(cache:Array):Array
2578    {
2579        var i:int = 0;
2580        var n:int = cache.length;
2581        for(i = 0; i < n ; i++)
2582        {
2583            cache[i]["yValue"] = -(cache[i]["yValue"]);
2584            if(_minField != "")
2585                cache[i]["minValue"] = -(cache[i]["minValue"]);
2586        }
2587        return cache;
2588    }
2589
2590    private function reverseXValues(cache:Array):Array
2591    {
2592        var i:int = 0;
2593        var n:int = cache.length;
2594        for(i = 0; i < n ; i++)
2595        {
2596            cache[i]["xValue"] = -(cache[i]["xValue"]);
2597        }
2598        return cache;
2599    }
2600
2601    mx_internal function get seriesRenderData():Object
2602    {
2603        if (!_renderData)
2604        {
2605            var renderDataType:Class = this.renderDataType;
2606            var rv:ColumnSeriesRenderData = new renderDataType();
2607            rv.cache = rv.filteredCache = [];
2608            rv.renderedHalfWidth = 0;
2609            rv.renderedXOffset = 0;
2610            rv.renderedBase = 0;
2611
2612            return rv;
2613        }
2614
2615        return _renderData;
2616    }
2617}
2618
2619}
2620
2621