package elements.axis { import flash.display.Sprite; import string.Utils; public class YAxisBase extends Sprite { protected var stroke:Number; protected var tick_length:Number; protected var colour:Number; protected var grid_colour:Number; public var style:Object; protected var labels:YAxisLabelsBase; private var user_labels:Array; private var user_ticks:Boolean; function YAxisBase() {} public function init(json:Object): void {} // called once the sprite has been added to the stage // so now it has access to the stage protected function _init(json:Object, name:String, style:Object): void { this.style = style; if( json[name] ) object_helper.merge_2( json[name], this.style ); this.colour = Utils.get_colour( style.colour ); this.grid_colour = Utils.get_colour( style['grid-colour'] ); this.stroke = style.stroke; this.tick_length = style['tick-length']; tr.aces('YAxisBase auto', this.auto_range( 50001 )); tr.aces('YAxisBase min, max', this.style.min, this.style.max); if ( this.style.max == null ) { // we have labels, so use the number of // labels as Y MAX this.style.max = this.labels.y_max; } // make sure we don't have 1,000,000 steps var min:Number = Math.min(this.style.min, this.style.max); var max:Number = Math.max(this.style.min, this.style.max); this.style.steps = this.get_steps(min, max, this.stage.stageHeight); if ( this.labels.i_need_labels ) this.labels.make_labels(min, max, this.style.steps); // // colour the grid lines // // TODO: remove this and // this.user_ticks // this.user_labels // 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.y != null) { var tmpObj:Object = { y: lbl.y }; 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); } } } } } public function auto_range(max:Number): Number { var maxValue:Number = Math.max(max) * 1.07; var l:Number = Math.round(Math.log(maxValue)/Math.log(10)); var p:Number = Math.pow(10, l) / 2; maxValue = Math.round((maxValue * 1.1) / p) * p; return maxValue; /* var maxValue:Number = Math.max($bar_1->data) * 1.07; $l = round(log($maxValue)/log(10)); $p = pow(10, $l) / 2; $maxValue = round($maxValue * 1.1 / $p) * $p; */ /* * http://forums.openflashchart.com/viewtopic.php?f=5&t=617&start=0 * cdcarson // y axis data... $counts = array_values($data); $ymax = max($counts); // add a bit of padding to the top, not strictly necessary... $ymax += ceil(.1 * $ymax); //$max_steps could be anything,depending on the height of the chart, font-size, etc.. $max_steps = 10; /** * The step sizes to test are created using an * array of multipliers and a power of 10, starting at 0. * $step_size = $multiplier * pow(10, $exponent); * Assuming $multipliers = array(1, 2, 5) this would give us... * 1, 2, 5, 10, 20, 50, 100, 200, 500, 1000, 2000, 5000,... * / $n = 0; $multipliers = array(1, 2, 5); $num_multipliers = count($multipliers); $exponent = floor($n / $num_multipliers); $multiplier = $multipliers[$n % $num_multipliers]; $step_size = $multiplier * pow(10, $exponent); $num_steps = ceil($ymax/$step_size); //keep testing until we have the right step_size... while ($num_steps >= $max_steps){ $n ++; $exponent = floor($n / $num_multipliers); $multiplier = $multipliers[$n % $num_multipliers]; $step_size = $multiplier * pow(10, $exponent); $num_steps = ceil($ymax/$step_size); } $yaxis = new y_axis(); $yaxis->set_range(0, $ymax, $step_size); */ } public function get_style():Object { return null; } // // may be called by the labels // public function set_y_max( m:Number ):void { this.style.max = m; } public function get_range():Range { return new Range( this.style.min, this.style.max, this.style.steps, this.style.offset ); } public function get_width():Number { return this.stroke + this.tick_length + this.labels.width; } public function die(): void { //this.offset = null; this.style = null; if (this.labels != null) this.labels.die(); this.labels = null; this.graphics.clear(); while ( this.numChildren > 0 ) this.removeChildAt(0); } private function get_steps(min:Number, max:Number, height:Number):Number { // try to avoid infinite loops... if ( this.style.steps == 0 ) this.style.steps = 1; if ( this.style.steps < 0 ) this.style.steps *= -1; // how many steps (grid lines) do we have? var s:Number = (max - min) / this.style.steps; if ( s > (height/2) ) { // either no steps are set, or they are wrong and // we have more grid lines than pixels to show them. // E.g: // max = 1,001,000 // min = 1,000 // s = 200,000 return (max - min) / 5; } return this.style.steps; } public function resize(label_pos:Number, sc:ScreenCoords):void { } protected function resize_helper(label_pos:Number, sc:ScreenCoords, right:Boolean):void { // Set opacity for the first line to 0 (otherwise it overlaps the x-axel line) // // Bug? Does this work on graphs with minus values? // var i2:Number = 0; var i:Number; var y:Number; var lbl:Object; var min:Number = Math.min(this.style.min, this.style.max); var max:Number = Math.max(this.style.min, this.style.max); if( !right ) this.labels.resize( label_pos, sc ); else this.labels.resize( sc.right + this.stroke + this.tick_length, sc ); if ( !this.style.visible ) return; this.graphics.clear(); this.graphics.lineStyle( 0, 0, 0 ); if ( this.style['grid-visible'] ) this.draw_grid_lines(this.style.steps, min, max, right, sc); var pos:Number; if (!right) pos = sc.left - this.stroke; else pos = sc.right; // Axis line: this.graphics.beginFill( this.colour, 1 ); this.graphics.drawRect( int(pos), // <-- pixel align sc.top, this.stroke, sc.height ); this.graphics.endFill(); // ticks.. var width:Number; if (this.user_ticks) { for each( lbl in this.user_labels ) { y = sc.get_y_from_val(lbl.y, right); if ( !right ) tick_pos = sc.left - this.stroke - this.tick_length; else tick_pos = sc.right + this.stroke; this.graphics.beginFill( this.colour, 1 ); this.graphics.drawRect( tick_pos, y - (this.stroke / 2), this.tick_length, this.stroke ); this.graphics.endFill(); } } else { for(i=min; i<=max; i+=this.style.steps) { // start at the bottom and work up: y = sc.get_y_from_val(i, right); var tick_pos:Number; if ( !right ) tick_pos = sc.left - this.stroke - this.tick_length; else tick_pos = sc.right + this.stroke; this.graphics.beginFill( this.colour, 1 ); this.graphics.drawRect( tick_pos, y - (this.stroke / 2), this.tick_length, this.stroke ); this.graphics.endFill(); } } } private function draw_grid_lines(steps:Number, min:Number, max:Number, right:Boolean, sc:ScreenCoords): void { var y:Number; var lbl:Object; // // draw GRID lines // if (this.user_ticks) { for each(lbl in this.user_labels ) { y = sc.get_y_from_val(lbl.y, right); this.graphics.beginFill(lbl["grid-colour"], 1); this.graphics.drawRect( sc.left, y, sc.width, 1 ); this.graphics.endFill(); } } else { // // hack: http://kb.adobe.com/selfservice/viewContent.do?externalId=tn_13989&sliceId=1 // max += 0.000004; for( var i:Number = min; i<=max; i+=steps ) { y = sc.get_y_from_val(i, right); this.graphics.beginFill( this.grid_colour, 1 ); this.graphics.drawRect( int(sc.left), int(y), // <-- make sure they are pixel aligned (2.5 - 3.5 == fuzzy lines) sc.width, 1 ); this.graphics.endFill(); } } } } }