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 * <mx:ColumnSeries ... > 83 * <mx:fills> 84 * <mx:SolidColor color="0xCC66FF"/> 85 * <mx:SolidColor color="0x9966CC"/> 86 * <mx:SolidColor color="0x9999CC"/> 87 * </mx:fills> 88 * </mx:ColumnSeries> 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><mx:ColumnSeries></code> tag inherits all the properties of its parent classes, and 175 * the following properties: 176 * </p> 177 * <pre> 178 * <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 * /> 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