root/lang/perl/Google-Chart-DBIC/trunk/lib/Google/Chart/DBIC.pm @ 17834

Revision 17834, 5.9 kB (checked in by lopnor, 6 years ago)

lang/perl/Google-Chart-DBIC: supports negative value, maybe.

Line 
1package Google::Chart::DBIC;
2use Moose;
3use Google::Chart;
4use Google::Chart::Types;
5use Google::Chart::DBIC::Types;
6use Data::Dumper ();
7use POSIX ();
8use Scalar::Util ();
9our $VERSION = '0.01';
10
11has 'size' => (
12    is => 'rw',
13    isa => 'Google::Chart::Size',
14    coerce => 1,
15    required => 1,
16    default => sub {
17        Class::MOP::load_class('Google::Chart::Size');
18        Google::Chart::Size->new( width => 400, height => 400 );
19    },
20);
21has 'type' => (
22    is => 'rw',
23    isa => 'Google::Chart::Type',
24    coerce => 1,
25    required => 1,
26    default => sub {
27        Class::MOP::load_class('Google::Chart::Type::Line');
28        Google::Chart::Type::Line->new;
29    },
30);
31has 'color' => (
32    is => 'rw',
33    isa => 'Google::Chart::Color',
34    coerce => 1,
35    required => 1,
36    default => sub {
37        Class::MOP::load_class('Google::Chart::Color');
38        my @default;
39        for (1 .. 10) {
40            push @default, (sprintf "%06X", rand() * 0xffffff);
41        }
42        Google::Chart::Color->new(values => \@default);
43    },
44);
45has 'resultset' => (
46    is => 'rw',
47    isa => 'DBIx::Class::ResultSet',
48    required => 1,
49);
50has 'min_value' => (
51    is => 'rw',
52    isa => 'Num',
53);
54has 'max_value' => (
55    is => 'rw',
56    isa => 'Num',
57);
58has 'axis_column' => (
59    is => 'rw',
60    isa => 'Str',
61);
62has 'key_column' => (
63    is => 'rw',
64    coerce => 1,
65    isa => 'Google::Chart::DBIC::KeyColumn'
66);
67
68__PACKAGE__->meta->make_immutable;
69
70no Moose;
71
72
73sub __find_axis_column {
74    my ($self, $row) = @_;
75
76    my @primary = $self->resultset->result_source->primary_columns;
77    my $axis_column = $self->axis_column || 'axis_x';
78
79    if ( $row->has_column_loaded($axis_column))
80    {
81        # no op. we're fine
82    } elsif (scalar @primary == 1) {
83        # either we don't have a axis_column defined, or the
84        # selected query did not use axis_column... but we have a
85        # primary key
86        $axis_column = $primary[0];
87    } else {
88        # In this case, as_uri() will Do The Right Thing
89        $axis_column = undef;
90    }
91
92    return $axis_column;
93}
94
95sub as_uri {
96    my $self = shift;
97    my $dataset = {};
98    my $axis_x = [];
99    my $max_value = 0;
100    my $min_value = 0;
101
102    my $resultset = $self->resultset;
103                     
104    my $axis_column; # this will be calculated only once
105    while (my $row = $resultset->next) {
106        my $axis = '';
107
108        $axis_column ||= $self->__find_axis_column( $row );
109        $axis = $row->get_column($axis_column) if $axis_column;
110        push @$axis_x, $axis unless grep {$_ eq $axis} @$axis_x;
111
112#        if ($axis_column && scalar @primary > 1 &&
113        for my $col ($row->columns) {
114            next unless $row->has_column_loaded($col);
115            next if $axis_column && $col eq $axis_column;
116            my $v = $row->$col;
117            next unless Scalar::Util::looks_like_number $v;
118            my $k = $col;
119            $k = join(':', map( {$row->get_column($_)} sort @{$self->key_column} ), $k) if $self->key_column;
120            push @{$dataset->{$k}}, Scalar::Util::looks_like_number $v ? $v : undef;
121            $max_value = $v if $v >= $max_value;
122            $min_value = $v if $v < $min_value;
123        }
124    }
125    $max_value = $self->max_value || $max_value;
126    $min_value = $self->min_value || $min_value;
127    my $chart = Google::Chart->new(
128        size => $self->size,
129        type => $self->type,
130        axis => [
131            {
132                location => 'x',
133                labels   => $axis_x ? $self->_roughen($axis_x, 5) : [],
134            },
135            {
136                location => 'y',
137                labels   => [ map { ($_ * ($max_value - $min_value)) + $min_value } map { 0.2 * $_ } (0 .. 5) ],
138            }
139        ],
140        data => {
141            module => 'Extended',
142            args => {
143                dataset => [values %$dataset],
144                max_value => $max_value,
145                min_value => $min_value,
146            },
147        },
148#        color => [@{$self->color}[0 .. (scalar values %$dataset) - 1]],
149        color => $self->color,
150        legend => [keys %$dataset],
151    );
152    return $chart->as_uri;
153}
154
155sub _roughen {
156    my ($self, $arr, $count) = @_;
157
158    return $arr if scalar @$arr < ($count - 1);
159    my $gap = POSIX::ceil($#{$arr}/ ($count - 1));
160    my $ret = [];
161    for my $i (0 .. $#{$arr}) {
162        push @$ret, ($i % $#{$arr} && $i % $gap) ? '' : $arr->[$i];
163    }
164    return $ret;
165}
166
1671;
168__END__
169
170=head1 NAME
171
172Google::Chart::DBIC - glue class for Google::Chart and DIBC
173
174=head1 SYNOPSIS
175
176  use TestApp::Schema;
177  use Google::Chart::DBIC;
178
179  my $schema = TestApp::Schema->connect(
180      "dbi:SQLite:$dbfile"
181  );
182  my @list = TestApp::Schema->resultset('Climate')->search({
183      place => 'Tokyo',
184  }{
185      select => ['high','low','month'],
186      as => ['high','low','axis_x'],
187  });
188  my $chart = Google::Chart::DBIC->new({
189      resultset => \@list,
190      size => '300x400',
191      type => 'line',
192  });
193  my $uri = $chart->as_uri;   
194
195 
196=head1 DESCRIPTION
197
198Google::Chart::DBIC is glue class for Google::Chart and DBIC.
199
200=head1 METHODS
201
202=head2 new(%args)
203
204Constructor.
205
206=over 4
207
208=item type
209
210will be passed to Google::Chart constructor.
211
212=item size
213
214will be passed to Google::Chart constructor.
215
216=item resultset
217
218'looks_like_number' value in the resultset will be plotted on the chart.
219If there is a column named 'axis_x', it will be assigned as bottom axis of the chart.
220
221=item max_value
222
223specify max_value of the chart. defaults max value of the resultset.
224
225=item color
226
227specify color if you don't like default colors.
228
229=item axis_column
230
231specify column name to use as bottom axis of the chart.
232
233=item key_column
234
235specify column name to use as hash key.
236
237=item value_column
238
239specify column name to use as hash value.
240
241=back
242
243=head2 as_uri
244
245Returns google chart uri.
246
247=head1 AUTHOR
248
249Author E<lt>nobuo.danjou@gmail.comE<gt>
250
251This library is free software; you can redistribute it and/or modify
252it under the same terms as Perl itself.
253
254=head1 SEE ALSO
255
256L<Google::Chart>
257
258=cut
259
Note: See TracBrowser for help on using the browser.