711 lines
15 KiB
Perl
711 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}),
|
|
fill => 'none',
|
|
);
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 drawLabels ( )
|
|
|
|
Draws the labels.
|
|
|
|
=cut
|
|
|
|
sub drawLabels {
|
|
my $self = shift;
|
|
my $location = shift;
|
|
|
|
my %anchorPoint = %{$self->getFirstAnchorLocation};
|
|
|
|
# Draw x-axis labels
|
|
foreach my $text (@{$self->getLabel}) {
|
|
$self->drawLabel($text, (
|
|
alignVertical => 'top',
|
|
align => 'left',
|
|
rotate => 90,
|
|
x => $anchorPoint{x},
|
|
y => $anchorPoint{y},
|
|
));
|
|
|
|
$anchorPoint{x} += $self->getAnchorSpacing->{x};
|
|
$anchorPoint{y} += $self->getAnchorSpacing->{y};
|
|
}
|
|
|
|
# Draw y-axis labels
|
|
$anchorPoint{x} = $self->getChartOffset->{x} - $self->getLabelOffset;
|
|
$anchorPoint{y} = $self->getChartOffset->{y} + $self->getChartHeight;
|
|
foreach (@{$self->getYLabels}) {
|
|
$self->drawLabel($_, (
|
|
alignHorizontal => 'right',
|
|
alignVertical => 'center',
|
|
x => $anchorPoint{x},
|
|
y => $anchorPoint{y},
|
|
));
|
|
$anchorPoint{y} -= $self->getPixelsPerUnit * $self->getYGranularity
|
|
}
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 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 getAnchorSpacing ()
|
|
|
|
This method MUST be overridden by all sub classes.
|
|
|
|
=cut
|
|
|
|
sub getAnchorSpacing {
|
|
die "You were supposed to override this method in the sub class.";
|
|
}
|
|
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=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;
|
|
|