axis.as

来自「用于flash/flex的 as3的 2D图形图像图表的动态生成」· AS 代码 · 共 714 行 · 第 1/2 页

AS
714
字号
package flare.vis.axis
{
	import flare.animate.Transitioner;
	import flare.display.TextSprite;
	import flare.scale.IScaleMap;
	import flare.scale.LinearScale;
	import flare.scale.Scale;
	import flare.scale.ScaleType;
	import flare.util.Arrays;
	import flare.util.Stats;
	import flare.util.Strings;
	
	import flash.display.DisplayObject;
	import flash.display.Sprite;
	import flash.geom.Point;
	import flash.text.TextFormat;
	import flash.utils.Dictionary;

	/**
	 * A metric data axis consisting of axis labels and gridlines.
	 * 
	 * <p>Axis labels can be configured both in terms of text formatting,
	 * orientation, and position. Use the <code>labelOffsetX</code> or
	 * <code>labelOffsetY</code> property to adjust label positioning. For
	 * example, <code>labelOffsetX = -10;</code> places the anchor point for
	 * the label ten pixels to the left of the data bounds, whereas
	 * <code>labelOffsetX = 10;</code> will place the point 10 pixels to the
	 * right of the data bounds. One could simultaneously adjust the
	 * <code>horizontalAnchor</code> property to align the labels as desired.
	 * </p>
	 * 
	 * <p>Similarly, axis gridlines can also be configured. The
	 * <code>lineCapX1</code>, <code>lineCapX2</code>, <code>lineCapY1</code>,
	 * and <code>lineCapY2</code> properties determine by how much the
	 * grid lines should exceed the data bounds. For example,
	 * <code>lineCapX1 = 5</code> causes the grid line to extend an extra
	 * 5 pixels to the left. Each of these values should be greater than or
	 * equal to zero.</p>
	 */
	public class Axis extends Sprite implements IScaleMap
	{
		// children indices
		private static const LABELS:uint = 1;
        private static const GRIDLINES:uint = 0;
		
		// axis scale
		private var _prevScale:Scale;
		// axis settings
		private var _xa:Number=0, _ya:Number=0;   // start of the axis
		private var _xb:Number=0, _yb:Number=0;   // end of the axis
		private var _xaP:Number=0, _yaP:Number=0; // previous start of the axis
		private var _xbP:Number=0, _ybP:Number=0; // previous end of the axis
		private var _xd:int, _yd:int;             // axis directions (1 or -1)
		private var _xlo:Number, _ylo:Number;     // label offsets
		// gridline settings
		private var _lineColor:uint = 0xd8d8d8;
		private var _lineWidth:Number = 0;
		// label settings
		private var _numLabels:int = -1;
		private var _anchorH:int = TextSprite.LEFT;
		private var _anchorV:int = TextSprite.TOP;
		private var _labelAngle:Number = 0;
		private var _labelColor:uint = 0;
		private var _labelFormat:String = null;
		private var _labelTextMode:int = TextSprite.BITMAP;
		private var _labelTextFormat:TextFormat = new TextFormat("Arial",12,0);
		// temporary variables
		private var _point:Point = new Point();
		
		// -- Properties ------------------------------------------------------
		
		/** Sprite containing the axis labels. */
		public function get labels():Sprite { return getChildAt(LABELS) as Sprite; }
		/** Sprite containing the axis grid lines. */
		public function get gridLines():Sprite { return getChildAt(GRIDLINES) as Sprite; }
		
		/** @inheritDoc */
		public function get x1():Number { return _xa; }
		public function set x1(x:Number):void { _xa = x; }
		
		/** @inheritDoc */
		public function get y1():Number { return _ya; }
		public function set y1(y:Number):void { _ya = y; }
		
		/** @inheritDoc */
		public function get x2():Number { return _xb; }
		public function set x2(x:Number):void { _xb = x; }
		
		/** @inheritDoc */
		public function get y2():Number { return _yb; }
		public function set y2(y:Number):void { _yb = y; }

		/** The Scale used to map values to this axis. */
		public var axisScale:Scale;
		
		/** Flag indicating if axis labels should be shown. */
		public var showLabels:Boolean = true;
		
		/** Flag indicating if labels should be removed in case of overlap. */
		public var fixLabelOverlap:Boolean = true;
		
		/** Flag indicating if axis grid lines should be shown. */
		public var showLines:Boolean = true;
		
		/** X length of axis gridlines. */
		public var lineLengthX:Number = 0;
		
		/** Y length of axis gridlines. */
		public var lineLengthY:Number = 0;	
			
		/** X offset for axis gridlines at the lower end of the axis. */
		public var lineCapX1:Number = 0;
		
		/** X offset for axis gridlines at the upper end of the axis. */
		public var lineCapX2:Number = 0;
		
		/** Y offset for axis gridlines at the lower end of the axis. */
		public var lineCapY1:Number = 0;
		
		/** Y offset for axis gridlines at the upper end of the axis. */
		public var lineCapY2:Number = 0;
		
		/** X-dimension offset value for axis labels. If negative or zero, this
		 *  value indicates how much to offset to the left of the data bounds.
		 *  If positive, the offset is made to the right of the data bounds. */
		public var labelOffsetX:Number = 0;	
			
		/** Y-dimension offset value for axis labels. If negative or zero, this
		 *  value indicates how much to offset above the data bounds.
		 *  If positive, the offset is made beneath the data bounds.*/
		public var labelOffsetY:Number = 0;
		
		/** The line color of axis grid lines. */
		public function get lineColor():uint { return _lineColor; }
		public function set lineColor(c:uint):void { _lineColor = c; updateGridLines(); }
		
		/** The line width of axis grid lines. */
		public function get lineWidth():Number { return _lineWidth; }
		public function set lineWidth(w:Number):void { _lineWidth = w; updateGridLines(); }
		
		/** The color of axis label text. */
		public function get labelColor():uint { return _labelColor; }
		public function set labelColor(c:uint):void { _labelColor = c; updateLabels(); }
		
		/** The angle (orientation) of axis label text. */
		public function get labelAngle():Number { return _labelAngle; }
		public function set labelAngle(a:Number):void { _labelAngle = a; updateLabels(); }
		
		/** TextFormat (font, size, style) for axis label text. */
		public function get labelTextFormat():TextFormat { return _labelTextFormat; }
		public function set labelTextFormat(f:TextFormat):void { _labelTextFormat = f; updateLabels(); }
		
		/** The text rendering mode to use for label TextSprites.
		 *  @see flare.display.TextSprite. */
		public function get labelTextMode():int { return _labelTextMode; }
		public function set labelTextMode(m:int):void { _labelTextMode = m; updateLabels(); }
		
		/** String formatting pattern used for axis labels, overwrites any
		 *  formatting pattern used by the <code>axisScale</code>. If null,
		 *  the formatting pattern for the <code>axisScale</code> is used. */
		public function get labelFormat():String {
			return _labelFormat==null ? null 
					: _labelFormat.substring(3, _labelFormat.length-1);
		}
		public function set labelFormat(fmt:String):void {
			_labelFormat = "{0:"+fmt+"}"; updateLabels();
		}
		
		/** The number of labels and gridlines to generate by default. If this
		 *  number is zero or less (default -1), the number of labels will be
		 *  automatically determined from the current scale and size. */
		public function get numLabels():int {
			// if set positive, return number
			if (_numLabels > 0) return _numLabels;
			// if ordinal return all labels
			if (ScaleType.isOrdinal(axisScale.scaleType)) return -1;
			// otherwise determine based on axis size (random hack...)
			var lx:Number = _xb-_xa; if (lx<0) lx = -lx;
			var ly:Number = _yb-_ya; if (ly<0) ly = -ly;
			lx = (lx > ly ? lx : ly);
			return lx > 200 ? 10 : lx < 20 ? 1 : int(lx/20);
		}
		public function set numLabels(n:int):void { _numLabels = n; }
		
		/** The horizontal anchor point for axis labels.
		 *  @see flare.display.TextSprite. */
		public function get horizontalAnchor():int { return _anchorH; }
		public function set horizontalAnchor(a:int):void { _anchorH = a; updateLabels(); }
		
		/** The vertical anchor point for axis labels.
		 *  @see flare.display.TextSprite. */
		public function get verticalAnchor():int { return _anchorV; }
		public function set verticalAnchor(a:int):void { _anchorV = a; updateLabels(); }		
		
		/** The x-coordinate of the axis origin. */
		public function get originX():Number {
			return (ScaleType.isQuantitative(axisScale.scaleType) ? X(0) : x1);
		}
		/** The y-coordinate of the axis origin. */
		public function get originY():Number {
			return (ScaleType.isQuantitative(axisScale.scaleType) ? Y(0) : y1);
		}
		
		// -- Initialization --------------------------------------------------
		
		/**
		 * Creates a new Axis.
		 * @param axisScale the axis scale to use. If null, a linear scale
		 *  is assumed.
		 */
		public function Axis(axisScale:Scale=null)
        {
            this.axisScale = axisScale ? axisScale : new LinearScale();
            _prevScale = this.axisScale;
            initializeChildren();
        }

		/**
		 * Initializes the child container sprites for labels and grid lines.
		 */
        protected function initializeChildren():void
        {
            addChild(new Sprite()); // add gridlines
            addChild(new Sprite()); // add labels
        }
		
		// -- Updates ---------------------------------------------------------
		
		/**
		 * Updates this axis, performing filtering and layout as needed.
		 * @param trans a Transitioner for collecting value updates
		 * @return the input transitioner.
		 */
		public function update(trans:Transitioner):Transitioner
        {
        	var t:Transitioner = (trans!=null ? trans : Transitioner.DEFAULT);
        	
        	// compute directions and offsets
        	_xd  = lineLengthX < 0 ? -1 : 1;
        	_yd  = lineLengthY < 0 ? -1 : 1;
        	_xlo =  _xd*labelOffsetX + (labelOffsetX>0 ? lineLengthX : 0);
        	_ylo = -_yd*labelOffsetY + (labelOffsetY<0 ? lineLengthY : 0);
        	
        	// run updates
            filter(t);
            layout(t);
            updateLabels(); // TODO run through transitioner?
            updateGridLines(); // TODO run through transitioner?
            return trans;
        }
		
		// -- Lookups ---------------------------------------------------------
		
		/**
		 * Returns the horizontal offset along the axis for the input value.
		 * @param value an input data value
		 * @return the horizontal offset along the axis corresponding to the
		 *  input value. This is the x-position minus <code>x1</code>.
		 */
		public function offsetX(value:Object):Number
        {
        	return axisScale.interpolate(value) * (_xb - _xa);
        }
        
        /**
		 * Returns the vertical offset along the axis for the input value.
		 * @param value an input data value
		 * @return the vertical offset along the axis corresponding to the
		 *  input value. This is the y-position minus <code>y1</code>.
		 */
        public function offsetY(value:Object):Number
        {
        	return axisScale.interpolate(value) * (_yb - _ya);
        }

		/** @inheritDoc */
		public function X(value:Object):Number
        {
        	return _xa + offsetX(value);
        }
        
        /** @inheritDoc */
        public function Y(value:Object):Number
        {
        	return _ya + offsetY(value);
        }
        
        /** @inheritDoc */
        public function value(x:Number, y:Number, stayInBounds:Boolean=true):Object
        {
        	// project the input point onto the axis line
        	// (P-A).(B-A) / |B-A|^2 == fractional projection onto axis line
        	var dx:Number = (_xb-_xa);
        	var dy:Number = (_yb-_ya);
        	var f:Number = ((x-_xa)*dx + (y-_ya)*dy) / (dx*dx + dy*dy);
        	// correct bounds, if desired
        	if (stayInBounds) {
        		if (f < 0) f = 0;
        		if (f > 1) f = 1;
        	}
        	// lookup and return value
        	return axisScale.lookup(f);
        }
		
		/**
		 * Clears the previous axis scale used, if cached.
		 */
		public function clearPreviousScale():void
		{
			_prevScale = axisScale;
		}
		
		// -- Filter ----------------------------------------------------------
		
		/**
		 * Performs filtering, determining which axis labels and grid lines
		 * should be visible.
		 * @param trans a Transitioner for collecting value updates.
		 */
		protected function filter(trans:Transitioner) : void
		{
			var ordinal:uint = 0, i:uint, idx:int = -1, val:Object;
			var label:AxisLabel = null;
			var gline:AxisGridLine = null;
			var nl:uint = labels.numChildren;
			var ng:uint = gridLines.numChildren;
			
			var keepLabels:Array = new Array(nl);
			var keepLines:Array = new Array(ng);
			var values:Array = axisScale.values(numLabels);
			
			if (showLabels) { // process labels
				for (i=0, ordinal=0; i<values.length; ++i) {
					val = values[i];
					if ((idx = findLabel(val, nl)) < 0) {
						label = createLabel(val);
					} else {
						label = labels.getChildAt(idx) as AxisLabel;
						keepLabels[idx] = true;
					}
					label.ordinal = ordinal++;
				}
			}
			if (showLines) { // process gridlines
				for (i=0, ordinal=0; i<values.length; ++i) {
					val = values[i];
					if ((idx = findGridLine(val, ng)) < 0) {
						gline = createGridLine(val);
					} else {
						gline = gridLines.getChildAt(idx) as AxisGridLine;
						keepLines[idx] = true;
					}
					gline.ordinal = ordinal++;
				}
			}
			markRemovals(trans, keepLabels, labels);
			markRemovals(trans, keepLines, gridLines);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?