package elements.axis { import flash.display.Sprite; import flash.geom.Matrix; import string.Utils; import charts.series.bars.Bar3D; import com.serialization.json.JSON; import Range; public class XAxis extends Sprite { private var steps:Number; private var alt_axis_colour:Number; private var alt_axis_step:Number; private var three_d:Boolean; private var three_d_height:Number; private var stroke:Number; private var tick_height:Number; private var colour:Number; public var offset:Boolean; private var grid_colour:Number; private var grid_visible:Boolean; private var user_ticks:Boolean; private var user_labels:Array; // make this private public var labels:XAxisLabels; private var style:Object; function XAxis( json:Object, min:Number, max:Number ) { // default values this.style = { stroke: 2, 'tick-height': 3, colour: '#784016', offset: true, 'grid-colour': '#F5E1AA', 'grid-visible': true, '3d': 0, steps: 1, min: 0, max: null }; if( json != null ) object_helper.merge_2( json.x_axis, this.style ); this.calcSteps(); this.stroke = this.style.stroke; this.tick_height = this.style['tick-height']; this.colour = this.style.colour; // is the axis offset (see ScreenCoords) this.offset = this.style.offset; this.grid_visible = this.style['grid-visible']; this.colour = Utils.get_colour( this.style.colour ); this.grid_colour = Utils.get_colour( this.style['grid-colour'] ); if( style['3d'] > 0 ) { this.three_d = true; this.three_d_height = int( this.style['3d'] ); } else this.three_d = false; // Patch from Will Henry if( json ) { if( json.x_label_style != undefined ) { if( json.x_label_style.alt_axis_step != undefined ) this.alt_axis_step = json.x_label_style.alt_axis_step; if( json.x_label_style.alt_axis_colour != undefined ) this.alt_axis_colour = Utils.get_colour(json.x_label_style.alt_axis_colour); } } this.labels = new XAxisLabels( json ); this.addChild( this.labels ); // the X Axis labels *may* require info from // this.obs if( !this.range_set() ) { // // the user has not told us how long the X axis // is, so we figure it out: // if( this.labels.need_labels ) { // // No X Axis labels set: // // tr.aces( 'max x', this.obs.get_min_x(), this.obs.get_max_x() ); this.set_range( min, max ); } else { // // X Axis labels used, even so, make the chart // big enough to show all values // // tr.aces('x labels', this.obs.get_min_x(), this.x_axis.labels.count(), this.obs.get_max_x()); if ( this.labels.count() > max ) { // Data and labesl are OK this.set_range( 0, this.labels.count() ); } else { // There is more data than labels -- oops this.set_range( min, max ); } } } else { //range set, but no labels... this.labels.auto_label( this.get_range(), this.get_steps() ); } // custom ticks: this.make_user_ticks(); } // // a little hacky, but we inspect the labels // to see if we need to display user custom ticks // private function make_user_ticks():void { if ((this.style.labels != null) && (this.style.labels.labels != null) && (this.style.labels.labels is Array) && (this.style.labels.labels.length > 0)) { this.user_labels = new Array(); for each( var lbl:Object in this.style.labels.labels ) { if (!(lbl is String)) { if (lbl.x != null) { var tmpObj:Object = { x: lbl.x }; if (lbl["grid-colour"]) { tmpObj["grid-colour"] = Utils.get_colour(lbl["grid-colour"]); } else { tmpObj["grid-colour"] = this.grid_colour; } this.user_ticks = true; this.user_labels.push(tmpObj); } } } } } private function calcSteps():void { if (this.style.max == null) { this.steps = 1; } else { var xRange:Number = this.style.max - this.style.min; var rev:Boolean = (this.style.min >= this.style.max); // min-max reversed? this.steps = ((this.style.steps != null) && (this.style.steps != 0)) ? this.style.steps : 1; // force max of 250 labels and tick marks if ((Math.abs(xRange) / this.steps) > 250) this.steps = xRange / 250; // guarantee lblSteps is the proper sign this.steps = rev ? -Math.abs(this.steps) : Math.abs(this.steps); } } // // have we been passed a range? (min and max?) // public function range_set():Boolean { return this.style.max != null; } // // We don't have a range, so we need to calculate it. // grid lines, depends on number of values, // the X Axis labels and X min and X max // public function set_range( min:Number, max:Number ):void { this.style.min = min; this.style.max = max; // Calc new steps this.calcSteps(); this.labels.auto_label( this.get_range(), this.get_steps() ); } // // how many items in the X axis? // public function get_range():Range { return new Range( this.style.min, this.style.max, this.steps, this.offset ); } public function get_steps():Number { return this.steps; } public function resize( sc:ScreenCoords, yPos:Number ):void { this.graphics.clear(); // // Grid lines // if (this.user_ticks) { for each( var lbl:Object in this.user_labels ) { this.graphics.beginFill(lbl["grid-colour"], 1); var xVal:Number = sc.get_x_from_val(lbl.x); this.graphics.drawRect( xVal, sc.top, 1, sc.height ); this.graphics.endFill(); } } else if(this.grid_visible) { var rev:Boolean = (this.style.min >= this.style.max); // min-max reversed? var tickMax:Number = /*(rev && this.style.offset) ? this.style.max-2 : */ this.style.max for( var i:Number=this.style.min; rev ? i >= tickMax : i <= tickMax; i+=this.steps ) { if( ( this.alt_axis_step > 1 ) && ( i % this.alt_axis_step == 0 ) ) this.graphics.beginFill(this.alt_axis_colour, 1); else this.graphics.beginFill(this.grid_colour, 1); xVal = sc.get_x_from_val(i); this.graphics.drawRect( xVal, sc.top, 1, sc.height ); this.graphics.endFill(); } } if( this.three_d ) this.three_d_axis( sc ); else this.two_d_axis( sc ); this.labels.resize( sc, yPos ); } public function three_d_axis( sc:ScreenCoords ):void { // for 3D var h:Number = this.three_d_height; var offset:Number = 12; var x_axis_height:Number = h+offset; // // ticks var item_width:Number = sc.width / this.style.max; // turn off out lines: this.graphics.lineStyle(0,0,0); var w:Number = 1; if (this.user_ticks) { for each( var lbl:Object in this.user_labels ) { var xVal:Number = sc.get_x_from_val(lbl.x); this.graphics.beginFill(this.colour, 1); this.graphics.drawRect( xVal, sc.bottom + x_axis_height, w, this.tick_height ); this.graphics.endFill(); } } else { for( var i:Number=0; i < this.style.max; i+=this.steps ) { var pos:Number = sc.get_x_tick_pos(i); this.graphics.beginFill(this.colour, 1); this.graphics.drawRect( pos, sc.bottom + x_axis_height, w, this.tick_height ); this.graphics.endFill(); } } var lighter:Number = Bar3D.Lighten( this.colour ); // TOP var colors:Array = [this.colour,lighter]; var alphas:Array = [100,100]; var ratios:Array = [0,255]; var matrix:Matrix = new Matrix(); matrix.createGradientBox(sc.width_(), offset, (270 / 180) * Math.PI, sc.left-offset, sc.bottom ); this.graphics.beginGradientFill('linear' /*GradientType.Linear*/, colors, alphas, ratios, matrix, 'pad'/*SpreadMethod.PAD*/ ); this.graphics.moveTo(sc.left,sc.bottom); this.graphics.lineTo(sc.right,sc.bottom); this.graphics.lineTo(sc.right-offset,sc.bottom+offset); this.graphics.lineTo(sc.left-offset,sc.bottom+offset); this.graphics.endFill(); // front colors = [this.colour,lighter]; alphas = [100,100]; ratios = [0, 255]; matrix.createGradientBox( sc.width_(), h, (270 / 180) * Math.PI, sc.left - offset, sc.bottom + offset ); this.graphics.beginGradientFill("linear", colors, alphas, ratios, matrix); this.graphics.moveTo(sc.left-offset,sc.bottom+offset); this.graphics.lineTo(sc.right-offset,sc.bottom+offset); this.graphics.lineTo(sc.right-offset,sc.bottom+offset+h); this.graphics.lineTo(sc.left-offset,sc.bottom+offset+h); this.graphics.endFill(); // right side colors = [this.colour,lighter]; alphas = [100,100]; ratios = [0,255]; // var matrix:Object = { matrixType:"box", x:box.left - offset, y:box.bottom + offset, w:box.width_(), h:h, r:(225 / 180) * Math.PI }; matrix.createGradientBox( sc.width_(), h, (225 / 180) * Math.PI, sc.left - offset, sc.bottom + offset ); this.graphics.beginGradientFill("linear", colors, alphas, ratios, matrix); this.graphics.moveTo(sc.right,sc.bottom); this.graphics.lineTo(sc.right,sc.bottom+h); this.graphics.lineTo(sc.right-offset,sc.bottom+offset+h); this.graphics.lineTo(sc.right-offset,sc.bottom+offset); this.graphics.endFill(); } // 2D: public function two_d_axis( sc:ScreenCoords ):void { // // ticks var item_width:Number = sc.width / this.style.max; var left:Number = sc.left+(item_width/2); //this.graphics.clear(); // Axis line: this.graphics.lineStyle( 0, 0, 0 ); this.graphics.beginFill( this.colour ); this.graphics.drawRect( sc.left, sc.bottom, sc.width, this.stroke ); this.graphics.endFill(); if (this.user_ticks) { for each( var lbl:Object in this.user_labels ) { var xVal:Number = sc.get_x_from_val(lbl.x); this.graphics.beginFill(this.colour, 1); this.graphics.drawRect( xVal-(this.stroke/2), sc.bottom + this.stroke, this.stroke, this.tick_height ); this.graphics.endFill(); } } else { for( var i:Number=this.style.min; i <= this.style.max; i+=this.steps ) { xVal = sc.get_x_from_val(i); this.graphics.beginFill(this.colour, 1); this.graphics.drawRect( xVal-(this.stroke/2), sc.bottom + this.stroke, this.stroke, this.tick_height ); this.graphics.endFill(); } } } public function get_height():Number { if( this.three_d ) { // 12 is the size of the slanty // 3D part of the X axis return this.three_d_height+12+this.tick_height + this.labels.get_height(); } else return this.stroke + this.tick_height + this.labels.get_height(); } public function first_label_width() : Number { return this.labels.first_label_width(); } public function last_label_width() : Number { return this.labels.last_label_width(); } public function die(): void { this.style = null; this.graphics.clear(); while ( this.numChildren > 0 ) this.removeChildAt(0); if (this.labels != null) this.labels.die(); this.labels = null; } } }