Chart::OFC2 - Generate html and data files for use with Open Flash Chart version 2


Chart-OFC2 documentation Contained in the Chart-OFC2 distribution.

Index


Code Index:

NAME

Top

Chart::OFC2 - Generate html and data files for use with Open Flash Chart version 2

SYNOPSIS

Top

OFC2 html:

    use Chart::OFC2;

    my $chart = Chart::OFC2->new(
        'title'  => 'Bar chart test',
    );
    print $chart->render_swf(600, 400, 'chart-data.json', 'test-chart');

OFC2 bar chart data:

    use Chart::OFC2;
    use Chart::OFC2::Axis;
    use Chart::OFC2::Bar;

    my $chart = Chart::OFC2->new(
        'title'  => 'Bar chart test',
        x_axis => {
            labels => {
                labels => [ 'Jan', 'Feb', 'Mar', 'Apr', 'May' ],
            }
        },
    );

    my $bar = Chart::OFC2::Bar->new();
    $bar->values([ 1..5 ]);
    $chart->add_element($bar);

    print $chart->render_chart_data();

WARNING

Top

Current version implements just subset of functionality that Open Flash Chart 2 is offering. But it should help you to starting creating OFC2 graphs quite fast. The JSON format is quite intuitive and can be created from any hash. This module is more like guideline.

This is early version PROTOTYPE so the API WILL change, be careful when upgrading versions.

DESCRIPTION

Top

OFC2 is a flash script for creating graphs. To have a graph we need an open-flash-chart.swf and a JSON data file describing graph data. Complete examples you can find after successful run of this module tests in t/output/ folder - t/output/bar.html, t/output/pie.html, t/output/hbar.html are html graphs and t/output/bad-data.json, t/output/pie-data.json, t/output/hbar-data.json are the data files.

PROPERTIES

Top

    has 'data_load_type' => (is => 'rw', isa => 'Str',  default => 'inline_js');
    has 'bootstrap'      => (is => 'rw', isa => 'Bool', default => '1');
    has 'title'          => (is => 'rw', isa => 'Chart::OFC2::Title', default => sub { Chart::OFC2::Title->new() }, lazy => 1, coerce  => 1);
    has 'x_axis'         => (is => 'rw', isa => 'Chart::OFC2::XAxis', default => sub { Chart::OFC2::XAxis->new() }, lazy => 1,);
    has 'y_axis'         => (is => 'rw', isa => 'Chart::OFC2::YAxis', default => sub { Chart::OFC2::YAxis->new() }, lazy => 1, );
    has 'elements'       => (is => 'rw', isa => 'ArrayRef', default => sub{[]}, lazy => 1);
    has 'extremes'       => (is => 'rw', isa => 'Chart::OFC2::Extremes',  default => sub { Chart::OFC2::Extremes->new() }, lazy => 1);
    has 'tooltip'        => (is => 'rw', isa => 'Chart::OFC2::ToolTip',);
    has 'bg_colour'      => (is => 'rw', isa => 'Str',  default => 'f8f8d8', alias => 'bg_color' );

METHODS

Top

new()

Object constructor.

get_element($type)

Returns new chart object of selected type. Currently only bar and pie is available.

add_element($element)

Adds passed element to the graph.

render_chart_data

Returns stringified JSON encoded graph data.

auto_extremes

Recalculate graph auto extremes.

render_swf($width, $height, $data_url, $div_id)

Returns html snippet that will represent one graph in a html document.

WARN: the arguments format will change to key = value> in the next releases.

FUNCTIONS

Top

smoother_number

round the number up a bit to a nice round number also changes number to an int

smooth($axis_name, $axis_type)

Smooth axis min/max.

bg_color()

Same as bg_colour().

NOTE

Top

Refresh button will not cause the data file of the graph to be reloaded so either use proper expiration settings for it or change the name of the file in html every time you generate new data. Like "data.json?".time().

SEE ALSO

Top

Chart::OFC, http://teethgrinder.co.uk/open-flash-chart-2/, http://github.com/jozef/chart-ofc2/

