| 1 |
<?php
|
| 2 |
// $Id: views_calc_plugin_style_chart.inc,v 1.6 2009/04/20 18:36:57 karens Exp $
|
| 3 |
|
| 4 |
/**
|
| 5 |
* @file
|
| 6 |
* Contains the chart style plugin.
|
| 7 |
*/
|
| 8 |
|
| 9 |
/**
|
| 10 |
* Style plugin to render view as a chart.
|
| 11 |
*
|
| 12 |
* @ingroup views_style_plugins
|
| 13 |
*/
|
| 14 |
class views_calc_plugin_style_chart extends views_plugin_style {
|
| 15 |
// Set default options.
|
| 16 |
function options(&$options) {
|
| 17 |
$options['format'] = 'pie2D';
|
| 18 |
$options['height'] = 200;
|
| 19 |
$options['width'] = 400;
|
| 20 |
$options['color'] = 'ffffff';
|
| 21 |
$options['aggregation_field'] = '';
|
| 22 |
$options['calc_fields'] = array();
|
| 23 |
$options['calc'] = 'COUNT';
|
| 24 |
$options['precision'] = 2;
|
| 25 |
}
|
| 26 |
|
| 27 |
// Generate a form for setting options.
|
| 28 |
function options_form(&$form, &$form_state) {
|
| 29 |
parent::options_form($form, $form_state);
|
| 30 |
|
| 31 |
$form['format'] = array(
|
| 32 |
'#type' => 'select',
|
| 33 |
'#title' => t('Chart format'),
|
| 34 |
'#options' => array(
|
| 35 |
'line2D' => t('Line 2D'),
|
| 36 |
'hbar2D' => t('Horizontal Bar 2D'),
|
| 37 |
'vbar2D' => t('Vertical Bar 2D'),
|
| 38 |
'pie2D' => t('Pie 2D'),
|
| 39 |
'pie3D' => t('Pie 3D'),
|
| 40 |
'venn' => t('Venn'),
|
| 41 |
'scatter' => t('Scatter Plot')
|
| 42 |
),
|
| 43 |
'#default_value' => $this->options['format'],
|
| 44 |
);
|
| 45 |
$form['height'] = array(
|
| 46 |
'#type' => 'textfield',
|
| 47 |
'#title' => t('Chart height'),
|
| 48 |
'#default_value' => $this->options['height'],
|
| 49 |
'#required' => TRUE, // Google charts breaks if it is empty.
|
| 50 |
'#description' => t('An integer value, the number of pixels of height for this chart.'),
|
| 51 |
);
|
| 52 |
$form['width'] = array(
|
| 53 |
'#type' => 'textfield',
|
| 54 |
'#title' => t('Chart width'),
|
| 55 |
'#default_value' => $this->options['width'],
|
| 56 |
'#required' => TRUE, // Google charts breaks if it is empty.
|
| 57 |
'#description' => t('An integer value, the number of pixels of width for this chart.'),
|
| 58 |
);
|
| 59 |
$form['color'] = array(
|
| 60 |
'#type' => 'textfield',
|
| 61 |
'#title' => t('Background color'),
|
| 62 |
'#default_value' => $this->options['color'],
|
| 63 |
'#description' => t('In hexadecimal format (RRGGBB). Do not use the # symbol.'),
|
| 64 |
'#required' => TRUE, // Google charts breaks if it is empty.
|
| 65 |
);
|
| 66 |
$form['show_legend'] = array(
|
| 67 |
'#type' => 'checkbox',
|
| 68 |
'#title' => t('Show legend'),
|
| 69 |
'#default_value' => $this->options['show_legend'],
|
| 70 |
'#description' => t('Display legend next to the chart.'),
|
| 71 |
);
|
| 72 |
|
| 73 |
$form['aggregation_field'] = array(
|
| 74 |
'#type' => 'select',
|
| 75 |
'#title' => t('Aggregation field'),
|
| 76 |
'#options' => $this->aggregated_field_options(),
|
| 77 |
'#default_value' => $this->options['aggregation_field'],
|
| 78 |
'#description' => t('Select a field to aggreagate the results on.')
|
| 79 |
);
|
| 80 |
// TODO Charts module cannot currently handle more than one series,
|
| 81 |
// update Multiple to TRUE if that changes.
|
| 82 |
$form['calc_fields'] = array(
|
| 83 |
'#type' => 'select',
|
| 84 |
'#title' => t('Computation field'),
|
| 85 |
'#options' => $this->aggregated_field_options(),
|
| 86 |
'#default_value' => $this->calc_fields(),
|
| 87 |
'#multiple' => FALSE,
|
| 88 |
'#description' => t('Select field to perform computations on.')
|
| 89 |
);
|
| 90 |
$form['calc'] = array(
|
| 91 |
'#type' => 'select',
|
| 92 |
'#title' => t('Computation to perform'),
|
| 93 |
'#options' => $this->calc_options(),
|
| 94 |
'#default_value' => $this->options['calc'],
|
| 95 |
);
|
| 96 |
$form['precision'] = array(
|
| 97 |
'#type' => 'select',
|
| 98 |
'#title' => t('Precision'),
|
| 99 |
'#options' => range(0, 4),
|
| 100 |
'#default_value' => $this->options['precision'],
|
| 101 |
'#description' => t('Decimal points to use in computed values.'),
|
| 102 |
);
|
| 103 |
}
|
| 104 |
|
| 105 |
function calc_options() {
|
| 106 |
return array(
|
| 107 |
'' => t('None'),
|
| 108 |
'SUM' => t('Sum'),
|
| 109 |
'COUNT' => t('Count'),
|
| 110 |
'AVG' => t('Average'),
|
| 111 |
'MIN' => t('Minimum'),
|
| 112 |
'MAX' => t('Maximum'),
|
| 113 |
);
|
| 114 |
}
|
| 115 |
|
| 116 |
/**
|
| 117 |
* Create an options array of available fields from this view.
|
| 118 |
*/
|
| 119 |
function aggregated_field_options() {
|
| 120 |
$field_names = array();
|
| 121 |
$handlers = $this->display->handler->get_handlers('field');
|
| 122 |
foreach ($handlers as $field => $handler) {
|
| 123 |
if ($label = $handler->label()) {
|
| 124 |
$field_names[$field] = $label;
|
| 125 |
}
|
| 126 |
else {
|
| 127 |
$field_names[$field] = $handler->ui_name();
|
| 128 |
}
|
| 129 |
}
|
| 130 |
return $field_names;
|
| 131 |
}
|
| 132 |
|
| 133 |
/**
|
| 134 |
* Make sure calc_fields is always an array, even when not multiple.
|
| 135 |
*/
|
| 136 |
function calc_fields() {
|
| 137 |
$calc_fields = (array) $this->options['calc_fields'];
|
| 138 |
return array_values($calc_fields);
|
| 139 |
}
|
| 140 |
|
| 141 |
// Define and display a chart from the grouped values.
|
| 142 |
function render() {
|
| 143 |
// Scan all Views data and insert them into a series.
|
| 144 |
$data = array();
|
| 145 |
|
| 146 |
// Get values from rows.
|
| 147 |
foreach ($this->calc_fields() as $calc) {
|
| 148 |
foreach ($this->view->result as $row) {
|
| 149 |
foreach ($this->view->field as $key => $field) {
|
| 150 |
if ($key == $this->options['aggregation_field']) {
|
| 151 |
$legend_field = array_key_exists($calc, $this->view->field) ? $this->view->field[$calc] : NULL;
|
| 152 |
$legend = !empty($legend_field->options['label']) ? $legend_field->options['label'] : NULL;
|
| 153 |
if ($this->options['show_legend']) {
|
| 154 |
$data[$calc]['#legend'] = $legend;
|
| 155 |
}
|
| 156 |
$value['#label'] = strip_tags(theme_views_view_field($this->view, $this->view->field[$key], $row)); // .': '. $row->$calc;
|
| 157 |
$value['#value'] = $row->$calc;
|
| 158 |
$data[$calc][] = $value;
|
| 159 |
}
|
| 160 |
}
|
| 161 |
}
|
| 162 |
}
|
| 163 |
|
| 164 |
// Get chart settings from options form.
|
| 165 |
$legend_field = $this->view->field[$this->options['aggregation_field']];
|
| 166 |
$chart = array(
|
| 167 |
'#type' => $this->options['format'],
|
| 168 |
'#height' => $this->options['height'],
|
| 169 |
'#width' => $this->options['width'],
|
| 170 |
'#color' => $this->options['color'],
|
| 171 |
);
|
| 172 |
|
| 173 |
// Use the view title as the chart title.
|
| 174 |
$chart['#title'] = $this->view->get_title();
|
| 175 |
|
| 176 |
// Insert series into the chart array.
|
| 177 |
foreach ($data as $series) {
|
| 178 |
$chart[] = $series;
|
| 179 |
}
|
| 180 |
|
| 181 |
// Print the chart.
|
| 182 |
return charts_chart($chart);
|
| 183 |
}
|
| 184 |
|
| 185 |
function query() {
|
| 186 |
parent::query();
|
| 187 |
|
| 188 |
// Clear the fields out, we'll replace them with calculated values.
|
| 189 |
$this->view->query->clear_fields();
|
| 190 |
// Clear out any sorting, it can create unexpected results
|
| 191 |
// when Views adds aggregation values for the sorts.
|
| 192 |
$this->view->query->orderby = array();
|
| 193 |
|
| 194 |
// Add the grouping information to the query.
|
| 195 |
// Field setting of array('aggregate' => TRUE) tells Views not to force
|
| 196 |
// another aggregation in for this field.
|
| 197 |
|
| 198 |
foreach ($this->view->field as $field) {
|
| 199 |
$query_field = substr($field->field, 0, 3) == 'cid' ? $field->definition['calc'] : $field->table .'.'. $field->field;
|
| 200 |
$query_alias = $field->field_alias;
|
| 201 |
|
| 202 |
// Add the aggregation.
|
| 203 |
if ($field->field == $this->options['aggregation_field']) {
|
| 204 |
$this->view->query->add_orderby(NULL, NULL, 'asc', $query_alias);
|
| 205 |
$this->view->query->add_groupby($query_field);
|
| 206 |
if (substr($field->field, 0, 3) == 'cid') {
|
| 207 |
$this->view->query->add_field(NULL, $query_field, $field->field, array('aggregate' => TRUE));
|
| 208 |
}
|
| 209 |
else {
|
| 210 |
$this->view->query->add_field($field->table, $field->field, NULL, array('aggregate' => TRUE));
|
| 211 |
}
|
| 212 |
}
|
| 213 |
// Add computed values.
|
| 214 |
if (in_array($field->field, $this->calc_fields())) {
|
| 215 |
$sql = "ROUND(". $this->options['calc'] ."($query_field), ". $this->options['precision'] .")";
|
| 216 |
$this->view->query->add_field(NULL, $sql, $field->field, array('aggregate' => TRUE));
|
| 217 |
|
| 218 |
// TODO This part is not relationship-safe, needs additional work
|
| 219 |
// to join in the right table if the computation is done
|
| 220 |
// on a field that comes from a relationship.
|
| 221 |
|
| 222 |
// Make sure the table with the right alias name is available
|
| 223 |
// (it might have been dropped during Views optimizations.)
|
| 224 |
$this->view->query->add_table($field->table);
|
| 225 |
}
|
| 226 |
}
|
| 227 |
}
|
| 228 |
}
|