webgui/lib/WebGUI/Image/Graph/XYGraph.pm
2006-05-22 15:58:31 +00:00

699 lines
15 KiB
Perl

package WebGUI::Image::Graph::XYGraph;
use strict;
use WebGUI::Image::Graph;
use WebGUI::International;
use List::Util;
use POSIX;
our @ISA = qw(WebGUI::Image::Graph);
=head1 NAME
Package WebGUI::Image::Graph::XYGraph
=head1 DESCRIPTION
Base class for flat xy charts.
=head1 SYNOPSIS
XY charts are graphs that have a x and a y coordinate. Examples are Line and Bar
graphs.
This package provides basics needs for such graphs like methods for drawing
axis, labels, rulers and the likes. Also it has methods to set parameters
belonging to xy charts in general such as setting chart width.
=head1 METHODS
These methods are available from this class:
=cut
#-------------------------------------------------------------------
=head2 configurationForm
The configuration form part for this object. See WebGUI::Image::Graph for
documentation.
=cut
sub configurationForm {
my ($configForms, $f);
my $self = shift;
my $i18n = WebGUI::International->new($self->session, 'Image_Graph_XYGraph');
$configForms = $self->SUPER::configurationForm;
$f = WebGUI::HTMLForm->new($self->session);
$f->trClass('Graph_XYGraph');
$f->integer(
name => 'xyGraph_chartWidth',
value => $self->getChartWidth,
label => $i18n->get('chart width'),
hoverHelp => $i18n->get('chart width description'),
);
$f->integer(
name => 'xyGraph_chartHeight',
value => $self->getChartHeight,
label => $i18n->get('chart height'),
hoverHelp => $i18n->get('chart height description'),
);
$f->yesNo(
name => 'xyGraph_drawLabels',
value => $self->showLabels,
label => $i18n->get('draw labels'),
hoverHelp => $i18n->get('draw labels description'),
);
$f->yesNo(
name => 'xyGraph_drawAxis',
value => $self->showAxis,
label => $i18n->get('draw axis'),
hoverHelp => $i18n->get('draw axis description'),
);
$f->color(
name => 'xyGraph_axisColor',
value => $self->getAxisColor,
label => $i18n->get('axis color'),
hoverHelp => $i18n->get('axis color description'),
);
$f->yesNo(
name => 'xyGraph_drawRulers',
value => $self->showRulers,
label => $i18n->get('draw rulers'),
hoverHelp => $i18n->get('draw rulers description'),
);
$f->color(
name => 'xyGraph_rulerColor',
value => $self->getRulerColor,
label => $i18n->get('ruler color'),
hoverHelp => $i18n->get('ruler color description'),
);
$f->selectBox(
name => 'xyGraph_drawMode',
value => [ $self->getDrawMode ],
label => $i18n->get('draw mode'),
hoverHelp => $i18n->get('draw mode description'),
multiple=> 0,
options => {
sideBySide => 'Side by side',
stacked => 'Stacked (cumulative',
},
);
$f->float(
name => 'xyGraph_yGranularity',
value => $self->getYGranularity,
label => $i18n->get('y granularity'),
hoverHelp => $i18n->get('y granularity description'),
);
$configForms->{'graph_xygraph'} = $f->printRowsOnly;
return $configForms;
}
#-------------------------------------------------------------------
=head2 draw
Draws the graph.
=cut
sub draw {
my $self = shift;
# Automagically set the chart offset.
my $maxYLabelWidth = List::Util::max(map {$self->getLabelDimensions($_)->{width}} @{$self->getYLabels});
$self->setChartOffset({
x=> $maxYLabelWidth + 2*$self->getLabelOffset,
y=> $self->getLabelOffset
});
$self->drawRulers if ($self->showRulers);
$self->drawGraph;
$self->drawAxis if ($self->showAxis);
$self->drawLabels if ($self->showLabels);
}
#-------------------------------------------------------------------
=head2 drawAxis
Draws the axis.
=cut
sub drawAxis {
my $self = shift;
my $chartOffset = $self->getChartOffset;
$self->image->Draw(
primitive => 'Path',
stroke => $self->getAxisColor,
points =>
" M ".$chartOffset->{x}.",".$chartOffset->{y}.
" L ".$chartOffset->{x}.",".($self->getChartHeight + $chartOffset->{y}).
" L ".($self->getChartWidth + $chartOffset->{x}).",".($self->getChartHeight + $chartOffset->{y})
);
}
#-------------------------------------------------------------------
=head2 drawLabels
Draws the labels.
=cut
sub drawLabels {
my $self = shift;
my $location = shift;
my %anchorPoint = %{$self->getFirstAnchorLocation};# %$location;
# Draw x-axis labels
foreach (@{$self->getLabel}) {
my $text = $self->wrapLabelToWidth($_, $self->getAnchorSpacing->{x});
$self->drawLabel($text, (
alignHorizontal => 'center',
alignVertical => 'top',
align => 'Center',
x => $anchorPoint{x},
y => $anchorPoint{y},
));
$anchorPoint{x} += $self->getAnchorSpacing->{x}; #$groupWidth + $self->getGroupSpacing;
$anchorPoint{y} += $self->getAnchorSpacing->{y};
}
# Draw y-axis labels
$anchorPoint{x} = $self->getChartOffset->{x} - $self->getLabelOffset;
$anchorPoint{y} = $self->getChartOffset->{y} + $self->getChartHeight;
# for (1 .. $self->getYRange / $self->getYGranularity) {
foreach (@{$self->getYLabels}) {
$self->drawLabel($_, (
alignHorizontal => 'right',
alignVertical => 'center',
x => $anchorPoint{x}, #$self->getChartOffset->{x} - $self->getLabelOffset,
y => $anchorPoint{y}, #$self->getChartOffset->{y} + $self->getChartHeight - $self->getPixelsPerUnit * $_*$self->getYGranularity,
));
$anchorPoint{y} -= $self->getPixelsPerUnit * $self->getYGranularity
}
}
#-------------------------------------------------------------------
=head drawRulers
Draws the rulers.
=cut
sub drawRulers {
my $self = shift;
my $chartOffset = $self->getChartOffset;
my $dist = $self->getLabelOffset;
for (1 .. $self->getYRange / $self->getYGranularity) {
$self->image->Draw(
primitive => 'Path',
stroke => $self->getRulerColor,
points =>
" M ".$chartOffset->{x}.",".($chartOffset->{y}+$self->getChartHeight - $self->getPixelsPerUnit * $_*$self->getYGranularity).
" L ".($chartOffset->{x}+$self->getChartWidth).",".($chartOffset->{y}+$self->getChartHeight - $self->getPixelsPerUnit * $_*$self->getYGranularity)
);
}
}
#-------------------------------------------------------------------
=head2 formNamespace
Extends the form namespace for this object. See WebGUI::Image::Graph for
documentation.
=cut
sub formNamespace {
my $self = shift;
return $self->SUPER::formNamespace.'_XYGraph';
}
#-------------------------------------------------------------------
=head2 getAxisColor
Returns the color triplet for the axis. Defaults to '#222222'.
=cut
sub getAxisColor {
my $self = shift;
return $self->{_axisProperties}->{axisColor} || '#222222';
}
#-------------------------------------------------------------------
=head2 getChartHeight
Returns the height of the chart. Defaults to 200.
=cut
sub getChartHeight {
my $self = shift;
return $self->{_properties}->{chartHeight} || 200;
}
#-------------------------------------------------------------------
=head2 getChartOffset
Returns the coordinates of the top-left corner of the chart. he coordinates are
contained in a hasref with keys 'x' and 'y'.
=cut
sub getChartOffset {
my $self = shift;
return $self->{_properties}->{chartOffset} || { x=>0, y=>0 }
}
#-------------------------------------------------------------------
=head2 getChartWidth
Returns the width of the chart. Defaults to 200.
=cut
sub getChartWidth {
my $self = shift;
return $self->{_properties}->{chartWidth} || 200;
}
#-------------------------------------------------------------------
=head2 getConfiguration
Returns a configuration hashref. See WebGUI::Image::Graph for documentation.
=cut
sub getConfiguration {
my $self = shift;
my $config = $self->SUPER::getConfiguration;
$config->{xyGraph_chartWidth} = $self->getChartWidth;
$config->{xyGraph_chartHeight} = $self->getChartHeight;
$config->{xyGraph_drawLabels} = $self->showLabels;
$config->{xyGraph_drawAxis} = $self->showAxis;
$config->{xyGraph_drawRulers} = $self->showRulers;
$config->{xyGraph_drawMode} = $self->getDrawMode;
$config->{xyGraph_yGranularity} = $self->getYGranularity;
return $config;
}
#-------------------------------------------------------------------
=head2 getDrawMode
Returns the drawmode. Currently supported are 'stacked' and 'sideBySide'.
Defaults to 'sideBySide'.
=cut
sub getDrawMode {
my $self = shift;
return $self->{_barProperties}->{drawMode} || 'sideBySide';
}
#-------------------------------------------------------------------
=head2 getPixelsPerUnit
Returns the number of pixels that correspond with one unit of the dataset
values.
=cut
sub getPixelsPerUnit {
my $self = shift;
return $self->getChartHeight / $self->getYRange;
}
#-------------------------------------------------------------------
=head2 getRulerColor
Returns the color triplet of the rulers in the graph. Defaults to '#777777'.
=cut
sub getRulerColor {
my $self = shift;
return $self->{_axisProperties}->{rulerColor} || '#777777';
}
#-------------------------------------------------------------------
=head2 getYGranularity
Returns the granularity of the labels and rulers in the Y direction. Defaults to
10. This is value is in terms of the values in the dataset and has no direct
relation to pixels.
=cut
sub getYGranularity {
my $self = shift;
return $self->{_properties}->{yGranularity} || 10;
}
#-------------------------------------------------------------------
=head2 getYLabels
Returns an arrayref containing the labels for the Y axis.
=cut
sub getYLabels {
my $self = shift;
my @yLabels;
for (0 .. $self->getYRange / $self->getYGranularity) {
push(@yLabels, $_ * $self->getYGranularity);
}
return \@yLabels;
}
#-------------------------------------------------------------------
=head2 getYRange
Returns the maxmimal value of the range that contains a whole number of times
the y granularity and is bigger than the maximum value in the dataset.
=cut
sub getYRange {
my $self = shift;
return $self->getYGranularity*ceil($self->getMaxValueFromDataset / $self->getYGranularity) || 1;
}
#-------------------------------------------------------------------
=head2 setAxisColor ( color )
Sets the color of the axis to the supplied value.
=head3 color
The triplet of the color you want to set the axis to. Must have the following
form: #ffffff.
=cut
sub setAxisColor {
my $self = shift;
my $color = shift;
$self->{_axisProperties}->{axisColor} = $color;
}
#-------------------------------------------------------------------
=head2 setChartHeight ( height )
Sets the height of the chart to the specified value.
=head3 height
The desired height in pixels.
=cut
sub setChartHeight {
my $self = shift;
my $height = shift;
$self->{_properties}->{chartHeight} = $height;
}
#-------------------------------------------------------------------
=head2 setChartOffset ( location )
Sets the location of the top-left corner of the graph within the image.
=head3 location
A hashref containing the desired location. Use the 'x' and 'y' as keys for the x
and y coordinate respectively.
=cut
sub setChartOffset {
my $self = shift;
my $point = shift;
$self->{_properties}->{chartOffset} = {%$point};
}
#-------------------------------------------------------------------
=head2 setChartHeight ( width )
Sets the width of the chart to the specified value.
=head3 width
The desired width in pixels.
=cut
sub setChartWidth {
my $self = shift;
my $width = shift;
$self->{_properties}->{chartWidth} =$width;
}
#-------------------------------------------------------------------
=head2 setConfiguration ( config )
Applies the settings in the given configuration hash. See WebGUI::Image::Graph
for more information.
=head3 config
A configuration hash.
=cut
sub setConfiguration {
my $self = shift;
my $config = shift;
$self->SUPER::setConfiguration($config);
$self->setChartWidth($config->{xyGraph_chartWidth});
$self->setChartHeight($config->{xyGraph_chartHeight});
$self->setShowLabels($config->{xyGraph_drawLabels});
$self->setShowAxis($config->{xyGraph_drawAxis});
$self->setShowRulers($config->{xyGraph_drawRulers});
$self->setDrawMode($config->{xyGraph_drawMode});
$self->setYGranularity($config->{xyGraph_yGranularity});
$self->setAxisColor($config->{xyGraph_axisColor});
$self->setRulerColor($config->{xyGraph_rulerColor});
return $config;
}
#-------------------------------------------------------------------
=head2 setDrawMode ( mode )
Set the way the datasets are drawn. Currently supported are 'stacked' and
'sideBySide' which correspond to respectivly cumulative drawing and normal
processing.
=head3 mode
The desired mode. Can be 'sideBySide' or 'stacked'.
=cut
sub setDrawMode {
my $self = shift;
my $mode = shift;
if ($mode eq 'stacked' || $mode eq 'sideBySide') {
$self->{_barProperties}->{drawMode} = $mode;
} else {
$self->{_barProperties}->{drawMode} = 'sideBySide';
}
}
#-------------------------------------------------------------------
=head2 setRulerColor ( color )
Set the color of the rulers.
=head3 color
The triplet of the desired ruler color. Must be in the following format:
'#ffffff'.
=cut
sub setRulerColor {
my $self = shift;
my $color = shift;
$self->{_axisProperties}->{rulerColor} = $color;
}
#-------------------------------------------------------------------
=head2 setShowAxis ( boolean )
Set whether or not to draw the axis.
=head3 boolean
If set to false the axis won't be drawn.
=cut
sub setShowAxis {
my $self = shift;
my $yesNo = shift;
$self->{_properties}->{showAxis} = $yesNo;
}
#-------------------------------------------------------------------
=head2 setShowLabels ( boolean )
Set whether or not to draw the labels.
=head3 boolean
If set to false the labels won't be drawn.
=cut
sub setShowLabels {
my $self = shift;
my $yesNo = shift;
$self->{_properties}->{showLabels} = $yesNo;
}
#-------------------------------------------------------------------
=head2 setShowRulers ( boolean )
Set whether or not to draw the rulers.
=head3 boolean
If set to false the rulers won't be drawn.
=cut
sub setShowRulers {
my $self = shift;
my $yesNo = shift;
$self->{_properties}->{showRulers} = $yesNo;
}
#-------------------------------------------------------------------
=head2 setYGranularity ( value )
Sets the y granularity. See getYGranularity for explanation of this concept.
=head3 value
The granularity in dataset units, not pixels.
=cut
sub setYGranularity {
my $self = shift;
my $granularity = shift;
$self->{_properties}->{yGranularity} = $granularity;
}
#-------------------------------------------------------------------
=head2 showAxis
Returns a boolean indicating whether to draw the axis.
=cut
sub showAxis {
my $self = shift;
return 1 unless (defined $self->{_properties}->{showAxis});
return $self->{_properties}->{showAxis};
}
#-------------------------------------------------------------------
=head2 showLabels
Returns a boolean indicating whether to draw the labels.
=cut
sub showLabels {
my $self = shift;
return 1 unless (defined $self->{_properties}->{showLabels});
return $self->{_properties}->{showLabels};
}
#-------------------------------------------------------------------
=head2 showRulers
Returns a boolean indicating whether to draw the rulers.
=cut
sub showRulers {
my $self = shift;
return 1 unless (defined $self->{_properties}->{showRulers});
return $self->{_properties}->{showRulers};
}
1;