dolibarr 22.0.5
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-2025 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{
47 public $type = array(); // Array with type of each series. Example: array('bars', 'horizontalbars', 'lines', 'pies', 'piesemicircle', 'polar'...)
51 public $mode = 'side'; // Mode bars graph: side, depth
55 private $_library; // Graphic library to use (jflot, chart, artichow)
56
62 public $data; // Data of graph: array(array('abs1',valA1,valB1), array('abs2',valA2,valB2), ...)
66 public $title; // Title of graph
70 public $cssprefix = ''; // To add into css styles
71
75 public $width = 380;
79 public $height = 200;
80
84 public $MaxValue = 0;
88 public $MinValue = 0;
92 public $SetShading = 0;
93
97 public $horizTickIncrement = -1;
101 public $SetNumXTicks = -1;
105 public $labelInterval = -1;
109 public $YLabel;
110
114 public $hideXGrid = false;
118 public $hideXValues = false;
122 public $hideYGrid = false;
123
127 public $Legend = array();
131 public $LegendWidthMin = 0;
135 public $showlegend = 1;
139 public $showpointvalue = 1;
143 public $showpercent = 0;
147 public $combine = 0; // 0.05 if you want to combine records < 5% into "other"
151 public $graph; // Object Graph (Artichow, Phplot...)
155 public $mirrorGraphValues = false;
159 public $tooltipsTitles = null;
163 public $tooltipsLabels = null;
164
168 public $error = '';
169
173 public $bordercolor; // array(R,G,B)
177 public $bgcolor; // array(R,G,B)
181 public $bgcolorgrid = array(255, 255, 255); // array(R,G,B)
185 public $datacolor; // array(array(R,G,B),...)
189 public $borderwidth = 1;
193 public $borderskip = 'start';
194
198 private $stringtoshow; // To store string to output graph into HTML page
199
200
206 public function __construct($library = 'auto')
207 {
208 global $conf;
209 global $theme_bordercolor, $theme_datacolor, $theme_bgcolor;
210
211 // Some default values for the case it is not defined into the theme later.
212 $this->bordercolor = array(235, 235, 224);
213 $this->datacolor = array(array(120, 130, 150), array(160, 160, 180), array(190, 190, 220));
214 $this->bgcolor = array(235, 235, 224);
215
216 // For small screen, we prefer a default with of 300
217 if (!empty($conf->dol_optimize_smallscreen)) {
218 $this->width = 300;
219 }
220
221 // Load color of the theme
222 $color_file = DOL_DOCUMENT_ROOT . '/theme/' . $conf->theme . '/theme_vars.inc.php';
223 if (is_readable($color_file)) {
224 include $color_file;
225 if (isset($theme_bordercolor)) {
226 $this->bordercolor = $theme_bordercolor;
227 }
228 if (isset($theme_datacolor)) {
229 $this->datacolor = $theme_datacolor;
230 }
231 if (isset($theme_bgcolor)) {
232 $this->bgcolor = $theme_bgcolor;
233 }
234 }
235 //print 'bgcolor: '.join(',',$this->bgcolor).'<br>';
236
237 $this->_library = $library;
238 if ($this->_library == 'auto') {
239 $this->_library = (!getDolGlobalString('MAIN_JS_GRAPH') ? 'chart' : $conf->global->MAIN_JS_GRAPH);
240 }
241 }
242
243
244 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
251 public function SetHorizTickIncrement($xi)
252 {
253 // phpcs:enable
254 $this->horizTickIncrement = $xi;
255 return true;
256 }
257
258 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
265 public function SetNumXTicks($xt)
266 {
267 // phpcs:enable
268 $this->SetNumXTicks = $xt;
269 return true;
270 }
271
272 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
279 public function SetLabelInterval($x)
280 {
281 // phpcs:enable
282 $this->labelInterval = $x;
283 return true;
284 }
285
286 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
293 public function SetHideXGrid($bool)
294 {
295 // phpcs:enable
296 $this->hideXGrid = $bool;
297 return true;
298 }
299
306 public function setHideXValues($bool)
307 {
308 $this->hideXValues = $bool;
309 return true;
310 }
311
312 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
319 public function SetHideYGrid($bool)
320 {
321 // phpcs:enable
322 $this->hideYGrid = $bool;
323 return true;
324 }
325
326 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
333 public function SetYLabel($label)
334 {
335 // phpcs:enable
336 $this->YLabel = $label;
337 }
338
339 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
346 public function SetWidth($w)
347 {
348 // phpcs:enable
349 $this->width = $w;
350 }
351
352 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
359 public function SetTitle($title)
360 {
361 // phpcs:enable
362 $this->title = $title;
363 }
364
365 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
373 public function SetData($data)
374 {
375 // phpcs:enable
376 $this->data = $data;
377 }
378
379 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
386 public function SetDataColor($datacolor)
387 {
388 // phpcs:enable
389 $this->datacolor = $datacolor;
390 }
391
398 public function setBorderColor($bordercolor)
399 {
400 $this->bordercolor = $bordercolor;
401 }
402
409 public function setBorderWidth($borderwidth)
410 {
411 $this->borderwidth = $borderwidth;
412 }
413
421 public function setBorderSkip($borderskip)
422 {
423 $this->borderskip = $borderskip;
424 }
425
432 public function setTooltipsLabels($tooltipsLabels)
433 {
434 $this->tooltipsLabels = $tooltipsLabels;
435 }
436
443 public function setTooltipsTitles($tooltipsTitles)
444 {
445 $this->tooltipsTitles = $tooltipsTitles;
446 }
447
448 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
456 public function SetType($type)
457 {
458 // phpcs:enable
459 $this->type = $type;
460 }
461
462 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
469 public function SetLegend($legend)
470 {
471 // phpcs:enable
472 $this->Legend = $legend;
473 }
474
475 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
482 public function SetLegendWidthMin($legendwidthmin)
483 {
484 // phpcs:enable
485 $this->LegendWidthMin = $legendwidthmin;
486 }
487
488 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
495 public function SetMaxValue($max)
496 {
497 // phpcs:enable
498 $this->MaxValue = $max;
499 }
500
501 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
507 public function GetMaxValue()
508 {
509 // phpcs:enable
510 return $this->MaxValue;
511 }
512
513 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
520 public function SetMinValue($min)
521 {
522 // phpcs:enable
523 $this->MinValue = $min;
524 }
525
526 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
532 public function GetMinValue()
533 {
534 // phpcs:enable
535 return $this->MinValue;
536 }
537
538 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
545 public function SetHeight($h)
546 {
547 // phpcs:enable
548 $this->height = $h;
549 }
550
551 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
558 public function SetShading($s)
559 {
560 // phpcs:enable
561 $this->SetShading = $s;
562 }
563
564 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
571 public function SetCssPrefix($s)
572 {
573 // phpcs:enable
574 $this->cssprefix = $s;
575 }
576
577 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
583 public function ResetBgColor()
584 {
585 // phpcs:enable
586 unset($this->bgcolor);
587 }
588
589 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
595 public function ResetBgColorGrid()
596 {
597 // phpcs:enable
598 unset($this->bgcolorgrid);
599 }
600
607 public function setMirrorGraphValues($mirrorGraphValues)
608 {
609 $this->mirrorGraphValues = $mirrorGraphValues;
610 }
611
617 public function isGraphKo()
618 {
619 return $this->error;
620 }
621
628 public function setShowLegend($showlegend)
629 {
630 $this->showlegend = $showlegend;
631 }
632
639 public function setShowPointValue($showpointvalue)
640 {
641 $this->showpointvalue = $showpointvalue;
642 }
643
650 public function setShowPercent($showpercent)
651 {
652 $this->showpercent = $showpercent;
653 }
654
655
656
657 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
664 public function SetBgColor($bg_color = array(255, 255, 255))
665 {
666 // phpcs:enable
667 global $theme_bgcolor, $theme_bgcoloronglet;
668
669 if (!is_array($bg_color)) {
670 if ($bg_color == 'onglet') {
671 //print 'ee'.join(',',$theme_bgcoloronglet);
672 $this->bgcolor = $theme_bgcoloronglet;
673 } else {
674 $this->bgcolor = $theme_bgcolor;
675 }
676 } else {
677 $this->bgcolor = $bg_color;
678 }
679 }
680
681 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
688 public function SetBgColorGrid($bg_colorgrid = array(255, 255, 255))
689 {
690 // phpcs:enable
691 global $theme_bgcolor, $theme_bgcoloronglet;
692
693 if (!is_array($bg_colorgrid)) {
694 if ($bg_colorgrid == 'onglet') {
695 //print 'ee'.join(',',$theme_bgcoloronglet);
696 $this->bgcolorgrid = $theme_bgcoloronglet;
697 } else {
698 $this->bgcolorgrid = $theme_bgcolor;
699 }
700 } else {
701 $this->bgcolorgrid = $bg_colorgrid;
702 }
703 }
704
705 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
711 public function ResetDataColor()
712 {
713 // phpcs:enable
714 unset($this->datacolor);
715 }
716
717 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
723 public function GetMaxValueInData()
724 {
725 // phpcs:enable
726 if (!is_array($this->data)) {
727 return 0;
728 }
729
730 $max = null;
731
732 $nbseries = (empty($this->data[0]) ? 0 : count($this->data[0]) - 1);
733
734 foreach ($this->data as $x) { // Loop on each x
735 for ($i = 0; $i < $nbseries; $i++) { // Loop on each series
736 if (is_null($max)) {
737 if (isset($x[$i + 1])) {
738 $max = $x[$i + 1]; // $i+1 because the index 0 is the legend
739 }
740 } elseif ($max < $x[$i + 1]) {
741 $max = $x[$i + 1];
742 }
743 }
744 }
745
746 return $max;
747 }
748
749 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
755 public function GetMinValueInData()
756 {
757 // phpcs:enable
758 if (!is_array($this->data)) {
759 return 0;
760 }
761
762 $min = null;
763
764 $nbseries = (empty($this->data[0]) ? 0 : count($this->data[0]) - 1);
765
766 foreach ($this->data as $x) { // Loop on each x
767 for ($i = 0; $i < $nbseries; $i++) { // Loop on each series
768 if (is_null($min)) {
769 if (isset($x[$i + 1])) {
770 $min = $x[$i + 1]; // $i+1 because the index 0 is the legend
771 }
772 } elseif ($min > $x[$i + 1]) {
773 $min = $x[$i + 1];
774 }
775 }
776 }
777
778 return $min;
779 }
780
781 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
787 public function GetCeilMaxValue()
788 {
789 // phpcs:enable
790 $max = $this->GetMaxValueInData();
791 if (!isset($max)) {
792 $max = 0;
793 }
794 if ($max != 0) {
795 $max++;
796 }
797 $size = dol_strlen((string) abs(ceil($max)));
798 $factor = 1;
799 for ($i = 0; $i < ($size - 1); $i++) {
800 $factor *= 10;
801 }
802
803 $res = 0;
804 $res = ceil($max / $factor) * $factor;
805
806 //print "max=".$max." res=".$res;
807 return (int) $res;
808 }
809
810 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
816 public function GetFloorMinValue()
817 {
818 // phpcs:enable
819 $min = $this->GetMinValueInData();
820 if ($min == '') {
821 $min = 0;
822 }
823 if ($min != 0) {
824 $min--;
825 }
826 $size = dol_strlen((string) abs(floor($min)));
827 $factor = 1;
828 for ($i = 0; $i < ($size - 1); $i++) {
829 $factor *= 10;
830 }
831
832 $res = floor($min / $factor) * $factor;
833
834 //print "min=".$min." res=".$res;
835 return $res;
836 }
837
845 public function draw($file, $fileurl = '')
846 {
847 if (empty($file)) {
848 $this->error = "Call to draw method was made with empty value for parameter file.";
849 dol_syslog(get_class($this) . "::draw " . $this->error, LOG_ERR);
850 return -2;
851 }
852 if (!is_array($this->data)) {
853 $this->error = "Call to draw method was made but SetData was not called or called with an empty dataset for parameters";
854 dol_syslog(get_class($this) . "::draw " . $this->error, LOG_ERR);
855 return -1;
856 }
857 if (count($this->data) < 1) {
858 $this->error = "Call to draw method was made but SetData was is an empty dataset";
859 dol_syslog(get_class($this) . "::draw " . $this->error, LOG_WARNING);
860 }
861 $call = "draw_" . $this->_library; // Example "draw_jflot"
862
863 return call_user_func_array(array($this, $call), array($file, $fileurl));
864 }
865
866 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
883 private function draw_jflot($file, $fileurl) // @phpstan-ignore-line
884 {
885 // phpcs:enable
886 global $langs;
887
888 dol_syslog(get_class($this) . "::draw_jflot this->type=" . implode(',', $this->type) . " this->MaxValue=" . $this->MaxValue);
889
890 if (empty($this->width) && empty($this->height)) {
891 print 'Error width or height not set';
892 return;
893 }
894
895 $legends = array();
896 $nblot = 0;
897 if (is_array($this->data) && is_array($this->data[0])) {
898 $nblot = count($this->data[0]) - 1; // -1 to remove legend
899 }
900 if ($nblot < 0) {
901 dol_syslog('Bad value for property ->data. Must be set by mydolgraph->SetData before calling mydolgrapgh->draw', LOG_WARNING);
902 }
903 $firstlot = 0;
904 // Works with line but not with bars
905 //if ($nblot > 2) $firstlot = ($nblot - 2); // We limit nblot to 2 because jflot can't manage more than 2 bars on same x
906
907 $i = $firstlot;
908 $series = array();
909 while ($i < $nblot) { // Loop on each series
910 $values = array(); // Array with horizontal y values (specific values of a series) for each abscisse x
911 $series[$i] = "var d" . $i . " = [];\n";
912
913 // Fill array $values
914 $x = 0;
915 foreach ($this->data as $valarray) { // Loop on each x
916 $legends[$x] = $valarray[0];
917 $values[$x] = (is_numeric($valarray[$i + 1]) ? $valarray[$i + 1] : null);
918 $x++;
919 }
920
921 if (isset($this->type[$firstlot]) && in_array($this->type[$firstlot], array('pie', 'piesemicircle', 'polar'))) {
922 foreach ($values as $x => $y) {
923 if (isset($y)) {
924 $series[$i] .= 'd' . $i . '.push({"label":"' . dol_escape_js($legends[$x]) . '", "data":' . $y . '});' . "\n";
925 }
926 }
927 } else {
928 foreach ($values as $x => $y) {
929 if (isset($y)) {
930 $series[$i] .= 'd' . $i . '.push([' . $x . ', ' . $y . ']);' . "\n";
931 }
932 }
933 }
934
935 unset($values);
936 $i++;
937 }
938 $tag = dol_escape_htmltag(dol_string_unaccent(dol_string_nospecial(basename($file), '_', array('-', '.'))));
939
940 $this->stringtoshow = '<!-- Build using jflot -->' . "\n";
941 if (!empty($this->title)) {
942 $this->stringtoshow .= '<div class="center dolgraphtitle' . (empty($this->cssprefix) ? '' : ' dolgraphtitle' . $this->cssprefix) . '">' . $this->title . '</div>';
943 }
944 if (!empty($this->shownographyet)) {
945 $this->stringtoshow .= '<div style="width:' . $this->width . 'px;height:' . $this->height . 'px;" class="nographyet"></div>';
946 $this->stringtoshow .= '<div class="nographyettext margintoponly">' . $langs->trans("NotEnoughDataYet") . '...</div>';
947 return;
948 }
949
950 // Start the div that will contains all the graph
951 $dolxaxisvertical = '';
952 if (count($this->data) > 20) {
953 $dolxaxisvertical = 'dol-xaxis-vertical';
954 }
955 $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";
956
957 $this->stringtoshow .= '<script nonce="'.getNonce().'" id="' . $tag . '">' . "\n";
958 $this->stringtoshow .= '$(function () {' . "\n";
959 $i = $firstlot;
960 if ($nblot < 0) {
961 $this->stringtoshow .= '<!-- No series of data -->' . "\n";
962 } else {
963 while ($i < $nblot) {
964 $this->stringtoshow .= '<!-- Series ' . $i . ' -->' . "\n";
965 $this->stringtoshow .= $series[$i] . "\n";
966 $i++;
967 }
968 }
969 $this->stringtoshow .= "\n";
970
971 // Special case for Graph of type 'pie'
972 if (isset($this->type[$firstlot]) && in_array($this->type[$firstlot], array('pie', 'piesemicircle', 'polar'))) {
973 $datacolor = array();
974 foreach ($this->datacolor as $val) {
975 if (is_array($val)) {
976 $datacolor[] = "#" . sprintf("%02x%02x%02x", $val[0], $val[1], $val[2]); // If datacolor is array(R, G, B)
977 } else {
978 $datacolor[] = "#" . str_replace(array('#', '-'), '', $val); // If $val is '124' or '#124'
979 }
980 }
981
982 $urltemp = ''; // TODO Add support for url link into labels
983 $showlegend = $this->showlegend;
984 $showpointvalue = $this->showpointvalue;
985 $showpercent = $this->showpercent;
986
987 $this->stringtoshow .= '
988 function plotWithOptions_' . $tag . '() {
989 $.plot($("#placeholder_' . $tag . '"), d0,
990 {
991 series: {
992 pie: {
993 show: true,
994 radius: 0.8,
995 ' . ($this->combine ? '
996 combine: {
997 threshold: ' . $this->combine . '
998 },' : '') . '
999 label: {
1000 show: true,
1001 radius: 0.9,
1002 formatter: function(label, series) {
1003 var percent=Math.round(series.percent);
1004 var number=series.data[0][1];
1005 return \'';
1006 $this->stringtoshow .= '<span style="font-size:8pt;text-align:center;padding:2px;color:black;">';
1007 if ($urltemp) {
1008 $this->stringtoshow .= '<a style="color: #FFFFFF;" border="0" href="' . $urltemp . '">';
1009 }
1010 $this->stringtoshow .= '\'+';
1011 $this->stringtoshow .= ($showlegend ? '' : 'label+\' \'+'); // Hide label if already shown in legend
1012 $this->stringtoshow .= ($showpointvalue ? 'number+' : '');
1013 $this->stringtoshow .= ($showpercent ? '\'<br>\'+percent+\'%\'+' : '');
1014 $this->stringtoshow .= '\'';
1015 if ($urltemp) {
1016 $this->stringtoshow .= '</a>';
1017 }
1018 $this->stringtoshow .= '</span>\';
1019 },
1020 background: {
1021 opacity: 0.0,
1022 color: \'#000000\'
1023 }
1024 }
1025 }
1026 },
1027 zoom: {
1028 interactive: true
1029 },
1030 pan: {
1031 interactive: true
1032 },';
1033 if (count($datacolor)) {
1034 $this->stringtoshow .= 'colors: ' . json_encode($datacolor) . ',';
1035 }
1036 $this->stringtoshow .= 'legend: {show: ' . ($showlegend ? 'true' : 'false') . ', position: \'ne\' }
1037 });
1038 }' . "\n";
1039 } else {
1040 // Other cases, graph of type 'bars', 'lines'
1041 // Add code to support tooltips
1042 // TODO: remove js css and use graph-tooltip-inner class instead by adding css in each themes
1043 $this->stringtoshow .= '
1044 function showTooltip_' . $tag . '(x, y, contents) {
1045 $(\'<div class="graph-tooltip-inner" id="tooltip_' . $tag . '">\' + contents + \'</div>\').css({
1046 position: \'absolute\',
1047 display: \'none\',
1048 top: y + 10,
1049 left: x + 15,
1050 border: \'1px solid #000\',
1051 padding: \'5px\',
1052 \'background-color\': \'#000\',
1053 \'color\': \'#fff\',
1054 \'font-weight\': \'bold\',
1055 width: 200,
1056 opacity: 0.80
1057 }).appendTo("body").fadeIn(100);
1058 }
1059
1060 var previousPoint = null;
1061 $("#placeholder_' . $tag . '").bind("plothover", function (event, pos, item) {
1062 $("#x").text(pos.x.toFixed(2));
1063 $("#y").text(pos.y.toFixed(2));
1064
1065 if (item) {
1066 if (previousPoint != item.dataIndex) {
1067 previousPoint = item.dataIndex;
1068
1069 $("#tooltip").remove();
1070 /* console.log(item); */
1071 var x = item.datapoint[0].toFixed(2);
1072 var y = item.datapoint[1].toFixed(2);
1073 var z = item.series.xaxis.ticks[item.dataIndex].label;
1074 ';
1075 if ($this->showpointvalue > 0) {
1076 $this->stringtoshow .= '
1077 showTooltip_' . $tag . '(item.pageX, item.pageY, item.series.label + "<br>" + z + " => " + y);
1078 ';
1079 }
1080 $this->stringtoshow .= '
1081 }
1082 }
1083 else {
1084 $("#tooltip_' . $tag . '").remove();
1085 previousPoint = null;
1086 }
1087 });
1088 ';
1089
1090 $this->stringtoshow .= 'var stack = null, steps = false;' . "\n";
1091
1092 $this->stringtoshow .= 'function plotWithOptions_' . $tag . '() {' . "\n";
1093 $this->stringtoshow .= '$.plot($("#placeholder_' . $tag . '"), [ ' . "\n";
1094 $i = $firstlot;
1095 while ($i < $nblot) {
1096 if ($i > $firstlot) {
1097 $this->stringtoshow .= ', ' . "\n";
1098 }
1099 $color = sprintf("%02x%02x%02x", $this->datacolor[$i][0], $this->datacolor[$i][1], $this->datacolor[$i][2]);
1100 $this->stringtoshow .= '{ ';
1101 if (!isset($this->type[$i]) || $this->type[$i] == 'bars') {
1102 if ($nblot == 3) {
1103 if ($i == $firstlot) {
1104 $align = 'right';
1105 } elseif ($i == $firstlot + 1) {
1106 $align = 'center';
1107 } else {
1108 $align = 'left';
1109 }
1110 $this->stringtoshow .= 'bars: { lineWidth: 1, show: true, align: "' . $align . '", barWidth: 0.45 }, ';
1111 } else {
1112 $this->stringtoshow .= 'bars: { lineWidth: 1, show: true, align: "' . ($i == $firstlot ? 'center' : 'left') . '", barWidth: 0.5 }, ';
1113 }
1114 }
1115 if (isset($this->type[$i]) && ($this->type[$i] == 'lines' || $this->type[$i] == 'linesnopoint')) {
1116 $this->stringtoshow .= 'lines: { show: true, fill: false }, points: { show: ' . ($this->type[$i] == 'linesnopoint' ? 'false' : 'true') . ' }, ';
1117 }
1118 $this->stringtoshow .= 'color: "#' . $color . '", label: "' . (isset($this->Legend[$i]) ? dol_escape_js($this->Legend[$i]) : '') . '", data: d' . $i . ' }';
1119 $i++;
1120 }
1121 // shadowSize: 0 -> Drawing is faster without shadows
1122 $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";
1123
1124 // Xaxis
1125 $this->stringtoshow .= ', xaxis: { ticks: [' . "\n";
1126 $x = 0;
1127 foreach ($this->data as $key => $valarray) {
1128 if ($x > 0) {
1129 $this->stringtoshow .= ', ' . "\n";
1130 }
1131 $this->stringtoshow .= ' [' . $x . ', "' . $valarray[0] . '"]';
1132 $x++;
1133 }
1134 $this->stringtoshow .= '] }' . "\n";
1135
1136 // Yaxis
1137 $this->stringtoshow .= ', yaxis: { min: ' . $this->MinValue . ', max: ' . ($this->MaxValue) . ' }' . "\n";
1138
1139 // Background color
1140 $color1 = sprintf("%02x%02x%02x", $this->bgcolorgrid[0], $this->bgcolorgrid[0], $this->bgcolorgrid[2]);
1141 $color2 = sprintf("%02x%02x%02x", $this->bgcolorgrid[0], $this->bgcolorgrid[1], $this->bgcolorgrid[2]);
1142 $this->stringtoshow .= ', grid: { hoverable: true, backgroundColor: { colors: ["#' . $color1 . '", "#' . $color2 . '"] }, borderWidth: 1, borderColor: \'#e6e6e6\', tickColor : \'#e6e6e6\' }' . "\n";
1143 $this->stringtoshow .= '});' . "\n";
1144 $this->stringtoshow .= '}' . "\n";
1145 }
1146
1147 $this->stringtoshow .= 'plotWithOptions_' . $tag . '();' . "\n";
1148 $this->stringtoshow .= '});' . "\n";
1149 $this->stringtoshow .= '</script>' . "\n";
1150 }
1151
1152
1153 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1170 private function draw_chart($file, $fileurl) // @phpstan-ignore-line
1171 {
1172 // phpcs:enable
1173 global $langs;
1174
1175 dol_syslog(get_class($this) . "::draw_chart this->type=" . implode(',', $this->type) . " this->MaxValue=" . $this->MaxValue);
1176
1177 if (empty($this->width) && empty($this->height)) {
1178 print 'Error width or height not set';
1179 return;
1180 }
1181
1182 $showlegend = $this->showlegend;
1183 $bordercolor = "";
1184
1185 $legends = array();
1186 $nblot = 0;
1187 if (is_array($this->data)) {
1188 foreach ($this->data as $valarray) { // Loop on each x
1189 $nblot = max($nblot, count($valarray) - 1); // -1 to remove legend
1190 }
1191 }
1192 //var_dump($nblot);
1193 if ($nblot < 0) {
1194 dol_syslog('Bad value for property ->data. Must be set by mydolgraph->SetData before calling mydolgrapgh->draw', LOG_WARNING);
1195 }
1196 $firstlot = 0;
1197 // Works with line but not with bars
1198 //if ($nblot > 2) $firstlot = ($nblot - 2); // We limit nblot to 2 because jflot can't manage more than 2 bars on same x
1199
1200 $series = array();
1201 '@phan-var-force array<int,array{stacknum:int,legend:string,legendwithgroup:string}> $arrayofgroupslegend';
1202 $arrayofgroupslegend = array();
1203 //var_dump($this->data);
1204
1205 $i = $firstlot;
1206 while ($i < $nblot) { // Loop on each series
1207 $values = array(); // Array with horizontal y values (specific values of a series) for each abscisse x (with x=0,1,2,...)
1208 $series[$i] = "";
1209
1210 // Fill array $series from $this->data
1211 $x = 0;
1212 foreach ($this->data as $valarray) { // Loop on each x
1213 $legends[$x] = (array_key_exists('label', $valarray) ? $valarray['label'] : $valarray[0]);
1214 $array_of_ykeys = array_keys($valarray);
1215 $alabelexists = 1;
1216 $tmpykey = explode('_', (string) ($array_of_ykeys[$i + ($alabelexists ? 1 : 0)]), 3);
1217 if (isset($tmpykey[2]) && (!empty($tmpykey[2]) || $tmpykey[2] == '0')) { // This is a 'Group by' array
1218 $tmpvalue = (array_key_exists('y_' . $tmpykey[1] . '_' . $tmpykey[2], $valarray) ? $valarray['y_' . $tmpykey[1] . '_' . $tmpykey[2]] : $valarray[$i + 1]);
1219 $values[$x] = (is_numeric($tmpvalue) ? $tmpvalue : null);
1220 $arrayofgroupslegend[$i] = array(
1221 'stacknum' => (int) $tmpykey[1],
1222 'legend' => $this->Legend[$tmpykey[1]] ?? '',
1223 'legendwithgroup' => ($this->Legend[$tmpykey[1]] ?? '') . ' - ' . $tmpykey[2]
1224 );
1225 } else {
1226 $tmpvalue = (array_key_exists('y_' . $i, $valarray) ? $valarray['y_' . $i] : $valarray[$i + 1]);
1227 //var_dump($i.'_'.$x.'_'.$tmpvalue);
1228 $values[$x] = (is_numeric($tmpvalue) ? $tmpvalue : null);
1229 }
1230 $x++;
1231 }
1232 //var_dump($values);
1233 $j = 0;
1234 foreach ($values as $x => $y) {
1235 if (isset($y)) {
1236 $series[$i] .= ($j > 0 ? ", " : "") . $y;
1237 } else {
1238 $series[$i] .= ($j > 0 ? ", " : "") . 'null';
1239 }
1240 $j++;
1241 }
1242
1243 $values = null; // Free mem
1244 $i++;
1245 }
1246 //var_dump($series);
1247 //var_dump($arrayofgroupslegend);
1248
1249 $tag = dol_escape_htmltag(dol_string_unaccent(dol_string_nospecial(basename($file), '_', array('-', '.'))));
1250
1251 $this->stringtoshow = '<!-- Build using chart -->' . "\n";
1252 if (!empty($this->title)) {
1253 $this->stringtoshow .= '<div class="center dolgraphtitle' . (empty($this->cssprefix) ? '' : ' dolgraphtitle' . $this->cssprefix) . '">' . $this->title . '</div>';
1254 }
1255 if (!empty($this->shownographyet)) {
1256 $this->stringtoshow .= '<div style="width:' . $this->width . (strpos($this->width, '%') > 0 ? '' : 'px') . '; height:' . $this->height . 'px;" class="nographyet"></div>';
1257 $this->stringtoshow .= '<div class="nographyettext margintoponly">' . $langs->trans("NotEnoughDataYet") . '...</div>';
1258 return;
1259 }
1260
1261 // Start the div that will contains all the graph
1262 $dolxaxisvertical = '';
1263 if (count($this->data) > 20) {
1264 $dolxaxisvertical = 'dol-xaxis-vertical';
1265 }
1266 // No height for the pie graph
1267 $cssfordiv = 'dolgraphchart';
1268 if (isset($this->type[$firstlot])) {
1269 $cssfordiv .= ' dolgraphchar' . $this->type[$firstlot];
1270 }
1271 $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";
1272 $this->stringtoshow .= '<canvas id="canvas_'.$tag.'"></canvas></div>'."\n";
1273
1274 $this->stringtoshow .= '<script nonce="'.getNonce().'" id="' . $tag . '">' . "\n";
1275 $i = $firstlot;
1276 if ($nblot < 0) {
1277 $this->stringtoshow .= '<!-- No series of data -->';
1278 } else {
1279 while ($i < $nblot) {
1280 //$this->stringtoshow .= '<!-- Series '.$i.' -->'."\n";
1281 //$this->stringtoshow .= $series[$i]."\n";
1282 $i++;
1283 }
1284 }
1285 $this->stringtoshow .= "\n";
1286
1287 // Special case for Graph of type 'pie', 'piesemicircle', or 'polar'
1288 if (isset($this->type[$firstlot]) && (in_array($this->type[$firstlot], array('pie', 'polar', 'piesemicircle')))) {
1289 $type = $this->type[$firstlot]; // pie or polar
1290 //$this->stringtoshow .= 'var options = {' . "\n";
1291 $this->stringtoshow .= 'var options = { maintainAspectRatio: false, aspectRatio: 2.5, ';
1292
1293
1294 $legendMaxLines = 0; // Does not work
1295
1296 /* For Chartjs v2.9 */
1297 if (empty($showlegend)) {
1298 $this->stringtoshow .= 'legend: { display: false }, ';
1299 } else {
1300 $this->stringtoshow .= 'legend: { labels: { boxWidth: 15 }, position: \'' . ($showlegend == 2 ? 'right' : 'top') . '\'';
1301 if (!empty($legendMaxLines)) {
1302 $this->stringtoshow .= ', maxLines: ' . $legendMaxLines;
1303 }
1304 $this->stringtoshow .= ' }, ' . "\n";
1305 }
1306
1307 /* For Chartjs v3.5 */
1308 $this->stringtoshow .= 'plugins: { ';
1309 if (empty($showlegend)) {
1310 $this->stringtoshow .= 'legend: { display: false }, ';
1311 } else {
1312 $this->stringtoshow .= 'legend: { labels: { boxWidth: 15 }, position: \'' . ($showlegend == 2 ? 'right' : 'top') . '\'';
1313 if (!empty($legendMaxLines)) {
1314 $this->stringtoshow .= ', maxLines: ' . $legendMaxLines;
1315 }
1316 $this->stringtoshow .= ' }, ' . "\n";
1317 }
1318 $this->stringtoshow .= ' }, ' . "\n";
1319
1320
1321 if ($this->type[$firstlot] == 'piesemicircle') {
1322 $this->stringtoshow .= 'circumference: Math.PI,' . "\n";
1323 $this->stringtoshow .= 'rotation: -Math.PI,' . "\n";
1324 }
1325 $this->stringtoshow .= 'elements: { arc: {' . "\n";
1326 // Color of each arc
1327 $this->stringtoshow .= 'backgroundColor: [';
1328 $i = 0;
1329 $foundnegativecolor = 0;
1330 foreach ($legends as $val) { // Loop on each series
1331 if ($i > 0) {
1332 $this->stringtoshow .= ', ' . "\n";
1333 }
1334 if (is_array($this->datacolor[$i])) {
1335 $color = 'rgb(' . $this->datacolor[$i][0] . ', ' . $this->datacolor[$i][1] . ', ' . $this->datacolor[$i][2] . ')'; // If datacolor is array(R, G, B)
1336 } else {
1337 $tmp = str_replace('#', '', $this->datacolor[$i]);
1338 if (strpos($tmp, '-') !== false) {
1339 $foundnegativecolor++;
1340 $color = 'rgba(0,0,0,.0)'; // If $val is '-123'
1341 } else {
1342 $color = "#" . $tmp; // If $val is '123' or '#123'
1343 }
1344 }
1345 $this->stringtoshow .= "'" . $color . "'";
1346 $i++;
1347 }
1348 $this->stringtoshow .= '], ' . "\n";
1349 // Border color
1350 if ($foundnegativecolor) {
1351 $this->stringtoshow .= 'borderColor: [';
1352 $i = 0;
1353 foreach ($legends as $val) { // Loop on each series
1354 if ($i > 0) {
1355 $this->stringtoshow .= ', ' . "\n";
1356 }
1357 if ($this->datacolor !== null) {
1358 $datacolor_item = $this->datacolor[$i];
1359 } else {
1360 $datacolor_item = null;
1361 }
1362
1363 if (is_array($datacolor_item) || $datacolor_item === null) {
1364 $color = 'null'; // If datacolor is array(R, G, B)
1365 } else {
1366 $tmpcolor = str_replace('#', '', $datacolor_item);
1367 if (strpos($tmpcolor, '-') !== false) {
1368 $color = '#' . str_replace('-', '', $tmpcolor); // If $val is '-123'
1369 } else {
1370 $color = 'null'; // If $val is '123' or '#123'
1371 }
1372 }
1373 $this->stringtoshow .= ($color == 'null' ? "'rgba(0,0,0,0.2)'" : "'" . $color . "'");
1374 $i++;
1375 }
1376 $this->stringtoshow .= ']';
1377 }
1378 $this->stringtoshow .= '} } };' . "\n";
1379
1380 $this->stringtoshow .= '
1381 var ctx = document.getElementById("canvas_' . $tag . '").getContext("2d");
1382 var chart = new Chart(ctx, {
1383 // The type of chart we want to create
1384 type: \'' . (in_array($type, array('pie', 'piesemicircle')) ? 'doughnut' : 'polarArea') . '\',
1385 // Configuration options go here
1386 options: options,
1387 data: {
1388 labels: [';
1389
1390 $i = 0;
1391 foreach ($legends as $val) { // Loop on each series
1392 if ($i > 0) {
1393 $this->stringtoshow .= ', ';
1394 }
1395 $this->stringtoshow .= "'" . dol_escape_js(dol_trunc($val, 25)) . "'"; // Lower than 25 make some important label (that we can't shorten) to be truncated
1396 $i++;
1397 }
1398
1399 $this->stringtoshow .= '],
1400 datasets: [';
1401 $i = 0;
1402 while ($i < $nblot) { // Loop on each series
1403 $color = 'rgb(' . $this->datacolor[$i][0] . ', ' . $this->datacolor[$i][1] . ', ' . $this->datacolor[$i][2] . ')';
1404
1405 if ($i > 0) {
1406 $this->stringtoshow .= ', ' . "\n";
1407 }
1408 $this->stringtoshow .= '{' . "\n";
1409 //$this->stringtoshow .= 'borderColor: \''.$color.'\', ';
1410 //$this->stringtoshow .= 'backgroundColor: \''.$color.'\', ';
1411 $this->stringtoshow .= ' data: [' . $series[$i] . ']';
1412 $this->stringtoshow .= '}' . "\n";
1413 $i++;
1414 }
1415 $this->stringtoshow .= ']' . "\n";
1416 $this->stringtoshow .= '}' . "\n";
1417 $this->stringtoshow .= '});' . "\n";
1418 } else {
1419 // Other cases, graph of type 'bars', 'lines', 'linesnopoint'
1420 $type = 'bar';
1421 $xaxis = '';
1422
1423 if (isset($this->type[$firstlot]) && $this->type[$firstlot] == 'horizontalbars') {
1424 $xaxis = "indexAxis: 'y', ";
1425 }
1426 if (isset($this->type[$firstlot]) && ($this->type[$firstlot] == 'lines' || $this->type[$firstlot] == 'linesnopoint')) {
1427 $type = 'line';
1428 }
1429
1430 // Set options
1431 $this->stringtoshow .= 'var options = { maintainAspectRatio: false, aspectRatio: 2.5, ';
1432 $this->stringtoshow .= $xaxis;
1433 if ($this->showpointvalue == 2) {
1434 $this->stringtoshow .= 'interaction: { intersect: true, mode: \'index\'}, ';
1435 }
1436
1437 /* For Chartjs v2.9 */
1438 /*
1439 if (empty($showlegend)) {
1440 $this->stringtoshow .= 'legend: { display: false }, '."\n";
1441 } else {
1442 $this->stringtoshow .= 'legend: { maxWidth: '.round($this->width / 2).', labels: { boxWidth: 15 }, position: \'' . ($showlegend == 2 ? 'right' : 'top') . '\' }, '."\n";
1443 }
1444 */
1445
1446 /* For Chartjs v3.5 */
1447 $this->stringtoshow .= 'plugins: { '."\n";
1448 if (empty($showlegend)) {
1449 $this->stringtoshow .= 'legend: { display: false }, '."\n";
1450 } else {
1451 $this->stringtoshow .= 'legend: { maxWidth: '.round(intval($this->width) / 2).', labels: { boxWidth: 15 }, position: \'' . (($showlegend && $showlegend == 2) ? 'right' : 'top') . '\' },'."\n";
1452 }
1453 if (is_array($this->tooltipsLabels) || is_array($this->tooltipsTitles)) {
1454 $this->stringtoshow .= 'tooltip: { mode: \'nearest\',
1455 callbacks: {';
1456 if (is_array($this->tooltipsTitles)) {
1457 $this->stringtoshow .= '
1458 title: function(tooltipItem, data) {
1459 var tooltipsTitle ='.json_encode($this->tooltipsTitles).'
1460 return tooltipsTitle[tooltipItem[0].datasetIndex];
1461 },';
1462 }
1463 if (is_array($this->tooltipsLabels)) {
1464 $this->stringtoshow .= 'label: function(tooltipItem, data) {
1465 var tooltipslabels ='.json_encode($this->tooltipsLabels).'
1466 return tooltipslabels[tooltipItem.datasetIndex]
1467 }';
1468 }
1469 $this->stringtoshow .= '}},';
1470 }
1471 $this->stringtoshow .= "}, \n";
1472
1473 /* For Chartjs v2.9 */
1474 /*
1475 $this->stringtoshow .= 'scales: { xAxis: [{ ';
1476 if ($this->hideXValues) {
1477 $this->stringtoshow .= ' ticks: { display: false }, display: true,';
1478 }
1479 //$this->stringtoshow .= 'type: \'time\', '; // Need Moment.js
1480 $this->stringtoshow .= 'distribution: \'linear\'';
1481 if ($type == 'bar' && count($arrayofgroupslegend) > 0) {
1482 $this->stringtoshow .= ', stacked: true';
1483 }
1484 $this->stringtoshow .= ' }]';
1485 $this->stringtoshow .= ', yAxis: [{ ticks: { beginAtZero: true }';
1486 if ($type == 'bar' && count($arrayofgroupslegend) > 0) {
1487 $this->stringtoshow .= ', stacked: true';
1488 }
1489 $this->stringtoshow .= ' }] }';
1490 */
1491
1492 // Add a callback to change label to show only positive value
1493 if (is_array($this->tooltipsLabels) || is_array($this->tooltipsTitles)) {
1494 $this->stringtoshow .= 'tooltips: { mode: \'nearest\',
1495 callbacks: {';
1496 if (is_array($this->tooltipsTitles)) {
1497 $this->stringtoshow .= '
1498 title: function(tooltipItem, data) {
1499 var tooltipsTitle ='.json_encode($this->tooltipsTitles).'
1500 return tooltipsTitle[tooltipItem[0].datasetIndex];
1501 },';
1502 }
1503 if (is_array($this->tooltipsLabels)) {
1504 $this->stringtoshow .= 'label: function(tooltipItem, data) {
1505 var tooltipslabels ='.json_encode($this->tooltipsLabels).'
1506 return tooltipslabels[tooltipItem.datasetIndex]
1507 }';
1508 }
1509 $this->stringtoshow .= '}},';
1510 }
1511 $this->stringtoshow .= '};';
1512 $this->stringtoshow .= '
1513 var ctx = document.getElementById("canvas_' . $tag . '").getContext("2d");
1514 var chart = new Chart(ctx, {
1515 // The type of chart we want to create
1516 type: \'' . $type . '\',
1517 // Configuration options go here
1518 options: options,
1519 data: {
1520 labels: [';
1521
1522 $i = 0;
1523 foreach ($legends as $val) { // Loop on each series
1524 if ($i > 0) {
1525 $this->stringtoshow .= ', ';
1526 }
1527 $this->stringtoshow .= "'" . dol_escape_js(dol_trunc($val, 32)) . "'";
1528 $i++;
1529 }
1530
1531 //var_dump($arrayofgroupslegend);
1532
1533 $this->stringtoshow .= '],
1534 datasets: [';
1535
1536 global $theme_datacolor;
1537 '@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';
1538 //var_dump($arrayofgroupslegend);
1539 $i = 0;
1540 $iinstack = 0;
1541 $oldstacknum = -1;
1542 $color = '#000000';
1543 while ($i < $nblot) { // Loop on each series
1544 $foundnegativecolor = 0;
1545 $usecolorvariantforgroupby = 0;
1546 // We used a 'group by' and we have too many colors so we generated color variants per
1547 if (!empty($arrayofgroupslegend) && is_array($arrayofgroupslegend[$i]) && count($arrayofgroupslegend[$i]) > 0) { // If we used a group by.
1548 $nbofcolorneeds = count($arrayofgroupslegend);
1549 $nbofcolorsavailable = count($theme_datacolor);
1550 if ($nbofcolorneeds > $nbofcolorsavailable) {
1551 $usecolorvariantforgroupby = 1;
1552 }
1553
1554 $textoflegend = $arrayofgroupslegend[$i]['legendwithgroup'];
1555 } else {
1556 $textoflegend = !empty($this->Legend[$i]) ? $this->Legend[$i] : '';
1557 }
1558
1559 if ($usecolorvariantforgroupby) {
1560 $idx = $arrayofgroupslegend[$i]['stacknum'];
1561
1562 $newcolor = $this->datacolor[$idx];
1563 // If we change the stack
1564 if ($oldstacknum == -1 || $idx != $oldstacknum) {
1565 $iinstack = 0;
1566 }
1567
1568 //var_dump($iinstack);
1569 if ($iinstack) {
1570 // Change color with offset of $iinstack
1571 //var_dump($newcolor);
1572 if ($iinstack % 2) { // We increase aggressiveness of reference color for color 2, 4, 6, ...
1573 $ratio = min(95, 10 + 10 * $iinstack); // step of 20
1574 $brightnessratio = min(90, 5 + 5 * $iinstack); // step of 10
1575 } else { // We decrease aggressiveness of reference color for color 3, 5, 7, ..
1576 $ratio = max(-100, -15 * $iinstack + 10); // step of -20
1577 $brightnessratio = min(90, 10 * $iinstack); // step of 20
1578 }
1579 //var_dump('Color '.($iinstack+1).' : '.$ratio.' '.$brightnessratio);
1580
1581 $newcolor = array_values(colorHexToRgb(colorAgressiveness(colorArrayToHex($newcolor), $ratio, $brightnessratio), false, true));
1582 }
1583 $oldstacknum = $arrayofgroupslegend[$i]['stacknum'];
1584
1585 $color = 'rgb(' . $newcolor[0] . ', ' . $newcolor[1] . ', ' . $newcolor[2] . ', 0.9)';
1586 $bordercolor = 'rgb(' . $newcolor[0] . ', ' . $newcolor[1] . ', ' . $newcolor[2] . ')';
1587 } else { // We do not use a 'group by'
1588 if (!empty($this->datacolor[$i])) {
1589 if (is_array($this->datacolor[$i])) {
1590 $color = 'rgb(' . $this->datacolor[$i][0] . ', ' . $this->datacolor[$i][1] . ', ' . $this->datacolor[$i][2] . ', 0.9)';
1591 } else {
1592 $color = $this->datacolor[$i];
1593 }
1594 }
1595 // else: $color will be undefined
1596 if (!empty($this->bordercolor[$i]) && is_array($this->bordercolor[$i])) {
1597 $bordercolor = 'rgb(' . $this->bordercolor[$i][0] . ', ' . $this->bordercolor[$i][1] . ', ' . $this->bordercolor[$i][2] . ', 0.9)';
1598 } else {
1599 if ($type != 'horizontalBar') {
1600 $bordercolor = $color;
1601 } else {
1602 $bordercolor = $this->bordercolor[$i];
1603 }
1604 }
1605
1606 // For negative colors, we invert border and background
1607 $tmp = str_replace('#', '', $color);
1608 if (strpos($tmp, '-') !== false) {
1609 $foundnegativecolor++;
1610 $bordercolor = str_replace('-', '', $color);
1611 $color = '#FFFFFF'; // If $val is '-123'
1612 }
1613 }
1614 if ($i > 0) {
1615 $this->stringtoshow .= ', ';
1616 }
1617 $this->stringtoshow .= "\n";
1618 $this->stringtoshow .= '{';
1619 $this->stringtoshow .= 'dolibarrinfo: \'y_' . $i . '\', ';
1620 $this->stringtoshow .= 'label: \'' . dol_escape_js(dol_string_nohtmltag($textoflegend)) . '\', ';
1621 $this->stringtoshow .= 'pointStyle: \'' . ((!empty($this->type[$i]) && $this->type[$i] == 'linesnopoint') ? 'line' : 'circle') . '\', ';
1622 $this->stringtoshow .= 'fill: ' . ($type == 'bar' ? 'true' : 'false') . ', ';
1623 if ($type == 'bar' || $type == 'horizontalBar') {
1624 $this->stringtoshow .= 'borderWidth: \''.$this->borderwidth.'\', ';
1625 }
1626 $this->stringtoshow .= 'borderColor: \'' . $bordercolor . '\', ';
1627 $this->stringtoshow .= 'borderSkipped: \'' . $this->borderskip . '\', ';
1628 $this->stringtoshow .= 'backgroundColor: \'' . $color . '\', ';
1629 if (!empty($arrayofgroupslegend) && !empty($arrayofgroupslegend[$i])) {
1630 $this->stringtoshow .= 'stack: \'' . $arrayofgroupslegend[$i]['stacknum'] . '\', ';
1631 }
1632 $this->stringtoshow .= 'data: [';
1633
1634 $this->stringtoshow .= $this->mirrorGraphValues ? '[-' . $series[$i] . ',' . $series[$i] . ']' : $series[$i];
1635 $this->stringtoshow .= ']';
1636 $this->stringtoshow .= '}' . "\n";
1637
1638 $i++;
1639 $iinstack++;
1640 }
1641 $this->stringtoshow .= ']' . "\n";
1642 $this->stringtoshow .= '}' . "\n";
1643 $this->stringtoshow .= '});' . "\n";
1644 }
1645
1646 $this->stringtoshow .= '</script>' . "\n";
1647 }
1648
1649
1655 public function total()
1656 {
1657 $value = 0;
1658 foreach ($this->data as $valarray) { // Loop on each x
1659 $value += $valarray[1];
1660 }
1661 return $value;
1662 }
1663
1670 public function show($shownographyet = 0)
1671 {
1672 global $langs;
1673
1674 if ($shownographyet) {
1675 $s = '<div class="nographyet" style="max-width: 400px; width:' . (preg_match('/%/', $this->width) ? $this->width : $this->width . 'px') . '; height:' . (preg_match('/%/', $this->height) ? $this->height : $this->height . 'px') . ';"></div>';
1676 $s .= '<div class="nographyettext margintoponly">';
1677 if (is_numeric($shownographyet)) {
1678 $s .= $langs->trans("NotEnoughDataYet") . '...';
1679 } else {
1680 $s .= $shownographyet . '...';
1681 }
1682 $s .= '</div>';
1683 return $s;
1684 }
1685
1686 return $this->stringtoshow;
1687 }
1688
1689
1697 public static function getDefaultGraphSizeForStats($direction, $defaultsize = '')
1698 {
1699 global $conf;
1700 $defaultsize = (int) $defaultsize;
1701
1702 if ($direction == 'width') {
1703 if (empty($conf->dol_optimize_smallscreen)) {
1704 return ($defaultsize ? $defaultsize : 500);
1705 } else {
1706 return (empty($_SESSION['dol_screenwidth']) ? 280 : ($_SESSION['dol_screenwidth'] - 40));
1707 }
1708 } elseif ($direction == 'height') {
1709 return (empty($conf->dol_optimize_smallscreen) ? ($defaultsize ? $defaultsize : 220) : 200);
1710 }
1711 return 0;
1712 }
1713}
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.
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...
global $conf
The following vars must be defined: $type2label $form $conf, $lang, The following vars may also be de...
Definition member.php:79
if(preg_match('/(crypted|dolcrypt):/i', $dolibarr_main_db_pass)||!empty($dolibarr_main_db_encrypted_pass)) $conf db type
Definition repair.php:158