font handling fixes
authorTony Cook <tony@develop-help.com>
Mon, 16 Mar 2009 09:54:50 +0000 (09:54 +0000)
committerTony Cook <tony@develop-help.com>
Mon, 16 Mar 2009 09:54:50 +0000 (09:54 +0000)
data validation fixes

untabify

Graph.pm
lib/Imager/Graph/Pie.pm
t/t10pie.t

index 93e05f8c1a3e4c061f49c6adf0cb26587b8f12ed..0f7b05c450f92d117d0d2ab1da6d79eb5b7e9440 100644 (file)
--- a/Graph.pm
+++ b/Graph.pm
@@ -542,11 +542,11 @@ relationships between the colors of various elements, for example the
 default style information contains:
 
    text=>{
-         color=>'lookup(fg)',
+          color=>'lookup(fg)',
           ...
          },
    legend =>{
-            color=>'lookup(text.color)',
+             color=>'lookup(text.color)',
              ...
             },
 
@@ -619,49 +619,49 @@ my %style_defs =
    back=> 'lookup(bg)',
    line=> 'lookup(fg)',
    text=>{
-         color => 'lookup(fg)',
+          color => 'lookup(fg)',
           font  => 'lookup(font)',
-         size  => 14,
-        },
+          size  => 14,
+         },
    title=>{ 
-          color  => 'lookup(text.color)', 
+           color  => 'lookup(text.color)', 
            font   => 'lookup(text.font)',
-          halign => 'center', 
-          valign => 'top',
-          size   => 'scale(text.size,2.0)',
-         },
+           halign => 'center', 
+           valign => 'top',
+           size   => 'scale(text.size,2.0)',
+          },
    legend =>{
-            color          => 'lookup(text.color)',
+             color          => 'lookup(text.color)',
              font           => 'lookup(text.font)',
-            size           => 'lookup(text.size)',
-            patchsize      => 'scale(legend.size,0.9)',
-            patchgap       => 'scale(legend.patchsize,0.3)',
-            patchborder    => 'lookup(line)',
-            halign         => 'right',
-            valign         => 'top',
-            padding        => 'scale(legend.size,0.3)',
-            outsidepadding => 'scale(legend.padding,0.4)',
-           },
+             size           => 'lookup(text.size)',
+             patchsize      => 'scale(legend.size,0.9)',
+             patchgap       => 'scale(legend.patchsize,0.3)',
+             patchborder    => 'lookup(line)',
+             halign         => 'right',
+             valign         => 'top',
+             padding        => 'scale(legend.size,0.3)',
+             outsidepadding => 'scale(legend.padding,0.4)',
+            },
    callout => {
-              color    => 'lookup(text.color)',
+               color    => 'lookup(text.color)',
                font     => 'lookup(text.font)',
-              size     => 'lookup(text.size)',
-              line     => 'lookup(line)',
-              inside   => 'lookup(callout.size)',
-              outside  => 'lookup(callout.size)',
-              leadlen  => 'scale(0.8,callout.size)',
-              gap      => 'scale(callout.size,0.3)',
-             },
+               size     => 'lookup(text.size)',
+               line     => 'lookup(line)',
+               inside   => 'lookup(callout.size)',
+               outside  => 'lookup(callout.size)',
+               leadlen  => 'scale(0.8,callout.size)',
+               gap      => 'scale(callout.size,0.3)',
+              },
    label => {
              font          => 'lookup(text.font)',
-            size          => 'lookup(text.size)',
-            color         => 'lookup(text.color)',
+             size          => 'lookup(text.size)',
+             color         => 'lookup(text.color)',
              hpad          => 'lookup(label.pad)',
              vpad          => 'lookup(label.pad)',
              pad           => 'scale(label.size,0.2)',
              pcformat      => sub { sprintf "%s (%.0f%%)", $_[0], $_[1] },
              pconlyformat  => sub { sprintf "%.1f%%", $_[0] },
-            },
+             },
    dropshadow => {
                   fill    => { solid => Imager::Color->new(0, 0, 0, 96) },
                   off     => 'scale(0.4,text.size)',
@@ -778,32 +778,32 @@ my %styles =
      { fountain=>'linear',
        xa_ratio=>0.13, ya_ratio=>0.13, xb_ratio=>0.87, yb_ratio=>0.87,
        segments => Imager::Fountain->simple(positions=>[0, 1],
-                                           colors=>[ NC('FFC0C0'), NC('FF0000') ]),
+                                            colors=>[ NC('FFC0C0'), NC('FF0000') ]),
      },
      { fountain=>'linear',
        xa_ratio=>0, ya_ratio=>0, xb_ratio=>1.0, yb_ratio=>1.0,
        segments => Imager::Fountain->simple(positions=>[0, 1],
-                                           colors=>[ NC('C0FFC0'), NC('00FF00') ]),
+                                            colors=>[ NC('C0FFC0'), NC('00FF00') ]),
      },
      { fountain=>'linear',
        xa_ratio=>0, ya_ratio=>0, xb_ratio=>1.0, yb_ratio=>1.0,
        segments => Imager::Fountain->simple(positions=>[0, 1],
-                                           colors=>[ NC('C0C0FF'), NC('0000FF') ]),
+                                            colors=>[ NC('C0C0FF'), NC('0000FF') ]),
      },
      { fountain=>'linear',
        xa_ratio=>0, ya_ratio=>0, xb_ratio=>1.0, yb_ratio=>1.0,
        segments => Imager::Fountain->simple(positions=>[0, 1],
-                                           colors=>[ NC('FFFFC0'), NC('FFFF00') ]),
+                                            colors=>[ NC('FFFFC0'), NC('FFFF00') ]),
      },
      { fountain=>'linear',
        xa_ratio=>0, ya_ratio=>0, xb_ratio=>1.0, yb_ratio=>1.0,
        segments => Imager::Fountain->simple(positions=>[0, 1],
-                                           colors=>[ NC('C0FFFF'), NC('00FFFF') ]),
+                                            colors=>[ NC('C0FFFF'), NC('00FFFF') ]),
      },
      { fountain=>'linear',
        xa_ratio=>0, ya_ratio=>0, xb_ratio=>1.0, yb_ratio=>1.0,
        segments => Imager::Fountain->simple(positions=>[0, 1],
-                                           colors=>[ NC('FFC0FF'), NC('FF00FF') ]),
+                                            colors=>[ NC('FFC0FF'), NC('FF00FF') ]),
      },
     ],
     back=>{ fountain=>'linear',
@@ -823,32 +823,32 @@ my %styles =
      { fountain=>'radial',
        xa_ratio=>0.5, ya_ratio=>0.5, xb_ratio=>1.0, yb_ratio=>0.5,
        segments => Imager::Fountain->simple(positions=>[0, 1],
-                                           colors=>[ NC('FF8080'), NC('FF0000') ]),
+                                            colors=>[ NC('FF8080'), NC('FF0000') ]),
      },
      { fountain=>'radial',
        xa_ratio=>0.5, ya_ratio=>0.5, xb_ratio=>1.0, yb_ratio=>0.5,
        segments => Imager::Fountain->simple(positions=>[0, 1],
-                                           colors=>[ NC('80FF80'), NC('00FF00') ]),
+                                            colors=>[ NC('80FF80'), NC('00FF00') ]),
      },
      { fountain=>'radial',
        xa_ratio=>0.5, ya_ratio=>0.5, xb_ratio=>1.0, yb_ratio=>0.5,
        segments => Imager::Fountain->simple(positions=>[0, 1],
-                                           colors=>[ NC('808080FF'), NC('0000FF') ]),
+                                            colors=>[ NC('808080FF'), NC('0000FF') ]),
      },
      { fountain=>'radial',
        xa_ratio=>0.5, ya_ratio=>0.5, xb_ratio=>1.0, yb_ratio=>0.5,
        segments => Imager::Fountain->simple(positions=>[0, 1],
-                                           colors=>[ NC('FFFF80'), NC('FFFF00') ]),
+                                            colors=>[ NC('FFFF80'), NC('FFFF00') ]),
      },
      { fountain=>'radial',
        xa_ratio=>0.5, ya_ratio=>0.5, xb_ratio=>1.0, yb_ratio=>0.5,
        segments => Imager::Fountain->simple(positions=>[0, 1],
-                                           colors=>[ NC('80FFFF'), NC('00FFFF') ]),
+                                            colors=>[ NC('80FFFF'), NC('00FFFF') ]),
      },
      { fountain=>'radial',
        xa_ratio=>0.5, ya_ratio=>0.5, xb_ratio=>1.0, yb_ratio=>0.5,
        segments => Imager::Fountain->simple(positions=>[0, 1],
-                                           colors=>[ NC('FF80FF'), NC('FF00FF') ]),
+                                            colors=>[ NC('FF80FF'), NC('FF00FF') ]),
      },
     ],
     back=>{ fountain=>'linear',
@@ -897,7 +897,7 @@ sub _style_setup {
         }
       }
       else {
-       $work{$key} = $src->{$key};
+        $work{$key} = $src->{$key};
       }
     }
   }
