File Coverage

blib/lib/GD/Graph/axestype3d.pm
Criterion Covered Total %
statement 4 6 66.6
branch n/a
condition n/a
subroutine 2 2 100.0
pod n/a
total 6 8 75.0


line stmt bran cond sub pod time code
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             #==========================================================================
26             package GD::Graph::axestype3d;
27              
28 1     1   6 use strict;
  1         2  
  1         47  
29            
30 1     1   892 use GD::Graph;
  0            
  0            
31             use GD::Graph::axestype;
32             use GD::Graph::utils qw(:all);
33             use GD::Graph::colour qw(:colours);
34             use 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              
41             use constant PI => 4 * atan2(1,1);
42              
43             my %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.
55             sub 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             # ----------------------------------------------------------
100             sub 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             # ----------------------------------------------------------
159             sub _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             # ----------------------------------------------------------
183             sub _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
199             sub _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
221             sub 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
247             sub 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
381             sub 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
462             sub 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
587             sub 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
706             sub 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              
787             1;