Merge pull request #15955 from JMAConsulting/core-1420
[civicrm-core.git] / CRM / Utils / Chart.php
CommitLineData
dc61ee93
RLAR
1<?php
2/*
3 +--------------------------------------------------------------------+
bc77d7c0 4 | Copyright CiviCRM LLC. All rights reserved. |
dc61ee93 5 | |
bc77d7c0
TO
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 |
dc61ee93
RLAR
9 +--------------------------------------------------------------------+
10 */
11
12/**
13 *
14 * @package CRM
ca5cec67 15 * @copyright CiviCRM LLC https://civicrm.org/licensing
dc61ee93
RLAR
16 */
17
18/**
19 * Build various graphs using the dc chart library.
20 */
21class CRM_Utils_Chart {
22
23 /**
24 * Colours.
25 * @var array
26 */
27 private static $_colours = [
28 "#C3CC38",
29 "#C8B935",
30 "#CEA632",
31 "#D3932F",
32 "#D9802C",
33 "#FA6900",
34 "#DC9B57",
35 "#F78F01",
36 "#5AB56E",
37 "#6F8069",
38 "#C92200",
39 "#EB6C5C",
40 ];
41
42 /**
43 * Build The Bar Gharph.
44 *
45 * @param array $params
46 * Assoc array of name/value pairs.
47 *
48 * @return object
003ae4f2 49 * $chart object data used for client-side chart rendering (currently with dc chart library).
dc61ee93
RLAR
50 */
51 public static function barChart($params) {
52 $output = static::commonParamsManipulation($params);
53 if (empty($output)) {
54 return NULL;
55 }
56 $output['type'] = 'barchart';
57 // Default title
58 $output += ['title' => ts('Bar Chart')];
59
60 // ? Not sure what reports use this, but it's not implemented.
61 // call user define function to handle on click event.
62 // if ($onClickFunName = CRM_Utils_Array::value('on_click_fun_name', $params)) {
63 // $bars[$barCount]->set_on_click($onClickFunName);
64 // }
65
66 //// get the currency to set in tooltip.
67 //$tooltip = CRM_Utils_Array::value('tip', $params, "$symbol #val#");
68
69 return $output;
70 }
71
72 /**
73 * Build a pie chart.
74 *
75 * @param array $params
76 * Assoc array of name/value pairs.
77 *
78 * @return array
79 */
80 public static function pieChart($params) {
81 $output = static::commonParamsManipulation($params);
82 if (empty($output)) {
83 return NULL;
84 }
85 $output['type'] = 'piechart';
86 $output += ['title' => ts('Pie Chart')];
87
88 // ? Not sure what reports use this, but it's not implemented.
89 // call user define function to handle on click event.
90 // if ($onClickFunName = CRM_Utils_Array::value('on_click_fun_name', $params)) {
91 // $bars[$barCount]->set_on_click($onClickFunName);
92 // }
93
94 //// get the currency to set in tooltip.
95 //$tooltip = CRM_Utils_Array::value('tip', $params, "$symbol #val#");
96
97 return $output;
98 }
99
100 /**
101 * Common data manipulation for charts.
102 *
103 * @param array $params
104 * Assoc array of name/value pairs.
105 *
106 * @return array
107 */
108 public static function commonParamsManipulation($params) {
109 if (empty($params)) {
110 return NULL;
111 }
112 $output = [];
113 if (empty($params['multiValues'])) {
114 $params['multiValues'] = [$params['values']];
115 }
116
117 $output['values'] = [];
118 foreach ($params['multiValues'] as $i => $dataSet) {
119 $output['values'][$i] = [];
120 foreach ($dataSet as $k => $v) {
121 $output['values'][$i][] = ['label' => $k, 'value' => (double) $v];
122 }
123 }
124 if (!$output['values']) {
125 return NULL;
126 }
127
128 // Ensure there's a legend (title)
129 if (!empty($params['legend'])) {
130 $output['title'] = $params['legend'];
131 }
132
133 $output['symbol'] = CRM_Core_BAO_Country::defaultCurrencySymbol();
134
135 // ? Not sure what reports use this, but it's not implemented.
136 // call user define function to handle on click event.
137 // if ($onClickFunName = CRM_Utils_Array::value('on_click_fun_name', $params)) {
138 // $bars[$barCount]->set_on_click($onClickFunName);
139 // }
140
141 //// get the currency to set in tooltip.
142 //$tooltip = CRM_Utils_Array::value('tip', $params, "$symbol #val#");
143
144 return $output;
145 }
146
147 /**
148 * @param $rows
149 * @param $chart
150 * @param $interval
151 *
152 * @return array
153 */
154 public static function chart($rows, $chart, $interval) {
155 $lcInterval = strtolower($interval);
156 $label = ucfirst($lcInterval);
157 $chartData = $dateKeys = [];
158 $intervalLabels = [
159 'year' => ts('Yearly'),
160 'fiscalyear' => ts('Yearly (Fiscal)'),
161 'month' => ts('Monthly'),
162 'quarter' => ts('Quarterly'),
163 'week' => ts('Weekly'),
164 'yearweek' => ts('Weekly'),
165 ];
166
167 switch ($lcInterval) {
168 case 'month':
169 case 'quarter':
170 case 'week':
171 case 'yearweek':
172 foreach ($rows['receive_date'] as $key => $val) {
173 list($year, $month) = explode('-', $val);
174 $dateKeys[] = substr($rows[$interval][$key], 0, 3) . ' of ' . $year;
175 }
176 $legend = $intervalLabels[$lcInterval];
177 break;
178
179 default:
180 foreach ($rows['receive_date'] as $key => $val) {
181 list($year, $month) = explode('-', $val);
182 $dateKeys[] = $year;
183 }
184 $legend = ts("%1", [1 => $label]);
185 if (!empty($intervalLabels[$lcInterval])) {
186 $legend = $intervalLabels[$lcInterval];
187 }
188 break;
189 }
190
191 if (!empty($dateKeys)) {
192 $graph = [];
193 if (!array_key_exists('multiValue', $rows)) {
194 $rows['multiValue'] = [$rows['value']];
195 }
196 foreach ($rows['multiValue'] as $key => $val) {
197 $graph[$key] = array_combine($dateKeys, $rows['multiValue'][$key]);
198 }
199 $chartData = [
200 'legend' => "$legend " . CRM_Utils_Array::value('legend', $rows, ts('Contribution')) . ' ' . ts('Summary'),
201 'values' => $graph[0],
202 'multiValues' => $graph,
203 'barKeys' => CRM_Utils_Array::value('barKeys', $rows, []),
204 ];
205 }
206
207 // rotate the x labels.
208 $chartData['xLabelAngle'] = CRM_Utils_Array::value('xLabelAngle', $rows, 0);
209 if (!empty($rows['tip'])) {
210 $chartData['tip'] = $rows['tip'];
211 }
212
213 // legend
214 $chartData['xname'] = CRM_Utils_Array::value('xname', $rows);
215 $chartData['yname'] = CRM_Utils_Array::value('yname', $rows);
216
217 // carry some chart params if pass.
218 foreach ([
219 'xSize',
220 'ySize',
221 'divName',
222 ] as $f) {
223 if (!empty($rows[$f])) {
224 $chartData[$f] = $rows[$f];
225 }
226 }
227
228 return self::buildChart($chartData, $chart);
229 }
230
231 /**
232 * @param $rows
233 * @param $chart
234 * @param $interval
235 * @param $chartInfo
236 *
237 * @return array
238 */
239 public static function reportChart($rows, $chart, $interval, &$chartInfo) {
240 foreach ($interval as $key => $val) {
241 $graph[$val] = $rows['value'][$key];
242 }
243
244 $chartData = [
245 'values' => $graph,
246 'legend' => $chartInfo['legend'],
247 'xname' => $chartInfo['xname'],
248 'yname' => $chartInfo['yname'],
249 ];
250
251 // rotate the x labels.
252 $chartData['xLabelAngle'] = CRM_Utils_Array::value('xLabelAngle', $chartInfo, 20);
253 if (!empty($chartInfo['tip'])) {
254 $chartData['tip'] = $chartInfo['tip'];
255 }
256
257 // carry some chart params if pass.
258 foreach ([
259 'xSize',
260 'ySize',
261 'divName',
262 ] as $f) {
263 if (!empty($rows[$f])) {
264 $chartData[$f] = $rows[$f];
265 }
266 }
267
268 return self::buildChart($chartData, $chart);
269 }
270
271 /**
272 * @param array $params
273 * @param $chart
274 *
275 * @return array
276 */
277 public static function buildChart(&$params, $chart) {
278 $theChart = [];
279 if ($chart && is_array($params) && !empty($params)) {
280 // build the chart objects.
281 $chartObj = CRM_Utils_Chart::$chart($params);
282
283 if ($chartObj) {
284 // calculate chart size.
285 $xSize = CRM_Utils_Array::value('xSize', $params, 400);
286 $ySize = CRM_Utils_Array::value('ySize', $params, 300);
287 if ($chart == 'barChart') {
288 $ySize = CRM_Utils_Array::value('ySize', $params, 250);
289 $xSize = 60 * count($params['values']);
290 // hack to show tooltip.
291 if ($xSize < 200) {
292 $xSize = (count($params['values']) > 1) ? 100 * count($params['values']) : 170;
293 }
294 elseif ($xSize > 600 && count($params['values']) > 1) {
295 $xSize = (count($params['values']) + 400 / count($params['values'])) * count($params['values']);
296 }
297 }
298
299 // generate unique id for this chart instance
300 $uniqueId = md5(uniqid(rand(), TRUE));
301
302 $theChart["chart_{$uniqueId}"]['size'] = ['xSize' => $xSize, 'ySize' => $ySize];
303 $theChart["chart_{$uniqueId}"]['object'] = $chartObj;
304
305 // assign chart data to template
306 $template = CRM_Core_Smarty::singleton();
307 $template->assign('uniqueId', $uniqueId);
0cf05243 308 $template->assign("chartData", json_encode($theChart ?? []));
dc61ee93
RLAR
309 }
310 }
311
312 return $theChart;
313 }
314
315}