grthtrhthjhtyjytjytkergtrhtrjytjerhrfh4:24 29/09/2026 */ class AOR_Chart extends Basic { const COLOUR_DEFAULTS = "['#1f78b4','#a6cee3','#b2df8a','#33a02c','#fb9a99','#e31a1c','#fdbf6f','#ff7f00','#cab2d6','#6a3d9a','#ffff99','#b15928','#144c73','#6caed1','#8acf4e','#20641c','#f8514f','#9e1214','#fc9d24','#b35900','#a880bb','#442763','#ffff4d','#733a1a']"; public $colours; public $new_schema = true; public $module_dir = 'AOR_Charts'; public $object_name = 'AOR_Chart'; public $table_name = 'aor_charts'; public $importable = true; public $disable_row_level_security = true ; public $id; public $name; public $date_entered; public $date_modified; public $modified_user_id; public $modified_by_name; public $created_by; public $created_by_name; public $description; public $deleted; public $created_by_link; public $modified_user_link; public $type; public $x_field; public $y_field; public $noDataMessage = "No Results"; public function __construct() { parent::__construct(); $this->colours = self::COLOUR_DEFAULTS; } /** * @deprecated deprecated since version 7.6, PHP4 Style Constructors are deprecated and will be remove in 7.8, please update your code, use __construct instead */ public function AOR_Chart() { $deprecatedMessage = 'PHP4 Style Constructors are deprecated and will be remove in 7.8, please update your code'; if (isset($GLOBALS['log'])) { $GLOBALS['log']->deprecated($deprecatedMessage); } else { trigger_error($deprecatedMessage, E_USER_DEPRECATED); } self::__construct(); } public function save_lines(array $post, AOR_Report $bean, $postKey) { $seenIds = array(); if (isset($post[$postKey.'id'])) { foreach ($post[$postKey . 'id'] as $key => $id) { if ($id && $post['record']!='') { $aorChart = BeanFactory::getBean('AOR_Charts', $id); } else { $aorChart = BeanFactory::newBean('AOR_Charts'); } $aorChart->name = $post[$postKey . 'title'][$key]; $aorChart->type = $post[$postKey . 'type'][$key]; $aorChart->x_field = $post[$postKey . 'x_field'][$key]; $aorChart->y_field = $post[$postKey . 'y_field'][$key]; $aorChart->aor_report_id = $bean->id; $aorChart->save(); $seenIds[] = $aorChart->id; } } //Any beans that exist but aren't in $seenIds must have been removed. foreach ($bean->get_linked_beans('aor_charts', 'AOR_Charts') as $chart) { if (!in_array($chart->id, $seenIds)) { $chart->mark_deleted($chart->id); } } } private function getValidChartTypes() { return array('bar','line','pie','radar','rose', 'grouped_bar', 'stacked_bar'); } private function getColour($seed, $rgbArray = false) { $hash = md5($seed); $r = hexdec(substr($hash, 0, 2)); $g = hexdec(substr($hash, 2, 2)); $b = hexdec(substr($hash, 4, 2)); if ($rgbArray) { return array('R'=>$r,'G'=>$g,'B'=>$b); } $highR = $r + 10; $highG = $g + 10; $highB = $b + 10; $main = '#'.str_pad(dechex($r), 2, '0', STR_PAD_LEFT) .str_pad(dechex($g), 2, '0', STR_PAD_LEFT) .str_pad(dechex($b), 2, '0', STR_PAD_LEFT); $highlight = '#'.dechex($highR).dechex($highG).dechex($highB); return array('main'=>$main,'highlight'=>$highlight); } public function buildChartImageBar($chartPicture, $recordImageMap = false) { $scaleSettings = array("DrawSubTicks" => false, "LabelRotation" => 30, 'MinDivHeight' => 50); $chartPicture->drawScale($scaleSettings); $chartPicture->drawBarChart(array("RecordImageMap"=>$recordImageMap)); } public function buildChartImagePie($chartPicture, $chartData, $reportData, $imageHeight, $imageWidth, $xName, $recordImageMap) { $PieChart = new pPie($chartPicture, $chartData); $x = 0; foreach ($reportData as $row) { $PieChart->setSliceColor($x, $this->getColour($row[$xName], true)); $x++; } $PieChart->draw2DPie($imageWidth/3, $imageHeight/2, array("Border"=>true,'Radius'=>200,''=>true,"RecordImageMap"=>$recordImageMap)); $PieChart->drawPieLegend($imageWidth*0.7, $imageHeight/3, array('FontSize'=>10,"FontName"=>"modules/AOR_Charts/lib/pChart/fonts/verdana.ttf",'BoxSize'=>14)); } public function buildChartImageLine($chartPicture, $recordImageMap = false) { $scaleSettings = array("XMargin"=>10,"YMargin"=>10,"GridR"=>200,"GridG"=>200,"GridB"=>200,'MinDivHeight' => 50,"LabelRotation" => 30); $chartPicture->drawScale($scaleSettings); $chartPicture->drawLineChart(array("RecordImageMap"=>$recordImageMap)); } public function buildChartImageRadar($chartPicture, $chartData, $recordImageMap) { $SplitChart = new pRadar(); $Options = array("LabelPos"=>RADAR_LABELS_HORIZONTAL,"RecordImageMap"=>$recordImageMap); $SplitChart->drawRadar($chartPicture, $chartData, $Options); } public function buildChartImage(array $reportData, array $fields, $asDataURI = true, $generateImageMapId = false) { global $current_user; require_once 'modules/AOR_Charts/lib/pChart/pChart.php'; if ($generateImageMapId !== false) { $generateImageMapId = $current_user->id."-".$generateImageMapId; } $html = ''; if (!in_array($this->type, $this->getValidChartTypes())) { return $html; } $x = $fields[$this->x_field]; $y = $fields[$this->y_field]; if (!$x || !$y) { //Malformed chart object - missing an axis field return ''; } $xName = str_replace(' ', '_', $x->label) . $this->x_field; $yName = str_replace(' ', '_', $y->label) . $this->y_field; $chartData = new pData(); $chartData->loadPalette("modules/AOR_Charts/lib/pChart/palettes/navy.color", true); $labels = array(); foreach ($reportData as $row) { $chartData->addPoints($row[$yName], 'data'); $chartData->addPoints($row[$xName], 'Labels'); $labels[] = $row[$xName]; } $chartData->setSerieDescription("Months", "Month"); $chartData->setAbscissa("Labels"); $imageHeight = 700; $imageWidth = 700; $chartPicture = new pImage($imageWidth, $imageHeight, $chartData); if ($generateImageMapId) { $imageMapDir = create_cache_directory('modules/AOR_Charts/ImageMap/'.$current_user->id.'/'); $chartPicture->initialiseImageMap($generateImageMapId, IMAGE_MAP_STORAGE_FILE, $generateImageMapId, $imageMapDir); } $chartPicture->Antialias = true; $chartPicture->drawFilledRectangle(0, 0, $imageWidth-1, $imageHeight-1, array("R"=>240,"G"=>240,"B"=>240,"BorderR"=>0,"BorderG"=>0,"BorderB"=>0,)); $chartPicture->setFontProperties(array("FontName"=>"modules/AOR_Charts/lib/pChart/fonts/verdana.ttf","FontSize"=>14)); $chartPicture->drawText($imageWidth/2, 20, $this->name, array("R"=>0,"G"=>0,"B"=>0,'Align'=>TEXT_ALIGN_TOPMIDDLE)); $chartPicture->setFontProperties(array("FontName"=>"modules/AOR_Charts/lib/pChart/fonts/verdana.ttf","FontSize"=>6)); $chartPicture->setGraphArea(60, 60, $imageWidth-60, $imageHeight-100); switch ($this->type) { case 'radar': $this->buildChartImageRadar($chartPicture, $chartData, !empty($generateImageMapId)); break; case 'pie': $this->buildChartImagePie($chartPicture, $chartData, $reportData, $imageHeight, $imageWidth, $xName, !empty($generateImageMapId)); break; case 'line': $this->buildChartImageLine($chartPicture, !empty($generateImageMapId)); break; case 'bar': default: $this->buildChartImageBar($chartPicture, !empty($generateImageMapId)); break; } if ($generateImageMapId) { $chartPicture->replaceImageMapTitle("data", $labels); } ob_start(); $chartPicture->render(null); $img = ob_get_clean(); if ($asDataURI) { return 'data:image/png;base64,'.base64_encode($img); } return $img; } public function buildChartHTML(array $reportData, array $fields, $index = 0, $chartType = AOR_Report::CHART_TYPE_PCHART, AOR_Field $mainGroupField = null) { switch ($chartType) { case AOR_Report::CHART_TYPE_PCHART: return $this->buildChartHTMLPChart($reportData, $fields, $index); case AOR_Report::CHART_TYPE_CHARTJS: return $this->buildChartHTMLChartJS($reportData, $fields); case AOR_Report::CHART_TYPE_RGRAPH: return $this->buildChartHTMLRGraph($reportData, $fields, $mainGroupField); } return ''; } /** * * @param type $labels * @return boolean Returns TRUE if colours successfully changed. FALSE on error and using colour defaults. */ private function generateChartColoursFromLabels($labels) { if (is_array($labels) && count($labels) > 1) { $colours = []; foreach ($labels as $onelabel) { $hash = md5($onelabel); $colours[] = substr($hash, 0, 6); } $this->colours = "['#" . implode($colours, "','#") . "']"; return true; } LoggerManager::getLogger()->warn('Incorrect labels given. Using default colours in charts.'); $this->colours = self::COLOUR_DEFAULTS; return false; } private function buildChartHTMLRGraph(array $reportData, array $fields, AOR_Field $mainGroupField = null) { $html = ''; if (!in_array($this->type, $this->getValidChartTypes())) { return $html; } $x = $fields[$this->x_field]; $y = $fields[$this->y_field]; if (!$x || !$y) { //Malformed chart object - missing an axis field return ''; } $xName = str_replace(' ', '_', $x->label) . $this->x_field; $yName = str_replace(' ', '_', $y->label) . $this->y_field; $defaultHeight = 500; $defaultWidth = 900; switch ($this->type) { /* //Polar was not implemented for the previous library (it is not in the getValidChartTypes method) case 'polar': $chartFunction = 'PolarArea'; $data = $this->getPolarChartData($reportData, $xName,$yName); $config = $this->getPolarChartConfig(); break; */ case 'radar': $chartFunction = 'Radar'; $data = $this->getRGraphBarChartData($reportData, $xName, $yName); $valid = $this->generateChartColoursFromLabels($data['labels']); $config = $this->getRadarChartConfig(); $chart = $this->getRGraphRadarChart(json_encode($data['data']), json_encode($data['labels']), json_encode($data['tooltips']), $this->name, $this->id, $defaultHeight, $defaultWidth); break; case 'pie': $chartFunction = 'Pie'; $data = $this->getRGraphBarChartData($reportData, $xName, $yName); $valid = $this->generateChartColoursFromLabels($data['labels']); $config = $this->getPieChartConfig(); $chart = $this->getRGraphPieChart(json_encode($data['data']), json_encode($data['labels']), json_encode($data['tooltips']), $this->name, $this->id, $defaultHeight, $defaultWidth); break; case 'line': $chartFunction = 'Line'; $data = $this->getRGraphBarChartData($reportData, $xName, $yName); $valid = $this->generateChartColoursFromLabels($data['labels']); $config = $this->getLineChartConfig(); $chart = $this->getRGraphLineChart(json_encode($data['data']), json_encode($data['labels']), json_encode($data['tooltips']), $this->name, $this->id, $defaultHeight, $defaultWidth); break; case 'rose': $chartFunction = 'Rose'; $data = $this->getRGraphBarChartData($reportData, $xName, $yName); $valid = $this->generateChartColoursFromLabels($data['labels']); $config = $this->getRoseChartConfig(); $chart = $this->getRGraphRoseChart(json_encode($data['data']), json_encode($data['labels']), json_encode($data['tooltips']), $this->name, $this->id, $defaultHeight, $defaultWidth); break; case 'grouped_bar': $chartFunction = 'Grouped bar'; $data = $this->getRGraphGroupedBarChartData($reportData, $xName, $yName, $mainGroupField); $valid = $this->generateChartColoursFromLabels($data['labels']); $config = $this->getGroupedBarChartConfig(); $chart = $this->getRGraphGroupedBarChart(json_encode($data['data']), json_encode($data['labels']), json_encode($data['tooltips']), $this->name, $this->id, $defaultHeight, $defaultWidth, true); break; case 'stacked_bar': $chartFunction = 'Stacked bar'; $data = $this->getRGraphGroupedBarChartData($reportData, $xName, $yName, $mainGroupField); $valid = $this->generateChartColoursFromLabels($data['labels']); $config = $this->getStackedBarChartConfig(); $chart = $this->getRGraphGroupedBarChart(json_encode($data['data']), json_encode($data['labels']), json_encode($data['tooltips']), $this->name, $this->id, $defaultHeight, $defaultWidth, false); break; case 'bar': default: $chartFunction = 'Bar'; $data = $this->getRGraphBarChartData($reportData, $xName, $yName); $valid = $this->generateChartColoursFromLabels($data['labels']); $config = $this->getBarChartConfig(); $chart = $this->getRGraphBarChart(json_encode($data['data']), json_encode($data['labels']), json_encode($data['tooltips']), $this->name, $this->id, $defaultHeight, $defaultWidth); break; } if (!$valid) { // exception LoggerManager::getLogger()->error("Invalid char data labels detected for chart type: $this->type"); } return $chart; } private function getRGraphRoseChart($chartDataValues, $chartLabelValues, $chartTooltips, $chartName, $chartId, $chartHeight = 400, $chartWidth = 400) { $dataArray = json_decode($chartDataValues); if (!is_array($dataArray)||count($dataArray) < 1) { return "