| File: | blib/lib/SVG/Sparkline.pm |
| Coverage: | 97.0% |
| line | stmt | bran | cond | sub | time | code |
|---|---|---|---|---|---|---|
| 1 | package SVG::Sparkline; | |||||
| 2 | ||||||
| 3 | 31 31 31 | 317238 48 596 | use warnings; | |||
| 4 | 30 30 30 | 69 25 403 | use strict; | |||
| 5 | 30 30 30 | 66 24 1017 | use Carp; | |||
| 6 | 30 30 30 | 32331 292847 267 | use SVG; | |||
| 7 | ||||||
| 8 | 30 30 30 | 32795 38 1162 | use overload '""' => \&to_string; | |||
| 9 | ||||||
| 10 | 30 30 30 | 1019 118 18605 | use 5.008000; | |||
| 11 | our $VERSION = 0.35; | |||||
| 12 | ||||||
| 13 | my %valid_parms = map { $_ => 1 } qw( | |||||
| 14 | -allns color -sized | |||||
| 15 | height width xscale yscale pady padx | |||||
| 16 | color bgcolor mark values | |||||
| 17 | ); | |||||
| 18 | ||||||
| 19 | sub new | |||||
| 20 | { | |||||
| 21 | 221 | 1919407 | my ($class, $type, $args) = @_; | |||
| 22 | 221 | 533 | croak "No Sparkline type specified.\n" unless defined $type; | |||
| 23 | # Use eval to load plugin. | |||||
| 24 | 220 28 27 27 28 28 28 26 26 26 26 26 26 20 20 20 15 15 15 13 13 13 10 10 10 8 8 8 7 7 7 6 6 6 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 4 4 4 3 3 3 | 7861 9368 45 750 1473 30 651 898 28 497 384 21 444 243 17 344 40 13 252 191 11 225 29 9 164 22 8 134 20 5 109 13 6 98 11 5 81 15 4 79 12 4 79 12 4 86 13 3 83 10 2 65 9 3 48 | eval "use SVG::Sparkline::$type;"; ## no critic (ProhibitStringyEval) | |||
| 25 | 220 | 477 | croak "Unrecognized Sparkline type '$type'.\n" if $@; | |||
| 26 | 219 | 633 | croak "Missing arguments hash.\n" unless defined $args; | |||
| 27 | 218 | 642 | croak "Arguments not supplied as a hash reference.\n" unless 'HASH' eq ref $args; | |||
| 28 | 217 | 270 | _no_unrecognized_parameters( $type, $args ); | |||
| 29 | ||||||
| 30 | 217 | 5138 | my $self = bless { | |||
| 31 | -allns => 0, | |||||
| 32 | color => '#000', | |||||
| 33 | -sized => 1, | |||||
| 34 | 217 | 413 | %{$args}, | |||
| 35 | }, $class; | |||||
| 36 | ||||||
| 37 | 217 | 359 | $self->_validate_pos_param( 'height', 12 ); | |||
| 38 | 215 | 235 | $self->_validate_pos_param( 'width', 0 ); | |||
| 39 | 213 | 242 | $self->_validate_pos_param( 'xscale' ); | |||
| 40 | 211 | 219 | $self->_validate_pos_param( 'yscale' ); | |||
| 41 | 211 | 275 | $self->_validate_nonneg_param( 'pady', 1 ); | |||
| 42 | 210 | 216 | $self->_validate_nonneg_param( 'padx', 0 ); | |||
| 43 | 209 | 266 | $self->_validate_mark_param(); | |||
| 44 | 199 | 178 | foreach my $arg (qw/color bgcolor/) | |||
| 45 | { | |||||
| 46 | 397 | 606 | next unless exists $self->{$arg}; | |||
| 47 | 208 | 286 | croak "The value of $arg is not a valid color.\n" | |||
| 48 | unless _is_color( $self->{$arg} ); | |||||
| 49 | } | |||||
| 50 | ||||||
| 51 | 197 | 260 | $self->{xoff} = -$self->{padx}; | |||
| 52 | 197 | 224 | $self->_make( $type ); | |||
| 53 | ||||||
| 54 | 166 | 727 | return $self; | |||
| 55 | } | |||||
| 56 | ||||||
| 57 | 0 | 0 | sub get_height { return $_[0]->{height}; } | |||
| 58 | 0 | 0 | sub get_width { return $_[0]->{width}; } | |||
| 59 | ||||||
| 60 | sub to_string | |||||
| 61 | { | |||||
| 62 | 185 | 4305 | my ($self) = @_; | |||
| 63 | 185 | 1286 | my $str = $self->{_SVG}->xmlify(); | |||
| 64 | # Cleanup | |||||
| 65 | 185 | 55042 | $str =~ s/ xmlns:(?:svg|xlink)="[^"]+"//g unless $self->{'-allns'}; | |||
| 66 | 185 | 260 | unless( $self->{'-sized'} ) | |||
| 67 | { | |||||
| 68 | # If I try to keep them from being created, default '100%' values | |||||
| 69 | # show up instead. | |||||
| 70 | 6 | 49 | $str =~ s/(<svg[^>]*) height="[^"]+"/$1/; | |||
| 71 | 6 | 30 | $str =~ s/(<svg[^>]*) width="[^"]+"/$1/; | |||
| 72 | } | |||||
| 73 | 185 | 1644 | return $str; | |||
| 74 | } | |||||
| 75 | ||||||
| 76 | sub _make | |||||
| 77 | { | |||||
| 78 | 197 | 190 | my ($self, $type) = @_; | |||
| 79 | 197 | 2730 | $self->{_SVG} = "SVG::Sparkline::$type"->make( $self ); | |||
| 80 | 166 | 139 | return; | |||
| 81 | } | |||||
| 82 | ||||||
| 83 | sub _no_unrecognized_parameters { | |||||
| 84 | 217 | 242 | my ( $type, $args ) = @_; | |||
| 85 | 217 | 231 | my $class = "SVG::Sparkline::$type"; | |||
| 86 | 217 217 | 148 471 | foreach my $parm (keys %{$args}) { | |||
| 87 | 406 | 1026 | croak "Parameter '$parm' not recognized for '$type'\n" | |||
| 88 | unless exists $valid_parms{$parm} || $class->valid_param( $parm ); | |||||
| 89 | } | |||||
| 90 | 217 | 252 | return; | |||
| 91 | } | |||||
| 92 | ||||||
| 93 | sub _validate_pos_param | |||||
| 94 | { | |||||
| 95 | 856 | 690 | my ($self, $name, $default) = @_; | |||
| 96 | 856 | 1974 | croak "'$name' must have a positive numeric value.\n" | |||
| 97 | if exists $self->{$name} && $self->{$name} <= 0; | |||||
| 98 | 850 | 874 | return if exists $self->{$name}; | |||
| 99 | ||||||
| 100 | 819 | 929 | $self->{$name} = $default if defined $default; | |||
| 101 | 819 | 589 | return; | |||
| 102 | } | |||||
| 103 | ||||||
| 104 | sub _validate_nonneg_param | |||||
| 105 | { | |||||
| 106 | 421 | 353 | my ($self, $name, $default) = @_; | |||
| 107 | 421 | 861 | croak "'$name' must be a non-negative numeric value.\n" | |||
| 108 | if exists $self->{$name} && $self->{$name} < 0; | |||||
| 109 | 419 | 450 | return if exists $self->{$name}; | |||
| 110 | ||||||
| 111 | 397 | 629 | $self->{$name} = $default if defined $default; | |||
| 112 | 397 | 259 | return; | |||
| 113 | } | |||||
| 114 | ||||||
| 115 | sub _validate_mark_param | |||||
| 116 | { | |||||
| 117 | 209 | 179 | my ($self) = @_; | |||
| 118 | ||||||
| 119 | 209 | 288 | return unless exists $self->{mark}; | |||
| 120 | ||||||
| 121 | 84 | 199 | croak "'mark' parameter must be an array reference.\n" | |||
| 122 | unless 'ARRAY' eq ref $self->{mark}; | |||||
| 123 | 83 | 240 | croak "'mark' array parameter must have an even number of elements.\n" | |||
| 124 | 83 | 54 | unless 0 == (@{$self->{mark}}%2); | |||
| 125 | ||||||
| 126 | 82 82 | 54 126 | my @marks = @{$self->{mark}}; | |||
| 127 | 82 | 106 | while(@marks) | |||
| 128 | { | |||||
| 129 | 84 | 118 | my ($index, $color) = splice( @marks, 0, 2 ); | |||
| 130 | 84 | 1072 | croak "'$index' is not a valid mark index.\n" | |||
| 131 | unless $index =~ /^(?:first|last|high|low|\d+)$/; | |||||
| 132 | 77 | 91 | croak "'$color' is not a valid mark color.\n" | |||
| 133 | unless _is_color( $color ); | |||||
| 134 | } | |||||
| 135 | 74 | 86 | return; | |||
| 136 | } | |||||
| 137 | ||||||
| 138 | sub _is_color | |||||
| 139 | { | |||||
| 140 | 310 | 71166 | my ($color) = @_; | |||
| 141 | 310 | 752 | return 1 if $color =~ /^#[[:xdigit:]]{3}$/; | |||
| 142 | 101 | 119 | return 1 if $color =~ /^#[[:xdigit:]]{6}$/; | |||
| 143 | 99 | 127 | return 1 if $color =~ /^rgb\(\d+,\d+,\d+\)$/; | |||
| 144 | 98 | 119 | return 1 if $color =~ /^rgb\(\d+%,\d+%,\d+%\)$/; | |||
| 145 | 97 | 303 | return 1 if $color =~ /^[[:alpha:]]+$/; | |||
| 146 | 18 | 355 | return; | |||
| 147 | } | |||||
| 148 | ||||||
| 149 | 1; # Magic true value required at end of module | |||||