comparison views_calc_plugin_style_chart.inc @ 0:0651c02e6ed7

views_calc 1.3
author Franck Deroche <franck@defr.org>
date Wed, 05 Aug 2009 18:20:29 +0200
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:0651c02e6ed7
1 <?php
2 // $Id: views_calc_plugin_style_chart.inc,v 1.7 2009/04/20 19:38:42 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 }