]> git.mxchange.org Git - friendica-addons.git/blob - jappixmini/jappix/php/drawsvgchart.php
default features - actually handle the security token in the addon code
[friendica-addons.git] / jappixmini / jappix / php / drawsvgchart.php
1 <?php
2
3 //   Extracted from CodingTeam for the Jappix project.
4
5 //   This file is a part of CodingTeam. Take a look at <http://codingteam.org>.
6 //   Copyright © 2007-2010 Erwan Briand <erwan@codingteam.net>
7 //
8 //   This program is free software: you can redistribute it and/or modify it
9 //   under the terms of the GNU Affero General Public License as published by
10 //   the Free Software Foundation, version 3 only.
11 //
12 //   This program is distributed in the hope that it will be useful, but
13 //   WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 //   or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
15 //   License for more details.
16 //
17 //   You should have received a copy of the GNU Affero General Public License
18 //   along with this program. If not, see <http://www.gnu.org/licenses/>.
19
20 /**
21  * @file
22  * This file contains the DrawSVGChart class.
23  */
24
25 /**
26  * DrawSVGChart class
27  */
28 class DrawSVGChart {
29     private $datas, $legend, $link, $xml_object, $svg,
30             $xml_elements, $evolution;
31     public $has_errors;
32
33     function createChart($datas=array(), $legend=array(), $link,
34                          $evolution=FALSE, $type='others')
35     {
36         $this->has_errors = FALSE;
37         $max = 0;
38
39         // One or two data arrays
40         if (isset($datas[0]) && is_array($datas[0]))
41         {
42             $datas_number = count($datas[0]);
43
44             if ($datas_number >= 1)
45                 $max = max($datas[0]);
46             else
47                 $this->has_errors = TRUE;
48         }
49         else
50         {
51             $datas_number = count($datas);
52
53             if ($datas_number >= 1)
54                 $max = max($datas);
55             else
56                 $this->has_errors = TRUE;
57         }
58
59         // Set the width of the chart
60         if ($datas_number * 55 > 400)
61             $width = $datas_number * 55;
62         else
63             $width = 400;
64
65         $height = 250;
66         $this->datas = $datas;
67         $this->legend = $legend;
68         $this->link = $link;
69         $this->evolution = $evolution;
70         $this->type = $type;
71         $this->xml_elements = array();
72
73         // Scale
74         if ($max <= 20)
75         {
76             $scale[4] = 20;
77             $scale[3] = 15;
78             $scale[2] = 10;
79             $scale[1] = 5;
80         }
81         else
82         {
83             $scale[4] = ceil($max / 20) * 20;
84             $scale[3] = $scale[4] * 3/4;
85             $scale[2] = $scale[4] * 2/4;
86             $scale[1] = $scale[4] * 1/4;
87         }
88
89         if ($scale[4] == 0 || $max == 0)
90             $this->has_errors = TRUE;
91
92         if ($this->has_errors)
93             return TRUE;
94
95         $this->xml_object = new DOMDocument('1.0', 'utf-8');
96         
97         // Process the static file host prefix
98         $static_prefix = '.';
99         
100         if(hasStatic())
101                 $static_prefix = HOST_STATIC.'/php';
102         
103         // Add the stylesheet
104         $style = $this->xml_object->createProcessingInstruction("xml-stylesheet",
105                  "type='text/css' href='".getFiles(genHash(getVersion()), '', 'css', '', 'stats-svg.css')."'");
106         $this->xml_object->appendChild($style);
107
108         // Create the root SVG element
109         $this->svg = $this->xml_object->createElement('svg');
110         $this->svg->setAttribute('xmlns:svg', 'http://www.w3.org/2000/svg');
111         $this->svg->setAttribute('xmlns', 'http://www.w3.org/2000/svg');
112         $this->svg->setAttribute('xmlns:xlink', 'http://www.w3.org/1999/xlink');
113         $this->svg->setAttribute('version', '1.1');
114         $this->svg->setAttribute('width', $width);
115         $this->svg->setAttribute('height', $height);
116         $this->svg->setAttribute('id', 'svg');
117         $this->xml_object->appendChild($this->svg);
118
119         // Create a definition
120         $this->xml_elements['basic_defs'] = $this->xml_object->createElement('defs');
121         $path = $this->xml_object->createElement('path');
122         $path->setAttribute('id', 'mark');
123         $path->setAttribute('d', 'M 0,234 v 4 ');
124         $path->setAttribute('stroke', '#596171');
125         $path->setAttribute('stroke-width', '2px');
126         $this->xml_elements['basic_defs']->appendChild($path);
127
128         // Create the static background
129         $this->xml_elements['static_background'] = $this->xml_object->createElement('g');
130         $this->xml_elements['static_background']->setAttribute('class', 'static-background');
131
132         // Draw the legend
133         $this->drawLegend();
134
135         // Draw the table
136         $this->drawTable($scale, $width);
137
138         // Draw the chart
139         $this->drawChart($scale, $width);
140     }
141
142     function drawLegend()
143     {
144         $pstart = 3;
145         $tstart = 7;
146
147         foreach ($this->legend as $item)
148         {
149             $val_path = $pstart + 11;
150             $val_text = $tstart + 10;
151
152             // Create the legend line
153             $path = $this->xml_object->createElement('path');
154             $path->setAttribute('d', 'M 40, '.$val_path.' L 55, '.$val_path);
155             $path->setAttribute('id', 'legendline');
156             $path->setAttribute('stroke', $item[0]);
157             $path->setAttribute('stroke-width', '2px');
158
159             // Create the legend text
160             $text = $this->xml_object->createElement('text', $item[1]);
161             $text->setAttribute('x', 57);
162             $text->setAttribute('y', $val_text);
163             $text->setAttribute('text-anchor', 'start');
164             $text->setAttribute('id', 'reftext');
165             $text->setAttribute('fill', $item[0]);
166             $text->setAttribute('font-size', '11px');
167             $text->setAttribute('font-family', "'DejaVu sans', Verdana, sans-serif");
168
169             // Append elemets
170             $this->xml_elements['static_background']->appendChild($path);
171             $this->xml_elements['static_background']->appendChild($text);
172
173             $pstart = $val_path;
174             $tstart = $val_text;
175         }
176     }
177
178     function drawTable($scale, $width)
179     {
180         // Create left scale
181         $top = TRUE;
182         $start = -17;
183
184         foreach ($scale as $level)
185         {
186             $type = $this->type;
187             
188             if(($type == 'share') || ($type == 'others'))
189                 $level = formatBytes($level);
190             
191             if ($top)
192                 $color = '#CED0D5';
193             else
194                 $color = '#EAEAEA';
195
196             $m = $start + 50;
197
198             $path = $this->xml_object->createElement('path');
199             $path->setAttribute('d', 'M 38, '.$m.' L '.$width.', '.$m);
200             $path->setAttribute('stroke', $color);
201             $path->setAttribute('stroke-width', '1px');
202
203             $text = $this->xml_object->createElement('text', $level);
204             $text->setAttribute('x', 34);
205             $text->setAttribute('y', ($m + 3));
206             $text->setAttribute('text-anchor', 'end');
207             $text->setAttribute('class', 'refleft');
208
209             $this->xml_elements['static_background']->appendChild($path);
210             $this->xml_elements['static_background']->appendChild($text);
211
212             $top = FALSE;
213             $start = $m;
214         }
215
216         // Add zero
217         $text = $this->xml_object->createElement('text', 0);
218         $text->setAttribute('x', 34);
219         $text->setAttribute('y', 236);
220         $text->setAttribute('text-anchor', 'end');
221         $text->setAttribute('class', 'refleft');
222
223         $this->xml_elements['static_background']->appendChild($text);
224     }
225
226     function drawChart($scale, $width)
227     {
228         if (isset($this->datas[0]) && is_array($this->datas[0]))
229         {
230             $foreached_datas = $this->datas[0];
231             $onlykeys_datas = array_keys($this->datas[0]);
232             $secondary_datas = array_keys($this->datas[1]);
233         }
234         else
235         {
236             $foreached_datas = $this->datas;
237             $onlykeys_datas = array_keys($this->datas);
238             $secondary_datas = FALSE;
239         }
240
241         // Create graphics data
242         $defs = $this->xml_object->createElement('defs');
243
244         $rect = $this->xml_object->createElement('rect');
245         $rect->setAttribute('id', 'focusbar');
246         $rect->setAttribute('width', 14);
247         $rect->setAttribute('height', 211);
248         $rect->setAttribute('x', -20);
249         $rect->setAttribute('y', 34);
250         $rect->setAttribute('style', 'fill: black; opacity: 0;');
251         $defs->appendChild($rect);
252
253         $path = $this->xml_object->createElement('path');
254         $path->setAttribute('id', 'bubble');
255
256         if ($this->evolution)
257             $path->setAttribute('d', 'M 4.7871575,0.5 L 39.084404,0.5 C 41.459488,0.5 43.371561,2.73 43.371561,5.5 L 43.371561,25.49999 L 43.30,31.05 L 4.7871575,30.49999 C 2.412072,30.49999 0.5,28.26999 0.5,25.49999 L 0.5,5.5 C 0.5,2.73 2.412072,0.5 4.7871575,0.5 z');
258         elseif ($secondary_datas)
259             $path->setAttribute('d', 'M 1,0 v 8 l -6,-10 c -1.5,-2 -1.5,-2 -6,-2 h -36                        c -3,0 -6,-3 -6,-6 v -28 c 0,-3 3,-6 6,-6 h 43 c 3,0 6,3 6,6 z');
260         else
261             $path->setAttribute('d', 'M 4.7871575,0.5 L 39.084404,0.5 C 41.459488,0.5 43.371561,2.73 43.371561,5.5 L 43.371561,25.49999 C 43.371561,27.07677 43.83887,41.00777 42.990767,40.95796 C 42.137828,40.90787 37.97451,30.49999 36.951406,30.49999 L 4.7871575,30.49999 C 2.412072,30.49999 0.5,28.26999 0.5,25.49999 L 0.5,5.5 C 0.5,2.73 2.412072,0.5 4.7871575,0.5 z');
262
263         $path->setAttribute('fill', 'none');
264         $path->setAttribute('fill-opacity', '0.85');
265         $path->setAttribute('pointer-events', 'none');
266         $path->setAttribute('stroke-linejoin', 'round');
267         $path->setAttribute('stroke', 'none');
268         $path->setAttribute('stroke-opacity', '0.8');
269         $path->setAttribute('stroke-width', '1px');
270         $defs->appendChild($path);
271
272         $rect = $this->xml_object->createElement('rect');
273         $rect->setAttribute('id', 'graphicbar');
274         $rect->setAttribute('width', '12');
275         $rect->setAttribute('height', '200');
276         $rect->setAttribute('rx', '2');
277         $rect->setAttribute('ry', '1');
278         $rect->setAttribute('fill', '#6C84C0');
279         $rect->setAttribute('fill-opacity', '0.6');
280         $rect->setAttribute('stroke', '#5276A9');
281         $rect->setAttribute('stroke-width', '1px');
282         $defs->appendChild($rect);
283
284         $rect = $this->xml_object->createElement('rect');
285         $rect->setAttribute('style', 'fill:#8B2323');
286         $rect->setAttribute('id', 'rectpoint');
287         $rect->setAttribute('width', 4);
288         $rect->setAttribute('height', 4);
289         $defs->appendChild($rect);
290
291         $this->xml_elements['chart_defs'] = $defs;
292         $global_g = $this->xml_object->createElement('g');
293
294         // Calc
295         $x_base = 35;
296         $y_base = 20;
297         $start = 18;
298         $element = 0;
299
300         $chart_defs = '';
301         $xprevious = 38;
302         $tprevious = 233;
303
304         foreach ($foreached_datas as $key => $data)
305         {
306             $x = 27 + $x_base;
307             $y = 107 + $y_base;
308
309             $top = 233 - ceil($data / ($scale[4] / 100) * 2);
310
311             if ($top <= 50)
312                 $bubble_top = 55;
313             elseif (!$secondary_datas)
314                 $bubble_top = ($top - 42);
315             elseif ($secondary_datas)
316                 $bubble_top = ($top - 10);
317
318             $type = $this->type;
319
320             if(($type == 'share') || ($type == 'others'))
321                 $value = formatBytes($data);
322             else
323                 $value = $data;
324             
325             // Create the chart with datas
326             $g = $this->xml_object->createElement('g');
327             $g->setAttribute('transform', 'translate('.$x.')');
328
329             $duse = $this->xml_object->createElement('use');
330             $duse->setAttribute('xlink:href', '#mark');
331             $duse->setAttribute('xmlns:xlink', 'http://www.w3.org/1999/xlink');
332             $g->appendChild($duse);
333
334             $data_g = $this->xml_object->createElement('g');
335             $data_g->setAttribute('class', 'gbar');
336
337             if ($this->link)
338             {
339                 $text = $this->xml_object->createElement('text');            
340
341                 $link = $this->xml_object->createElement('a', mb_substr(filterSpecialXML($onlykeys_datas[$element]), 0, 7));
342                 $link->setAttribute('xlink:href', str_replace('{data}', filterSpecialXML($onlykeys_datas[$element]), $this->link));
343                 $link->setAttribute('target', '_main');
344                 $text->appendChild($link);
345             }
346             else
347                 $text = $this->xml_object->createElement('text', mb_substr(filterSpecialXML($onlykeys_datas[$element]), 0, 7));
348
349             $text->setAttribute('class', 'reftext');
350             $text->setAttribute('y', 248);
351             $text->setAttribute('text-anchor', 'middle');
352
353             $data_g->appendChild($text);
354
355             $uselink = $this->xml_object->createElement('use');
356             $uselink->setAttribute('xlink:href', '#focusbar');
357             $uselink->setAttribute('xmlns:xlink', 'http://www.w3.org/1999/xlink');
358             $data_g->appendChild($uselink);
359
360             if (!$this->evolution)
361             {
362                 $rect = $this->xml_object->createElement('rect');
363                 $rect->setAttribute('class', 'bluebar');
364                 $rect->setAttribute('height', (233 - $top));
365                 $rect->setAttribute('width', 13);
366                 $rect->setAttribute('x', -6);
367                 $rect->setAttribute('y', $top);
368                 $rect->setAttribute('fill', $this->legend[0][0]);
369                 $rect->setAttribute('fill-opacity', '0.6');
370                 $data_g->appendChild($rect);
371             }
372             else
373             {
374                 $use = $this->xml_object->createElement('use');
375                 $use->setAttribute('xlink:href', '#rectpoint');
376                 $use->setAttribute('y', ($top - 1));
377                 $use->setAttribute('x', -2);
378                 $data_g->appendChild($use);
379
380                 if ($x != (35 + 27))
381                     $chart_defs .= 'L '.$x.' '.$top.'  ';
382                 else
383                     $chart_defs .= 'M '.$xprevious.' '.$tprevious.' L '.$x.' '.$top.'  ';
384
385                 $xprevious = $x;
386                 $tprevious = $top;
387             }
388
389             if ($secondary_datas && isset($secondary_datas[$element]))
390             {
391                 $datalink = $secondary_datas[$element];
392                 $dataval = $this->datas[1][$datalink];
393                 $stop = 233 - ceil($dataval / ($scale[4] / 100) * 2);
394
395                 $rect = $this->xml_object->createElement('rect');
396                 $rect->setAttribute('class', 'redbar');
397                 $rect->setAttribute('height', (233 - $stop));
398                 $rect->setAttribute('width', 13);
399                 $rect->setAttribute('x', -6);
400                 $rect->setAttribute('y', $stop);
401                 $rect->setAttribute('fill', $this->legend[1][0]);
402                 $rect->setAttribute('fill-opacity', '0.7');
403                 $data_g->appendChild($rect);
404             }
405
406             if (!$this->evolution)
407             {
408                 $path = $this->xml_object->createElement('path');
409                 $path->setAttribute('stroke', '#5276A9');
410                 $path->setAttribute('stroke-width', '2px');
411                 $path->setAttribute('fill', 'none');
412                 $path->setAttribute('d', 'M -7,233 v -'.(232 - $top).' c 0,-1 1,-1 1,-1 h 12 c 1,0 2,0 2,1 v '.(232 - $top).' z');
413                 $data_g->appendChild($path);
414             }
415
416             $uselink = $this->xml_object->createElement('use');
417             $uselink->setAttribute('xmlns:xlink', 'http://www.w3.org/1999/xlink');
418             $uselink->setAttribute('xlink:href', '#bubble');
419             $uselink->setAttribute('y', $bubble_top);
420
421             if (!$secondary_datas)
422                 $uselink->setAttribute('x', -42);
423
424             $data_g->appendChild($uselink);
425
426             $text = $this->xml_object->createElement('text', $value);
427             $text->setAttribute('class', 'bubbletextblue');
428             $text->setAttribute('x', -10);
429
430             if (!$secondary_datas)
431                 $text->setAttribute('y', ($bubble_top + 20));
432             else
433                 $text->setAttribute('y', ($bubble_top - 27));
434
435             $text->setAttribute('fill', 'none');
436             $data_g->appendChild($text);
437
438             if ($secondary_datas && isset($secondary_datas[$element]))
439             {
440                 $text = $this->xml_object->createElement('text', $dataval);
441                 $text->setAttribute('class', 'bubbletextred');
442                 $text->setAttribute('x', -10);
443                 $text->setAttribute('y', ($bubble_top - 11));
444                 $text->setAttribute('fill', 'none');
445                 $data_g->appendChild($text);
446             }
447
448             $g->appendChild($data_g);
449             $global_g->appendChild($g);
450
451             $x_base = $x_base + 50;
452             $y_base = $y_base + 20;
453             $element ++;            
454         }
455
456         if ($this->evolution)
457         {
458             $path = $this->xml_object->createElement('path');
459             $path->setAttribute('d', $chart_defs);
460             $path->setAttribute('stroke', $this->legend[0][0]);
461             $path->setAttribute('stroke-width', '1px');
462             $path->setAttribute('fill', 'none');
463             $this->xml_elements['evolution_path'] = $path;
464         }
465
466         $this->xml_elements['global_g'] = $global_g;
467
468         $path = $this->xml_object->createElement('path');
469         $path->setAttribute('d', 'M 38,233 h '.$width);
470         $path->setAttribute('stroke', '#2F4F77');
471         $path->setAttribute('stroke-width', '2px');
472         $path->setAttribute('pointer-events', 'none');
473         $this->xml_elements['final_path'] = $path;
474     }
475
476     function has_errors()
477     {
478         return $this->has_errors;
479     }
480
481     function getXMLOutput()
482     {
483         if (isset($this->xml_object))
484         {
485             // Add SVG elements to the DOM object
486             foreach($this->xml_elements as $element)
487                 $this->svg->appendChild($element);
488
489             // Return the XML
490             $this->xml_object->formatOutput = true; 
491             return $this->xml_object->saveXML();
492         }
493     }
494 }
495 ?>