[7849] | 1 | package {
|
---|
| 2 | import flash.geom.Point;
|
---|
| 3 | import charts.series.dots.Point;
|
---|
| 4 |
|
---|
| 5 | public class ScreenCoords extends ScreenCoordsBase
|
---|
| 6 | {
|
---|
| 7 | private var x_range:Range;
|
---|
| 8 | private var y_range:Range;
|
---|
| 9 | private var y_right_range:Range;
|
---|
| 10 |
|
---|
| 11 | // position of the zero line
|
---|
| 12 | //public var zero:Number=0;
|
---|
| 13 | //public var steps:Number=0;
|
---|
| 14 |
|
---|
| 15 | // tick_offset is set by 3D axis
|
---|
| 16 | public var tick_offset:Number;
|
---|
| 17 | private var x_offset:Boolean;
|
---|
| 18 | private var y_offset:Boolean;
|
---|
| 19 | private var bar_groups:Number;
|
---|
| 20 |
|
---|
| 21 |
|
---|
| 22 | public function ScreenCoords( top:Number, left:Number, right:Number, bottom:Number,
|
---|
| 23 | y_axis_range:Range,
|
---|
| 24 | y_axis_right_range:Range,
|
---|
| 25 | x_axis_range:Range,
|
---|
| 26 | x_left_label_width:Number, x_right_label_width:Number,
|
---|
| 27 | three_d:Boolean )
|
---|
| 28 | {
|
---|
| 29 | super( top, left, right, bottom );
|
---|
| 30 |
|
---|
| 31 | var tmp_left:Number = left;
|
---|
| 32 |
|
---|
| 33 | this.x_range = x_axis_range;
|
---|
| 34 | this.y_range = y_axis_range;
|
---|
| 35 | this.y_right_range = y_axis_right_range;
|
---|
| 36 |
|
---|
| 37 | // tr.ace( '-----' );
|
---|
| 38 | // tr.ace( this.x_range.count() );
|
---|
| 39 | // tr.ace( this.y_range.count() );
|
---|
| 40 |
|
---|
| 41 |
|
---|
| 42 | if( x_range ) {
|
---|
| 43 | right = this.jiggle( left, right, x_right_label_width, x_axis_range.count() );
|
---|
| 44 | tmp_left = this.shrink_left( left, right, x_left_label_width, x_axis_range.count() );
|
---|
| 45 | }
|
---|
| 46 |
|
---|
| 47 | this.top = top;
|
---|
| 48 | this.left = Math.max(left, tmp_left);
|
---|
| 49 |
|
---|
| 50 | // round this down to the nearest int:
|
---|
| 51 | this.right = Math.floor( right );
|
---|
| 52 | this.bottom = bottom;
|
---|
| 53 | this.width = this.right-this.left;
|
---|
| 54 | this.height = bottom-top;
|
---|
| 55 |
|
---|
| 56 | if( three_d )
|
---|
| 57 | {
|
---|
| 58 | // tell the box object that the
|
---|
| 59 | // X axis labels need to be offset
|
---|
| 60 | this.tick_offset = 12;
|
---|
| 61 | }
|
---|
| 62 | else
|
---|
| 63 | this.tick_offset = 0;
|
---|
| 64 |
|
---|
| 65 | //
|
---|
| 66 | // x_offset:
|
---|
| 67 | //
|
---|
| 68 | // False True
|
---|
| 69 | //
|
---|
| 70 | // | |
|
---|
| 71 | // | |
|
---|
| 72 | // | |
|
---|
| 73 | // +--+--+--+ |-+--+--+--+-+
|
---|
| 74 | // 0 1 2 3 0 1 2 3
|
---|
| 75 | //
|
---|
| 76 |
|
---|
| 77 | // PIE charts don't have these:
|
---|
| 78 | if( x_axis_range ) {
|
---|
| 79 | this.x_offset = x_axis_range.offset;
|
---|
| 80 | }
|
---|
| 81 | if( y_axis_range ) {
|
---|
| 82 | // tr.aces( 'YYYY', y_axis_range.offset );
|
---|
| 83 | this.y_offset = y_axis_range.offset;
|
---|
| 84 | }
|
---|
| 85 |
|
---|
| 86 | this.bar_groups = 1;
|
---|
| 87 | }
|
---|
| 88 |
|
---|
| 89 | //
|
---|
| 90 | // if the last X label is wider than the chart area, the last few letters will
|
---|
| 91 | // be outside the drawing area. So we make the chart width smaller so the label
|
---|
| 92 | // will fit into the screen.
|
---|
| 93 | //
|
---|
| 94 | //DZ: this implementation chops off the last label on scatter charts because it
|
---|
| 95 | // assumes the label is centered on the last "item" (like a bar) instead of
|
---|
| 96 | // at the max edge of the plot.
|
---|
| 97 | public function jiggle_original( left:Number, right:Number, x_label_width:Number, count:Number ): Number {
|
---|
| 98 | var r:Number = 0;
|
---|
| 99 |
|
---|
| 100 | if( x_label_width != 0 )
|
---|
| 101 | {
|
---|
| 102 | var item_width:Number = (right-left) / count;
|
---|
| 103 | r = right - (item_width / 2);
|
---|
| 104 | var new_right:Number = right;
|
---|
| 105 |
|
---|
| 106 | // while the right most X label is off the edge of the
|
---|
| 107 | // Stage, move the box.right - 1
|
---|
| 108 | while( r+(x_label_width/2) > right )
|
---|
| 109 | {
|
---|
| 110 | new_right -= 1;
|
---|
| 111 | // changing the right also changes the item_width:
|
---|
| 112 | item_width = (new_right-left) / count;
|
---|
| 113 | r = new_right-(item_width/2);
|
---|
| 114 | }
|
---|
| 115 | right = new_right;
|
---|
| 116 | }
|
---|
| 117 | return right;
|
---|
| 118 | }
|
---|
| 119 |
|
---|
| 120 | //DZ: this implementation probably add white space on the right side of a
|
---|
| 121 | // non-scatter type plot because it assumes that the label is centered at
|
---|
| 122 | // the max edge of the plot instead of centered on the last "item"
|
---|
| 123 | // (like a bar)
|
---|
| 124 | public function jiggle( left:Number, right:Number, x_label_width:Number, count:Number ): Number {
|
---|
| 125 | return right - (x_label_width / 2);
|
---|
| 126 | }
|
---|
| 127 |
|
---|
| 128 | //
|
---|
| 129 | // if the left label is truncated, shrink the box until
|
---|
| 130 | // it fits onto the screen
|
---|
| 131 | //
|
---|
| 132 | public function shrink_left( left:Number, right:Number, x_label_width:Number, count:Number ): Number {
|
---|
| 133 | var pos:Number = 0;
|
---|
| 134 |
|
---|
| 135 | if( x_label_width != 0 )
|
---|
| 136 | {
|
---|
| 137 | var item_width:Number = (right-left) / count;
|
---|
| 138 | pos = left+(item_width/2);
|
---|
| 139 | var new_left:Number = left;
|
---|
| 140 |
|
---|
| 141 | // while the left most label is hanging off the Stage
|
---|
| 142 | // move the box.left in one pixel:
|
---|
| 143 | while( pos-(x_label_width/2) < 0 )
|
---|
| 144 | {
|
---|
| 145 | new_left += 1;
|
---|
| 146 | // changing the left also changes the item_width:
|
---|
| 147 | item_width = (right-new_left) / count;
|
---|
| 148 | pos = new_left+(item_width/2);
|
---|
| 149 | }
|
---|
| 150 | left = new_left;
|
---|
| 151 | }
|
---|
| 152 |
|
---|
| 153 | return left;
|
---|
| 154 |
|
---|
| 155 | }
|
---|
| 156 |
|
---|
| 157 | //
|
---|
| 158 | // the bottom point of a bar:
|
---|
| 159 | // min=-100 and max=100, use b.zero
|
---|
| 160 | // min = 10 and max = 20, use b.bottom
|
---|
| 161 | //
|
---|
| 162 | public override function get_y_bottom( right_axis:Boolean = false ):Number
|
---|
| 163 | {
|
---|
| 164 | //
|
---|
| 165 | // may have min=10, max=20, or
|
---|
| 166 | // min = 20, max = -20 (upside down chart)
|
---|
| 167 | //
|
---|
| 168 | var r:Range = right_axis ? this.y_right_range : this.y_range;
|
---|
| 169 |
|
---|
| 170 | var min:Number = r.min;
|
---|
| 171 | var max:Number = r.max;
|
---|
| 172 | min = Math.min( min, max );
|
---|
| 173 |
|
---|
| 174 | return this.get_y_from_val( Math.max(0,min), right_axis );
|
---|
| 175 | }
|
---|
| 176 |
|
---|
| 177 | // takes a value and returns the screen Y location
|
---|
| 178 | public function getY_old( i:Number, right_axis:Boolean ):Number
|
---|
| 179 | {
|
---|
| 180 | var r:Range = right_axis ? this.y_right_range : this.y_range;
|
---|
| 181 |
|
---|
| 182 | var steps:Number = this.height / (r.count());// ( right_axis ));
|
---|
| 183 |
|
---|
| 184 | // find Y pos for value=zero
|
---|
| 185 | var y:Number = this.bottom-(steps*(r.min*-1));
|
---|
| 186 |
|
---|
| 187 | // move up (-Y) to our point (don't forget that y_min will shift it down)
|
---|
| 188 | y -= i*steps;
|
---|
| 189 | return y;
|
---|
| 190 | }
|
---|
| 191 |
|
---|
| 192 | //
|
---|
| 193 | // takes a value and returns the screen Y location
|
---|
| 194 | // what is the Y range?
|
---|
| 195 | //
|
---|
| 196 | // Horizontal bar charts are offset. Note:
|
---|
| 197 | // step = 1
|
---|
| 198 | // and step/2 is offset at the bottom and top
|
---|
| 199 | // so we add 1*step so we can calculate:
|
---|
| 200 | //
|
---|
| 201 | // offset = true
|
---|
| 202 | //
|
---|
| 203 | // |
|
---|
| 204 | // X -|==========
|
---|
| 205 | // |
|
---|
| 206 | // Y -|===
|
---|
| 207 | // |
|
---|
| 208 | // Z -|========
|
---|
| 209 | // +--+--+--+--+--+--
|
---|
| 210 | //
|
---|
| 211 | // offset = false
|
---|
| 212 | //
|
---|
| 213 | // 2 -|
|
---|
| 214 | // |
|
---|
| 215 | // 1 -| 0--0--0--0--0
|
---|
| 216 | // |
|
---|
| 217 | // 0 -+--+--+--+--+--+--
|
---|
| 218 | //
|
---|
| 219 | public override function get_y_from_val( i:Number, right_axis:Boolean = false ):Number {
|
---|
| 220 |
|
---|
| 221 | var r:Range = right_axis ? this.y_right_range : this.y_range;
|
---|
| 222 |
|
---|
| 223 | var steps:Number = this.height / r.count();
|
---|
| 224 |
|
---|
| 225 | // tr.ace( 'off' );
|
---|
| 226 | // tr.ace( this.y_offset.offset );
|
---|
| 227 | // tr.ace( count );
|
---|
| 228 |
|
---|
| 229 | var tmp:Number = 0;
|
---|
| 230 | if( this.y_offset )
|
---|
| 231 | tmp = (steps / 2);
|
---|
| 232 |
|
---|
| 233 | // move up (-Y) to our point (don't forget that y_min will shift it down)
|
---|
| 234 | return this.bottom-tmp-(r.min-i)*steps*-1;
|
---|
| 235 | }
|
---|
| 236 |
|
---|
| 237 | public override function get_get_x_from_pos_and_y_from_val( index:Number, y:Number, right_axis:Boolean = false ):flash.geom.Point {
|
---|
| 238 |
|
---|
| 239 | return new flash.geom.Point(
|
---|
| 240 | this.get_x_from_pos( index ),
|
---|
| 241 | this.get_y_from_val( y, right_axis ) );
|
---|
| 242 | }
|
---|
| 243 |
|
---|
| 244 | public function width_():Number
|
---|
| 245 | {
|
---|
| 246 | return this.right-this.left_();
|
---|
| 247 | }
|
---|
| 248 |
|
---|
| 249 | private function left_():Number
|
---|
| 250 | {
|
---|
| 251 | var padding_left:Number = this.tick_offset;
|
---|
| 252 | return this.left+padding_left;
|
---|
| 253 | }
|
---|
| 254 |
|
---|
| 255 | //
|
---|
| 256 | // Scatter and Horizontal Bar charts use this:
|
---|
| 257 | //
|
---|
| 258 | // get the x position by value
|
---|
| 259 | // (e.g. what is the x position for -5 ?)
|
---|
| 260 | //
|
---|
| 261 | public override function get_x_from_val( i:Number ):Number {
|
---|
| 262 | // Patch from DZ:
|
---|
| 263 | var rev:Boolean = this.x_range.min > this.x_range.max;
|
---|
| 264 | var count:Number = this.x_range.count();
|
---|
| 265 | count += (rev && this.x_range.offset) ? -2 : 0;
|
---|
| 266 | var item_width:Number = this.width_() / count;
|
---|
| 267 | // end DZ
|
---|
| 268 |
|
---|
| 269 |
|
---|
| 270 | var pos:Number = i-this.x_range.min;
|
---|
| 271 |
|
---|
| 272 | var tmp:Number = 0;
|
---|
| 273 | if( this.x_offset )
|
---|
| 274 | tmp = Math.abs(item_width/2);
|
---|
| 275 |
|
---|
| 276 | return this.left_()+tmp+(pos*item_width);
|
---|
| 277 | }
|
---|
| 278 |
|
---|
| 279 | //
|
---|
| 280 | // get the x location of the n'th item
|
---|
| 281 | //
|
---|
| 282 | public override function get_x_from_pos( i:Number ):Number {
|
---|
| 283 | // DZ:
|
---|
| 284 | // var item_width:Number = Math.abs(this.width_() / this.x_range.count());
|
---|
| 285 | var rev:Boolean = this.x_range.min > this.x_range.max;
|
---|
| 286 | var count:Number = this.x_range.count();
|
---|
| 287 | count += (rev && this.x_range.offset) ? -2 : 0;
|
---|
| 288 | var item_width:Number = Math.abs(this.width_() / count);
|
---|
| 289 |
|
---|
| 290 | var tmp:Number = 0;
|
---|
| 291 | if( this.x_offset )
|
---|
| 292 | tmp = (item_width/2);
|
---|
| 293 |
|
---|
| 294 | return this.left_()+tmp+(i*item_width);
|
---|
| 295 | }
|
---|
| 296 |
|
---|
| 297 | //
|
---|
| 298 | // get the position of the n'th X axis tick
|
---|
| 299 | //
|
---|
| 300 | public function get_x_tick_pos( i:Number ):Number
|
---|
| 301 | {
|
---|
| 302 | return this.get_x_from_pos(i) - this.tick_offset;
|
---|
| 303 | }
|
---|
| 304 |
|
---|
| 305 |
|
---|
| 306 | //
|
---|
| 307 | // make a point object, using the absolute values (e.g. -5,-5 )
|
---|
| 308 | /*
|
---|
| 309 | public function make_point_2( x:Number, y:Number, right_axis:Boolean ):charts.Elements.Point
|
---|
| 310 | {
|
---|
| 311 | return new charts.Elements.Point(
|
---|
| 312 | this.get_x_from_val( x ),
|
---|
| 313 | this.get_y_from_val( y, right_axis )
|
---|
| 314 |
|
---|
| 315 | // whats this for?
|
---|
| 316 | //,y
|
---|
| 317 | );
|
---|
| 318 | }*/
|
---|
| 319 |
|
---|
| 320 | public function set_bar_groups( n:Number ): void {
|
---|
| 321 | this.bar_groups = n;
|
---|
| 322 | }
|
---|
| 323 |
|
---|
| 324 | //
|
---|
| 325 | // index: the n'th bar from the left
|
---|
| 326 | //
|
---|
| 327 | public function get_bar_coords( index:Number, group:Number ):Object {
|
---|
| 328 | var item_width:Number = this.width_() / this.x_range.count();
|
---|
| 329 |
|
---|
| 330 | // the bar(s) have gaps between them:
|
---|
| 331 | var bar_set_width:Number = item_width*0.8;
|
---|
| 332 |
|
---|
| 333 | // get the margin between sets of bars:
|
---|
| 334 | var tmp:Number = 0;
|
---|
| 335 | if( this.x_offset )
|
---|
| 336 | tmp = item_width;
|
---|
| 337 |
|
---|
| 338 | // 1 bar == 100% wide, 2 bars = 50% wide each
|
---|
| 339 | var bar_width:Number = bar_set_width / this.bar_groups;
|
---|
| 340 | //bar_width -= 0.001; // <-- hack so bars don't quite touch
|
---|
| 341 |
|
---|
| 342 | var bar_left:Number = this.left_()+((tmp-bar_set_width)/2);
|
---|
| 343 | var left:Number = bar_left+(index*item_width);
|
---|
| 344 | left += bar_width * group;
|
---|
| 345 |
|
---|
| 346 | return { x:left, width:bar_width };
|
---|
| 347 | }
|
---|
| 348 |
|
---|
| 349 | public function get_horiz_bar_coords( index:Number, group:Number ):Object {
|
---|
| 350 |
|
---|
| 351 | // split the height into equal heights for each bar
|
---|
| 352 | var bar_width:Number = this.height / this.y_range.count();
|
---|
| 353 |
|
---|
| 354 | // the bar(s) have gaps between them:
|
---|
| 355 | var bar_set_width:Number = bar_width*0.8;
|
---|
| 356 |
|
---|
| 357 | // 1 bar == 100% wide, 2 bars = 50% wide each
|
---|
| 358 | var group_width:Number = bar_set_width / this.bar_groups;
|
---|
| 359 |
|
---|
| 360 | var bar_top:Number = this.top+((bar_width-bar_set_width)/2);
|
---|
| 361 | var top:Number = bar_top+(index*bar_width);
|
---|
| 362 | top += group_width * group;
|
---|
| 363 |
|
---|
| 364 | return { y:top, width:group_width };
|
---|
| 365 | }
|
---|
| 366 |
|
---|
| 367 |
|
---|
| 368 | public function makePointHLC( x:Number, high:Number, close:Number, low:Number, right_axis:Boolean, group:Number, group_count:Number )
|
---|
| 369 | :PointHLC {
|
---|
| 370 |
|
---|
| 371 | var item_width:Number = this.width_() / this.x_range.count();
|
---|
| 372 | // the bar(s) have gaps between them:
|
---|
| 373 | var bar_set_width:Number = item_width*1;
|
---|
| 374 |
|
---|
| 375 | // get the margin between sets of bars:
|
---|
| 376 | var bar_left:Number = this.left_()+((item_width-bar_set_width)/2);
|
---|
| 377 | // 1 bar == 100% wide, 2 bars = 50% wide each
|
---|
| 378 | var bar_width:Number = bar_set_width/group_count;
|
---|
| 379 |
|
---|
| 380 | var left:Number = bar_left+(x*item_width);
|
---|
| 381 | left += bar_width*group;
|
---|
| 382 |
|
---|
| 383 | return new PointHLC(
|
---|
| 384 | left,
|
---|
| 385 | this.get_y_from_val( high, right_axis ),
|
---|
| 386 | this.get_y_from_val( close, right_axis ),
|
---|
| 387 | this.get_y_from_val( low, right_axis ),
|
---|
| 388 | high,
|
---|
| 389 | bar_width
|
---|
| 390 | // ,close
|
---|
| 391 | );
|
---|
| 392 |
|
---|
| 393 | }
|
---|
| 394 | }
|
---|
| 395 | }
|
---|