@@ -1011,23 +1011,23 @@ sub _get_number {
   else {
     if ($what =~ /^lookup\(([\w.]+)\)$/) {
       @depth < MAX_DEPTH
-       or return $self->_error("too many levels of recursion in lookup (@depth)");
+        or return $self->_error("too many levels of recursion in lookup (@depth)");
       return $self->_get_number($1, @depth);
     }
     elsif ($what =~ /^scale\(
-                   ((?:[a-z][\w.]*)|$NUM_RE)
+                    ((?:[a-z][\w.]*)|$NUM_RE)
                     ,
-                   ((?:[a-z][\w.]*)|$NUM_RE)\)$/x) {
+                    ((?:[a-z][\w.]*)|$NUM_RE)\)$/x) {
       my ($left, $right) = ($1, $2);
       unless ($left =~ /^$NUM_RE$/) {
-       @depth < MAX_DEPTH 
-         or return $self->_error("too many levels of recursion in scale (@depth)");
-       $left = $self->_get_number($left, @depth);
+        @depth < MAX_DEPTH 
+          or return $self->_error("too many levels of recursion in scale (@depth)");
+        $left = $self->_get_number($left, @depth);
       }
       unless ($right =~ /^$NUM_RE$/) {
-       @depth < MAX_DEPTH 
-         or return $self->_error("too many levels of recursion in scale (@depth)");
-       $right = $self->_get_number($right, @depth);
+        @depth < MAX_DEPTH 
+          or return $self->_error("too many levels of recursion in scale (@depth)");
+        $right = $self->_get_number($right, @depth);
       }
       return $left * $right;
     }
@@ -1085,7 +1085,7 @@ sub _get_color {
   unless (ref $what) {
     if ($what =~ /^lookup\((\w+(?:\.\w+)?)\)$/) {
       @depth < MAX_DEPTH or
-       return $self->_error("too many levels of recursion in lookup (@depth)");
+        return $self->_error("too many levels of recursion in lookup (@depth)");
 
       return $self->_get_color($1, @depth);
     }
@@ -1121,33 +1121,33 @@ sub _translate_fill {
       # default to normal combine mode
       my %work = ( combine => 'normal', %$what );
       if ($what->{hatch}) {
-       if (!$work{fg}) {
-         $work{fg} = $self->_get_color('fg')
-           or return;
-       }
-       if (!$work{bg}) {
-         $work{bg} = $self->_get_color('bg')
-           or return;
-       }
-       return ( fill=>\%work );
+        if (!$work{fg}) {
+          $work{fg} = $self->_get_color('fg')
+            or return;
+        }
+        if (!$work{bg}) {
+          $work{bg} = $self->_get_color('bg')
+            or return;
+        }
+        return ( fill=>\%work );
       }
       elsif ($what->{fountain}) {
-       for my $key (qw(xa ya xb yb)) {
-         if (exists $work{"${key}_ratio"}) {
-           if ($key =~ /^x/) {
-             $work{$key} = $box->[0] + $work{"${key}_ratio"} 
-               * ($box->[2] - $box->[0]);
-           }
-           else {
-             $work{$key} = $box->[1] + $work{"${key}_ratio"} 
-               * ($box->[3] - $box->[1]);
-           }
-         }
-       }
-       return ( fill=>\%work );
+        for my $key (qw(xa ya xb yb)) {
+          if (exists $work{"${key}_ratio"}) {
+            if ($key =~ /^x/) {
+              $work{$key} = $box->[0] + $work{"${key}_ratio"} 
+                * ($box->[2] - $box->[0]);
+            }
+            else {
+              $work{$key} = $box->[1] + $work{"${key}_ratio"} 
+                * ($box->[3] - $box->[1]);
+            }
+          }
+        }
+        return ( fill=>\%work );
       }
       else {
-       return ( fill=> \%work );
+        return ( fill=> \%work );
       }
     }
   }
@@ -1276,7 +1276,7 @@ sub _text_bbox {
     or return;
 
   my @bbox = $text_info{font}->bounding_box(%text_info, string=>$text,
-                                           canon=>1);
+                                            canon=>1);
 
   return @bbox[0..3];
 }
@@ -1344,7 +1344,7 @@ sub _remove_box {
 
   if ($areay < $areax) {
     if ($object_box->[1] - $chart_box->[1] 
-       < $chart_box->[3] - $object_box->[3]) {
+        < $chart_box->[3] - $object_box->[3]) {
       $chart_box->[1] = $object_box->[3];
     }
     else {
@@ -1353,7 +1353,7 @@ sub _remove_box {
   }
   else {
     if ($object_box->[0] - $chart_box->[0] 
-       < $chart_box->[2] - $object_box->[2]) {
+        < $chart_box->[2] - $object_box->[2]) {
       $chart_box->[0] = $object_box->[2];
     }
     else {
@@ -1406,8 +1406,8 @@ sub _draw_legend_horizontal {
     }
     else {
       if ($pos + $gap + $entry_width > $chart_box->[2]) {
-       $pos = 0;
-       $height += $row_height;
+        $pos = 0;
+        $height += $row_height;
       }
       push @offsets, [ $pos, $height ];
     }
@@ -1434,7 +1434,7 @@ sub _draw_legend_horizontal {
               ymin=>$box[1]+$outsidepadding, 
               xmax=>$box[2]-$outsidepadding, 
               ymax=>$box[3]-$outsidepadding,
-            $self->_get_fill('legend.fill', \@box));
+             $self->_get_fill('legend.fill', \@box));
   }
   $box[0] += $outsidepadding;
   $box[1] += $outsidepadding;
@@ -1459,11 +1459,11 @@ sub _draw_legend_horizontal {
     my @fill = $self->_data_fill($dataindex, \@patchbox)
       or return;
     $img->box(xmin=>$left, ymin=>$top, xmax=>$left + $patchsize,
-              ymax=>$top + $patchsize, @fill);
+               ymax=>$top + $patchsize, @fill);
     if ($self->{_style}{legend}{patchborder}) {
       $img->box(xmin=>$left, ymin=>$top, xmax=>$left + $patchsize,
-               ymax=>$top + $patchsize,
-               color=>$patchborder);
+                ymax=>$top + $patchsize,
+                color=>$patchborder);
     }
     $img->string(%text_info, x=>$textpos, 'y'=>$top + $patchsize, 
                  text=>$label);
@@ -1474,7 +1474,7 @@ sub _draw_legend_horizontal {
     my $border_color = $self->_get_color('legend.border')
       or return;
     $img->box(xmin=>$box[0], ymin=>$box[1], xmax=>$box[2], ymax=>$box[3],
-             color=>$border_color);
+              color=>$border_color);
   }
   $self->_remove_box($chart_box, \@box);
   1;
@@ -1505,8 +1505,8 @@ sub _draw_legend_vertical {
     }
   }
   my @box = (0, 0, 
-            $width + $patchsize + $padding * 2 + $gap,
-            $height + $padding * 2 - $gap);
+             $width + $patchsize + $padding * 2 + $gap,
+             $height + $padding * 2 - $gap);
   my $outsidepadding = 0;
   if ($self->{_style}{legend}{border}) {
     defined($outsidepadding = $self->_get_integer('legend.outsidepadding'))
@@ -1521,7 +1521,7 @@ sub _draw_legend_vertical {
               ymin=>$box[1]+$outsidepadding, 
               xmax=>$box[2]-$outsidepadding, 
               ymax=>$box[3]-$outsidepadding,
-            $self->_get_fill('legend.fill', \@box));
+             $self->_get_fill('legend.fill', \@box));
   }
   $box[0] += $outsidepadding;
   $box[1] += $outsidepadding;
