ONO::Lib::PDF::Elements::Chart

package ONO::Lib::PDF::Elements::Chart;
################################################################################
# COPYRIGHT / LICENSE #
################################################################################
#
# This file is part of the ONO Software Project.
#
# Copyright (C) 2000-2025 Jos KIRPS [ www.kirps.com | jos_AT_kirps_DOT_com ]
# and The Joopita Project [ www.joopita.org | contact_AT_joopita_DOT_com ]
#
# This file, as well as other parts of the ONO Software Project or related
# elements, are FREE SOFTWARE available under the ARTISTIC LICENSE 2.0.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
#
# For the full license, see /ono/osr/license/LICENSE.txt, or write to
# jos_AT_kirps_DOT_com or contact_AT_joopita_DOT_com.
#
################################################################################
# END OF COPYRIGHT / LICENSE, HERE COMES THE CODE ... #
################################################################################

use strict;

use ONO::IO;

use ONO::Lib::PDF::Draw;

use ONO::Lib::Image::Canvas::Draw;

#: This module generates specific PDF content.

sub chart {

my (
$self,
$canvas,
$type,
$x,
$y,
$width,
$height,
$weight,
$data_ref,

) = @_;

#: This generates a chart image, output can be HTML and/or PDF.
#:
#: The data hash may contain addtional instructions:
#:
#: debug adds DEBUG stream to HTML variable, work in both HTML and PDF mode
#: html enables HTML generation, disables PDF generation
#:
#: elements
#:
#: element_X_degrees
#: element_X_percent
#: element_X_color
#:
#: ori (h/v)
#:
#: cols
#: rows

my %data = %$data_ref;

my ($HTML,$weight2);

if ($weight) {
$weight = 1;
}

if ($data{"elements"}) {
$weight2 = $weight;
}

my $canvas2 = "0:0:0:0";

my $DEBUG = "ONO_Lib_PDF_Elements_Chart, $type, ";

if ($type eq "pie") {

$DEBUG .= "pie, ";

my $wh = $width/2;

my $x2 = $x+$wh;
my $y2 = $y+$wh;

my $start = 0;

$DEBUG .= qq~elements: $data{"elements"}, ~;

for (my $i = 1; $i < $data{"elements"}+1; $i++) {

if ($data{"element_${i}_degrees"}) {

$DEBUG .= qq~element ($data{"element_${i}_degrees"},$data{"element_${i}_color"}), ~;

my $end = $start + $data{"element_${i}_degrees"};

if ($data{'html'}) {
$HTML .= ONO::Lib::Image::Canvas::Draw->pie($canvas2,$x2,$y2-($wh/2)-1,($wh/2)-2,1,"","",$data{'elements'},$data_ref);
} else {
ONO::Lib::PDF::Draw->pie($canvas,$x2,$y2,$wh,$start,$end,$weight2,"0:0:0:0",$data{"element_${i}_color"});
}

$start = $end;

}

}

if ($data{'html'}) {
} else {
ONO::Lib::PDF::Draw->circle($canvas,$x2,$y2,$wh,$weight);
}

}

if ($type eq "bar") {

$DEBUG .= "bar, ";

my $start_x = $x;
my $start_y = $y;

my ($off_x,$off_y);

my $ratio = 1;
my $height2 = $height;
my $width2 = $width;



if ($data{"rows"}) {
$ratio = $data{"rows"};
$height2 = $height/$data{"rows"};
}

if ($data{"cols"}) {
$width2 = $width/$data{"cols"};
}

$DEBUG .= "elements = $data{'elements'}, rows = $data{'rows'}, cols = $data{'cols'}, ";

for (my $i = 1; $i < $data{"elements"}+1; $i++) {

if ($data{"element_${i}_percent"}) {

$DEBUG .= "element ( ";

my $end_x = $start_x+$width/100*$data{"element_${i}_percent"}*$ratio;
my $end_y = $start_y+$height2;

if ($data{"ori"} eq "v") {
$end_x = $start_x+$width2;
$end_y = $start_y+$height2/100*$data{"element_${i}_percent"}*$ratio;
}

if ($data{'html'}) {
$HTML .= ONO::Lib::Image::Canvas::Draw->rect($canvas2,$start_x+$off_x,$start_y+$off_y,$end_x+$off_x,$end_y+$off_y,$weight,"",$data{"element_${i}_color"});
} else {
ONO::Lib::PDF::Draw->rect($canvas,$start_x+$off_x,$start_y+$off_y,$end_x+$off_x,$end_y+$off_y,0,"",$data{"element_${i}_color"});
}

if ($data{"ori"} eq "" || $data{"ori"} eq "h") {
$start_x = $end_x;
if ($data{"rows"}) {
if ($i%($data{"elements"}/$data{"rows"}) == 0) {
$start_x = $x;
$start_y = $start_y + $height2;
}
}
}

if ($data{"ori"} eq "v") {
$start_y = $end_y;
if ($data{"cols"}) {
if ($i%($data{"elements"}/$data{"cols"}) == 0) {
$start_x = $start_x + $width2;
$start_y = $y;
}
}
}

$DEBUG .= "), ";

}
}

if ($data{'html'}) {
$HTML .= ONO::Lib::Image::Canvas::Draw->rect($canvas2,$x,$y,$x+$width,$y+$height,$weight);
for (my $r = 0; $r < $data{"rows"}; $r++) {
$HTML .= ONO::Lib::Image::Canvas::Draw->line($canvas2,$x,$y+($height/$data{"rows"})*$r,$x+$width,$y+($height/$data{"rows"})*$r,$weight,"0:0:0:0");
}
for (my $c = 0; $c < $data{"cols"}; $c++) {
$HTML .= ONO::Lib::Image::Canvas::Draw->line($canvas2,$x+($width/$data{"cols"})*$c,$y,$x+($width/$data{"cols"})*$c,$y+$height,$weight,"0:0:0:0");
}
} else {
ONO::Lib::PDF::Draw->rect($canvas,$x,$y,$x+$width,$y+$height,$weight);
for (my $r = 0; $r < $data{"rows"}; $r++) {
ONO::Lib::PDF::Draw->line($canvas,$x,$y+($height/$data{"rows"})*$r,$x+$width,$y+($height/$data{"rows"})*$r,$weight);
}
for (my $c = 0; $c < $data{"cols"}; $c++) {
ONO::Lib::PDF::Draw->line($canvas,$x+($width/$data{"cols"})*$c,$y,$x+($width/$data{"cols"})*$c,$y+$height,$weight);
}
}

}

if ($type eq "dots") {

$DEBUG .= "dots, ";

if ($data{'html'}) {
# no outer rect will be drawn in HTML mode
} else {
ONO::Lib::PDF::Draw->rect($canvas,$x,$y,$x+$width,$y+$height,$weight/10,"","0:244:244:244",2);
}

my $radius = $width;
if (!$radius) {
$radius = 1;
}
my $dots_fit_in = 0;

my $whilecounter;
while ($whilecounter < 256 && $dots_fit_in < $data{"elements"}+1) {
$whilecounter++;
my $max_dots_in_x = int($width/($radius*2));
my $max_dots_in_y = int($height/($radius*2));
$dots_fit_in = $max_dots_in_x * $max_dots_in_y;
$radius = $radius*0.97;
}

my ($off_x,$off_y) = ($radius,$radius);

for (my $i = 1; $i < $data{"elements"}+1; $i++) {

if ($data{'html'}) {
$HTML .= ONO::Lib::Image::Canvas::Draw->circle($canvas2,$x+$off_x+0.5,$y+$off_y+0.5,$radius*0.8,$weight,$data{"element_${i}_color"},"0:0:0:0");
} else {
ONO::Lib::PDF::Draw->circle($canvas,$x+$off_x+0.5,$y+$off_y+0.5,$radius*0.8,$weight,$data{"element_${i}_color"});
}

$off_x = $off_x + $radius*2;

if ($off_x > $width-$radius*1.2) {
$off_x = $radius;
$off_y = $off_y + $radius*2;
}

}

}

$HTML = ONO::Lib::Image::Canvas::Draw->canvas_render($HTML,$width,$height);

if (ONO::IO->devstation && $data{'debug'}) {
$HTML = qq~<div class="bo">$HTML$DEBUG</div>~;
}

return $HTML;

}

###############################################################################
# end of script
###############################################################################

1;

__END__