SVGGraph::Pie - Perl extension for Pie as SVG


SVGGraph-Pie documentation Contained in the SVGGraph-Pie distribution.

Index


Code Index:

NAME

Top

SVGGraph::Pie - Perl extension for Pie as SVG

SYNOPSIS

Top

  use SVGGraph::Pie;

  my $svggraph = SVGGraph::Pie->new;
  $svggraph->CreateGraph(
      {
          imageheight => 500,
          imagewidth  => 500,
          centertop  => 250,
          centerleft => 250,
          radius => 200,
          title => 'Financial Results Q1 2002',
          titlestyle => 'font-size:24;fill:#FF0000;',
          borderwidth => 4, # border line's width
          label => 'true',  # Woud you like display label?
          labeltop  => '100',
          labelleft => '400',
      },
      [
          {value => 10, color => 'red'},
          {value => 20, color => 'blue'),
          ...
          ..
          .
      ],
  );

DESCRIPTION

Top

SVGGraph::Pie allow you to create Piegraphs as SVG very easily.

EXAMPLES

Top

  #!/usr/bin/perl -w

  use strict;
  use SVGGraph::Pie;

  my @values = [
      {value => 11, color => 'red'},
      {value => 23, color => 'rgb(200,0,0)'},
      {value => 39, color => 'rgb(150,0,0)'},
      {value => 13, color => 'rgb(100,0,0)'},
      {value => 44, color => 'rgb(100,0,50)'},
      {value => 50, color => 'rgb(50,0,100)'},
      {value => 60, color => 'rgb(0,0,100)'},
      {value => 12, color => 'rgb(0,0,150)'},
      {value => 39, color => 'rgb(0,0,200)'},
  ];

  my $svggraph = SVGGraph::Pie->new;

  print "Content-type: image/svg-xml\n\n";
  print $svggraph->CreateGraph(
      {
          imageheight => 500,
          imagewidth  => 1000,
          radius => 200,
          title => 'Financial Results Q1 2002',
          titlestyle => 'font-size:24;fill:#FF0000;',
          borderwidth => 4,
          label => 'true',
      },
      \@values,
  );




AUTHOR

Top

milano <milano@cpan.org>

SEE ALSO

Top

SVG, SVGGraph


SVGGraph-Pie documentation Contained in the SVGGraph-Pie distribution.

package SVGGraph::Pie;

use strict;
use vars qw($VERSION);
$VERSION = '0.05';
use constant PI  => '3.141592654';
use constant GAP => 15;

use SVG;

sub _croak { require Carp; Carp::croak(@_) }
sub _carp  { require Carp; Carp::carp(@_)  }

sub new {
    my $self = shift;
    return bless {}, $self;
}

sub CreateGraph {
    my $self    = shift;
    my $options = shift;

    ## The rest are references to arrays of values, colors, lables
    my $values = shift;

    my $start;
    my @labelcolors;

    ## Option default settings
    my $imageheight = 500;
    my $imagewidth  = 500;
    my $radius      = 180;
    $imageheight = $$options{imageheight} if $$options{imageheight};
    $imagewidth  = $$options{imagewidth}  if $$options{imagewidth};
    $radius      = $$options{radius}      if $$options{radius};

    my $cx = int($imagewidth  / 2) - 50;
    my $cy = int($imageheight / 2);
    $cx = $$options{centerleft} if $$options{centerleft};
    $cy = $$options{centertop}  if $$options{centertop};

    my $borderwidth = 4;
    $borderwidth = $$options{borderwidth} if $$options{borderwidth};

    ## Calc total
    my $total;
    foreach (@$values) {
	$total += $_->{value};
    }

    ## Create SVG Object
    my $svg = SVG->new(
	width  => $imageheight,
	height => $imageheight,
	title  => ($$options{title} ? $$options{title} : ''),
    );

    ## Draw Lines
    $start = -90;

    my @separator_lines;
    my $pie = $svg->tag('g', id => "pie_chart", transform => "translate($cx,$cy)");

    for (my $i = 0; $i < @$values; $i++) {
	my $slice   = $values->[$i]->{value} / $total * 360;

	my $color = $values->[$i]->{color};
	if ($color eq "") {
	    $color = sprintf 'rgb(%d,%d,%d)',
		int(rand(256)), int(rand(256)), int(rand(256));
	}
	push @labelcolors, $color;

	my $do_arc = 0;
	my $radians = $slice * PI / 180;
	$do_arc++  if $slice > 180;

	my $ry = ($radius * sin($radians));
	my $rx = $radius * cos($radians);
	push(@separator_lines, $rx, $ry, $start);

	my $g = $pie->tag('g', id => "wedge_$i", transform => "rotate($start)");
	$g->path(
	    style => {'fill' => "$color"},
	    d => "M $radius,0 A $radius,$radius 0 $do_arc,1 $rx,$ry L 0,0 z"
	);

	$start += $slice;
    }

    ## Draw circle
    $svg->circle(
	cx => $cx,
	cy => $cy,
	r  => $radius,
	style => {
	    'stroke' => 'black',
	    'stroke-width' => $borderwidth,
	    'fill-opacity' => 0,
	},
    );

    ## Draw separater
    my $i = 0;
    while (my $start = pop(@separator_lines)) {
	$i++;
	my $separator_y = pop(@separator_lines);
	my $separator_x = pop(@separator_lines);
	my $g = $pie->tag('g', id => "line_$i", transform => "rotate($start)");
	$g->line(
	    x1 => 0,
	    y1 => 0,
	    x2 => $separator_x,
	    y2 => $separator_y,
	    style => {
		'stroke' => 'black',
		'stroke-width' => $borderwidth
	    },
	);
    }

    ## Title
    if ($$options{title}) {
	my $titlestyle = 'font-size:24;';
	$titlestyle = $$options{titlestyle} if $$options{titlestyle};
	$svg->text(
	    'x' => 20,
	    'y' => 40,
	    'style' => $titlestyle,
	)->cdata($$options{title});
    }

    ## Label
    if ($$options{label}) {
	my $labelleft = $cx + $radius + 10;
	$labelleft = $$options{labelleft} if $$options{labelleft};
	$start = $cy - $radius;
	$start = $$options{labeltop} if $$options{labeltop};

	for (my $i = 0; $i < @$values; $i++) {
	    $svg->rectangle(
		'x' => $labelleft,
		'y' => $start,
		'width' => 20,
		'height' => 20,
		'rx' => 5,
		'ry' => 5,
		'style' => {
		    fill => $labelcolors[$i],
		    stroke => 'black',
		},
	    );
	    $svg->text(
		'x' => $labelleft + 25,
		'y' => $start + GAP,
	    )->cdata($values->[$i]->{label});

	    $start += 25;
	}
    }

    return $svg->xmlify;
}

## private method
sub _round {
    my $decimal = shift;

    $decimal *= 10;
    $decimal = int($decimal + 0.5);
    $decimal /= 10;

    return $decimal;
}

1;
__END__