PluginProbe ʕ •ᴥ•ʔ
GiveWP – Donation Plugin and Fundraising Platform / trunk
GiveWP – Donation Plugin and Fundraising Platform vtrunk
4.16.2 4.16.1 4.16.0 4.15.5 4.15.4 4.15.3 4.15.2 4.15.1 4.15.0 2.3.0 2.3.1 2.3.2 2.30.0 2.31.0 2.31.1 2.32.0 2.33.0 2.33.1 2.33.2 2.33.3 2.33.4 2.33.5 2.4.0 2.4.1 2.4.2 2.4.3 2.4.4 2.4.5 2.4.6 2.4.7 2.5.0 2.5.1 2.5.10 2.5.11 2.5.12 2.5.13 2.5.2 2.5.3 2.5.4 2.5.5 2.5.6 2.5.7 2.5.8 2.5.9 2.6.0 2.6.1 2.6.2 2.6.3 2.7.0 2.7.1 2.7.2 2.7.3 2.7.4 2.7.5 2.8.0 2.8.1 2.9.0 2.9.1 2.9.2 2.9.3 2.9.4 2.9.5 2.9.6 2.9.7 3.0.0 3.0.1 3.0.2 3.0.3 3.0.4 3.1.0 3.1.1 3.1.2 3.10.0 3.11.0 3.12.0 3.12.1 3.12.2 3.12.3 3.13.0 3.14.0 3.14.1 3.14.2 3.15.0 3.15.1 3.16.0 3.16.1 3.16.2 3.16.3 3.16.4 3.16.5 3.17.0 3.17.1 3.17.2 3.18.0 3.19.0 3.19.1 3.19.2 3.19.3 3.19.4 3.2.0 3.2.1 3.2.2 3.20.0 3.21.0 3.21.1 3.22.0 3.22.1 3.22.2 3.3.0 3.3.1 3.4.0 3.4.1 3.4.2 3.5.0 3.5.1 3.6.0 3.6.1 3.6.2 3.7.0 3.8.0 3.9.0 4.0.0 4.1.0 4.1.1 4.10.0 4.10.1 4.11.0 4.12.0 4.13.0 4.13.1 4.13.2 4.14.0 4.14.1 4.14.2 4.14.3 4.14.4 4.14.5 4.14.6 4.2.0 4.2.1 4.3.0 4.3.1 4.3.2 4.4.0 4.5.0 4.6.1 4.7.0 4.7.1 4.8.0 4.8.1 4.9.0 trunk 1.9.0 2.0.0 2.0.1 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7 2.1.0 2.1.1 2.1.2 2.1.3 2.1.4 2.1.5 2.1.6 2.1.7 2.1.8 2.10.0 2.10.1 2.10.2 2.10.3 2.10.4 2.11.0 2.11.1 2.11.2 2.11.3 2.12.0 2.12.1 2.12.2 2.12.3 2.13.0 2.13.1 2.13.2 2.13.3 2.13.4 2.14.0 2.15.0 2.16.0 2.16.1 2.17.0 2.17.1 2.17.3 2.18.0 2.18.1 2.19.1 2.19.2 2.19.3 2.19.4 2.19.5 2.19.6 2.19.7 2.19.8 2.2.0 2.2.1 2.2.2 2.2.3 2.2.4 2.2.5 2.2.6 2.20.0 2.20.1 2.20.2 2.21.0 2.21.1 2.21.2 2.21.3 2.21.4 2.22.0 2.22.1 2.22.2 2.22.3 2.23.0 2.23.1 2.23.2 2.24.0 2.24.1 2.24.2 2.25.0 2.25.1 2.25.2 2.25.3 2.26.0 2.27.0 2.27.1 2.27.2 2.27.3 2.28.0 2.29.0 2.29.1 2.29.2
give / includes / libraries / googlechartlib / GoogleChart.php
give / includes / libraries / googlechartlib Last commit date
icons 8 years ago markers 8 years ago GoogleChart.php 8 years ago GoogleChartApi.php 8 years ago GoogleChartAxis.php 8 years ago GoogleChartData.php 8 years ago GoogleChartIcon.php 8 years ago GoogleChartMarker.php 8 years ago LICENSE 8 years ago
GoogleChart.php
1081 lines
1 <?php
2
3 /** @file
4 * This file is part of Google Chart PHP library.
5 *
6 * Copyright (c) 2010 Rémi Lanvin <remi@cloudconnected.fr>
7 *
8 * Licensed under the MIT license.
9 *
10 * For the full copyright and license information, please view the LICENSE file.
11 */
12
13 require_once 'GoogleChartApi.php';
14 require_once 'GoogleChartData.php';
15 require_once 'GoogleChartAxis.php';
16 require_once 'GoogleChartMarker.php';
17
18 /**
19 * A chart.
20 *
21 * This class represent a chart. It provides a bunch of setters to customize it.
22 * When creating a new chart, you need to specify 3 things:
23 * - type of the chart (see http://code.google.com/apis/chart/docs/gallery/chart_gall.html)
24 * - width
25 * - height
26 *
27 * Then you need to add data to that chart using GoogleChartData class.
28 *
29 * Depending on the type of chart, you can also add one or more axis using GoogleChartAxis class.
30 *
31 * @par Line chart example
32 *
33 * @include line_chart.php
34 *
35 * @par Work around for unimplemented features
36 *
37 * You can override any parameter by setting its value in the class.
38 * For example, to following code will override the background:
39 *
40 * \code
41 * $chart = new GoogleChart('lc', 500, 200);
42 * $chart->chf = 'b,s,cccccc';
43 * var_dump($chart->getQuery());
44 * \endcode
45 *
46 * You can use this method for working with features that are currently
47 * not implemented in the library (or buggy).
48 */
49 class GoogleChart extends GoogleChartApi
50 {
51 const AUTOSCALE_OFF = false;
52 const AUTOSCALE_VALUES = true;
53
54 const BACKGROUND = 'bg';
55 const CHART_AREA = 'c';
56
57 const TEXT = 't';
58 const SIMPLE_ENCODING = 's';
59 const EXTENDED_ENCODING = 'e';
60
61 /**
62 * Store the type of the chart as string.
63 */
64 protected $type = '';
65
66 /**
67 * Width
68 */
69 protected $width = '';
70
71 /**
72 * Height
73 */
74 protected $height = '';
75
76 /**
77 * List of all data series (GoogleChartData)
78 */
79 protected $data = array();
80
81 /**
82 * Data format (text, simple encoding or extended encoding)
83 */
84 protected $data_format = self::TEXT;
85
86 /**
87 * Data format have different separator character
88 */
89 protected $data_separator = array(
90 self::TEXT => '|',
91 self::SIMPLE_ENCODING => ',',
92 self::EXTENDED_ENCODING => ','
93 );
94
95 /**
96 * List of all axes (GoogleChartAxis)
97 */
98 protected $axes = array();
99
100 /**
101 * List of all markers (GoogleChartMarker) @c chm parameter
102 */
103 protected $markers = array();
104
105 /**
106 * List of dynamic markers (GooglechartIcon). @c chem parameter
107 */
108 protected $dynamic_markers = array();
109
110 protected $grid_lines = null;
111
112 protected $chts = false;
113 protected $title = null;
114 protected $title_color = '000000';
115 protected $title_size = '12';
116
117 protected $autoscale = true;
118 protected $scale = null;
119
120 protected $legend_position = null;
121 protected $legend_label_order = null;
122 protected $legend_skip_empty = true;
123
124 protected $fills = null;
125
126 protected $_compute_data_label = false;
127
128 //~ protected $chma = false;
129 protected $margin = null;
130 protected $legend_size = null;
131
132 /**
133 * Create a new chart.
134 *
135 * @param $type (string)
136 * Google chart type.
137 * @param $width (int)
138 * @param $height (int)
139 *
140 * @see http://code.google.com/apis/chart/docs/gallery/chart_gall.html
141 */
142 public function __construct($type, $width, $height)
143 {
144 $this->type = $type;
145 $this->width = $width;
146 $this->height = $height;
147
148 //~ $this->setAutoscale(self::AUTOSCALE_Y_AXIS);
149 //~ $this->setQueryMethod(self::POST);
150 }
151
152 /**
153 * Set the data format used by the chart.
154 * Default is GoogleChart::TEXT (basic text format).
155 * @since 0.5
156 */
157 public function setDataFormat($format)
158 {
159 if ( $format !== self::TEXT && $format !== self::SIMPLE_ENCODING && $format !== self::EXTENDED_ENCODING ) {
160 throw new InvalidArgumentException('Invalid data format');
161 }
162
163 $this->data_format = $format;
164 }
165
166 /**
167 * Add a data serie to the chart.
168 *
169 * @param $data (GoogleChartData)
170 * @see GoogleChartData
171 */
172 public function addData(GoogleChartData $data)
173 {
174 if ( $data->hasIndex() )
175 throw new LogicException('Invalid data serie. This data serie has already been added.');
176
177 $index = array_push($this->data, $data);
178 $data->setIndex($index - 1);
179 return $this;
180 }
181
182 /**
183 * Add a visible axis to the chart.
184 *
185 * @param $axis (GoogleChartAxis)
186 * @see GoogleChartAxis
187 */
188 public function addAxis(GoogleChartAxis $axis)
189 {
190 $this->axes[] = $axis;
191
192 return $this;
193 }
194
195 /**
196 * Add a marker to the chart.
197 *
198 * @param $marker (GoogleChartMarker)
199 * @see GoogleChartShapeMarker, GoogleChartTextMarker, GoogleChartLineMarker
200 * @return $this
201 */
202 public function addMarker(GoogleChartMarker $marker)
203 {
204 $this->markers[] = $marker;
205
206 return $this;
207 }
208
209 /**
210 * Add a dynamic icon marker to the chart.
211 *
212 * Dynamic icon marker are different than regular marker. Technically, they
213 * are defined using @c chem parameter instead of @c chm for regular marker.
214 *
215 * @param $marker (GoogleChartIcon)
216 * @return $this
217 */
218 public function addDynamicMarker(GoogleChartIcon $marker)
219 {
220 $this->dynamic_markers[] = $marker;
221
222 return $this;
223 }
224
225 /**
226 * @name Scaling
227 */
228 //@{
229 /**
230 * Set autoscaling mode.
231 *
232 * Autoscaling is a feature provided by this library. Because Google Chart
233 * default scale is 0:100, most of the time your data will not appears the
234 * way you want. So you need to set a scale for the chart.
235 *
236 * @see http://code.google.com/p/googlechartphplib/wiki/Autoscaling
237 *
238 * @see http://code.google.com/apis/chart/docs/data_formats.html#data_scaling
239 *
240 * @param $autoscale (bool)
241 * @return $this
242 */
243 public function setAutoscale($autoscale)
244 {
245 if ( $autoscale !== true && $autoscale !== false ) {
246 throw new InvalidArgumentException('Invalid autoscale mode.');
247 }
248
249 $this->autoscale = $autoscale;
250 return $this;
251 }
252
253 /**
254 * Set a global scale for the chart.
255 * Turns off autoscaling.
256 * @since 0.5
257 * @param $min (int)
258 * @param $max (int)
259 * @return $this
260 */
261 public function setScale($min, $max)
262 {
263 $this->setAutoscale(false);
264
265 $this->scale = array(
266 'min' => $min,
267 'max' => $max
268 );
269 return $this;
270 }
271
272 /**
273 * Return the scale.
274 * Note that after the chart has been computed, this function will returns
275 * the actual scale computed by the chart.
276 *
277 * @return array
278 */
279 public function getScale()
280 {
281 return $this->scale;
282 }
283
284 /**
285 * Compute the @c chds parameter.
286 * @internal
287 */
288 public function computeChds()
289 {
290 if ( $this->scale === null ) {
291 throw new LogicException('Cannot compute scale that has not been set');
292 }
293 return $this->scale['min'].','.$this->scale['max'];
294 }
295 //@}
296
297 /**
298 * @name Chart title and style (chtt, chts)
299 */
300 //@{
301 /**
302 * Set the chart title (@c chtt).
303 *
304 * @param $title (string)
305 *
306 * @see http://code.google.com/apis/chart/docs/chart_params.html#gcharts_chart_title
307 * @return $this
308 */
309 public function setTitle($title)
310 {
311 $this->title = $title;
312 return $this;
313 }
314
315 /**
316 * Returns chart title setted by setTitle().
317 * @return string
318 */
319 public function getTitle()
320 {
321 return $this->title;
322 }
323
324 /** @internal
325 * Compute @c chtt parameter (chart title).
326 *
327 * @return string or null if parameter is not needed
328 * @see http://code.google.com/apis/chart/docs/chart_params.html#gcharts_chart_title
329 */
330 public function computeChtt()
331 {
332 if ( $this->title === null )
333 return null;
334
335 return str_replace(array("\r","\n"), array('','|'), $this->title);
336 }
337
338 /**
339 * Set the color of the title (@c chts).
340 *
341 * @param $color (string in ) The title color, in RRGGBB hexadecimal format. Default color is black.
342 *
343 * @since 0.4
344 * @see http://code.google.com/apis/chart/docs/chart_params.html#gcharts_chart_title
345 */
346 public function setTitleColor($color)
347 {
348 $this->chts = true;
349 $this->title_color = $color;
350 return $this;
351 }
352
353 /**
354 * Returns the title color.
355 *
356 * If no title color has been set using setTitleColor(), it will returns
357 * the default title color.
358 *
359 * @since 0.4
360 * @return string in RRGGBB format
361 */
362 public function getTitleColor()
363 {
364 return $this->title_color;
365 }
366
367 /**
368 * Set the font size of the title (@c chts).
369 *
370 * @param $size (int) Font size of the title, in points.
371 *
372 * @since 0.4
373 * @see http://code.google.com/apis/chart/docs/chart_params.html#gcharts_chart_title
374 */
375 public function setTitleSize($size)
376 {
377 $this->chts = true;
378 $this->title_size = $size;
379 return $this;
380 }
381
382 /**
383 * Returns the title size.
384 *
385 * If no title size has been set using setTitleSize(), it will returns the
386 * default title color.
387 *
388 * @since 0.4
389 * @return string
390 */
391 public function getTitleSize()
392 {
393 return $this->title_size;
394 }
395
396 /** @internal
397 * Compute @c chts parameter.
398 *
399 * @since 0.4
400 * @return string or null if the parameter is not needed
401 * @see http://code.google.com/apis/chart/docs/chart_params.html#gcharts_chart_title
402 */
403 public function computeChts()
404 {
405 return $this->title_color.','.$this->title_size;
406 }
407
408 /**
409 * @internal
410 * Return true if chts parameter is needed
411 * Little trick here, if no title is set, then chts is not needed, even
412 * if specified
413 * @return bool
414 */
415 public function hasChts()
416 {
417 return $this->chts;
418 }
419
420 //@}
421
422 /**
423 * @name Chart Legend Text and Style (@c chdl, @c chdlp, @c chma)
424 */
425 //@{
426
427 /**
428 * Set position of the legend box (@c chdlp).
429 *
430 * The parameter is not checked so you can pass whatever you want. This way,
431 * if the Google Chart API evolves, this library will still works. However,
432 * be warned that you chart may not be displayed as expected if you pass wrong
433 * parameter.
434 *
435 * @see http://code.google.com/apis/chart/docs/chart_params.html#gcharts_legend
436 *
437 * @param $position (string)
438 * One of the following: 'b', 'bv', 't', 'tv', 'r', 'l'
439 * (read Google Chart Documentation for details).
440 * @return $this
441 */
442 public function setLegendPosition($position)
443 {
444 $this->legend_position = $position;
445 return $this;
446 }
447
448 /**
449 * Set labels order inside the legend box (chdlp).
450 *
451 * The parameter is not checked so you can pass whatever you want. This way,
452 * if the Google Chart API evolves, this library will still works. However,
453 * be warned that you chart may not be displayed as expected if you pass wrong
454 * parameter.
455 *
456 * @see http://code.google.com/apis/chart/docs/chart_params.html#gcharts_legend
457 *
458 * @param $label_order (string)
459 * One of the following: 'l', 'r', 'a', or a list of numbers
460 * separated by commas (read Google Chart Documentation for details).
461 * @return $this
462 */
463 public function setLegendLabelOrder($label_order)
464 {
465 $this->legend_label_order = $label_order;
466 return $this;
467 }
468
469 /**
470 * Set if empty legends entries shoud be skipped in the legend or not.
471 *
472 * @param $skip_empty (bool)
473 */
474 public function setLegendSkipEmpty($skip_empty)
475 {
476 $this->legend_skip_empty = (bool) $skip_empty;
477 return $this;
478 }
479
480 /**
481 * Size of the legend box (@c chma).
482 *
483 * @since 0.5
484 * @param $width (int)
485 * @param $height (int)
486 */
487 public function setLegendSize($width, $height)
488 {
489 $this->legend_size = array(
490 'width' => $width,
491 'heigh' => $height
492 );
493 return $this;
494 }
495
496 /**
497 * @internal
498 * @since 0.4
499 */
500 public function computeChdlp()
501 {
502 $str = '';
503 if ( $this->legend_position !== null ) {
504 $str .= $this->legend_position;
505 }
506 if ( $this->legend_skip_empty === true ) {
507 $str .= 's';
508 }
509 if ( $this->legend_label_order !== null ) {
510 $str .= '|'.$this->legend_label_order;
511 }
512 return $str;
513 }
514
515 /**
516 * @internal
517 * @since 0.4
518 */
519 public function hasChdlp()
520 {
521 return $this->legend_skip_empty === true || $this->legend_position !== null || $this->legend_label_order !== null;
522 }
523 //@}
524
525 /**
526 * Specify solid or dotted grid lines on the chart. (@c chg)
527 *
528 * @param $x_axis_step_size
529 * @param $y_axis_step_size
530 * @param $dash_length
531 * @param $space_length
532 * @param $x_offset
533 * @param $y_offset
534 *
535 * @see http://code.google.com/apis/chart/docs/chart_params.html#gcharts_grid_lines
536 */
537 public function setGridLines($x_axis_step_size, $y_axis_step_size, $dash_length = false,
538 $space_length = false, $x_offset = false, $y_offset = false)
539 {
540 $this->grid_lines = $x_axis_step_size.','.$y_axis_step_size;
541 if ( $dash_length !== false ) {
542 $this->grid_lines .= ','.$dash_length;
543 if ( $space_length !== false ) {
544 $this->grid_lines .= ','.$space_length;
545 if ( $x_offset !== false ) {
546 $this->grid_lines .= ','.$x_offset;
547 if ( $y_offset !== false ) {
548 $this->grid_lines .= ','.$y_offset;
549 }
550 }
551 }
552 }
553 return $this;
554 }
555
556 /**
557 * @name Gradient, Solid and Stripped Fills (chf)
558 */
559 //@{
560 /**
561 * Set a solid background (fill) for an area (@c chf).
562 *
563 * @param $color (string) RGB color
564 * @param $area One of the following:
565 * - GoogleChart::BACKGROUND for the whole background
566 * - GoogleChart::CHART_AREA for only the chart area background
567 * @return $this
568 */
569 public function setFill($color, $area = self::BACKGROUND)
570 {
571 if ( $area != self::BACKGROUND && $area != self::CHART_AREA ) {
572 throw new InvalidArgumentException('Invalid fill area.');
573 }
574
575 $this->fills[$area] = $area.',s,'.$color;
576 return $this;
577 }
578
579 /**
580 * Set the opacity for solid background (fill).
581 *
582 * @param $opacity (int) Between 0 (transparent) and 100 (opaque)
583 * @return $this
584 */
585 public function setOpacity($opacity)
586 {
587 if ( $opacity < 0 || $opacity > 100 ) {
588 throw new InvalidArgumentException('Invalid opacity (must be between 0 and 100).');
589 }
590
591 // 100% = 255
592 $opacity = str_pad(dechex(round($opacity * 255 / 100)), 8, 0, STR_PAD_LEFT);
593
594 // Opacity doesn't work with other backgrounds
595 $this->fills[self::BACKGROUND] = 'a,s,'.$opacity;
596
597 return $this;
598 }
599
600 /**
601 * Gradient fill.
602 *
603 * @param $angle (int)
604 * A number specifying the angle of the gradient
605 * from 0 (horizontal) to 90 (vertical).
606 * @param $colors (array)
607 * An array of color of the fill. Each color can be a
608 * string in RRGGBB hexadecimal format, or an array of two values: RRGGBB
609 * color, and color centerpoint.
610 *
611 * @see http://code.google.com/apis/chart/docs/chart_params.html#gcharts_gradient_fills
612 */
613 public function setGradientFill($angle, array $colors, $area = self::BACKGROUND)
614 {
615 if ( $angle < 0 || $angle > 90 ) {
616 throw new InvalidArgumentException('Invalid angle (must be between 0 and 90).');
617 }
618
619 if ( ! isset($colors[1]) ) {
620 throw new InvalidArgumentException('You must specify at least 2 colors to create a gradient fill.');
621 }
622
623 if ( $area != self::BACKGROUND && $area != self::CHART_AREA ) {
624 throw new InvalidArgumentException('Invalid area.');
625 }
626
627 $tmp = array();
628 $i = 0;
629 $n = sizeof($colors);
630 for ( $i = 0; $i < $n; $i++ ) {
631 $centerpoint = null;
632 $color = null;
633
634 if ( is_array($colors[$i]) ) {
635 $c = $colors[$i];
636 if ( ! isset($c[0]) ) {
637 throw new InvalidArgumentException('Each color must be an array of the color code in RRGGBB and the color centerpoint.');
638 }
639 $color = $c[0];
640 if ( isset($c[1]) ) {
641 $centerpoint = $c[1];
642 }
643 }
644 else {
645 $color = $colors[$i];
646 }
647 // No color centerpoint, try to calculate a good one:
648 if ( ! $centerpoint ) {
649 $centerpoint = $i / ($n-1);
650 }
651 $tmp[] = $color.','.round($centerpoint,2);
652 }
653
654 $this->fills[$area] = $area.',lg,'.$angle.','.implode(',',$tmp);
655 }
656
657 /**
658 * Striped fill.
659 * @todo
660 */
661 public function setStripedFill($angle, array $colors, $area = self::BACKGROUND)
662 {
663
664 }
665 //@}
666
667 /**
668 * @name Chart Margins
669 */
670 //@{
671
672 /**
673 * Set margin around the charts (@c chma).
674 *
675 * This function works like the CSS property "margin" :
676 * - If you specify only one parameter, then this value is used for all.
677 * - If you specify 2 parameters, then first is "top/bottom" and second is "left/right"
678 * - If you specify 4 parameters, then they are: top, right, bottom, left (tips: it's clockwise).
679 *
680 * @since 0.5
681 *
682 * @param $top (float)
683 * @param $right (float)
684 * @param $bottom (float)
685 * @param $left (float)
686 * @return $this
687 */
688 public function setMargin($top, $right = null, $bottom = null, $left = null)
689 {
690 // If only one value, then all have the same values
691 if ( $left === null && $right === null && $bottom === null ) {
692 $this->margin = array(
693 'left' => (float) $top,
694 'right' => (float) $top,
695 'top' => (float) $top,
696 'bottom' => (float) $top
697 );
698 }
699 elseif ( $left === null && $bottom === null ) {
700 $this->margin = array(
701 'left' => (float) $right,
702 'right' => (float) $right,
703 'top' => (float) $top,
704 'bottom' => (float) $top
705 );
706 }
707 else {
708 $this->margin = array(
709 'left' => (float) $left,
710 'right' => (float) $right,
711 'top' => (float) $top,
712 'bottom' => (float) $bottom
713 );
714 }
715 return $this;
716 }
717
718 /**
719 * @internal
720 */
721 public function computeChma()
722 {
723 $str = '';
724 if ( $this->margin ) {
725 $str = implode(',',$this->margin);
726 }
727 if ( $this->legend_size ) {
728 $str .= '|'.implode(',',$this->legend_size);
729 }
730 return $str;
731 }
732
733 /**
734 * @internal
735 */
736 public function hasChma()
737 {
738 return $this->margin !== null || $this->legend_size !== null;
739 }
740
741 //@}
742
743 /**
744 * @name URL creation
745 */
746 //@{
747
748 /**
749 * Compute the whole query as an array.
750 * @internal
751 * Shouldn't be overrided, but who knows?
752 */
753 protected function computeQuery()
754 {
755 $q = array(
756 'cht' => $this->type,
757 'chs' => $this->width.'x'.$this->height
758 );
759
760 $this->compute($q);
761
762 $q = array_merge($q, $this->parameters);
763
764 return $q;
765 }
766
767 /**
768 * Compute the whole query as an array.
769 * @internal
770 * To be overrided by child classes.
771 */
772 protected function compute(array & $q)
773 {
774 if ( $this->grid_lines ) {
775 $q['chg'] = $this->grid_lines;
776 }
777 if ( $this->fills ) {
778 $q['chf'] = implode('|',$this->fills);
779 }
780
781 if ( $this->hasChma() ) {
782 $q['chma'] = $this->computeChma();
783 }
784 $this->computeTitle($q);
785
786 $this->computeScale($q);
787 $this->computeData($q);
788 $this->computeMarkers($q);
789 $this->computeAxes($q);
790 }
791
792 /**
793 * Compute title related parameters (chtt and chts)
794 * @internal
795 */
796 protected function computeTitle(array & $q)
797 {
798 if ( $this->title ) {
799 $q['chtt'] = $this->computeChtt();
800
801 if ( $this->hasChts() ) {
802 $q['chts'] = $this->computeChts();
803 }
804 }
805 }
806
807 /**
808 * @internal
809 * @since 0.5
810 */
811 protected function computeScale(array & $q)
812 {
813 if ( ! $this->autoscale )
814 return $this;
815
816 $value_min = 0;
817 $value_max = 0;
818
819 foreach ( $this->data as $i => $d ) {
820 $values = $d->getValues();
821 if ( $values === null || empty($values) )
822 continue;
823
824 $max = max($values);
825 $min = min($values);
826 if ( $max > $value_max ) {
827 $value_max = $max;
828 }
829 if ( $min < $value_min ) {
830 $value_min = $min;
831 }
832 }
833
834 if ( $value_min > 0 )
835 $value_min = 0;
836
837 $this->scale = array('min' => $value_min, 'max' => $value_max);
838 return $this;
839 }
840
841 /**
842 * Compute data series.
843 *
844 * @note This function is too long. I think it needs a redesign, but for the
845 * moment I have no idea how to make it shorter.
846 *
847 * @internal
848 */
849 protected function computeData(array & $q)
850 {
851 $data = array();
852
853 $colors = array();
854 $colors_needed = false;
855
856 $styles = array();
857 $styles_needed = false;
858
859 $fills = array();
860
861 $scales = array();
862 $scale_needed = false;
863
864 $legends = array();
865 $legends_needed = false;
866
867 if ( $this->_compute_data_label ) {
868 $labels = array();
869 }
870
871 foreach ( $this->data as $i => $d ) {
872 // Data serie values and scale
873 if ( $d->hasValues() ) {
874 $data[] = $d->computeChd($this->data_format, $this->scale);
875 // Compute per-data scale only if autoscale if off
876 if ( ! $this->autoscale && ! $this->scale ) {
877 $scales[] = $d->computeChds();
878 if ( $d->hasCustomScale() ) {
879 $scale_needed = true;
880 }
881 }
882 }
883
884 // Data serie color (chco)
885 $colors[] = $d->computeChco();
886 if ( $colors_needed == false && $d->hasChco() ) {
887 $colors_needed = true;
888 }
889
890 // Data serie style (chls)
891 $styles[] = $d->computeChls();
892 if ( $styles_needed == false && $d->hasChls() ) {
893 $styles_needed = true;
894 }
895
896 $tmp = $d->computeChm($i);
897 if ( $tmp ) {
898 $fills[] = $tmp;
899 }
900
901 $legends[] = $d->getLegend();
902 if ( $legends_needed == false && $d->hasCustomLegend() ) {
903 $legends_needed = true;
904 }
905
906 if ( $this->_compute_data_label ) {
907 $labels[] = $d->computeChl();
908 }
909 }
910 if ( ! isset($data[0]) )
911 return;
912
913 $q['chd'] = $this->data_format.':'.implode($this->data_separator[$this->data_format],$data);
914
915 if ( $colors_needed ) {
916 $q['chco'] = implode(',',$colors);
917 }
918 if ( $styles_needed ) {
919 $q['chls'] = implode('|',$styles);
920 }
921
922 if ( $this->_compute_data_label ) {
923 $tmp = rtrim(implode('|',$labels),'|');
924 if ( $tmp ) {
925 $q['chl'] = $tmp;
926 }
927 }
928
929 if ( $this->scale ) {
930 $q['chds'] = $this->computeChds();
931 }
932 elseif ( $scale_needed && isset($scales[0]) ) {
933 $q['chds'] = implode(',', $scales);
934 }
935
936 // Legends
937 if ( $legends_needed ) {
938 $q['chdl'] = implode('|',$legends);
939 if ( $this->hasChdlp() ) {
940 $q['chdlp'] = $this->computeChdlp();
941 }
942 }
943
944 if ( isset($fills[0]) )
945 $q['chm'] = implode('|',$fills);
946
947 return $this;
948 }
949
950
951 /**
952 * Compute the markers.
953 * @internal
954 * This function loops through the lists of the markers.
955 */
956 protected function computeMarkers(array & $q)
957 {
958 $markers = array();
959 $dynamic_markers = array();
960 $additional_data = array();
961
962 $nb_data_series = sizeof($this->data);
963 $current_index = $nb_data_series;
964
965 $array = $this->markers + $this->dynamic_markers;
966 foreach ( $array as $m ) {
967 $data = $m->getData();
968
969 $index = null;
970 if ( $data ) {
971 // Get the data serie index
972 $index = $data->getIndex();
973 if ( $index === null ) {
974 $additional_data[] = $data->computeChd($this->data_format);
975 $index = $current_index;
976 $current_index += 1;
977 }
978 }
979
980 // Now $index contains the correct data serie index
981 $tmp = $m->compute($index, $this->type);
982 if ( $tmp === null )
983 continue; // Ignore empty markers
984
985 if ( $m instanceof GoogleChartMarker ) {
986 $markers[] = $tmp;
987 }
988 else {
989 $dynamic_markers[] = $tmp;
990 }
991 }
992
993 if ( isset($markers[0]) ) {
994 $q['chm'] = (isset($q['chm']) ? $q['chm'].'|' : '').implode('|',$markers);
995 }
996
997 if ( isset($dynamic_markers[0]) ) {
998 $q['chem'] = implode('|',$dynamic_markers);
999 }
1000
1001 // Append every additional_data to 'chd'
1002 if ( isset($additional_data[0]) ) {
1003 $q['chd'] = $this->data_format.$nb_data_series.substr($q['chd'],1).$this->data_separator[$this->data_format].implode($this->data_separator[$this->data_format],$additional_data);
1004 }
1005 }
1006
1007 /**
1008 * Compute axes.
1009 * @internal
1010 */
1011 protected function computeAxes(array & $q)
1012 {
1013 $axes = array();
1014 $labels = array();
1015 $ranges = array();
1016 $tick_marks = array();
1017 $styles = array();
1018 $label_positions = array();
1019 foreach ( $this->axes as $i => $a ) {
1020 $axes[] = $a->getName();
1021 if ( $a->hasCustomLabels() ) {
1022 $labels[] = sprintf($a->getLabels(), $i);
1023 }
1024
1025 $tmp = $a->getRange();
1026 if ( $tmp !== null ) {
1027 $ranges[] = sprintf($tmp, $i);
1028 }
1029
1030 $tmp = $a->getTickMarks();
1031 if ( $tmp !== null ) {
1032 $tick_marks[] = sprintf($tmp, $i);
1033 }
1034
1035 $tmp = $a->computeChxs($i, $this->type);
1036 if ( $tmp !== null ) {
1037 $styles[] = $tmp;
1038 }
1039
1040 if ( $a->hasChxp() ) {
1041 $label_positions[] = $a->computeChxp($i);
1042 }
1043 }
1044 if ( isset($axes[0]) ) {
1045 $q['chxt'] = implode(',',$axes);
1046 if ( isset($labels[0]) ) {
1047 $q['chxl'] = implode('|',$labels);
1048 }
1049 if ( isset($ranges[0]) ) {
1050 $q['chxr'] = implode('|', $ranges);
1051 }
1052 if ( isset($tick_marks[0]) ) {
1053 $q['chxtc'] = implode('|', $tick_marks);
1054 }
1055 if ( isset($styles[0]) ) {
1056 $q['chxs'] = implode('|', $styles);
1057 }
1058 if ( isset($label_positions[0]) ) {
1059 $q['chxp'] = implode('|',$label_positions);
1060 }
1061 }
1062
1063 return $this;
1064 }
1065
1066 //@}
1067
1068
1069 }
1070
1071 /** @example line_chart.php
1072 * A basic example of how to work with line chart.
1073 */
1074 /** @example line_chart_sin_cos.php
1075 * Another line chart example, with multiple data series.
1076 */
1077 /**
1078 * @example line_chart_full.php
1079 * Another line chart example with plenty of options enabled.
1080 */
1081