mirror of
https://github.com/salesagility/SuiteCRM.git
synced 2024-12-22 12:28:31 +00:00
841 lines
31 KiB
PHP
Executable File
841 lines
31 KiB
PHP
Executable File
<?php
|
|
/**
|
|
* Advanced OpenReports, SugarCRM Reporting.
|
|
* @package Advanced OpenReports for SugarCRM
|
|
* @copyright SalesAgility Ltd http://www.salesagility.com
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE as published by
|
|
* the Free Software Foundation; either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* 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. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
|
|
* along with this program; if not, see http://www.gnu.org/licenses
|
|
* or write to the Free Software Foundation,Inc., 51 Franklin Street,
|
|
* Fifth Floor, Boston, MA 02110-1301 USA
|
|
*
|
|
* @author SalesAgility <info@salesagility.com>
|
|
*/
|
|
|
|
#[\AllowDynamicProperties]
|
|
class AOR_Chart extends Basic
|
|
{
|
|
public 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;
|
|
}
|
|
|
|
|
|
|
|
|
|
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(' ', '_', (string) $x->label) . $this->x_field;
|
|
$yName = str_replace(' ', '_', (string) $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(' ', '_', (string) $x->label) . $this->x_field;
|
|
$yName = str_replace(' ', '_', (string) $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((string) $chartDataValues);
|
|
if (!is_array($dataArray)||count($dataArray) < 1) {
|
|
return "<h3>$this->noDataMessage</h3>";
|
|
}
|
|
$html = '';
|
|
$html .= "<canvas id='$chartId' width='$chartWidth' height='$chartHeight' class='resizableCanvas'></canvas>";
|
|
$html .= <<<EOF
|
|
<script>
|
|
new RGraph.Rose({
|
|
id: '$chartId',
|
|
options:{
|
|
//title: '$chartName',
|
|
//labels: $chartLabelValues,
|
|
//textSize:8,
|
|
textSize:10,
|
|
//titleSize:10,
|
|
tooltips:$chartTooltips,
|
|
tooltipsEvent:'onmousemove',
|
|
tooltipsCssClass: 'rgraph_chart_tooltips_css',
|
|
colors: $this->colours,
|
|
colorsSequential:true
|
|
},
|
|
data: $chartDataValues
|
|
}).draw();
|
|
</script>
|
|
EOF;
|
|
return $html;
|
|
}
|
|
|
|
|
|
|
|
//I have not used a parameter for getRGraphBarChart to say whether to group etc, as the future development could be quite different
|
|
//for both, hence the separate methods. However, the $grouped parameter allows us to specify whether the chart is grouped (true)
|
|
//or stacked (false)
|
|
private function getRGraphGroupedBarChart($chartDataValues, $chartLabelValues, $chartTooltips, $chartName, $chartId, $chartHeight = 400, $chartWidth = 400, $grouped = false)
|
|
{
|
|
$dataArray = json_decode((string) $chartDataValues);
|
|
$grouping = 'grouped'; //$mainGroupField->label; //'grouped';
|
|
if (!$grouped) {
|
|
$grouping='stacked';
|
|
}
|
|
if (!is_array($dataArray)||count($dataArray) < 1) {
|
|
return "<h3>$this->noDataMessage</h3>";
|
|
}
|
|
$html = '';
|
|
$html .= "<canvas id='$chartId' width='$chartWidth' height='$chartHeight' class='resizableCanvas'></canvas>";
|
|
$html .= <<<EOF
|
|
<script>
|
|
new RGraph.Bar({
|
|
id: '$chartId',
|
|
data: $chartDataValues,
|
|
options: {
|
|
grouping:'$grouping',
|
|
backgroundGrid:false,
|
|
backgroundGrid:false,
|
|
gutterBottom: 150,
|
|
gutterTop:25,
|
|
gutterLeft:128,
|
|
title: '$chartName',
|
|
|
|
tooltips:$chartTooltips,
|
|
tooltipsEvent:'onmousemove',
|
|
tooltipsCssClass: 'rgraph_chart_tooltips_css',
|
|
|
|
shadow:false,
|
|
titleSize:10,
|
|
labels: $chartLabelValues,
|
|
textSize:10,
|
|
textAngle: 90,
|
|
colors: $this->colours,
|
|
ymax:calculateMaxYForSmallNumbers($chartDataValues)
|
|
}
|
|
}).draw();
|
|
</script>
|
|
EOF;
|
|
return $html;
|
|
}
|
|
|
|
|
|
|
|
private function getRGraphBarChart($chartDataValues, $chartLabelValues, $chartTooltips, $chartName, $chartId, $chartHeight = 400, $chartWidth = 400)
|
|
{
|
|
$dataArray = json_decode((string) $chartDataValues);
|
|
if (!is_array($dataArray)||count($dataArray) < 1) {
|
|
return "<h3>$this->noDataMessage</h3>";
|
|
}
|
|
$html = '';
|
|
$html .= "<canvas id='$chartId' width='$chartWidth' height='$chartHeight' class='resizableCanvas'></canvas>";
|
|
$html .= <<<EOF
|
|
<script>
|
|
new RGraph.Bar({
|
|
id: '$chartId',
|
|
data: $chartDataValues,
|
|
options: {
|
|
title: '$chartName',
|
|
gutterBottom: 150,
|
|
gutterLeft: 128,
|
|
gutterTop: 25,
|
|
//title: '$chartName',
|
|
labels: $chartLabelValues,
|
|
colorsSequential:true,
|
|
textAngle: 90,
|
|
textSize:10,
|
|
titleSize:10,
|
|
backgroundGrid:false,
|
|
|
|
tooltips:$chartTooltips,
|
|
tooltipsCssClass: 'rgraph_chart_tooltips_css',
|
|
tooltipsEvent:'onmousemove',
|
|
|
|
colors: $this->colours,
|
|
ymax:calculateMaxYForSmallNumbers($chartDataValues)
|
|
}
|
|
}).draw();
|
|
</script>
|
|
EOF;
|
|
return $html;
|
|
}
|
|
|
|
private function getRGraphRadarChart($chartDataValues, $chartLabelValues, $chartTooltips, $chartName, $chartId, $chartHeight = 400, $chartWidth = 400)
|
|
{
|
|
$dataArray = json_decode((string) $chartDataValues);
|
|
if (!is_array($dataArray)||count($dataArray) < 1) {
|
|
return "<h3>$this->noDataMessage</h3>";
|
|
}
|
|
$html = '';
|
|
$html .= "<canvas id='$chartId' width='$chartWidth' height='$chartHeight' class='resizableCanvas'></canvas>";
|
|
$html .= <<<EOF
|
|
<script>
|
|
new RGraph.Radar({
|
|
id: '$chartId',
|
|
data: $chartDataValues,
|
|
options: {
|
|
title: '$chartName',
|
|
labels: $chartLabelValues,
|
|
textSize:10,
|
|
|
|
|
|
tooltips:$chartTooltips,
|
|
tooltipsEvent:'onmousemove',
|
|
tooltipsCssClass: 'rgraph_chart_tooltips_css',
|
|
|
|
colors: $this->colours,
|
|
ymax:calculateMaxYForSmallNumbers($chartDataValues)
|
|
}
|
|
}).draw();
|
|
</script>
|
|
EOF;
|
|
return $html;
|
|
}
|
|
|
|
private function getRGraphPieChart($chartDataValues, $chartLabelValues, $chartTooltips, $chartName, $chartId, $chartHeight = 400, $chartWidth = 400)
|
|
{
|
|
$dataArray = json_decode((string) $chartDataValues);
|
|
if (!is_array($dataArray)||count($dataArray) < 1) {
|
|
return "<h3>$this->noDataMessage</h3>";
|
|
}
|
|
/*
|
|
if($chartHeight > 400)
|
|
$chartHeight = 400;
|
|
if($chartWidth > 600)
|
|
$chartWidth = 400;
|
|
*/
|
|
$html = '';
|
|
$html .= "<canvas id='$chartId' width='$chartWidth' height='$chartHeight' class='resizableCanvas'></canvas>";
|
|
$html .= <<<EOF
|
|
<script>
|
|
new RGraph.Pie({
|
|
id: '$chartId',
|
|
data: $chartDataValues,
|
|
options: {
|
|
title: '$chartName',
|
|
textSize:10,
|
|
titleSize:10,
|
|
tooltips:$chartTooltips,
|
|
tooltipsEvent:'onmousemove',
|
|
tooltipsCssClass: 'rgraph_chart_tooltips_css',
|
|
labels: $chartLabelValues,
|
|
colors: $this->colours
|
|
}
|
|
}).draw();
|
|
</script>
|
|
EOF;
|
|
return $html;
|
|
}
|
|
|
|
private function getRGraphLineChart($chartDataValues, $chartLabelValues, $chartTooltips, $chartName, $chartId, $chartHeight = 400, $chartWidth = 400)
|
|
{
|
|
$dataArray = json_decode((string) $chartDataValues);
|
|
if (!is_array($dataArray)||count($dataArray) < 1) {
|
|
return "<h3>$this->noDataMessage</h3>";
|
|
}
|
|
$html = '';
|
|
$html .= "<canvas id='$chartId' width='$chartWidth' height='$chartHeight' class='resizableCanvas'></canvas>";
|
|
$html .= <<<EOF
|
|
<script>
|
|
new RGraph.Line({
|
|
id: '$chartId',
|
|
data: $chartDataValues,
|
|
options: {
|
|
title: '$chartName',
|
|
gutterBottom: 150,
|
|
//gutterTop:50,
|
|
tickmarks:'encircle',
|
|
textSize:10,
|
|
titleSize:10,
|
|
gutterLeft:128,
|
|
//title: '$chartName',
|
|
labels: $chartLabelValues,
|
|
|
|
tooltips:$chartTooltips,
|
|
tooltipsEvent:'onmousemove',
|
|
tooltipsCssClass: 'rgraph_chart_tooltips_css',
|
|
|
|
tickmarks:'circle',
|
|
|
|
textAngle: 90,
|
|
//titleSize:10,
|
|
backgroundGrid:false,
|
|
colors: $this->colours,
|
|
ymax:calculateMaxYForSmallNumbers($chartDataValues),
|
|
}
|
|
}).draw();
|
|
</script>
|
|
EOF;
|
|
return $html;
|
|
}
|
|
|
|
private function buildChartHTMLChartJS(array $reportData, array $fields)
|
|
{
|
|
$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(' ', '_', (string) $x->label) . $this->x_field;
|
|
$yName = str_replace(' ', '_', (string) $y->label) . $this->y_field;
|
|
|
|
switch ($this->type) {
|
|
case 'radar':
|
|
$chartFunction = 'Radar';
|
|
$data = $this->getRadarChartData($reportData, $xName, $yName);
|
|
$config = $this->getRadarChartConfig();
|
|
break;
|
|
case 'pie':
|
|
$chartFunction = 'Pie';
|
|
$data = $this->getPieChartData($reportData, $xName, $yName);
|
|
$config = $this->getPieChartConfig();
|
|
break;
|
|
case 'line':
|
|
$chartFunction = 'Line';
|
|
$data = $this->getLineChartData($reportData, $xName, $yName);
|
|
$config = $this->getLineChartConfig();
|
|
break;
|
|
case 'bar':
|
|
default:
|
|
$chartFunction = 'Bar';
|
|
$data = $this->getBarChartData($reportData, $xName, $yName);
|
|
$config = $this->getBarChartConfig();
|
|
break;
|
|
}
|
|
$data = json_encode($data);
|
|
$config = json_encode($config);
|
|
$chartId = 'chart'.$this->id;
|
|
$html .= "<h3>{$this->name}</h3>";
|
|
$html .= "<canvas id='{$chartId}' width='400' height='400'></canvas>";
|
|
$html .= <<<EOF
|
|
<script>
|
|
$(document).ready(function(){
|
|
SUGAR.util.doWhen("typeof Chart != 'undefined'", function(){
|
|
var data = {$data};
|
|
var ctx = document.getElementById("{$chartId}").getContext("2d");
|
|
console.log('Creating new chart');
|
|
var config = {$config};
|
|
var chart = new Chart(ctx).{$chartFunction}(data, config);
|
|
var legend = chart.generateLegend();
|
|
$('#{$chartId}').after(legend);
|
|
});
|
|
});
|
|
</script>
|
|
EOF;
|
|
return $html;
|
|
}
|
|
|
|
private function buildChartHTMLPChart(array $reportData, array $fields, $index = 0)
|
|
{
|
|
$html = '';
|
|
$imgUri = $this->buildChartImage($reportData, $fields, true, $index);
|
|
$img = "<img id='{$this->id}_img' src='{$imgUri}'>";
|
|
$html .= $img;
|
|
$html .= <<<EOF
|
|
<script>
|
|
SUGAR.util.doWhen("typeof addImage != 'undefined'", function(){
|
|
addImage('{$this->id}_img','{$this->id}_img_map','index.php?module=AOR_Charts&action=getImageMap&to_pdf=1&imageMapId={$index}');
|
|
});
|
|
</script>
|
|
EOF;
|
|
return $html;
|
|
}
|
|
|
|
private function getShortenedLabel($label, $maxLabelSize = 20)
|
|
{
|
|
if (strlen((string) $label) > $maxLabelSize) {
|
|
return mb_substr($label, 0, $maxLabelSize).'...';
|
|
}
|
|
return $label;
|
|
}
|
|
|
|
|
|
private function getRGraphGroupedBarChartData($reportData, $xName, $yName, AOR_Field $mainGroupField = null)
|
|
{
|
|
|
|
|
|
// get z-axis name
|
|
|
|
$zName = null;
|
|
foreach ($reportData[0] as $key => $value) {
|
|
$field = str_replace(' ', '_', is_null($mainGroupField) ? 'no data' : $mainGroupField->label);
|
|
if (preg_match('/^' . $field . '[0-9]+/', (string) $key)) {
|
|
$zName = $key;
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// get grouped values
|
|
|
|
$data = array();
|
|
$tooltips = array();
|
|
|
|
$usedKeys = array();
|
|
foreach ($reportData as $key => $row) {
|
|
$filter = $row[$xName];
|
|
foreach ($reportData as $key2 => $row2) {
|
|
if ($row2[$xName] == $filter && !in_array($key, $usedKeys)) {
|
|
$data [ $row[$xName] ] [] = (float) $row[$yName];
|
|
$tooltips [ $row[$xName] ] [] = isset($row[$zName]) ? $row[$zName] : null;
|
|
$usedKeys[] = $key;
|
|
}
|
|
}
|
|
}
|
|
|
|
$_data = array();
|
|
foreach ($data as $label => $values) {
|
|
$_data[$label] = [];
|
|
foreach ($values as $key => $value) {
|
|
$_data[$label][$tooltips[$label][$key]] = ($_data[$label][$tooltips[$label][$key]] ?? 0) + 1;
|
|
}
|
|
}
|
|
|
|
$data = $_data;
|
|
|
|
|
|
// make data format for charts
|
|
|
|
$_data = array();
|
|
$_labels = array();
|
|
$_tooltips = array();
|
|
foreach ($data as $label => $values) {
|
|
$_labels[] = $this->getShortenedLabel($label);
|
|
$_values = array();
|
|
foreach ($values as $tooltip => $value) {
|
|
$_tooltips[] = $tooltip . " ($value)";
|
|
$_values[] = $value;
|
|
}
|
|
$_data[] = $_values;
|
|
}
|
|
|
|
|
|
$chart = array(
|
|
'data' => $_data,
|
|
'labels' => $_labels,
|
|
'tooltips' => $_tooltips,
|
|
);
|
|
|
|
return $chart;
|
|
}
|
|
|
|
private function getRGraphBarChartData($reportData, $xName, $yName)
|
|
{
|
|
$chart = [];
|
|
$chart['labels']=array();
|
|
$chart['data']=array();
|
|
$chart['tooltips']=array();
|
|
foreach ($reportData as $row) {
|
|
$chart['labels'][] = $this->getShortenedLabel($row[$xName]);
|
|
$chart['tooltips'][] = $row[$xName].': '.$row[$yName];
|
|
$chart['data'][] = (float)$row[$yName];
|
|
}
|
|
return $chart;
|
|
}
|
|
|
|
|
|
private function getBarChartData($reportData, $xName, $yName)
|
|
{
|
|
$data = array();
|
|
$data['labels'] = array();
|
|
$datasetData = array();
|
|
foreach ($reportData as $row) {
|
|
$data['labels'][] = $row[$xName];
|
|
$datasetData[] = $row[$yName];
|
|
}
|
|
|
|
$data['datasets'] = array();
|
|
$data['datasets'][] = array(
|
|
'fillColor' => "rgba(151,187,205,0.2)",
|
|
'strokeColor' => "rgba(151,187,205,1)",
|
|
'pointColor' => "rgba(151,187,205,1)",
|
|
'pointStrokeColor' => "#fff",
|
|
'pointHighlightFill' => "#fff",
|
|
'pointHighlightStroke' => "rgba(151,187,205,1)4",
|
|
'data'=>$datasetData);
|
|
return $data;
|
|
}
|
|
|
|
private function getLineChartData($reportData, $xName, $yName)
|
|
{
|
|
return $this->getBarChartData($reportData, $xName, $yName);
|
|
}
|
|
|
|
private function getBarChartConfig()
|
|
{
|
|
return array();
|
|
}
|
|
private function getLineChartConfig()
|
|
{
|
|
return $this->getBarChartConfig();
|
|
}
|
|
|
|
private function getGroupedBarChartConfig()
|
|
{
|
|
return $this->getBarChartConfig();
|
|
}
|
|
|
|
private function getStackedBarChartConfig()
|
|
{
|
|
return $this->getBarChartConfig();
|
|
}
|
|
|
|
private function getRoseChartConfig()
|
|
{
|
|
return $this->getBarChartConfig();
|
|
}
|
|
|
|
private function getRadarChartData($reportData, $xName, $yName)
|
|
{
|
|
return $this->getBarChartData($reportData, $xName, $yName);
|
|
}
|
|
|
|
private function getRadarChartConfig()
|
|
{
|
|
return array();
|
|
}
|
|
|
|
private function getPieChartConfig()
|
|
{
|
|
$config = array();
|
|
$config['legendTemplate'] = "<ul class=\"<%=name.toLowerCase()%>-legend\"><% for (var i=0; i<segments.length; i++){%><li><span style=\"background-color:<%=segments[i].fillColor%>\"> </span> <%if(segments[i].label){%><%=segments[i].label%><%}%></li><%}%></ul>";
|
|
return $config;
|
|
}
|
|
|
|
private function getPieChartData($reportData, $xName, $yName)
|
|
{
|
|
$data = array();
|
|
|
|
foreach ($reportData as $row) {
|
|
if (!$row[$yName]) {
|
|
continue;
|
|
}
|
|
$colour = $this->getColour($row[$xName]);
|
|
$data[] = array(
|
|
'value' => (int)$row[$yName],
|
|
'label' => $row[$xName],
|
|
'color' => $colour['main'],
|
|
'highlight' => $colour['highlight'],
|
|
);
|
|
}
|
|
return $data;
|
|
}
|
|
}
|