File Coverage

lib/Text/HistogramChart.pm
Criterion Covered Total %
statement 145 158 91.7
branch 72 110 65.4
condition 13 27 48.1
subroutine 11 11 100.0
pod 3 3 100.0
total 244 309 78.9


line stmt bran cond sub pod time code
1             package Text::HistogramChart;
2            
3             ## no critic (Subroutines::RequireArgUnpacking)
4             ## no critic (RequirePodAtEnd)
5             # By using =encoding utf8 this module would require perl 5.10. No need for that!
6             ## no critic (Documentation::RequirePODUseEncodingUTF8 )
7            
8 1     1   24318 use 5.008_001;
  1         4  
  1         41  
9 1     1   5 use strict;
  1         3  
  1         28  
10 1     1   6 use warnings;
  1         5  
  1         79  
11            
12            
13             =head1 NAME
14            
15             Text::HistogramChart - Make Text Histogram (Upright Bars) Charts
16            
17             =head1 VERSION
18            
19             Version 0.005
20            
21             =cut
22            
23             #use version 0.77 (); our $VERSION = 0.003; # Require version 0.77 of module "version". Even for Perl v.5.10.0, get latest bug-fixes and API
24             our $VERSION = 0.005;
25            
26            
27             =head1 SYNOPSIS
28            
29             Text::HistogramChart creates graphical charts for terminal displays or any other display device where bitmap graphics is not available!
30             You can supply the Y axel legend (vertical) values or Text::HistogramChart can calculate them from the input values.
31            
32             require Text::HistogramChart;
33            
34             my $chart = Text::HistogramChart->new();
35            
36             @values = (1, 2, 3, 4, 5, 4, 3, 2, 1, 0, -1, -2, -3, -4, -5, -4, -3, -2, -1, 0);
37             @legend_values = (4, 3, 2, 1, 0, -1, -2, -3, -4);
38             $chart->{'values'} = \@values;
39             $chart->{'legend_values'} = \@legend_values;
40             $chart->{'screen_height'} = 9; # (height reserved for the graph.)
41             $chart->{'roof_value'} = 0; # (active if != 0), # Arbitrarily squeeze or extend the size (height) of bars (not screen)
42             $chart->{'floor_value'} = 0; # (the "floor" of the chart, default: 0)
43             $chart->{'write_floor'} = 1; # (make floor visible)
44             $chart->{'use_floor'} = 1; # (use the floor value)
45             $chart->{'write_floor_value'} = 1; # If value == floor_value, then write value (mostly "0").
46             $chart->{'write_legend'} = 1; # (Prepend legend to each row.)
47             $chart->{'legend_horizontal_width'} = 4; # width of the space left for legend (left edge of chart)
48             $chart->{'horizontal_width'} = 2; # Horizontal width of one bar. This parameter directly influences the width of the screen (i.e. chart).
49             $chart->{'write_value'} = 1; # (YES = 1, NO = 0, default: no; write the value on the end of the bar),
50             $chart->{'write_always_over_value'} = 0; # (YES = 1, NO = 0, default: yes; write the value only if it is too high for the graph),
51             $chart->{'write_always_under_value'} = 0; # (YES = 1, NO = 0, default: yes; write the value only if it is too low for the graph),
52             $chart->{'bar_char'} = '|'; # (default: '|')
53             $chart->{'floor_char'} = '-'; # (default '-' )
54             $chart->{'over_value_char'} = '+'; # (default: '+')
55             $chart->{'under_value_char'} = '_'; # (default: '-' )
56             $rval = $chart->chart();
57             if($rval >= 1) {
58             my @ready_chart = @{$chart->{'screen'}};
59             print (join '\n', @ready_chart) . "\n";
60             } else {
61             print "Error in creating chart: " . $chart->error_string . "\n";
62             }
63            
64             # Result:
65             # 4 4 5 4
66             # 3 3 | | | 3
67             # 2 2 | | | | | 2
68             # 1 1 | | | | | | | 1
69             # 0 ------------------0 ------------------0
70             # -1 -1| | | | | | | -1
71             # -2 -2| | | | | -2
72             # -3 -3| | | -3
73             # -4 -4-5-4
74            
75            
76             =head1 DESCRIPTION
77            
78             Text::HistogramChart creates graphical charts for terminal displays or any other display device where bitmap graphics is not available or desired!
79             You can supply the Y axel legend (vertical) values or Text::HistogramChart can calculate them from the input values.
80            
81            
82             =head1 USAGE
83            
84             The following variables are available to fine tune the chart
85             (see SYNOPSIS for an example of usage):
86            
87             =over 4
88            
89             =item B, B, B
90            
91             The 'screen' is the area in which the chart is drawn. The size is defined with three variables.
92             B is the absolute Y-axis height in character rows.
93             B is the number of characters used for one bar (one value). If you have 10 values and
94             B is 3, then the length of the screen (the X-axis) is 10 * 3 = 30 characters (without legend).
95             Use B to define the legend width. The default for both is 5 characters.
96             Screen height defaults to 10 characters.
97            
98             =item B
99             Set this to 1 if you want the legend values prepended to the left edge of the chart.
100            
101             =item B, B, B, B
102            
103             Set B to 1 if you want the value of each bar written to the top (or bottom if the value is negative).
104             Set B and B to 1 if you only want want the value written when
105             the value is greater than the maximum given legend value (or less than the minimum).
106             Set B to 1 if you want the value written when it equals to 'floor', normally when the value is 0.
107            
108             =item B, B, B, B
109            
110             These variables define the characters used for writing the chart
111             B and B are used when the value is off the scale (too big or too small).
112             B is the horizontal line usually at 0.
113             B is the normal 'bar'.
114            
115             Any of these charaters can be more than one character is size.
116             If you want "fatter" vertical bars, just set bar_char to '||'.
117             Remember to set the other values to double digits as well.
118            
119             =item B, B, B, B, B
120            
121             With B and B you can restrict the chart into a certain 'height'.
122             E.g. you are measuring the CPU performance of a server. The performance is usually between 70% and 95% of total capacity.
123             To show the occasional drops to 0%-70% is a waste of (terminal) space. So you set
124             B to 95 and B to 70.
125             This feature not yet implemented.
126             Set B to 1 if you want a horizontal bar across the screen at 0.
127            
128            
129             =back
130            
131            
132             =head1 DEPENDENCIES
133            
134             Requires Perl version 5.008.001.
135            
136             Requires the following modules:
137            
138             =over 4
139            
140             =item Hash::Util
141            
142             =back
143            
144            
145             =cut
146            
147 1     1   925 use utf8;
  1         10  
  1         5  
