YAxisBase.as 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  1. package elements.axis {
  2. import flash.display.Sprite;
  3. import string.Utils;
  4. public class YAxisBase extends Sprite {
  5. protected var stroke:Number;
  6. protected var tick_length:Number;
  7. protected var colour:Number;
  8. protected var grid_colour:Number;
  9. public var style:Object;
  10. protected var labels:YAxisLabelsBase;
  11. private var user_labels:Array;
  12. private var user_ticks:Boolean;
  13. function YAxisBase() {}
  14. public function init(json:Object): void {}
  15. // called once the sprite has been added to the stage
  16. // so now it has access to the stage
  17. protected function _init(json:Object, name:String, style:Object): void {
  18. this.style = style;
  19. if( json[name] )
  20. object_helper.merge_2( json[name], this.style );
  21. this.colour = Utils.get_colour( style.colour );
  22. this.grid_colour = Utils.get_colour( style['grid-colour'] );
  23. this.stroke = style.stroke;
  24. this.tick_length = style['tick-length'];
  25. tr.aces('YAxisBase auto', this.auto_range( 50001 ));
  26. tr.aces('YAxisBase min, max', this.style.min, this.style.max);
  27. if ( this.style.max == null ) {
  28. // we have labels, so use the number of
  29. // labels as Y MAX
  30. this.style.max = this.labels.y_max;
  31. }
  32. // make sure we don't have 1,000,000 steps
  33. var min:Number = Math.min(this.style.min, this.style.max);
  34. var max:Number = Math.max(this.style.min, this.style.max);
  35. this.style.steps = this.get_steps(min, max, this.stage.stageHeight);
  36. if ( this.labels.i_need_labels )
  37. this.labels.make_labels(min, max, this.style.steps);
  38. //
  39. // colour the grid lines
  40. //
  41. // TODO: remove this and
  42. // this.user_ticks
  43. // this.user_labels
  44. //
  45. if ((this.style.labels != null) &&
  46. (this.style.labels.labels != null) &&
  47. (this.style.labels.labels is Array) &&
  48. (this.style.labels.labels.length > 0))
  49. {
  50. this.user_labels = new Array();
  51. for each( var lbl:Object in this.style.labels.labels )
  52. {
  53. if (!(lbl is String)) {
  54. if (lbl.y != null)
  55. {
  56. var tmpObj:Object = { y: lbl.y };
  57. if (lbl["grid-colour"])
  58. {
  59. tmpObj["grid-colour"] = Utils.get_colour(lbl["grid-colour"]);
  60. }
  61. else
  62. {
  63. tmpObj["grid-colour"] = this.grid_colour;
  64. }
  65. this.user_ticks = true;
  66. this.user_labels.push(tmpObj);
  67. }
  68. }
  69. }
  70. }
  71. }
  72. public function auto_range(max:Number): Number {
  73. var maxValue:Number = Math.max(max) * 1.07;
  74. var l:Number = Math.round(Math.log(maxValue)/Math.log(10));
  75. var p:Number = Math.pow(10, l) / 2;
  76. maxValue = Math.round((maxValue * 1.1) / p) * p;
  77. return maxValue;
  78. /*
  79. var maxValue:Number = Math.max($bar_1->data) * 1.07;
  80. $l = round(log($maxValue)/log(10));
  81. $p = pow(10, $l) / 2;
  82. $maxValue = round($maxValue * 1.1 / $p) * $p;
  83. */
  84. /*
  85. * http://forums.openflashchart.com/viewtopic.php?f=5&t=617&start=0
  86. * cdcarson
  87. // y axis data...
  88. $counts = array_values($data);
  89. $ymax = max($counts);
  90. // add a bit of padding to the top, not strictly necessary...
  91. $ymax += ceil(.1 * $ymax);
  92. //$max_steps could be anything,depending on the height of the chart, font-size, etc..
  93. $max_steps = 10;
  94. /**
  95. * The step sizes to test are created using an
  96. * array of multipliers and a power of 10, starting at 0.
  97. * $step_size = $multiplier * pow(10, $exponent);
  98. * Assuming $multipliers = array(1, 2, 5) this would give us...
  99. * 1, 2, 5, 10, 20, 50, 100, 200, 500, 1000, 2000, 5000,...
  100. * /
  101. $n = 0;
  102. $multipliers = array(1, 2, 5);
  103. $num_multipliers = count($multipliers);
  104. $exponent = floor($n / $num_multipliers);
  105. $multiplier = $multipliers[$n % $num_multipliers];
  106. $step_size = $multiplier * pow(10, $exponent);
  107. $num_steps = ceil($ymax/$step_size);
  108. //keep testing until we have the right step_size...
  109. while ($num_steps >= $max_steps){
  110. $n ++;
  111. $exponent = floor($n / $num_multipliers);
  112. $multiplier = $multipliers[$n % $num_multipliers];
  113. $step_size = $multiplier * pow(10, $exponent);
  114. $num_steps = ceil($ymax/$step_size);
  115. }
  116. $yaxis = new y_axis();
  117. $yaxis->set_range(0, $ymax, $step_size);
  118. */
  119. }
  120. public function get_style():Object { return null; }
  121. //
  122. // may be called by the labels
  123. //
  124. public function set_y_max( m:Number ):void {
  125. this.style.max = m;
  126. }
  127. public function get_range():Range {
  128. return new Range( this.style.min, this.style.max, this.style.steps, this.style.offset );
  129. }
  130. public function get_width():Number {
  131. return this.stroke + this.tick_length + this.labels.width;
  132. }
  133. public function die(): void {
  134. //this.offset = null;
  135. this.style = null;
  136. if (this.labels != null) this.labels.die();
  137. this.labels = null;
  138. this.graphics.clear();
  139. while ( this.numChildren > 0 )
  140. this.removeChildAt(0);
  141. }
  142. private function get_steps(min:Number, max:Number, height:Number):Number {
  143. // try to avoid infinite loops...
  144. if ( this.style.steps == 0 )
  145. this.style.steps = 1;
  146. if ( this.style.steps < 0 )
  147. this.style.steps *= -1;
  148. // how many steps (grid lines) do we have?
  149. var s:Number = (max - min) / this.style.steps;
  150. if ( s > (height/2) ) {
  151. // either no steps are set, or they are wrong and
  152. // we have more grid lines than pixels to show them.
  153. // E.g:
  154. // max = 1,001,000
  155. // min = 1,000
  156. // s = 200,000
  157. return (max - min) / 5;
  158. }
  159. return this.style.steps;
  160. }
  161. public function resize(label_pos:Number, sc:ScreenCoords):void { }
  162. protected function resize_helper(label_pos:Number, sc:ScreenCoords, right:Boolean):void {
  163. // Set opacity for the first line to 0 (otherwise it overlaps the x-axel line)
  164. //
  165. // Bug? Does this work on graphs with minus values?
  166. //
  167. var i2:Number = 0;
  168. var i:Number;
  169. var y:Number;
  170. var lbl:Object;
  171. var min:Number = Math.min(this.style.min, this.style.max);
  172. var max:Number = Math.max(this.style.min, this.style.max);
  173. if( !right )
  174. this.labels.resize( label_pos, sc );
  175. else
  176. this.labels.resize( sc.right + this.stroke + this.tick_length, sc );
  177. if ( !this.style.visible )
  178. return;
  179. this.graphics.clear();
  180. this.graphics.lineStyle( 0, 0, 0 );
  181. if ( this.style['grid-visible'] )
  182. this.draw_grid_lines(this.style.steps, min, max, right, sc);
  183. var pos:Number;
  184. if (!right)
  185. pos = sc.left - this.stroke;
  186. else
  187. pos = sc.right;
  188. // Axis line:
  189. this.graphics.beginFill( this.colour, 1 );
  190. this.graphics.drawRect(
  191. int(pos), // <-- pixel align
  192. sc.top,
  193. this.stroke,
  194. sc.height );
  195. this.graphics.endFill();
  196. // ticks..
  197. var width:Number;
  198. if (this.user_ticks)
  199. {
  200. for each( lbl in this.user_labels )
  201. {
  202. y = sc.get_y_from_val(lbl.y, right);
  203. if ( !right )
  204. tick_pos = sc.left - this.stroke - this.tick_length;
  205. else
  206. tick_pos = sc.right + this.stroke;
  207. this.graphics.beginFill( this.colour, 1 );
  208. this.graphics.drawRect( tick_pos, y - (this.stroke / 2), this.tick_length, this.stroke );
  209. this.graphics.endFill();
  210. }
  211. }
  212. else
  213. {
  214. for(i=min; i<=max; i+=this.style.steps) {
  215. // start at the bottom and work up:
  216. y = sc.get_y_from_val(i, right);
  217. var tick_pos:Number;
  218. if ( !right )
  219. tick_pos = sc.left - this.stroke - this.tick_length;
  220. else
  221. tick_pos = sc.right + this.stroke;
  222. this.graphics.beginFill( this.colour, 1 );
  223. this.graphics.drawRect( tick_pos, y - (this.stroke / 2), this.tick_length, this.stroke );
  224. this.graphics.endFill();
  225. }
  226. }
  227. }
  228. private function draw_grid_lines(steps:Number, min:Number, max:Number, right:Boolean, sc:ScreenCoords): void {
  229. var y:Number;
  230. var lbl:Object;
  231. //
  232. // draw GRID lines
  233. //
  234. if (this.user_ticks)
  235. {
  236. for each(lbl in this.user_labels )
  237. {
  238. y = sc.get_y_from_val(lbl.y, right);
  239. this.graphics.beginFill(lbl["grid-colour"], 1);
  240. this.graphics.drawRect( sc.left, y, sc.width, 1 );
  241. this.graphics.endFill();
  242. }
  243. }
  244. else
  245. {
  246. //
  247. // hack: http://kb.adobe.com/selfservice/viewContent.do?externalId=tn_13989&sliceId=1
  248. //
  249. max += 0.000004;
  250. for( var i:Number = min; i<=max; i+=steps ) {
  251. y = sc.get_y_from_val(i, right);
  252. this.graphics.beginFill( this.grid_colour, 1 );
  253. this.graphics.drawRect(
  254. int(sc.left),
  255. int(y), // <-- make sure they are pixel aligned (2.5 - 3.5 == fuzzy lines)
  256. sc.width,
  257. 1 );
  258. this.graphics.endFill();
  259. }
  260. }
  261. }
  262. }
  263. }