| //////////////////////////////////////////////////////////////////////////////// |
| // |
| // Licensed to the Apache Software Foundation (ASF) under one or more |
| // contributor license agreements. See the NOTICE file distributed with |
| // this work for additional information regarding copyright ownership. |
| // The ASF licenses this file to You under the Apache License, Version 2.0 |
| // (the "License"); you may not use this file except in compliance with |
| // the License. You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // |
| //////////////////////////////////////////////////////////////////////////////// |
| |
| package mx.charts |
| { |
| |
| import flash.display.DisplayObject; |
| import flash.events.MouseEvent; |
| import flash.geom.Rectangle; |
| import flash.utils.Dictionary; |
| |
| import mx.charts.chartClasses.IChartElement; |
| import mx.charts.renderers.BoxItemRenderer; |
| import mx.charts.styles.HaloDefaults; |
| import mx.core.IDataRenderer; |
| import mx.core.IFactory; |
| import mx.core.IFlexDisplayObject; |
| import mx.core.IUITextField; |
| import mx.core.UIComponent; |
| import mx.core.UITextField; |
| import mx.core.mx_internal; |
| import mx.graphics.SolidColor; |
| import mx.styles.CSSStyleDeclaration; |
| import mx.styles.ISimpleStyleClient; |
| import mx.core.IFlexModuleFactory; |
| |
| use namespace mx_internal; |
| |
| //-------------------------------------- |
| // Styles |
| //-------------------------------------- |
| |
| include "../styles/metadata/GapStyles.as" |
| include "../styles/metadata/PaddingStyles.as" |
| include "styles/metadata/TextStyles.as" |
| |
| /** |
| * Specifies an IFill object that defines the fill for the legend element. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| [Style(name="fill", type="Object", inherit="no")] |
| |
| /** |
| * Specifies the label placement of the legend element. Recognized values are |
| * <code>"top"</code>, <code>"bottom"</code>, <code>"left"</code>, and <code>"right"</code>. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| [Style(name="labelPlacement", type="String", enumeration="top,bottom,right,left", inherit="yes")] |
| |
| /** |
| * Specifies the class that renders the marker portion of the legend item. |
| * Typically the marker is provided by the chart element that |
| * generates the legend item. |
| * When you create a legend manually, however, this style specifies |
| * what class is used to render the marker. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| [Style(name="legendMarkerRenderer", type="mx.core.IFactory", inherit="no")] |
| |
| /** |
| * Specifies the height of the legend element. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| [Style(name="markerHeight", type="Number", format="Length", inherit="yes")] |
| |
| /** |
| * Specifies the width of the legend element. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| [Style(name="markerWidth", type="Number", format="Length", inherit="yes")] |
| |
| /** |
| * Specifies the line stroke for the legend element. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| [Style(name="stroke", type="Object", inherit="no")] |
| |
| /** |
| * Controls the individual legend elements in a chart legend. |
| * |
| * @mxml |
| * |
| * <p>The <code><mx:LegendItem></code> tag inherits all the properties |
| * of its parent classes and adds the following properties:</p> |
| * |
| * <pre> |
| * <mx:LegendItem |
| * <strong>Properties</strong> |
| * element="<i>No default</i>" |
| * label="<i>No default</i>" |
| * source="<i>No default</i>" |
| * legendData="<i>No default</i>" |
| * marker="<i>No default</i>" |
| * markerAspectRatio="<i>No default</i>" |
| * |
| * <strong>Styles</strong> |
| * fill="<i>IFill; no default.</i>" |
| * fontWeight="normal|bold" |
| * fontSize="10" |
| * horizontalGap="8" |
| * labelPlacement="right|left|top|bottom" |
| * legendMarkerRenderer="<i>Defaults to series's itemRenderer</i>" |
| * markerHeight="15" |
| * markerWidth="10" |
| * paddingLeft="0" |
| * paddingRight="0" |
| * stroke="<i>IStroke; no default</i>" |
| * textDecoration="underline|none" |
| * verticalGap="6" |
| * /> |
| * </pre> |
| * |
| * @see mx.charts.Legend |
| * @see mx.charts.chartClasses.LegendData |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public class LegendItem extends UIComponent |
| { |
| include "../core/Version.as"; |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Class initialization |
| // |
| //-------------------------------------------------------------------------- |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Constructor |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * Constructor. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public function LegendItem() |
| { |
| super(); |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Variables |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * @private |
| */ |
| private static var _moduleFactoryInitialized:Dictionary = new Dictionary(true); |
| |
| /** |
| * @private |
| */ |
| private var nameLabel:IUITextField; |
| |
| /** |
| * @private |
| */ |
| private var labelChanged:Boolean = false; |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Properties |
| // |
| //-------------------------------------------------------------------------- |
| |
| //---------------------------------- |
| // element |
| //---------------------------------- |
| |
| [Inspectable(environment="none")] |
| |
| /** |
| * The chart element that is responsible for generating this legend item. |
| * When a Legend control's contents are automatically generated by a chart, |
| * this field refers to the element (usually a series) |
| * that this item represents. |
| * In some cases, multiple items refer to the same element. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public var element:IChartElement; |
| |
| //---------------------------------- |
| // label |
| //---------------------------------- |
| |
| /** |
| * @private |
| * Storage for the label property. |
| */ |
| private var _label:String = ""; |
| |
| [Inspectable(category="General")] |
| |
| /** |
| * Specifies the text that Flex displays alongside the legend element. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public function get label():String |
| { |
| return _label; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set label(value:String):void |
| { |
| _label = value; |
| labelChanged = true; |
| |
| invalidateSize(); |
| invalidateDisplayList(); |
| } |
| |
| //---------------------------------- |
| // legendData |
| //---------------------------------- |
| |
| /** |
| * @private |
| * Storage for the legendData property. |
| */ |
| private var _legendData:Object; |
| |
| [Inspectable(environment="none")] |
| |
| /** |
| * The LegendData instance that this LegendItem object represents. |
| * When a chart generates the contents of a Legend control, |
| * the elements of the chart generate one or more |
| * LegendData structures for display in the Legend. |
| * Each LegendData structure generates one LegendItem object. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public function set legendData(value:Object):void |
| { |
| _legendData = value; |
| |
| if (_marker is IDataRenderer) |
| (_marker as IDataRenderer).data = _legendData; |
| } |
| |
| //---------------------------------- |
| // marker |
| //---------------------------------- |
| |
| /** |
| * @private |
| * Storage for the marker property. |
| */ |
| private var _marker:IFlexDisplayObject; |
| |
| [Inspectable] |
| |
| /** |
| * The marker displayed by this legend item. |
| * Markers are typically assigned by the chart element |
| * that generated the LegendData associated with this item. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public function get marker():IFlexDisplayObject |
| { |
| return _marker; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set marker(value:IFlexDisplayObject):void |
| { |
| if (_marker) |
| removeChild(_marker as DisplayObject); |
| |
| _marker = value; |
| |
| if (_marker) |
| addChild(_marker as DisplayObject); |
| |
| if (_marker is IDataRenderer) |
| (_marker as IDataRenderer).data = _legendData; |
| |
| invalidateDisplayList(); |
| } |
| |
| //---------------------------------- |
| // markerAspectRatio |
| //---------------------------------- |
| |
| [Inspectable(category="General")] |
| |
| /** |
| * The aspect ratio for the marker associated with this legend item. |
| * Some markers provided by chart series are intended for display |
| * at a particular aspect ratio. |
| * If this property is set, the legend item guarantees |
| * the aspect ratio of the marker during layout. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public var markerAspectRatio:Number; |
| |
| //---------------------------------- |
| // source |
| //---------------------------------- |
| |
| [Inspectable(environment="none")] |
| |
| /** |
| * Contains a reference |
| * to the data series that the LegendItem was generated from |
| * if you bind the <code>dataProvider</code> property |
| * of the parent Legend control to a chart control. |
| * Otherwise, this property contains a reference |
| * to the object associated with the LegendItem. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public function get source():Object |
| { |
| return element; |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Overridden methods: UIComponent |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * @inheritDoc |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| override public function set moduleFactory(factory:IFlexModuleFactory):void |
| { |
| super.moduleFactory = factory; |
| |
| if (_moduleFactoryInitialized[factory]) |
| return; |
| |
| _moduleFactoryInitialized[factory] = true; |
| } |
| |
| /** |
| * @private |
| */ |
| override protected function createChildren():void |
| { |
| nameLabel = IUITextField(createInFontContext(UITextField)); |
| nameLabel.selectable = false; |
| nameLabel.styleName = this; |
| addChild(DisplayObject(nameLabel)); |
| |
| super.createChildren(); |
| |
| if (!nameLabel) |
| { |
| nameLabel = IUITextField(createInFontContext(UITextField)); |
| nameLabel.selectable = false; |
| nameLabel.styleName = this; |
| addChild(DisplayObject(nameLabel)); |
| } |
| } |
| |
| /** |
| * @private |
| */ |
| override protected function measure():void |
| { |
| super.measure(); |
| |
| var txt:String = _label; |
| |
| var labelPlacement:String = getStyle("labelPlacement"); |
| if (labelPlacement == "" && parent) |
| labelPlacement = UIComponent(parent).getStyle("labelPlacement"); |
| |
| var itemW:Number = 0; |
| var itemH:Number = 0; |
| |
| // If the text is empty (or undefined), make the preferred |
| // size big enough to hold a capital and decending character |
| // using the current font. |
| if (txt == null || txt == "" || txt.length < 2) |
| txt = "Wj"; |
| |
| if (labelChanged) |
| { |
| labelChanged = false; |
| nameLabel.htmlText = _label; |
| } |
| |
| var textW:Number = nameLabel.textWidth + UITextField.TEXT_WIDTH_PADDING; |
| var textH:Number = nameLabel.textHeight + UITextField.TEXT_HEIGHT_PADDING; |
| |
| if (isNaN(textW)) |
| textW = 0; |
| if (isNaN(textH)) |
| textH = 0; |
| |
| if (textW > 0 || calculateMarkerWidth() > 0) |
| { |
| itemW += getStyle("paddingLeft") + getStyle("paddingRight"); |
| itemH += getStyle("paddingTop") + getStyle("paddingBottom"); |
| |
| if (labelPlacement == "top" || labelPlacement == "bottom") |
| { |
| itemW += Math.max(textW, calculateMarkerWidth()); |
| itemH += getStyle("verticalGap") + calculateMarkerHeight() + textH; |
| } |
| else |
| { |
| itemW += getStyle("horizontalGap") + calculateMarkerWidth() + textW; |
| itemH += Math.max(textH, calculateMarkerHeight()); |
| } |
| } |
| |
| measuredWidth = itemW; |
| measuredHeight = itemH; |
| |
| // Set the labelField size here. |
| // This way the width getter will return the proper value |
| // when the resize event is fired. |
| nameLabel.setActualSize(getExplicitOrMeasuredWidth(), measuredHeight); |
| } |
| |
| /** |
| * @private |
| */ |
| override protected function updateDisplayList(unscaledWidth:Number, |
| unscaledHeight:Number):void |
| { |
| super.updateDisplayList(unscaledWidth, unscaledHeight); |
| |
| var labelPlacement:String = getStyle("labelPlacement"); |
| |
| var labelX:Number = 0; |
| var labelY:Number = 0; |
| |
| var markerX:Number = 0; |
| var markerY:Number = 0; |
| |
| var paddingLeft:Number = getStyle("paddingLeft"); |
| var paddingRight:Number = getStyle("paddingRight"); |
| var paddingTop:Number = getStyle("paddingTop"); |
| |
| var mAvailableWidth:Number = calculateMarkerWidth(); |
| var mAvailableHeight:Number = calculateMarkerHeight(); |
| |
| var markerH:Number = mAvailableHeight; |
| var markerW:Number = mAvailableWidth; |
| |
| var txt:String = _label; |
| |
| if (txt == null || txt.length < 2) |
| txt = "Wj"; |
| |
| if (labelChanged) |
| { |
| labelChanged = false; |
| nameLabel.text = _label; |
| } |
| |
| var textW:Number = nameLabel.textWidth + UITextField.TEXT_WIDTH_PADDING; |
| var textH:Number = nameLabel.textHeight + UITextField.TEXT_HEIGHT_PADDING; |
| |
| var cx:Number; |
| |
| if (isNaN(textW)) |
| textW = 0; |
| if (isNaN(textH)) |
| textH = 0; |
| |
| switch (labelPlacement) |
| { |
| case "top": |
| { |
| labelY = paddingTop; |
| markerY = labelY + getStyle("verticalGap") + textH; |
| |
| cx = paddingLeft + |
| (unscaledWidth - paddingLeft - paddingRight) / 2; |
| labelX = cx - textW / 2; |
| markerX = cx - markerW / 2; |
| |
| break; |
| } |
| |
| case "bottom": |
| { |
| markerY = paddingTop; |
| labelY = markerY + getStyle("verticalGap") + markerH; |
| |
| cx = paddingLeft + |
| (unscaledWidth - paddingLeft - paddingRight) / 2; |
| labelX = cx - textW / 2; |
| markerX = cx - markerW / 2; |
| |
| break; |
| } |
| |
| case "left": |
| { |
| markerX = unscaledWidth - markerW - paddingRight; |
| labelX = markerX - getStyle("horizontalGap") - textW; |
| |
| labelY = markerY = paddingTop; |
| if (textH < markerH) |
| labelY += (markerH - textH) / 2; |
| else |
| markerY += (textH - markerH) / 2; |
| |
| break; |
| } |
| |
| default: // default is right |
| { |
| markerX = paddingLeft; |
| labelX = markerX + getStyle("horizontalGap") + markerW; |
| |
| markerY = labelY = paddingTop; |
| if (markerH < textH) |
| markerY += (textH - markerH) / 2; |
| else |
| labelY += (markerH - textH) / 2; |
| |
| break; |
| } |
| } |
| |
| nameLabel.move(labelX, labelY); |
| |
| if (!isNaN(markerAspectRatio)) |
| { |
| var availableAR:Number = markerW / markerH; |
| if (availableAR > markerAspectRatio) |
| markerW = markerAspectRatio * markerH; |
| else |
| markerH = markerW / markerAspectRatio; |
| } |
| |
| var rc:Rectangle = new Rectangle((mAvailableWidth - markerW) / 2, |
| (mAvailableHeight - markerH) / 2, |
| markerW, markerH); |
| |
| if (!_marker) |
| { |
| var markerClass:IFactory = getStyle("legendMarkerRenderer"); |
| |
| if (markerClass) |
| marker = markerClass.newInstance(); |
| else |
| marker = new BoxItemRenderer(); |
| |
| if (_marker is ISimpleStyleClient) |
| { |
| (_marker as ISimpleStyleClient).styleName = |
| (!element) ? this : element; |
| } |
| } |
| |
| _marker.x = markerX + (mAvailableWidth - markerW) / 2; |
| _marker.y = markerY + (mAvailableHeight - markerH) / 2; |
| |
| _marker.setActualSize(markerW, markerH); |
| } |
| |
| /** |
| * @private |
| */ |
| override public function styleChanged(styleProp:String):void |
| { |
| invalidateDisplayList(); |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Methods |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * @private |
| */ |
| private function calculateMarkerWidth():Number |
| { |
| var out:Number = getStyle("markerWidth"); |
| if (isNaN(out)) |
| out = 10; |
| return out; |
| } |
| |
| /** |
| * @private |
| */ |
| private function calculateMarkerHeight():Number |
| { |
| var out:Number = getStyle("markerHeight"); |
| if (isNaN(out)) |
| out = 15; |
| return out; |
| } |
| } |
| |
| } |