File Coverage

blib/lib/Chart/Sequence/Layout.pm
Criterion Covered Total %
statement 60 136 44.1
branch 0 16 0.0
condition 0 10 0.0
subroutine 20 21 95.2
pod 1 1 100.0
total 81 184 44.0


line stmt bran cond sub pod time code
1             package Chart::Sequence::Layout;
2              
3             $VERSION = 0.000_1;
4              
5             =head1 NAME
6              
7             Chart::Sequence::Layout - Lay out a sequence so it can be rendered
8              
9             =head1 SYNOPSIS
10              
11             use Chart::Sequence::Layout;
12              
13             my $layout = Chart::Sequence::Layout->new( ... );
14              
15             $layout->layout( $sequence );
16              
17             =head1 DESCRIPTION
18              
19             Takes a sequence and lays it out. Leaves coordinates in the source sequence.
20              
21             =for test_script t/Chart-Sequence-Renderer-Imager.t
22              
23             =cut
24              
25 1     1   6955 use POSIX qw( floor );
  1         7937  
  1         7  
26 1     1   1787 use Chart::Sequence::Object ();
  1         3  
  1         31  
27             @ISA = qw( Chart::Sequence::Object );
28              
29 1     1   5 use strict;
  1         2  
  1         35  
30              
31             ## For whole diagram
32 1     1   6 use constant diagram_margins => 10;
  1         1  
  1         90  
33 1     1   4 use constant diagram_left_margin => diagram_margins;
  1         2  
  1         58  
34 1     1   5 use constant diagram_right_margin => diagram_margins;
  1         1  
  1         47  
35 1     1   5 use constant diagram_top_margin => diagram_margins;
  1         8  
  1         59  
36 1     1   5 use constant diagram_bottom_margin => diagram_margins;
  1         1  
  1         44  
37              
38             ## For box labels
39 1     1   5 use constant box_margins => 10;
  1         1  
  1         47  
40 1     1   5 use constant box_left_margin => box_margins;
  1         1  
  1         50  
41 1     1   5 use constant box_right_margin => box_margins;
  1         1  
  1         51  
42 1     1   4 use constant box_top_margin => box_margins;
  1         2  
  1         49  
43 1     1   4 use constant box_bottom_margin => box_margins;
  1         1  
  1         47  
44              
45 1     1   4 use constant box_spacing => 10;
  1         2  
  1         44  
46              
47 1     1   5 use constant first_message_spacing => 20;
  1         1  
  1         50  
48 1     1   5 use constant last_message_spacing => 10;
  1         2  
  1         35  
49              
50 1     1   4 use constant message_top_margin => 2;
  1         2  
  1         41  
51 1     1   4 use constant message_bottom_margin => 2;
  1         2  
  1         130  
52 1     1   5 use constant message_left_margin => 2;
  1         2  
  1         38  
53 1     1   5 use constant message_right_margin => 2;
  1         2  
  1         1170  
