XAxisLabels.as 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338
  1. package elements.axis {
  2. import flash.display.Sprite;
  3. import flash.text.TextField;
  4. import flash.text.TextFormat;
  5. import flash.display.DisplayObject;
  6. import flash.geom.Rectangle;
  7. import elements.axis.AxisLabel;
  8. import string.Utils;
  9. import string.DateUtils;
  10. import com.serialization.json.JSON;
  11. // import DateUtils;
  12. public class XAxisLabels extends Sprite {
  13. public var need_labels:Boolean;
  14. public var axis_labels:Array;
  15. // JSON style:
  16. private var style:Object;
  17. private var userSpecifiedVisible:Object;
  18. //
  19. // Ugh, ugly code so we can rotate the text:
  20. //
  21. // [Embed(systemFont='Arial', fontName='spArial', mimeType='application/x-font', unicodeRange='U+0020-U+007E')]
  22. [Embed(systemFont = 'Arial', fontName = 'spArial', mimeType = 'application/x-font')]
  23. public static var ArialFont__:Class;
  24. function XAxisLabels( json:Object ) {
  25. this.need_labels = true;
  26. // TODO: remove this and the class
  27. // var style:XLabelStyle = new XLabelStyle( json.x_labels );
  28. this.style = {
  29. rotate: 0,
  30. visible: null,
  31. labels: null,
  32. text: '#val#', // <-- default to display the position number or x value
  33. steps: null, // <-- null for auto labels
  34. size: 10,
  35. align: 'auto',
  36. colour: '#000000',
  37. "visible-steps": null
  38. };
  39. // cache the text for tooltips
  40. this.axis_labels = new Array();
  41. if( ( json.x_axis != null ) && ( json.x_axis.labels != null ) )
  42. object_helper.merge_2( json.x_axis.labels, this.style );
  43. // save the user specified visible value foe use with auto_labels
  44. this.userSpecifiedVisible = this.style.visible;
  45. // for user provided labels, default to visible if not specified
  46. if (this.style.visible == null) this.style.visible = true;
  47. // Force rotation value if "rotate" is specified
  48. if ( this.style.rotate is String )
  49. {
  50. if (this.style.rotate == "vertical")
  51. {
  52. this.style.rotate = 270;
  53. }
  54. else if (this.style.rotate == "diagonal")
  55. {
  56. this.style.rotate = -45;
  57. }
  58. }
  59. this.style.colour = Utils.get_colour( this.style.colour );
  60. if( ( this.style.labels is Array ) && ( this.style.labels.length > 0 ) )
  61. {
  62. //
  63. // we WERE passed labels
  64. //
  65. this.need_labels = false;
  66. if (this.style.steps == null)
  67. this.style.steps = 1;
  68. //
  69. // BUG: this should start counting at X MIN, not zero
  70. //
  71. var x:Number = 0;
  72. var lblCount:Number = 0;
  73. // Allow for only displaying some of the labels
  74. var visibleSteps:Number = (this.style["visible-steps"] == null) ? this.style.steps : this.style["visible-steps"];
  75. for each( var s:Object in this.style.labels )
  76. {
  77. var tmpStyle:Object = { };
  78. object_helper.merge_2( this.style, tmpStyle );
  79. tmpStyle.visible = ((lblCount % visibleSteps) == 0);
  80. tmpStyle.x = x;
  81. // we need the x position for #x_label# tooltips
  82. this.add( s, tmpStyle );
  83. x++;
  84. lblCount++;
  85. }
  86. }
  87. }
  88. //
  89. // we were not passed labels and need to make
  90. // them from the X Axis range
  91. //
  92. public function auto_label( range:Range, steps:Number ):void {
  93. //
  94. // if the user has passed labels we don't do this
  95. //
  96. if ( this.need_labels ) {
  97. var rev:Boolean = (range.min >= range.max); // min-max reversed?
  98. // Use the steps specific to labels if provided by user
  99. var lblSteps:Number = 1;
  100. if (this.style.steps != null) lblSteps = this.style.steps;
  101. // force max of 250 labels
  102. if (Math.abs(range.count() / lblSteps) > 250) lblSteps = range.count() / 250;
  103. // guarantee lblSteps is the proper sign
  104. lblSteps = rev ? -Math.abs(lblSteps) : Math.abs(lblSteps);
  105. // Allow for only displaying some of the labels
  106. var visibleSteps:Number = (this.style["visible-steps"] == null) ? steps : this.style["visible-steps"];
  107. var tempStyle:Object = {};
  108. object_helper.merge_2( this.style, tempStyle );
  109. var lblCount:Number = 0;
  110. for ( var i:Number = range.min; rev ? i >= range.max : i <= range.max; i += lblSteps ) {
  111. tempStyle.x = i;
  112. // restore the user specified visble value
  113. if (this.userSpecifiedVisible == null)
  114. {
  115. tempStyle.visible = ((lblCount % visibleSteps) == 0);
  116. lblCount++;
  117. }
  118. else
  119. {
  120. tempStyle.visible = this.userSpecifiedVisible;
  121. }
  122. this.add( null, tempStyle );
  123. }
  124. }
  125. }
  126. public function add( label:Object, style:Object ) : void
  127. {
  128. var label_style:Object = {
  129. colour: style.colour,
  130. text: style.text,
  131. rotate: style.rotate,
  132. size: style.size,
  133. align: style.align,
  134. visible: style.visible,
  135. x: style.x
  136. };
  137. //
  138. // inherit some properties from
  139. // our parents 'globals'
  140. //
  141. if( label is String )
  142. label_style.text = label as String;
  143. else
  144. object_helper.merge_2( label, label_style );
  145. // Replace magic date variables in x label text
  146. if (label_style.x != null) {
  147. label_style.text = this.replace_magic_values(label_style.text, label_style.x);
  148. }
  149. var lines:Array = label_style.text.split( '<br>' );
  150. label_style.text = lines.join( '\n' );
  151. // Map X location to label string
  152. this.axis_labels[label_style.x] = label_style.text;
  153. // only create the label if necessary
  154. if (label_style.visible) {
  155. // our parent colour is a number, but
  156. // we may have our own colour:
  157. if( label_style.colour is String )
  158. label_style.colour = Utils.get_colour( label_style.colour );
  159. var l:TextField = this.make_label( label_style );
  160. this.addChild( l );
  161. }
  162. }
  163. public function get( i:Number ) : String
  164. {
  165. if( i<this.axis_labels.length )
  166. return this.axis_labels[i];
  167. else
  168. return '';
  169. }
  170. public function make_label( label_style:Object ):TextField {
  171. // we create the text in its own movie clip, so when
  172. // we rotate it, we can move the regestration point
  173. var title:AxisLabel = new AxisLabel();
  174. title.x = 0;
  175. title.y = 0;
  176. //this.css.parseCSS(this.style);
  177. //title.styleSheet = this.css;
  178. title.text = label_style.text;
  179. var fmt:TextFormat = new TextFormat();
  180. fmt.color = label_style.colour;
  181. // TODO: != null
  182. if( label_style.rotate != 0 )
  183. {
  184. // so we can rotate the text
  185. fmt.font = "spArial";
  186. title.embedFonts = true;
  187. }
  188. else
  189. {
  190. fmt.font = "Verdana";
  191. }
  192. fmt.size = label_style.size;
  193. fmt.align = "left";
  194. title.setTextFormat(fmt);
  195. title.autoSize = "left";
  196. title.rotate_and_align( label_style.rotate, label_style.align, this );
  197. // we don't know the x & y locations yet...
  198. title.visible = label_style.visible;
  199. if (label_style.x != null)
  200. {
  201. // store the x value for use in resize
  202. title.xVal = label_style.x;
  203. }
  204. return title;
  205. }
  206. public function count() : Number
  207. {
  208. return this.axis_labels.length-1;
  209. }
  210. public function get_height() : Number
  211. {
  212. var height:Number = 0;
  213. for( var pos:Number=0; pos < this.numChildren; pos++ )
  214. {
  215. var child:DisplayObject = this.getChildAt(pos);
  216. height = Math.max( height, child.height );
  217. }
  218. return height;
  219. }
  220. public function resize( sc:ScreenCoords, yPos:Number ) : void
  221. {
  222. this.graphics.clear();
  223. var i:Number = 0;
  224. for( var pos:Number=0; pos < this.numChildren; pos++ )
  225. {
  226. var child:AxisLabel = this.getChildAt(pos) as AxisLabel;
  227. if (isNaN(child.xVal))
  228. {
  229. child.x = sc.get_x_tick_pos(pos) + child.xAdj;
  230. }
  231. else
  232. {
  233. child.x = sc.get_x_from_val(child.xVal) + child.xAdj;
  234. }
  235. child.y = yPos + child.yAdj;
  236. }
  237. }
  238. //
  239. // to help Box calculate the correct width:
  240. //
  241. public function last_label_width() : Number
  242. {
  243. // is the last label shown?
  244. // if( ( (this.labels.length-1) % style.step ) != 0 )
  245. // return 0;
  246. // get the width of the right most label
  247. // because it may stick out past the end of the graph
  248. // and we don't want to truncate it.
  249. // return this.mcs[(this.mcs.length-1)]._width;
  250. if ( this.numChildren > 0 )
  251. // this is a kludge compensating for ScreenCoords dividing the width by 2
  252. return AxisLabel(this.getChildAt(this.numChildren - 1)).rightOverhang * 2;
  253. else
  254. return 0;
  255. }
  256. // see above comments
  257. public function first_label_width() : Number
  258. {
  259. if( this.numChildren>0 )
  260. // this is a kludge compensating for ScreenCoords dividing the width by 2
  261. return AxisLabel(this.getChildAt(0)).leftOverhang * 2;
  262. else
  263. return 0;
  264. }
  265. public function die(): void {
  266. this.axis_labels = null;
  267. this.style = null;
  268. this.graphics.clear();
  269. while ( this.numChildren > 0 )
  270. this.removeChildAt(0);
  271. }
  272. private function replace_magic_values(labelText:String, xVal:Number):String {
  273. labelText = labelText.replace('#val#', NumberUtils.formatNumber(xVal));
  274. labelText = DateUtils.replace_magic_values(labelText, xVal);
  275. return labelText;
  276. }
  277. }
  278. }