Imager-Graph
view release on metacpan or search on metacpan
lib/Imager/Graph/Pie.pm view on Meta::CPAN
my @others;
my $index = 0;
for my $item (@$data) {
if ($item / $total < $self->{_style}{pie}{maxsegment}) {
push(@others, $index);
}
++$index;
}
if (@others) {
my $others = 0;
for my $index (reverse @others) {
$others += $data->[$index];
splice(@$labels, $index, 1);
splice(@$data, $index, 1);
}
push(@$labels, $self->{_style}{otherlabel}) if @$labels;
push(@$data, $others);
}
}
# used for debugging
sub _test_line {
my ($x, $y, @l) = @_;
my $res = $l[0]*$x + $l[1] * $y + $l[2];
print "test ", (abs($res) < 0.000001) ? "success\n" : "failure $res\n";
}
=item _fit_text($cx, $cy, $name, $text, $radius, $begin, $end)
Attempts to fit text into a pie segment with its center at ($cx, $cy)
with the given radius, covering the angles $begin through $end.
Returns a list defining the bounding box of the text if it does fit.
=cut
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)
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;
my $boty = $topy + $tbox[3];
my @lines;
for my $y ($topy, $boty) {
my %entry = ( 'y'=>$y );
$entry{line} = [ line_from_points($tcx, $y, $tcx+1, $y) ];
$entry{left} = -$radius;
$entry{right} = $radius;
for my $angle ($begin, $end) {
my $ex = $cx + cos($angle)*$radius;
my $ey = $cy + sin($angle)*$radius;
my @line = line_from_points($cx, $cy, $ex, $ey);
#_test_line($cx, $cy, @line);
#_test_line($ex, $ey, @line);
my $goodsign = $line[0] * $tcx + $line[1] * $tcy + $line[2];
for my $pos (@entry{qw/left right/}) {
my $sign = $line[0] * ($pos+$tcx) + $line[1] * $y + $line[2];
if ($goodsign * $sign < 0) {
if (my @p = intersect_lines(@line, @{$entry{line}})) {
# die "$goodsign $sign ($pos, $tcx) no intersect (@line) (@{$entry{line}})" ; # this would be wierd
#_test_line(@p, @line);
#_test_line(@p, @{$entry{line}});
$pos = $p[0]-$tcx;
}
else {
return;
}
}
# circle
my $dist2 = ($pos+$tcx-$cx) * ($pos+$tcx-$cx)
+ ($y - $cy) * ($y - $cy);
if ($dist2 > $radius * $radius) {
my @points =
intersect_line_and_circle(@{$entry{line}}, $cx, $cy, $radius);
while (@points) {
my @p = splice(@points, 0, 2);
if ($p[0] < $cx && $tcx+$pos < $p[0]) {
$pos = $p[0]-$tcx;
}
elsif ($p[0] > $cx && $tcx+$pos > $p[0]) {
$pos = $p[0]-$tcx;
}
}
}
}
}
push(@lines, \%entry);
}
my $left = $lines[0]{left} > $lines[1]{left} ? $lines[0]{left} : $lines[1]{left};
my $right = $lines[0]{right} < $lines[1]{right} ? $lines[0]{right} : $lines[1]{right};
return if $right - $left < $tbox[2];
return ($tcx+$left, $topy, $tcx+$right, $boty);
}
sub _composite {
( 'pie', $_[0]->SUPER::_composite() );
}
sub _style_defs {
my ($self) = @_;
my %work = %{$self->SUPER::_style_defs()};
$work{otherlabel} = "(others)";
$work{pie} =
{
guessfactor=>0.6,
size=>0.8,
maxsegment=> 0.01,
};
\%work;
}
1;
__END__
=back
( run in 0.689 second using v1.01-cache-2.11-cpan-71847e10f99 )