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 22class CPieGraphDraw extends CGraphDraw { 23 24 const DEFAULT_HEADER_PADDING_TOP = 30; 25 26 const GRAPH_WIDTH_MIN = 20; 27 const GRAPH_HEIGHT_MIN = 20; 28 29 public function __construct($type = GRAPH_TYPE_PIE) { 30 parent::__construct($type); 31 $this->background = false; 32 $this->sum = false; 33 $this->exploderad = 1; 34 $this->exploderad3d = 3; 35 $this->graphheight3d = 12; 36 $this->shiftlegendright = 17 * 7 + 7 + 10; // count of static chars * px/char + for color rectangle + space 37 } 38 39 /********************************************************************************************************/ 40 /* PRE CONFIG: ADD / SET / APPLY 41 /********************************************************************************************************/ 42 public function addItem($itemid, $calc_fnc = CALC_FNC_AVG, $color = null, $type = null) { 43 $items = CMacrosResolverHelper::resolveItemNames([get_item_by_itemid($itemid)]); 44 45 $this->items[$this->num] = reset($items); 46 47 $host = get_host_by_hostid($this->items[$this->num]['hostid']); 48 49 $this->items[$this->num]['host'] = $host['host']; 50 $this->items[$this->num]['hostname'] = $host['name']; 51 $this->items[$this->num]['color'] = is_null($color) ? 'Dark Green' : $color; 52 $this->items[$this->num]['calc_fnc'] = is_null($calc_fnc) ? CALC_FNC_AVG : $calc_fnc; 53 $this->items[$this->num]['calc_type'] = is_null($type) ? GRAPH_ITEM_SIMPLE : $type; 54 55 $this->num++; 56 } 57 58 public function switchPie3D($type = false) { 59 if ($type) { 60 $this->type = $type; 61 } 62 else { 63 switch ($this->type) { 64 case GRAPH_TYPE_EXPLODED: 65 $this->type = GRAPH_TYPE_3D_EXPLODED; 66 break; 67 case GRAPH_TYPE_3D_EXPLODED: 68 $this->type = GRAPH_TYPE_EXPLODED; 69 break; 70 case GRAPH_TYPE_3D: 71 $this->type = GRAPH_TYPE_PIE; 72 break; 73 case GRAPH_TYPE_PIE: 74 $this->type = GRAPH_TYPE_3D; 75 break; 76 default: 77 $this->type = GRAPH_TYPE_PIE; 78 } 79 } 80 return $this->type; 81 } 82 83 protected function calc3dheight($height) { 84 $this->graphheight3d = (int) ($height / 20); 85 } 86 87 protected function calcExplodedCenter($anglestart, $angleend, $x, $y, $count) { 88 $count *= $this->exploderad; 89 $anglemid = (int) (($anglestart + $angleend) / 2); 90 91 $y+= round($count * sin(deg2rad($anglemid))); 92 $x+= round($count * cos(deg2rad($anglemid))); 93 94 return [$x, $y]; 95 } 96 97 protected function calcExplodedRadius($sizeX, $sizeY, $count) { 98 $count *= $this->exploderad * 2; 99 $sizeX -= $count; 100 $sizeY -= $count; 101 return [$sizeX, $sizeY]; 102 } 103 104 protected function calc3DAngle($sizeX, $sizeY) { 105 $sizeY *= GRAPH_3D_ANGLE / 90; 106 return [$sizeX, round($sizeY)]; 107 } 108 109 protected function selectData() { 110 $this->data = []; 111 $now = time(); 112 113 if (isset($this->stime)) { 114 $this->from_time = $this->stime; 115 $this->to_time = $this->stime + $this->period; 116 } 117 else { 118 $this->to_time = $now; 119 $this->from_time = $this->to_time - $this->period; 120 } 121 122 $strvaluelength = 0; // we need to know how long in px will be our legend 123 124 // fetch values for items with the "last" function 125 $lastValueItems = []; 126 foreach ($this->items as $item) { 127 if ($item['calc_fnc'] == CALC_FNC_LST) { 128 $lastValueItems[] = $item; 129 } 130 } 131 if ($lastValueItems) { 132 $history = Manager::History()->getLastValues($lastValueItems); 133 } 134 135 $items = []; 136 137 for ($i = 0; $i < $this->num; $i++) { 138 $item = get_item_by_itemid($this->items[$i]['itemid']); 139 $from_time = $this->from_time; 140 $to_time = $this->to_time; 141 142 $to_resolve = []; 143 144 // Override item history setting with housekeeping settings, if they are enabled in config. 145 if (CHousekeepingHelper::get(CHousekeepingHelper::HK_HISTORY_GLOBAL)) { 146 $item['history'] = timeUnitToSeconds(CHousekeepingHelper::get(CHousekeepingHelper::HK_HISTORY)); 147 } 148 else { 149 $to_resolve[] = 'history'; 150 } 151 152 if (CHousekeepingHelper::get(CHousekeepingHelper::HK_TRENDS_GLOBAL)) { 153 $item['trends'] = timeUnitToSeconds(CHousekeepingHelper::get(CHousekeepingHelper::HK_TRENDS)); 154 } 155 else { 156 $to_resolve[] = 'trends'; 157 } 158 159 // Otherwise, resolve user macro and parse the string. If successful, convert to seconds. 160 if ($to_resolve) { 161 $item = CMacrosResolverHelper::resolveTimeUnitMacros([$item], $to_resolve)[0]; 162 163 $simple_interval_parser = new CSimpleIntervalParser(); 164 165 if (!CHousekeepingHelper::get(CHousekeepingHelper::HK_HISTORY_GLOBAL)) { 166 if ($simple_interval_parser->parse($item['history']) != CParser::PARSE_SUCCESS) { 167 show_error_message(_s('Incorrect value for field "%1$s": %2$s.', 'history', 168 _('invalid history storage period') 169 )); 170 exit; 171 } 172 $item['history'] = timeUnitToSeconds($item['history']); 173 } 174 175 if (!CHousekeepingHelper::get(CHousekeepingHelper::HK_TRENDS_GLOBAL)) { 176 if ($simple_interval_parser->parse($item['trends']) != CParser::PARSE_SUCCESS) { 177 show_error_message(_s('Incorrect value for field "%1$s": %2$s.', 'trends', 178 _('invalid trend storage period') 179 )); 180 exit; 181 } 182 $item['trends'] = timeUnitToSeconds($item['trends']); 183 } 184 } 185 186 $this->data[$this->items[$i]['itemid']]['last'] = isset($history[$item['itemid']]) 187 ? $history[$item['itemid']][0]['value'] : null; 188 $this->data[$this->items[$i]['itemid']]['shift_min'] = 0; 189 $this->data[$this->items[$i]['itemid']]['shift_max'] = 0; 190 $this->data[$this->items[$i]['itemid']]['shift_avg'] = 0; 191 192 $item['source'] = ($item['trends'] == 0 || ($item['history'] > time() - ($from_time + $this->period / 2))) 193 ? 'history' 194 : 'trends'; 195 $items[] = $item; 196 } 197 198 $results = Manager::History()->getGraphAggregationByWidth($items, $from_time, $to_time); 199 $i = 0; 200 201 foreach ($items as $item) { 202 if (array_key_exists($item['itemid'], $results)) { 203 $result = $results[$item['itemid']]; 204 $this->dataFrom = $result['source']; 205 206 foreach ($result['data'] as $row) { 207 $this->data[$item['itemid']]['min'] = $row['min']; 208 $this->data[$item['itemid']]['max'] = $row['max']; 209 $this->data[$item['itemid']]['avg'] = $row['avg']; 210 $this->data[$item['itemid']]['clock'] = $row['clock']; 211 } 212 unset($result); 213 } 214 else { 215 $this->dataFrom = $item['source']; 216 } 217 218 switch ($this->items[$i]['calc_fnc']) { 219 case CALC_FNC_MIN: 220 $fncName = 'min'; 221 break; 222 case CALC_FNC_MAX: 223 $fncName = 'max'; 224 break; 225 case CALC_FNC_LST: 226 $fncName = 'last'; 227 break; 228 case CALC_FNC_AVG: 229 default: 230 $fncName = 'avg'; 231 } 232 233 $item_value = empty($this->data[$item['itemid']][$fncName]) 234 ? 0 235 : abs($this->data[$item['itemid']][$fncName]); 236 237 if ($this->items[$i]['calc_type'] == GRAPH_ITEM_SUM) { 238 $this->background = $i; 239 $graph_sum = $item_value; 240 } 241 242 $this->sum += $item_value; 243 244 $convertedUnit = strlen(convertUnits([ 245 'value' => $item_value, 246 'units' => $item['units'] 247 ])); 248 $strvaluelength = max($strvaluelength, $convertedUnit); 249 $i++; 250 } 251 252 if (isset($graph_sum)) { 253 $this->sum = $graph_sum; 254 } 255 $this->shiftlegendright += $strvaluelength * 7; 256 } 257 258 protected function drawLegend() { 259 $shiftY = $this->shiftY + $this->shiftYLegend; 260 $fontSize = 8; 261 262 // check if host name will be displayed 263 $displayHostName = (count(array_unique(zbx_objectValues($this->items, 'hostname'))) > 1); 264 265 // calculate function name X shift 266 $functionNameXShift = 0; 267 268 foreach ($this->items as $item) { 269 $name = $displayHostName ? $item['hostname'].': '.$item['name_expanded'] : $item['name_expanded']; 270 $dims = imageTextSize($fontSize, 0, $name); 271 272 if ($dims['width'] > $functionNameXShift) { 273 $functionNameXShift = $dims['width']; 274 } 275 } 276 277 // display items 278 $i = 0; 279 $top_padding = $this->with_vertical_padding ? 10 : -(static::DEFAULT_TOP_BOTTOM_PADDING / 2); 280 281 foreach ($this->items as $item) { 282 $color = $this->getColor($item['color'], 0); 283 284 // function name 285 switch ($item['calc_fnc']) { 286 case CALC_FNC_MIN: 287 $fncName = 'min'; 288 $fncRealName = _('min'); 289 break; 290 case CALC_FNC_MAX: 291 $fncName = 'max'; 292 $fncRealName = _('max'); 293 break; 294 case CALC_FNC_LST: 295 $fncName = 'last'; 296 $fncRealName = _('last'); 297 break; 298 case CALC_FNC_AVG: 299 default: 300 $fncName = 'avg'; 301 $fncRealName = _('avg'); 302 } 303 304 if (isset($this->data[$item['itemid']]) 305 && isset($this->data[$item['itemid']][$fncName])) { 306 $dataValue = $this->data[$item['itemid']][$fncName]; 307 $proc = ($this->sum == 0) ? 0 : ($dataValue * 100) / $this->sum; 308 309 $strValue = sprintf(_('Value').': %s ('.(round($proc) != round($proc, 2) ? '%0.2f' : '%0.0f').'%%)', 310 convertUnits([ 311 'value' => $dataValue, 312 'units' => $this->items[$i]['units'] 313 ]), 314 $proc 315 ); 316 317 $str = '['.$fncRealName.']'; 318 } 319 else { 320 $strValue = _('Value: no data'); 321 322 $str = '['._('no data').']'; 323 } 324 325 // item name 326 imageText( 327 $this->im, 328 $fontSize, 329 0, 330 $this->shiftXleft + 15, 331 $this->sizeY + $shiftY + 14 * $i + 5, 332 $this->getColor($this->graphtheme['textcolor'], 0), 333 $displayHostName ? $item['hostname'].': '.$item['name_expanded'] : $item['name_expanded'] 334 ); 335 336 // function name 337 imageText( 338 $this->im, 339 $fontSize, 340 0, 341 $this->shiftXleft + $functionNameXShift + 30, 342 $this->sizeY + $shiftY + 14 * $i + 5, 343 $this->getColor($this->graphtheme['textcolor'], 0), 344 $str 345 ); 346 347 // left square fill 348 imagefilledrectangle( 349 $this->im, 350 $this->shiftXleft, 351 $this->sizeY + $shiftY + 14 * $i - 5, 352 $this->shiftXleft + 10, 353 $this->sizeY + $shiftY + 5 + 14 * $i, 354 $color 355 ); 356 357 // left square frame 358 imagerectangle( 359 $this->im, 360 $this->shiftXleft, 361 $this->sizeY + $shiftY + 14 * $i - 5, 362 $this->shiftXleft + 10, 363 $this->sizeY + $shiftY + 5 + 14 * $i, 364 $this->getColor('Black No Alpha') 365 ); 366 367 $shiftX = $this->fullSizeX - $this->shiftlegendright - $this->shiftXright + 25; 368 369 // right square fill 370 imagefilledrectangle( 371 $this->im, 372 $shiftX - 10, 373 $this->shiftY + $top_padding + 14 * $i, 374 $shiftX, 375 $this->shiftY + $top_padding + 10 + 14 * $i, 376 $color 377 ); 378 379 // right square frame 380 imagerectangle( 381 $this->im, 382 $shiftX - 10, 383 $this->shiftY + $top_padding + 14 * $i, 384 $shiftX, 385 $this->shiftY + $top_padding + 10 + 14 * $i, 386 $this->GetColor('Black No Alpha') 387 ); 388 389 // item value 390 imagetext( 391 $this->im, 392 $fontSize, 393 0, 394 $shiftX + 5, 395 $this->shiftY + $top_padding + 14 * $i + 10, 396 $this->getColor($this->graphtheme['textcolor'], 0), 397 $strValue 398 ); 399 400 $i++; 401 } 402 403 if ($this->sizeY < 120) { 404 return; 405 } 406 } 407 408 protected function drawElementPie($values) { 409 $sum = $this->sum; 410 411 if ($this->background !== false) { 412 $least = 0; 413 foreach ($values as $item => $value) { 414 if ($item != $this->background) { 415 $least += $value; 416 } 417 } 418 $values[$this->background] -= $least; 419 } 420 421 if ($sum <= 0) { 422 $values = [0 => 1]; 423 $sum = 1; 424 $isEmptyData = true; 425 } 426 else { 427 $isEmptyData = false; 428 } 429 430 $sizeX = $this->sizeX; 431 $sizeY = $this->sizeY; 432 433 if ($this->type == GRAPH_TYPE_EXPLODED) { 434 list($sizeX, $sizeY) = $this->calcExplodedRadius($sizeX, $sizeY, count($values)); 435 } 436 437 $xc = $x = (int) $this->sizeX / 2 + $this->shiftXleft; 438 $yc = $y = (int) $this->sizeY / 2 + $this->shiftY; 439 440 $anglestart = 0; 441 $angleend = 0; 442 443 foreach ($values as $item => $value) { 444 if ($value == 0) { 445 continue; 446 } 447 448 $angleend += (int) (360 * $value / $sum) + 1; 449 $angleend = ($angleend > 360) ? 360 : $angleend; 450 451 if (($angleend - $anglestart) < 1) { 452 continue; 453 } 454 455 if ($this->type == GRAPH_TYPE_EXPLODED) { 456 list($x, $y) = $this->calcExplodedCenter($anglestart, $angleend, $xc, $yc, count($values)); 457 } 458 459 imagefilledarc( 460 $this->im, 461 $x, 462 $y, 463 $sizeX, 464 $sizeY, 465 $anglestart, 466 $angleend, 467 $this->getColor((!$isEmptyData ? $this->items[$item]['color'] : 'FFFFFF'), 0), 468 IMG_ARC_PIE 469 ); 470 imagefilledarc( 471 $this->im, 472 $x, 473 $y, 474 $sizeX, 475 $sizeY, 476 $anglestart, 477 $angleend, 478 $this->getColor('Black'), 479 IMG_ARC_PIE | IMG_ARC_EDGED | IMG_ARC_NOFILL 480 ); 481 $anglestart = $angleend; 482 } 483 } 484 485 protected function drawElementPie3D($values) { 486 $sum = $this->sum; 487 488 if ($this->background !== false) { 489 $least = 0; 490 foreach ($values as $item => $value) { 491 if ($item != $this->background) { 492 $least += $value; 493 } 494 } 495 $values[$this->background] -= $least; 496 } 497 498 if ($sum <= 0) { 499 $values = [0 => 1]; 500 $sum = 1; 501 $isEmptyData = true; 502 } 503 else { 504 $isEmptyData = false; 505 } 506 507 $sizeX = $this->sizeX; 508 $sizeY = $this->sizeY; 509 510 $this->exploderad = $this->exploderad3d; 511 512 if ($this->type == GRAPH_TYPE_3D_EXPLODED) { 513 list($sizeX, $sizeY) = $this->calcExplodedRadius($sizeX, $sizeY, count($values)); 514 } 515 516 list($sizeX, $sizeY) = $this->calc3DAngle($sizeX, $sizeY); 517 518 $xc = $x = (int) $this->sizeX / 2 + $this->shiftXleft; 519 $yc = $y = (int) $this->sizeY / 2 + $this->shiftY; 520 521 // bottom angle line 522 $anglestart = 0; 523 $angleend = 0; 524 525 foreach ($values as $item => $value) { 526 if ($value == 0) { 527 continue; 528 } 529 530 $angleend += (int) (360 * $value / $sum) + 1; 531 $angleend = ($angleend > 360) ? 360 : $angleend; 532 533 if (($angleend - $anglestart) < 1) { 534 continue; 535 } 536 537 if ($this->type == GRAPH_TYPE_3D_EXPLODED) { 538 list($x, $y) = $this->calcExplodedCenter($anglestart, $angleend, $xc, $yc, count($values)); 539 } 540 541 imagefilledarc( 542 $this->im, 543 $x, 544 $y + $this->graphheight3d + 1, 545 $sizeX, 546 $sizeY, 547 $anglestart, 548 $angleend, 549 $this->getShadow((!$isEmptyData ? $this->items[$item]['color'] : 'FFFFFF'), 0), 550 IMG_ARC_PIE 551 ); 552 imagefilledarc( 553 $this->im, 554 $x, 555 $y + $this->graphheight3d + 1, 556 $sizeX, 557 $sizeY, 558 $anglestart, 559 $angleend, 560 $this->getColor('Black'), 561 IMG_ARC_PIE | IMG_ARC_EDGED | IMG_ARC_NOFILL 562 ); 563 $anglestart = $angleend; 564 } 565 566 // 3d effect 567 for ($i = $this->graphheight3d; $i > 0; $i--) { 568 $anglestart = 0; 569 $angleend = 0; 570 571 foreach ($values as $item => $value) { 572 if ($value == 0) { 573 continue; 574 } 575 576 $angleend += (int) (360 * $value / $sum) + 1; 577 $angleend = ($angleend > 360) ? 360 : $angleend; 578 579 if (($angleend - $anglestart) < 1) { 580 continue; 581 } 582 elseif ($this->sum == 0) { 583 continue; 584 } 585 586 if ($this->type == GRAPH_TYPE_3D_EXPLODED) { 587 list($x, $y) = $this->calcExplodedCenter($anglestart, $angleend, $xc, $yc, count($values)); 588 } 589 590 imagefilledarc( 591 $this->im, 592 $x, 593 $y + $i, 594 $sizeX, 595 $sizeY, 596 $anglestart, 597 $angleend, 598 $this->getShadow((!$isEmptyData ? $this->items[$item]['color'] : 'FFFFFF'), 0), 599 IMG_ARC_PIE 600 ); 601 $anglestart = $angleend; 602 } 603 } 604 605 $anglestart = 0; 606 $angleend = 0; 607 608 foreach ($values as $item => $value) { 609 if ($value == 0) { 610 continue; 611 } 612 613 $angleend += (int) (360 * $value / $sum) + 1; 614 $angleend = ($angleend > 360) ? 360 : $angleend; 615 616 if (($angleend - $anglestart) < 1) { 617 continue; 618 } 619 620 if ($this->type == GRAPH_TYPE_3D_EXPLODED) { 621 list($x, $y) = $this->calcExplodedCenter($anglestart, $angleend, $xc, $yc, count($values)); 622 } 623 624 imagefilledarc( 625 $this->im, 626 $x, 627 $y, 628 $sizeX, 629 $sizeY, 630 $anglestart, 631 $angleend, 632 $this->getColor((!$isEmptyData ? $this->items[$item]['color'] : 'FFFFFF'), 0), 633 IMG_ARC_PIE 634 ); 635 imagefilledarc( 636 $this->im, 637 $x, 638 $y, 639 $sizeX, 640 $sizeY, 641 $anglestart, 642 $angleend, 643 $this->getColor('Black'), 644 IMG_ARC_PIE | IMG_ARC_EDGED | IMG_ARC_NOFILL 645 ); 646 $anglestart = $angleend; 647 } 648 } 649 650 public function draw() { 651 $debug_mode = CWebUser::getDebugMode(); 652 if ($debug_mode) { 653 $start_time = microtime(true); 654 } 655 set_image_header(); 656 $this->calculateTopPadding(); 657 658 $this->selectData(); 659 if (hasErrorMesssages()) { 660 show_messages(); 661 } 662 663 $this->shiftYLegend = 20; 664 $this->shiftXleft = 10; 665 $this->shiftXright = 0; 666 $this->fullSizeX = $this->sizeX; 667 $this->fullSizeY = $this->sizeY; 668 669 if ($this->sizeX < 300 || $this->sizeY < 200) { 670 $this->showLegend(0); 671 } 672 673 if ($this->drawLegend == 1) { 674 $this->sizeX -= $this->shiftXleft + $this->shiftXright + $this->shiftlegendright; 675 $this->sizeY -= $this->shiftY + $this->shiftYLegend + 14 * $this->num + 8; 676 } 677 elseif ($this->with_vertical_padding) { 678 $this->sizeX -= $this->shiftXleft * 2; 679 $this->sizeY -= $this->shiftY * 2; 680 } 681 682 if (!$this->with_vertical_padding) { 683 if ($this->drawLegend == 1) { 684 // Increase size of graph by sum of: 8px legend font size and 5px legend item bottom shift. 685 $this->sizeY += 13; 686 } 687 else { 688 // Remove y shift if only graph is rendered (no labels, header, vertical paddings). 689 $this->shiftY = 0; 690 } 691 } 692 693 $this->sizeX = min($this->sizeX, $this->sizeY); 694 $this->sizeY = min($this->sizeX, $this->sizeY); 695 696 if ($this->sizeX + $this->shiftXleft > $this->fullSizeX) { 697 $this->sizeX = $this->fullSizeX - $this->shiftXleft - $this->shiftXleft; 698 $this->sizeY = min($this->sizeX, $this->sizeY); 699 } 700 701 $this->calc3dheight($this->sizeY); 702 703 $this->exploderad = (int) $this->sizeX / 100; 704 $this->exploderad3d = (int) $this->sizeX / 60; 705 706 if (function_exists('ImageColorExactAlpha') && function_exists('ImageCreateTrueColor') && @imagecreatetruecolor(1, 1)) { 707 $this->im = imagecreatetruecolor($this->fullSizeX, $this->fullSizeY); 708 } 709 else { 710 $this->im = imagecreate($this->fullSizeX, $this->fullSizeY); 711 } 712 $this->initColors(); 713 $this->drawRectangle(); 714 $this->drawHeader(); 715 716 // for each metric 717 $values = []; 718 for ($i = 0; $i < $this->num; $i++) { 719 $data = &$this->data[$this->items[$i]['itemid']]; 720 721 if (!isset($data)) { 722 continue; 723 } 724 725 switch ($this->items[$i]['calc_fnc']) { 726 case CALC_FNC_MIN: 727 $fncName = 'min'; 728 break; 729 case CALC_FNC_MAX: 730 $fncName = 'max'; 731 break; 732 case CALC_FNC_LST: 733 $fncName = 'last'; 734 break; 735 case CALC_FNC_AVG: 736 default: 737 $fncName = 'avg'; 738 } 739 740 $values[$i] = empty($this->data[$this->items[$i]['itemid']][$fncName]) 741 ? 0 742 : abs($this->data[$this->items[$i]['itemid']][$fncName]); 743 } 744 745 switch ($this->type) { 746 case GRAPH_TYPE_EXPLODED: 747 $this->drawElementPie($values); 748 break; 749 case GRAPH_TYPE_3D: 750 $this->drawElementPie3D($values); 751 break; 752 case GRAPH_TYPE_3D_EXPLODED: 753 $this->drawElementPie3D($values); 754 break; 755 default: 756 $this->drawElementPie($values); 757 } 758 759 if ($this->drawLegend == 1) { 760 $this->drawLegend(); 761 } 762 763 if ($debug_mode) { 764 $str = sprintf('%0.2f', microtime(true) - $start_time); 765 imageText( 766 $this->im, 767 6, 768 90, 769 $this->fullSizeX - 2, 770 $this->fullSizeY - 5, 771 $this->getColor('Gray'), 772 _s('Data from %1$s. Generated in %2$s sec.', $this->dataFrom, $str) 773 ); 774 } 775 776 unset($this->items, $this->data); 777 778 imageOut($this->im); 779 } 780} 781