Merge pull request #3837 from eileenmcnaughton/CRM-15113
[civicrm-core.git] / CRM / Utils / OpenFlashChart.php
CommitLineData
6a488035
TO
1<?php
2/*
3 +--------------------------------------------------------------------+
232624b1 4 | CiviCRM version 4.4 |
6a488035
TO
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2013 |
7 +--------------------------------------------------------------------+
8 | This file is a part of CiviCRM. |
9 | |
10 | CiviCRM is free software; you can copy, modify, and distribute it |
11 | under the terms of the GNU Affero General Public License |
12 | Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
13 | |
14 | CiviCRM is distributed in the hope that it will be useful, but |
15 | WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
17 | See the GNU Affero General Public License for more details. |
18 | |
19 | You should have received a copy of the GNU Affero General Public |
20 | License and the CiviCRM Licensing Exception along |
21 | with this program; if not, contact CiviCRM LLC |
22 | at info[AT]civicrm[DOT]org. If you have questions about the |
23 | GNU Affero General Public License or the licensing of CiviCRM, |
24 | see the CiviCRM license FAQ at http://civicrm.org/licensing |
25 +--------------------------------------------------------------------+
26*/
27
28/**
29 *
30 * @package CRM
31 * @copyright CiviCRM LLC (c) 2004-2013
32 * $Id$
33 *
34 */
35
36require_once 'packages/OpenFlashChart/php-ofc-library/open-flash-chart.php';
37
38/**
39 * Build various graphs using Open Flash Chart library.
40 */
41class CRM_Utils_OpenFlashChart {
42
43 /**
44 * colours.
45 * @var array
46 * @static
47 */
48 private static $_colours = array(
49 "#C3CC38", "#C8B935", "#CEA632", "#D3932F",
50 "#D9802C", "#FA6900", "#DC9B57", "#F78F01",
51 "#5AB56E", "#6F8069", "#C92200", "#EB6C5C",
52 );
53
54 /**
55 * Build The Bar Gharph.
56 *
57 * @param array $params assoc array of name/value pairs
58 *
59 * @return object $chart object of open flash chart.
60 * @static
61 */
62 static function &barChart(&$params) {
63 $chart = NULL;
64 if (empty($params)) {
65 return $chart;
66 }
0c98098b
DS
67 if (!CRM_Utils_Array::value('multiValues', $params)) {
68 $params['multiValues'] = array($params['values']);
69 }
6a488035 70
0c98098b 71 $values = CRM_Utils_Array::value('multiValues', $params);
6a488035
TO
72 if (!is_array($values) || empty($values)) {
73 return $chart;
74 }
75
76 // get the required data.
6a488035
TO
77 $chartTitle = CRM_Utils_Array::value('legend', $params) ? $params['legend'] : ts('Bar Chart');
78
0c98098b
DS
79 $xValues = $yValues = array();
80 $xValues = array_keys($values[0]);
81 $yValues = array_values($values[0]);
82
6a488035
TO
83 //set y axis parameters.
84 $yMin = 0;
85
86 // calculate max scale for graph.
87 $yMax = ceil(max($yValues));
88 if ($mod = $yMax % (str_pad(5, strlen($yMax) - 1, 0))) {
89 $yMax += str_pad(5, strlen($yMax) - 1, 0) - $mod;
90 }
91 $ySteps = $yMax / 5;
92
0c98098b 93 $bars = array();
6a488035
TO
94 $config = CRM_Core_Config::singleton();
95 $symbol = $config->defaultCurrencySymbol;
0c98098b
DS
96 foreach ($values as $barCount => $barVal) {
97 $bars[$barCount] = new bar_glass();
6a488035 98
0c98098b
DS
99 $yValues = array_values($barVal);
100 foreach ($yValues as &$yVal) {
101 // type casting is required for chart to render values correctly
102 $yVal = (double) $yVal;
103 }
104 $bars[$barCount]->set_values($yValues);
105 if ($barCount > 0) {
106 // FIXME: for bars > 2, we'll need to come out with other colors
107 $bars[$barCount]->colour( '#BF3B69');
108 }
d7797bc2 109
0c98098b
DS
110 if ($barKey = CRM_Utils_Array::value($barCount, CRM_Utils_Array::value('barKeys', $params))) {
111 $bars[$barCount]->key($barKey,12);
112 }
113
114 // call user define function to handle on click event.
115 if ($onClickFunName = CRM_Utils_Array::value('on_click_fun_name', $params)) {
116 $bars[$barCount]->set_on_click($onClickFunName);
117 }
118
119 // get the currency to set in tooltip.
120 $tooltip = CRM_Utils_Array::value('tip', $params, "$symbol #val#");
121 $bars[$barCount]->set_tooltip($tooltip);
122 }
6a488035
TO
123
124 // create x axis label obj.
125 $xLabels = new x_axis_labels();
d7797bc2 126 // set_labels function requires xValues array of string or x_axis_label
5a0052f4 127 // so type casting array values to string values
d7797bc2
PJ
128 array_walk($xValues, function(&$value, $index) {
129 $value = (string)$value;
130 });
6a488035
TO
131 $xLabels->set_labels($xValues);
132
133 // set angle for labels.
134 if ($xLabelAngle = CRM_Utils_Array::value('xLabelAngle', $params)) {
135 $xLabels->rotate($xLabelAngle);
136 }
137
138 // create x axis obj.
139 $xAxis = new x_axis();
140 $xAxis->set_labels($xLabels);
141
142 //create y axis and set range.
143 $yAxis = new y_axis();
144 $yAxis->set_range($yMin, $yMax, $ySteps);
145
146 // create chart title obj.
147 $title = new title($chartTitle);
148
149 // create chart.
150 $chart = new open_flash_chart();
151
152 // add x axis w/ labels to chart.
153 $chart->set_x_axis($xAxis);
154
155 // add y axis values to chart.
156 $chart->add_y_axis($yAxis);
157
158 // set title to chart.
159 $chart->set_title($title);
160
161 // add bar element to chart.
0c98098b
DS
162 foreach ($bars as $bar) {
163 $chart->add_element($bar);
164 }
6a488035
TO
165
166 // add x axis legend.
167 if ($xName = CRM_Utils_Array::value('xname', $params)) {
168 $xLegend = new x_legend($xName);
169 $xLegend->set_style("{font-size: 13px; color:#000000; font-family: Verdana; text-align: center;}");
170 $chart->set_x_legend($xLegend);
171 }
172
173 // add y axis legend.
174 if ($yName = CRM_Utils_Array::value('yname', $params)) {
175 $yLegend = new y_legend($yName);
176 $yLegend->set_style("{font-size: 13px; color:#000000; font-family: Verdana; text-align: center;}");
177 $chart->set_y_legend($yLegend);
178 }
179
180 return $chart;
181 }
182
183 /**
184 * Build The Pie Gharph.
185 *
186 * @param array $params assoc array of name/value pairs
187 *
188 * @return object $chart object of open flash chart.
189 * @static
190 */
191 static function &pieChart(&$params) {
192 $chart = NULL;
193 if (empty($params)) {
194 return $chart;
195 }
196 $allValues = CRM_Utils_Array::value('values', $params);
197 if (!is_array($allValues) || empty($allValues)) {
198 return $chart;
199 }
200
201 // get the required data.
202 $values = array();
203 foreach ($allValues as $label => $value) {
204 $values[] = new pie_value((double)$value, $label);
205 }
206 $graphTitle = CRM_Utils_Array::value('legend', $params) ? $params['legend'] : ts('Pie Chart');
207
208 //get the currency.
209 $config = CRM_Core_Config::singleton();
210 $symbol = $config->defaultCurrencySymbol;
211
212 $pie = new pie();
213 $pie->radius(100);
214
215 // call user define function to handle on click event.
216 if ($onClickFunName = CRM_Utils_Array::value('on_click_fun_name', $params)) {
217 $pie->on_click($onClickFunName);
218 }
219
220 $pie->set_start_angle(35);
221 $pie->add_animation(new pie_fade());
222 $pie->add_animation(new pie_bounce(2));
223
224 // set the tooltip.
225 $tooltip = CRM_Utils_Array::value('tip', $params, "Amount is $symbol #val# of $symbol #total# <br>#percent#");
226 $pie->set_tooltip($tooltip);
227
228 // set colours.
229 $pie->set_colours(self::$_colours);
230
231 $pie->set_values($values);
232
233 //create chart.
234 $chart = new open_flash_chart();
235
236 // create chart title obj.
237 $title = new title($graphTitle);
238 $chart->set_title($title);
239
240 $chart->add_element($pie);
241 $chart->x_axis = NULL;
242
243 return $chart;
244 }
245
246 /**
247 * Build The 3-D Bar Gharph.
248 *
249 * @param array $params assoc array of name/value pairs
250 *
251 * @return object $chart object of open flash chart.
252 * @static
253 */
254 static function &bar_3dChart(&$params) {
255 $chart = NULL;
256 if (empty($params)) {
257 return $chart;
258 }
259
260 // $params['values'] should contains the values for each
261 // criteria defined in $params['criteria']
262 $values = CRM_Utils_Array::value('values', $params);
263 $criterias = CRM_Utils_Array::value('criteria', $params);
264 if (!is_array($values) || empty($values) || !is_array($criterias) || empty($criterias)) {
265 return $chart;
266 }
267
268 // get the required data.
269 $xReferences = $xValueLabels = $xValues = $yValues = array();
270
271 foreach ($values as $xVal => $yVal) {
272 if (!is_array($yVal) || empty($yVal)) {
273 continue;
274 }
275
276 $xValueLabels[] = (string)$xVal;
277 foreach ($criterias as $criteria) {
278 $xReferences[$criteria][$xVal] = (double)CRM_Utils_Array::value($criteria, $yVal, 0);
279 $yValues[] = (double)CRM_Utils_Array::value($criteria, $yVal, 0);
280 }
281 }
282
283 if (empty($xReferences)) {
284
285 return $chart;
286
287 }
288
289 // get the currency.
290 $config = CRM_Core_Config::singleton();
291 $symbol = $config->defaultCurrencySymbol;
292
293 // set the tooltip.
294 $tooltip = CRM_Utils_Array::value('tip', $params, "$symbol #val#");
295
296 $count = 0;
297 foreach ($xReferences as $criteria => $values) {
298 $toolTipVal = $tooltip;
299 // for seperate tooltip for each criteria
300 if (is_array($tooltip)) {
301 $toolTipVal = CRM_Utils_Array::value($criteria, $tooltip, "$symbol #val#");
302 }
303
304 // create bar_3d object
305 $xValues[$count] = new bar_3d();
306 // set colour pattel
307 $xValues[$count]->set_colour(self::$_colours[$count]);
308 // define colur pattel with bar criterias
309 $xValues[$count]->key((string)$criteria, 12);
310 // define bar chart values
311 $xValues[$count]->set_values(array_values($values));
312
313 // set tooltip
314 $xValues[$count]->set_tooltip($toolTipVal);
315 $count++;
316 }
317
318 $chartTitle = CRM_Utils_Array::value('legend', $params) ? $params['legend'] : ts('Bar Chart');
319
320 //set y axis parameters.
321 $yMin = 0;
322
323 // calculate max scale for graph.
324 $yMax = ceil(max($yValues));
325 if ($mod = $yMax % (str_pad(5, strlen($yMax) - 1, 0))) {
326 $yMax += str_pad(5, strlen($yMax) - 1, 0) - $mod;
327 }
328
329 // if max value of y-axis <= 0, then set default values
330 if ($yMax <= 0) {
331 $ySteps = 1;
332 $yMax = 5;
333 }
334 else {
335 $ySteps = $yMax / 5;
336 }
337
338 // create x axis label obj.
339 $xLabels = new x_axis_labels();
340 $xLabels->set_labels($xValueLabels);
341
342 // set angle for labels.
343 if ($xLabelAngle = CRM_Utils_Array::value('xLabelAngle', $params)) {
344 $xLabels->rotate($xLabelAngle);
345 }
346
347 // create x axis obj.
348 $xAxis = new x_axis();
349 $xAxis->set_labels($xLabels);
350
351 //create y axis and set range.
352 $yAxis = new y_axis();
353 $yAxis->set_range($yMin, $yMax, $ySteps);
354
355 // create chart title obj.
356 $title = new title($chartTitle);
357
358 // create chart.
359 $chart = new open_flash_chart();
360
361 // add x axis w/ labels to chart.
362 $chart->set_x_axis($xAxis);
363
364 // add y axis values to chart.
365 $chart->add_y_axis($yAxis);
366
367 // set title to chart.
368 $chart->set_title($title);
369
370 foreach ($xValues as $bar) {
371 // add bar element to chart.
372 $chart->add_element($bar);
373 }
374
375 // add x axis legend.
376 if ($xName = CRM_Utils_Array::value('xname', $params)) {
377 $xLegend = new x_legend($xName);
378 $xLegend->set_style("{font-size: 13px; color:#000000; font-family: Verdana; text-align: center;}");
379 $chart->set_x_legend($xLegend);
380 }
381
382 // add y axis legend.
383 if ($yName = CRM_Utils_Array::value('yname', $params)) {
384 $yLegend = new y_legend($yName);
385 $yLegend->set_style("{font-size: 13px; color:#000000; font-family: Verdana; text-align: center;}");
386 $chart->set_y_legend($yLegend);
387 }
388
389 return $chart;
390 }
391
392 static function chart($rows, $chart, $interval) {
0c98098b 393 $chartData = $dateKeys = array();
6a488035
TO
394
395 switch ($interval) {
396 case 'Month':
397 foreach ($rows['receive_date'] as $key => $val) {
398 list($year, $month) = explode('-', $val);
0c98098b 399 $dateKeys[] = substr($rows['Month'][$key], 0, 3) . ' ' . $year;
6a488035 400 }
0c98098b 401 $legend = ts('Monthly');
6a488035
TO
402 break;
403
404 case 'Quarter':
405 foreach ($rows['receive_date'] as $key => $val) {
406 list($year, $month) = explode('-', $val);
0c98098b 407 $dateKeys[] = 'Quarter ' . $rows['Quarter'][$key] . ' of ' . $year;
6a488035 408 }
0c98098b 409 $legend = ts('Quarterly');
6a488035
TO
410 break;
411
412 case 'Week':
413 foreach ($rows['receive_date'] as $key => $val) {
414 list($year, $month) = explode('-', $val);
0c98098b 415 $dateKeys[] = 'Week ' . $rows['Week'][$key] . ' of ' . $year;
6a488035 416 }
0c98098b 417 $legend = ts('Weekly');
6a488035
TO
418 break;
419
420 case 'Year':
421 foreach ($rows['receive_date'] as $key => $val) {
422 list($year, $month) = explode('-', $val);
0c98098b 423 $dateKeys[] = $year;
6a488035 424 }
0c98098b 425 $legend = ts('Yearly');
6a488035
TO
426 break;
427 }
428
0c98098b
DS
429 if (!empty($dateKeys)) {
430 $graph = array();
431 if (!array_key_exists('multiValue', $rows)) {
432 $rows['multiValue'] = array($rows['value']);
433 }
434 foreach ($rows['multiValue'] as $key => $val) {
435 $graph[$key] = array_combine($dateKeys, $rows['multiValue'][$key]);
436 }
d7797bc2 437 $chartData =
0c98098b
DS
438 array(
439 'legend' => "$legend " . CRM_Utils_Array::value('legend', $rows, ts('Contribution')) . ' ' . ts('Summary'),
440 'values' => $graph[0],
441 'multiValues' => $graph,
442 'barKeys' => CRM_Utils_Array::value('barKeys', $rows, array()),
443 );
444 }
445
6a488035 446 // rotate the x labels.
0c98098b 447 $chartData['xLabelAngle'] = CRM_Utils_Array::value('xLabelAngle', $rows, 0);
6a488035
TO
448 if (CRM_Utils_Array::value('tip', $rows)) {
449 $chartData['tip'] = $rows['tip'];
450 }
451
452 //legend
453 $chartData['xname'] = CRM_Utils_Array::value('xname', $rows);
454 $chartData['yname'] = CRM_Utils_Array::value('yname', $rows);
455
456 // carry some chart params if pass.
457 foreach (array(
458 'xSize', 'ySize', 'divName') as $f) {
459 if (CRM_Utils_Array::value($f, $rows)) {
460 $chartData[$f] = $rows[$f];
461 }
462 }
463
464 return self::buildChart($chartData, $chart);
465 }
466
467 static function reportChart($rows, $chart, $interval, &$chartInfo) {
468 foreach ($interval as $key => $val) {
469 $graph[$val] = $rows['value'][$key];
470 }
471
472 $chartData = array(
473 'values' => $graph,
474 'legend' => $chartInfo['legend'],
475 'xname' => $chartInfo['xname'],
476 'yname' => $chartInfo['yname'],
477 );
478
479 // rotate the x labels.
480 $chartData['xLabelAngle'] = CRM_Utils_Array::value('xLabelAngle', $chartInfo, 20);
481 if (CRM_Utils_Array::value('tip', $chartInfo)) {
482 $chartData['tip'] = $chartInfo['tip'];
483 }
484
485 // carry some chart params if pass.
486 foreach (array(
487 'xSize', 'ySize', 'divName') as $f) {
488 if (CRM_Utils_Array::value($f, $rows)) {
489 $chartData[$f] = $rows[$f];
490 }
491 }
492
493 return self::buildChart($chartData, $chart);
494 }
495
83abdecd 496 static function buildChart(&$params, $chart) {
6a488035
TO
497 $openFlashChart = array();
498 if ($chart && is_array($params) && !empty($params)) {
499 // build the chart objects.
0e6e8724 500 $chartObj = CRM_Utils_OpenFlashChart::$chart($params);
6a488035
TO
501
502 $openFlashChart = array();
503 if ($chartObj) {
504 // calculate chart size.
505 $xSize = CRM_Utils_Array::value('xSize', $params, 400);
506 $ySize = CRM_Utils_Array::value('ySize', $params, 300);
507 if ($chart == 'barChart') {
508 $ySize = CRM_Utils_Array::value('ySize', $params, 250);
509 $xSize = 60 * count($params['values']);
510 //hack to show tooltip.
511 if ($xSize < 200) {
512 $xSize = (count($params['values']) > 1) ? 100 * count($params['values']) : 170;
513 }
514 elseif ($xSize > 600 && count($params['values']) > 1) {
515 $xSize = (count($params['values']) + 400 / count($params['values'])) * count($params['values']);
516 }
517 }
518
519 // generate unique id for this chart instance
520 $uniqueId = md5(uniqid(rand(), TRUE));
521
522 $openFlashChart["chart_{$uniqueId}"]['size'] = array('xSize' => $xSize, 'ySize' => $ySize);
523 $openFlashChart["chart_{$uniqueId}"]['object'] = $chartObj;
524
525 // assign chart data to template
526 $template = CRM_Core_Smarty::singleton();
527 $template->assign('uniqueId', $uniqueId);
528 $template->assign("openFlashChartData", json_encode($openFlashChart));
529 }
530 }
531
532 return $openFlashChart;
533 }
534}
535