@@ -1544,11 +1544,11 @@ sub _draw_legend_vertical {
     my @fill = $self->_data_fill($dataindex, \@patchbox)
       or return;
     $img->box(xmin=>$patchpos, ymin=>$ypos, xmax=>$patchpos + $patchsize,
-              ymax=>$ypos + $patchsize, @fill);
+               ymax=>$ypos + $patchsize, @fill);
     if ($self->{_style}{legend}{patchborder}) {
       $img->box(xmin=>$patchpos, ymin=>$ypos, xmax=>$patchpos + $patchsize,
-               ymax=>$ypos + $patchsize,
-               color=>$patchborder);
+                ymax=>$ypos + $patchsize,
+                color=>$patchborder);
     }
     $img->string(%text_info, x=>$textpos, 'y'=>$ypos + $patchsize, 
                  text=>$label);
@@ -1566,7 +1566,7 @@ sub _draw_legend_vertical {
     my $border_color = $self->_get_color('legend.border')
       or return;
     $img->box(xmin=>$box[0], ymin=>$box[1], xmax=>$box[2], ymax=>$box[3],
-             color=>$border_color);
+              color=>$border_color);
   }
   $self->_remove_box($chart_box, \@box);
   1;
index dcba2ae5a0f5dfec0f5af3fe80a681436e090693..23ea92d58083862eb0f61d59f70e60b5875401e9 100644 (file)
@@ -11,8 +11,8 @@ package Imager::Graph::Pie;
   my $chart = Imager::Graph::Pie->new;
   # see Imager::Graph for options
   my $img = $chart->draw(
-                        data => [ $first_amount, $second_amount ],
-                        size => 350);
+                         data => [ $first_amount, $second_amount ],
+                         size => 350);
 
 =head1 DESCRIPTION
 
