package elements.axis { import flash.display.Sprite; import flash.text.TextField; import flash.text.TextFormat; import flash.display.DisplayObject; import flash.geom.Rectangle; import elements.axis.AxisLabel; import string.Utils; import string.DateUtils; import com.serialization.json.JSON; // import DateUtils; public class XAxisLabels extends Sprite { public var need_labels:Boolean; public var axis_labels:Array; // JSON style: private var style:Object; private var userSpecifiedVisible:Object; // // Ugh, ugly code so we can rotate the text: // // [Embed(systemFont='Arial', fontName='spArial', mimeType='application/x-font', unicodeRange='U+0020-U+007E')] [Embed(systemFont = 'Arial', fontName = 'spArial', mimeType = 'application/x-font')] public static var ArialFont__:Class; function XAxisLabels( json:Object ) { this.need_labels = true; // TODO: remove this and the class // var style:XLabelStyle = new XLabelStyle( json.x_labels ); this.style = { rotate: 0, visible: null, labels: null, text: '#val#', // <-- default to display the position number or x value steps: null, // <-- null for auto labels size: 10, align: 'auto', colour: '#000000', "visible-steps": null }; // cache the text for tooltips this.axis_labels = new Array(); if( ( json.x_axis != null ) && ( json.x_axis.labels != null ) ) object_helper.merge_2( json.x_axis.labels, this.style ); // save the user specified visible value foe use with auto_labels this.userSpecifiedVisible = this.style.visible; // for user provided labels, default to visible if not specified if (this.style.visible == null) this.style.visible = true; // Force rotation value if "rotate" is specified if ( this.style.rotate is String ) { if (this.style.rotate == "vertical") { this.style.rotate = 270; } else if (this.style.rotate == "diagonal") { this.style.rotate = -45; } } this.style.colour = Utils.get_colour( this.style.colour ); if( ( this.style.labels is Array ) && ( this.style.labels.length > 0 ) ) { // // we WERE passed labels // this.need_labels = false; if (this.style.steps == null) this.style.steps = 1; // // BUG: this should start counting at X MIN, not zero // var x:Number = 0; var lblCount:Number = 0; // Allow for only displaying some of the labels var visibleSteps:Number = (this.style["visible-steps"] == null) ? this.style.steps : this.style["visible-steps"]; for each( var s:Object in this.style.labels ) { var tmpStyle:Object = { }; object_helper.merge_2( this.style, tmpStyle ); tmpStyle.visible = ((lblCount % visibleSteps) == 0); tmpStyle.x = x; // we need the x position for #x_label# tooltips this.add( s, tmpStyle ); x++; lblCount++; } } } // // we were not passed labels and need to make // them from the X Axis range // public function auto_label( range:Range, steps:Number ):void { // // if the user has passed labels we don't do this // if ( this.need_labels ) { var rev:Boolean = (range.min >= range.max); // min-max reversed? // Use the steps specific to labels if provided by user var lblSteps:Number = 1; if (this.style.steps != null) lblSteps = this.style.steps; // force max of 250 labels if (Math.abs(range.count() / lblSteps) > 250) lblSteps = range.count() / 250; // guarantee lblSteps is the proper sign lblSteps = rev ? -Math.abs(lblSteps) : Math.abs(lblSteps); // Allow for only displaying some of the labels var visibleSteps:Number = (this.style["visible-steps"] == null) ? steps : this.style["visible-steps"]; var tempStyle:Object = {}; object_helper.merge_2( this.style, tempStyle ); var lblCount:Number = 0; for ( var i:Number = range.min; rev ? i >= range.max : i <= range.max; i += lblSteps ) { tempStyle.x = i; // restore the user specified visble value if (this.userSpecifiedVisible == null) { tempStyle.visible = ((lblCount % visibleSteps) == 0); lblCount++; } else { tempStyle.visible = this.userSpecifiedVisible; } this.add( null, tempStyle ); } } } public function add( label:Object, style:Object ) : void { var label_style:Object = { colour: style.colour, text: style.text, rotate: style.rotate, size: style.size, align: style.align, visible: style.visible, x: style.x }; // // inherit some properties from // our parents 'globals' // if( label is String ) label_style.text = label as String; else object_helper.merge_2( label, label_style ); // Replace magic date variables in x label text if (label_style.x != null) { label_style.text = this.replace_magic_values(label_style.text, label_style.x); } var lines:Array = label_style.text.split( '
' ); label_style.text = lines.join( '\n' ); // Map X location to label string this.axis_labels[label_style.x] = label_style.text; // only create the label if necessary if (label_style.visible) { // our parent colour is a number, but // we may have our own colour: if( label_style.colour is String ) label_style.colour = Utils.get_colour( label_style.colour ); var l:TextField = this.make_label( label_style ); this.addChild( l ); } } public function get( i:Number ) : String { if( i 0 ) // this is a kludge compensating for ScreenCoords dividing the width by 2 return AxisLabel(this.getChildAt(this.numChildren - 1)).rightOverhang * 2; else return 0; } // see above comments public function first_label_width() : Number { if( this.numChildren>0 ) // this is a kludge compensating for ScreenCoords dividing the width by 2 return AxisLabel(this.getChildAt(0)).leftOverhang * 2; else return 0; } public function die(): void { this.axis_labels = null; this.style = null; this.graphics.clear(); while ( this.numChildren > 0 ) this.removeChildAt(0); } private function replace_magic_values(labelText:String, xVal:Number):String { labelText = labelText.replace('#val#', NumberUtils.formatNumber(xVal)); labelText = DateUtils.replace_magic_values(labelText, xVal); return labelText; } } }