3 +--------------------------------------------------------------------+
4 | Copyright CiviCRM LLC. All rights reserved. |
6 | This work is published under the GNU AGPLv3 license with some |
7 | permitted exceptions and without any warranty. For full license |
8 | and copyright information, see https://civicrm.org/licensing |
9 +--------------------------------------------------------------------+
15 * @copyright CiviCRM LLC https://civicrm.org/licensing
19 * Build various graphs using the dc chart library.
21 class CRM_Utils_Chart
{
24 * Build The Bar Graph.
26 * @param array $params
27 * Assoc array of name/value pairs.
30 * $chart object data used for client-side chart rendering (currently with dc chart library).
32 public static function barChart($params) {
33 $output = static::commonParamsManipulation($params);
37 $output['type'] = 'barchart';
39 $output +
= ['title' => ts('Bar Chart')];
41 // ? Not sure what reports use this, but it's not implemented.
42 // call user define function to handle on click event.
43 // if ($onClickFunName = CRM_Utils_Array::value('on_click_fun_name', $params)) {
44 // $bars[$barCount]->set_on_click($onClickFunName);
47 //// get the currency to set in tooltip.
48 //$tooltip = CRM_Utils_Array::value('tip', $params, "$symbol #val#");
56 * @param array $params
57 * Assoc array of name/value pairs.
61 public static function pieChart($params) {
62 $output = static::commonParamsManipulation($params);
66 $output['type'] = 'piechart';
67 $output +
= ['title' => ts('Pie Chart')];
69 // ? Not sure what reports use this, but it's not implemented.
70 // call user define function to handle on click event.
71 // if ($onClickFunName = CRM_Utils_Array::value('on_click_fun_name', $params)) {
72 // $bars[$barCount]->set_on_click($onClickFunName);
75 //// get the currency to set in tooltip.
76 //$tooltip = CRM_Utils_Array::value('tip', $params, "$symbol #val#");
82 * Common data manipulation for charts.
84 * @param array $params
85 * Assoc array of name/value pairs.
89 public static function commonParamsManipulation($params) {
94 if (empty($params['multiValues'])) {
95 $params['multiValues'] = [$params['values']];
98 $output['values'] = [];
99 foreach ($params['multiValues'] as $i => $dataSet) {
100 $output['values'][$i] = [];
101 foreach ($dataSet as $k => $v) {
102 $output['values'][$i][] = ['label' => $k, 'value' => (double) $v];
105 if (!$output['values']) {
109 // Ensure there's a legend (title)
110 if (!empty($params['legend'])) {
111 $output['title'] = $params['legend'];
114 $output['symbol'] = CRM_Core_BAO_Country
::defaultCurrencySymbol();
116 // ? Not sure what reports use this, but it's not implemented.
117 // call user define function to handle on click event.
118 // if ($onClickFunName = CRM_Utils_Array::value('on_click_fun_name', $params)) {
119 // $bars[$barCount]->set_on_click($onClickFunName);
122 //// get the currency to set in tooltip.
123 //$tooltip = CRM_Utils_Array::value('tip', $params, "$symbol #val#");
130 * @param string $chart
131 * @param string $interval
135 public static function chart($rows, $chart, $interval) {
136 $lcInterval = strtolower($interval);
137 $label = ucfirst($lcInterval);
138 $chartData = $dateKeys = [];
140 'year' => ts('Yearly'),
141 'fiscalyear' => ts('Yearly (Fiscal)'),
142 'month' => ts('Monthly'),
143 'quarter' => ts('Quarterly'),
144 'week' => ts('Weekly'),
145 'yearweek' => ts('Weekly'),
148 switch ($lcInterval) {
153 foreach ($rows['receive_date'] as $key => $val) {
154 list($year, $month) = explode('-', $val);
155 $dateKeys[] = substr($rows[$interval][$key], 0, 3) . ' of ' . $year;
157 $legend = $intervalLabels[$lcInterval];
161 foreach ($rows['receive_date'] as $key => $val) {
162 list($year, $month) = explode('-', $val);
165 $legend = ts("%1", [1 => $label]);
166 if (!empty($intervalLabels[$lcInterval])) {
167 $legend = $intervalLabels[$lcInterval];
172 if (!empty($dateKeys)) {
174 if (!array_key_exists('multiValue', $rows)) {
175 $rows['multiValue'] = [$rows['value']];
177 foreach ($rows['multiValue'] as $key => $val) {
178 $graph[$key] = array_combine($dateKeys, $rows['multiValue'][$key]);
181 'legend' => "$legend " . CRM_Utils_Array
::value('legend', $rows, ts('Contribution')) . ' ' . ts('Summary'),
182 'values' => $graph[0],
183 'multiValues' => $graph,
184 'barKeys' => $rows['barKeys'] ??
[],
188 // rotate the x labels.
189 $chartData['xLabelAngle'] = $rows['xLabelAngle'] ??
0;
190 if (!empty($rows['tip'])) {
191 $chartData['tip'] = $rows['tip'];
195 $chartData['xname'] = $rows['xname'] ??
NULL;
196 $chartData['yname'] = $rows['yname'] ??
NULL;
198 // carry some chart params if pass.
204 if (!empty($rows[$f])) {
205 $chartData[$f] = $rows[$f];
209 return self
::buildChart($chartData, $chart);
214 * @param string $chart
215 * @param array $interval
216 * @param array $chartInfo
220 public static function reportChart($rows, $chart, $interval, &$chartInfo) {
221 foreach ($interval as $key => $val) {
222 $graph[$val] = $rows['value'][$key];
227 'legend' => $chartInfo['legend'],
228 'xname' => $chartInfo['xname'],
229 'yname' => $chartInfo['yname'],
232 // rotate the x labels.
233 $chartData['xLabelAngle'] = CRM_Utils_Array
::value('xLabelAngle', $chartInfo, 20);
234 if (!empty($chartInfo['tip'])) {
235 $chartData['tip'] = $chartInfo['tip'];
238 // carry some chart params if pass.
244 if (!empty($rows[$f])) {
245 $chartData[$f] = $rows[$f];
249 return self
::buildChart($chartData, $chart);
253 * @param array $params
254 * @param string $chart
258 public static function buildChart(&$params, $chart) {
260 if ($chart && is_array($params) && !empty($params)) {
261 // build the chart objects.
262 $chartObj = CRM_Utils_Chart
::$chart($params);
265 // calculate chart size.
266 $xSize = CRM_Utils_Array
::value('xSize', $params, 400);
267 $ySize = CRM_Utils_Array
::value('ySize', $params, 300);
268 if ($chart == 'barChart') {
269 $ySize = CRM_Utils_Array
::value('ySize', $params, 250);
270 $xSize = 60 * count($params['values']);
271 // hack to show tooltip.
273 $xSize = (count($params['values']) > 1) ?
100 * count($params['values']) : 170;
275 elseif ($xSize > 600 && count($params['values']) > 1) {
276 $xSize = (count($params['values']) +
400 / count($params['values'])) * count($params['values']);
280 // generate unique id for this chart instance
281 $uniqueId = md5(uniqid(rand(), TRUE));
283 $theChart["chart_{$uniqueId}"]['size'] = ['xSize' => $xSize, 'ySize' => $ySize];
284 $theChart["chart_{$uniqueId}"]['object'] = $chartObj;
286 // assign chart data to template
287 $template = CRM_Core_Smarty
::singleton();
288 $template->assign('uniqueId', $uniqueId);
289 $template->assign("chartData", json_encode($theChart ??
[]));