package Catalyst::View::Chart::Strip; use strict; use base qw/Catalyst::View/; use UNIVERSAL::require; use Carp; use NEXT; our $VERSION = '0.05'; =head1 NAME Catalyst::View::Chart::Strip - A Catalyst View for Chart::Strip graphics =head1 SYNOPSIS package MyApp::View::ChartStrip; use strict; use base 'Catalyst::View::Chart::Strip'; __PACKAGE__->config( cs_package => 'Chart::Strip', height => 192, width => 720, limit_factor => 1, transparent => 0, img_type => 'png', palette => [qw/ FF0000 00CC00 0000FF CC00CC /], ); 1; # A controller method which generates a chart: sub thechart : Local { my ( $self, $c ) = @_; [ ... generate $data and $opts somehow or other ... ] $c->stash->{chart_opts} = $opts; $c->stash->{chart_data} = $data; $c->forward('MyApp::View::ChartStrip'); } =head1 DESCRIPTION This view allows the serving of Chart::Strip stripchart graphics via Catalyst. The raw numeric data and various chart options are placed in C<$c-Estash>. Instances of L, like C shown in the synopsis above, can be thought of as basically a collection of common defaults for the various chart options. You should probably create a seperate View class for each distinct style of charts your application commonly generates. All of the standard constructor arguments documented by L are supported as C<-Econfig> parameters in your View class, and are also overrideable at chart generation time via C<$c-Estash-E{chart_opts}>. L adds a few new options in addition to the ones that are standard in L, which are detailed below. =head1 CONFIGURATION PARAMETERS (See L for a complete list of options. Any L option can be passed through as a C<-Econfig> parameter). All of these options are valid both a C<-Econfig> time, or at chart generation time via C<$c-Estash-E{chart_opts}>. =head2 img_type Sets the output image type. Values currently supported by L and L beneath it are C and C. The default is C if unspecified. =head2 quality This is the quality parameter for the output graphics data, as documented in detail by L's documentation. Valid quality ranges are 0-100 for C and 0-9 for C. Completely optional, and defaults to a reasonably normal value in both cases. =head2 palette An optional arrayref of colors as six-digit hexidecimal strings, like C or C<4A5C2D>. The various datasets in your graph will be colored with the colors of this array in order, recycling to the top of the list if there are more data items than colors specified. The default is a reasonable 9-color high-contrast palette designed for a white background, which happens to also be the default. =head2 cs_package This allows choosing an alternative but compatible C implementation, such as L. Defaults to the original L. =head1 STASH VARIABLES As shown in the synopsis at the top, your chart is ultimately defined by the contents of two stash variables: C<$c-Estash-E{chart_opts}>, and C<$c-Estash-E{chart_data}>. C is analogous to the configuration options described above for the View-wide C<-Econfig> settings. Valid things here are all of the documented arguments to L's C method, as well as the configuration parameters specifically details above. C should be an arrayref of sets of data to be charted. Each item in the arrayref should in turn be a hashref consisting of two keys: C and C. These two keys are analogous to the two arguments of L's C method. In other words, the following example standard L code: my $chart = Chart::Strip‐>new( title => 'Happiness of our Group' ); $chart‐>add_data( $davey_data, { style => 'line', color => 'FF0000', label => 'Davey' } ); $chart‐>add_data( $jenna_data, { style => 'line', color => '00FF88', label => 'Jenna' } ); Becomes this in terms of stash variables: $c->stash->{chart_opts}->{title} = 'Happiness of our Group'; $c->stash->{chart_data} = [ { data => $davey_data, opts => { style => 'line', color => 'FF0000', label => 'Davey' } }, { data => $jenna_data, opts => { style => 'line', color => '00FF88', label => 'Jenna' } }, ]; Note that colors are completely optional for us, since we have a reasonable default palette. You need only neccesarily supply the style and label options for a reasonable chart. See L for a full-fledged controller action you can copy and paste as a working example. =cut # This default palette is hand-tweaked for contrast # against white background on an RGB monitor for human eyes. # The first 7 colors are very good, and the last 2 are decent # enough for most purposes. There is no perfect 9+ color # high-constrast palette, and this is probably as good as it gets. our $def_pal = [qw/ FF0000 00CC00 0000FF CC00CC 00BBDD DDBB00 000000 666666 557700 /]; =head1 METHODS =head2 new Constructor for these Views. Mainly just defaults the above-documented View-specific options, and loads the selected C package. =cut sub new { my $self = shift->NEXT::new(@_); $self->{cs_package} ||= 'Chart::Strip'; $self->{img_type} ||= 'png'; $self->{palette} ||= $def_pal; $self->{cs_package}->require or croak "Cannot load Chart::Strip module '$self->{cs_package}'"; $self; } =head2 process This does the chart generation itself. The bulk of the code is concerned with applying the palette to your data before constructing the L object and using it to generate the output binary image data. =cut sub process { my ($self, $c) = @_; my $opts = $c->stash->{chart_opts}; my $data = $c->stash->{chart_data}; my $chart = $self->{cs_package}->new( %$self, %$opts ); my $palette = $chart->{palette}; # This is all in support of defaulted color palettes my $is_stacked = ($data->[0]->{opts}->{style} eq 'stacked'); if($is_stacked) { my $stack = $data->[0]; if( ! @{ $stack->{opts}->{colors} || [] } ) { my @stacked_colors; my $cnum = 0; my $ncolors_wanted = @{$stack->{data}->[0]->{values}}; foreach (1..$ncolors_wanted) { unshift(@stacked_colors, $palette->[$cnum]); $cnum++; $cnum = 0 if $cnum > $#$palette; } $stack->{opts}->{colors} = \@stacked_colors; $chart->add_data($stack->{data}, $stack->{opts}); } } else { my $cnum = 0; foreach (@$data) { $_->{opts}->{color} ||= $palette->[$cnum]; $chart->add_data($_->{data}, $_->{opts}); $cnum++; $cnum = 0 if $cnum > $#$palette; } } my $itype = $chart->{img_type}; $c->response->content_type("image/$itype"); $c->response->body($chart->$itype($chart->{quality})); } =head1 SEE ALSO L, L, L, L, L, L =head1 AUTHOR Brandon L Black, C =head1 LICENSE You may distribute this code under the same terms as Perl itself. =cut 1;