App-Widget-ChartDirector
view release on metacpan or search on metacpan
lib/App/Widget/ChartDirector.pm view on Meta::CPAN
$total_x_length += length($_) + 2; #Taking 2 as the gap value
push (@x_values, length($_));
}
@x_values = sort { $a <=> $b} @x_values;
$self->{total_x_length} = $total_x_length;
$self->{width} = $width;
if ($total_x_length > $width/8 && $x->[0] !~ /^[0-9]{4}-[0-9]{2}-[0-9]{2}$/) {
$width += ($#$x) * ceil (3 * $#$x / 100 ) + 0.5 if ($#$x > 50);
}
}
my $legend_pos = $spec->{legend_pos} || "default"; # Any one from default, top or bottom
my (@length_y_value, $max_legend_length, $num_legend_columns, $legend_width, $margin, $textsize, $number_legend_rows, $length_labels, $length_labels_avg);
my (@length_all_labels, $diff_largest_and_avg, $gap_legends);
if ($legend_pos ne "default") {
$legend_width = $width - 2 * $right_margin;
($margin,$textsize) = (6,10);
$max_legend_length = ceil ( $legend_width / ($textsize * 3/4)); # This is a nearyby approximation of number of characters inside a row in the legends
$length_labels = 0;
foreach my $y_value (@{$spec->{y_labels}}) {
$length_labels += length($y_value);
push (@length_all_labels, length($y_value) );
}
@length_all_labels = sort { $a <=> $b } @length_all_labels;
$length_labels_avg = ceil ($length_labels / ($#{$spec->{y_labels}} + 1));
$diff_largest_and_avg = $length_all_labels[-1] - $length_labels_avg;
# Calculation of gap b/w the legends
$gap_legends = $margin;
if($diff_largest_and_avg > $gap_legends) {
$gap_legends += ceil ($diff_largest_and_avg / 2);
}
else {
$gap_legends += 1;
$gap_legends -= ceil ($diff_largest_and_avg - $gap_legends / 3) if ($length_labels_avg >= $max_legend_length / 4); # Reduce gap if the average length of legends is higher than max. legend length by 4.
}
# Calculation of number of columns
for (my $cols = 1; $cols <= 20; $cols++) { # Taking min. 1 and max. 20 columns
$num_legend_columns = $cols if (($length_labels_avg + $gap_legends) < ($max_legend_length / $cols));
}
$num_legend_columns += 1 if (($length_labels_avg + $gap_legends) > ($max_legend_length / 2)); #Add a new column if the avg. legend length is greater than half of the max. permissible length
if ($spec->{num_legend_columns} ) {
$num_legend_columns = $spec->{num_legend_columns};
}
do {
$num_legend_columns += 1 if ($height > (2 * $spec->{height})); #If the legend height is greater than max. permissible limit than add a new column and the legends will truncate
$height = $spec->{height};
$number_legend_rows = int (($#{$spec->{y_labels}} + 1) / $num_legend_columns);
if (($#{$spec->{y_labels}} + 1) % $num_legend_columns != 0 ) {
$number_legend_rows += 1;
}
$height += (($margin + $textsize) * $number_legend_rows) + (4 * $margin);
} while ($height > (2 * $spec->{height})); # Max. graph height should not be greater than twice of chosen graph height
if ($#{$spec->{y_labels}} <= 0) {
$height = $spec->{height};
}
}
my $graph_height_increment = 0;
my $fontsize = 10;
if ($spec->{x_label_pos}) {
if ($#$x > 30 && $total_x_length > $width/8 && $x->[0] !~ /^[0-9]{4}-[0-9]{2}-[0-9]{2}$/) {
for (my $i = 30; $i <= $#$x; $i++ ) {
$fontsize = $fontsize - 0.1;
$fontsize = 1 if ($fontsize < 1);
}
$fontsize += ceil(($width - $spec->{width})/$#$x) - 1 if ($#$x > 50);
}
$self->{fontsize} = $fontsize;
if ($total_x_length > $width/8 && $x->[0] !~ /^[0-9]{4}-[0-9]{2}-[0-9]{2}$/) {
$graph_height_increment = 1/2 * $x_values[-1] * floor ($fontsize);
$height += $graph_height_increment;
}
}
my $c = new XYChart($width, $height);
my $graph_adjusted_height = $height - $spec->{height}-$graph_height_increment;
my ($top_margin_adjusted,$bottom_margin_adjusted);
if ($legend_pos eq "top" ) {
$top_margin_adjusted = $top_margin+$graph_adjusted_height;
$bottom_margin_adjusted = $height-$top_margin-$bottom_margin-$graph_adjusted_height-$graph_height_increment;
}
elsif ($legend_pos eq "bottom") {
$top_margin_adjusted = $top_margin;
$bottom_margin_adjusted = $height-$top_margin-$bottom_margin-$graph_adjusted_height-$graph_height_increment;
}
else {
$top_margin_adjusted = $top_margin;
$bottom_margin_adjusted = $height-$top_margin-$bottom_margin-$graph_height_increment;
}
my $plot_area = $c->setPlotArea($left_margin , $top_margin_adjusted,
$width-$left_margin-$right_margin,
$bottom_margin_adjusted);
$spec->{plot_area_x} = $left_margin;
$spec->{plot_area_y} = $top_margin_adjusted;
$spec->{plot_area_width} = $width - $left_margin - $right_margin;
$spec->{plot_area_height} = $bottom_margin_adjusted;
$spec->{plot_bgcolor} = $plot_bgcolor;
$plot_area->setBackground(hex($plot_bgcolor), hex($plot_bgcolor));
$c->addTitle($spec->{title}, "arialbd.ttf", 12, hex($titlecolor)) if ($spec->{title});
if ($y_max_zero == 0) {
$c->yAxis()->setMargin($top_margin_adjusted + 15);
}
#Add a legend box at (55, 22) using horizontal layout, with transparent
#background
my $legend;
if ($spec->{y_labels}) {
my $x_adj = 0;
my $y_adj = -2;
if ($spec->{"3D"}) {
$x_adj += 5;
$y_adj += -5;
}
if (($#{$spec->{y_labels}} > 0) && ($legend_pos eq "top" || $legend_pos eq "bottom")) {
if ($legend_pos eq "top" ) {
$legend = $c->addLegend($right_margin, $top_margin + $y_adj, 0,"arial.ttf",10);
}
elsif ($legend_pos eq "bottom" ) {
$legend = $c->addLegend($right_margin, $height - $graph_adjusted_height - $top_margin/4 , 0,"arial.ttf",10);
}
$legend->setBackground(hex($plot_bgcolor));
$legend->setMargin(5);
$legend->setWidth($legend_width);
lib/App/Widget/ChartDirector.pm view on Meta::CPAN
if ($end_datetime =~ /^([0-9]{4})-([0-9]{2})-([0-9]{2})$/) {
$end_yr = $1;
$end_time = &perlchartdir::chartTime($1, $2, $3);
}
$chart->xAxis()->setDateScale($begin_time, $end_time);
my (@x_date);
for (my $i = 0; $i <= $#$x; $i++) {
if ($x->[$i] =~ /^([0-9]{4})-([0-9]{2})-([0-9]{2})$/) {
#$x_date[$i] = &perlchartdir::chartTime($1, $2, $3);
$x_date[$i] = "$2/$3";
}
else {
$x_date[$i] = $perlchartdir::NoValue;
}
}
$x_title .= " " if ($x_title);
$x_title .= "($begin_yr";
$x_title .= "-$end_yr" if ($end_yr ne $begin_yr);
$x_title .= ")";
$chart->xAxis()->setLabels(\@x_date);
my $r = sprintf("%.0f", $#x_date / 15);
my $w = sprintf("%.0f", (800 / $spec->{width}));
$r += $w if ($w > 1 && $r > 0);
$r += 1 if ($#x_date >= 13 && $spec->{width} <= 600);
$chart->xAxis()->setLabelStep($r);
}
elsif ($x->[0] =~ /^[0-9]+$/) {
$layer->setXData($x);
}
else {
if ($x->[0] =~ /^[0-9]+\-[0-9]+$/) {
my %m = ("01"=>"Jan","02"=>"Feb","03"=>"Mar","04"=>"Apr",
"05"=>"May","06"=>"Jun","07"=>"Jul","08"=>"Aug",
"09"=>"Sep","10"=>"Oct","11"=>"Nov","12"=>"Dec");
for (my $i = 0; $i <= $#$x; $i++) {
if ($x->[$i] =~ /^([0-9]+)\-([0-9]+)$/){
my $yr = $1; my $month = $2;
$yr = substr($yr, 2, 2);
$x->[$i] = "$m{$month}$yr";
}
}
$chart->xAxis()->setLabels($x);
my $r = sprintf("%.0f", $#$x / 24);
my $w = sprintf("%.0f", (900 / $spec->{width}));
$r += $w;
$chart->xAxis()->setLabelStep($r);
}
else {
foreach my $xlabel (@$x) {
if ($xlabel =~ /^-/) {
$xlabel = '\\' . $xlabel;
}
}
$chart->xAxis()->setLabels($x);
if ($spec->{x_label_pos}) {
$chart->xAxis()->setLabels($x)->setFontAngle(45) if ( $self->{total_x_length} > $self->{width}/8 );
$chart->xAxis()->setLabels($x)->setFontSize($self->{fontsize}, 0) if ($#$x > 30);
}
}
}
}
if ($spec->{graphtype} ne "pie" && $spec->{graphtype} ne "meter") {
my $x_titlecolor = $self->get_theme_value("x_titlecolor", "0xfffcf0");
$chart->xAxis()->setTitle($x_title, "arial.ttf", 10, hex($x_titlecolor)) if ($x_title);
}
}
sub write_line_graph_image {
&App::sub_entry if ($App::trace);
my ($self, $spec) = @_;
my $c = $self->new_xy_chart($spec);
my $data_set_colors;
if ($spec->{data_set_colors}) {
foreach my $color ( split(/,(?:\s+)?/, $spec->{data_set_colors}) ) {
$color =~ s/^#//;
push (@$data_set_colors, hex($color));
}
}
#Display 1 out of 3 labels on the x-axis.
# $c->xAxis()->setLabelStep(3);
#Set the labels on the x axis by spreading the labels evenly between the first
#point (index = 0) and the last point (index = noOfPoints - 1)
# $c->xAxis()->setLinearScale(0, $noOfPoints - 1, $labels);
# $c->xAxis()->setLinearScale(0, 2, $x);
#############
my @color_set = ("0xFF0000", "0xFF00", "0xFFFD00", "0xFF00FF", "0x6E641E", "0xA5BF8",
"0x44A816", "0x8B0000", "0x6495ED", "0xFF8C00", "0xA4E8B", "0xDEB887", "0x9932CC",
"0xAFC8", "0x55FF0000", "0x30D40", "0x708090", "0xBDB76B", "0xADD8E6");
#"0xFFC0CB", - This is no more needed - RNS 070831-000229
#############
my $x = $self->get_x($spec);
my $yn = $self->get_y($spec);
my ($layer, $dataset);
my @symbols = (
{ symbol => $perlchartdir::SquareSymbol, size => 7, },
{ symbol => $perlchartdir::DiamondSymbol, size => 9, },
{ symbol => $perlchartdir::CircleShape, size => 7, },
{ symbol => $perlchartdir::TriangleShape, size => 8, },
);
if ($spec->{area}) {
$layer = $c->addAreaLayer2($perlchartdir::Stack);
$spec->{stacked} = 0; # stacking is done for us in the area layer
}
else {
$layer = $c->addLineLayer2();
$layer->setLineWidth(2);
}
$layer->set3D(5) if ($spec->{"3D"});
if ($#$yn > 0) {
my ($stacked_y, $y, $dataset);
if ($spec->{stacked}) {
$stacked_y = [ ]; # make a copy
lib/App/Widget/ChartDirector.pm view on Meta::CPAN
# TODO: this needs more work before it really works
sub write_meter_graph_image {
&App::sub_entry if ($App::trace);
my ($self, $spec) = @_;
my $c = $self->new_meter_chart($spec);
my $x = $self->get_x($spec);
my $yn = $self->get_y($spec) || [[]];
my $value = $yn->[0][0];
my $radius = $spec->{radius};
my $center_x = $spec->{center_x};
my $center_y = $spec->{center_y};
#my $y_max = $spec->{y_max} || 100;
my $y_max = $value || 100;
my ($major_tick, $minor_tick, $micro_tick);
{
my $y_mantissa = $y_max;
my $y_scale = 1;
while ($y_mantissa > 1.0) {
$y_mantissa /= 10;
$y_scale *= 10;
}
if ($y_mantissa > 0.5) {
$y_max = $y_scale;
$minor_tick = $y_max/10;
$micro_tick = $y_max/20;
}
elsif ($y_mantissa > 0.2) {
$y_max = 0.5 * $y_scale;
$minor_tick = $y_max/25;
$micro_tick = undef;
}
else {
$y_max = 0.2 * $y_scale;
$minor_tick = $y_max/10;
$micro_tick = $y_max/20;
}
$major_tick = $y_max/5;
}
my $y_red = $spec->{y_red} || ($y_max * 0.80);
my $y_yellow = $spec->{y_yellow} || ($y_max * 0.60);
#Meter scale is 0 - 100, with major tick every 20 units, minor tick every 10
#units, and micro tick every 5 units
$c->setScale(0, $y_max, $major_tick, $minor_tick, $micro_tick);
#Set 0 - 60 as green (66FF66) zone
$c->addZone(0, $y_yellow, 0, $radius, 0x66ff66);
#Set 60 - 80 as yellow (FFFF33) zone
$c->addZone($y_yellow, $y_red, 0, $radius, 0xffff33);
#Set 80 - 100 as red (FF6666) zone
$c->addZone($y_red, $y_max, 0, $radius, 0xff6666);
#Add a text label centered at (100, 60) with 12 pts Arial Bold font
if ($spec->{y_title}) {
$c->addText($center_x, $center_y-int($radius * 0.35), $spec->{y_title},
"arialbd.ttf", 11, $perlchartdir::TextColor, $perlchartdir::Center);
}
my $x_title = "";
$x_title = $spec->{x_title} if ($spec->{x_title});
if ($x) {
$x_title .= ": " if ($x_title);
$x_title .= $x->[0];
}
if ($spec->{y_labels}) {
if ($x_title) {
$x_title .= " ($spec->{y_labels}[0])";
}
else {
$x_title = $spec->{y_labels}[0];
}
}
if ($x_title) {
$c->addText($center_x, $center_y+18, $x_title,
"arialbd.ttf", 10, $perlchartdir::TextColor, $perlchartdir::Center);
}
#Add a text box at the top right corner of the meter showing the value formatted
#to 2 decimal places, using white text on a black background, and with 1 pixel
#3D depressed border
$c->addText($center_x + int($radius * 0.7), $center_y - int($radius * 1.0),
$c->formatValue($value, "2"),
"arial.ttf", 8, 0xffffff)->setBackground(0x0, 0, -1);
#Add a semi-transparent blue (40666699) pointer with black border at the
#specified value
$value = $y_max if ($value > $y_max);
$value = 0 if ($value < 0);
$c->addPointer($value, 0x40666699, 0x0);
$c->makeChart($spec->{image_path});
&App::sub_exit() if ($App::trace);
}
sub write_pie_graph_image {
&App::sub_entry if ($App::trace);
my ($self, $spec) = @_;
my $c = $self->new_pie_chart($spec);
my $x = $self->get_x($spec);
my $yn = $self->get_y($spec);
my $data;
foreach my $y (@$yn) { push (@$data, @{$y}); }
if ($#$x > 0) {
$c->setData($data, $x);
}
else {
$c->setData($data, $spec->{y_labels});
}
# The depths for the sectors
#my $depths = [30, 20, 10, 10];
#$c->set3D2($depths);
#$c->setStartAngle(225);
$c->set3D() if ($spec->{"3D"});
$c->makeChart($spec->{image_path});
&App::sub_exit() if ($App::trace);
}
#my $data = [25, 18, 15, 12, 8, 30, 35];
##The labels for the pie chart
#my $labels = ["Labor", "Licenses", "Taxes", "Legal", "Insurance", "Facilities",
# "Production"];
##Create a PieChart object of size 360 x 300 pixels
#my $c = new PieChart(360, 300);
##Set the center of the pie at (180, 140) and the radius to 100 pixels
#$c->setPieSize(180, 140, 100);
##Add a title to the pie chart
#$c->addTitle("Project Cost Breakdown");
##Draw the pie in 3D
#$c->set3D();
##Set the pie data and the pie labels
#$c->setData($data, $labels);
# TODO: This one doesn't work yet
sub write_step_graph_image_step {
&App::sub_entry if ($App::trace);
my ($self, $spec) = @_;
require "perlchartdir.pm";
#Create a XYChart object of size 500 x 270 pixels, with a pale blue (0xe0e0ff)
#background, a light blue (0xccccff) border, and 1 pixel 3D border effect.
my $c = new XYChart(600, 350, 0xe0e0ff, 0xccccff, 1); #800
#Set the plotarea at (50, 50) and of size 420 x 180 pixels, using white
#(0xffffff) as the plot area background color. Turn on both horizontal and
#vertical grid lines with light grey color (0xc0c0c0)
$c->setPlotArea(50, 50, 320, 260, 0xffffff)->setGridColor(0xc0c0c0, 0xc0c0c0); #720
#Add a legend box at (55, 25) (top of the chart) with horizontal layout. Use 10
#pts Arial Bold Italic font. Set the background and border color to Transparent.
$c->addLegend(55, 20, 0, "arialbi.ttf", 10)->setBackground($perlchartdir::Transparent);
#Add a title to the chart using 14 points Times Bold Itatic font, using blue
#(0x9999ff) as the background color
$c->addTitle("Rate History", "arialbi.ttf", 12)->setBackground(0x9999ff);
#Set the y axis label format to display a percentage sign
#$c->yAxis()->setLabelFormat("{value}%");
my $labels = $spec->{labels} || [ "Unknown" ];
my $default_colors =
[ 0x0000ff, 0x00ff00, 0xff0000, 0x00ffff, 0xff00ff, 0xffff00,
0x111199, 0x119911, 0x991111, 0x119999, 0x991199, 0x999911,
0x3333dd, 0x33dd33, 0xdd3333, 0x33dddd, 0xdd33dd, 0xdddd33,
0x2222bb, 0x22bb22, 0xbb2222, 0x22bbbb, 0xbb22bb, 0xbbbb22 ];
my $colors = $spec->{colors} || $default_colors;
my ($label, $color, $step_xaxis, $xaxis, $yaxis, $layer);
for (my $i = 0; $i <= $#$labels; $i++) {
$label = $labels->[$i];
$color = $colors->[$i] || 0;
if ($color =~ /^0[xX][0-9A-Fa-f]+$/) {
$color = eval $color;
}
$xaxis = $spec->{"x$i"} || [ $i, $i+1, $i+2, $i+3 ];
$yaxis = $spec->{"y$i"} || [ $i, $i+1, $i+2, $i+3 ];
# set the xAxis scale
#$c->xAxis()->setLinearScale($xaxis->[0] - 1, $xaxis->[$#$xaxis], 1, 0);
$c->xAxis()->setAutoScale(0,0,1);
$c->yAxis()->setAutoScale(0,0,1);
$c->xAxis()->setIndent(1);
# we decrement the $step_xaxis values by a day to account for the fact that
# the step function runs from left to right but that the spec-> occurred
# from right to left.
$step_xaxis = [ @$xaxis ]; # make a copy
for (my $x = 0; $x <= $#$step_xaxis; $x++) {
$step_xaxis->[$x]--;
}
#Add a step line layer to the chart and set the line width to 2 pixels
$layer = $c->addStepLineLayer($yaxis, $color, $label);
#$layer->setXData($step_xaxis);
$layer->setLineWidth(2);
# Add a line layer to the chart
# $layer = $c->addLineLayer();
# Add the line. Plot the points with a 9 pixel diamond symbol
# $layer->addDataSet($yaxis, $color)->setDataSymbol( $perlchartdir::DiamondSymbol, 9);
# Enable data label on the data points. Set the label format to nn%.
# $layer->setDataLabelFormat("{value}");
}
print $c->makeChart($spec->{image_path});
&App::sub_exit() if ($App::trace);
}
sub write_step_graph_image {
&App::sub_entry if ($App::trace);
my ($self, $spec) = @_;
my $c = $self->new_xy_chart($spec);
my $x = $self->get_x($spec);
( run in 1.429 second using v1.01-cache-2.11-cpan-5735350b133 )