axis.as

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

AS
714
字号
		}
		
		/**
		 * Marks all items slated for removal from this axis.
		 * @param trans a Transitioner for collecting value updates.
		 * @param keep a Boolean array indicating which items to keep
		 * @param con a container Sprite whose contents should be marked
		 *  for removal
		 */
		protected function markRemovals(trans:Transitioner, keep:Array, con:Sprite) : void
		{
			for (var i:uint = keep.length; --i >= 0; ) {
				if (!keep[i]) trans.removeChild(con.getChildAt(i));
			}
		}
		
		// -- Layout ----------------------------------------------------------
		
		/**
		 * Performs layout, setting the position of labels and grid lines.
		 * @param trans a Transitioner for collecting value updates.
		 */
		protected function layout(trans:Transitioner) : void
		{
			var i:uint, label:AxisLabel, gline:AxisGridLine, p:Point;
			var _lab:Sprite = this.labels;
			var _gls:Sprite = this.gridLines;
			var o:Object;
			
			// layout labels
			for (i=0; i<_lab.numChildren; ++i) {
				label = _lab.getChildAt(i) as AxisLabel;
				p = positionLabel(label, axisScale);
				
				o = trans.$(label);
				o.x = p.x;
				o.y = p.y;
				o.alpha = trans.willRemove(label) ? 0 : 1;
			}
			// fix label overlap
			if (fixLabelOverlap) fixOverlap(trans);
			// layout gridlines
			for (i=0; i<_gls.numChildren; ++i) {
				gline = _gls.getChildAt(i) as AxisGridLine;
				p = positionGridLine(gline, axisScale);
				
				o = trans.$(gline);
				o.x1 = p.x;
				o.y1 = p.y;
				o.x2 = p.x + lineLengthX + _xd*(lineCapX1+lineCapX2);
				o.y2 = p.y + lineLengthY + _yd*(lineCapY1+lineCapY2);
				o.alpha = trans.willRemove(gline) ? 0 : 1;
			}
			// update previous scale
			_prevScale = axisScale.clone(); // clone scale
			_xaP = _xa; _yaP = _ya; _xbP = _xb; _ybP = _yb;
		}
		
		// -- Label Overlap ---------------------------------------------------
		
		/**
		 * Eliminates overlap between labels along an axis. 
		 * @param trans a transitioner, potentially storing label positions
		 */		
		protected function fixOverlap(trans:Transitioner):void
		{
			var labs:Array = [], d:DisplayObject, i:int;
			// collect and sort labels
			for (i=0; i<labels.numChildren; ++i) {
				var s:AxisLabel = AxisLabel(labels.getChildAt(i));
				if (!trans.willRemove(s)) labs.push(s);
			}
			if (labs.length == 0) return;
			labs.sortOn("ordinal", Array.NUMERIC);
			
			// stores the labels to remove
			var rem:Dictionary = new Dictionary();
			
			if (axisScale.scaleType == ScaleType.LOG) {
				fixLogOverlap(labs, rem, trans, axisScale);
			}
			
			// maintain min and max if we get down to two
			i = labs.length;
			var min:Object = labs[0];
			var max:Object = labs[i-1];
			var mid:Object = (i&1) ? labs[(i>>1)] : null;

			// fix overlap with an iterative optimization
			// remove every other label with each iteration
			while (hasOverlap(labs, trans)) {
				// reduce labels
				i = labs.length;
				if (mid && i>3 && i<8) { // use min, med, max if we can
					for each (d in labs) rem[d] = d;
					if (rem[min]) delete rem[min];
					if (rem[max]) delete rem[max];
					if (rem[mid]) delete rem[mid];
					labs = [min, mid, max];
				}
				else if (i < 4) { // use min and max if we're down to two
					if (rem[min]) delete rem[min];
					if (rem[max]) delete rem[max];
					for each (d in labs) {
						if (d != min && d != max) rem[d] = d;
					}
					break;
				}
				else { // else remove every odd element
					i = i - (i&1 ? 2 : 1);
					for (; i>0; i-=2) {
						rem[labs[i]] = labs[i];
						labs.splice(i, 1); // remove from array
					}
				}
			}
			
			// remove the deleted labels
			for each (d in rem) {
				trans.$(d).alpha = 0;
				trans.removeChild(d, true);
			}
		}
		
		private static function fixLogOverlap(labs:Array, rem:Dictionary,
			trans:Transitioner, scale:Scale):void
		{
				var base:int = int(Object(scale).base), i:int, j:int, zidx:int;
				if (!hasOverlap(labs, trans)) return;
				
				// find zero
				zidx = Arrays.binarySearch(labs, 0, "value");
				var neg:Boolean = Number(scale.min) < 0;
				var pos:Boolean = Number(scale.max) > 0;
				
				// if includes negative, traverse backwards from zero/end
				if (neg) {
					i = (zidx<0 ? labs.length : zidx) - (pos ? 1 : 2);
					for (j=pos?1:2; i>=0; ++j, --i) {
						if (j == base) {
							j = 1;
						} else {
							rem[labs[i]] = labs[i];
							labs.splice(i, 1); --zidx;
						}
					}
				}
				// if includes positive, traverse forwards from zero/start
				if (pos) {
					i = (zidx<0 ? 0 : zidx+1) + (neg ? 0 : 1);
					for (j=neg?1:2; i<labs.length; ++j) {
						if (j == base) {
							j = 1; ++i;
						} else {
							rem[labs[i]] = labs[i];
							labs.splice(i, 1);
						}
					}
				}
		}
		
		private static function hasOverlap(labs:Array, trans:Transitioner):Boolean
		{
			var d:DisplayObject = labs[0], e:DisplayObject;
			for (var i:int=1; i<labs.length; ++i) {
				if (overlaps(trans, d, (e=labs[i]))) return true;
				d = e;
			}
			return false;
		}
		
		/**
		 * Indicates if two display objects overlap, sensitive to any target
		 * values stored in a transitioner.
		 * @param trans a Transitioner, potentially with target values
		 * @param l1 a display object
		 * @param l2 a display object
		 * @return true if the objects overlap (considering values in the
		 *  transitioner, if appropriate), false otherwise
		 */
		private static function overlaps(trans:Transitioner,
			l1:DisplayObject, l2:DisplayObject):Boolean
		{
			if (trans.immediate) return l1.hitTestObject(l2);
			// get original co-ordinates
			var xa:Number = l1.x, ya:Number = l1.y;
			var xb:Number = l2.x, yb:Number = l2.y;
			var o:Object;
			// set to target co-ordinates
			o = trans.$(l1); l1.x = o.x; l1.y = o.y;
			o = trans.$(l2); l2.x = o.x; l2.y = o.y;
			// compute overlap
			var b:Boolean = l1.hitTestObject(l2);
			// reset to original coordinates
			l1.x = xa; l1.y = ya; l2.x = xb; l2.y = yb;
			return b;
		}
		
		// -- Axis Label Helpers ----------------------------------------------
		
		/**
		 * Creates a new axis label.
		 * @param val the value to create the label for
		 * @return an AxisLabel
		 */		
		protected function createLabel(val:Object) : AxisLabel
		{
			var label:AxisLabel = new AxisLabel();
			var f:Number = _prevScale.interpolate(val);
			label.alpha = 0;
			label.value = val;
			label.x = _xlo + _xaP + f*(_xbP - _xaP);
			label.y = _ylo + _yaP + f*(_ybP - _yaP);
			updateLabel(label);
			labels.addChild(label);
			return label;
		}
		
		/**
		 * Computes the position of an axis label.
		 * @param label the axis label to layout
		 * @param scale the scale used to map values to the axis
		 * @return a Point with x,y coordinates for the axis label
		 */
		protected function positionLabel(label:AxisLabel, scale:Scale) : Point
		{
			var f:Number = scale.interpolate(label.value);
			_point.x = _xlo + _xa + f*(_xb-_xa);
			_point.y = _ylo + _ya + f*(_yb-_ya);
			return _point;
		}
		
		/**
		 * Updates an axis label's settings
		 * @param label the label to update
		 */		
		protected function updateLabel(label:AxisLabel) : void
		{
			label.textFormat = _labelTextFormat;
			label.horizontalAnchor = _anchorH;
			label.verticalAnchor = _anchorV;
			label.rotation = (180/Math.PI) * _labelAngle;
			label.textMode = _labelTextMode;
			label.text = _labelFormat==null ? axisScale.label(label.value)
					   : Strings.format(_labelFormat, label.value);
		}
		
		/**
		 * Updates all axis labels.
		 */		
		protected function updateLabels() : void
		{
			var _labels:Sprite = this.labels;
			for (var i:uint = 0; i<_labels.numChildren; ++i) {
				updateLabel(_labels.getChildAt(i) as AxisLabel);
			}
		}
		
		/**
		 * Returns the index of a label in the label's container sprite for a
		 * given data value.
		 * @param val the data value to find
		 * @param len the number of labels to check
		 * @return the index of a label with matching value, or -1 if no label
		 *  was found
		 */		
		protected function findLabel(val:Object, len:uint) : int
		{
			var _labels:Sprite = this.labels;
			for (var i:uint = 0; i < len; ++i) {
				// TODO: make this robust to repeated values
				if (Stats.equal((_labels.getChildAt(i) as AxisLabel).value, val)) {
					return i;
				}
			}
			return -1;
		}
		
		// -- Axis GridLine Helpers -------------------------------------------
		
		/**
		 * Creates a new axis grid line.
		 * @param val the value to create the grid lines for
		 * @return an AxisGridLine
		 */	
		protected function createGridLine(val:Object) : AxisGridLine
		{
			var gline:AxisGridLine = new AxisGridLine();
			var f:Number = _prevScale.interpolate(val);
			gline.alpha = 0;
			gline.value = val;
			gline.x1 = _xaP + f*(_xbP-_xaP) - _xd*lineCapX1;
			gline.y1 = _yaP + f*(_ybP-_yaP) - _yd*lineCapY1;
			gline.x2 = gline.x1 + lineLengthX + _xd*(lineCapX1 + lineCapX2)
			gline.y2 = gline.y1 + lineLengthY + _yd*(lineCapY1 + lineCapY2);
			updateGridLine(gline);
			gridLines.addChild(gline);
			return gline;
		}
		
		/**
		 * Computes the position of an axis grid line.
		 * @param gline the axis grid line to layout
		 * @param scale the scale used to map values to the axis
		 * @return a Point with x,y coordinates for the axis grid line
		 */
		protected function positionGridLine(gline:AxisGridLine, scale:Scale) : Point
		{
			var f:Number = scale.interpolate(gline.value);
			_point.x = _xa + f*(_xb-_xa) - _xd*lineCapX1;
			_point.y = _ya + f*(_yb-_ya) - _yd*lineCapY1;
			return _point;
		}
		
		/**
		 * Updates an axis grid line's settings
		 * @param gline the grid line to update
		 */
		protected function updateGridLine(gline:AxisGridLine) : void
		{
			gline.lineColor = _lineColor;
			gline.lineWidth = _lineWidth;
		}
		
		/**
		 * Updates all grid lines.
		 */
		protected function updateGridLines() : void
		{
			var _glines:Sprite = this.gridLines;
			for (var i:uint = 0; i<_glines.numChildren; ++i) {
				updateGridLine(_glines.getChildAt(i) as AxisGridLine);
			}
		}
		
		/**
		 * Returns the index of a grid lines in the line's container sprite
		 * for a given data value.
		 * @param val the data value to find
		 * @param len the number of grid lines to check
		 * @return the index of a grid line with matching value, or -1 if no
		 *  grid line was found
		 */	
		protected function findGridLine(val:Object, len:uint) : int
		{
			var _glines:Sprite = this.gridLines;
			for (var i:uint = 0; i<len; ++i) {
				// TODO: make this robust to repeated values
				if (Stats.equal((_glines.getChildAt(i) as AxisGridLine).value, val)) {
					return i;
				}
			}
			return -1;
		}
		
	} // end of class Axis
}

⌨️ 快捷键说明

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