1<?php
2
3/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
4
5/**
6 * Image_Graph - PEAR PHP OO Graph Rendering Utility.
7 *
8 * PHP version 5
9 *
10 * LICENSE: This library is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Lesser General Public License as published by
12 * the Free Software Foundation; either version 2.1 of the License, or (at your
13 * option) any later version. This library is distributed in the hope that it
14 * will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
15 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
16 * General Public License for more details. You should have received a copy of
17 * the GNU Lesser General Public License along with this library; if not, write
18 * to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19 * 02111-1307 USA
20 *
21 * @category   Images
22 * @package    Image_Graph
23 * @subpackage Plot
24 * @author     Jesper Veggerby <pear.nosey@veggerby.dk>
25 * @author     Stefan Neufeind <pear.neufeind@speedpartner.de>
26 * @copyright  2003-2009 The PHP Group
27 * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
28 * @version    SVN: $Id: Plot.php 291755 2009-12-06 02:25:02Z neufeind $
29 * @link       http://pear.php.net/package/Image_Graph
30 */
31
32/**
33 * Include file Image/Graph/Plotarea/Element.php
34 */
35require_once 'Image/Graph/Plotarea/Element.php';
36
37/**
38 * Framework for a chart
39 *
40 * @category   Images
41 * @package    Image_Graph
42 * @subpackage Plot
43 * @author     Jesper Veggerby <pear.nosey@veggerby.dk>
44 * @author     Stefan Neufeind <pear.neufeind@speedpartner.de>
45 * @copyright  2003-2009 The PHP Groupn
46 * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
47 * @version    Release: 0.8.0
48 * @link       http://pear.php.net/package/Image_Graph
49 * @abstract
50 */
51class Image_Graph_Plot extends Image_Graph_Plotarea_Element
52{
53
54    /**
55     * The dataset to plot
56     * @var Dataset
57     * @access private
58     */
59    var $_dataset;
60
61    /**
62     * The marker to plot the data set as
63     * @var Marker
64     * @access private
65     */
66    var $_marker = null;
67
68    /**
69     * The dataselector to use for data marking
70     * @var DataSelector
71     * @access private
72     */
73    var $_dataSelector = null;
74
75    /**
76     * The Y axis to associate the plot with
77     * @var int
78     * @access private
79     */
80    var $_axisY = IMAGE_GRAPH_AXIS_Y;
81
82    /**
83     * The type of the plot if multiple datasets are used
84     * @var string
85     * @access private
86     */
87    var $_multiType = 'normal';
88
89    /**
90     * The title of the plot, used for legending in case of simple plots
91     * @var string
92     * @access private
93     */
94    var $_title = 'plot';
95
96    /**
97     * PlotType [Constructor]
98     *
99     * Valid values for multiType are:
100     *
101     * 'normal' Plot is normal, multiple datasets are displayes next to one
102     * another
103     *
104     * 'stacked' Datasets are stacked on top of each other
105     *
106     * 'stacked100pct' Datasets are stacked and displayed as percentages of the
107     * total sum
108     *
109     * I no title is specified a default is used, which is basically the plot
110     * type (fx. for a 'Image_Graph_Plot_Smoothed_Area' default title is
111     * 'Smoothed Area')
112     *
113     * @param Image_Graph_Dataset &$dataset  The data set (value containter) to
114     *   plot or an array of datasets
115     * @param string              $multiType The type of the plot
116     * @param string              $title     The title of the plot (used for legends,
117     *   {@link Image_Graph_Legend})
118     */
119    function Image_Graph_Plot(& $dataset, $multiType = 'normal', $title = '')
120    {
121        if (!is_a($dataset, 'Image_Graph_Dataset')) {
122            if (is_array($dataset)) {
123                $keys = array_keys($dataset);
124                foreach ($keys as $key) {
125                    if (!is_a($dataset[$key], 'Image_Graph_Dataset')) {
126                        $this->_error('Invalid dataset passed to ' . get_class($this));
127                    }
128                }
129                unset($keys);
130            } else {
131                $this->_error('Invalid dataset passed to ' . get_class($this));
132            }
133        }
134
135        parent::__construct();
136        if ($dataset) {
137            if (is_array($dataset)) {
138                $this->_dataset =& $dataset;
139            } else {
140                $this->_dataset = array(&$dataset);
141            }
142        }
143        if ($title) {
144            $this->_title = $title;
145        } else {
146            $this->_title = str_replace('_', ' ', substr(get_class($this), 17));
147        }
148
149        $multiType = strtolower($multiType);
150        if (($multiType == 'normal')
151            || ($multiType == 'stacked')
152            || ($multiType == 'stacked100pct')
153        ) {
154            $this->_multiType = $multiType;
155        } else {
156            $this->_error(
157                'Invalid multitype: ' . $multiType .
158                ' expected (normal|stacked|stacked100pct)'
159            );
160            $this->_multiType = 'normal';
161        }
162    }
163
164    /**
165     * Sets the title of the plot, used for legend
166     *
167     * @param string $title The title of the plot
168     *
169     * @return void
170     */
171    function setTitle($title)
172    {
173        $this->_title = $title;
174    }
175
176    /**
177     * Parses the URL mapping data in the point and adds it to the parameter array used by
178     * Image_Canvas
179     *
180     * @param array $point      The data point (from the dataset)
181     * @param array $canvasData The The for the canvas method
182     *
183     * @return array The union of the canvas data points and the appropriate points for the dataset
184     * @access private
185     */
186    function _mergeData($point, $canvasData)
187    {
188        if (isset($point['data'])) {
189            if (isset($point['data']['url'])) {
190                $canvasData['url'] = $point['data']['url'];
191            }
192            if (isset($point['data']['target'])) {
193                $canvasData['target'] = $point['data']['target'];
194            }
195            if (isset($point['data']['alt'])) {
196                $canvasData['alt'] = $point['data']['alt'];
197            }
198            if (isset($point['data']['htmltags'])) {
199                $canvasData['htmltags'] = $point['data']['htmltags'];
200            }
201        }
202
203        return $canvasData;
204    }
205
206    /**
207     * Sets the Y axis to plot the data
208     *
209     * @param int $axisY The Y axis (either IMAGE_GRAPH_AXIS_Y / 'y' or
210     *   IMAGE_GRAPH_AXIS_Y_SECONDARY / 'ysec' (defaults to IMAGE_GRAPH_AXIS_Y))
211     *
212     * @return void
213     * @access private
214     */
215    function _setAxisY($axisY)
216    {
217        if ($axisY == 'y') {
218            $this->_axisY = IMAGE_GRAPH_AXIS_Y;
219        } elseif ($axisY == 'ysec') {
220            $this->_axisY = IMAGE_GRAPH_AXIS_Y_SECONDARY;
221        } else {
222            $this->_axisY = $axisY;
223        }
224    }
225
226    /**
227     * Sets the marker to 'display' data points on the graph
228     *
229     * @param Marker &$marker The marker
230     *
231     * @return Marker
232     */
233    function &setMarker(& $marker)
234    {
235        $this->add($marker);
236        $this->_marker =& $marker;
237        return $marker;
238    }
239
240    /**
241     * Sets the dataselector to specify which data should be displayed on the
242     * plot as markers and which are not
243     *
244     * @param DataSelector &$dataSelector The dataselector
245     *
246     * @return void
247     */
248    function setDataSelector(& $dataSelector)
249    {
250        $this->_dataSelector =& $dataSelector;
251    }
252
253    /**
254     * Calculate marker point data
255     *
256     * @param array $point     The point to calculate data for
257     * @param array $nextPoint The next point
258     * @param array $prevPoint The previous point
259     * @param array &$totals   The pre-calculated totals, if needed
260     *
261     * @return array An array containing marker point data
262     * @access private
263     */
264    function _getMarkerData($point, $nextPoint, $prevPoint, & $totals)
265    {
266        if (is_array($this->_dataset)) {
267            if ($this->_multiType == 'stacked') {
268                if (!isset($totals['SUM_Y'])) {
269                    $totals['SUM_Y'] = array();
270                }
271                $x = $point['X'];
272                if (!isset($totals['SUM_Y'][$x])) {
273                    $totals['SUM_Y'][$x] = 0;
274                }
275            } elseif ($this->_multiType == 'stacked100pct') {
276                $x = $point['X'];
277                if ($totals['TOTAL_Y'][$x] != 0) {
278                    if (!isset($totals['SUM_Y'])) {
279                        $totals['SUM_Y'] = array();
280                    }
281                    if (!isset($totals['SUM_Y'][$x])) {
282                        $totals['SUM_Y'][$x] = 0;
283                    }
284                }
285            }
286
287            if (isset($totals['ALL_SUM_Y'])) {
288                $point['SUM_Y'] = $totals['ALL_SUM_Y'];
289            }
290
291            if (!$prevPoint) {
292                $point['AX'] = -5;
293                $point['AY'] = 5;
294                $point['PPX'] = 0;
295                $point['PPY'] = 0;
296                $point['NPX'] = $nextPoint['X'];
297                $point['NPY'] = $nextPoint['Y'];
298            } elseif (!$nextPoint) {
299                $point['AX'] = 5;
300                $point['AY'] = 5;
301                $point['PPX'] = $prevPoint['X'];
302                $point['PPY'] = $prevPoint['Y'];
303                $point['NPX'] = 0;
304                $point['NPY'] = 0;
305            } else {
306                $point['AX'] = $this->_pointY($prevPoint) - $this->_pointY($nextPoint);
307                $point['AY'] = $this->_pointX($nextPoint) - $this->_pointX($prevPoint);
308                $point['PPX'] = $prevPoint['X'];
309                $point['PPY'] = $prevPoint['Y'];
310                $point['NPX'] = $nextPoint['X'];
311                $point['NPY'] = $nextPoint['Y'];
312            }
313
314            $point['APX'] = $point['X'];
315            $point['APY'] = $point['Y'];
316
317            if ((isset($totals['MINIMUM_X'])) && ($totals['MINIMUM_X'] != 0)) {
318                $point['PCT_MIN_X'] = 100 * $point['X'] / $totals['MINIMUM_X'];
319            }
320            if ((isset($totals['MAXIMUM_X'])) && ($totals['MAXIMUM_X'] != 0)) {
321                $point['PCT_MAX_X'] = 100 * $point['X'] / $totals['MAXIMUM_X'];
322            }
323
324            if ((isset($totals['MINIMUM_Y'])) && ($totals['MINIMUM_Y'] != 0)) {
325                $point['PCT_MIN_Y'] = 100 * $point['Y'] / $totals['MINIMUM_Y'];
326            }
327            if ((isset($totals['MAXIMUM_Y'])) && ($totals['MAXIMUM_Y'] != 0)) {
328                $point['PCT_MAX_Y'] = 100 * $point['Y'] / $totals['MAXIMUM_Y'];
329            }
330
331            $point['LENGTH'] = sqrt(($point['AX'] * $point['AX']) + ($point['AY'] * $point['AY']));
332
333            if ((isset($point['LENGTH'])) && ($point['LENGTH'] != 0)) {
334                $point['ANGLE'] = asin($point['AY'] / $point['LENGTH']);
335            }
336
337            if ((isset($point['AX'])) && ($point['AX'] > 0)) {
338                $point['ANGLE'] = pi() - $point['ANGLE'];
339            }
340
341            if ($this->_parent->_horizontal) {
342                $point['MARKER_Y1'] = $this->_pointY($point) -
343                    (isset($totals['WIDTH']) ? $totals['WIDTH'] : 0);
344
345                $point['MARKER_Y2'] = $this->_pointY($point) +
346                    (isset($totals['WIDTH']) ? $totals['WIDTH'] : 0);
347
348                $point['COLUMN_WIDTH'] = abs(($point['MARKER_Y2'] - $point['MARKER_Y1']) / count($this->_dataset));
349
350                $point['MARKER_Y'] = $point['MARKER_Y1'] +
351                    ((isset($totals['NUMBER']) ? $totals['NUMBER'] : 0) + 0.5) *
352                    $point['COLUMN_WIDTH'];
353
354                $point['MARKER_X'] = $this->_pointX($point);
355
356                if ($this->_multiType == 'stacked') {
357                    $point['MARKER_Y'] = ($point['MARKER_Y1'] + $point['MARKER_Y2']) / 2;
358
359                    $P1 = array('Y' => $totals['SUM_Y'][$x]);
360                    $P2 = array('Y' => $totals['SUM_Y'][$x] + $point['Y']);
361
362                    $point['MARKER_X'] = ($this->_pointX($P1) + $this->_pointX($P2)) / 2;
363                } elseif ($this->_multiType == 'stacked100pct') {
364                    $x = $point['X'];
365                    if ($totals['TOTAL_Y'][$x] != 0) {
366                        $point['MARKER_Y'] = ($point['MARKER_Y1'] + $point['MARKER_Y2']) / 2;
367
368                        $P1 = array(
369                            'Y' => 100 * $totals['SUM_Y'][$x] / $totals['TOTAL_Y'][$x]
370                        );
371
372                        $P2 = array(
373                            'Y' => 100 * ($totals['SUM_Y'][$x] + $point['Y']) / $totals['TOTAL_Y'][$x]
374                        );
375
376                        $point['MARKER_X'] = ($this->_pointX($P1) + $this->_pointX($P2)) / 2;
377                    } else {
378                        $point = false;
379                    }
380                }
381            } else {
382                $point['MARKER_X1'] = $this->_pointX($point) - (isset($totals['WIDTH']) ? $totals['WIDTH'] : 0);
383
384                $point['MARKER_X2'] = $this->_pointX($point) + (isset($totals['WIDTH']) ? $totals['WIDTH'] : 0);
385
386                $point['COLUMN_WIDTH'] = abs(($point['MARKER_X2'] - $point['MARKER_X1']) / count($this->_dataset));
387
388                $point['MARKER_X'] = $point['MARKER_X1'] + ((isset($totals['NUMBER']) ? $totals['NUMBER'] : 0) + 0.5) * $point['COLUMN_WIDTH'];
389
390                $point['MARKER_Y'] = $this->_pointY($point);
391
392                if ($this->_multiType == 'stacked') {
393                    $point['MARKER_X'] = ($point['MARKER_X1'] + $point['MARKER_X2']) / 2;
394
395                    $P1 = array('Y' => $totals['SUM_Y'][$x]);
396                    $P2 = array('Y' => $totals['SUM_Y'][$x] + $point['Y']);
397
398                    $point['MARKER_Y'] = ($this->_pointY($P1) + $this->_pointY($P2)) / 2;
399                } elseif ($this->_multiType == 'stacked100pct') {
400                    $x = $point['X'];
401                    if ($totals['TOTAL_Y'][$x] != 0) {
402                        $point['MARKER_X'] = ($point['MARKER_X1'] + $point['MARKER_X2']) / 2;
403
404                        $P1 = array(
405                            'Y' => 100 * $totals['SUM_Y'][$x] / $totals['TOTAL_Y'][$x]
406                        );
407
408                        $P2 = array(
409                            'Y' => 100 * ($totals['SUM_Y'][$x] + $point['Y']) / $totals['TOTAL_Y'][$x]
410                        );
411
412                        $point['MARKER_Y'] = ($this->_pointY($P1) + $this->_pointY($P2)) / 2;
413                    } else {
414                        $point = false;
415                    }
416                }
417            }
418            return $point;
419        }
420    }
421
422    /**
423     * Draws markers on the canvas
424     *
425     * @return void
426     * @access private
427     */
428    function _drawMarker()
429    {
430        if (($this->_marker) && (is_array($this->_dataset))) {
431            $this->_canvas->startGroup(get_class($this) . '_marker');
432
433            $totals = $this->_getTotals();
434            $totals['WIDTH'] = $this->width() / ($this->_maximumX() + 2) / 2;
435
436            $number = 0;
437            $keys = array_keys($this->_dataset);
438            foreach ($keys as $key) {
439                $dataset =& $this->_dataset[$key];
440                $totals['MINIMUM_X'] = $dataset->minimumX();
441                $totals['MAXIMUM_X'] = $dataset->maximumX();
442                $totals['MINIMUM_Y'] = $dataset->minimumY();
443                $totals['MAXIMUM_Y'] = $dataset->maximumY();
444                $totals['NUMBER'] = $number ++;
445                $dataset->_reset();
446                while ($point = $dataset->_next()) {
447                    $prevPoint = $dataset->_nearby(-2);
448                    $nextPoint = $dataset->_nearby();
449
450                    $x = $point['X'];
451                    $y = $point['Y'];
452                    if (((!is_object($this->_dataSelector))
453                        || ($this->_dataSelector->_select($point))) && ($point['Y'] !== null)
454                    ) {
455
456                        $point = $this->_getMarkerData(
457                            $point,
458                            $nextPoint,
459                            $prevPoint,
460                            $totals
461                        );
462
463                        if (is_array($point)) {
464                            $this->_marker->_drawMarker(
465                                $point['MARKER_X'],
466                                $point['MARKER_Y'],
467                                $point
468                            );
469                        }
470                    }
471                    if (!isset($totals['SUM_Y'])) {
472                        $totals['SUM_Y'] = array();
473                    }
474                    if (isset($totals['SUM_Y'][$x])) {
475                        $totals['SUM_Y'][$x] += $y;
476                    } else {
477                        $totals['SUM_Y'][$x] = $y;
478                    }
479                }
480            }
481            unset($keys);
482            $this->_canvas->endGroup();
483        }
484    }
485
486    /**
487     * Get the minimum X value from the dataset
488     *
489     * @return double The minimum X value
490     * @access private
491     */
492    function _minimumX()
493    {
494        if (!is_array($this->_dataset)) {
495            return 0;
496        }
497
498        $min = false;
499        if (is_array($this->_dataset)) {
500            $keys = array_keys($this->_dataset);
501            foreach ($keys as $key) {
502                if ($min === false) {
503                    $min = $this->_dataset[$key]->minimumX();
504                } else {
505                    $min = min($min, $this->_dataset[$key]->minimumX());
506                }
507            }
508            unset($keys);
509        }
510        return $min;
511    }
512
513    /**
514     * Get the maximum X value from the dataset
515     *
516     * @return double The maximum X value
517     * @access private
518     */
519    function _maximumX()
520    {
521        if (!is_array($this->_dataset)) {
522            return 0;
523        }
524
525        $max = 0;
526        if (is_array($this->_dataset)) {
527            $keys = array_keys($this->_dataset);
528            foreach ($keys as $key) {
529                $max = max($max, $this->_dataset[$key]->maximumX());
530            }
531            unset($keys);
532        }
533        return $max;
534    }
535
536    /**
537     * Get the minimum Y value from the dataset
538     *
539     * @return double The minimum Y value
540     * @access private
541     */
542    function _minimumY()
543    {
544        if (!is_array($this->_dataset)) {
545            return 0;
546        }
547
548        $min = false;
549        if (is_array($this->_dataset)) {
550            $keys = array_keys($this->_dataset);
551            foreach ($keys as $key) {
552                if ($this->_multiType == 'normal') {
553                    if ($min === false) {
554                        $min = $this->_dataset[$key]->minimumY();
555                    } else {
556                        $min = min($min, $this->_dataset[$key]->minimumY());
557                    }
558                } else {
559                    if ($min === false) {
560                        $min = 0;
561                    }
562                    $dataset =& $this->_dataset[$key];
563                    $dataset->_reset();
564                    while ($point = $dataset->_next()) {
565                        if ($point['Y'] < 0) {
566                            $x = $point['X'];
567                            if ((!isset($total)) || (!isset($total[$x]))) {
568                                $total[$x] = $point['Y'];
569                            } else {
570                                $total[$x] += $point['Y'];
571                            }
572                            if (isset($min)) {
573                                $min = min($min, $total[$x]);
574                            } else {
575                                $min = $total[$x];
576                            }
577                        }
578                    }
579                }
580            }
581            unset($keys);
582        }
583        return $min;
584    }
585
586    /**
587     * Get the maximum Y value from the dataset
588     *
589     * @return double The maximum Y value
590     * @access private
591     */
592    function _maximumY()
593    {
594        if ($this->_multiType == 'stacked100pct') {
595            return 100;
596        }
597
598        $maxY = 0;
599        if (is_array($this->_dataset)) {
600            $keys = array_keys($this->_dataset);
601            foreach ($keys as $key) {
602                $dataset =& $this->_dataset[$key];
603
604                if ($this->_multiType == 'normal') {
605                    if (isset($maxY)) {
606                        $maxY = max($maxY, $dataset->maximumY());
607                    } else {
608                        $maxY = $dataset->maximumY();
609                    }
610                } else {
611                    $dataset->_reset();
612                    while ($point = $dataset->_next()) {
613                        if ($point['Y'] > 0) {
614                            $x = $point['X'];
615                            if ((!isset($total)) || (!isset($total[$x]))) {
616                                $total[$x] = $point['Y'];
617                            } else {
618                                $total[$x] += $point['Y'];
619                            }
620                            if (isset($maxY)) {
621                                $maxY = max($maxY, $total[$x]);
622                            } else {
623                                $maxY = $total[$x];
624                            }
625                        }
626                    }
627                }
628            }
629            unset($keys);
630        }
631        return $maxY;
632    }
633
634    /**
635     * Get the X pixel position represented by a value
636     *
637     * @param double $point The value to get the pixel-point for
638     *
639     * @return double The pixel position along the axis
640     * @access private
641     */
642    function _pointX($point)
643    {
644        $point['AXIS_Y'] = $this->_axisY;
645        return parent::_pointX($point);
646    }
647
648    /**
649     * Get the Y pixel position represented by a value
650     *
651     * @param double $point the value to get the pixel-point for
652     *
653     * @return double The pixel position along the axis
654     * @access private
655     */
656    function _pointY($point)
657    {
658        $point['AXIS_Y'] = $this->_axisY;
659        return parent::_pointY($point);
660    }
661
662    /**
663     * Update coordinates
664     *
665     * @return void
666     * @access private
667     */
668    function _updateCoords()
669    {
670        $this->_setCoords($this->_parent->_plotLeft, $this->_parent->_plotTop, $this->_parent->_plotRight, $this->_parent->_plotBottom);
671        parent::_updateCoords();
672    }
673
674    /**
675     * Get the dataset
676     *
677     * @return Image_Graph_Dataset The dataset(s)
678     */
679    function &dataset()
680    {
681        return $this->_dataset;
682    }
683
684    /**
685     * Calulate totals
686     *
687     * @return array An associated array with the totals
688     * @access private
689     */
690    function _getTotals()
691    {
692        $total = array(
693            'MINIMUM_X' => $this->_minimumX(),
694            'MAXIMUM_X' => $this->_maximumX(),
695            'MINIMUM_Y' => $this->_minimumY(),
696            'MAXIMUM_Y' => $this->_maximumY()
697        );
698        $total['ALL_SUM_Y'] = 0;
699
700        $keys = array_keys($this->_dataset);
701        foreach ($keys as $key) {
702            $dataset =& $this->_dataset[$key];
703
704            $dataset->_reset();
705            while ($point = $dataset->_next()) {
706                $x = $point['X'];
707
708                if (is_numeric($point['Y'])) {
709                    $total['ALL_SUM_Y'] += $point['Y'];
710                    if (isset($total['TOTAL_Y'][$x])) {
711                        $total['TOTAL_Y'][$x] += $point['Y'];
712                    } else {
713                        $total['TOTAL_Y'][$x] = $point['Y'];
714                    }
715                }
716
717                if (is_numeric($point['X'])) {
718                    if (isset($total['TOTAL_X'][$x])) {
719                        $total['TOTAL_X'][$x] += $point['X'];
720                    } else {
721                        $total['TOTAL_X'][$x] = $point['X'];
722                    }
723                }
724            }
725        }
726        unset($keys);
727        return $total;
728    }
729
730    /**
731     * Perform the actual drawing on the legend.
732     *
733     * @param int $x0 The top-left x-coordinate
734     * @param int $y0 The top-left y-coordinate
735     * @param int $x1 The bottom-right x-coordinate
736     * @param int $y1 The bottom-right y-coordinate
737     *
738     * @return void
739     * @access private
740     */
741    function _drawLegendSample($x0, $y0, $x1, $y1)
742    {
743        $this->_canvas->rectangle(array('x0' => $x0, 'y0' => $y0, 'x1' => $x1, 'y1' => $y1));
744    }
745
746    /**
747     * Draw a sample for use with legend
748     *
749     * @param array &$param The parameters for the legend
750     *
751     * @return void
752     * @access private
753     */
754    function _legendSample(&$param)
755    {
756        if (!is_array($this->_dataset)) {
757            return false;
758        }
759
760        if (is_a($this->_fillStyle, 'Image_Graph_Fill')) {
761            $this->_fillStyle->_reset();
762        }
763
764        $count = 0;
765        $keys = array_keys($this->_dataset);
766        foreach ($keys as $key) {
767            $dataset =& $this->_dataset[$key];
768            $count++;
769
770            $caption = ($dataset->_name ? $dataset->_name : $this->_title);
771
772            $this->_canvas->setFont($param['font']);
773            $width = 20 + $param['width'] + $this->_canvas->textWidth($caption);
774            $param['maxwidth'] = max($param['maxwidth'], $width);
775            $x2 = $param['x'] + $width;
776            $y2 = $param['y'] + $param['height'] + 5;
777
778            if ((($param['align'] & IMAGE_GRAPH_ALIGN_VERTICAL) != 0) && ($y2 > $param['bottom'])) {
779                $param['y'] = $param['top'];
780                $param['x'] = $x2;
781                $y2 = $param['y'] + $param['height'];
782            } elseif ((($param['align'] & IMAGE_GRAPH_ALIGN_VERTICAL) == 0) && ($x2 > $param['right'])) {
783                $param['x'] = $param['left'];
784                $param['y'] = $y2;
785                $x2 = $param['x'] + 20 + $param['width'] + $this->_canvas->textWidth($caption);
786            }
787
788            $x = $x0 = $param['x'];
789            $y = $param['y'];
790            $y0 = $param['y'];
791            $x1 = $param['x'] + $param['width'];
792            $y1 = $param['y'] + $param['height'];
793
794            if (!isset($param['simulate'])) {
795                $this->_getFillStyle($key);
796                $this->_getLineStyle();
797                $this->_drawLegendSample($x0, $y0, $x1, $y1);
798
799                if (($this->_marker) && ($dataset) && ($param['show_marker'])) {
800                    $dataset->_reset();
801                    $point = $dataset->_next();
802                    $prevPoint = $dataset->_nearby(-2);
803                    $nextPoint = $dataset->_nearby();
804
805                    $tmp = array();
806                    $point = $this->_getMarkerData($point, $nextPoint, $prevPoint, $tmp);
807                    if (is_array($point)) {
808                        $point['MARKER_X'] = $x+$param['width']/2;
809                        $point['MARKER_Y'] = $y;
810                        unset ($point['AVERAGE_Y']);
811                        $this->_marker->_drawMarker($point['MARKER_X'], $point['MARKER_Y'], $point);
812                    }
813                }
814                $this->write($x + $param['width'] + 10, $y + $param['height'] / 2, $caption, IMAGE_GRAPH_ALIGN_CENTER_Y | IMAGE_GRAPH_ALIGN_LEFT, $param['font']);
815            }
816
817            if (($param['align'] & IMAGE_GRAPH_ALIGN_VERTICAL) != 0) {
818                $param['y'] = $y2;
819            } else {
820                $param['x'] = $x2;
821            }
822        }
823        unset($keys);
824    }
825
826}
827
828?>
829