1<?php 2/* 3** Zabbix 4** Copyright (C) 2001-2021 Zabbix SIA 5** 6** This program is free software; you can redistribute it and/or modify 7** it under the terms of the GNU General Public License as published by 8** the Free Software Foundation; either version 2 of the License, or 9** (at your option) any later version. 10** 11** This program is distributed in the hope that it will be useful, 12** but WITHOUT ANY WARRANTY; without even the implied warranty of 13** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14** GNU General Public License for more details. 15** 16** You should have received a copy of the GNU General Public License 17** along with this program; if not, write to the Free Software 18** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19**/ 20 21 22abstract class CGraphDraw { 23 24 /** 25 * Default top padding including header label height and vertical padding. 26 */ 27 const DEFAULT_HEADER_PADDING_TOP = 36; 28 /** 29 * Default font size for header label text. 30 */ 31 const DEFAULT_HEADER_LABEL_FONT_SIZE = 11; 32 /** 33 * Default value for top and bottom padding. 34 */ 35 const DEFAULT_TOP_BOTTOM_PADDING = 12; 36 37 /** 38 * Header label visibility. 39 */ 40 public $draw_header = true; 41 /** 42 * Use top and bottom padding for graph image. 43 */ 44 public $with_vertical_padding = true; 45 46 public function __construct($type = GRAPH_TYPE_NORMAL) { 47 $this->stime = null; 48 $this->fullSizeX = null; 49 $this->fullSizeY = null; 50 $this->m_minY = null; 51 $this->m_maxY = null; 52 $this->data = []; 53 $this->items = []; 54 $this->min = null; 55 $this->max = null; 56 $this->avg = null; 57 $this->clock = null; 58 $this->count = null; 59 $this->header = null; 60 $this->from_time = null; 61 $this->to_time = null; 62 $this->colors = null; 63 $this->colorsrgb = null; 64 $this->im = null; 65 $this->period = SEC_PER_HOUR; 66 $this->sizeX = 900; // default graph size X 67 $this->sizeY = 200; // default graph size Y 68 $this->shiftXleft = 100; 69 $this->shiftXright = 50; 70 $this->shiftXCaption = 0; 71 $this->num = 0; 72 $this->type = $type; // graph type 73 $this->drawLegend = 1; 74 $this->graphtheme = getUserGraphTheme(); 75 $this->shiftY = 0; 76 } 77 78 /** 79 * Recalculate $this->shiftY property for graph according header label visibility settings and visibility of graph 80 * top and bottom padding settings. 81 */ 82 protected function calculateTopPadding() { 83 $shift = static::DEFAULT_HEADER_PADDING_TOP; 84 85 if (!$this->draw_header) { 86 $shift -= static::DEFAULT_HEADER_LABEL_FONT_SIZE; 87 } 88 89 if (!$this->with_vertical_padding) { 90 $shift -= static::DEFAULT_TOP_BOTTOM_PADDING; 91 } 92 93 $this->shiftY = $shift; 94 } 95 96 public function initColors() { 97 // red, green, blue, alpha 98 $this->colorsrgb = [ 99 'Red' => [255, 0, 0, 50], 100 'Dark Red' => [150, 0, 0, 50], 101 'Green' => [0, 255, 0, 50], 102 'Dark Green' => [0, 150, 0, 50], 103 'Blue' => [0, 0, 255, 50], 104 'Dark Blue' => [0, 0, 150, 50], 105 'Yellow' => [255, 255, 0, 50], 106 'Dark Yellow' => [150, 150, 0, 50], 107 'Cyan' => [0, 255, 255, 50], 108 'Dark Cyan' => [0, 150, 150, 50], 109 'Black' => [0, 0, 0, 50], 110 'Gray' => [150, 150, 150, 50], 111 'White' => [255, 255, 255], 112 'Dark Red No Alpha' => [150, 0, 0], 113 'Black No Alpha' => [0, 0, 0], 114 'HistoryMinMax' => [90, 150, 185, 50], 115 'HistoryMax' => [255, 100, 100, 50], 116 'HistoryMin' => [50, 255, 50, 50], 117 'HistoryAvg' => [50, 50, 50, 50], 118 'ValueMinMax' => [255, 255, 150, 50], 119 'ValueMax' => [255, 180, 180, 50], 120 'ValueMin' => [100, 255, 100, 50], 121 'Not Work Period' => [230, 230, 230], 122 'UnknownData' => [130, 130, 130, 50] 123 ]; 124 125 // i should rename no alpha to alpha at some point to get rid of some confusion 126 foreach ($this->colorsrgb as $name => $RGBA) { 127 if (isset($RGBA[3]) && function_exists('imagecolorexactalpha') 128 && function_exists('imagecreatetruecolor') && @imagecreatetruecolor(1, 1)) { 129 $this->colors[$name] = imagecolorexactalpha($this->im, $RGBA[0], $RGBA[1], $RGBA[2], $RGBA[3]); 130 } 131 else { 132 $this->colors[$name] = imagecolorallocate($this->im, $RGBA[0], $RGBA[1], $RGBA[2]); 133 } 134 } 135 } 136 137 public function showLegend($type = true) { 138 $this->drawLegend = $type; 139 } 140 141 public function setPeriod($period) { 142 $this->period = $period; 143 } 144 145 public function setSTime($stime) { 146 if ($stime > 19000000000000 && $stime < 21000000000000) { 147 $this->stime = zbxDateToTime($stime); 148 } 149 else { 150 $this->stime = $stime; 151 } 152 } 153 154 public function setWidth($value = null) { 155 // avoid sizex==0, to prevent division by zero later 156 if ($value == 0) { 157 $value = null; 158 } 159 if (is_null($value)) { 160 $value = 900; 161 } 162 $this->sizeX = $value; 163 } 164 165 public function setHeight($value = null) { 166 if ($value == 0) { 167 $value = null; 168 } 169 if (is_null($value)) { 170 $value = 200; 171 } 172 $this->sizeY = $value; 173 } 174 175 public function getWidth() { 176 return $this->sizeX; 177 } 178 179 public function getHeight() { 180 return $this->sizeY; 181 } 182 183 public function getLastValue($num) { 184 $data = &$this->data[$this->items[$num]['itemid']]; 185 186 if (isset($data)) { 187 for ($i = $this->sizeX - 1; $i >= 0; $i--) { 188 if (!empty($data['count'][$i])) { 189 switch ($this->items[$num]['calc_fnc']) { 190 case CALC_FNC_MIN: 191 return $data['min'][$i]; 192 case CALC_FNC_MAX: 193 return $data['max'][$i]; 194 case CALC_FNC_ALL: 195 case CALC_FNC_AVG: 196 default: 197 return $data['avg'][$i]; 198 } 199 } 200 } 201 } 202 203 return 0; 204 } 205 206 public function drawRectangle() { 207 imagefilledrectangle($this->im, 0, 0, 208 $this->fullSizeX, 209 $this->fullSizeY, 210 $this->getColor($this->graphtheme['backgroundcolor'], 0) 211 ); 212 } 213 214 public function drawHeader() { 215 if (!$this->draw_header) { 216 return; 217 } 218 219 if (!isset($this->header)) { 220 $str = $this->items[0]['hostname'].NAME_DELIMITER.$this->items[0]['name']; 221 } 222 else { 223 // TODO: graphs shouldn't resolve names themselves 224 $str = CMacrosResolverHelper::resolveGraphName($this->header, $this->items); 225 } 226 227 // calculate largest font size that can fit graph header 228 // TODO: font size must be dynamic in other parts of the graph as well, like legend, timeline, etc 229 for ($fontsize = static::DEFAULT_HEADER_LABEL_FONT_SIZE; $fontsize > 7; $fontsize--) { 230 $dims = imageTextSize($fontsize, 0, $str); 231 $x = $this->fullSizeX / 2 - ($dims['width'] / 2); 232 233 // Most important information must be displayed. 234 if ($x < 2) { 235 $x = 2; 236 } 237 if ($dims['width'] <= $this->fullSizeX) { 238 break; 239 } 240 } 241 $y_baseline = 24; 242 243 if (!$this->with_vertical_padding) { 244 $y_baseline -= static::DEFAULT_TOP_BOTTOM_PADDING; 245 } 246 247 imageText($this->im, $fontsize, 0, $x, $y_baseline, $this->getColor($this->graphtheme['textcolor'], 0), $str); 248 } 249 250 public function setHeader($header) { 251 $this->header = $header; 252 } 253 254 public function getColor($color, $alfa = 50) { 255 if (isset($this->colors[$color])) { 256 return $this->colors[$color]; 257 } 258 259 return get_color($this->im, $color, $alfa); 260 } 261 262 public function getShadow($color, $alfa = 0) { 263 if (isset($this->colorsrgb[$color])) { 264 $red = $this->colorsrgb[$color][0]; 265 $green = $this->colorsrgb[$color][1]; 266 $blue = $this->colorsrgb[$color][2]; 267 } 268 else { 269 list($red, $green, $blue) = hex2rgb($color); 270 } 271 272 if ($this->sum > 0) { 273 $red = (int)($red * 0.6); 274 $green = (int)($green * 0.6); 275 $blue = (int)($blue * 0.6); 276 } 277 278 $RGB = [$red, $green, $blue]; 279 280 if (isset($alfa) && function_exists('imagecolorexactalpha') && function_exists('imagecreatetruecolor') 281 && @imagecreatetruecolor(1, 1)) { 282 return imagecolorexactalpha($this->im, $RGB[0], $RGB[1], $RGB[2], $alfa); 283 } 284 285 return imagecolorallocate($this->im, $RGB[0], $RGB[1], $RGB[2]); 286 } 287} 288