1package com.yahoo.astra.fl.charts.axes
2{
3	import com.yahoo.astra.display.BitmapText;
4	import com.yahoo.astra.utils.DynamicRegistration;
5	import flash.geom.Point;
6
7	/**
8	 * The default vertical axis renderer for a cartesian chart.
9	 *
10	 * @see com.yahoo.astra.fl.charts.CartesianChart
11	 * @author Tripp Bridges
12	 */
13	public class VerticalAxisRenderer extends DefaultAxisRenderer implements ICartesianAxisRenderer
14	{
15
16	//--------------------------------------
17	//  Constructor
18	//--------------------------------------
19		public function VerticalAxisRenderer()
20		{
21			super();
22			this.orientation = AxisOrientation.VERTICAL;
23		}
24
25	//--------------------------------------
26	//  Protected Methods
27	//--------------------------------------
28
29		/**
30		 * @private
31		 * Positions the title along the axis.
32		 */
33		override protected function positionTitle():void
34		{
35			var showTitle:Boolean = this.getStyleValue("showTitle") as Boolean;
36			this.titleTextField.visible = showTitle;
37			if(showTitle)
38			{
39				var titleRotation:Number = this.getStyleValue("titleRotation") as Number;
40				titleRotation = Math.max(-90, Math.min(titleRotation, 90));
41
42				this.titleTextField.rotation = titleRotation;
43				if(this.position == "right")
44				{
45					this.titleTextField.y = this.contentBounds.y + (this.contentBounds.height) / 2;
46					this.titleTextField.x = this.width - this.titleTextField.width;
47				}
48				else
49				{
50					this.titleTextField.y = this.contentBounds.y + (this.contentBounds.height) / 2;
51					this.titleTextField.x = 0;
52				}
53				if(titleRotation > 0)
54				{
55					this.titleTextField.x += this.titleTextField.contentHeight * Math.sin(titleRotation * Math.PI/180);
56					this.titleTextField.y -= this.titleTextField.height/2;
57				}
58				else if(titleRotation < 0)
59				{
60					this.titleTextField.y += this.titleTextField.height/2;
61				}
62				else
63				{
64					this.titleTextField.y -= this.titleTextField.height/2;
65				}
66			}
67		}
68
69		/**
70		 * @private
71		 * Draws the axis origin line.
72		 */
73		override protected function drawAxis():void
74		{
75			super.drawAxis();
76			var verticalX:Number = this.contentBounds.x;
77			if(this.position == "right")
78			{
79				verticalX = this.contentBounds.x + this.contentBounds.width;
80			}
81			var verticalStart:Number = this.contentBounds.y;
82			var verticalEnd:Number = this.contentBounds.y + this.contentBounds.height;
83			this.graphics.moveTo(verticalX, verticalStart);
84			this.graphics.lineTo(verticalX, verticalEnd);
85		}
86
87		/**
88		 * @private
89		 * Draws a set of ticks on the axis.
90		 */
91		override protected function drawTicks(data:Array, showTicks:Boolean, tickPosition:String,
92			tickLength:Number, tickWeight:Number, tickColor:uint):void
93		{
94			if(!showTicks)
95			{
96				return;
97			}
98
99			this.graphics.lineStyle(tickWeight, tickColor);
100
101			var axisPosition:Number = this.position == "right" ? this.contentBounds.x + this.contentBounds.width : this.contentBounds.x;
102			if(this.position == "right") tickLength *= -1;
103			var dataCount:int = data.length;
104			for(var i:int = 0; i < dataCount; i++)
105			{
106				var axisData:AxisData = AxisData(data[i]);
107				if(isNaN(axisData.position))
108				{
109					//skip bad positions
110					continue;
111				}
112
113				var position:Number = axisData.position;
114				position += this.contentBounds.y;
115
116				switch(tickPosition)
117				{
118					case TickPosition.OUTSIDE:
119						this.graphics.moveTo(axisPosition - tickLength, position);
120						this.graphics.lineTo(axisPosition, position);
121						break;
122
123					case TickPosition.INSIDE:
124						this.graphics.moveTo(axisPosition, position);
125						this.graphics.lineTo(axisPosition + tickLength, position);
126						break;
127
128					default: //CROSS
129						this.graphics.moveTo(axisPosition - tickLength / 2, position);
130						this.graphics.lineTo(axisPosition + tickLength / 2, position);
131						break;
132				}
133			}
134		}
135
136		/**
137		 * @private
138		 * Positions a set of labels on the axis.
139		 */
140		override protected function positionLabels(labels:Array, showLabels:Boolean, labelDistance:Number, labelRotation:Number, embedFonts:Boolean):void
141		{
142			if(!showLabels) return;
143			var labelCount:int = this.labelTextFields.length;
144			for(var i:int = 0; i < labelCount; i++)
145			{
146				var label:BitmapText = BitmapText(this.labelTextFields[i]);
147				label.rotation = 0;
148				var axisData:AxisData = AxisData(this.ticks[i]);
149				var position:Number = axisData.position;
150				position += this.contentBounds.y;
151				var absRotation:Number = Math.abs(labelRotation);
152				var xRegistration:Number;
153				label.y = position;
154
155				if(this.position == "left")
156				{
157					label.x = this.contentBounds.x - labelDistance - this.outerTickOffset;
158					xRegistration = label.width - Math.min(label.height/2, Math.sin(absRotation * Math.PI/180) * label.height/4);
159					if(absRotation > 0 && absRotation < 90)
160					{
161						label.y -= label.height/2;
162						label.x -= label.width;
163						DynamicRegistration.rotate(label, new Point(xRegistration, label.height / 2), labelRotation);
164					}
165					else if(labelRotation == 90)
166					{
167						label.rotation = labelRotation;
168						label.y -= label.height/2;
169					}
170					else if(labelRotation == -90)
171					{
172						label.rotation = labelRotation;
173						label.x -= label.width;
174						label.y += label.height/2;
175					}
176					else
177					{
178						label.x -= label.width;
179						label.y -= label.height/2;
180					}
181				}
182				else
183				{
184					label.x = this.contentBounds.x + this.contentBounds.width + labelDistance + this.outerTickOffset;
185					xRegistration = Math.min(label.height/2, Math.sin(absRotation * Math.PI/180) * label.height/4);
186					if(absRotation > 0 && absRotation < 90)
187					{
188						label.y -= label.height/2;
189						DynamicRegistration.rotate(label, new Point(xRegistration, label.height / 2), labelRotation);
190					}
191					else if(labelRotation == 90)
192					{
193						label.rotation = labelRotation;
194						label.y -= label.height/2;
195						label.x += label.width;
196					}
197					else if(labelRotation == -90)
198					{
199						DynamicRegistration.rotate(label, new Point(xRegistration, label.height / 2), labelRotation);
200						label.y += label.height/2;
201					}
202					else
203					{
204						label.y -= label.height/2;
205					}
206				}
207
208				label.x = Math.round(label.x);
209				label.y = Math.round(label.y);
210				this.handleOverlappingLabels();
211			}
212		}
213
214		/**
215		 * @private
216		 * If labels overlap, some may need to be hidden.
217		 */
218		override protected function handleOverlappingLabels():void
219		{
220			var showLabels:Boolean = this.getStyleValue("showLabels");
221			var hideOverlappingLabels:Boolean = this.getStyleValue("hideOverlappingLabels");
222			if(!showLabels || !hideOverlappingLabels)
223			{
224				return;
225			}
226			var labelRotation:Number = this.getStyleValue("labelRotation") as Number;
227			var lastVisibleLabel:BitmapText;
228 			var labelCount:int = this.labelTextFields.length;
229			for(var i:int = 0; i < labelCount; i++)
230			{
231				var idealDistance:Number;
232				var index:int = labelRotation >= 0 ? i : (labelCount - i - 1);
233				var label:BitmapText = BitmapText(this.labelTextFields[index]);
234				label.visible = true;
235				if(lastVisibleLabel)
236				{
237					var diff:Number;
238					var offset:Point;
239					offset = new Point(0, 0);
240					var radians:Number = Math.abs(labelRotation) * Math.PI/180;
241					if(lastVisibleLabel.y > label.y)
242					{
243						if(Math.abs(labelRotation) == 90)
244						{
245							idealDistance = label.textField.textWidth;
246						}
247						else if(labelRotation == 0)
248						{
249							idealDistance = label.textField.textHeight;
250						}
251						else
252						{
253							idealDistance = (label.textField.textHeight / (Math.cos((Math.abs(labelRotation))*Math.PI/180)));
254							idealDistance = Math.min(idealDistance, label.height);
255						}
256						if((label.y + label.height + idealDistance) > (lastVisibleLabel.y + lastVisibleLabel.height))
257						{
258							label.visible = false;
259						}
260					}
261					else
262					{
263						if(Math.abs(labelRotation) == 90)
264						{
265							idealDistance = lastVisibleLabel.textField.textWidth;
266						}
267						else if(labelRotation == 0)
268						{
269							idealDistance = lastVisibleLabel.textField.textHeight;
270						}
271						else
272						{
273							idealDistance = (lastVisibleLabel.textField.textHeight / (Math.cos((Math.abs(labelRotation))*Math.PI/180)));
274							idealDistance = Math.min(idealDistance, lastVisibleLabel.height);
275						}
276						if((lastVisibleLabel.y + lastVisibleLabel.height + idealDistance) > (label.y + label.height))
277						{
278							label.visible = false;
279						}
280					}
281				}
282				if(label.visible)
283				{
284					lastVisibleLabel = label;
285				}
286			}
287		}
288
289
290	}
291}