File Coverage

blib/lib/Math/Geometry/Construction/Draw/SVG.pm
Criterion Covered Total %
statement 1 3 33.3
branch n/a
condition n/a
subroutine 1 1 100.0
pod n/a
total 2 4 50.0


line stmt bran cond sub pod time code
1             package Math::Geometry::Construction::Draw::SVG;
2 1     1   1869 use Moose;
  0            
  0            
3             extends 'Math::Geometry::Construction::Draw';
4              
5             use 5.008008;
6              
7             use Carp;
8              
9             =head1 NAME
10              
11             C<Math::Geometry::Construction::Draw::SVG> - SVG output
12              
13             =head1 VERSION
14              
15             Version 0.021
16              
17             =cut
18              
19             our $VERSION = '0.021';
20              
21              
22             ###########################################################################
23             # #
24             # Generate Output #
25             # #
26             ###########################################################################
27              
28             sub BUILD {
29             my ($self, $args) = @_;
30              
31             my $bg = delete $args->{background}; # modifies given hash!
32             delete $args->{transform};
33             $self->_output(SVG->new(%$args));
34             $self->_set_background($bg, %$args);
35             }
36              
37             sub _set_background {
38             my ($self, $color, %args) = @_;
39              
40             return if(!$color);
41             if(ref($color) eq 'ARRAY' and @$color == 3) {
42             $color = sprintf('rgb(%d, %d, %d)', @$color);
43             }
44              
45             my $x = 0;
46             my $y = 0;
47             my $w = $args{width};
48             my $h = $args{height};
49             if($args{viewBox}) {
50             my $wsp = qr/\s+|\s*\,\s*/;
51             if($args{viewBox} =~ /^\s*(.*)$wsp(.*)$wsp(.*)$wsp(.*?)\s*$/) {
52             ($x, $y, $w, $h) = ($1, $2, $3, $4);
53             }
54             else { warn "Failed to parse viewBox attribute.\n" }
55             }
56              
57             $self->output->rect('x' => $x,
58             'y' => $y,
59             width => $w,
60             height => $h,
61             stroke => 'none',
62             fill => $color);
63              
64             }
65              
66             sub process_style {
67             my ($self, $element, %style) = @_;
68              
69             while(my ($key, $value) = each(%style)) {
70             if($value and ref($value) eq 'ARRAY' and @$value == 3) {
71             $style{$key} = sprintf('rgb(%d, %d, %d)', @$value);
72             }
73             }
74              
75             return %style;
76             }
77              
78             sub line {
79             my ($self, %args) = @_;
80              
81             $args{style} = {$self->process_style('line', %{$args{style}})}
82             if($args{style});
83              
84             ($args{x1}, $args{y1}) = $self->transform_coordinates
85             ($args{x1}, $args{y1});
86             ($args{x2}, $args{y2}) = $self->transform_coordinates
87             ($args{x2}, $args{y2});
88              
89             $self->output->line(%args);
90             }
91              
92             sub circle {
93             my ($self, %args) = @_;
94              
95             $args{style} = {$self->process_style('circle', %{$args{style}})}
96             if($args{style});
97              
98             ($args{cx}, $args{cy}) = $self->transform_coordinates
99             ($args{cx}, $args{cy});
100             $args{rx} = $self->transform_x_length($args{r});
101             $args{ry} = $self->transform_y_length($args{r});
102             delete $args{r};
103              
104             if(defined($args{x1}) and defined($args{y1}) and
105             defined($args{x2}) and defined($args{y2}))
106             {
107             my @boundary = $self->is_flipped
108             ? ([$self->transform_coordinates($args{x2}, $args{y2})],
109             [$self->transform_coordinates($args{x1}, $args{y1})])
110             : ([$self->transform_coordinates($args{x1}, $args{y1})],
111             [$self->transform_coordinates($args{x2}, $args{y2})]);
112              
113             my @phi = map { atan2($boundary[$_]->[1] - $args{cy},
114             $boundary[$_]->[0] - $args{cx}) }
115             (0, 1);
116              
117             my $delta_phi = $phi[1] - $phi[0];
118             $delta_phi += 6.28318530717959 if($delta_phi < 0);
119             my $large = $delta_phi > 3.14159265358979 ? 1 : 0;
120              
121             $args{d} = sprintf('M%f %f A%f %f %d %d %f %f',
122             @{$boundary[0]},
123             $args{rx}, $args{ry},
124             $large, 1,
125             @{$boundary[1]});
126              
127             delete(@args{'cx', 'cy', 'rx', 'ry', 'x1', 'y1', 'x2', 'y2'});
128             $self->output->path(%args);
129             }
130             else {
131             delete(@args{'x1', 'y1', 'x2', 'y2'});
132             $self->output->ellipse(%args);
133             }
134             }
135              
136             sub text {
137             my ($self, %args) = @_;
138              
139             $args{style} = {$self->process_style('text', %{$args{style}})}
140             if($args{style});
141              
142             ($args{x}, $args{y}) = $self->transform_coordinates
143             ($args{x}, $args{y});
144              
145             my $data = delete $args{text};
146             my $text = $self->output->text(%args);
147             $text->cdata($data);
148             }
149              
150              
151             1;
152              
153              
154             __END__
155              
156             =pod
157              
158             =head1 SYNOPSIS
159              
160             use Math::Geometry::Construction;
161              
162             my $construction = Math::Geometry::Construction->new;
163             my $p1 = $construction->add_point('x' => 100, 'y' => 150);
164             my $p2 = $construction->add_point('x' => 130, 'y' => 110);
165              
166             my $l1 = $construction->add_line(extend => 10,
167             support => [$p1, $p2]);
168              
169             my $tikz = $construction->as_tikz(width => 8,
170             height => 3,
171             view_box => [0, 0, 800, 300],
172             svg_mode => 1);
173              
174             print $construction->as_svg(width => 800, height => 300)->xmlify;
175              
176              
177             =head1 DESCRIPTION
178              
179             This class implements the
180             L<Math::Geometry::Construction::Draw|Math::Geometry::Construction::Draw>
181             interface in order to generate C<SVG> output. It is instantiated by
182             the L<draw method|Math::Geometry::Construction/draw> in
183             C<Math::Geometry::Construction>.
184              
185             The output created by this class will be an L<SVG|SVG> object. See
186             C<SYNOPSIS>.
187              
188             Key/value pairs in the style settings of lines, circles etc. are
189             passed unchanged to the respective C<SVG> element.
190              
191              
192             =head1 INTERFACE
193              
194             =head2 Public Attributes
195              
196             =head2 Methods
197              
198              
199             =head1 SEE ALSO
200              
201             =over 4
202              
203             =item * L<SVG|SVG>
204              
205             =item * L<http://www.w3.org/TR/SVG11/>
206              
207             =back
208              
209              
210             =head1 AUTHOR
211              
212             Lutz Gehlen, C<< <perl at lutzgehlen.de> >>
213              
214              
215             =head1 LICENSE AND COPYRIGHT
216              
217             Copyright 2011, 2013 Lutz Gehlen.
218              
219             This program is free software; you can redistribute it and/or modify it
220             under the terms of either: the GNU General Public License as published
221             by the Free Software Foundation; or the Artistic License.
222              
223             See http://dev.perl.org/licenses/ for more information.
224              
225              
226             =cut
227