/[drupal]/contributions/modules/sparkline/sparkline.module
ViewVC logotype

Contents of /contributions/modules/sparkline/sparkline.module

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.8 - (show annotations) (download) (as text)
Mon Mar 16 18:31:11 2009 UTC (8 months, 1 week ago) by chris
Branch: MAIN
CVS Tags: HEAD
Changes since 1.7: +66 -4 lines
File MIME type: text/x-php
#394154.  Patch committed.  Thanks to Andrew Berry for the improvements.
1 <?php
2 // $Id: sparkline.module,v 1.7 2008/09/05 22:41:29 chris Exp $
3
4 /**
5 * @file
6 * A Drupal wrapper for the PHP Sparklines library. Allows other modules to
7 * generate sparklines, and provides a filter for users to embed them in posts.
8 */
9
10 function sparkline_menu() {
11 $items = array();
12 $items['admin/settings/sparkling'] = array(
13 'title' => 'Sparklines',
14 'description' => 'Configure the cache location and other settings for sparkline rendering.',
15 'page callback' => 'drupal_get_form',
16 'page arguments' => array('sparkline_admin_settings'),
17 'access callback' => 'user_access',
18 'access arguments' => array('administer sparklines'),
19 );
20 return $items;
21 }
22
23
24 /**
25 * Implementation of hook_perm(). Just used to control access to the admin screen.
26 */
27 function sparkline_perm() {
28 return array('administer sparklines');
29 }
30
31 /**
32 * Implementation of hook_theme(). Registers theme functions.
33 */
34 function sparkline_theme() {
35 return array(
36 'sparkline' => array('arguments' => array('element')),
37 'sparkline_element' => array('arguments' => array()),
38 );
39 }
40
41
42 /**
43 * Implementation of hook_cron(). This clears out any 'non-permanent' cached sparklines.
44 */
45 function sparkline_cron() {
46 _sparkline_flush_cache();
47 }
48
49 /**
50 * Implementation of hook_help().
51 */
52 function sparkline_help($path, $arg) {
53 switch ($path) {
54 case 'admin/modules#description':
55 // This description is shown in the listing at admin/modules.
56 return t('Lets users sparkline graphs using simple tags.');
57 }
58 }
59
60 /**
61 * Form API callback to validate the sparkline admin settings form.
62 */
63 function sparkline_admin_settings_validate($form, &$form_state) {
64 if (!is_dir($form_state['values']['sparkline_path'])) {
65 form_set_error('sparkline_path', t('The directory %dir does not exist.', array('%dir' => $form_state['values']['sparkline_path'])));
66 }
67 $cache_path = file_directory_path() .'/'. $form_state['values']['sparkline_cache'];
68 file_check_directory($cache_path, FILE_CREATE_DIRECTORY, 'sparkline_cache');
69 }
70
71 /**
72 * Render the form for the sparkline settings page.
73 *
74 * @return
75 * The system settings form for the sparklines module.
76 */
77 function sparkline_admin_settings() {
78 $form = array();
79 $form['sparkline_path'] = array(
80 '#type' => 'textfield',
81 '#title' => t('Sparkline PHP path'),
82 '#required' => TRUE,
83 '#description' => t('The Sparklines PHP library (http://sparkline.org) is required. Download it and copy it to the sparkline module directory.'),
84 '#default_value' => variable_get('sparkline_path', drupal_get_path('module', 'sparkline') .'/sparkline-php-0.2'),
85 );
86
87 $form['sparkline_cache'] = array(
88 '#type' => 'textfield',
89 '#title' => t('The name of the sparkline cache directory, inside of the normal Drupal files directory'),
90 '#required' => TRUE,
91 '#default_value' => variable_get('sparkline_cache', 'sparkline'),
92 );
93
94 return system_settings_form($form);
95 }
96
97 /**
98 * Implementation of hook_filter_tips().
99 */
100 function sparkline_filter_tips($delta, $format, $long = FALSE) {
101 return t('Sparkline filter: [sparkline style=line|bar|winloss height=15 12,3,-2,39,23,2,......]');
102 }
103
104 /**
105 * Implementation of hook_filter().
106 */
107 function sparkline_filter($op, $delta = 0, $format = -1, $text = '') {
108 if ($op == 'list') {
109 return array(0 => t('Sparkline filter'));
110 }
111
112 switch ($delta) {
113 case 0:
114 switch ($op) {
115 case 'description':
116 return t('Lets writers use the [sparkline] tag to embed tiny visual graphs in their posts.');
117
118 case 'prepare':
119 return $text;
120
121 case 'process':
122 return _sparkline_process_text($text);
123 }
124 break;
125 }
126 }
127
128 /**
129 * Process text from the sparkline input filter.
130 *
131 * @param $text
132 * The text to process.
133 * @return
134 * The rendered sparklines included in the text.
135 */
136 function _sparkline_process_text($text) {
137 $pattern = "/\[sparkline[ +]?(?:(?:style=)?(bar|line|winloss))?[ +]?(?:height=([0-9]*))?[ +]?(?:width=([0-9]*))?[ +]?(?:min=([0-9]*))?[ +]?(?:max=([0-9]*))? ([-0-9,]*)\]/";
138 if (preg_match_all($pattern, $text, $matches)) {
139 foreach ($matches[0] as $key => $value) {
140 $style = empty($matches[1][$key]) ? 'bar' : $matches[1][$key];
141 $tmp = sparkline_elements();
142 $sparkline = $tmp['sparkline_'. $style];
143
144 if (!empty($matches[2][$key])) {
145 $sparkline['#height'] = $matches[2][$key];
146 }
147 if (!empty($matches[3][$key])) {
148 $sparkline['#width'] = $matches[3][$key];
149 }
150 $sparkline['#min'] = empty($matches[4][$key]) ? NULL : $matches[4][$key];
151 $sparkline['#max'] = empty($matches[5][$key]) ? NULL : $matches[5][$key];
152 $sparkline['#data'] = explode(',', $matches[6][$key]);
153
154 // We do this so that filtered sparklines (which rarely change and whose urls are cached)
155 // don't get blown out of the cache folder at cron-time.
156 $sparkline['#do_not_flush'] = TRUE;
157
158 $replacements[$key] = theme('sparkline', $sparkline);
159 }
160 $text = str_replace($matches[0], $replacements, $text);
161 }
162 return $text;
163 }
164
165 /**
166 * Implementation of hook_elements().
167 */
168 function sparkline_elements() {
169 $elements['sparkline_line'] = _sparkline_defaults(array(
170 '#style' => 'line',
171 '#flag_points' => TRUE,
172 '#min' => NULL,
173 '#max' => NULL,
174 ));
175
176 $elements['sparkline_bar'] = _sparkline_defaults(array(
177 '#style' => 'bar',
178 '#bar_width' => 2,
179 '#bar_gap' => 1,
180 '#min' => NULL,
181 '#max' => NULL,
182 ));
183
184 $elements['sparkline_winloss'] = _sparkline_defaults(array(
185 '#style' => 'winloss',
186 '#bar_width' => 2,
187 '#bar_gap' => 1,
188 ));
189
190 return $elements;
191 }
192
193 /**
194 * Return the default values for a sparkline element.
195 *
196 * @param $element
197 * The element to add default settings to.
198 *
199 * @return
200 * The element with the default settings.
201 */
202 function _sparkline_defaults($element = array()) {
203 $element['#width'] = 'auto';
204 $element['#height'] = 15;
205 $element['#positive_color'] = 'black';
206 $element['#negative_color'] = 'red';
207 $element['#background_color'] = 'white';
208 $element['#data'] = array();
209 $element['#theme'] = 'sparkline_element';
210 $element['#do_not_flush'] = FALSE;
211 return $element;
212 }
213
214 /**
215 * Theme a sparkline element. Lines, bars, and win/loss sparklines can be
216 * rendered.
217 *
218 * @param $element
219 * The sparkline element to render.
220 *
221 * @return unknown_type
222 * The themed sparkline element HTML.
223 */
224 function theme_sparkline($element) {
225 $api_path = variable_get('sparkline_path', drupal_get_path('module', 'sparkline') .'/sparkline-php-0.2') .'/lib';
226
227 switch ($element['#style']) {
228 case 'line':
229 $path = _sparkline_generate_path($element);
230 if (!file_exists($path)) {
231 require_once($api_path .'/Sparkline_Line.php');
232 $sparkline = new Sparkline_Line(FALSE);
233 $min = 0;
234 $max = 0;
235 foreach ($element['#data'] as $i => $value) {
236 $min = ($element['#data'][$min] > $value) ? $i : $min;
237 $max = ($element['#data'][$max] < $value) ? $i : $max;
238
239 $sparkline->SetData($i, $value);
240 }
241 if ($element['#width'] == 'auto') {
242 $element['#width'] = min(count($element['#data']) * 3, 200);
243 }
244
245 if (!empty($element['#min'])) {
246 $sparkline->SetYMin($element['#min']);
247 }
248 if (!empty($element['#max'])) {
249 $sparkline->SetYMax($element['#max']);
250 }
251 if ($element['#flag_points']) {
252 $keys = array_keys($element['#data']);
253 $end = $keys[count($keys) - 1];
254 $sparkline->SetFeaturePoint($end - 1, $element['#data'][$end], 'grey', 2);
255 $sparkline->SetFeaturePoint($min, $element['#data'][$min], $element['#negative_color'], 2);
256 $sparkline->SetFeaturePoint($max, $element['#data'][$max ], $element['#positive_color'], 2);
257 }
258
259 $sparkline->RenderResampled($element['#width'], $element['#height']);
260 $sparkline->Output($path);
261 }
262 break;
263
264 case 'bar':
265 $path = _sparkline_generate_path($element);
266 if (!file_exists($path)) {
267 require_once($api_path .'/Sparkline_Bar.php');
268 $sparkline = new Sparkline_Bar(FALSE);
269
270 $sparkline->SetBarWidth($element['#bar_width']);
271 $sparkline->SetBarSpacing($element['#bar_gap']);
272
273 foreach ($element['#data'] as $i => $value) {
274 $sparkline->SetData($i, $value, ($value < 0 ? $element['#negative_color'] : $element['#positive_color']), FALSE);
275 }
276 if (!empty($element['#min'])) {
277 $sparkline->SetYMin($element['#min']);
278 }
279 if (!empty($element['#max'])) {
280 $sparkline->SetYMax($element['#max']);
281 }
282 $sparkline->Render($element['#height']);
283 $sparkline->Output($path);
284 }
285 break;
286
287 case 'winloss':
288 $path = _sparkline_generate_path($element);
289 if (!file_exists($path)) {
290 require_once($api_path .'/Sparkline_Bar.php');
291 $sparkline = new Sparkline_Bar(FALSE);
292
293 $sparkline->SetBarWidth($element['#bar_width']);
294 $sparkline->SetBarSpacing($element['#bar_gap']);
295
296 foreach ($element['#data'] as $i => $value) {
297 if ($value < 1) {
298 $sparkline->SetData($i, -1, $element['#negative_color'], FALSE);
299 }
300 else {
301 $sparkline->SetData($i, 1, $element['#positive_color'], FALSE);
302 }
303 }
304 if (!empty($element['#min'])) {
305 $sparkline->SetYMin($element['#min']);
306 }
307 $sparkline->Render($element['#height']);
308 $sparkline->Output($path);
309 }
310 break;
311 }
312
313 if (isset($path)) {
314 return theme('image', $path, NULL, NULL, array('class' => 'sparkline'));
315 }
316 }
317
318 /**
319 * Theme a sparkline form element.
320 *
321 * @param $element
322 * The form element to theme.
323 *
324 * @return
325 * The themed HTML for the sparkline element.
326 */
327 function theme_sparkline_element($element) {
328 return theme('form_element', $element, theme('sparkline', $element));
329 }
330
331 /**
332 * Generate a path to a sparkline.
333 *
334 * @param $sparkline
335 * The sparkline element to look up.
336 *
337 * @return
338 * The path to the sparkline.
339 */
340 function _sparkline_generate_path($sparkline) {
341 // If the directory doesn't exist, create it.
342 $cache_dir = file_directory_path() .'/'. variable_get('sparkline_cache', 'sparkline');
343 if (!file_exists($cache_dir)) {
344 mkdir(file_directory_path() .'/'. variable_get('sparkline_cache', 'sparkline'));
345 }
346 if (!empty($sparkline['#filename'])) {
347 return file_directory_path() .'/'. variable_get('sparkline_cache', 'sparkline') .'/'. $sparkline['#filename'];
348 }
349 else {
350 return file_directory_path() .'/'. variable_get('sparkline_cache', 'sparkline') .'/'. ($element['#do_not_flush'] ? '-' : '') . md5(serialize($sparkline)) .'.png';
351 }
352 }
353
354 /**
355 * Flush the sparkline image cache.
356 */
357 function _sparkline_flush_cache() {
358 $listing = file_directory_path() .'/'. variable_get('sparkline_cache', 'sparkline') ."/{!-}*.png";
359 foreach (glob($listing) as $file) {
360 if (is_file($file) === true) {
361 @unlink($file);
362 }
363 }
364 }

  ViewVC Help
Powered by ViewVC 1.1.2