File Coverage

blib/lib/Treemap.pm
Criterion Covered Total %
statement 19 76 25.0
branch 2 26 7.6
condition 1 9 11.1
subroutine 5 10 50.0
pod 2 4 50.0
total 29 125 23.2


line stmt bran cond sub pod time code
1             package Treemap;
2              
3 1     1   20423 use 5.006;
  1         38  
  1         41  
4 1     1   5 use strict;
  1         2  
  1         30  
5 1     1   4 use warnings;
  1         2  
  1         29  
6 1     1   5 use Carp;
  1         1  
  1         1061  
7              
8             require Exporter;
9              
10             our @ISA = qw(Exporter);
11             our @EXPORT_OK = ( );
12             our @EXPORT = qw( );
13             our $VERSION = '0.02';
14              
15              
16             # ------------------------------------------
17             # Methods:
18             # ------------------------------------------
19              
20              
21             # ------------------------------------------
22             # new() - Create and return new Treemap
23             # object:
24             # ------------------------------------------
25             sub new
26             {
27 1     1 1 15 my $proto = shift;
28 1   33     10 my $class = ref( $proto ) || $proto;
29 1         11 my $self = {
30             RECT => undef,
31             TEXT => undef,
32             CACHE => 1,
33             INPUT => undef,
34             OUTPUT => undef,
35             PADDING => 5,
36             SPACING => 5,
37             @_, # Override previous attributes
38             };
39              
40 1 50       5 die "No 'INPUT' object was specified in call to " . $class . "::new, cannot proceed.\nSee: perldoc Treemap\nError occured" if ( ! $self->{INPUT} );
41 1 50       83 die "No 'OUTPUT' object was specified in call to " . $class . "::new, cannot proceed.\nSee: perldoc Treemap\nError occured" if ( ! $self->{OUTPUT} );
42              
43             # set default "draw" functions
44             # $self->{ RECT } = \▭
45             # $self->{ TEXT } = \&text;
46              
47 1         3 bless $self, $class;
48 1         4 return $self;
49             }
50              
51             sub rect
52             {
53 0     0 0   print " ";
54 0           print "rect: @_\n";
55             }
56              
57             sub text
58             {
59 0     0 0   print " ";
60 0           print "text: @_\n";
61             }
62              
63             sub map
64             {
65 0     0 1   my $self = shift;
66              
67             # Get dimensions from OUTPUT object
68 0           my $width = $self->{OUTPUT}->width;
69 0           my $height= $self->{OUTPUT}->height;
70              
71             # Call _map function with tree data from INPUT object.
72 0           $self->_map( $self->{INPUT}->treedata, 0, 0, $width-1, $height-1 );
73             }
74              
75             sub _map
76             {
77 0     0     my $self = shift;
78 0           my ( @p, @q, $tree, $o );
79 0           ( $tree, $p[0], $p[1], $q[0], $q[1], $o ) = @_;
80 0   0       $o = $o || 0; # Orientation of our slicing
81              
82             # Draw our rectangle
83             #&{$self->{ RECT }}( $p[0], $p[1], $q[0], $q[1], $tree->{colour} );
84 0           $self->{ OUTPUT }->rect( $p[0], $p[1], $q[0], $q[1], $tree->{colour} );
85              
86             # Shrink the space available to children
87 0           my( $pt, $qt ) = $self->_shrink( \@p, \@q, $self->{PADDING} );
88 0           my @r = @$pt; my @s = @$qt;
  0            
89              
90             # Non-empty Set, Descend
91 0 0         if( $tree->{children} )
92             {
93 0           my $width = abs($r[$o] - $s[$o]);
94 0           my $size = $tree->{size};
95              
96             # Process each child
97 0           foreach my $child( @{$tree->{children}} )
  0            
98             {
99             # Give this child a percentage of the parent's space, based on
100             # parent's size (make sure we don't cause divide by zero errors)
101 0 0         $s[$o] = $r[$o] + $width * ( $child->{size} / $size ) if ( $size > 0 );
102              
103             # Rotate the space by 90 degrees, by xor'ing the 'o'rientation
104             {
105 0           my( $rt, $st ) = $self->_shrink( \@r, \@s, $self->{SPACING} );
  0            
106 0           my @r = @{$rt}; my @s = @{$st};
  0            
  0            
  0            
107 0   0       $self->_map( $child, $r[0], $r[1], $s[0], $s[1], ($o xor 1) );
108             }
109 0           $r[$o] = $s[$o];
110             }
111             }
112             # Draw label
113             #&{ $self->{ TEXT } }( $tree->{name} );
114 0 0         $self->{ OUTPUT }->text( $p[0], $p[1], $q[0], $q[1], $tree->{name}, ($tree->{children}?1:undef) );
115             }
116              
117             sub _shrink
118             {
119 0     0     my $self = shift;
120 0           my ( $p, $q, $shr ) = @_;
121 0           my ( $w, $h, $r, $s );
122 0           my ( $w_shrink, $h_shrink ) = ( 0, 0 );
123              
124 0           $w = $q->[0] - $p->[0];
125 0           $h = $q->[1] - $p->[1];
126              
127             # Shrinking by %
128             #
129             # +----------W1-----------+
130             # | |
131             # | +-------W2--------+ |
132             # | | | |
133             # H1 H2 | |
134             # | | A2 | |
135             # | +-----------------+ |
136             # | A1 |
137             # +-----------------------+
138             #
139             # A2 = A1*PCT
140             # H2*W2 = H1*W1*PCT (1)
141             #
142             # Since aspect ratio is constant:
143             #
144             # H2/W2 = H1/W1
145             # H2 = (H1*W2)/W1
146             #
147             # From (1):
148             #
149             # H2*W2 = H1*W1*PCT
150             # W2*(H1*W2)/W1 = H1*W1*PCT
151             # W2^2*H1/W1 = H1*W1*PCT
152             # W2^2 = W1^2*PCT
153             # W2 = (W1^2*PCT)^0.5
154             #
155 0 0         if ( $shr =~ /^([\d]+)%$/ )
156             {
157 0           my $pct = ( 100 - $1 ) / 100;
158 0           my $w2 = (($w**2)*$pct)**0.5;
159 0           $shr = ( abs($w) - $w2 ) / 2;
160             }
161              
162             # SLOPPY!!!
163             # These two if structures should be in a simple loop.....
164             # SLOPPY!!!
165 0 0         if ( abs( $w ) >= $shr )
166             {
167 0 0         if ( $w > 0 )
    0          
168             {
169 0           $w_shrink = $shr;
170             }
171             elsif( $w < 0 )
172             {
173 0           $w_shrink = - $shr;
174             }
175             }
176             # We can't shrink by that factor, so shrink as much as we can
177             else
178             {
179 0           $w_shrink = $w / 2;
180             }
181              
182 0 0         if ( abs( $h ) >= $shr )
183             {
184 0 0         if ( $h > 0 )
    0          
185             {
186 0           $h_shrink = $shr;
187             }
188             elsif( $h < 0 )
189             {
190 0           $h_shrink = - $shr;
191             }
192             }
193             # We can't shrink by that factor, so shrink as much as we can
194             else
195             {
196 0           $h_shrink = $h / 2;
197             }
198              
199             # Perfomr shrink
200 0 0         $self->{DEBUG} && print "Shrinking by $w_shrink, $h_shrink\n";
201 0           $r->[0] = $p->[0] + $w_shrink;
202 0           $r->[1] = $p->[1] + $h_shrink;
203              
204 0           $s->[0] = $q->[0] - $w_shrink;
205 0           $s->[1] = $q->[1] - $h_shrink;
206 0           return ( $r, $s );
207             }
208              
209             1;
210              
211             __END__