dolibarr 21.0.0-alpha
dolgraph.class.php
Go to the documentation of this file.
1<?php
2/* Copyright (c) 2003-2006 Rodolphe Quiedeville <rodolphe@quiedeville.org>
3 * Copyright (c) 2004-2015 Laurent Destailleur <eldy@users.sourceforge.net>
4 * Copyright (C) 2024 MDW <mdeweerd@users.noreply.github.com>
5 * Copyright (C) 2024 Frédéric France <frederic.france@free.fr>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <https://www.gnu.org/licenses/>.
19 */
20
43{
44 public $type = array(); // Array with type of each series. Example: array('bars', 'horizontalbars', 'lines', 'pies', 'piesemicircle', 'polar'...)
45 public $mode = 'side'; // Mode bars graph: side, depth
46 private $_library; // Graphic library to use (jflot, chart, artichow)
47
49 public $data; // Data of graph: array(array('abs1',valA1,valB1), array('abs2',valA2,valB2), ...)
50 public $title; // Title of graph
51 public $cssprefix = ''; // To add into css styles
52
56 public $width = 380;
60 public $height = 200;
61
62 public $MaxValue = 0;
63 public $MinValue = 0;
64 public $SetShading = 0;
65
66 public $horizTickIncrement = -1;
67 public $SetNumXTicks = -1;
68 public $labelInterval = -1;
69 public $YLabel;
70
71 public $hideXGrid = false;
72 public $hideXValues = false;
73 public $hideYGrid = false;
74
75 public $Legend = array();
76 public $LegendWidthMin = 0;
77 public $showlegend = 1;
78 public $showpointvalue = 1;
79 public $showpercent = 0;
80 public $combine = 0; // 0.05 if you want to combine records < 5% into "other"
81 public $graph; // Object Graph (Artichow, Phplot...)
85 public $mirrorGraphValues = false;
86 public $tooltipsTitles = null;
87 public $tooltipsLabels = null;
88
92 public $error = '';
93
94 public $bordercolor; // array(R,G,B)
95 public $bgcolor; // array(R,G,B)
96 public $bgcolorgrid = array(255, 255, 255); // array(R,G,B)
97 public $datacolor; // array(array(R,G,B),...)
98 public $borderwidth = 1;
99 public $borderskip = 'start';
100
101 private $stringtoshow; // To store string to output graph into HTML page
102
103
109 public function __construct($library = 'auto')
110 {
111 global $conf;
112 global $theme_bordercolor, $theme_datacolor, $theme_bgcolor;
113
114 // Some default values for the case it is not defined into the theme later.
115 $this->bordercolor = array(235, 235, 224);
116 $this->datacolor = array(array(120, 130, 150), array(160, 160, 180), array(190, 190, 220));
117 $this->bgcolor = array(235, 235, 224);
118
119 // For small screen, we prefer a default with of 300
120 if (!empty($conf->dol_optimize_smallscreen)) {
121 $this->width = 300;
122 }
123
124 // Load color of the theme
125 $color_file = DOL_DOCUMENT_ROOT . '/theme/' . $conf->theme . '/theme_vars.inc.php';
126 if (is_readable($color_file)) {
127 include $color_file;
128 if (isset($theme_bordercolor)) {
129 $this->bordercolor = $theme_bordercolor;
130 }
131 if (isset($theme_datacolor)) {
132 $this->datacolor = $theme_datacolor;
133 }
134 if (isset($theme_bgcolor)) {
135 $this->bgcolor = $theme_bgcolor;
136 }
137 }
138 //print 'bgcolor: '.join(',',$this->bgcolor).'<br>';
139
140 $this->_library = $library;
141 if ($this->_library == 'auto') {
142 $this->_library = (!getDolGlobalString('MAIN_JS_GRAPH') ? 'chart' : $conf->global->MAIN_JS_GRAPH);
143 }
144 }
145
146
147 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
154 public function SetHorizTickIncrement($xi)
155 {
156 // phpcs:enable
157 $this->horizTickIncrement = $xi;
158 return true;
159 }
160
161 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
168 public function SetNumXTicks($xt)
169 {
170 // phpcs:enable
171 $this->SetNumXTicks = $xt;
172 return true;
173 }
174
175 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
182 public function SetLabelInterval($x)
183 {
184 // phpcs:enable
185 $this->labelInterval = $x;
186 return true;
187 }
188
189 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
196 public function SetHideXGrid($bool)
197 {
198 // phpcs:enable
199 $this->hideXGrid = $bool;
200 return true;
201 }
202
209 public function setHideXValues($bool)
210 {
211 $this->hideXValues = $bool;
212 return true;
213 }
214
215 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
222 public function SetHideYGrid($bool)
223 {
224 // phpcs:enable
225 $this->hideYGrid = $bool;
226 return true;
227 }
228
229 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
236 public function SetYLabel($label)
237 {
238 // phpcs:enable
239 $this->YLabel = $label;
240 }
241
242 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
249 public function SetWidth($w)
250 {
251 // phpcs:enable
252 $this->width = $w;
253 }
254
255 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
262 public function SetTitle($title)
263 {
264 // phpcs:enable
265 $this->title = $title;
266 }
267
268 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
276 public function SetData($data)
277 {
278 // phpcs:enable
279 $this->data = $data;
280 }
281
282 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
289 public function SetDataColor($datacolor)
290 {
291 // phpcs:enable
292 $this->datacolor = $datacolor;
293 }
294
301 public function setBorderColor($bordercolor)
302 {
303 $this->bordercolor = $bordercolor;
304 }
305
312 public function setBorderWidth($borderwidth)
313 {
314 $this->borderwidth = $borderwidth;
315 }
316
324 public function setBorderSkip($borderskip)
325 {
326 $this->borderskip = $borderskip;
327 }
328
335 public function setTooltipsLabels($tooltipsLabels)
336 {
337 $this->tooltipsLabels = $tooltipsLabels;
338 }
339
346 public function setTooltipsTitles($tooltipsTitles)
347 {
348 $this->tooltipsTitles = $tooltipsTitles;
349 }
350
351 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
359 public function SetType($type)
360 {
361 // phpcs:enable
362 $this->type = $type;
363 }
364
365 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
372 public function SetLegend($legend)
373 {
374 // phpcs:enable
375 $this->Legend = $legend;
376 }
377
378 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
385 public function SetLegendWidthMin($legendwidthmin)
386 {
387 // phpcs:enable
388 $this->LegendWidthMin = $legendwidthmin;
389 }
390
391 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
398 public function SetMaxValue($max)
399 {
400 // phpcs:enable
401 $this->MaxValue = $max;
402 }
403
404 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
410 public function GetMaxValue()
411 {
412 // phpcs:enable
413 return $this->MaxValue;
414 }
415
416 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
423 public function SetMinValue($min)
424 {
425 // phpcs:enable
426 $this->MinValue = $min;
427 }
428
429 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
435 public function GetMinValue()
436 {
437 // phpcs:enable
438 return $this->MinValue;
439 }
440
441 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
448 public function SetHeight($h)
449 {
450 // phpcs:enable
451 $this->height = $h;
452 }
453
454 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
461 public function SetShading($s)
462 {
463 // phpcs:enable
464 $this->SetShading = $s;
465 }
466
467 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
474 public function SetCssPrefix($s)
475 {
476 // phpcs:enable
477 $this->cssprefix = $s;
478 }
479
480 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
486 public function ResetBgColor()
487 {
488 // phpcs:enable
489 unset($this->bgcolor);
490 }
491
492 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
498 public function ResetBgColorGrid()
499 {
500 // phpcs:enable
501 unset($this->bgcolorgrid);
502 }
503
510 public function setMirrorGraphValues($mirrorGraphValues)
511 {
512 $this->mirrorGraphValues = $mirrorGraphValues;
513 }
514
520 public function isGraphKo()
521 {
522 return $this->error;
523 }
524
531 public function setShowLegend($showlegend)
532 {
533 $this->showlegend = $showlegend;
534 }
535
542 public function setShowPointValue($showpointvalue)
543 {
544 $this->showpointvalue = $showpointvalue;
545 }
546
553 public function setShowPercent($showpercent)
554 {
555 $this->showpercent = $showpercent;
556 }
557
558
559
560 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
567 public function SetBgColor($bg_color = array(255, 255, 255))
568 {
569 // phpcs:enable
570 global $theme_bgcolor, $theme_bgcoloronglet;
571
572 if (!is_array($bg_color)) {
573 if ($bg_color == 'onglet') {
574 //print 'ee'.join(',',$theme_bgcoloronglet);
575 $this->bgcolor = $theme_bgcoloronglet;
576 } else {
577 $this->bgcolor = $theme_bgcolor;
578 }
579 } else {
580 $this->bgcolor = $bg_color;
581 }
582 }
583
584 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
591 public function SetBgColorGrid($bg_colorgrid = array(255, 255, 255))
592 {
593 // phpcs:enable
594 global $theme_bgcolor, $theme_bgcoloronglet;
595
596 if (!is_array($bg_colorgrid)) {
597 if ($bg_colorgrid == 'onglet') {
598 //print 'ee'.join(',',$theme_bgcoloronglet);
599 $this->bgcolorgrid = $theme_bgcoloronglet;
600 } else {
601 $this->bgcolorgrid = $theme_bgcolor;
602 }
603 } else {
604 $this->bgcolorgrid = $bg_colorgrid;
605 }
606 }
607
608 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
614 public function ResetDataColor()
615 {
616 // phpcs:enable
617 unset($this->datacolor);
618 }
619
620 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
626 public function GetMaxValueInData()
627 {
628 // phpcs:enable
629 if (!is_array($this->data)) {
630 return 0;
631 }
632
633 $max = null;
634
635 $nbseries = (empty($this->data[0]) ? 0 : count($this->data[0]) - 1);
636
637 foreach ($this->data as $x) { // Loop on each x
638 for ($i = 0; $i < $nbseries; $i++) { // Loop on each series
639 if (is_null($max)) {
640 $max = $x[$i + 1]; // $i+1 because the index 0 is the legend
641 } elseif ($max < $x[$i + 1]) {
642 $max = $x[$i + 1];
643 }
644 }
645 }
646
647 return $max;
648 }
649
650 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
656 public function GetMinValueInData()
657 {
658 // phpcs:enable
659 if (!is_array($this->data)) {
660 return 0;
661 }
662
663 $min = null;
664
665 $nbseries = (empty($this->data[0]) ? 0 : count($this->data[0]) - 1);
666
667 foreach ($this->data as $x) { // Loop on each x
668 for ($i = 0; $i < $nbseries; $i++) { // Loop on each series
669 if (is_null($min)) {
670 $min = $x[$i + 1]; // $i+1 because the index 0 is the legend
671 } elseif ($min > $x[$i + 1]) {
672 $min = $x[$i + 1];
673 }
674 }
675 }
676
677 return $min;
678 }
679
680 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
686 public function GetCeilMaxValue()
687 {
688 // phpcs:enable
689 $max = $this->GetMaxValueInData();
690 if ($max != 0) {
691 $max++;
692 }
693 $size = dol_strlen((string) abs(ceil($max)));
694 $factor = 1;
695 for ($i = 0; $i < ($size - 1); $i++) {
696 $factor *= 10;
697 }
698
699 $res = 0;
700 if (is_numeric($max)) {
701 $res = ceil($max / $factor) * $factor;
702 }
703
704 //print "max=".$max." res=".$res;
705 return (int) $res;
706 }
707
708 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
714 public function GetFloorMinValue()
715 {
716 // phpcs:enable
717 $min = $this->GetMinValueInData();
718 if ($min == '') {
719 $min = 0;
720 }
721 if ($min != 0) {
722 $min--;
723 }
724 $size = dol_strlen((string) abs(floor($min)));
725 $factor = 1;
726 for ($i = 0; $i < ($size - 1); $i++) {
727 $factor *= 10;
728 }
729
730 $res = floor($min / $factor) * $factor;
731
732 //print "min=".$min." res=".$res;
733 return $res;
734 }
735
743 public function draw($file, $fileurl = '')
744 {
745 if (empty($file)) {
746 $this->error = "Call to draw method was made with empty value for parameter file.";
747 dol_syslog(get_class($this) . "::draw " . $this->error, LOG_ERR);
748 return -2;
749 }
750 if (!is_array($this->data)) {
751 $this->error = "Call to draw method was made but SetData was not called or called with an empty dataset for parameters";
752 dol_syslog(get_class($this) . "::draw " . $this->error, LOG_ERR);
753 return -1;
754 }
755 if (count($this->data) < 1) {
756 $this->error = "Call to draw method was made but SetData was is an empty dataset";
757 dol_syslog(get_class($this) . "::draw " . $this->error, LOG_WARNING);
758 }
759 $call = "draw_" . $this->_library; // Example "draw_jflot"
760
761 return call_user_func_array(array($this, $call), array($file, $fileurl));
762 }
763
764 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
781 private function draw_jflot($file, $fileurl) // @phpstan-ignore-line
782 {
783 // phpcs:enable
784 global $langs;
785
786 dol_syslog(get_class($this) . "::draw_jflot this->type=" . implode(',', $this->type) . " this->MaxValue=" . $this->MaxValue);
787
788 if (empty($this->width) && empty($this->height)) {
789 print 'Error width or height not set';
790 return;
791 }
792
793 $legends = array();
794 $nblot = 0;
795 if (is_array($this->data) && is_array($this->data[0])) {
796 $nblot = count($this->data[0]) - 1; // -1 to remove legend
797 }
798 if ($nblot < 0) {
799 dol_syslog('Bad value for property ->data. Must be set by mydolgraph->SetData before calling mydolgrapgh->draw', LOG_WARNING);
800 }
801 $firstlot = 0;
802 // Works with line but not with bars
803 //if ($nblot > 2) $firstlot = ($nblot - 2); // We limit nblot to 2 because jflot can't manage more than 2 bars on same x
804
805 $i = $firstlot;
806 $series = array();
807 while ($i < $nblot) { // Loop on each series
808 $values = array(); // Array with horizontal y values (specific values of a series) for each abscisse x
809 $series[$i] = "var d" . $i . " = [];\n";
810
811 // Fill array $values
812 $x = 0;
813 foreach ($this->data as $valarray) { // Loop on each x
814 $legends[$x] = $valarray[0];
815 $values[$x] = (is_numeric($valarray[$i + 1]) ? $valarray[$i + 1] : null);
816 $x++;
817 }
818
819 if (isset($this->type[$firstlot]) && in_array($this->type[$firstlot], array('pie', 'piesemicircle', 'polar'))) {
820 foreach ($values as $x => $y) {
821 if (isset($y)) {
822 $series[$i] .= 'd' . $i . '.push({"label":"' . dol_escape_js($legends[$x]) . '", "data":' . $y . '});' . "\n";
823 }
824 }
825 } else {
826 foreach ($values as $x => $y) {
827 if (isset($y)) {
828 $series[$i] .= 'd' . $i . '.push([' . $x . ', ' . $y . ']);' . "\n";
829 }
830 }
831 }
832
833 unset($values);
834 $i++;
835 }
836 $tag = dol_escape_htmltag(dol_string_unaccent(dol_string_nospecial(basename($file), '_', array('-', '.'))));
837
838 $this->stringtoshow = '<!-- Build using jflot -->' . "\n";
839 if (!empty($this->title)) {
840 $this->stringtoshow .= '<div class="center dolgraphtitle' . (empty($this->cssprefix) ? '' : ' dolgraphtitle' . $this->cssprefix) . '">' . $this->title . '</div>';
841 }
842 if (!empty($this->shownographyet)) {
843 $this->stringtoshow .= '<div style="width:' . $this->width . 'px;height:' . $this->height . 'px;" class="nographyet"></div>';
844 $this->stringtoshow .= '<div class="nographyettext margintoponly">' . $langs->trans("NotEnoughDataYet") . '...</div>';
845 return;
846 }
847
848 // Start the div that will contains all the graph
849 $dolxaxisvertical = '';
850 if (count($this->data) > 20) {
851 $dolxaxisvertical = 'dol-xaxis-vertical';
852 }
853 $this->stringtoshow .= '<div id="placeholder_' . $tag . '" style="width:' . $this->width . 'px;height:' . $this->height . 'px;" class="dolgraph' . (empty($dolxaxisvertical) ? '' : ' ' . $dolxaxisvertical) . (empty($this->cssprefix) ? '' : ' dolgraph' . $this->cssprefix) . ' center"></div>' . "\n";
854
855 $this->stringtoshow .= '<script nonce="'.getNonce().'" id="' . $tag . '">' . "\n";
856 $this->stringtoshow .= '$(function () {' . "\n";
857 $i = $firstlot;
858 if ($nblot < 0) {
859 $this->stringtoshow .= '<!-- No series of data -->' . "\n";
860 } else {
861 while ($i < $nblot) {
862 $this->stringtoshow .= '<!-- Series ' . $i . ' -->' . "\n";
863 $this->stringtoshow .= $series[$i] . "\n";
864 $i++;
865 }
866 }
867 $this->stringtoshow .= "\n";
868
869 // Special case for Graph of type 'pie'
870 if (isset($this->type[$firstlot]) && in_array($this->type[$firstlot], array('pie', 'piesemicircle', 'polar'))) {
871 $datacolor = array();
872 foreach ($this->datacolor as $val) {
873 if (is_array($val)) {
874 $datacolor[] = "#" . sprintf("%02x%02x%02x", $val[0], $val[1], $val[2]); // If datacolor is array(R, G, B)
875 } else {
876 $datacolor[] = "#" . str_replace(array('#', '-'), '', $val); // If $val is '124' or '#124'
877 }
878 }
879
880 $urltemp = ''; // TODO Add support for url link into labels
881 $showlegend = $this->showlegend;
882 $showpointvalue = $this->showpointvalue;
883 $showpercent = $this->showpercent;
884
885 $this->stringtoshow .= '
886 function plotWithOptions_' . $tag . '() {
887 $.plot($("#placeholder_' . $tag . '"), d0,
888 {
889 series: {
890 pie: {
891 show: true,
892 radius: 0.8,
893 ' . ($this->combine ? '
894 combine: {
895 threshold: ' . $this->combine . '
896 },' : '') . '
897 label: {
898 show: true,
899 radius: 0.9,
900 formatter: function(label, series) {
901 var percent=Math.round(series.percent);
902 var number=series.data[0][1];
903 return \'';
904 $this->stringtoshow .= '<span style="font-size:8pt;text-align:center;padding:2px;color:black;">';
905 if ($urltemp) {
906 $this->stringtoshow .= '<a style="color: #FFFFFF;" border="0" href="' . $urltemp . '">';
907 }
908 $this->stringtoshow .= '\'+';
909 $this->stringtoshow .= ($showlegend ? '' : 'label+\' \'+'); // Hide label if already shown in legend
910 $this->stringtoshow .= ($showpointvalue ? 'number+' : '');
911 $this->stringtoshow .= ($showpercent ? '\'<br>\'+percent+\'%\'+' : '');
912 $this->stringtoshow .= '\'';
913 if ($urltemp) {
914 $this->stringtoshow .= '</a>';
915 }
916 $this->stringtoshow .= '</span>\';
917 },
918 background: {
919 opacity: 0.0,
920 color: \'#000000\'
921 }
922 }
923 }
924 },
925 zoom: {
926 interactive: true
927 },
928 pan: {
929 interactive: true
930 },';
931 if (count($datacolor)) {
932 $this->stringtoshow .= 'colors: ' . json_encode($datacolor) . ',';
933 }
934 $this->stringtoshow .= 'legend: {show: ' . ($showlegend ? 'true' : 'false') . ', position: \'ne\' }
935 });
936 }' . "\n";
937 } else {
938 // Other cases, graph of type 'bars', 'lines'
939 // Add code to support tooltips
940 // TODO: remove js css and use graph-tooltip-inner class instead by adding css in each themes
941 $this->stringtoshow .= '
942 function showTooltip_' . $tag . '(x, y, contents) {
943 $(\'<div class="graph-tooltip-inner" id="tooltip_' . $tag . '">\' + contents + \'</div>\').css({
944 position: \'absolute\',
945 display: \'none\',
946 top: y + 10,
947 left: x + 15,
948 border: \'1px solid #000\',
949 padding: \'5px\',
950 \'background-color\': \'#000\',
951 \'color\': \'#fff\',
952 \'font-weight\': \'bold\',
953 width: 200,
954 opacity: 0.80
955 }).appendTo("body").fadeIn(100);
956 }
957
958 var previousPoint = null;
959 $("#placeholder_' . $tag . '").bind("plothover", function (event, pos, item) {
960 $("#x").text(pos.x.toFixed(2));
961 $("#y").text(pos.y.toFixed(2));
962
963 if (item) {
964 if (previousPoint != item.dataIndex) {
965 previousPoint = item.dataIndex;
966
967 $("#tooltip").remove();
968 /* console.log(item); */
969 var x = item.datapoint[0].toFixed(2);
970 var y = item.datapoint[1].toFixed(2);
971 var z = item.series.xaxis.ticks[item.dataIndex].label;
972 ';
973 if ($this->showpointvalue > 0) {
974 $this->stringtoshow .= '
975 showTooltip_' . $tag . '(item.pageX, item.pageY, item.series.label + "<br>" + z + " => " + y);
976 ';
977 }
978 $this->stringtoshow .= '
979 }
980 }
981 else {
982 $("#tooltip_' . $tag . '").remove();
983 previousPoint = null;
984 }
985 });
986 ';
987
988 $this->stringtoshow .= 'var stack = null, steps = false;' . "\n";
989
990 $this->stringtoshow .= 'function plotWithOptions_' . $tag . '() {' . "\n";
991 $this->stringtoshow .= '$.plot($("#placeholder_' . $tag . '"), [ ' . "\n";
992 $i = $firstlot;
993 while ($i < $nblot) {
994 if ($i > $firstlot) {
995 $this->stringtoshow .= ', ' . "\n";
996 }
997 $color = sprintf("%02x%02x%02x", $this->datacolor[$i][0], $this->datacolor[$i][1], $this->datacolor[$i][2]);
998 $this->stringtoshow .= '{ ';
999 if (!isset($this->type[$i]) || $this->type[$i] == 'bars') {
1000 if ($nblot == 3) {
1001 if ($i == $firstlot) {
1002 $align = 'right';
1003 } elseif ($i == $firstlot + 1) {
1004 $align = 'center';
1005 } else {
1006 $align = 'left';
1007 }
1008 $this->stringtoshow .= 'bars: { lineWidth: 1, show: true, align: "' . $align . '", barWidth: 0.45 }, ';
1009 } else {
1010 $this->stringtoshow .= 'bars: { lineWidth: 1, show: true, align: "' . ($i == $firstlot ? 'center' : 'left') . '", barWidth: 0.5 }, ';
1011 }
1012 }
1013 if (isset($this->type[$i]) && ($this->type[$i] == 'lines' || $this->type[$i] == 'linesnopoint')) {
1014 $this->stringtoshow .= 'lines: { show: true, fill: false }, points: { show: ' . ($this->type[$i] == 'linesnopoint' ? 'false' : 'true') . ' }, ';
1015 }
1016 $this->stringtoshow .= 'color: "#' . $color . '", label: "' . (isset($this->Legend[$i]) ? dol_escape_js($this->Legend[$i]) : '') . '", data: d' . $i . ' }';
1017 $i++;
1018 }
1019 // shadowSize: 0 -> Drawing is faster without shadows
1020 $this->stringtoshow .= "\n" . ' ], { series: { shadowSize: 0, stack: stack, lines: { fill: false, steps: steps }, bars: { barWidth: 0.6, fillColor: { colors: [{opacity: 0.9 }, {opacity: 0.85}] }} }' . "\n";
1021
1022 // Xaxis
1023 $this->stringtoshow .= ', xaxis: { ticks: [' . "\n";
1024 $x = 0;
1025 foreach ($this->data as $key => $valarray) {
1026 if ($x > 0) {
1027 $this->stringtoshow .= ', ' . "\n";
1028 }
1029 $this->stringtoshow .= ' [' . $x . ', "' . $valarray[0] . '"]';
1030 $x++;
1031 }
1032 $this->stringtoshow .= '] }' . "\n";
1033
1034 // Yaxis
1035 $this->stringtoshow .= ', yaxis: { min: ' . $this->MinValue . ', max: ' . ($this->MaxValue) . ' }' . "\n";
1036
1037 // Background color
1038 $color1 = sprintf("%02x%02x%02x", $this->bgcolorgrid[0], $this->bgcolorgrid[0], $this->bgcolorgrid[2]);
1039 $color2 = sprintf("%02x%02x%02x", $this->bgcolorgrid[0], $this->bgcolorgrid[1], $this->bgcolorgrid[2]);
1040 $this->stringtoshow .= ', grid: { hoverable: true, backgroundColor: { colors: ["#' . $color1 . '", "#' . $color2 . '"] }, borderWidth: 1, borderColor: \'#e6e6e6\', tickColor : \'#e6e6e6\' }' . "\n";
1041 $this->stringtoshow .= '});' . "\n";
1042 $this->stringtoshow .= '}' . "\n";
1043 }
1044
1045 $this->stringtoshow .= 'plotWithOptions_' . $tag . '();' . "\n";
1046 $this->stringtoshow .= '});' . "\n";
1047 $this->stringtoshow .= '</script>' . "\n";
1048 }
1049
1050
1051 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1068 private function draw_chart($file, $fileurl) // @phpstan-ignore-line
1069 {
1070 // phpcs:enable
1071 global $langs;
1072
1073 dol_syslog(get_class($this) . "::draw_chart this->type=" . implode(',', $this->type) . " this->MaxValue=" . $this->MaxValue);
1074
1075 if (empty($this->width) && empty($this->height)) {
1076 print 'Error width or height not set';
1077 return;
1078 }
1079
1080 $showlegend = $this->showlegend;
1081 $bordercolor = "";
1082
1083 $legends = array();
1084 $nblot = 0;
1085 if (is_array($this->data)) {
1086 foreach ($this->data as $valarray) { // Loop on each x
1087 $nblot = max($nblot, count($valarray) - 1); // -1 to remove legend
1088 }
1089 }
1090 //var_dump($nblot);
1091 if ($nblot < 0) {
1092 dol_syslog('Bad value for property ->data. Must be set by mydolgraph->SetData before calling mydolgrapgh->draw', LOG_WARNING);
1093 }
1094 $firstlot = 0;
1095 // Works with line but not with bars
1096 //if ($nblot > 2) $firstlot = ($nblot - 2); // We limit nblot to 2 because jflot can't manage more than 2 bars on same x
1097
1098 $series = array();
1099 $arrayofgroupslegend = array();
1100 //var_dump($this->data);
1101
1102 $i = $firstlot;
1103 while ($i < $nblot) { // Loop on each series
1104 $values = array(); // Array with horizontal y values (specific values of a series) for each abscisse x (with x=0,1,2,...)
1105 $series[$i] = "";
1106
1107 // Fill array $series from $this->data
1108 $x = 0;
1109 foreach ($this->data as $valarray) { // Loop on each x
1110 $legends[$x] = (array_key_exists('label', $valarray) ? $valarray['label'] : $valarray[0]);
1111 $array_of_ykeys = array_keys($valarray);
1112 $alabelexists = 1;
1113 $tmpykey = explode('_', ($array_of_ykeys[$i + ($alabelexists ? 1 : 0)]), 3);
1114 if (isset($tmpykey[2]) && (!empty($tmpykey[2]) || $tmpykey[2] == '0')) { // This is a 'Group by' array
1115 $tmpvalue = (array_key_exists('y_' . $tmpykey[1] . '_' . $tmpykey[2], $valarray) ? $valarray['y_' . $tmpykey[1] . '_' . $tmpykey[2]] : $valarray[$i + 1]);
1116 $values[$x] = (is_numeric($tmpvalue) ? $tmpvalue : null);
1117 $arrayofgroupslegend[$i] = array(
1118 'stacknum' => $tmpykey[1],
1119 'legend' => $this->Legend[$tmpykey[1]],
1120 'legendwithgroup' => $this->Legend[$tmpykey[1]] . ' - ' . $tmpykey[2]
1121 );
1122 } else {
1123 $tmpvalue = (array_key_exists('y_' . $i, $valarray) ? $valarray['y_' . $i] : $valarray[$i + 1]);
1124 //var_dump($i.'_'.$x.'_'.$tmpvalue);
1125 $values[$x] = (is_numeric($tmpvalue) ? $tmpvalue : null);
1126 }
1127 $x++;
1128 }
1129 //var_dump($values);
1130 $j = 0;
1131 foreach ($values as $x => $y) {
1132 if (isset($y)) {
1133 $series[$i] .= ($j > 0 ? ", " : "") . $y;
1134 } else {
1135 $series[$i] .= ($j > 0 ? ", " : "") . 'null';
1136 }
1137 $j++;
1138 }
1139
1140 $values = null; // Free mem
1141 $i++;
1142 }
1143 //var_dump($series);
1144 //var_dump($arrayofgroupslegend);
1145
1146 $tag = dol_escape_htmltag(dol_string_unaccent(dol_string_nospecial(basename($file), '_', array('-', '.'))));
1147
1148 $this->stringtoshow = '<!-- Build using chart -->' . "\n";
1149 if (!empty($this->title)) {
1150 $this->stringtoshow .= '<div class="center dolgraphtitle' . (empty($this->cssprefix) ? '' : ' dolgraphtitle' . $this->cssprefix) . '">' . $this->title . '</div>';
1151 }
1152 if (!empty($this->shownographyet)) {
1153 $this->stringtoshow .= '<div style="width:' . $this->width . (strpos($this->width, '%') > 0 ? '' : 'px') . '; height:' . $this->height . 'px;" class="nographyet"></div>';
1154 $this->stringtoshow .= '<div class="nographyettext margintoponly">' . $langs->trans("NotEnoughDataYet") . '...</div>';
1155 return;
1156 }
1157
1158 // Start the div that will contains all the graph
1159 $dolxaxisvertical = '';
1160 if (count($this->data) > 20) {
1161 $dolxaxisvertical = 'dol-xaxis-vertical';
1162 }
1163 // No height for the pie graph
1164 $cssfordiv = 'dolgraphchart';
1165 if (isset($this->type[$firstlot])) {
1166 $cssfordiv .= ' dolgraphchar' . $this->type[$firstlot];
1167 }
1168 $this->stringtoshow .= '<div id="placeholder_'.$tag.'" style="min-height: '.$this->height.(strpos((string) $this->height, '%') > 0 ? '' : 'px').'; max-height: '.(strpos((string) $this->height, '%') > 0 ? $this->height : ((int) $this->height + 100) . 'px').'; width:'.$this->width.(strpos((string) $this->width, '%') > 0 ? '' : 'px').';" class="'.$cssfordiv.' dolgraph'.(empty($dolxaxisvertical) ? '' : ' '.$dolxaxisvertical).(empty($this->cssprefix) ? '' : ' dolgraph'.$this->cssprefix).' center">'."\n";
1169 $this->stringtoshow .= '<canvas id="canvas_'.$tag.'"></canvas></div>'."\n";
1170
1171 $this->stringtoshow .= '<script nonce="'.getNonce().'" id="' . $tag . '">' . "\n";
1172 $i = $firstlot;
1173 if ($nblot < 0) {
1174 $this->stringtoshow .= '<!-- No series of data -->';
1175 } else {
1176 while ($i < $nblot) {
1177 //$this->stringtoshow .= '<!-- Series '.$i.' -->'."\n";
1178 //$this->stringtoshow .= $series[$i]."\n";
1179 $i++;
1180 }
1181 }
1182 $this->stringtoshow .= "\n";
1183
1184 // Special case for Graph of type 'pie', 'piesemicircle', or 'polar'
1185 if (isset($this->type[$firstlot]) && (in_array($this->type[$firstlot], array('pie', 'polar', 'piesemicircle')))) {
1186 $type = $this->type[$firstlot]; // pie or polar
1187 //$this->stringtoshow .= 'var options = {' . "\n";
1188 $this->stringtoshow .= 'var options = { maintainAspectRatio: false, aspectRatio: 2.5, ';
1189
1190
1191 $legendMaxLines = 0; // Does not work
1192
1193 /* For Chartjs v2.9 */
1194 if (empty($showlegend)) {
1195 $this->stringtoshow .= 'legend: { display: false }, ';
1196 } else {
1197 $this->stringtoshow .= 'legend: { labels: { boxWidth: 15 }, position: \'' . ($showlegend == 2 ? 'right' : 'top') . '\'';
1198 if (!empty($legendMaxLines)) {
1199 $this->stringtoshow .= ', maxLines: ' . $legendMaxLines;
1200 }
1201 $this->stringtoshow .= ' }, ' . "\n";
1202 }
1203
1204 /* For Chartjs v3.5 */
1205 $this->stringtoshow .= 'plugins: { ';
1206 if (empty($showlegend)) {
1207 $this->stringtoshow .= 'legend: { display: false }, ';
1208 } else {
1209 $this->stringtoshow .= 'legend: { labels: { boxWidth: 15 }, position: \'' . ($showlegend == 2 ? 'right' : 'top') . '\'';
1210 if (!empty($legendMaxLines)) {
1211 $this->stringtoshow .= ', maxLines: ' . $legendMaxLines;
1212 }
1213 $this->stringtoshow .= ' }, ' . "\n";
1214 }
1215 $this->stringtoshow .= ' }, ' . "\n";
1216
1217
1218 if ($this->type[$firstlot] == 'piesemicircle') {
1219 $this->stringtoshow .= 'circumference: Math.PI,' . "\n";
1220 $this->stringtoshow .= 'rotation: -Math.PI,' . "\n";
1221 }
1222 $this->stringtoshow .= 'elements: { arc: {' . "\n";
1223 // Color of each arc
1224 $this->stringtoshow .= 'backgroundColor: [';
1225 $i = 0;
1226 $foundnegativecolor = 0;
1227 foreach ($legends as $val) { // Loop on each series
1228 if ($i > 0) {
1229 $this->stringtoshow .= ', ' . "\n";
1230 }
1231 if (is_array($this->datacolor[$i])) {
1232 $color = 'rgb(' . $this->datacolor[$i][0] . ', ' . $this->datacolor[$i][1] . ', ' . $this->datacolor[$i][2] . ')'; // If datacolor is array(R, G, B)
1233 } else {
1234 $tmp = str_replace('#', '', $this->datacolor[$i]);
1235 if (strpos($tmp, '-') !== false) {
1236 $foundnegativecolor++;
1237 $color = 'rgba(0,0,0,.0)'; // If $val is '-123'
1238 } else {
1239 $color = "#" . $tmp; // If $val is '123' or '#123'
1240 }
1241 }
1242 $this->stringtoshow .= "'" . $color . "'";
1243 $i++;
1244 }
1245 $this->stringtoshow .= '], ' . "\n";
1246 // Border color
1247 if ($foundnegativecolor) {
1248 $this->stringtoshow .= 'borderColor: [';
1249 $i = 0;
1250 foreach ($legends as $val) { // Loop on each series
1251 if ($i > 0) {
1252 $this->stringtoshow .= ', ' . "\n";
1253 }
1254 if (is_array($this->datacolor[$i])) {
1255 $color = 'null'; // If datacolor is array(R, G, B)
1256 } else {
1257 $tmp = str_replace('#', '', $this->datacolor[$i]);
1258 if (strpos($tmp, '-') !== false) {
1259 $color = '#' . str_replace('-', '', $tmp); // If $val is '-123'
1260 } else {
1261 $color = 'null'; // If $val is '123' or '#123'
1262 }
1263 }
1264 $this->stringtoshow .= ($color == 'null' ? "'rgba(0,0,0,0.2)'" : "'" . $color . "'");
1265 $i++;
1266 }
1267 $this->stringtoshow .= ']';
1268 }
1269 $this->stringtoshow .= '} } };' . "\n";
1270
1271 $this->stringtoshow .= '
1272 var ctx = document.getElementById("canvas_' . $tag . '").getContext("2d");
1273 var chart = new Chart(ctx, {
1274 // The type of chart we want to create
1275 type: \'' . (in_array($type, array('pie', 'piesemicircle')) ? 'doughnut' : 'polarArea') . '\',
1276 // Configuration options go here
1277 options: options,
1278 data: {
1279 labels: [';
1280
1281 $i = 0;
1282 foreach ($legends as $val) { // Loop on each series
1283 if ($i > 0) {
1284 $this->stringtoshow .= ', ';
1285 }
1286 $this->stringtoshow .= "'" . dol_escape_js(dol_trunc($val, 25)) . "'"; // Lower than 25 make some important label (that we can't shorten) to be truncated
1287 $i++;
1288 }
1289
1290 $this->stringtoshow .= '],
1291 datasets: [';
1292 $i = 0;
1293 while ($i < $nblot) { // Loop on each series
1294 $color = 'rgb(' . $this->datacolor[$i][0] . ', ' . $this->datacolor[$i][1] . ', ' . $this->datacolor[$i][2] . ')';
1295
1296 if ($i > 0) {
1297 $this->stringtoshow .= ', ' . "\n";
1298 }
1299 $this->stringtoshow .= '{' . "\n";
1300 //$this->stringtoshow .= 'borderColor: \''.$color.'\', ';
1301 //$this->stringtoshow .= 'backgroundColor: \''.$color.'\', ';
1302 $this->stringtoshow .= ' data: [' . $series[$i] . ']';
1303 $this->stringtoshow .= '}' . "\n";
1304 $i++;
1305 }
1306 $this->stringtoshow .= ']' . "\n";
1307 $this->stringtoshow .= '}' . "\n";
1308 $this->stringtoshow .= '});' . "\n";
1309 } else {
1310 // Other cases, graph of type 'bars', 'lines', 'linesnopoint'
1311 $type = 'bar';
1312 $xaxis = '';
1313
1314 if (isset($this->type[$firstlot]) && $this->type[$firstlot] == 'horizontalbars') {
1315 $xaxis = "indexAxis: 'y', ";
1316 }
1317 if (isset($this->type[$firstlot]) && ($this->type[$firstlot] == 'lines' || $this->type[$firstlot] == 'linesnopoint')) {
1318 $type = 'line';
1319 }
1320
1321 // Set options
1322 $this->stringtoshow .= 'var options = { maintainAspectRatio: false, aspectRatio: 2.5, ';
1323 $this->stringtoshow .= $xaxis;
1324 if ($this->showpointvalue == 2) {
1325 $this->stringtoshow .= 'interaction: { intersect: true, mode: \'index\'}, ';
1326 }
1327
1328 /* For Chartjs v2.9 */
1329 /*
1330 if (empty($showlegend)) {
1331 $this->stringtoshow .= 'legend: { display: false }, '."\n";
1332 } else {
1333 $this->stringtoshow .= 'legend: { maxWidth: '.round($this->width / 2).', labels: { boxWidth: 15 }, position: \'' . ($showlegend == 2 ? 'right' : 'top') . '\' }, '."\n";
1334 }
1335 */
1336
1337 /* For Chartjs v3.5 */
1338 $this->stringtoshow .= 'plugins: { '."\n";
1339 if (empty($showlegend)) {
1340 $this->stringtoshow .= 'legend: { display: false }, '."\n";
1341 } else {
1342 $this->stringtoshow .= 'legend: { maxWidth: '.round(intval($this->width) / 2).', labels: { boxWidth: 15 }, position: \'' . (($showlegend && $showlegend == 2) ? 'right' : 'top') . '\' },'."\n";
1343 }
1344 if (is_array($this->tooltipsLabels) || is_array($this->tooltipsTitles)) {
1345 $this->stringtoshow .= 'tooltip: { mode: \'nearest\',
1346 callbacks: {';
1347 if (is_array($this->tooltipsTitles)) {
1348 $this->stringtoshow .= '
1349 title: function(tooltipItem, data) {
1350 var tooltipsTitle ='.json_encode($this->tooltipsTitles).'
1351 return tooltipsTitle[tooltipItem[0].datasetIndex];
1352 },';
1353 }
1354 if (is_array($this->tooltipsLabels)) {
1355 $this->stringtoshow .= 'label: function(tooltipItem, data) {
1356 var tooltipslabels ='.json_encode($this->tooltipsLabels).'
1357 return tooltipslabels[tooltipItem.datasetIndex]
1358 }';
1359 }
1360 $this->stringtoshow .= '}},';
1361 }
1362 $this->stringtoshow .= "}, \n";
1363
1364 /* For Chartjs v2.9 */
1365 /*
1366 $this->stringtoshow .= 'scales: { xAxis: [{ ';
1367 if ($this->hideXValues) {
1368 $this->stringtoshow .= ' ticks: { display: false }, display: true,';
1369 }
1370 //$this->stringtoshow .= 'type: \'time\', '; // Need Moment.js
1371 $this->stringtoshow .= 'distribution: \'linear\'';
1372 if ($type == 'bar' && count($arrayofgroupslegend) > 0) {
1373 $this->stringtoshow .= ', stacked: true';
1374 }
1375 $this->stringtoshow .= ' }]';
1376 $this->stringtoshow .= ', yAxis: [{ ticks: { beginAtZero: true }';
1377 if ($type == 'bar' && count($arrayofgroupslegend) > 0) {
1378 $this->stringtoshow .= ', stacked: true';
1379 }
1380 $this->stringtoshow .= ' }] }';
1381 */
1382
1383 // Add a callback to change label to show only positive value
1384 if (is_array($this->tooltipsLabels) || is_array($this->tooltipsTitles)) {
1385 $this->stringtoshow .= 'tooltips: { mode: \'nearest\',
1386 callbacks: {';
1387 if (is_array($this->tooltipsTitles)) {
1388 $this->stringtoshow .= '
1389 title: function(tooltipItem, data) {
1390 var tooltipsTitle ='.json_encode($this->tooltipsTitles).'
1391 return tooltipsTitle[tooltipItem[0].datasetIndex];
1392 },';
1393 }
1394 if (is_array($this->tooltipsLabels)) {
1395 $this->stringtoshow .= 'label: function(tooltipItem, data) {
1396 var tooltipslabels ='.json_encode($this->tooltipsLabels).'
1397 return tooltipslabels[tooltipItem.datasetIndex]
1398 }';
1399 }
1400 $this->stringtoshow .= '}},';
1401 }
1402 $this->stringtoshow .= '};';
1403 $this->stringtoshow .= '
1404 var ctx = document.getElementById("canvas_' . $tag . '").getContext("2d");
1405 var chart = new Chart(ctx, {
1406 // The type of chart we want to create
1407 type: \'' . $type . '\',
1408 // Configuration options go here
1409 options: options,
1410 data: {
1411 labels: [';
1412
1413 $i = 0;
1414 foreach ($legends as $val) { // Loop on each series
1415 if ($i > 0) {
1416 $this->stringtoshow .= ', ';
1417 }
1418 $this->stringtoshow .= "'" . dol_escape_js(dol_trunc($val, 32)) . "'";
1419 $i++;
1420 }
1421
1422 //var_dump($arrayofgroupslegend);
1423
1424 $this->stringtoshow .= '],
1425 datasets: [';
1426
1427 global $theme_datacolor;
1428 '@phan-var-force array{0:array{0:int,1:int,2:int},1:array{0:int,1:int,2:int},2:array{0:int,1:int,2:int},3:array{0:int,1:int,2:int}} $theme_datacolor';
1429 //var_dump($arrayofgroupslegend);
1430 $i = 0;
1431 $iinstack = 0;
1432 $oldstacknum = -1;
1433 while ($i < $nblot) { // Loop on each series
1434 $foundnegativecolor = 0;
1435 $usecolorvariantforgroupby = 0;
1436 // We used a 'group by' and we have too many colors so we generated color variants per
1437 if (!empty($arrayofgroupslegend) && is_array($arrayofgroupslegend[$i]) && count($arrayofgroupslegend[$i]) > 0) { // If we used a group by.
1438 $nbofcolorneeds = count($arrayofgroupslegend);
1439 $nbofcolorsavailable = count($theme_datacolor);
1440 if ($nbofcolorneeds > $nbofcolorsavailable) {
1441 $usecolorvariantforgroupby = 1;
1442 }
1443
1444 $textoflegend = $arrayofgroupslegend[$i]['legendwithgroup'];
1445 } else {
1446 $textoflegend = !empty($this->Legend[$i]) ? $this->Legend[$i] : '';
1447 }
1448
1449 if ($usecolorvariantforgroupby) {
1450 $newcolor = $this->datacolor[$arrayofgroupslegend[$i]['stacknum']];
1451 // If we change the stack
1452 if ($oldstacknum == -1 || $arrayofgroupslegend[$i]['stacknum'] != $oldstacknum) {
1453 $iinstack = 0;
1454 }
1455
1456 //var_dump($iinstack);
1457 if ($iinstack) {
1458 // Change color with offset of $iinstack
1459 //var_dump($newcolor);
1460 if ($iinstack % 2) { // We increase aggressiveness of reference color for color 2, 4, 6, ...
1461 $ratio = min(95, 10 + 10 * $iinstack); // step of 20
1462 $brightnessratio = min(90, 5 + 5 * $iinstack); // step of 10
1463 } else { // We decrease aggressiveness of reference color for color 3, 5, 7, ..
1464 $ratio = max(-100, -15 * $iinstack + 10); // step of -20
1465 $brightnessratio = min(90, 10 * $iinstack); // step of 20
1466 }
1467 //var_dump('Color '.($iinstack+1).' : '.$ratio.' '.$brightnessratio);
1468
1469 $newcolor = array_values(colorHexToRgb(colorAgressiveness(colorArrayToHex($newcolor), $ratio, $brightnessratio), false, true));
1470 }
1471 $oldstacknum = $arrayofgroupslegend[$i]['stacknum'];
1472
1473 $color = 'rgb(' . $newcolor[0] . ', ' . $newcolor[1] . ', ' . $newcolor[2] . ', 0.9)';
1474 $bordercolor = 'rgb(' . $newcolor[0] . ', ' . $newcolor[1] . ', ' . $newcolor[2] . ')';
1475 } else { // We do not use a 'group by'
1476 if (!empty($this->datacolor[$i])) {
1477 if (is_array($this->datacolor[$i])) {
1478 $color = 'rgb(' . $this->datacolor[$i][0] . ', ' . $this->datacolor[$i][1] . ', ' . $this->datacolor[$i][2] . ', 0.9)';
1479 } else {
1480 $color = $this->datacolor[$i];
1481 }
1482 }
1483 // else: $color will be undefined
1484 if (!empty($this->bordercolor[$i]) && is_array($this->bordercolor[$i])) {
1485 $bordercolor = 'rgb(' . $this->bordercolor[$i][0] . ', ' . $this->bordercolor[$i][1] . ', ' . $this->bordercolor[$i][2] . ', 0.9)';
1486 } else {
1487 if ($type != 'horizontalBar') {
1488 $bordercolor = $color;
1489 } else {
1490 $bordercolor = $this->bordercolor[$i];
1491 }
1492 }
1493
1494 // For negative colors, we invert border and background
1495 $tmp = str_replace('#', '', $color);
1496 if (strpos($tmp, '-') !== false) {
1497 $foundnegativecolor++;
1498 $bordercolor = str_replace('-', '', $color);
1499 $color = '#FFFFFF'; // If $val is '-123'
1500 }
1501 }
1502 if ($i > 0) {
1503 $this->stringtoshow .= ', ';
1504 }
1505 $this->stringtoshow .= "\n";
1506 $this->stringtoshow .= '{';
1507 $this->stringtoshow .= 'dolibarrinfo: \'y_' . $i . '\', ';
1508 $this->stringtoshow .= 'label: \'' . dol_escape_js(dol_string_nohtmltag($textoflegend)) . '\', ';
1509 $this->stringtoshow .= 'pointStyle: \'' . ((!empty($this->type[$i]) && $this->type[$i] == 'linesnopoint') ? 'line' : 'circle') . '\', ';
1510 $this->stringtoshow .= 'fill: ' . ($type == 'bar' ? 'true' : 'false') . ', ';
1511 if ($type == 'bar' || $type == 'horizontalBar') {
1512 $this->stringtoshow .= 'borderWidth: \''.$this->borderwidth.'\', ';
1513 }
1514 $this->stringtoshow .= 'borderColor: \'' . $bordercolor . '\', ';
1515 $this->stringtoshow .= 'borderSkipped: \'' . $this->borderskip . '\', ';
1516 $this->stringtoshow .= 'backgroundColor: \'' . $color . '\', ';
1517 if (!empty($arrayofgroupslegend) && !empty($arrayofgroupslegend[$i])) {
1518 $this->stringtoshow .= 'stack: \'' . $arrayofgroupslegend[$i]['stacknum'] . '\', ';
1519 }
1520 $this->stringtoshow .= 'data: [';
1521
1522 $this->stringtoshow .= $this->mirrorGraphValues ? '[-' . $series[$i] . ',' . $series[$i] . ']' : $series[$i];
1523 $this->stringtoshow .= ']';
1524 $this->stringtoshow .= '}' . "\n";
1525
1526 $i++;
1527 $iinstack++;
1528 }
1529 $this->stringtoshow .= ']' . "\n";
1530 $this->stringtoshow .= '}' . "\n";
1531 $this->stringtoshow .= '});' . "\n";
1532 }
1533
1534 $this->stringtoshow .= '</script>' . "\n";
1535 }
1536
1537
1543 public function total()
1544 {
1545 $value = 0;
1546 foreach ($this->data as $valarray) { // Loop on each x
1547 $value += $valarray[1];
1548 }
1549 return $value;
1550 }
1551
1558 public function show($shownographyet = 0)
1559 {
1560 global $langs;
1561
1562 if ($shownographyet) {
1563 $s = '<div class="nographyet" style="width:' . (preg_match('/%/', $this->width) ? $this->width : $this->width . 'px') . '; height:' . (preg_match('/%/', $this->height) ? $this->height : $this->height . 'px') . ';"></div>';
1564 $s .= '<div class="nographyettext margintoponly">';
1565 if (is_numeric($shownographyet)) {
1566 $s .= $langs->trans("NotEnoughDataYet") . '...';
1567 } else {
1568 $s .= $shownographyet . '...';
1569 }
1570 $s .= '</div>';
1571 return $s;
1572 }
1573
1574 return $this->stringtoshow;
1575 }
1576
1577
1585 public static function getDefaultGraphSizeForStats($direction, $defaultsize = '')
1586 {
1587 global $conf;
1588 $defaultsize = (int) $defaultsize;
1589
1590 if ($direction == 'width') {
1591 if (empty($conf->dol_optimize_smallscreen)) {
1592 return ($defaultsize ? $defaultsize : 500);
1593 } else {
1594 return (empty($_SESSION['dol_screenwidth']) ? 280 : ($_SESSION['dol_screenwidth'] - 40));
1595 }
1596 } elseif ($direction == 'height') {
1597 return (empty($conf->dol_optimize_smallscreen) ? ($defaultsize ? $defaultsize : 220) : 200);
1598 }
1599 return 0;
1600 }
1601}
Class to build graphs.
setTooltipsTitles($tooltipsTitles)
Set tooltips titles of the graph.
setTooltipsLabels($tooltipsLabels)
Set tooltips labels of the graph.
__construct($library='auto')
Constructor.
draw_jflot($file, $fileurl)
Build a graph into ->stringtoshow using the JFlot library.
draw($file, $fileurl='')
Build a graph into memory using correct library (may also be wrote on disk, depending on library used...
SetYLabel($label)
Set y label.
ResetDataColor()
Reset data color.
SetBgColorGrid($bg_colorgrid=array(255, 255, 255))
Define background color of grid.
SetHideYGrid($bool)
Hide Y grid.
SetHorizTickIncrement($xi)
Utiliser SetNumTicks ou SetHorizTickIncrement mais pas les 2.
SetMinValue($min)
Set min value.
ResetBgColor()
Reset bg color.
setHideXValues($bool)
Hide X Values.
SetNumXTicks($xt)
Utiliser SetNumTicks ou SetHorizTickIncrement mais pas les 2.
SetCssPrefix($s)
Set shading.
GetMaxValue()
Get max value.
GetCeilMaxValue()
Return max value of all data.
GetMaxValueInData()
Get max value among all values of all series.
GetMinValue()
Get min value.
SetHideXGrid($bool)
Hide X grid.
isGraphKo()
Is graph ko.
setMirrorGraphValues($mirrorGraphValues)
Mirror Values of the graph.
SetLabelInterval($x)
Set label interval to reduce number of labels.
SetDataColor($datacolor)
Set data color.
SetWidth($w)
Set width.
SetData($data)
Set data.
GetMinValueInData()
Return min value of all values of all series.
SetType($type)
Set type.
SetMaxValue($max)
Set max value.
SetLegend($legend)
Set legend.
SetHeight($h)
Set height.
setBorderSkip($borderskip)
Set border skip.
setShowPercent($showpercent)
Show percent or not.
draw_chart($file, $fileurl)
Build a graph using Chart library.
setShowLegend($showlegend)
Show legend or not.
setBorderColor($bordercolor)
Set border color.
setBorderWidth($borderwidth)
Set border width.
SetTitle($title)
Set title.
SetLegendWidthMin($legendwidthmin)
Set min width.
ResetBgColorGrid()
Reset bgcolorgrid.
GetFloorMinValue()
Return min value of all data.
$data
Array of data.
SetBgColor($bg_color=array(255, 255, 255))
Define background color of complete image.
SetShading($s)
Set shading.
setShowPointValue($showpointvalue)
Show pointvalue or not.
dol_string_nohtmltag($stringtoclean, $removelinefeed=1, $pagecodeto='UTF-8', $strip_tags=0, $removedoublespaces=1)
Clean a string from all HTML tags and entities.
dol_string_nospecial($str, $newstr='_', $badcharstoreplace='', $badcharstoremove='', $keepspaces=0)
Clean a string from all punctuation characters to use it as a ref or login.
dol_strlen($string, $stringencoding='UTF-8')
Make a strlen call.
dol_escape_js($stringtoescape, $mode=0, $noescapebackslashn=0)
Returns text escaped for inclusion into javascript code.
dol_string_unaccent($str)
Clean a string from all accent characters to be used as ref, login or by dol_sanitizeFileName.
getDolGlobalString($key, $default='')
Return a Dolibarr global constant string value.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
dol_escape_htmltag($stringtoescape, $keepb=0, $keepn=0, $noescapetags='', $escapeonlyhtmltags=0, $cleanalsojavascript=0)
Returns text escaped for inclusion in HTML alt or title or value tags, or into values of HTML input f...
if(preg_match('/crypted:/i', $dolibarr_main_db_pass)||!empty($dolibarr_main_db_encrypted_pass)) $conf db type
Definition repair.php:137