AUTHOR

Top

Jozef Kutej <jkutej@cpan.org>

I've used some of the code from the perl-ofc-library/open_flash_chart.pm that is shipped together with all the rest OFC2 files.

CONTRIBUTORS

Top

The following people have contributed to the Chart::OFC2 by commiting their code, sending patches, reporting bugs, asking questions, suggesting useful advices, nitpicking, chatting on IRC or commenting on my blog (in no particular order):

    Rodney Webster
    John Goulah C<< <jgoulah@cpan.org> >>
    Noƫ Snaterse
    Adam J. Foxson C<< <atom@cpan.org> >>
    Jeff Tam

SUPPORT

Top

* Mailinglist

http://lists.meon.sk/mailman/listinfo/chart-ofc2

* GitHub: issues

http://github.com/jozef/chart-ofc2/issues

* RT: CPAN's request tracker

http://rt.cpan.org/NoAuth/Bugs.html?Dist=Chart-OFC2

* AnnoCPAN: Annotated CPAN documentation

http://annocpan.org/dist/Chart-OFC2

* CPAN Ratings

http://cpanratings.perl.org/d/Chart-OFC2

* Search CPAN

http://search.cpan.org/dist/Chart-OFC2

COPYRIGHT AND LICENSE

Top


Chart-OFC2 documentation Contained in the Chart-OFC2 distribution.
package Chart::OFC2;


use Moose;
use Moose::Util::TypeConstraints;
use MooseX::StrictConstructor;
use MooseX::Aliases;

our $VERSION = '0.07';

use Carp::Clan 'croak';
use JSON::XS qw();

use Chart::OFC2::Axis;
use Chart::OFC2::Bar;
use Chart::OFC2::Title;
use Chart::OFC2::Extremes;
use Chart::OFC2::ToolTip;
use List::Util 'min', 'max';
use List::MoreUtils 'any';

has 'data_load_type' => (is => 'rw', isa => 'Str',  default => 'inline_js');
has 'bootstrap'      => (is => 'rw', isa => 'Bool', default => '1');
has 'title'          => (is => 'rw', isa => 'Chart::OFC2::Title', default => sub { Chart::OFC2::Title->new() }, lazy => 1, coerce  => 1);
has 'x_axis'         => (is => 'rw', isa => 'Chart::OFC2::XAxis', default => sub { Chart::OFC2::XAxis->new() }, lazy => 1, coerce  => 1);
has 'y_axis'         => (is => 'rw', isa => 'Chart::OFC2::YAxis', default => sub { Chart::OFC2::YAxis->new() }, lazy => 1, coerce  => 1);
has 'elements'       => (is => 'rw', isa => 'ArrayRef', default => sub{[]}, lazy => 1);
has 'extremes'       => (is => 'rw', isa => 'Chart::OFC2::Extremes',  default => sub { Chart::OFC2::Extremes->new() }, lazy => 1);
has '_json'          => (is => 'rw', isa => 'Object',  default => sub { JSON::XS->new->pretty(1)->convert_blessed(1) }, lazy => 1);
has 'tooltip'        => (is => 'rw', isa => 'Chart::OFC2::ToolTip', coerce  => 1);
has 'bg_colour'      => (is => 'rw', isa => 'Str',  default => 'f8f8d8', alias => 'bg_color' );

# elements are the data series items, usually containing values to plot
sub get_element {
    my ($self, $element_name) = @_;
    
    my $element_module = (
          $element_name eq 'bar' ? 'Chart::OFC2::Bar'
        : $element_name eq 'pie' ? 'Chart::OFC2::Pie'
        : undef
    );
    croak 'unsupported element - ', $element_name
        if not defined $element_name;
    
    return $element_module->new();
}


sub add_element {
    my ($self, $element) = @_;
    
    if ($element->use_extremes) {
        $self->y_axis->max('a');
        $self->y_axis->min('a');
        $self->x_axis->max('a');
        $self->x_axis->min('a');
    }
    
    push(@{ $self->elements }, $element);
}