148 1     1   944 use Hash::Util qw{lock_keys unlock_keys};
  1         3005  
  1         6  
149            
150             # Global creator
151             BEGIN {
152 1     1   107 use Exporter ();
  1         2  
  1         70  
153 1     1   2 our (@ISA, @EXPORT_OK, %EXPORT_TAGS);
154            
155 1         16 @ISA = qw(Exporter DynaLoader);
156 1         3 %EXPORT_TAGS = ( ); # eg: TAG => [ qw!name1 name2! ],
157 1         2417 @EXPORT_OK = qw();
158             }
159             our @EXPORT_OK;
160            
161             # Global destructor
162 1     1   6802 END {
163             }
164            
165             # CONSTANTS for this module
166             my $TRUE = 1;
167             my $FALSE = 0;
168             my $EMPTY_STR = q{};
169             my @EMPTY_ARRAY = (); ## no critic (ProhibitUselessInitialization)
170             my $SPACE = q{ };
171             my $HALF_ROW = 0.5; ## no critic (ValuesAndExpressions::ProhibitMagicNumbers)
172            
173             # DEFAULTS
174             my $DEFAULT_SCREEN_HEIGHT = 10; ## no critic (ProhibitMagicNumbers)
175             my $DEFAULT_ROOF_VALUE = 0;
176             my $DEFAULT_BOTTOM_VALUE = 0;
177             my $DEFAULT_FLOOR_VALUE = 0;
178             my $DEFAULT_WRITE_FLOOR = 0; # FALSE
179             my $DEFAULT_USE_FLOOR = 0; # FALSE
180             my $DEFAULT_WRITE_FLOOR_VALUE = 0; # FALSE
181             my $DEFAULT_WRITE_LEGEND = 0;
182             my $DEFAULT_LEGEND_HORIZONTAL_WIDTH = 5; ## no critic (ProhibitMagicNumbers)
183             my $DEFAULT_HORIZONTAL_WIDTH = 5; ## no critic (ProhibitMagicNumbers)
184             my $DEFAULT_WRITE_VALUE = 0; # FALSE
185             my $DEFAULT_WRITE_ALWAYS_OVER_VALUE = 0; # FALSE
186             my $DEFAULT_WRITE_ALWAYS_UNDER_VALUE = 0; # FALSE
187            
188             my $DEFAULT_BAR_CHAR = q{|};
189             my $DEFAULT_FLOOR_CHAR = q{-};
190             my $DEFAULT_OVER_VALUE_CHAR = q{+};
191             my $DEFAULT_UNDER_VALUE_CHAR = q{-};
192             my $DEFAULT_LEGEND_VALUES = \@EMPTY_ARRAY;
193             my $DEFAULT_VALUES = \@EMPTY_ARRAY;
194             my $DEFAULT_SCREEN = q{};
195             my $DEFAULT_ERROR_STRING = q{};
196            
197             # GLOBALS
198             # No global variables
199            
200            
201            
202             =head1 EXPORT
203            
204             Text::HistogramChart is a purely object-oriented module.
205             No exported functions.
206            
207            
208             =head1 SUBROUTINES/METHODS
209            
210             =head2 new
211            
212             Creator function.
213            
214             =cut
215            
216             sub new {
217 1     1 1 252 my $class = shift;
218 1         3 my $self;
219 1         8 my @self_keys = (
220             'screen_height', # (height reserved for the chart.)
221             'roof_value', # (active if != 0), # Arbitrarily squeeze or extend the size (height) of bars (not screen)
222             'bottom_value', # (below floor, active if != 0), # Not yet implemented.
223             'floor_value', # (the "floor" of the chart, default: 0)
224             'write_floor', # (make floor visible)
225             'use_floor', # (use the floor value)
226             'write_floor_value', # If value == floor_value, then write value (mostly "0").
227             'write_legend', # (Prepend legend to each row.)
228             'legend_horizontal_width', # width of the space left for legend (left edge of chart)
229             'horizontal_width', # Horizontal width of one bar. This parameter directly influences the width of the screen (i.e. chart).
230             'write_value', # (YES = 1, NO = 0, default: no; write the value on the end of the bar),
231             'write_always_over_value', # (YES = 1, NO = 0, default: yes; write the value only if it is too high for the graph),
232             'write_always_under_value', # (YES = 1, NO = 0, default: yes; write the value only if it is too low for the graph),
233             'bar_char', # (default: '|')
234             'floor_char', # (default: '-' )
235             'over_value_char', # (default: '+'; overruled by write_value and write_always_over_value)
236             'under_value_char', # (default: '-'; overruled by write_value and write_always_under_value)
237             'legend_values', # array of legend values (numbers). Pointer to.
238             'values', # array of values (numbers). Pointer to.
239             'screen', # The result: array of strings. Pointer to.
240             'error_string', # A meaningful error!
241             );
242 1         3 lock_keys(%{$self}, @self_keys);
  1         10  
243 1         147 $self->{'screen_height'} = $DEFAULT_SCREEN_HEIGHT;
244 1         3 $self->{'roof_value'} = $DEFAULT_ROOF_VALUE;
245 1         2 $self->{'bottom_value'} = $DEFAULT_BOTTOM_VALUE;
246 1         3 $self->{'floor_value'} = $DEFAULT_FLOOR_VALUE;
247 1         3 $self->{'write_floor'} = $DEFAULT_WRITE_FLOOR;
248 1         2 $self->{'use_floor'} = $DEFAULT_USE_FLOOR;
249 1         3 $self->{'write_floor_value'} = $DEFAULT_WRITE_FLOOR_VALUE;
250 1         1 $self->{'write_legend'} = $DEFAULT_WRITE_LEGEND;
251 1         2 $self->{'legend_horizontal_width'} = $DEFAULT_LEGEND_HORIZONTAL_WIDTH;
252 1         3 $self->{'horizontal_width'} = $DEFAULT_HORIZONTAL_WIDTH;
253 1         1 $self->{'write_value'} = $DEFAULT_WRITE_VALUE;
254 1         468 $self->{'write_always_over_value'} = $DEFAULT_WRITE_ALWAYS_OVER_VALUE;
255 1         3 $self->{'write_always_under_value'} = $DEFAULT_WRITE_ALWAYS_UNDER_VALUE;
256            
257 1         15 $self->{'bar_char'} = $DEFAULT_BAR_CHAR;
258 1         2 $self->{'floor_char'} = $DEFAULT_FLOOR_CHAR;
259 1         3 $self->{'over_value_char'} = $DEFAULT_OVER_VALUE_CHAR;
260 1         1 $self->{'under_value_char'} = $DEFAULT_UNDER_VALUE_CHAR;
261 1         2 $self->{'legend_values'} = $DEFAULT_LEGEND_VALUES;
262 1         1 $self->{'values'} = $DEFAULT_VALUES;
263 1         2 $self->{'screen'} = $DEFAULT_SCREEN;
264 1         1 $self->{'error_string'} = $DEFAULT_ERROR_STRING;
265            
266 1         2 unlock_keys(%{$self});
  1         5  
267 1         8 my $blessed_ref = bless $self, $class;
268 1         2 lock_keys(%{$self}, @self_keys);
  1         10  
269 1         138 return $blessed_ref;
270             }
271            
272             =head2 chart
273            
274             Create the chart. Writes the ready chart into $self->{'screen'}.
275             The ready chart is an array of strings without linefeed.
276             Returns >= 1, if successful, else $self->{'error_string'} contains the error.
277            
278             =cut
279            
280             sub chart {
281 7     7 1 24044 my $return_value = 1;
282            
283 7         11 my $self = shift;
284            
285 7         8 my @values = @{$self->{'values'}};
  7         23  
286 7         9 my @legend_values;
287 7         8 my $horizontal_width_empty = $EMPTY_STR;
288 7         23 while(length $horizontal_width_empty < $self->{'horizontal_width'}) {
289 27         55 $horizontal_width_empty .= $SPACE;
290             }
291            
292 7         7 my @output_rows;
293             # If user wants, write only the legend.
294             # Always create the legend first so you know which rows have which values!
295             # If user gives the legend values (parameter LEGEND_VALUES)
296             # then all the better for you (no need to calculate the legend yourself).
297             # But only write the legend if user demands it (parameter WRITE_LEGEND).
298             # Even without writing the legend, the legend values define the distance between rows.
299 7         16 my $sprf_format = q{%-} . $self->{'legend_horizontal_width'} . q{s};
300 7 100 66     22 if(defined $self->{'legend_values'} && scalar @{$self->{'legend_values'}} > 0) {
  7         32  
301 4         5 @legend_values = @{$self->{'legend_values'}};
  4         11  
302 4 50       15 if(scalar(@legend_values) != $self->{'screen_height'}) {
303 0         0 $self->{'error_string'} = 'Screen height must be equal to the number of legend values!';
304 0         0 return 0;
305             }
306 4         18 @legend_values = sort {$a <=> $b} @legend_values; # Sort them to be sure
  73         74  
307             }
308             else {
309 3         4 my $highest_value = 0;
310 3 50       8 if($self->{'roof_value'} != 0) {
311 0         0 $highest_value = $self->{'roof_value'};
312             }
313             else {
314 3         7 foreach my $value (@values) {
315 43 100       76 if($value > $highest_value) {
316 26         33 $highest_value = $value;
317             }
318             }
319             }
320 3         5 my $lowest_value = 0;
321 3 50       8 if($self->{'bottom_value'} != 0) {
322 0         0 $lowest_value = $self->{'bottom_value'};
323             }
324             else {
325 3         5 foreach my $value (@values) {
326 43 50       81 if($value < $lowest_value) {
327 0         0 $lowest_value = $value;
328             }
329             }
330             }
331 3         9 my $rows_for_one = $self->{'screen_height'} / $highest_value;
332 3         6 my $amount_per_row = $highest_value / $self->{'screen_height'};
333             #my $rows_for_one = $self->{'screen_height'} / ($highest_value - $lowest_value + 1); //TODO
334             #my $amount_per_row = ($highest_value - $lowest_value + 1) / $self->{'screen_height'}; //TODO
335            
336             # Make a legend based on lowest and highest value in @values
337 3         4 my $screen_top_row = $self->{'screen_height'} - 1;
338 3         3 my $screen_bottom_row = 0;
339             #my $screen_top_row = $highest_value - $lowest_value; //TODO
340             #my $screen_bottom_row = 0; //TODO
341 3         11 for(my $i_row = $screen_bottom_row; $i_row <= $screen_top_row; $i_row++) {
342 40         124 push @legend_values, (sprintf $sprf_format, int(($i_row + 1) * $amount_per_row + $HALF_ROW));
343             #push @legend_values, (sprintf $sprf_format, int(($i_row + $lowest_value) * $amount_per_row + 0.5)); //TODO
344             }
345             }
346 7 100       19 if($self->{'write_legend'} == 1) {
347 6         20 for(my $i_row = $self->{'screen_height'} - 1; $i_row >= 0; $i_row--) { ## no critic (ControlStructures::ProhibitCStyleForLoops)
348 74         200 $output_rows[$i_row] .= sprintf $sprf_format, int $legend_values[$i_row];
349             }
350             }
351            
352             # Now the values
353             # We write one pillar at a time: one value = one pillar!
354             # So, we write from left to right, one pillar at a time!
355             # We write the pillar starting from the bottom.
356 7         9 my $screen_top_row = $self->{'screen_height'} - 1;
357 7         8 my $screen_bottom_row = 0;
358 7         9 my $screen_floor_row = $screen_bottom_row;
359 7 100       17 if($self->{'use_floor'} == 1) {
360 3         7 for(0..@legend_values-1) {
361 34 100       68 if($legend_values[$_] == $self->{'floor_value'}) {
362 3         6 $screen_floor_row = $_;
363             }
364             }
365             }
366 7         13 foreach my $value (@values) {
367 108         238 for(my $i_row = $screen_bottom_row; $i_row <= $screen_top_row; $i_row++) {
368 1298 100       2265 if($value != $self->{'floor_value'}) { # If value == 0, just write spaces.
369 1194 100 66     5923 if($i_row == $screen_bottom_row) { ## no critic (ControlStructures::ProhibitCascadingIfElse)
    100 66        
    100          
    100          
    50          
370 99 100       181 if($i_row < $screen_floor_row) {
    50          
371 47 100       85 if($value > $legend_values[$i_row]) { # Write empty space
    50          
372 43         111 $output_rows[$i_row] .= $horizontal_width_empty;
373             }
374             elsif($value <= $legend_values[$i_row]) { # Write value
375 4 50       18 if(length($value) > $self->{'horizontal_width'}) { # Doesn't fit on the row.
376 0 0       0 $output_rows[$i_row] .= center_text(
    0          
377             $self->{'write_always_under_value'} ? $self->{'under_value_char'} : ($self->{'write_value'} ? $value : $self->{'bar_char'}),
378             $self->{'horizontal_width'}, $SPACE, 'right');
379             }
380             else {
381 4 100       16 $output_rows[$i_row] .= center_text(
    50          
382             $self->{'write_always_under_value'} ? $value : ($self->{'write_value'} ? $value : $self->{'bar_char'}),
383             $self->{'horizontal_width'}, $SPACE, 'right');
384             }
385             }
386             else {
387             }
388             }
389             elsif($i_row >= $screen_floor_row) {
390 52 100 66     138 if($value >= $legend_values[$i_row + 1]) { # Write bar char
    100 33        
    50 0        
    0          
391 43         89 $output_rows[$i_row] .= center_text($self->{'bar_char'}, $self->{'horizontal_width'}, $SPACE, 'right');
392             }
393             elsif($value >= $legend_values[$i_row] && $value < $legend_values[$i_row + 1]) { # Write value
394 7 100       30 $output_rows[$i_row] .= center_text($self->{'write_value'} ? $value : $self->{'bar_char'}, $self->{'horizontal_width'}, $SPACE, 'right');
395             }
396             elsif($value < $legend_values[$i_row] && $value >= $self->{'floor_value'}) { # Write value maybe
397 2 50       8 $output_rows[$i_row] .= center_text(
398             $self->{'write_always_under_value'} ? $value : '',
399             $self->{'horizontal_width'}, $SPACE, 'right');
400             }
401             elsif($value < $legend_values[$i_row] && $value < $self->{'floor_value'}) { # Write value
402 0 0       0 $output_rows[$i_row] .= center_text($self->{'write_value'} ? $value : $self->{'bar_char'}, $self->{'horizontal_width'}, $SPACE, 'right');
403             }
404             else {
405             }
406             }
407             else {
408             }
409             }
410            
411             # (Possible) middle rows (floor down)
412             elsif($i_row < $screen_floor_row && $i_row > $screen_bottom_row) {
413 203 100 66     677 if($value <= $legend_values[$i_row - 1]) { # Write bar char
    100          
    50          
414 47         91 $output_rows[$i_row] .= center_text($self->{'bar_char'}, $self->{'horizontal_width'}, $SPACE, 'right');
415             }
416             elsif($value <= $legend_values[$i_row] && $value > $legend_values[$i_row - 1]) { # Write value
417 20 100       61 $output_rows[$i_row] .= center_text($self->{'write_value'} ? $value : $self->{'bar_char'}, $self->{'horizontal_width'}, $SPACE, 'right');
418             }
419             elsif($value > $legend_values[$i_row]) { # Write white space
420 136         337 $output_rows[$i_row] .= $horizontal_width_empty;
421             }
422             else {
423             }
424             }
425            
426             # Floor row
427             elsif($i_row == $screen_floor_row) {
428 47 50       81 if($self->{'write_floor'} == 1) {
429 47         103 $output_rows[$i_row] .= center_text('-', $self->{'horizontal_width'}, "-", 'right');
430             }
431             else {
432 0 0 0     0 if($value > $legend_values[$i_row - 1] && $value < $legend_values[$i_row + 1]) { # Write value
433 0 0       0 $output_rows[$i_row] .= center_text($self->{'write_value'} ? $value : $self->{'bar_char'}, $self->{'horizontal_width'}, $SPACE, 'right');
434             }
435             else { # Write bar char
436 0         0 $output_rows[$i_row] .= center_text($self->{'bar_char'}, $self->{'horizontal_width'}, $SPACE, 'right');
437             }
438             }
439             }
440            
441             # (Possible) middle rows (floor up)
442             elsif($i_row > $screen_floor_row && $i_row < $screen_top_row) {
443 746 100 66     2333 if($value >= $legend_values[$i_row + 1]) { # Write bar char
    100          
    50          
444 231         498 $output_rows[$i_row] .= center_text($self->{'bar_char'}, $self->{'horizontal_width'}, $SPACE, 'right');
445             }
446             elsif($value >= $legend_values[$i_row] && $value < $legend_values[$i_row + 1]) { # Write value
447 59 100       172 $output_rows[$i_row] .= center_text($self->{'write_value'} ? $value : $self->{'bar_char'}, $self->{'horizontal_width'}, $SPACE, 'right');
448             }
449             elsif($value < $legend_values[$i_row]) { # Write white space
450 456         1190 $output_rows[$i_row] .= $horizontal_width_empty;
451             }
452             else {
453             }
454             }
455            
456             # Top row, here value is only >= or
457             elsif($i_row == $screen_top_row) {
458 99 100       217 if($value >= $legend_values[$i_row]) { # Write value or bar char
    50          
459 6 50       17 if(length($value) > $self->{'horizontal_width'}) { # Doesn't fit on the row.
460 0 0       0 $output_rows[$i_row] .= center_text(
    0          
461             $self->{'write_always_over_value'} ? $self->{'over_value_char'} : ($self->{'write_value'} ? $value : $self->{'bar_char'}),
462             $self->{'horizontal_width'}, $SPACE, 'right');
463             }
464             else {
465 6 100       28 $output_rows[$i_row] .= center_text(
    50          
466             $self->{'write_always_over_value'} ? $value : ($self->{'write_value'} ? $value : $self->{'bar_char'}),
467             $self->{'horizontal_width'}, $SPACE, 'right');
468             }
469             }
470             elsif($value < $legend_values[$i_row]) { # Write white space
471 93         320 $output_rows[$i_row] .= $horizontal_width_empty;
472             }
473             else {
474             }
475             }
476             else {
477             }
478             }
479             else { # $value is same as $self->{'floor_value'}
480 104 100       177 if($self->{'floor_value'} == $legend_values[$i_row]) { # This is the floor row, the "0" row.
481 6 50       13 if($self->{'write_floor_value'} == 1) {
    0          
482 6         13 $output_rows[$i_row] .= center_text($value, $self->{'horizontal_width'}, $SPACE, 'right');
483             }
484             elsif($self->{'write_floor'}) {
485 0         0 $output_rows[$i_row] .= center_text($self->{'floor_char'}, $self->{'horizontal_width'}, $SPACE, 'right');
486             }
487             else {
488 0         0 $output_rows[$i_row] .= $horizontal_width_empty;
489             }
490             }
491             else {
492 98         220 $output_rows[$i_row] .= $horizontal_width_empty;
493             }
494             }
495             }
496             }
497             # Now we have to flip the order!
498 7         11 my @reversed_rows;
499 7         14 foreach my $screen_row (@output_rows) {
500 84         166 unshift @reversed_rows, $screen_row;
501             }
502 7         15 $self->{'screen'} = \@reversed_rows;
503            
504             # Clean up
505 7         50 return $return_value;
506             }
507            
508             =head1 INTERNAL SUBROUTINES
509            
510             =head2 center_text
511            
512             Center a string into a string buffer. Return the buffer.
513             Parameters: text to be centered, field width, fill character (default: " "), start direction (default: left).
514             If text is longer than field width, it is not truncated!
515            
516             =cut
517            
518             sub center_text {
519 472     472 1 538 my $text = $_[0];
520 472         455 my $field_width = $_[1];
521 472 50       688 my $fill_character = ($_[2] ? $_[2] : $SPACE);
522 472 50       704 my $start_direction = ($_[3] ? $_[3] : 'left'); ## no critic (ProhibitMagicNumbers)
523 472         447 my $next_add_direction = $start_direction;
524             # MODIFY BUFFER
525 472         935 while(length($text) < $field_width) {
526 1248 100       1873 if($next_add_direction eq 'left') {
527 475         603 $text = $fill_character . $text;
528 475         976 $next_add_direction = 'right'
529             }
530             else {
531 773         740 $text = $text . $fill_character;
532 773         1533 $next_add_direction = 'left'
533             }
534             }
535            
536 472         1757 return $text;
537             }
538            
539             =head1 AUTHOR
540            
541             Mikko Koivunalho, C<< >>
542            
543             =head1 BUGS
544            
545             Please report any bugs or feature requests to C, or through
546             the web interface at L. I will be notified, and then you'll
547             automatically be notified of progress on your bug as I make changes.
548            
549            
550            
551            
552             =head1 SUPPORT
553            
554             You can find documentation for this module with the perldoc command.
555            
556             perldoc Text::HistogramChart
557            
558            
559             You can also look for information at:
560            
561             =over 4
562            
563             =item * RT: CPAN's request tracker (report bugs here)
564            
565             L
566            
567             =item * AnnoCPAN: Annotated CPAN documentation
568            
569             L
570            
571             =item * CPAN Ratings
572            
573             L
574            
575             =item * Search CPAN
576            
577             L
578            
579             =back
580            
581            
582             =head1 ACKNOWLEDGEMENTS
583            
584             None.
585            
586            
587             =head1 DIAGNOSTICS
588            
589             None.
590            
591            
592             =head1 CONFIGURATION AND ENVIRONMENT
593            
594             Please see the examples.
595            
596            
597             =head1 INCOMPATIBILITIES
598            
599             None known.
600            
601            
602             =head1 BUGS AND LIMITATIONS
603            
604             Plenty I'm sure.
605             Using roof_value and bottom_value together to restrict the bars into a certain scope is not yet implemented.
606            
607            
608             =head1 LICENSE AND COPYRIGHT
609            
610             Copyright 2012 Mikko Koivunalho.
611            
612             This program is free software; you can redistribute it and/or modify it
613             under the terms of either: the GNU General Public License as published
614             by the Free Software Foundation; or the Artistic License.
615            
616             See http://dev.perl.org/licenses/ for more information.
617            
618            
619             =cut
620            
621             1; # End of Text::HistogramChart