@@ -179,13 +179,11 @@ and a title, but move the legend down, and add a dropshadow:
 
 something a bit prettier:
 
-  # requires Imager > 0.38
   $img = $pie->draw(data=>\@data, labels=>\@labels,
                     style=>'fount_lin', features=>'legend');
 
 suitable for monochrome output:
 
-  # requires Imager > 0.38
   $img = $pie->draw(data=>\@data, labels=>\@labels,
                     style=>'mono', features=>'legend');
 
@@ -197,10 +195,26 @@ sub draw {
 
   $opts{data} 
     or return $self->_error("No data parameter supplied");
-  my @data = @{$opts{data}};
+  my @data = @{$opts{data}}
+    or return $self->_error("No values in the data parameter");
   my @labels;
   @labels = @{$opts{labels}} if $opts{labels};
 
+  my $total = 0;
+  {
+    my $index = 0;
+    for my $item (@data) {
+      $item < 0
+        and return $self->_error("Data index $index is less than zero");
+      
+      $total += $item;
+      
+      ++$index;
+    }
+  }
+  $total == 0
+    and return $self->_error("Sum of all data values is zero");
+
   $self->_style_setup(\%opts);
 
   my $style = $self->{_style};
@@ -208,11 +222,6 @@ sub draw {
   my $img = $self->_make_img()
     or return;
 
-  my $total = 0;
-  for my $item (@data) {
-    $total += $item;
-  }
-
   my @chart_box = ( 0, 0, $img->getwidth-1, $img->getheight-1 );
   if ($style->{title}{text}) {
     $self->_draw_title($img, \@chart_box)
@@ -272,33 +281,35 @@ sub draw {
       elsif ($style->{features}{labels}) {
         $item->{label} = 1;
       }
-      my @lbox = $self->_text_bbox($item->{text}, 'label')
-       or return;
-      $item->{lbox} = \@lbox;
-      if ($item->{label}) {
-        unless ($self->_fit_text(0, 0, 'label', $item->{text}, $guessradius,
-                                 $item->{begin}, $item->{end})) {
-          $item->{callout} = 1;
+      $item->{callout} = 1 if $style->{features}{allcallouts};
+      if (!$item->{callout}) {
+        my @lbox = $self->_text_bbox($item->{text}, 'label')
+          or return;
+        $item->{lbox} = \@lbox;
+        if ($item->{label}) {
+          unless ($self->_fit_text(0, 0, 'label', $item->{text}, $guessradius,
+                                   $item->{begin}, $item->{end})) {
+            $item->{callout} = 1;
+          }
         }
       }
-      $item->{callout} = 1 if $style->{features}{allcallouts};
       if ($item->{callout}) {
         $item->{label} = 0;
-       my @cbox = $self->_text_bbox($item->{text}, 'callout')
-         or return;
-       $item->{cbox} = \@cbox;
-       $item->{cangle} = ($item->{begin} + $item->{end}) / 2;
-       my $dist = cos($item->{cangle}) * ($guessradius+
+        my @cbox = $self->_text_bbox($item->{text}, 'callout')
+          or return;
+        $item->{cbox} = \@cbox;
+        $item->{cangle} = ($item->{begin} + $item->{end}) / 2;
+        my $dist = cos($item->{cangle}) * ($guessradius+
                                            $callout_outside);
-       my $co_size = $callout_leadlen + $callout_gap + $item->{cbox}[2];
-       if ($dist < 0) {
-         $dist -= $co_size - $guessradius;
-         $dist < $ebox[0] and $ebox[0] = $dist;
-       }
-       else {
-         $dist += $co_size - $guessradius;
-         $dist > $ebox[2] and $ebox[2] = $dist;
-       }
+        my $co_size = $callout_leadlen + $callout_gap + $item->{cbox}[2];
+        if ($dist < 0) {
+          $dist -= $co_size - $guessradius;
+          $dist < $ebox[0] and $ebox[0] = $dist;
+        }
+        else {
+          $dist += $co_size - $guessradius;
+          $dist > $ebox[2] and $ebox[2] = $dist;
+        }
       }
     }
     push(@info, $item);
@@ -349,28 +360,32 @@ sub draw {
       my $px = int($cx + $radius * cos($item->{begin}));
       my $py = int($cy + $radius * sin($item->{begin}));
       $item->{begin} < $item->{end}
-       or next;
+        or next;
       $img->line(x1=>$cx, y1=>$cy, x2=>$px, y2=>$py, color=>$outcolor);
       for (my $i = $item->{begin}; $i < $item->{end}; $i += PI/180) {
-       my $stroke_end = $i + PI/180;
-       $stroke_end = $item->{end} if $stroke_end > $item->{end};
-       my $nx = int($cx + $radius * cos($stroke_end));
-       my $ny = int($cy + $radius * sin($stroke_end));
-       $img->line(x1=>$px, y1=>$py, x2=>$nx, y2=>$ny, color=>$outcolor,
-                 antialias=>1);
-       ($px, $py) = ($nx, $ny);
+        my $stroke_end = $i + PI/180;
+        $stroke_end = $item->{end} if $stroke_end > $item->{end};
+        my $nx = int($cx + $radius * cos($stroke_end));
+        my $ny = int($cy + $radius * sin($stroke_end));
+        $img->line(x1=>$px, y1=>$py, x2=>$nx, y2=>$ny, color=>$outcolor,
+                  antialias=>1);
+        ($px, $py) = ($nx, $ny);
       }
     }
   }
 
   my $callout_inside = $radius - $self->_get_number('callout.inside');
   $callout_outside += $radius;
-  my %callout_text = $self->_text_style('callout')
-    or return;
-  my %label_text = $self->_text_style('label')
-    or return;
+  my %callout_text;
+  my %label_text;
   for my $label (@info) {
-    if ($label->{label}) {
+    if ($label->{label} && !$label->{callout}) {
+      # at this point we know we need the label font, to calculate
+      # whether the label will fit if anything else
+      unless (%label_text) {
+        %label_text = $self->_text_style('label')
+          or return;
+      }
       my @loc = $self->_fit_text($cx, $cy, 'label', $label->{text}, $radius,
                                  $label->{begin}, $label->{end});
       if (@loc) {
@@ -384,31 +399,35 @@ sub draw {
       }
       else {
         $label->{callout} = 1;
-       my @cbox = $self->_text_bbox($label->{text}, 'callout')
-         or return;
+        my @cbox = $self->_text_bbox($label->{text}, 'callout')
+          or return;
         $label->{cbox} = \@cbox; 
         $label->{cangle} = ($label->{begin} + $label->{end}) / 2;
       }
     }
     if ($label->{callout}) {
+      unless (%callout_text) {
+        %callout_text = $self->_text_style('callout')
+          or return;
+      }
       my $ix = floor(0.5 + $cx + $callout_inside * cos($label->{cangle}));
       my $iy = floor(0.5 + $cy + $callout_inside * sin($label->{cangle}));
       my $ox = floor(0.5 + $cx + $callout_outside * cos($label->{cangle}));
       my $oy = floor(0.5 + $cy + $callout_outside * sin($label->{cangle}));
       my $lx = ($ox < $cx) ? $ox - $callout_leadlen : $ox + $callout_leadlen;
       $img->line(x1=>$ix, y1=>$iy, x2=>$ox, y2=>$oy, antialias=>1,
-                color=>$self->_get_color('callout.color'));
+                 color=>$self->_get_color('callout.color'));
       $img->line(x1=>$ox, y1=>$oy, x2=>$lx, y2=>$oy, antialias=>1,
-                color=>$self->_get_color('callout.color'));
+                 color=>$self->_get_color('callout.color'));
       #my $tx = $lx + $callout_gap;
       my $ty = $oy + $label->{cbox}[3]/2+$label->{cbox}[1];
       if ($lx < $cx) {
-       $img->string(%callout_text, x=>$lx-$callout_gap-$label->{cbox}[2], 
-                    'y'=>$ty, text=>$label->{text});
+        $img->string(%callout_text, x=>$lx-$callout_gap-$label->{cbox}[2], 
+                     'y'=>$ty, text=>$label->{text});
       }
       else {
-       $img->string(%callout_text, x=>$lx+$callout_gap, 'y'=>$ty, 
-                    text=>$label->{text});
+        $img->string(%callout_text, x=>$lx+$callout_gap, 'y'=>$ty, 
+                     text=>$label->{text});
       }
     }
   }
@@ -473,7 +492,8 @@ sub _fit_text {
   my ($self, $cx, $cy, $name, $text, $radius, $begin, $end) = @_;
 
   #print "fit: $cx, $cy '$text' $radius $begin $end\n";
-  my @tbox = $self->_text_bbox($text, $name);
+  my @tbox = $self->_text_bbox($text, $name)
+    or return;
   my $tcx = floor(0.5+$cx + cos(($begin+$end)/2) * $radius *3/5);
   my $tcy = floor(0.5+$cy + sin(($begin+$end)/2) * $radius *3/5);
   my $topy = $tcy - $tbox[3]/2;
index 7e3d61c0d9ade9123ef924cbb4c1fc740ec8ae11..21341f946d47297b0e35661112317cff456f8ab4 100644 (file)
@@ -21,7 +21,7 @@ my $font = Imager::Font::Test->new();
 my @data = ( 100, 180, 80, 20, 2, 1, 0.5 );
 my @labels = qw(alpha beta gamma delta epsilon phi gi);
 
-plan tests => 26;
+plan tests => 34;
 
 my $pie = Imager::Graph::Pie->new;
 ok($pie, "creating pie chart object");
@@ -166,20 +166,57 @@ cmpimg($img6, "testimg/t10_hlegend.png", 550_000);
   ok(!$im, "should fail to produce labelled graph with no font");
   like($pie->error, qr/label\.font/, "message should mention which font");
 
- SKIP: 
-  {
-    $font
-      or skip("No font to setup the callout font", 2);
-    $im = $pie->draw
-      (
-       data => \@data,
-       labels => \@labels,
-       features => [ 'allcallouts' ],
-       label => { font => $font },
-      );
-    ok(!$im, "should fail to produce callout labelled graph with no font");
-    like($pie->error, qr/callout\.font/, "message should mention which font");
-  }
+  $im = $pie->draw
+    (
+     data => \@data,
+     labels => \@labels,
+     features => [ 'allcallouts' ],
+     label => { font => $font },
+    );
+  ok(!$im, "should fail to produce callout labelled graph with no font");
+  like($pie->error, qr/callout\.font/, "message should mention which font");
+
+  # shouldn't need to set label font if doing all callouts
+  $im = $pie->draw
+    (
+     data => \@data,
+     labels => \@labels,
+     features => [ 'allcallouts' ],
+     callout => { font => $font },
+    );
+  ok($im, "should produce callout labelled graph with only callout font")
+    or print "# ", $pie->error, "\n";
+
+  # shouldn't need to set callout font if doing all labels
+  $im = $pie->draw
+    (
+     data => [ 1, 1, 1 ],
+     labels => [ qw/a b c/ ],
+     label => { font => $font }
+    );
+  ok($im, "should produce label only graph with only label font");
+}
+
+{
+  # draw with an empty data array is bad
+  # problem reported and fixed by Patrick Michaud
+  my $im = $pie->draw(data => []);
+  ok(!$im, "fail to draw with empty data");
+  like($pie->error, qr/No values/, "message appropriate");
+}
+
+{ # pie charts can't represent negative values
+  # problem reported and fixed by Patrick Michaud
+  my $im = $pie->draw(data => [ 10, -1, 10 ]);
+  ok(!$im, "fail to draw with negative value");
+  is($pie->error, "Data index 1 is less than zero", "check message");
+}
+
+{ # pie can't represent all zeros
+  # problem reported and fixed by Patrick Michaud
+  my $im = $pie->draw(data => [ 0, 0, 0 ]);
+  ok(!$im, "fail to draw with all zero values");
+  is($pie->error, "Sum of all data values is zero", "check message");
 }
 
 sub cmpimg {