1#========================================================================== 2# Module: GD::Graph::axestype3d 3# 4# Copyright (C) 1999,2001 Wadsack-Allen. All Rights Reserved. 5# 6# Based on axestype.pm,v 1.21 2000/04/15 08:59:36 mgjv 7# Copyright (c) 1995-1998 Martien Verbruggen 8# 9#-------------------------------------------------------------------------- 10# Date Modification Author 11# ------------------------------------------------------------------------- 12# 1999SEP18 Created 3D axestype base class (this JW 13# module) changes noted in comments. 14# 1999OCT15 Fixed to include all GIFgraph functions JW 15# necessary for PNG support. 16# 2000JAN19 Converted to GD::Graph sublcass JW 17# 2000FEB21 Fixed bug in y-labels' height JW 18# 2000APR18 Updated for compatibility with GD::Graph 1.30 JW 19# 2000AUG21 Added 3d shading JW 20# 2000SEP04 Allowed box_clr without box axis JW 21# 06Dec2001 Fixed bug in rendering of x tick when x_tick_number is set JW 22#========================================================================== 23# TODO 24# * Modify to use true 3-d extrusions at any theta and phi 25#========================================================================== 26package GD::Graph::axestype3d; 27 28use strict; 29 30use GD::Graph; 31use GD::Graph::axestype; 32use GD::Graph::utils qw(:all); 33use GD::Graph::colour qw(:colours); 34use Carp; 35 36@GD::Graph::axestype3d::ISA = qw(GD::Graph::axestype); 37$GD::Graph::axestype3d::VERSION = '0.63'; 38 39# Commented inheritance from GD::Graph::axestype unless otherwise noted. 40 41use constant PI => 4 * atan2(1,1); 42 43my %Defaults = ( 44 depth_3d => 20, 45 '3d_shading' => 1, 46 47 # the rest are inherited 48); 49 50# Inherit _has_default 51 52 53# Can't inherit initialise, because %Defaults is referenced file- 54# specific, not class specific. 55sub initialise 56{ 57 my $self = shift; 58 59 my $rc = $self->SUPER::initialise(); 60 61 while( my($key, $val) = each %Defaults ) { 62 $self->{$key} = $val 63 } # end while 64 65 return $rc; 66} # end initialise 67 68# PUBLIC 69# Inherit plot 70# Inherit set 71# Inherit setup_text 72# Inherit set_x_label_font 73# Inherit set_y_label_font 74# Inherit set_x_axis_font 75# Inherit set_y_axis_font 76# Inherit set_legend 77# Inherit set_legend_font 78 79 80 81# ---------------------------------------------------------- 82# Sub: init_graph 83# 84# Args: (None) 85# 86# Description: 87# Override GD::Graph::init_graph to add 3d shading colors, 88# if requested 89# 90# [From GD::Graph] 91# Initialise the graph output canvas, setting colours (and 92# getting back index numbers for them) setting the graph to 93# transparent, and interlaced, putting a logo (if defined) 94# on there. 95# ---------------------------------------------------------- 96# Date Modification Author 97# ---------------------------------------------------------- 98# 20Aug2000 Added to support 3d graph extensions JW 99# ---------------------------------------------------------- 100sub init_graph { 101 my $self = shift; 102 103 # Sets up the canvas and color palette 104 $self->SUPER::init_graph( @_ ); 105 106 # Now create highlights and showdows for each color 107 # in the palette 108 if( $self->{'3d_shading'} ) { 109 $self->{'3d_highlights'} = []; 110 $self->{'3d_shadows'} = []; 111 $self->{'3d_highlights'}[$self->{bgci}] = $self->set_clr( $self->_brighten( _rgb($self->{bgclr}) ) ); 112 $self->{'3d_shadows'}[$self->{bgci}] = $self->set_clr( $self->_darken( _rgb($self->{bgclr}) ) ); 113 114 $self->{'3d_highlights'}[$self->{fgci}] = $self->set_clr( $self->_brighten( _rgb($self->{fgclr}) ) ); 115 $self->{'3d_shadows'}[$self->{fgci}] = $self->set_clr( $self->_darken( _rgb($self->{fgclr}) ) ); 116 117 $self->{'3d_highlights'}[$self->{tci}] = $self->set_clr( $self->_brighten( _rgb($self->{textclr}) ) ); 118 $self->{'3d_shadows'}[$self->{tci}] = $self->set_clr( $self->_darken( _rgb($self->{textclr}) ) ); 119 120 $self->{'3d_highlights'}[$self->{lci}] = $self->set_clr( $self->_brighten( _rgb($self->{labelclr}) ) ); 121 $self->{'3d_shadows'}[$self->{lci}] = $self->set_clr( $self->_darken( _rgb($self->{labelclr}) ) ); 122 123 $self->{'3d_highlights'}[$self->{alci}] = $self->set_clr( $self->_brighten( _rgb($self->{axislabelclr}) ) ); 124 $self->{'3d_shadows'}[$self->{alci}] = $self->set_clr( $self->_darken( _rgb($self->{axislabelclr}) ) ); 125 126 $self->{'3d_highlights'}[$self->{acci}] = $self->set_clr( $self->_brighten( _rgb($self->{accentclr}) ) ); 127 $self->{'3d_shadows'}[$self->{acci}] = $self->set_clr( $self->_darken( _rgb($self->{accentclr}) ) ); 128 129 $self->{'3d_highlights'}[$self->{valuesci}] = $self->set_clr( $self->_brighten( _rgb($self->{valuesclr}) ) ); 130 $self->{'3d_shadows'}[$self->{valuesci}] = $self->set_clr( $self->_darken( _rgb($self->{valuesclr}) ) ); 131 132 $self->{'3d_highlights'}[$self->{legendci}] = $self->set_clr( $self->_brighten( _rgb($self->{legendclr}) ) ); 133 $self->{'3d_shadows'}[$self->{legendci}] = $self->set_clr( $self->_darken( _rgb($self->{legendclr}) ) ); 134 135 if( $self->{boxclr} ) { 136 $self->{'3d_highlights'}[$self->{boxci}] = $self->set_clr( $self->_brighten( _rgb($self->{boxclr}) ) ); 137 $self->{'3d_shadows'}[$self->{boxci}] = $self->set_clr( $self->_darken( _rgb($self->{boxclr}) ) ); 138 } # end if 139 } # end if 140 141 return $self; 142} # end init_graph 143 144 145# PRIVATE 146 147# ---------------------------------------------------------- 148# Sub: _brighten 149# 150# Args: $r, $g, $b 151# $r, $g, $b The Red, Green, and Blue components of a color 152# 153# Description: Brightens the color by adding white 154# ---------------------------------------------------------- 155# Date Modification Author 156# ---------------------------------------------------------- 157# 21AUG2000 Created to build 3d highlights table JW 158# ---------------------------------------------------------- 159sub _brighten { 160 my $self = shift; 161 my( $r, $g, $b ) = @_; 162 my $p = ($r + $g + $b) / 70; 163 $p = 3 if $p < 3; 164 my $f = _max( $r / $p, _max( $g / $p, $b / $p ) ); 165 $r = _min( 255, int( $r + $f ) ); 166 $g = _min( 255, int( $g + $f ) ); 167 $b = _min( 255, int( $b + $f ) ); 168 return( $r, $g, $b ); 169} # end _brighten 170 171# ---------------------------------------------------------- 172# Sub: _darken 173# 174# Args: $r, $g, $b 175# $r, $g, $b The Red, Green, and Blue components of a color 176# 177# Description: Darkens the color by adding black 178# ---------------------------------------------------------- 179# Date Modification Author 180# ---------------------------------------------------------- 181# 21AUG2000 Created to build 3d shadows table JW 182# ---------------------------------------------------------- 183sub _darken { 184 my $self = shift; 185 my( $r, $g, $b ) = @_; 186 my $p = ($r + $g + $b) / 70; 187 $p = 3 if $p < 3; 188 my $f = _max( $r / $p, _max( $g / $p, $b / $p) ); 189 $r = _max( 0, int( $r - $f ) ); 190 $g = _max( 0, int( $g - $f ) ); 191 $b = _max( 0, int( $b - $f ) ); 192 return( $r, $g, $b ); 193} # end _darken 194 195 196# inherit check_data from GD::Graph 197 198# [JAW] Setup boundaries as parent, the adjust for 3d extrusion 199sub _setup_boundaries 200{ 201 my $self = shift; 202 203 $self->SUPER::_setup_boundaries(); 204 205 # adjust for top of 3-d extrusion 206 $self->{top} += $self->{depth_3d}; 207 208 return $self->_set_error('Vertical size too small') 209 if $self->{bottom} <= $self->{top}; 210 211 # adjust for right of 3-d extrusion 212 $self->{right} -= $self->{depth_3d}; 213 214 return $self->_set_error('Horizontal size too small') 215 if $self->{right} <= $self->{left}; 216 217 return $self; 218} # end _setup_boundaries 219 220# [JAW] Determine 3d-extrusion depth, then call parent 221sub setup_coords 222{ 223 my $self = shift; 224 225 # Calculate the 3d-depth of the graph 226 # Note this sets a minimum depth of ~20 pixels 227# if (!defined $self->{x_tick_number}) { 228 my $depth = _max( $self->{bar_depth}, $self->{line_depth} ); 229 if( $self->{overwrite} == 1 ) { 230 $depth *= $self->{_data}->num_sets(); 231 } # end if 232 $self->{depth_3d} = _max( $depth, $self->{depth_3d} ); 233# } # end if 234 235 $self->SUPER::setup_coords(); 236 237 return $self; 238} # end setup_coords 239 240# Inherit create_y_labels 241# Inherit get_x_axis_label_height 242# Inherit create_x_labels 243# inherit open_graph from GD::Graph 244# Inherit draw_text 245 246# [JAW] Draws entire bounding cube for 3-d extrusion 247sub draw_axes 248{ 249 my $s = shift; 250 my $g = $s->{graph}; 251 252 my ($l, $r, $b, $t) = 253 ( $s->{left}, $s->{right}, $s->{bottom}, $s->{top} ); 254 my $depth = $s->{depth_3d}; 255 256 if ( $s->{box_axis} ) { 257 # -- Draw a bounding box 258 if( $s->{boxci} ) { 259 # -- Fill the box with color 260 # Back box 261 $g->filledRectangle($l+$depth+1, $t-$depth+1, $r+$depth-1, $b-$depth-1, $s->{boxci}); 262 263 # Left side 264 my $poly = new GD::Polygon; 265 $poly->addPt( $l, $t ); 266 $poly->addPt( $l + $depth, $t - $depth ); 267 $poly->addPt( $l + $depth, $b - $depth ); 268 $poly->addPt( $l, $b ); 269 if( $s->{'3d_shading'} ) { 270 $g->filledPolygon( $poly, $s->{'3d_shadows'}[$s->{boxci}] ); 271 } else { 272 $g->filledPolygon( $poly, $s->{boxci} ); 273 } # end if 274 275 # Bottom 276 $poly = new GD::Polygon; 277 $poly->addPt( $l, $b ); 278 $poly->addPt( $l + $depth, $b - $depth ); 279 $poly->addPt( $r + $depth, $b - $depth ); 280 $poly->addPt( $r, $b ); 281 if( $s->{'3d_shading'} ) { 282 $g->filledPolygon( $poly, $s->{'3d_highlights'}[$s->{boxci}] ); 283 } else { 284 $g->filledPolygon( $poly, $s->{boxci} ); 285 } # end if 286 } # end if 287 288 # -- Draw the box frame 289 290 # Back box 291 $g->rectangle($l+$depth, $t-$depth, $r+$depth, $b-$depth, $s->{fgci}); 292 293 # Connecting frame 294 $g->line($l, $t, $l + $depth, $t - $depth, $s->{fgci}); 295 $g->line($r, $t, $r + $depth, $t - $depth, $s->{fgci}); 296 $g->line($l, $b, $l + $depth, $b - $depth, $s->{fgci}); 297 $g->line($r, $b, $r + $depth, $b - $depth, $s->{fgci}); 298 299 # Front box 300 $g->rectangle($l, $t, $r, $b, $s->{fgci}); 301 302 } else { 303 if( $s->{boxci} ) { 304 # -- Fill the background box with color 305 # Back box 306 $g->filledRectangle($l+$depth+1, $t-$depth+1, $r+$depth-1, $b-$depth-1, $s->{boxci}); 307 308 # Left side 309 my $poly = new GD::Polygon; 310 $poly->addPt( $l, $t ); 311 $poly->addPt( $l + $depth, $t - $depth ); 312 $poly->addPt( $l + $depth, $b - $depth ); 313 $poly->addPt( $l, $b ); 314 if( $s->{'3d_shading'} ) { 315 $g->filledPolygon( $poly, $s->{'3d_shadows'}[$s->{boxci}] ); 316 } else { 317 $g->filledPolygon( $poly, $s->{boxci} ); 318 } # end if 319 320 # Bottom 321 $poly = new GD::Polygon; 322 $poly->addPt( $l, $b ); 323 $poly->addPt( $l + $depth, $b - $depth ); 324 $poly->addPt( $r + $depth, $b - $depth ); 325 $poly->addPt( $r, $b ); 326 if( $s->{'3d_shading'} ) { 327 $g->filledPolygon( $poly, $s->{'3d_highlights'}[$s->{boxci}] ); 328 } else { 329 $g->filledPolygon( $poly, $s->{boxci} ); 330 } # end if 331 } # end if 332 # -- Draw the frame only for back & sides 333 334 # Back box 335 $g->rectangle($l + $depth, $t - $depth, $r + $depth, $b - $depth, $s->{fgci}); 336 337 # Y axis 338 my $poly = new GD::Polygon; 339 $poly->addPt( $l, $t ); 340 $poly->addPt( $l, $b ); 341 $poly->addPt( $l + $depth, $b - $depth ); 342 $poly->addPt( $l + $depth, $t - $depth ); 343 $g->polygon( $poly, $s->{fgci} ); 344 345 # X axis 346 if( !$s->{zero_axis_only} ) { 347 $poly = new GD::Polygon; 348 $poly->addPt( $l, $b ); 349 $poly->addPt( $r, $b ); 350 $poly->addPt( $r + $depth, $b - $depth ); 351 $poly->addPt( $l + $depth, $b - $depth ); 352 $g->polygon( $poly, $s->{fgci} ); 353 } # end if 354 355 # Second Y axis 356 if( $s->{two_axes} ){ 357 $poly = new GD::Polygon; 358 $poly->addPt( $r, $b ); 359 $poly->addPt( $r, $t ); 360 $poly->addPt( $r + $depth, $t - $depth ); 361 $poly->addPt( $r + $depth, $b - $depth ); 362 $g->polygon( $poly, $s->{fgci} ); 363 } # end if 364 } # end if 365 366 # Zero axis 367 if ($s->{zero_axis} or $s->{zero_axis_only}) { 368 my ($x, $y) = $s->val_to_pixel(0, 0, 1); 369 my $poly = new GD::Polygon; 370 $poly->addPt( $l, $y ); 371 $poly->addPt( $r, $y ); 372 $poly->addPt( $r + $depth, $y - $depth ); 373 $poly->addPt( $l + $depth, $y - $depth); 374 $g->polygon( $poly, $s->{fgci} ); 375 } # end if 376 377} # end draw_axes 378 379# [JAW] Draws ticks and values for y axes in 3d extrusion 380# Modified from MVERB source 381sub draw_y_ticks 382{ 383 my $self = shift; 384 385 for my $t (0 .. $self->{y_tick_number}) 386 { 387 for my $a (1 .. ($self->{two_axes} + 1)) 388 { 389 my $value = $self->{y_values}[$a][$t]; 390 my $label = $self->{y_labels}[$a][$t]; 391 392 my ($x, $y) = $self->val_to_pixel(0, $value, $a); 393 $x = ($a == 1) ? $self->{left} : $self->{right}; 394 395 # CONTRIB Jeremy Wadsack 396 # Draw on the back of the extrusion 397 $x += $self->{depth_3d}; 398 $y -= $self->{depth_3d}; 399 400 if ($self->{y_long_ticks}) 401 { 402 $self->{graph}->line( 403 $x, $y, 404 $x + $self->{right} - $self->{left}, $y, 405 $self->{fgci} 406 ) unless ($a-1); 407 # CONTRIB Jeremy Wadsack 408 # Draw conector ticks 409 $self->{graph}->line( $x - $self->{depth_3d}, 410 $y + $self->{depth_3d}, 411 $x, 412 $y, 413 $self->{fgci} 414 ) unless ($a-1); 415 } 416 else 417 { 418 $self->{graph}->line( 419 $x, $y, 420 $x + (3 - 2 * $a) * $self->{y_tick_length}, $y, 421 $self->{fgci} 422 ); 423 # CONTRIB Jeremy Wadsack 424 # Draw conector ticks 425 $self->{graph}->line( $x - $self->{depth_3d}, 426 $y + $self->{depth_3d}, 427 $x - $self->{depth_3d} + (3 - 2 * $a) * $self->{y_tick_length}, 428 $y + $self->{depth_3d} - (3 - 2 * $a) * $self->{y_tick_length}, 429 $self->{fgci} 430 ); 431 } 432 433 next 434 if $t % ($self->{y_label_skip}) || ! $self->{y_plot_values}; 435 436 $self->{gdta_y_axis}->set_text($label); 437 $self->{gdta_y_axis}->set_align('center', 438 $a == 1 ? 'right' : 'left'); 439 $x -= (3 - 2 * $a) * $self->{axis_space}; 440 441 # CONTRIB Jeremy Wadsack 442 # Subtract 3-d extrusion width from left axis label 443 # (it was added for ticks) 444 $x -= (2 - $a) * $self->{depth_3d}; 445 446 # CONTRIB Jeremy Wadsack 447 # Add 3-d extrusion height to label 448 # (it was subtracted for ticks) 449 $y += $self->{depth_3d}; 450 451 $self->{gdta_y_axis}->draw($x, $y); 452 453 } # end foreach 454 } # end foreach 455 456 return $self; 457 458} # end draw_y_ticks 459 460# [JAW] Darws ticks and values for x axes wih 3d extrusion 461# Modified from MVERB source 462sub draw_x_ticks 463{ 464 my $self = shift; 465 466 for (my $i = 0; $i < $self->{_data}->num_points; $i++) 467 { 468 my ($x, $y) = $self->val_to_pixel($i + 1, 0, 1); 469 470 $y = $self->{bottom} unless $self->{zero_axis_only}; 471 472 # CONTRIB Damon Brodie for x_tick_offset 473 next if (!$self->{x_all_ticks} and 474 ($i - $self->{x_tick_offset}) % $self->{x_label_skip} and 475 $i != $self->{_data}->num_points - 1 476 ); 477 478 # CONTRIB Jeremy Wadsack 479 # Draw on the back of the extrusion 480 $x += $self->{depth_3d}; 481 $y -= $self->{depth_3d}; 482 483 if ($self->{x_ticks}) 484 { 485 if ($self->{x_long_ticks}) 486 { 487 # CONTRIB Jeremy Wadsack 488 # Move up by 3d depth 489 $self->{graph}->line( $x, 490 $self->{bottom} - $self->{depth_3d}, 491 $x, 492 $self->{top} - $self->{depth_3d}, 493 $self->{fgci}); 494 # CONTRIB Jeremy Wadsack 495 # Draw conector ticks 496 $self->{graph}->line( $x - $self->{depth_3d}, 497 $y + $self->{depth_3d}, 498 $x, 499 $y, 500 $self->{fgci} 501 ); 502 } 503 else 504 { 505 $self->{graph}->line( $x, $y, $x, $y - $self->{x_tick_length}, $self->{fgci} ); 506 # CONTRIB Jeremy Wadsack 507 # Draw conector ticks 508 $self->{graph}->line( $x - $self->{depth_3d}, 509 $y + $self->{depth_3d}, 510 $x - $self->{depth_3d} + $self->{x_tick_length}, 511 $y + $self->{depth_3d} - $self->{x_tick_length}, 512 $self->{fgci} 513 ); 514 } 515 } 516 517 # CONTRIB Damon Brodie for x_tick_offset 518 next if 519 ($i - $self->{x_tick_offset}) % ($self->{x_label_skip}) and 520 $i != $self->{_data}->num_points - 1; 521 522 $self->{gdta_x_axis}->set_text($self->{_data}->get_x($i)); 523 524 # CONTRIB Jeremy Wadsack 525 # Subtract 3-d extrusion width from left label 526 # Add 3-d extrusion height to left label 527 # (they were changed for ticks) 528 $x -= $self->{depth_3d}; 529 $y += $self->{depth_3d}; 530 531 my $yt = $y + $self->{axis_space}; 532 533 if ($self->{x_labels_vertical}) 534 { 535 $self->{gdta_x_axis}->set_align('center', 'right'); 536 $self->{gdta_x_axis}->draw($x, $yt, PI/2); 537 } 538 else 539 { 540 $self->{gdta_x_axis}->set_align('top', 'center'); 541 $self->{gdta_x_axis}->draw($x, $yt); 542 } 543 544 } # end for 545 546 return $self; 547 548} # end draw_x_ticks 549 550 551# CONTRIB Scott Prahl 552# Assume x array contains equally spaced x-values 553# and generate an appropriate axis 554# 555#### 556# 'True' numerical X axis addition 557# From: Gary Deschaines 558# 559# These modification to draw_x_ticks_number pass x-tick values to the 560# val_to_pixel subroutine instead of x-tick indices when ture[sic] numerical 561# x-axis mode is detected. Also, x_tick_offset and x_label_skip are 562# processed differently when true numerical x-axis mode is detected to 563# allow labeled major x-tick marks and un-labeled minor x-tick marks. 564# 565# For example: 566# 567# x_tick_number => 14, 568# x_ticks => 1, 569# x_long_ticks => 1, 570# x_tick_length => -4, 571# x_min_value => 100, 572# x_max_value => 800, 573# x_tick_offset => 2, 574# x_label_skip => 2, 575# 576# 577# ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ 578# | | | | | | | | | | | | | 579# 1 -| | | | | | | | | | | | | 580# | | | | | | | | | | | | | 581# 0 _|_________|____|____|____|____|____|____|____|____|____|____|_________| 582# | | | | | | | | | | | 583# 200 300 400 500 600 700 584#### 585# [JAW] Added commented items for 3d rendering 586# Based on MVERB source 587sub draw_x_ticks_number 588{ 589 my $self = shift; 590 591 for my $i (0 .. $self->{x_tick_number}) 592 { 593 my ($value, $x, $y); 594 595 if (defined($self->{x_min_value}) && defined($self->{x_max_value})) 596 { 597 next if ($i - $self->{x_tick_offset}) < 0; 598 next if ($i + $self->{x_tick_offset}) > $self->{x_tick_number}; 599 $value = $self->{x_values}[$i]; 600 ($x, $y) = $self->val_to_pixel($value, 0, 1); 601 } 602 else 603 { 604 $value = ($self->{_data}->num_points - 1) 605 * ($self->{x_values}[$i] - $self->{true_x_min}) 606 / ($self->{true_x_max} - $self->{true_x_min}); 607 ($x, $y) = $self->val_to_pixel($value + 1, 0, 1); 608 } 609 610 $y = $self->{bottom} unless $self->{zero_axis_only}; 611 612 # Draw on the back of the extrusion 613 $x += $self->{depth_3d}; 614 $y -= $self->{depth_3d}; 615 616 if ($self->{x_ticks}) 617 { 618 if ($self->{x_long_ticks}) 619 { 620 # XXX This mod needs to be done everywhere ticks are 621 # drawn 622 if ( $self->{x_tick_length} >= 0 ) 623 { 624 # Move up by 3d depth 625 $self->{graph}->line( $x, 626 $self->{bottom} - $self->{depth_3d}, 627 $x, 628 $self->{top} - $self->{depth_3d}, 629 $self->{fgci}); 630 } 631 else 632 { 633 $self->{graph}->line( 634 $x, $self->{bottom} - $self->{x_tick_length}, 635 $x, $self->{top}, $self->{fgci}); 636 } 637 # CONTRIB Jeremy Wadsack 638 # Draw conector ticks 639 $self->{graph}->line( $x - $self->{depth_3d}, 640 $y + $self->{depth_3d}, 641 $x, 642 $y, 643 $self->{fgci} 644 ); 645 } 646 else 647 { 648 $self->{graph}->line($x, $y, 649 $x, $y - $self->{x_tick_length}, $self->{fgci} ); 650 # CONTRIB Jeremy Wadsack 651 # Draw conector ticks 652 $self->{graph}->line( $x - $self->{depth_3d}, 653 $y + $self->{depth_3d}, 654 $x, - $self->{depth_3d} + $self->{tick_length}, 655 $y, + $self->{depth_3d} - $self->{tick_length}, 656 $self->{fgci} 657 ); 658 } # end if -- x_long_ticks 659 } # end if -- x_ticks 660 661 # If we have to skip labels, we'll do it here. 662 # Make sure to always draw the last one. 663 next if $i % $self->{x_label_skip} && $i != $self->{x_tick_number}; 664 665 $self->{gdta_x_axis}->set_text($self->{x_labels}[$i]); 666 667 # CONTRIB Jeremy Wadsack 668 # Subtract 3-d extrusion width from left label 669 # Add 3-d extrusion height to left label 670 # (they were changed for ticks) 671 $x -= $self->{depth_3d}; 672 $y += $self->{depth_3d}; 673 674 if ($self->{x_labels_vertical}) 675 { 676 $self->{gdta_x_axis}->set_align('center', 'right'); 677 my $yt = $y + $self->{text_space}/2; 678 $self->{gdta_x_axis}->draw($x, $yt, PI/2); 679 } 680 else 681 { 682 $self->{gdta_x_axis}->set_align('top', 'center'); 683 my $yt = $y + $self->{text_space}/2; 684 $self->{gdta_x_axis}->draw($x, $yt); 685 } # end if 686 } # end for 687 688 return $self; 689 690} # end draw_x_tick_number 691 692# Inherit draw_ticks 693# Inherit draw_data 694# Inherit draw_data_set 695# Inherit set_max_min 696# Inherit get_max_y 697# Inherit get_min_y 698# Inherit get_max_min_y_all 699# Inherit _get_bottom 700# Inherit val_to_pixel 701# Inherit setup_legend 702 703 704# [JW] Override draw_legend and reverse the drawing order 705# if cumulate is enabled so legend matches data on chart 706sub draw_legend 707{ 708 my $self = shift; 709 710 return unless defined $self->{legend}; 711 712 my $xl = $self->{lg_xs} + $self->{legend_spacing}; 713 my $y = $self->{lg_ys} + $self->{legend_spacing} - 1; 714 715 # If there's a frame, offset by the size and margin 716 $xl += $self->{legend_frame_margin} + $self->{legend_frame_size} if $self->{legend_frame_size}; 717 $y += $self->{legend_frame_margin} + $self->{legend_frame_size} if $self->{legend_frame_size}; 718 719 my $i = 0; 720 my $row = 1; 721 my $x = $xl; # start position of current element 722 my @legends = @{$self->{legend}}; 723 my $i_step = 1; 724 725 # If we are working in cumulate mode, then reverse the drawing order 726 if( $self->{cumulate} ) { 727 @legends = reverse @legends; 728 $i = scalar(@legends); 729 $i = $self->{_data}->num_sets if $self->{_data}->num_sets < $i; 730 $i++; 731 $i_step = -1; 732 } # end if 733 734 foreach my $legend (@legends) 735 { 736 $i += $i_step; 737 738 # Legend for Pie goes over first set, and all points 739 # Works in either direction 740 last if $i > $self->{_data}->num_sets; 741 last if $i < 1; 742 743 my $xe = $x; # position within an element 744 745 next unless defined($legend) && $legend ne ""; 746 747 $self->draw_legend_marker($i, $xe, $y); 748 749 $xe += $self->{legend_marker_width} + $self->{legend_spacing}; 750 my $ys = int($y + $self->{lg_el_height}/2 - $self->{lgfh}/2); 751 752 $self->{gdta_legend}->set_text($legend); 753 $self->{gdta_legend}->draw($xe, $ys); 754 755 $x += $self->{lg_el_width}; 756 757 if (++$row > $self->{lg_cols}) 758 { 759 $row = 1; 760 $y += $self->{lg_el_height}; 761 $x = $xl; 762 } 763 } 764 765 # If there's a frame, draw it now 766 if( $self->{legend_frame_size} ) { 767 $x = $self->{lg_xs} + $self->{legend_spacing}; 768 $y = $self->{lg_ys} + $self->{legend_spacing} - 1; 769 770 for $i ( 0 .. $self->{legend_frame_size} - 1 ) { 771 $self->{graph}->rectangle( 772 $x + $i, 773 $y + $i, 774 $x + $self->{lg_x_size} + 2 * $self->{legend_frame_margin} - $i - 1, 775 $y + $self->{lg_y_size} + 2 * $self->{legend_frame_margin} - $i - 1, 776 $self->{acci}, 777 ); 778 } # end for 779 } # end if 780 781} 782 783 784 785# Inherit draw_legend_marker 786 7871; 788