1package com.yahoo.astra.fl.charts.axes 2{ 3 import com.yahoo.astra.utils.GeomUtil; 4 import com.yahoo.astra.utils.NumberUtil; 5 6 import fl.core.UIComponent; 7 8 import flash.geom.Point; 9 10 //TODO: Add support for labels. 11 /** 12 * The default axis renderer for radial axes. 13 * 14 * @author Josh Tynjala 15 */ 16 public class RadialAxisRenderer extends UIComponent implements IRadialAxisRenderer 17 { 18 19 //-------------------------------------- 20 // Class Variables 21 //-------------------------------------- 22 23 /** 24 * @private 25 */ 26 private static var defaultStyles:Object = 27 { 28 //axis 29 showAxis: true, 30 axisWeight: 1, 31 axisColor: 0x888a85, 32 33 //ticks 34 showTicks: true, 35 tickWeight: 1, 36 tickColor: 0x888a85, 37 tickLength: 4, 38 tickPosition: TickPosition.INSIDE, 39 40 //minor ticks 41 showMinorTicks: true, 42 minorTickWeight: 1, 43 minorTickColor: 0x888a85, 44 minorTickLength: 3, 45 minorTickPosition: TickPosition.INSIDE 46 }; 47 48 //-------------------------------------- 49 // Class Methods 50 //-------------------------------------- 51 52 /** 53 * @copy fl.core.UIComponent#getStyleDefinition() 54 */ 55 public static function getStyleDefinition():Object 56 { 57 return mergeStyles(defaultStyles, UIComponent.getStyleDefinition()); 58 } 59 60 //-------------------------------------- 61 // Constructor 62 //-------------------------------------- 63 64 /** 65 * Constructor. 66 */ 67 public function RadialAxisRenderer() 68 { 69 super(); 70 } 71 72 //-------------------------------------- 73 // Properties 74 //-------------------------------------- 75 76 /** 77 * @inheritDoc 78 */ 79 public function get length():Number 80 { 81 return Math.min(this.width, this.height) * Math.PI; 82 } 83 84 /** 85 * @private 86 * Storage for the ticks property. 87 */ 88 private var _ticks:Array = []; 89 90 /** 91 * @inheritDoc 92 */ 93 public function get ticks():Array 94 { 95 return this._ticks; 96 } 97 98 /** 99 * @private 100 */ 101 public function set ticks(value:Array):void 102 { 103 this._ticks = value; 104 this.invalidate(); 105 } 106 107 /** 108 * @private 109 * Storage for the minorTicks property. 110 */ 111 private var _minorTicks:Array = []; 112 113 /** 114 * @inheritDoc 115 */ 116 public function get minorTicks():Array 117 { 118 return this._minorTicks; 119 } 120 121 /** 122 * @private 123 */ 124 public function set minorTicks(value:Array):void 125 { 126 this._minorTicks = value; 127 this.invalidate(); 128 } 129 130 //-------------------------------------- 131 // Public Methods 132 //-------------------------------------- 133 134 /** 135 * @inheritDoc 136 */ 137 public function updateBounds():void 138 { 139 //no labels are created at this time, so this function is pretty useless 140 } 141 142 //-------------------------------------- 143 // Protected Methods 144 //-------------------------------------- 145 146 /** 147 * @private 148 */ 149 override protected function draw():void 150 { 151 var showTicks:Boolean = this.getStyleValue("showTicks") as Boolean; 152 var showMinorTicks:Boolean = this.getStyleValue("showMinorTicks") as Boolean; 153 var ticks:Array = this.ticks.concat(); 154 var minorTicks:Array = this.minorTicks.concat(); 155 if(showMinorTicks && showTicks) 156 { 157 //filter out minor ticks that appear at the same position 158 //as major ticks. 159 minorTicks = minorTicks.filter(function(item:AxisData, index:int, source:Array):Boolean 160 { 161 return !ticks.some(function(item2:AxisData, index2:int, source2:Array):Boolean 162 { 163 //using fuzzyEquals because we may encounter rounding errors 164 return NumberUtil.fuzzyEquals(item.position, item2.position, 10); 165 }); 166 }); 167 } 168 169 this.graphics.clear(); 170 171 this.drawAxis(); 172 173 var tickPosition:String = this.getStyleValue("tickPosition") as String; 174 var tickLength:Number = this.getStyleValue("tickLength") as Number; 175 var tickWeight:int = this.getStyleValue("tickWeight") as int; 176 var tickColor:uint = this.getStyleValue("tickColor") as uint; 177 this.drawTicks(ticks, showTicks, tickPosition, tickLength, tickWeight, tickColor); 178 179 var minorTickPosition:String = this.getStyleValue("minorTickPosition") as String; 180 var minorTickLength:Number = this.getStyleValue("minorTickLength") as Number; 181 var minorTickWeight:int = this.getStyleValue("minorTickWeight") as int; 182 var minorTickColor:uint = this.getStyleValue("minorTickColor") as uint; 183 this.drawTicks(minorTicks, showMinorTicks, minorTickPosition, minorTickLength, minorTickWeight, minorTickColor); 184 185 super.draw(); 186 } 187 188 /** 189 * @private 190 * Draws the main axis line. 191 */ 192 protected function drawAxis():void 193 { 194 var showAxis:Boolean = this.getStyleValue("showAxis") as Boolean; 195 if(!showAxis) 196 { 197 return; 198 } 199 200 var axisWeight:int = this.getStyleValue("axisWeight") as int; 201 var axisColor:uint = this.getStyleValue("axisColor") as uint; 202 this.graphics.lineStyle(axisWeight, axisColor); 203 204 var center:Point = new Point(this.width / 2, this.height / 2); 205 var radius:Number = Math.min(center.x, center.y); 206 this.graphics.drawCircle(center.x, center.y, radius); 207 } 208 209 /** 210 * @private 211 * Draws a set of ticks along the main axis line. This function is shared 212 * by major and minor ticks. 213 */ 214 protected function drawTicks(data:Array, showTicks:Boolean, tickPosition:String, 215 tickLength:Number, tickWeight:Number, tickColor:uint):void 216 { 217 if(!showTicks) 218 { 219 return; 220 } 221 222 this.graphics.lineStyle(tickWeight, tickColor); 223 224 var center:Point = new Point(this.width / 2, this.height / 2); 225 var radius:Number = Math.min(center.x, center.y); 226 227 var dataCount:int = data.length; 228 for(var i:int = 0; i < dataCount; i++) 229 { 230 var axisData:AxisData = AxisData(data[i]); 231 if(isNaN(axisData.position)) 232 { 233 //skip bad positions 234 continue; 235 } 236 237 var position:Number = axisData.position; 238 var angle:Number = GeomUtil.degreesToRadians(position * 360 / this.length); 239 var tickCenter:Point = Point.polar(radius, angle); 240 tickCenter = tickCenter.add(center); 241 switch(tickPosition) 242 { 243 case TickPosition.OUTSIDE: 244 var outsideEnd:Point = Point.polar(tickLength, angle); 245 outsideEnd = outsideEnd.add(tickCenter); 246 this.graphics.moveTo(tickCenter.x, tickCenter.y); 247 this.graphics.lineTo(outsideEnd.x, outsideEnd.y); 248 break; 249 case TickPosition.INSIDE: 250 var insideEnd:Point = Point.polar(tickLength, GeomUtil.degreesToRadians(180 + GeomUtil.radiansToDegrees(angle))); 251 insideEnd = insideEnd.add(tickCenter); 252 this.graphics.moveTo(tickCenter.x, tickCenter.y); 253 this.graphics.lineTo(insideEnd.x, insideEnd.y); 254 break; 255 default: //CROSS 256 outsideEnd = Point.polar(tickLength / 2, angle); 257 outsideEnd = outsideEnd.add(tickCenter); 258 insideEnd = Point.polar(tickLength / 2, GeomUtil.degreesToRadians(180 + GeomUtil.radiansToDegrees(angle))); 259 insideEnd = insideEnd.add(tickCenter); 260 this.graphics.moveTo(outsideEnd.x, outsideEnd.y); 261 this.graphics.lineTo(insideEnd.x, insideEnd.y); 262 break; 263 } 264 } 265 266 } 267 268 } 269}