sub render_chart_data {
    my $self = shift;

    $self->auto_extremes();
    
    return $self->_json->encode({
        'title'    => $self->title,
        'x_axis'   => $self->x_axis,
        'y_axis'   => $self->y_axis,
        'tooltip'  => $self->tooltip,
        'elements' => $self->elements,
        'bg_colour' => $self->bg_colour,
    });
}


sub auto_extremes {
    my $self = shift;
        
    foreach my $axis_name ('x_axis', 'y_axis') {
        my $axis = $self->$axis_name;
        next if not defined $axis;
        
        foreach my $axis_type ('min', 'max') {
            my $axis_value = $axis->$axis_type;
            if ((defined $axis_value) and ($axis_value eq 'a')) {
                $axis->$axis_type($self->smooth($axis_name, $axis_type));
            }
        }
    }
    
    return;
}


sub render_swf {
    my ($self, $width, $height, $data_url, $div_id) = @_;
    
    $div_id ||= 'my_chart';

    my $html = '';

    if ($self->data_load_type eq 'inline_js') {
        if ($self->bootstrap) {
            $html .= '<script type="text/javascript" src="swfobject.js"></script>';
            $self->{'skip_bootstrap'} = 1;
        }
        $html .= qq^
                        <div id="$div_id"></div>
                        <script type="text/javascript">
                                swfobject.embedSWF(
                                        "open-flash-chart.swf", "$div_id", "$width", "$height",
                                        "9.0.0", "expressInstall.swf",
                                        {"data-file":"$data_url"}
                                );
                        </script>
                ^;
    }
    else {
        $html .= qq^
                        <object
                                classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000"
                                codebase="http://fpdownload.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=8,0,0,0"
                                width="$width"
                                height="$height"
                                id="graph_2"
                                align="middle">
                        <param name="allowScriptAccess" value="sameDomain" />
                        <param name="movie" value="open-flash-chart.swf?width=$width&height=$height&data=$data_url"/>
                        <param name="quality" value="high" />
                        <param name="bgcolor" value="#FFFFFF" />
                        <embed
                                src="open-flash-chart.swf?width=$width&height=$height&data=$data_url"
                                quality="high"
                                bgcolor="#FFFFFF"
                                width="$width"
                                height="$height"
                                name="open-flash-chart"
                                align="middle"
                                allowScriptAccess="sameDomain"
                                type="application/x-shockwave-flash"
                                pluginspage="http://www.macromedia.com/go/getflashplayer"
                        />
                        </object>
                ^;
    }

    return $html;
}


sub smoother_number {
    my $number  = shift;
    my $min_max = shift;
    my $n       = $number;
    
    return
        if not defined $number;

    if ($min_max eq 'max') {
        $n += 1;
    }
    else {
        $n -= 1;
    }
    if ($n <= 10) { $n = int($n) }
    elsif ($n < 30)    { $n = $n + (-$n % 5) }
    elsif ($n < 100)   { $n = $n + (-$n % 10) }
    elsif ($n < 500)   { $n = $n + (-$n % 50) }
    elsif ($n < 1000)  { $n = $n + (-$n % 100) }
    elsif ($n < 10000) { $n = $n + (-$n % 200) }
    else               { $n = $n + (-$n % 500) }
    return int($n);
}


sub smooth {
    my $self      = shift;
    my $axis_name = shift;
    my $axis_type = shift;
    
    my $extremes_name = $axis_name.'_'.$axis_type;
    my $cmp_function  = ($axis_type eq 'min' ? \&min : \&max);
    
    my $number;
    foreach my $element (@{$self->elements}) {
        my $element_number = $element->extremes->$extremes_name;
        
        next
            if not defined $element_number;
        $number = $element_number
            if not defined $number;
        $number = $cmp_function->($number, $element_number);
    }
    
    return smoother_number($number, $axis_type);
}

sub bg_color {
    &bg_colour;
}

__PACKAGE__->meta->make_immutable;

1;


__END__