Graph-ChartSVG
view release on metacpan or search on metacpan
lib/Graph/ChartSVG.pm view on Meta::CPAN
package Graph::ChartSVG::Layer;
use Moose;
has 'data' => ( isa => 'Graph::ChartSVG::Data', is => 'rw', required => 0 );
has 'glyph' => ( isa => 'Graph::ChartSVG::Glyph', is => 'rw', required => 0 );
has 'overlay' => ( isa => 'Graph::ChartSVG::Overlay', is => 'rw', required => 0 );
1;
package Graph::ChartSVG::Data;
use Moose;
has 'data_set' => ( isa => 'ArrayRef', is => 'rw', required => 0 );
has 'type' => ( isa => 'Str', is => 'rw', required => 0, default => 'line' );
has 'thickness' => ( isa => 'Num', is => 'rw', required => 0, default => 1 );
has 'color' => ( isa => 'Str | ArrayRef', is => 'rw', required => 0, default => '00000000' );
has 'opacity' => ( isa => 'Num', is => 'rw', required => 0, default => 1 );
has 'max' => ( isa => 'Int', is => 'rw', required => 0 );
has 'last' => ( isa => 'Int', is => 'rw', required => 0 );
has 'label' => ( isa => 'Str', is => 'rw', required => 0 );
has 'offset' => ( isa => 'Num', is => 'rw', required => 0, default => 0 );
has 'scale' => ( isa => 'Num | ArrayRef', is => 'rw', required => 0, default => 1 );
1;
package Graph::ChartSVG::Frame;
use Moose;
has 'type' => ( isa => 'Str', is => 'rw', required => 0, default => 'line' );
has 'thickness' => ( isa => 'Num', is => 'rw', required => 0, default => 0 );
has 'color' => ( isa => 'Str', is => 'rw', required => 0, default => '00000000' );
1;
package Graph::ChartSVG::Glyph;
use Moose;
has 'x' => ( isa => 'Str', is => 'rw', required => 1, default => 0 );
has 'y' => ( isa => 'Str', is => 'rw', required => 1, default => 0 );
has 'type' => ( isa => 'Str', is => 'rw', required => 0, default => 'line' );
has 'filled' => ( isa => 'Bool', is => 'rw', required => 0 );
has 'color' => ( isa => 'Str', is => 'rw', required => 0, default => '00000000' );
has 'anchor' => ( isa => 'Str', is => 'rw', required => 0, default => 'start' );
has 'data_set' => ( isa => 'ArrayRef', is => 'rw', required => 0 );
has 'thickness' => ( isa => 'Num', is => 'rw', required => 0, default => 1 );
has 'font' => ( isa => 'Str', is => 'rw' );
has 'size' => ( isa => 'Num', is => 'rw' );
has 'font_weight' => ( isa => 'Str', is => 'rw' );
has 'stretch' => ( isa => 'Str', is => 'rw' );
has 'letter_spacing' => ( isa => 'Num', is => 'rw' );
has 'word_spacing' => ( isa => 'Num', is => 'rw' );
has 'label' => ( isa => 'Str', is => 'rw', required => 0 );
1;
package Graph::ChartSVG::Border;
use Moose;
has 'left' => ( isa => 'Num', is => 'rw', required => 0, default => 0 );
has 'right' => ( isa => 'Num', is => 'rw', required => 0, default => 0 );
has 'top' => ( isa => 'Num', is => 'rw', required => 0, default => 0 );
has 'bottom' => ( isa => 'Num', is => 'rw', required => 0, default => 0 );
1;
package Graph::ChartSVG::Label;
lib/Graph/ChartSVG.pm view on Meta::CPAN
has 'label2' => ( isa => 'Graph::ChartSVG::Label', is => 'rw', required => 0 );
1;
package Graph::ChartSVG::Grid;
use Moose;
has 'x' => ( isa => 'Graph::ChartSVG::Grid_def', is => 'rw', required => 0 );
has 'y' => ( isa => 'Graph::ChartSVG::Grid_def', is => 'rw', required => 0 );
has 'y_up' => ( isa => 'Graph::ChartSVG::Grid_def', is => 'rw', required => 0 );
has 'y_down' => ( isa => 'Graph::ChartSVG::Grid_def', is => 'rw', required => 0 );
has 'x_up' => ( isa => 'Graph::ChartSVG::Grid_def', is => 'rw', required => 0 );
has 'x_down' => ( isa => 'Graph::ChartSVG::Grid_def', is => 'rw', required => 0 );
has 'debord' => ( isa => 'Graph::ChartSVG::Border', is => 'rw', required => 0, default => sub { Graph::ChartSVG::Border->new } );
1;
package Graph::ChartSVG::Overlay;
use Moose;
has 'type' => ( isa => 'Str', is => 'rw', required => 0, default => 'v' );
has 'debord_1' => ( isa => 'Num', is => 'rw', required => 0, default => 0 );
has 'debord_2' => ( isa => 'Num', is => 'rw', required => 0, default => 0 );
has 'data_set' => ( isa => 'HashRef', is => 'rw', required => 0 );
has 'color' => ( isa => 'Str', is => 'rw', required => 0, default => '00000000' );
1;
package Graph::ChartSVG;
use Moose;
use constant PI => 4 * atan2( 1, 1 );
use SVG;
use SVG::Parser qw(SAX=XML::LibXML::SAX::Parser);
use List::Util qw( max min sum );
# use Math::Complex;
# use Compress::Zlib;
use Hash::Merge qw( merge );
use Data::Serializer;
# use Carp::Clan;
use Carp;
#use Data::Dumper;
# use Devel::Size qw(size total_size);
# use Clone qw(clone);
use MIME::Base64;
use vars qw( $VERSION );
$VERSION = '2.07';
has 'active_size' => ( isa => 'ArrayRef', is => 'rw', required => 0 );
has 'total_size' => ( isa => 'ArrayRef', is => 'rw', required => 0 );
has 'bg_color' => ( isa => 'Str', is => 'rw', required => 0, default => 'ffffffff' );
has 'frame' => ( isa => 'Graph::ChartSVG::Frame', is => 'rw', required => 0, default => sub { Graph::ChartSVG::Frame->new } );
has 'grid' => ( isa => 'Graph::ChartSVG::Grid', is => 'rw', required => 0 );
#has 'reticle' => ( isa => 'HashRef', is => 'rw', required => 0 );
has 'overlay' => ( isa => 'Graph::ChartSVG::Overlay', is => 'rw', required => 0 );
has 'glyph' => ( isa => 'ArrayRef', is => 'rw', required => 0 );
#has 'layer' => ( isa => 'ArrayRef', is => 'rw' ,default => sub { [ Layer->new]} );
has 'layer' => ( isa => 'ArrayRef[Layer]', is => 'rw' );
has 'image' => ( isa => 'Str', is => 'rw' );
has 'svg_raw' => ( isa => 'Str', is => 'rw' );
has 'border' => ( isa => 'Graph::ChartSVG::Border', is => 'rw', required => 0, default => sub { Graph::ChartSVG::Border->new } );
has 'tag' => ( isa => 'Bool', is => 'rw', required => 0 );
#has 'tag' => ( isa => 'Tag', is => 'rw', required => 0 );
#has 'tag' => ( isa => 'HashRef', is => 'rw', required => 0 );
sub Tag
{
my $self = shift;
my $args = shift;
if ( exists $self->{ tag } )
{
$self->{ tag } = merge( $self->{ tag }, $args );
}
else
{
$self->{ tag } = $args;
}
bless $self;
}
sub label
{
my $self = shift;
my $label = shift;
foreach my $l ( 1 .. ( scalar @{ $self->{ Layer } } ) )
{
my $m = $l - 1;
if ( defined $self->{ Layer }->[$m]
&& exists $self->{ Layer }->[$m]->{ label }
&& $self->{ Layer }->[$m]->{ label } eq $label )
{
# carp "$l => ".Dumper($self->{ Layer }->[$m]->{ data_set });
return wantarray
? ( $self->{ Layer }->[$m]->{ data_set }, $m )
: $self->{ Layer }->[$m]->{ data_set };
}
}
return ();
}
sub move
{
my $self = shift;
my $from = shift;
my $to = shift;
my $type = 'Layer';
my @tmp;
if ( exists $self->{ $type } )
{
my $elem = splice @{ $self->{ $type } }, $from, 1;
@tmp = ( @{ $self->{ $type } }[ 0 .. ( $to - 1 ) ], $elem, @{ $self->{ $type } }[ ( $to ) .. $#{ $self->{ $type } } ] );
}
lib/Graph/ChartSVG.pm view on Meta::CPAN
id => 'ellipse_' . $layer_ind . '_' . $ind,
style => \%style,
# transform => "matrix(1,0,0,-1," . $self->border->left . "," . ( $self->total_size->[1] - $Y - $self->border->bottom ) . ")",
);
$ind++;
}
}
elsif ( exists $layer->{ type } && $layer->{ type } eq 'image' )
{
my $image_nbr = 1;
foreach my $set ( @{ $layer->data_set } )
{
my $raw_img = $set->{ image };
my $img64 = encode_base64( $raw_img, "\n" );
my $tag = $svg->image(
x => $set->{ x } || 0,
y => -$set->{ y } || 0,
width => $set->{ width },
height => $set->{ height },
id => 'image_' . $layer_ind . '_' . $image_nbr,
'-href' => "data:image/png;base64," . $img64,
transform => "matrix(1,0,0,1," . $X . "," . $Y . ")",
);
$image_nbr++;
}
# $tag = $svg->image(
# x=>100, y=>100,
# width=>300, height=>200,
# '-href'=>"image.png", #may also embed SVG, e.g. "image.svg"
# id=>'image_1'
# );
}
}
#######################################
############## Overlay ################
#######################################
if ( ( ref $layer ) eq 'Graph::ChartSVG::Overlay' )
{
$layer_goup = $data_goup->group( id => "data_$layer_ind" );
my $ind = 0;
my $color_hex = $layer->{ color };
if ( $layer->{ type } eq 'v' )
{
foreach my $start ( keys %{ $layer->{ data_set } } )
{
my $stop = $layer->{ data_set }->{ $start };
my $k = $layer_goup->rectangle(
x => $start,
y => -$layer->{ debord_1 },
width => $stop - $start,
height => $self->{ active_size }->[1] + $layer->{ debord_1 } + $layer->{ debord_2 },
style => {
'opacity' => eval( hex( ( unpack "a6 a2", $color_hex )[1] ) / 255 ) || 1,
'fill' => '#' . ( unpack "a6", $color_hex ) || 0,
'fill-opacity' => eval( hex( ( unpack "a6 a2", $color_hex )[1] ) / 255 ) || 1,
'fill-rule' => 'nonzero'
},
id => 'v_overlay_' . $layer_ind . '_' . $ind
);
$ind++;
}
}
if ( $layer->{ type } eq 'h' )
{
foreach my $start ( keys %{ $layer->{ data_set } } )
{
my $stop = $layer->{ data_set }->{ $start };
my $k = $layer_goup->rectangle(
x => -$layer->{ debord_1 },
y => $start,
width => $self->{ active_size }->[0] + $layer->{ debord_1 } + $layer->{ debord_2 },
height => $stop - $start,
style => {
'opacity' => eval( hex( ( unpack "a6 a2", $color_hex )[1] ) / 255 ) || 1,
'fill' => '#' . ( unpack "a6", $color_hex ) || 0,
'fill-opacity' => eval( hex( ( unpack "a6 a2", $color_hex )[1] ) / 255 ) || 1,
'fill-rule' => 'nonzero'
},
id => 'h_overlay_' . $layer_ind . '_' . $ind
);
$ind++;
}
}
}
$layer_ind++;
}
my $info_data_group = $svg->group( id => "info_data" );
my $obj = Data::Serializer->new( 'compress' => 1 );
my $tag = $obj->serialize( \@list_data );
$info_data_group->comment( $tag );
#######################################
## grid
#######################################
if ( defined $self->grid )
{
if ( defined $self->grid->x )
{
my $x_grid_group = $svg->group( id => "x_grid" );
my $x_grid_text = $x_grid_group->group(
id => "x_grid_text",
transform => "matrix(1,0,0,1, 0," . ( $self->border->bottom ) . " )"
);
my $thickness = $self->grid->x->thickness || 1;
my $color_hex = $self->grid->x->color;
my $max_length_x;
$max_length_x = max( map( length, @{ $self->grid->x->label->text } ) )
if ( defined( $self->grid->x->label )
&& ( ref( $self->grid->x->label->text ) eq 'ARRAY' ) );
my $max_length_x2;
$max_length_x2 = max( map( length, @{ $self->grid->x->label2->text } ) )
if ( defined( $self->grid->x->label2 )
&& ( ref( $self->grid->x->label2->text ) eq 'ARRAY' ) );
for ( my $nbr = $self->grid->x->number - 1 ; $nbr >= 0 ; $nbr-- )
{
my $val = $nbr * ( ( ( $self->active_size->[1] ) / ( $self->grid->x->number - 1 ) ) );
my $text_indx = $self->grid->x->number - $nbr - 1;
my $tag = $x_grid_group->line(
id => 'x_grid_' . $nbr,
x1 => $self->border->left - $self->grid->debord->left,
y1 => $self->border->bottom + $val,
x2 => $self->border->left + $self->active_size->[0] + $self->grid->debord->right,
y2 => $self->border->bottom + $val,
style => {
'fill' => 'none',
'opacity' => eval( hex( ( unpack "a6 a2", $color_hex )[1] ) / 255 ) || 1,
'stroke' => '#' . ( unpack "a6", $color_hex ) || 0,
'stroke-width' => $thickness,
'stroke-linecap' => 'butt',
'stroke-linejoin' => 'miter',
'stroke-opacity' => 1
},
transform => "matrix(1,0,0,-1," . ( 0 ) . "," . ( $self->total_size->[1] ) . ")",
);
if ( defined $self->grid->x->label && defined $self->grid->x->label->text->[$text_indx] )
lib/Graph/ChartSVG.pm view on Meta::CPAN
# carp Dumper($sib2);
#
# }
#
# }
$self;
}
# __PACKAGE__->meta->make_immutable;
#
1;
=head1 METHODS
OO interface
=head2 Graph::ChartSVG->new
=over
Create a new Chart
possible parameters are :
=back
=head3 active_size
=over
=back
an array ref with x,y size of the active graph ( without the reserved border for label )
=head3 bg_color
=over
=back
an hex color for the global background color
=head3 frame
=over
=back
a Frame object to surround the active part of the graph
=head3 grid
=over
=back
a Grid oject to add to the graph
=head3 overlay
=over
=back
a Overlay to add on top of the graph ( useful to enhance a period in alarm )
=head3 layer
=over
=back
a Layer object
=head3 border
=over
=back
a Border object ( = some extra space to fit aroubd the active graph to allow label.
This increase the actual_size and create the total_size)
=head3 tag
=over
=back
a Tag objet ( if missing create a automatically incremented one )
=head3 glyph
=over
=back
a Glyph object to add on the graph ( like a arrow to point at the end of the current data )
my $graph = Graph::ChartSVG->new( active_size => \@size, bg_color => 'FCF4C6', frame => $f, png_tag => 1 );
=over
=back
=head2 Frame->new
=over
=back
=head3 color
=over
=back
( run in 2.735 seconds using v1.01-cache-2.11-cpan-39bf76dae61 )