54              
55             =head2 METHODS
56              
57             =over
58              
59             =cut
60              
61             =item lay_out
62              
63             $layout->lay_out( $sequence, $renderer, $options );
64              
65             Adds a set of coordinates to each object in $sequence.
66              
67             Options:
68              
69             DiagonalArrows => 1, # Make arrows angle in direction of time.
70              
71             =cut
72              
73             sub lay_out {
74 0     0 1   my $self = shift;
75 0           my ( $sequence, $renderer, $options ) = @_;
76 0   0       $options ||= {};
77             # $options->{DiagonalArrows} = 1;
78              
79 0 0 0       my @messages = sort {
      0        
      0        
      0        
80 0           ( $a->send_time || 0 ) <=> ( $b->send_time || 0 )
81             ||
82             ( $a->number || 0 ) <=> ( $b->number || 0 )
83             } $sequence->messages;
84              
85 0           my @nodes = $sequence->nodes;
86              
87             ## Gather the necessary metrics
88 0           my $nodes_h = 0;
89 0           for ( @nodes ) {
90 0           my $l = {};
91 0           $_->_layout_info( $l );
92              
93 0           my $label = $_->name;
94 0           my $lm = $l->{label_metrics} = $renderer->string_metrics(
95             %$options,
96             string => $label,
97             );
98              
99 0           $l->{label} = $label;
100 0           $l->{font} = $lm->{font};
101 0           $l->{fontcolor} = $lm->{color};
102 0           $l->{w} = $lm->{w} + box_left_margin + box_right_margin;
103 0           $l->{h} = $lm->{h} + box_top_margin + box_bottom_margin;
104 0 0         $nodes_h = $l->{h} if $l->{h} > $nodes_h;
105             }
106              
107 0           my $messages_w = 0;
108 0           for ( @messages ) {
109 0           my $l = {};
110 0           $_->_layout_info( $l );
111              
112 0           my $label = $_->name;
113 0           my $lm = $l->{label_metrics} = $renderer->string_metrics(
114             color => $_->color,
115             %$options,
116             string => $label,
117             );
118              
119 0           $l->{label} = $label;
120 0           $l->{font} = $lm->{font};
121 0           $l->{fontcolor} = $lm->{color};
122 0           $lm->{h} += message_top_margin + message_bottom_margin;
123 0           $lm->{w} += message_left_margin + message_right_margin;
124 0 0         $messages_w = $lm->{w} if $lm->{w} > $messages_w;
125             }
126              
127             # Lay out the image
128 0           my $w = 0;
129 0           my $h = 0;
130             { # nodes.
131 0           my $x = diagram_left_margin + $messages_w;
  0            
132 0           my $y = diagram_top_margin;
133              
134 0           for ( @nodes ) {
135 0           my $l = $_->_layout_info;
136              
137 0           my $lm = $l->{label_metrics};
138              
139 0           $l->{x} = $x;
140 0           $l->{y} = $y;
141 0           $l->{lx} = $x + box_left_margin + $lm->{x_offs};
142 0           $l->{ly} = $y + box_top_margin + $lm->{y_offs};
143 0           $l->{cx} = $l->{x} + floor( $l->{w} / 2 );
144 0           $x += $l->{w} + box_spacing;
145             }
146 0 0         $w = $x if $x > $w;
147 0 0         $h = $y if $y > $h;
148             }
149              
150             { # messages & arrows
151 0           my $greybar_index = 0;
  0            
152 0           my $x = diagram_left_margin;
153 0           my $y = diagram_top_margin + $nodes_h + first_message_spacing;
154              
155 0           for ( @messages ) {
156 0           my $l = $_->_layout_info;
157 0           my $f = $sequence->node_named( $_->from )->_layout_info;
158 0           my $t = $sequence->node_named( $_->to )->_layout_info;
159 0           my $lm = $l->{label_metrics};
160              
161 0           $l->{gb_index} = $greybar_index;
162 0 0         $greybar_index = $greybar_index ? 0 : 1;
163 0           $l->{gby1} = $y;
164 0           $l->{gby2} = $l->{gby1} + $lm->{h};
165              
166 0           $l->{lx} = $x + message_left_margin;
167 0           $l->{ly} = $y + message_top_margin;
168              
169 0           $l->{x1} = $f->{cx};
170 0           $l->{x2} = $t->{cx};
171              
172 0 0         if ( $options->{DiagonalArrows} ) {
173 0           $l->{y1} = $y + message_top_margin;
174 0           $l->{y2} = $y + $lm->{h} - message_bottom_margin;
175             }
176             else {
177 0           $l->{y1} = $l->{y2} =
178             $y + floor( 0.5 + message_top_margin + $lm->{b_offs} / 2 );
179             }
180              
181 0           $y += $lm->{h};
182             }
183 0           $y += last_message_spacing;
184            
185 0 0         $h = $y if $y > $h;
186             }
187              
188 0           for ( map $_->_layout_info, $sequence->nodes ) {
189 0           $_->{end_y} = $h;
190             }
191              
192             $sequence->_layout_info(
193             {
194 0           w => $w + diagram_right_margin,
195             h => $h + diagram_bottom_margin,
196             }
197             );
198              
199 0           for ( map $_->_layout_info, $sequence->messages ) {
200 0           $_->{gbx1} = diagram_left_margin;
201 0           $_->{gbx2} = $w - diagram_right_margin;
202             }
203             }
204              
205             =back
206              
207             =head1 LIMITATIONS
208              
209             =head1 COPYRIGHT
210              
211             Copyright 2002, R. Barrie Slaymaker, Jr., All Rights Reserved
212              
213             =head1 LICENSE
214              
215             You may use this module under the terms of the BSD, Artistic, oir GPL licenses,
216             any version.
217              
218             =head1 AUTHOR
219              
220             Barrie Slaymaker
221              
222             =cut
223              
224             1;