Merge remote-tracking branch 'upstream/4.3' into 4.3-master-2013-09-25-01-46-57
[civicrm-core.git] / CRM / Utils / OpenFlashChart.php
1 <?php
2 /*
3 +--------------------------------------------------------------------+
4 | CiviCRM version 4.4 |
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
36 require_once 'packages/OpenFlashChart/php-ofc-library/open-flash-chart.php';
37
38 /**
39 * Build various graphs using Open Flash Chart library.
40 */
41 class 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 }
67 if (!CRM_Utils_Array::value('multiValues', $params)) {
68 $params['multiValues'] = array($params['values']);
69 }
70
71 $values = CRM_Utils_Array::value('multiValues', $params);
72 if (!is_array($values) || empty($values)) {
73 return $chart;
74 }
75
76 // get the required data.
77 $chartTitle = CRM_Utils_Array::value('legend', $params) ? $params['legend'] : ts('Bar Chart');
78
79 $xValues = $yValues = array();
80 $xValues = array_keys($values[0]);
81 $yValues = array_values($values[0]);
82
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
93 $bars = array();
94 $config = CRM_Core_Config::singleton();
95 $symbol = $config->defaultCurrencySymbol;
96 foreach ($values as $barCount => $barVal) {
97 $bars[$barCount] = new bar_glass();
98
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 }
109
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 }
123
124 // create x axis label obj.
125 $xLabels = new x_axis_labels();
126 $xLabels->set_labels($xValues);
127
128 // set angle for labels.
129 if ($xLabelAngle = CRM_Utils_Array::value('xLabelAngle', $params)) {
130 $xLabels->rotate($xLabelAngle);
131 }
132
133 // create x axis obj.
134 $xAxis = new x_axis();
135 $xAxis->set_labels($xLabels);
136
137 //create y axis and set range.
138 $yAxis = new y_axis();
139 $yAxis->set_range($yMin, $yMax, $ySteps);
140
141 // create chart title obj.
142 $title = new title($chartTitle);
143
144 // create chart.
145 $chart = new open_flash_chart();
146
147 // add x axis w/ labels to chart.
148 $chart->set_x_axis($xAxis);
149
150 // add y axis values to chart.
151 $chart->add_y_axis($yAxis);
152
153 // set title to chart.
154 $chart->set_title($title);
155
156 // add bar element to chart.
157 foreach ($bars as $bar) {
158 $chart->add_element($bar);
159 }
160
161 // add x axis legend.
162 if ($xName = CRM_Utils_Array::value('xname', $params)) {
163 $xLegend = new x_legend($xName);
164 $xLegend->set_style("{font-size: 13px; color:#000000; font-family: Verdana; text-align: center;}");
165 $chart->set_x_legend($xLegend);
166 }
167
168 // add y axis legend.
169 if ($yName = CRM_Utils_Array::value('yname', $params)) {
170 $yLegend = new y_legend($yName);
171 $yLegend->set_style("{font-size: 13px; color:#000000; font-family: Verdana; text-align: center;}");
172 $chart->set_y_legend($yLegend);
173 }
174
175 return $chart;
176 }
177
178 /**
179 * Build The Pie Gharph.
180 *
181 * @param array $params assoc array of name/value pairs
182 *
183 * @return object $chart object of open flash chart.
184 * @static
185 */
186 static function &pieChart(&$params) {
187 $chart = NULL;
188 if (empty($params)) {
189 return $chart;
190 }
191 $allValues = CRM_Utils_Array::value('values', $params);
192 if (!is_array($allValues) || empty($allValues)) {
193 return $chart;
194 }
195
196 // get the required data.
197 $values = array();
198 foreach ($allValues as $label => $value) {
199 $values[] = new pie_value((double)$value, $label);
200 }
201 $graphTitle = CRM_Utils_Array::value('legend', $params) ? $params['legend'] : ts('Pie Chart');
202
203 //get the currency.
204 $config = CRM_Core_Config::singleton();
205 $symbol = $config->defaultCurrencySymbol;
206
207 $pie = new pie();
208 $pie->radius(100);
209
210 // call user define function to handle on click event.
211 if ($onClickFunName = CRM_Utils_Array::value('on_click_fun_name', $params)) {
212 $pie->on_click($onClickFunName);
213 }
214
215 $pie->set_start_angle(35);
216 $pie->add_animation(new pie_fade());
217 $pie->add_animation(new pie_bounce(2));
218
219 // set the tooltip.
220 $tooltip = CRM_Utils_Array::value('tip', $params, "Amount is $symbol #val# of $symbol #total# <br>#percent#");
221 $pie->set_tooltip($tooltip);
222
223 // set colours.
224 $pie->set_colours(self::$_colours);
225
226 $pie->set_values($values);
227
228 //create chart.
229 $chart = new open_flash_chart();
230
231 // create chart title obj.
232 $title = new title($graphTitle);
233 $chart->set_title($title);
234
235 $chart->add_element($pie);
236 $chart->x_axis = NULL;
237
238 return $chart;
239 }
240
241 /**
242 * Build The 3-D Bar Gharph.
243 *
244 * @param array $params assoc array of name/value pairs
245 *
246 * @return object $chart object of open flash chart.
247 * @static
248 */
249 static function &bar_3dChart(&$params) {
250 $chart = NULL;
251 if (empty($params)) {
252 return $chart;
253 }
254
255 // $params['values'] should contains the values for each
256 // criteria defined in $params['criteria']
257 $values = CRM_Utils_Array::value('values', $params);
258 $criterias = CRM_Utils_Array::value('criteria', $params);
259 if (!is_array($values) || empty($values) || !is_array($criterias) || empty($criterias)) {
260 return $chart;
261 }
262
263 // get the required data.
264 $xReferences = $xValueLabels = $xValues = $yValues = array();
265
266 foreach ($values as $xVal => $yVal) {
267 if (!is_array($yVal) || empty($yVal)) {
268 continue;
269 }
270
271 $xValueLabels[] = (string)$xVal;
272 foreach ($criterias as $criteria) {
273 $xReferences[$criteria][$xVal] = (double)CRM_Utils_Array::value($criteria, $yVal, 0);
274 $yValues[] = (double)CRM_Utils_Array::value($criteria, $yVal, 0);
275 }
276 }
277
278 if (empty($xReferences)) {
279
280 return $chart;
281
282 }
283
284 // get the currency.
285 $config = CRM_Core_Config::singleton();
286 $symbol = $config->defaultCurrencySymbol;
287
288 // set the tooltip.
289 $tooltip = CRM_Utils_Array::value('tip', $params, "$symbol #val#");
290
291 $count = 0;
292 foreach ($xReferences as $criteria => $values) {
293 $toolTipVal = $tooltip;
294 // for seperate tooltip for each criteria
295 if (is_array($tooltip)) {
296 $toolTipVal = CRM_Utils_Array::value($criteria, $tooltip, "$symbol #val#");
297 }
298
299 // create bar_3d object
300 $xValues[$count] = new bar_3d();
301 // set colour pattel
302 $xValues[$count]->set_colour(self::$_colours[$count]);
303 // define colur pattel with bar criterias
304 $xValues[$count]->key((string)$criteria, 12);
305 // define bar chart values
306 $xValues[$count]->set_values(array_values($values));
307
308 // set tooltip
309 $xValues[$count]->set_tooltip($toolTipVal);
310 $count++;
311 }
312
313 $chartTitle = CRM_Utils_Array::value('legend', $params) ? $params['legend'] : ts('Bar Chart');
314
315 //set y axis parameters.
316 $yMin = 0;
317
318 // calculate max scale for graph.
319 $yMax = ceil(max($yValues));
320 if ($mod = $yMax % (str_pad(5, strlen($yMax) - 1, 0))) {
321 $yMax += str_pad(5, strlen($yMax) - 1, 0) - $mod;
322 }
323
324 // if max value of y-axis <= 0, then set default values
325 if ($yMax <= 0) {
326 $ySteps = 1;
327 $yMax = 5;
328 }
329 else {
330 $ySteps = $yMax / 5;
331 }
332
333 // create x axis label obj.
334 $xLabels = new x_axis_labels();
335 $xLabels->set_labels($xValueLabels);
336
337 // set angle for labels.
338 if ($xLabelAngle = CRM_Utils_Array::value('xLabelAngle', $params)) {
339 $xLabels->rotate($xLabelAngle);
340 }
341
342 // create x axis obj.
343 $xAxis = new x_axis();
344 $xAxis->set_labels($xLabels);
345
346 //create y axis and set range.
347 $yAxis = new y_axis();
348 $yAxis->set_range($yMin, $yMax, $ySteps);
349
350 // create chart title obj.
351 $title = new title($chartTitle);
352
353 // create chart.
354 $chart = new open_flash_chart();
355
356 // add x axis w/ labels to chart.
357 $chart->set_x_axis($xAxis);
358
359 // add y axis values to chart.
360 $chart->add_y_axis($yAxis);
361
362 // set title to chart.
363 $chart->set_title($title);
364
365 foreach ($xValues as $bar) {
366 // add bar element to chart.
367 $chart->add_element($bar);
368 }
369
370 // add x axis legend.
371 if ($xName = CRM_Utils_Array::value('xname', $params)) {
372 $xLegend = new x_legend($xName);
373 $xLegend->set_style("{font-size: 13px; color:#000000; font-family: Verdana; text-align: center;}");
374 $chart->set_x_legend($xLegend);
375 }
376
377 // add y axis legend.
378 if ($yName = CRM_Utils_Array::value('yname', $params)) {
379 $yLegend = new y_legend($yName);
380 $yLegend->set_style("{font-size: 13px; color:#000000; font-family: Verdana; text-align: center;}");
381 $chart->set_y_legend($yLegend);
382 }
383
384 return $chart;
385 }
386
387 static function chart($rows, $chart, $interval) {
388 $chartData = $dateKeys = array();
389
390 switch ($interval) {
391 case 'Month':
392 foreach ($rows['receive_date'] as $key => $val) {
393 list($year, $month) = explode('-', $val);
394 $dateKeys[] = substr($rows['Month'][$key], 0, 3) . ' ' . $year;
395 }
396 $legend = ts('Monthly');
397 break;
398
399 case 'Quarter':
400 foreach ($rows['receive_date'] as $key => $val) {
401 list($year, $month) = explode('-', $val);
402 $dateKeys[] = 'Quarter ' . $rows['Quarter'][$key] . ' of ' . $year;
403 }
404 $legend = ts('Quarterly');
405 break;
406
407 case 'Week':
408 foreach ($rows['receive_date'] as $key => $val) {
409 list($year, $month) = explode('-', $val);
410 $dateKeys[] = 'Week ' . $rows['Week'][$key] . ' of ' . $year;
411 }
412 $legend = ts('Weekly');
413 break;
414
415 case 'Year':
416 foreach ($rows['receive_date'] as $key => $val) {
417 list($year, $month) = explode('-', $val);
418 $dateKeys[] = $year;
419 }
420 $legend = ts('Yearly');
421 break;
422 }
423
424 if (!empty($dateKeys)) {
425 $graph = array();
426 if (!array_key_exists('multiValue', $rows)) {
427 $rows['multiValue'] = array($rows['value']);
428 }
429 foreach ($rows['multiValue'] as $key => $val) {
430 $graph[$key] = array_combine($dateKeys, $rows['multiValue'][$key]);
431 }
432 $chartData =
433 array(
434 'legend' => "$legend " . CRM_Utils_Array::value('legend', $rows, ts('Contribution')) . ' ' . ts('Summary'),
435 'values' => $graph[0],
436 'multiValues' => $graph,
437 'barKeys' => CRM_Utils_Array::value('barKeys', $rows, array()),
438 );
439 }
440
441 // rotate the x labels.
442 $chartData['xLabelAngle'] = CRM_Utils_Array::value('xLabelAngle', $rows, 0);
443 if (CRM_Utils_Array::value('tip', $rows)) {
444 $chartData['tip'] = $rows['tip'];
445 }
446
447 //legend
448 $chartData['xname'] = CRM_Utils_Array::value('xname', $rows);
449 $chartData['yname'] = CRM_Utils_Array::value('yname', $rows);
450
451 // carry some chart params if pass.
452 foreach (array(
453 'xSize', 'ySize', 'divName') as $f) {
454 if (CRM_Utils_Array::value($f, $rows)) {
455 $chartData[$f] = $rows[$f];
456 }
457 }
458
459 return self::buildChart($chartData, $chart);
460 }
461
462 static function reportChart($rows, $chart, $interval, &$chartInfo) {
463 foreach ($interval as $key => $val) {
464 $graph[$val] = $rows['value'][$key];
465 }
466
467 $chartData = array(
468 'values' => $graph,
469 'legend' => $chartInfo['legend'],
470 'xname' => $chartInfo['xname'],
471 'yname' => $chartInfo['yname'],
472 );
473
474 // rotate the x labels.
475 $chartData['xLabelAngle'] = CRM_Utils_Array::value('xLabelAngle', $chartInfo, 20);
476 if (CRM_Utils_Array::value('tip', $chartInfo)) {
477 $chartData['tip'] = $chartInfo['tip'];
478 }
479
480 // carry some chart params if pass.
481 foreach (array(
482 'xSize', 'ySize', 'divName') as $f) {
483 if (CRM_Utils_Array::value($f, $rows)) {
484 $chartData[$f] = $rows[$f];
485 }
486 }
487
488 return self::buildChart($chartData, $chart);
489 }
490
491 static function buildChart(&$params, $chart) {
492 $openFlashChart = array();
493 if ($chart && is_array($params) && !empty($params)) {
494 // build the chart objects.
495 $chartObj = CRM_Utils_OpenFlashChart::$chart($params);
496
497 $openFlashChart = array();
498 if ($chartObj) {
499 // calculate chart size.
500 $xSize = CRM_Utils_Array::value('xSize', $params, 400);
501 $ySize = CRM_Utils_Array::value('ySize', $params, 300);
502 if ($chart == 'barChart') {
503 $ySize = CRM_Utils_Array::value('ySize', $params, 250);
504 $xSize = 60 * count($params['values']);
505 //hack to show tooltip.
506 if ($xSize < 200) {
507 $xSize = (count($params['values']) > 1) ? 100 * count($params['values']) : 170;
508 }
509 elseif ($xSize > 600 && count($params['values']) > 1) {
510 $xSize = (count($params['values']) + 400 / count($params['values'])) * count($params['values']);
511 }
512 }
513
514 // generate unique id for this chart instance
515 $uniqueId = md5(uniqid(rand(), TRUE));
516
517 $openFlashChart["chart_{$uniqueId}"]['size'] = array('xSize' => $xSize, 'ySize' => $ySize);
518 $openFlashChart["chart_{$uniqueId}"]['object'] = $chartObj;
519
520 // assign chart data to template
521 $template = CRM_Core_Smarty::singleton();
522 $template->assign('uniqueId', $uniqueId);
523 $template->assign("openFlashChartData", json_encode($openFlashChart));
524 }
525 }
526
527 return $openFlashChart;
528 }
529 }
530