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