Ajout : ./garradin
[garradin.git] / include / libs / svgplot / lib.svgplot.php
1 <?php
2
3 class SVGPlot
4 {
5 protected $width = null;
6 protected $height = null;
7 protected $data = array();
8 protected $title = null;
9 protected $labels = array();
10 protected $legend = true;
11
12 public function __construct($width = 600, $height = 400)
13 {
14 $this->width = (int) $width;
15 $this->height = (int) $height;
16 }
17
18 public function setTitle($title)
19 {
20 $this->title = $title;
21 return true;
22 }
23
24 public function toggleLegend()
25 {
26 $this->legend = !$this->legend;
27 }
28
29 public function setLabels($labels)
30 {
31 $this->labels = $labels;
32 return true;
33 }
34
35 public function add(SVGPlot_Data $data)
36 {
37 $this->data[] = $data;
38 return true;
39 }
40
41 public function display()
42 {
43 header('Content-Type: image/svg+xml');
44 echo $this->output();
45 }
46
47 public function output()
48 {
49 $out = '<?xml version="1.0" encoding="utf-8" standalone="no"?>' . PHP_EOL;
50 $out.= '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/SVG/DTD/svg10.dtd">' . PHP_EOL;
51 $out.= '<svg width="'.$this->width.'" height="'.$this->height.'" viewBox="0 0 '.$this->width.' '.$this->height.'" xmlns="http://www.w3.org/2000/svg" version="1.1">' . PHP_EOL;
52
53 if ($this->title)
54 {
55 $out .= '<text x="'.round($this->width/2).'" y="'.($this->height * 0.07).'" font-size="'.($this->height * 0.05).'" fill="white" '
56 . 'stroke="white" stroke-width="'.($this->height * 0.01).'" stroke-linejoin="round" stroke-linecap="round" '
57 . 'text-anchor="middle" style="font-family: Verdana, Arial, sans-serif; font-weight: bold;">'.$this->title.'</text>' . PHP_EOL;
58 $out .= '<text x="'.round($this->width/2).'" y="'.($this->height * 0.07).'" font-size="'.($this->height * 0.05).'" fill="black" '
59 . 'text-anchor="middle" style="font-family: Verdana, Arial, sans-serif; font-weight: bold;">'.$this->title.'</text>' . PHP_EOL;
60 }
61
62 $out .= $this->_renderLinegraph();
63
64 if ($this->legend)
65 {
66 $x = $this->width - ($this->width * 0.06);
67 $y = $this->height * 0.1;
68
69 foreach ($this->data as $row)
70 {
71 $out .= '<rect x="'.$x.'" y="'.($y - $this->height * 0.01).'" width="'.($this->width * 0.04).'" height="'.($this->height * 0.04).'" fill="'.$row->color.'" stroke="black" stroke-width="1" rx="2" />' . PHP_EOL;
72
73 if ($row->title)
74 {
75 $out .= '<text x="'.($x-($this->width * 0.02)).'" y="'.($y+($this->height * 0.025)).'" '
76 . 'font-size="'.($this->height * 0.05).'" fill="white" stroke="white" '
77 . 'stroke-width="'.($this->height * 0.01).'" stroke-linejoin="round" '
78 . 'stroke-linecap="round" text-anchor="end" style="font-family: Verdana, Arial, '
79 . 'sans-serif;">'.$row->title.'</text>' . PHP_EOL;
80 $out .= '<text x="'.($x-($this->width * 0.02)).'" y="'.($y+($this->height * 0.025)).'" '
81 . 'font-size="'.($this->height * 0.05).'" fill="black" text-anchor="end" '
82 . 'style="font-family: Verdana, Arial, sans-serif;">'.$row->title.'</text>' . PHP_EOL;
83 }
84
85 $y += ($this->height * 0.07);
86 }
87 }
88
89 $out .= '</svg>';
90
91 return $out;
92 }
93
94 protected function _renderLinegraph()
95 {
96 $out = '';
97
98 if (empty($this->data))
99 {
100 return $out;
101 }
102
103 // Figure out the maximum Y-axis value
104 $max_value = 0;
105 $nb_elements = 0;
106
107 foreach ($this->data as $row)
108 {
109 if ($max_value == 0)
110 {
111 $nb_elements = count($row->get());
112 }
113
114 $max = max($row->get());
115
116 if ($max > $max_value)
117 {
118 $max_value = $max;
119 }
120 }
121
122 if ($nb_elements < 1)
123 {
124 return $out;
125 }
126
127 $divide = round($max_value / ($this->height * 0.8), 2) ?: 1;
128 $y_axis_val = ceil(abs($max_value) / ($this->height * 0.8)) * 50;
129 $space = round(($this->width - ($this->width * 0.1)) / $nb_elements, 2);
130
131 for ($i = 0; $i < 10; $i++)
132 {
133 if (($y_axis_val * $i) <= $max_value)
134 {
135 $line_y = ($this->height * 0.93) - (($y_axis_val / $divide) * $i);
136 $out .= '<line x1="'.($this->width * 0.1).'" y1="'.($line_y).'" x2="'.$this->width.'" y2="'.($line_y).'" stroke-width="1" stroke="#ccc" />' . PHP_EOL;
137 $out .= '<g><text x="'.($this->width * 0.08).'" y="'.($line_y).'" font-size="'.($this->height * 0.04).'" fill="gray" text-anchor="end" style="font-family: Verdana, Arial, sans-serif;">'.($y_axis_val * $i).'</text></g>' . PHP_EOL;
138 }
139 }
140
141 // X-axis lines
142 $y = $this->height - ($this->height * 0.07);
143 $x = $this->width * 0.1;
144 $i = 0;
145
146 foreach ($this->data[0]->get() as $k=>$v)
147 {
148 if ($x >= $this->width)
149 break;
150
151 $out .= '<line x1="'.$x.'" y1="'.($y).'" x2="'.$x.'" y2="'.($this->height * 0.1).'" stroke-width="1" stroke="#ccc" />' . PHP_EOL;
152 $x += $space + $this->data[0]->width;
153 }
154
155 // labels for x axis
156 $y = $this->height - ($this->height * 0.07);
157 $i = 0;
158 $step = round($nb_elements / 5);
159
160 for ($i = 0; $i <= $nb_elements; $i += $step)
161 {
162 //echo
163 $x = ($i * ($space + $this->data[0]->width)) + ($this->width * 0.1);
164
165 if ($x >= $this->width)
166 break;
167
168 if (isset($this->labels[$i]))
169 {
170 $out .= '<g><text x="'.$x.'" y="'.($y+($this->height * 0.06)).'" '
171 . 'font-size="'.($this->height * 0.04).'" fill="gray" text-anchor="middle" '
172 . 'style="font-family: Verdana, Arial, sans-serif;">'
173 . ($this->labels[$i]).'</text></g>' . PHP_EOL;
174 }
175 }
176
177 $y = ($this->height * 0.1);
178 $w = $this->width - ($this->width * 0.1);
179 $h = $this->height - ($this->height * 0.17);
180
181 foreach ($this->data as $row)
182 {
183 $out .= '<polyline fill="none" stroke="'.$row->color.'" stroke-width="'.$row->width.'" '
184 .'stroke-linecap="round" points="';
185
186 $x = ($this->width * 0.1);
187
188 foreach ($row->get() as $k=>$v)
189 {
190 $_y = $y + ($h - round($v / $divide, 2)) + round($row->width / 2);
191 $out.= $x.','.$_y.' ';
192 $x += $space + $row->width;
193 }
194
195 $out .= '" />' . PHP_EOL;
196 }
197
198 return $out;
199 }
200 }
201
202 class SVGPlot_Data
203 {
204 public $color = 'blue';
205 public $width = '10';
206 public $title = null;
207 protected $data = array();
208
209 public function __construct($data)
210 {
211 if (is_array($data))
212 $this->data = $data;
213 elseif (!is_object($data))
214 $this->append($data);
215 }
216
217 public function append($data)
218 {
219 $this->data[] = $data;
220 return true;
221 }
222
223 public function get()
224 {
225 return $this->data;
226 }
227 }
228
229 ?>