| [ Index ] |
PHP Cross Reference of MantisBT |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * File containing the two dimensional renderer 4 * 5 * @package Graph 6 * @version 1.5 7 * @copyright Copyright (C) 2005-2009 eZ Systems AS. All rights reserved. 8 * @license http://ez.no/licenses/new_bsd New BSD License 9 */ 10 /** 11 * Class to transform chart primitives into image primitives. Renders charts in 12 * a two dimensional view. 13 * 14 * The class options are defined in the class {@link ezcGraphRenderer2dOptions} 15 * extending the basic renderer options in {@link ezcGraphRendererOptions}. 16 * 17 * <code> 18 * $graph = new ezcGraphPieChart(); 19 * $graph->palette = new ezcGraphPaletteBlack(); 20 * $graph->title = 'Access statistics'; 21 * $graph->options->label = '%2$d (%3$.1f%%)'; 22 * 23 * $graph->data['Access statistics'] = new ezcGraphArrayDataSet( array( 24 * 'Mozilla' => 19113, 25 * 'Explorer' => 10917, 26 * 'Opera' => 1464, 27 * 'Safari' => 652, 28 * 'Konqueror' => 474, 29 * ) ); 30 * $graph->data['Access statistics']->highlight['Explorer'] = true; 31 * 32 * // $graph->renderer = new ezcGraphRenderer2d(); 33 * 34 * $graph->renderer->options->moveOut = .2; 35 * 36 * $graph->renderer->options->pieChartOffset = 63; 37 * 38 * $graph->renderer->options->pieChartGleam = .3; 39 * $graph->renderer->options->pieChartGleamColor = '#FFFFFF'; 40 * $graph->renderer->options->pieChartGleamBorder = 2; 41 * 42 * $graph->renderer->options->pieChartShadowSize = 3; 43 * $graph->renderer->options->pieChartShadowColor = '#000000'; 44 * 45 * $graph->renderer->options->legendSymbolGleam = .5; 46 * $graph->renderer->options->legendSymbolGleamSize = .9; 47 * $graph->renderer->options->legendSymbolGleamColor = '#FFFFFF'; 48 * 49 * $graph->renderer->options->pieChartSymbolColor = '#BABDB688'; 50 * 51 * $graph->render( 400, 150, 'tutorial_pie_chart_pimped.svg' ); 52 * </code> 53 * 54 * @version 1.5 55 * @package Graph 56 * @mainclass 57 */ 58 class ezcGraphRenderer2d 59 extends 60 ezcGraphRenderer 61 implements 62 ezcGraphRadarRenderer, ezcGraphStackedBarsRenderer, ezcGraphOdometerRenderer 63 { 64 65 /** 66 * Pie segment labels divided into two array, containing the labels on the 67 * left and right side of the pie chart center. 68 * 69 * @var array 70 */ 71 protected $pieSegmentLabels = array( 72 0 => array(), 73 1 => array(), 74 ); 75 76 /** 77 * Contains the boundings used for pie segments 78 * 79 * @var ezcGraphBoundings 80 */ 81 protected $pieSegmentBoundings = false; 82 83 /** 84 * Array with symbols for post processing, which ensures, that the symbols 85 * are rendered topmost. 86 * 87 * @var array 88 */ 89 protected $linePostSymbols = array(); 90 91 /** 92 * Options 93 * 94 * @var ezcGraphRenderer2dOptions 95 */ 96 protected $options; 97 98 /** 99 * Collect axis labels, so that the axis are drawn, when all axis spaces 100 * are known. 101 * 102 * @var array 103 */ 104 protected $axisLabels = array(); 105 106 /** 107 * Collects circle sectors to draw shadow in background of all circle 108 * sectors. 109 * 110 * @var array 111 */ 112 protected $circleSectors = array(); 113 114 /** 115 * Constructor 116 * 117 * @param array $options Default option array 118 * @return void 119 * @ignore 120 */ 121 public function __construct( array $options = array() ) 122 { 123 $this->options = new ezcGraphRenderer2dOptions( $options ); 124 } 125 126 /** 127 * __get 128 * 129 * @param mixed $propertyName 130 * @throws ezcBasePropertyNotFoundException 131 * If a the value for the property options is not an instance of 132 * @return mixed 133 * @ignore 134 */ 135 public function __get( $propertyName ) 136 { 137 switch ( $propertyName ) 138 { 139 case 'options': 140 return $this->options; 141 default: 142 return parent::__get( $propertyName ); 143 } 144 } 145 146 /** 147 * Draw pie segment 148 * 149 * Draws a single pie segment 150 * 151 * @param ezcGraphBoundings $boundings Chart boundings 152 * @param ezcGraphContext $context Context of call 153 * @param ezcGraphColor $color Color of pie segment 154 * @param float $startAngle Start angle 155 * @param float $endAngle End angle 156 * @param mixed $label Label of pie segment 157 * @param bool $moveOut Move out from middle for hilighting 158 * @return void 159 */ 160 public function drawPieSegment( 161 ezcGraphBoundings $boundings, 162 ezcGraphContext $context, 163 ezcGraphColor $color, 164 $startAngle = .0, 165 $endAngle = 360., 166 $label = false, 167 $moveOut = false ) 168 { 169 // Apply offset 170 $startAngle += $this->options->pieChartOffset; 171 $endAngle += $this->options->pieChartOffset; 172 173 // Calculate position and size of pie 174 $center = new ezcGraphCoordinate( 175 $boundings->x0 + ( $boundings->width ) / 2, 176 $boundings->y0 + ( $boundings->height ) / 2 177 ); 178 179 // Limit radius to fourth of width and half of height at maximum 180 $radius = min( 181 ( $boundings->width ) * $this->options->pieHorizontalSize, 182 ( $boundings->height ) * $this->options->pieVerticalSize 183 ); 184 185 // Move pie segment out of the center 186 if ( $moveOut ) 187 { 188 $direction = ( $endAngle + $startAngle ) / 2; 189 190 $center = new ezcGraphCoordinate( 191 $center->x + $this->options->moveOut * $radius * cos( deg2rad( $direction ) ), 192 $center->y + $this->options->moveOut * $radius * sin( deg2rad( $direction ) ) 193 ); 194 } 195 196 // Add circle sector to queue 197 $this->circleSectors[] = array( 198 'center' => $center, 199 'context' => $context, 200 'width' => $radius * 2 * ( 1 - $this->options->moveOut ), 201 'height' => $radius * 2 * ( 1 - $this->options->moveOut ), 202 'start' => $startAngle, 203 'end' => $endAngle, 204 'color' => $color, 205 ); 206 207 if ( $label ) 208 { 209 // Determine position of label 210 $direction = ( $endAngle + $startAngle ) / 2; 211 $pieSegmentCenter = new ezcGraphCoordinate( 212 $center->x + cos( deg2rad( $direction ) ) * $radius, 213 $center->y + sin( deg2rad( $direction ) ) * $radius 214 ); 215 216 // Split labels up into left an right size and index them on their 217 // y position 218 $this->pieSegmentLabels[(int) ($pieSegmentCenter->x > $center->x)][$pieSegmentCenter->y] = array( 219 new ezcGraphCoordinate( 220 $center->x + cos( deg2rad( $direction ) ) * $radius * 2 / 3, 221 $center->y + sin( deg2rad( $direction ) ) * $radius * 2 / 3 222 ), 223 $label, 224 $context 225 ); 226 } 227 228 if ( !$this->pieSegmentBoundings ) 229 { 230 $this->pieSegmentBoundings = $boundings; 231 } 232 } 233 234 /** 235 * Draws the collected circle sectors 236 * 237 * All circle sectors are collected and drawn later to be able to render 238 * the shadows of the pie segments in the back of all pie segments. 239 * 240 * @return void 241 */ 242 protected function finishCircleSectors() 243 { 244 // Add circle sector sides to simple z buffer prioriry list 245 if ( $this->options->pieChartShadowSize > 0 ) 246 { 247 foreach ( $this->circleSectors as $circleSector ) 248 { 249 $this->driver->drawCircleSector( 250 new ezcGraphCoordinate( 251 $circleSector['center']->x + $this->options->pieChartShadowSize, 252 $circleSector['center']->y + $this->options->pieChartShadowSize 253 ), 254 $circleSector['width'], 255 $circleSector['height'], 256 $circleSector['start'], 257 $circleSector['end'], 258 $this->options->pieChartShadowColor->transparent( $this->options->pieChartShadowTransparency ), 259 true 260 ); 261 } 262 } 263 264 foreach ( $this->circleSectors as $circleSector ) 265 { 266 // Draw circle sector 267 $this->addElementReference( 268 $circleSector['context'], 269 $this->driver->drawCircleSector( 270 $circleSector['center'], 271 $circleSector['width'], 272 $circleSector['height'], 273 $circleSector['start'], 274 $circleSector['end'], 275 $circleSector['color'], 276 true 277 ) 278 ); 279 280 $darkenedColor = $circleSector['color']->darken( $this->options->dataBorder ); 281 $this->driver->drawCircleSector( 282 $circleSector['center'], 283 $circleSector['width'], 284 $circleSector['height'], 285 $circleSector['start'], 286 $circleSector['end'], 287 $darkenedColor, 288 false 289 ); 290 291 if ( $this->options->pieChartGleam !== false ) 292 { 293 $gradient = new ezcGraphLinearGradient( 294 $circleSector['center'], 295 new ezcGraphCoordinate( 296 $circleSector['center']->x, 297 $circleSector['center']->y - $circleSector['height'] / 2 298 ), 299 $this->options->pieChartGleamColor->transparent( 1 ), 300 $this->options->pieChartGleamColor->transparent( $this->options->pieChartGleam ) 301 ); 302 303 $this->addElementReference( $circleSector['context'], 304 $this->driver->drawCircleSector( 305 $circleSector['center'], 306 $circleSector['width'] - $this->options->pieChartGleamBorder * 2, 307 $circleSector['height'] - $this->options->pieChartGleamBorder * 2, 308 $circleSector['start'], 309 $circleSector['end'], 310 $gradient, 311 true 312 ) 313 ); 314 315 $gradient = new ezcGraphLinearGradient( 316 new ezcGraphCoordinate( 317 $circleSector['center']->x, 318 $circleSector['center']->y + $circleSector['height'] / 4 319 ), 320 new ezcGraphCoordinate( 321 $circleSector['center']->x, 322 $circleSector['center']->y + $circleSector['height'] / 2 323 ), 324 $this->options->pieChartGleamColor->transparent( 1 ), 325 $this->options->pieChartGleamColor->transparent( $this->options->pieChartGleam ) 326 ); 327 328 $this->addElementReference( $circleSector['context'], 329 $this->driver->drawCircleSector( 330 $circleSector['center'], 331 $circleSector['width'] - $this->options->pieChartGleamBorder * 2, 332 $circleSector['height'] - $this->options->pieChartGleamBorder * 2, 333 $circleSector['start'], 334 $circleSector['end'], 335 $gradient, 336 true 337 ) 338 ); 339 } 340 } 341 } 342 343 /** 344 * Draws the collected pie segment labels 345 * 346 * All labels are collected and drawn later to be able to partition the 347 * available space for the labels woth knowledge of the overall label 348 * count and their required size and optimal position. 349 * 350 * @return void 351 */ 352 protected function finishPieSegmentLabels() 353 { 354 if ( $this->pieSegmentBoundings === false ) 355 { 356 return true; 357 } 358 359 $boundings = $this->pieSegmentBoundings; 360 361 // Calculate position and size of pie 362 $center = new ezcGraphCoordinate( 363 $boundings->x0 + ( $boundings->width ) / 2, 364 $boundings->y0 + ( $boundings->height ) / 2 365 ); 366 367 // Limit radius to fourth of width and half of height at maximum 368 $radius = min( 369 ( $boundings->width ) * $this->options->pieHorizontalSize, 370 ( $boundings->height ) * $this->options->pieVerticalSize 371 ); 372 373 $pieChartHeight = min( 374 $radius * 2 + $radius / max( 1, count ( $this->pieSegmentLabels[0] ), count( $this->pieSegmentLabels[1] ) ) * 4, 375 $boundings->height 376 ); 377 $pieChartYPosition = $boundings->y0 + ( ( $boundings->height ) - $pieChartHeight ) / 2; 378 379 // Calculate maximum height of labels 380 $labelHeight = min( 381 ( count( $this->pieSegmentLabels[0] ) 382 ? $pieChartHeight / count( $this->pieSegmentLabels[0] ) 383 : $pieChartHeight 384 ), 385 ( count( $this->pieSegmentLabels[1] ) 386 ? $pieChartHeight / count( $this->pieSegmentLabels[1] ) 387 : $pieChartHeight 388 ), 389 ( $pieChartHeight ) * $this->options->maxLabelHeight 390 ); 391 392 $symbolSize = $this->options->symbolSize; 393 394 foreach ( $this->pieSegmentLabels as $side => $labelPart ) 395 { 396 $minHeight = $pieChartYPosition; 397 $toShare = $pieChartHeight - count( $labelPart ) * $labelHeight; 398 399 // Sort to draw topmost label first 400 ksort( $labelPart ); 401 $sign = ( $side ? -1 : 1 ); 402 403 foreach ( $labelPart as $height => $label ) 404 { 405 if ( ( $height - $labelHeight / 2 ) > $minHeight ) 406 { 407 $share = min( $toShare, ( $height - $labelHeight / 2) - $minHeight ); 408 $minHeight += $share; 409 $toShare -= $share; 410 } 411 412 // Determine position of label 413 $minHeight += max( 0, $height - $minHeight - $labelHeight ) / $pieChartHeight * $toShare; 414 $verticalDistance = ( $center->y - $minHeight - $labelHeight / 2 ) / $radius; 415 416 $labelPosition = new ezcGraphCoordinate( 417 $center->x - 418 $sign * ( 419 abs( $verticalDistance ) > 1 420 // If vertical distance to center is greater then the 421 // radius, use the centerline for the horizontal 422 // position 423 ? max ( 424 5, 425 abs( $label[0]->x - $center->x ) 426 ) 427 // Else place the label outside of the pie chart 428 : ( cos ( asin ( $verticalDistance ) ) * $radius + 429 $symbolSize * (int) $this->options->showSymbol 430 ) 431 ), 432 $minHeight + $labelHeight / 2 433 ); 434 435 if ( $this->options->showSymbol ) 436 { 437 // Draw label 438 $this->driver->drawLine( 439 $label[0], 440 $labelPosition, 441 $this->options->pieChartSymbolColor, 442 1 443 ); 444 445 $this->driver->drawCircle( 446 $label[0], 447 $symbolSize, 448 $symbolSize, 449 $this->options->pieChartSymbolColor, 450 true 451 ); 452 $this->driver->drawCircle( 453 $labelPosition, 454 $symbolSize, 455 $symbolSize, 456 $this->options->pieChartSymbolColor, 457 true 458 ); 459 } 460 461 $this->addElementReference( 462 $label[2], 463 $this->driver->drawTextBox( 464 $label[1], 465 new ezcGraphCoordinate( 466 ( !$side ? $boundings->x0 : $labelPosition->x + $symbolSize ), 467 $minHeight 468 ), 469 ( !$side ? $labelPosition->x - $boundings->x0 - $symbolSize : $boundings->x1 - $labelPosition->x - $symbolSize ), 470 $labelHeight, 471 ( !$side ? ezcGraph::RIGHT : ezcGraph::LEFT ) | ezcGraph::MIDDLE 472 ) 473 ); 474 475 // Add used space to minHeight 476 $minHeight += $labelHeight; 477 } 478 } 479 } 480 481 /** 482 * Draw the collected line symbols 483 * 484 * Symbols for the data lines are collected and delayed to ensure that 485 * they are not covered and hidden by other data lines. 486 * 487 * @return void 488 */ 489 protected function finishLineSymbols() 490 { 491 foreach ( $this->linePostSymbols as $symbol ) 492 { 493 $this->addElementReference( 494 $symbol['context'], 495 $this->drawSymbol( 496 $symbol['boundings'], 497 $symbol['color'], 498 $symbol['symbol'] 499 ) 500 ); 501 } 502 } 503 504 /** 505 * Draw bar 506 * 507 * Draws a bar as a data element in a line chart 508 * 509 * @param ezcGraphBoundings $boundings Chart boundings 510 * @param ezcGraphContext $context Context of call 511 * @param ezcGraphColor $color Color of line 512 * @param ezcGraphCoordinate $position Position of data point 513 * @param float $stepSize Space which can be used for bars 514 * @param int $dataNumber Number of dataset 515 * @param int $dataCount Count of datasets in chart 516 * @param int $symbol Symbol to draw for line 517 * @param float $axisPosition Position of axis for drawing filled lines 518 * @return void 519 */ 520 public function drawBar( 521 ezcGraphBoundings $boundings, 522 ezcGraphContext $context, 523 ezcGraphColor $color, 524 ezcGraphCoordinate $position, 525 $stepSize, 526 $dataNumber = 1, 527 $dataCount = 1, 528 $symbol = ezcGraph::NO_SYMBOL, 529 $axisPosition = 0. ) 530 { 531 // Apply margin 532 $margin = $stepSize * $this->options->barMargin; 533 $padding = $stepSize * $this->options->barPadding; 534 $barWidth = ( $stepSize - $margin ) / $dataCount - $padding; 535 $offset = - $stepSize / 2 + $margin / 2 + ( $dataCount - $dataNumber - 1 ) * ( $padding + $barWidth ) + $padding / 2; 536 537 $barPointArray = array( 538 new ezcGraphCoordinate( 539 $boundings->x0 + ( $boundings->width ) * $position->x + $offset, 540 $boundings->y0 + ( $boundings->height ) * $axisPosition 541 ), 542 new ezcGraphCoordinate( 543 $boundings->x0 + ( $boundings->width ) * $position->x + $offset, 544 $boundings->y0 + ( $boundings->height ) * $position->y 545 ), 546 new ezcGraphCoordinate( 547 $boundings->x0 + ( $boundings->width ) * $position->x + $offset + $barWidth, 548 $boundings->y0 + ( $boundings->height ) * $position->y 549 ), 550 new ezcGraphCoordinate( 551 $boundings->x0 + ( $boundings->width ) * $position->x + $offset + $barWidth, 552 $boundings->y0 + ( $boundings->height ) * $axisPosition 553 ), 554 ); 555 556 $this->addElementReference( 557 $context, 558 $this->driver->drawPolygon( 559 $barPointArray, 560 $color, 561 true 562 ) 563 ); 564 565 if ( $this->options->dataBorder > 0 ) 566 { 567 $darkened = $color->darken( $this->options->dataBorder ); 568 $this->driver->drawPolygon( 569 $barPointArray, 570 $darkened, 571 false, 572 1 573 ); 574 } 575 } 576 577 /** 578 * Draw stacked bar 579 * 580 * Draws a stacked bar part as a data element in a line chart 581 * 582 * @param ezcGraphBoundings $boundings Chart boundings 583 * @param ezcGraphContext $context Context of call 584 * @param ezcGraphColor $color Color of line 585 * @param ezcGraphCoordinate $start 586 * @param ezcGraphCoordinate $position 587 * @param float $stepSize Space which can be used for bars 588 * @param int $symbol Symbol to draw for line 589 * @param float $axisPosition Position of axis for drawing filled lines 590 * @return void 591 */ 592 public function drawStackedBar( 593 ezcGraphBoundings $boundings, 594 ezcGraphContext $context, 595 ezcGraphColor $color, 596 ezcGraphCoordinate $start, 597 ezcGraphCoordinate $position, 598 $stepSize, 599 $symbol = ezcGraph::NO_SYMBOL, 600 $axisPosition = 0. ) 601 { 602 // Apply margin 603 $margin = $stepSize * $this->options->barMargin; 604 $barWidth = $stepSize - $margin; 605 $offset = - $stepSize / 2 + $margin / 2; 606 607 $barPointArray = array( 608 new ezcGraphCoordinate( 609 $boundings->x0 + ( $boundings->width ) * $position->x + $offset, 610 $boundings->y0 + ( $boundings->height ) * $start->y 611 ), 612 new ezcGraphCoordinate( 613 $boundings->x0 + ( $boundings->width ) * $position->x + $offset, 614 $boundings->y0 + ( $boundings->height ) * $position->y 615 ), 616 new ezcGraphCoordinate( 617 $boundings->x0 + ( $boundings->width ) * $position->x + $offset + $barWidth, 618 $boundings->y0 + ( $boundings->height ) * $position->y 619 ), 620 new ezcGraphCoordinate( 621 $boundings->x0 + ( $boundings->width ) * $position->x + $offset + $barWidth, 622 $boundings->y0 + ( $boundings->height ) * $start->y 623 ), 624 ); 625 626 $this->addElementReference( 627 $context, 628 $this->driver->drawPolygon( 629 $barPointArray, 630 $color, 631 true 632 ) 633 ); 634 635 if ( $this->options->dataBorder > 0 ) 636 { 637 $darkened = $color->darken( $this->options->dataBorder ); 638 $this->driver->drawPolygon( 639 $barPointArray, 640 $darkened, 641 false, 642 1 643 ); 644 } 645 } 646 647 /** 648 * Draw data line 649 * 650 * Draws a line as a data element in a line chart 651 * 652 * @param ezcGraphBoundings $boundings Chart boundings 653 * @param ezcGraphContext $context Context of call 654 * @param ezcGraphColor $color Color of line 655 * @param ezcGraphCoordinate $start Starting point 656 * @param ezcGraphCoordinate $end Ending point 657 * @param int $dataNumber Number of dataset 658 * @param int $dataCount Count of datasets in chart 659 * @param int $symbol Symbol to draw for line 660 * @param ezcGraphColor $symbolColor Color of the symbol, defaults to linecolor 661 * @param ezcGraphColor $fillColor Color to fill line with 662 * @param float $axisPosition Position of axis for drawing filled lines 663 * @param float $thickness Line thickness 664 * @return void 665 */ 666 public function drawDataLine( 667 ezcGraphBoundings $boundings, 668 ezcGraphContext $context, 669 ezcGraphColor $color, 670 ezcGraphCoordinate $start, 671 ezcGraphCoordinate $end, 672 $dataNumber = 1, 673 $dataCount = 1, 674 $symbol = ezcGraph::NO_SYMBOL, 675 ezcGraphColor $symbolColor = null, 676 ezcGraphColor $fillColor = null, 677 $axisPosition = 0., 678 $thickness = 1. ) 679 { 680 // Perhaps fill up line 681 if ( $fillColor !== null && 682 $start->x != $end->x ) 683 { 684 $startValue = $axisPosition - $start->y; 685 $endValue = $axisPosition - $end->y; 686 687 if ( ( $startValue == 0 ) || 688 ( $endValue == 0 ) || 689 ( $startValue / abs( $startValue ) == $endValue / abs( $endValue ) ) ) 690 { 691 // Values have the same sign or are on the axis 692 $this->driver->drawPolygon( 693 array( 694 new ezcGraphCoordinate( 695 $boundings->x0 + ( $boundings->width ) * $start->x, 696 $boundings->y0 + ( $boundings->height ) * $start->y 697 ), 698 new ezcGraphCoordinate( 699 $boundings->x0 + ( $boundings->width ) * $end->x, 700 $boundings->y0 + ( $boundings->height ) * $end->y 701 ), 702 new ezcGraphCoordinate( 703 $boundings->x0 + ( $boundings->width ) * $end->x, 704 $boundings->y0 + ( $boundings->height ) * $axisPosition 705 ), 706 new ezcGraphCoordinate( 707 $boundings->x0 + ( $boundings->width ) * $start->x, 708 $boundings->y0 + ( $boundings->height ) * $axisPosition 709 ), 710 ), 711 $fillColor, 712 true 713 ); 714 } 715 else 716 { 717 // values are on differente sides of the axis - split the filled polygon 718 $startDiff = abs( $axisPosition - $start->y ); 719 $endDiff = abs( $axisPosition - $end->y ); 720 721 $cuttingPosition = $startDiff / ( $endDiff + $startDiff ); 722 $cuttingPoint = new ezcGraphCoordinate( 723 $start->x + ( $end->x - $start->x ) * $cuttingPosition, 724 $axisPosition 725 ); 726 727 $this->driver->drawPolygon( 728 array( 729 new ezcGraphCoordinate( 730 $boundings->x0 + ( $boundings->width ) * $start->x, 731 $boundings->y0 + ( $boundings->height ) * $axisPosition 732 ), 733 new ezcGraphCoordinate( 734 $boundings->x0 + ( $boundings->width ) * $start->x, 735 $boundings->y0 + ( $boundings->height ) * $start->y 736 ), 737 new ezcGraphCoordinate( 738 $boundings->x0 + ( $boundings->width ) * $cuttingPoint->x, 739 $boundings->y0 + ( $boundings->height ) * $cuttingPoint->y 740 ), 741 ), 742 $fillColor, 743 true 744 ); 745 746 $this->driver->drawPolygon( 747 array( 748 new ezcGraphCoordinate( 749 $boundings->x0 + ( $boundings->width ) * $end->x, 750 $boundings->y0 + ( $boundings->height ) * $axisPosition 751 ), 752 new ezcGraphCoordinate( 753 $boundings->x0 + ( $boundings->width ) * $end->x, 754 $boundings->y0 + ( $boundings->height ) * $end->y 755 ), 756 new ezcGraphCoordinate( 757 $boundings->x0 + ( $boundings->width ) * $cuttingPoint->x, 758 $boundings->y0 + ( $boundings->height ) * $cuttingPoint->y 759 ), 760 ), 761 $fillColor, 762 true 763 ); 764 } 765 } 766 767 // Draw line 768 $this->driver->drawLine( 769 new ezcGraphCoordinate( 770 $boundings->x0 + ( $boundings->width ) * $start->x, 771 $boundings->y0 + ( $boundings->height ) * $start->y 772 ), 773 new ezcGraphCoordinate( 774 $boundings->x0 + ( $boundings->width ) * $end->x, 775 $boundings->y0 + ( $boundings->height ) * $end->y 776 ), 777 $color, 778 $thickness 779 ); 780 781 // Draw line symbol 782 if ( $symbol !== ezcGraph::NO_SYMBOL ) 783 { 784 if ( $symbolColor === null ) 785 { 786 $symbolColor = $color; 787 } 788 789 $this->linePostSymbols[] = array( 790 'boundings' => new ezcGraphBoundings( 791 $boundings->x0 + ( $boundings->width ) * $end->x - $this->options->symbolSize / 2, 792 $boundings->y0 + ( $boundings->height ) * $end->y - $this->options->symbolSize / 2, 793 $boundings->x0 + ( $boundings->width ) * $end->x + $this->options->symbolSize / 2, 794 $boundings->y0 + ( $boundings->height ) * $end->y + $this->options->symbolSize / 2 795 ), 796 'color' => $symbolColor, 797 'context' => $context, 798 'symbol' => $symbol, 799 ); 800 } 801 } 802 803 /** 804 * Returns a coordinate in the given bounding box for the given angle 805 * radius with the center as base point. 806 * 807 * @param ezcGraphBoundings $boundings 808 * @param ezcGraphCoordinate $center 809 * @param float $angle 810 * @param float $radius 811 * @return float 812 */ 813 protected function getCoordinateFromAngleAndRadius( 814 ezcGraphBoundings $boundings, 815 ezcGraphCoordinate $center, 816 $angle, 817 $radius 818 ) 819 { 820 $direction = new ezcGraphCoordinate( 821 sin( $angle ) * $boundings->width / 2, 822 -cos( $angle ) * $boundings->height / 2 823 ); 824 825 $offset = new ezcGraphCoordinate( 826 sin( $angle ) * $this->xAxisSpace, 827 -cos( $angle ) * $this->yAxisSpace 828 ); 829 830 $direction->x -= 2 * $offset->x; 831 $direction->y -= 2 * $offset->y; 832 833 return new ezcGraphCoordinate( 834 $boundings->x0 + 835 $center->x + 836 $offset->x + 837 $direction->x * $radius, 838 $boundings->y0 + 839 $center->y + 840 $offset->y + 841 $direction->y * $radius 842 ); 843 } 844 845 /** 846 * Draw radar chart data line 847 * 848 * Draws a line as a data element in a radar chart 849 * 850 * @param ezcGraphBoundings $boundings Chart boundings 851 * @param ezcGraphContext $context Context of call 852 * @param ezcGraphColor $color Color of line 853 * @param ezcGraphCoordinate $center Center of radar chart 854 * @param ezcGraphCoordinate $start Starting point 855 * @param ezcGraphCoordinate $end Ending point 856 * @param int $dataNumber Number of dataset 857 * @param int $dataCount Count of datasets in chart 858 * @param int $symbol Symbol to draw for line 859 * @param ezcGraphColor $symbolColor Color of the symbol, defaults to linecolor 860 * @param ezcGraphColor $fillColor Color to fill line with 861 * @param float $thickness Line thickness 862 * @return void 863 */ 864 public function drawRadarDataLine( 865 ezcGraphBoundings $boundings, 866 ezcGraphContext $context, 867 ezcGraphColor $color, 868 ezcGraphCoordinate $center, 869 ezcGraphCoordinate $start, 870 ezcGraphCoordinate $end, 871 $dataNumber = 1, 872 $dataCount = 1, 873 $symbol = ezcGraph::NO_SYMBOL, 874 ezcGraphColor $symbolColor = null, 875 ezcGraphColor $fillColor = null, 876 $thickness = 1. 877 ) 878 { 879 // Calculate line points from chart coordinates 880 $start = $this->getCoordinateFromAngleAndRadius( 881 $boundings, 882 $center, 883 $start->x * 2 * M_PI, 884 $start->y 885 ); 886 $end = $this->getCoordinateFromAngleAndRadius( 887 $boundings, 888 $center, 889 $end->x * 2 * M_PI, 890 $end->y 891 ); 892 893 // Fill line 894 if ( $fillColor !== null ) 895 { 896 $this->driver->drawPolygon( 897 array( 898 $start, 899 $end, 900 new ezcGraphCoordinate( 901 $boundings->x0 + $center->x, 902 $boundings->y0 + $center->y 903 ), 904 ), 905 $fillColor, 906 true 907 ); 908 } 909 910 // Draw line 911 $this->driver->drawLine( 912 $start, 913 $end, 914 $color, 915 $thickness 916 ); 917 918 if ( $symbol !== ezcGraph::NO_SYMBOL ) 919 { 920 $this->drawSymbol( 921 new ezcGraphBoundings( 922 $end->x - $this->options->symbolSize / 2, 923 $end->y - $this->options->symbolSize / 2, 924 $end->x + $this->options->symbolSize / 2, 925 $end->y + $this->options->symbolSize / 2 926 ), 927 $symbolColor, 928 $symbol 929 ); 930 } 931 } 932 933 /** 934 * Draws a highlight textbox for a datapoint. 935 * 936 * A highlight textbox for line and bar charts means a box with the current 937 * value in the graph. 938 * 939 * @param ezcGraphBoundings $boundings Chart boundings 940 * @param ezcGraphContext $context Context of call 941 * @param ezcGraphCoordinate $end Ending point 942 * @param float $axisPosition Position of axis for drawing filled lines 943 * @param int $dataNumber Number of dataset 944 * @param int $dataCount Count of datasets in chart 945 * @param ezcGraphFontOptions $font Font used for highlight string 946 * @param string $text Acutual value 947 * @param int $size Size of highlight text 948 * @param ezcGraphColor $markLines 949 * @param int $xOffset 950 * @param int $yOffset 951 * @param float $stepSize 952 * @param int $type 953 * @return void 954 */ 955 public function drawDataHighlightText( 956 ezcGraphBoundings $boundings, 957 ezcGraphContext $context, 958 ezcGraphCoordinate $end, 959 $axisPosition = 0., 960 $dataNumber = 1, 961 $dataCount = 1, 962 ezcGraphFontOptions $font, 963 $text, 964 $size, 965 ezcGraphColor $markLines = null, 966 $xOffset = 0, 967 $yOffset = 0, 968 $stepSize = 0., 969 $type = ezcGraph::LINE ) 970 { 971 // Bar specific calculations 972 if ( $type !== ezcGraph::LINE ) 973 { 974 $margin = $stepSize * $this->options->barMargin; 975 $padding = $stepSize * $this->options->barPadding; 976 $barWidth = ( $stepSize - $margin ) / $dataCount - $padding; 977 $offset = -( $dataNumber + ( $dataCount - 1 ) / -2 ) * ( $barWidth + $padding ); 978 } 979 980 $this->driver->options->font = $font; 981 $width = $boundings->width / $dataCount; 982 983 $dataPoint = new ezcGraphCoordinate( 984 $boundings->x0 + ( $boundings->width ) * $end->x + $xOffset + 985 ( $type === ezcGraph::LINE ? 0 : $offset ), 986 $boundings->y0 + ( $boundings->height ) * $end->y + $yOffset 987 ); 988 989 if ( $end->y < $axisPosition ) 990 { 991 $this->driver->drawTextBox( 992 $text, 993 new ezcGraphCoordinate( 994 $dataPoint->x - $width / 2, 995 $dataPoint->y - $size - $font->padding - $this->options->symbolSize 996 ), 997 $width, 998 $size, 999 ezcGraph::CENTER | ezcGraph::BOTTOM 1000 ); 1001 } 1002 else 1003 { 1004 $this->driver->drawTextBox( 1005 $text, 1006 new ezcGraphCoordinate( 1007 $dataPoint->x - $width / 2, 1008 $dataPoint->y + $font->padding + $this->options->symbolSize 1009 ), 1010 $width, 1011 $size, 1012 ezcGraph::CENTER | ezcGraph::TOP 1013 ); 1014 } 1015 } 1016 1017 /** 1018 * Draw legend 1019 * 1020 * Will draw a legend in the bounding box 1021 * 1022 * @param ezcGraphBoundings $boundings Bounding of legend 1023 * @param ezcGraphChartElementLegend $legend Legend to draw; 1024 * @param int $type Type of legend: Protrait or landscape 1025 * @return void 1026 */ 1027 public function drawLegend( 1028 ezcGraphBoundings $boundings, 1029 ezcGraphChartElementLegend $legend, 1030 $type = ezcGraph::VERTICAL ) 1031 { 1032 $labels = $legend->labels; 1033 1034 // Calculate boundings of each label 1035 if ( $type & ezcGraph::VERTICAL ) 1036 { 1037 $labelWidth = $boundings->width; 1038 $labelHeight = min( 1039 ( $boundings->height ) / count( $labels ) - $legend->spacing, 1040 $legend->symbolSize + 2 * $legend->padding 1041 ); 1042 } 1043 else 1044 { 1045 $labelWidth = ( $boundings->width ) / count( $labels ) - $legend->spacing; 1046 $labelHeight = min( 1047 $boundings->height, 1048 $legend->symbolSize + 2 * $legend->padding 1049 ); 1050 } 1051 1052 $symbolSize = $labelHeight - 2 * $legend->padding; 1053 1054 // Draw all labels 1055 $labelPosition = new ezcGraphCoordinate( $boundings->x0, $boundings->y0 ); 1056 foreach ( $labels as $label ) 1057 { 1058 $this->elements['legend_url'][$label['label']] = $label['url']; 1059 1060 $this->elements['legend'][$label['label']]['symbol'] = $this->drawSymbol( 1061 new ezcGraphBoundings( 1062 $labelPosition->x + $legend->padding, 1063 $labelPosition->y + $legend->padding, 1064 $labelPosition->x + $legend->padding + $symbolSize, 1065 $labelPosition->y + $legend->padding + $symbolSize 1066 ), 1067 $label['color'], 1068 $label['symbol'] 1069 ); 1070 1071 $this->elements['legend'][$label['label']]['text'] = $this->driver->drawTextBox( 1072 $label['label'], 1073 new ezcGraphCoordinate( 1074 $labelPosition->x + 2 * $legend->padding + $symbolSize, 1075 $labelPosition->y + $legend->padding 1076 ), 1077 $labelWidth - $symbolSize - 3 * $legend->padding, 1078 $labelHeight - 2 * $legend->padding, 1079 ezcGraph::LEFT | ezcGraph::MIDDLE 1080 ); 1081 1082 $labelPosition->x += ( $type === ezcGraph::VERTICAL ? 0 : $labelWidth + $legend->spacing ); 1083 $labelPosition->y += ( $type === ezcGraph::VERTICAL ? $labelHeight + $legend->spacing : 0 ); 1084 } 1085 } 1086 1087 /** 1088 * Draw box 1089 * 1090 * Box are wrapping each major chart element and draw border, background 1091 * and title to each chart element. 1092 * 1093 * Optionally a padding and margin for each box can be defined. 1094 * 1095 * @param ezcGraphBoundings $boundings Boundings of the box 1096 * @param ezcGraphColor $background Background color 1097 * @param ezcGraphColor $borderColor Border color 1098 * @param int $borderWidth Border width 1099 * @param int $margin Margin 1100 * @param int $padding Padding 1101 * @param mixed $title Title of the box 1102 * @param int $titleSize Size of title in the box 1103 * @return ezcGraphBoundings Remaining inner boundings 1104 */ 1105 public function drawBox( 1106 ezcGraphBoundings $boundings, 1107 ezcGraphColor $background = null, 1108 ezcGraphColor $borderColor = null, 1109 $borderWidth = 0, 1110 $margin = 0, 1111 $padding = 0, 1112 $title = false, 1113 $titleSize = 16 ) 1114 { 1115 // Apply margin 1116 $boundings->x0 += $margin; 1117 $boundings->y0 += $margin; 1118 $boundings->x1 -= $margin; 1119 $boundings->y1 -= $margin; 1120 1121 if ( $background instanceof ezcGraphColor ) 1122 { 1123 // Draw box background 1124 $this->driver->drawPolygon( 1125 array( 1126 new ezcGraphCoordinate( $boundings->x0, $boundings->y0 ), 1127 new ezcGraphCoordinate( $boundings->x1, $boundings->y0 ), 1128 new ezcGraphCoordinate( $boundings->x1, $boundings->y1 ), 1129 new ezcGraphCoordinate( $boundings->x0, $boundings->y1 ), 1130 ), 1131 $background, 1132 true 1133 ); 1134 } 1135 1136 if ( ( $borderColor instanceof ezcGraphColor ) && 1137 ( $borderWidth > 0 ) ) 1138 { 1139 // Draw border 1140 $this->driver->drawPolygon( 1141 array( 1142 new ezcGraphCoordinate( $boundings->x0, $boundings->y0 ), 1143 new ezcGraphCoordinate( $boundings->x1, $boundings->y0 ), 1144 new ezcGraphCoordinate( $boundings->x1, $boundings->y1 ), 1145 new ezcGraphCoordinate( $boundings->x0, $boundings->y1 ), 1146 ), 1147 $borderColor, 1148 false, 1149 $borderWidth 1150 ); 1151 1152 // Reduce local boundings by borderWidth 1153 $boundings->x0 += $borderWidth; 1154 $boundings->y0 += $borderWidth; 1155 $boundings->x1 -= $borderWidth; 1156 $boundings->y1 -= $borderWidth; 1157 } 1158 1159 // Apply padding 1160 $boundings->x0 += $padding; 1161 $boundings->y0 += $padding; 1162 $boundings->x1 -= $padding; 1163 $boundings->y1 -= $padding; 1164 1165 // Add box title 1166 if ( $title !== false ) 1167 { 1168 switch ( $this->options->titlePosition ) 1169 { 1170 case ezcGraph::TOP: 1171 $this->driver->drawTextBox( 1172 $title, 1173 new ezcGraphCoordinate( $boundings->x0, $boundings->y0 ), 1174 $boundings->width, 1175 $titleSize, 1176 $this->options->titleAlignement 1177 ); 1178 1179 $boundings->y0 += $titleSize + $padding; 1180 $boundings->y1 -= $titleSize + $padding; 1181 break; 1182 case ezcGraph::BOTTOM: 1183 $this->driver->drawTextBox( 1184 $title, 1185 new ezcGraphCoordinate( $boundings->x0, $boundings->y1 - $titleSize ), 1186 $boundings->width, 1187 $titleSize, 1188 $this->options->titleAlignement 1189 ); 1190 1191 $boundings->y1 -= $titleSize + $padding; 1192 break; 1193 } 1194 } 1195 1196 return $boundings; 1197 } 1198 1199 /** 1200 * Draw text 1201 * 1202 * Draws the provided text in the boundings 1203 * 1204 * @param ezcGraphBoundings $boundings Boundings of text 1205 * @param string $text Text 1206 * @param int $align Alignement of text 1207 * @param ezcGraphRotation $rotation 1208 * @return void 1209 */ 1210 public function drawText( 1211 ezcGraphBoundings $boundings, 1212 $text, 1213 $align = ezcGraph::LEFT, 1214 ezcGraphRotation $rotation = null ) 1215 { 1216 $this->driver->drawTextBox( 1217 $text, 1218 new ezcGraphCoordinate( $boundings->x0, $boundings->y0 ), 1219 $boundings->width, 1220 $boundings->height, 1221 $align, 1222 $rotation 1223 ); 1224 } 1225 1226 /** 1227 * Draw grid line 1228 * 1229 * Draw line for the grid in the chart background 1230 * 1231 * @param ezcGraphCoordinate $start Start point 1232 * @param ezcGraphCoordinate $end End point 1233 * @param ezcGraphColor $color Color of the grid line 1234 * @return void 1235 */ 1236 public function drawGridLine( ezcGraphCoordinate $start, ezcGraphCoordinate $end, ezcGraphColor $color ) 1237 { 1238 $this->driver->drawLine( 1239 $start, 1240 $end, 1241 $color, 1242 1 1243 ); 1244 } 1245 1246 /** 1247 * Draw step line 1248 * 1249 * Draw a step (marker for label position) on a axis. 1250 * 1251 * @param ezcGraphCoordinate $start Start point 1252 * @param ezcGraphCoordinate $end End point 1253 * @param ezcGraphColor $color Color of the grid line 1254 * @return void 1255 */ 1256 public function drawStepLine( ezcGraphCoordinate $start, ezcGraphCoordinate $end, ezcGraphColor $color ) 1257 { 1258 $this->driver->drawLine( 1259 $start, 1260 $end, 1261 $color, 1262 1 1263 ); 1264 } 1265 1266 /** 1267 * Draw axis 1268 * 1269 * Draws an axis form the provided start point to the end point. A specific 1270 * angle of the axis is not required. 1271 * 1272 * For the labeleing of the axis a sorted array with major steps and an 1273 * array with minor steps is expected, which are build like this: 1274 * array( 1275 * array( 1276 * 'position' => (float), 1277 * 'label' => (string), 1278 * ) 1279 * ) 1280 * where the label is optional. 1281 * 1282 * The label renderer class defines how the labels are rendered. For more 1283 * documentation on this topic have a look at the basic label renderer 1284 * class. 1285 * 1286 * Additionally it can be specified if a major and minor grid are rendered 1287 * by defining a color for them. The axis label is used to add a caption 1288 * for the axis. 1289 * 1290 * @param ezcGraphBoundings $boundings Boundings of axis 1291 * @param ezcGraphCoordinate $start Start point of axis 1292 * @param ezcGraphCoordinate $end Endpoint of axis 1293 * @param ezcGraphChartElementAxis $axis Axis to render 1294 * @param ezcGraphAxisLabelRenderer $labelClass Used label renderer 1295 * @return void 1296 */ 1297 public function drawAxis( 1298 ezcGraphBoundings $boundings, 1299 ezcGraphCoordinate $start, 1300 ezcGraphCoordinate $end, 1301 ezcGraphChartElementAxis $axis, 1302 ezcGraphAxisLabelRenderer $labelClass = null, 1303 ezcGraphBoundings $innerBoundings = null ) 1304 { 1305 // Legacy axis drawing for BC reasons 1306 if ( $innerBoundings === null ) 1307 { 1308 return $this->legacyDrawAxis( $boundings, $start, $end, $axis, $labelClass ); 1309 } 1310 1311 // Calculate axis start and end points depending on inner boundings 1312 if ( ( $axis->position === ezcGraph::TOP ) || 1313 ( $axis->position === ezcGraph::BOTTOM ) ) 1314 { 1315 $innerStart = new ezcGraphCoordinate( 1316 $start->x + $boundings->x0, 1317 ( $axis->position === ezcGraph::TOP ? $innerBoundings->y0 : $innerBoundings->y1 ) 1318 ); 1319 $innerEnd = new ezcGraphCoordinate( 1320 $end->x + $boundings->x0, 1321 ( $axis->position === ezcGraph::TOP ? $innerBoundings->y1 : $innerBoundings->y0 ) 1322 ); 1323 } 1324 else 1325 { 1326 $innerStart = new ezcGraphCoordinate( 1327 ( $axis->position === ezcGraph::LEFT ? $innerBoundings->x0 : $innerBoundings->x1 ), 1328 $start->y + $boundings->y0 1329 ); 1330 $innerEnd = new ezcGraphCoordinate( 1331 ( $axis->position === ezcGraph::LEFT ? $innerBoundings->x1 : $innerBoundings->x0 ), 1332 $end->y + $boundings->y0 1333 ); 1334 } 1335 1336 // Shorten axis, if requested 1337 if ( $this->options->shortAxis ) 1338 { 1339 $start = clone $innerStart; 1340 $end = clone $innerEnd; 1341 } 1342 else 1343 { 1344 $start->x += $boundings->x0; 1345 $start->y += $boundings->y0; 1346 $end->x += $boundings->x0; 1347 $end->y += $boundings->y0; 1348 } 1349 1350 // Determine normalized direction 1351 $direction = new ezcGraphVector( 1352 $start->x - $end->x, 1353 $start->y - $end->y 1354 ); 1355 $direction->unify(); 1356 1357 // Draw axis 1358 $this->driver->drawLine( 1359 $start, 1360 $end, 1361 $axis->border, 1362 1 1363 ); 1364 1365 // Draw small arrowhead 1366 $this->drawAxisArrowHead( 1367 $end, 1368 $direction, 1369 max( 1370 $axis->minArrowHeadSize, 1371 min( 1372 $axis->maxArrowHeadSize, 1373 abs( ceil( ( ( $end->x - $start->x ) + ( $end->y - $start->y ) ) * $axis->axisSpace / 4 ) ) 1374 ) 1375 ), 1376 $axis->border 1377 ); 1378 1379 // Draw axis label, if set 1380 $this->drawAxisLabel( $end, $innerBoundings, $axis ); 1381 1382 // If font should not be synchronized, use font configuration from 1383 // each axis 1384 if ( $this->options->syncAxisFonts === false ) 1385 { 1386 $this->driver->options->font = $axis->font; 1387 } 1388 1389 $labelClass->renderLabels( 1390 $this, 1391 $boundings, 1392 $innerStart, 1393 $innerEnd, 1394 $axis, 1395 $innerBoundings 1396 ); 1397 } 1398 1399 /** 1400 * Draw axis label 1401 * 1402 * Draw labels at the end of an axis. 1403 * 1404 * @param ezcGraphCoordinate $position 1405 * @param ezcGraphBoundings $boundings 1406 * @param ezcGraphChartElementAxis $axis 1407 * @return void 1408 */ 1409 protected function drawAxisLabel( ezcGraphCoordinate $position, ezcGraphBoundings $boundings, ezcGraphChartElementAxis $axis ) 1410 { 1411 if ( $axis->label === false ) 1412 { 1413 return; 1414 } 1415 1416 $width = $boundings->width; 1417 switch ( $axis->position ) 1418 { 1419 case ezcGraph::TOP: 1420 $this->driver->drawTextBox( 1421 $axis->label, 1422 new ezcGraphCoordinate( 1423 $position->x + $axis->labelMargin - $width * ( 1 - $axis->axisSpace * 2 ), 1424 $position->y - $axis->labelMargin - $axis->labelSize 1425 ), 1426 $width * ( 1 - $axis->axisSpace * 2 ) - $axis->labelMargin, 1427 $axis->labelSize, 1428 ezcGraph::TOP | ezcGraph::RIGHT, 1429 new ezcGraphRotation( $axis->labelRotation, new ezcGraphCoordinate( 1430 $position->x + $axis->labelSize / 2, 1431 $position->y - $axis->labelSize / 2 1432 ) ) 1433 ); 1434 break; 1435 case ezcGraph::BOTTOM: 1436 $this->driver->drawTextBox( 1437 $axis->label, 1438 new ezcGraphCoordinate( 1439 $position->x + $axis->labelMargin, 1440 $position->y + $axis->labelMargin 1441 ), 1442 $width * ( 1 - $axis->axisSpace * 2 ) - $axis->labelMargin, 1443 $axis->labelSize, 1444 ezcGraph::TOP | ezcGraph::LEFT, 1445 new ezcGraphRotation( $axis->labelRotation, new ezcGraphCoordinate( 1446 $position->x + $axis->labelSize / 2, 1447 $position->y + $axis->labelSize / 2 1448 ) ) 1449 ); 1450 break; 1451 case ezcGraph::LEFT: 1452 $this->driver->drawTextBox( 1453 $axis->label, 1454 new ezcGraphCoordinate( 1455 $position->x - $width, 1456 $position->y - $axis->labelSize - $axis->labelMargin 1457 ), 1458 $width - $axis->labelMargin, 1459 $axis->labelSize, 1460 ezcGraph::BOTTOM | ezcGraph::RIGHT, 1461 new ezcGraphRotation( $axis->labelRotation, new ezcGraphCoordinate( 1462 $position->x - $axis->labelSize / 2, 1463 $position->y - $axis->labelSize / 2 1464 ) ) 1465 ); 1466 break; 1467 case ezcGraph::RIGHT: 1468 $this->driver->drawTextBox( 1469 $axis->label, 1470 new ezcGraphCoordinate( 1471 $position->x, 1472 $position->y - $axis->labelSize - $axis->labelMargin 1473 ), 1474 $width - $axis->labelMargin, 1475 $axis->labelSize, 1476 ezcGraph::BOTTOM | ezcGraph::LEFT, 1477 new ezcGraphRotation( $axis->labelRotation, new ezcGraphCoordinate( 1478 $position->x + $axis->labelSize / 2, 1479 $position->y - $axis->labelSize / 2 1480 ) ) 1481 ); 1482 break; 1483 } 1484 } 1485 1486 /** 1487 * Draw axis 1488 * 1489 * Draws an axis form the provided start point to the end point. A specific 1490 * angle of the axis is not required. 1491 * 1492 * For the labeleing of the axis a sorted array with major steps and an 1493 * array with minor steps is expected, which are build like this: 1494 * array( 1495 * array( 1496 * 'position' => (float), 1497 * 'label' => (string), 1498 * ) 1499 * ) 1500 * where the label is optional. 1501 * 1502 * The label renderer class defines how the labels are rendered. For more 1503 * documentation on this topic have a look at the basic label renderer 1504 * class. 1505 * 1506 * Additionally it can be specified if a major and minor grid are rendered 1507 * by defining a color for them. The axis label is used to add a caption 1508 * for the axis. 1509 * 1510 * This function is deprecated and will be removed in favor of its 1511 * reimplementation using the innerBoundings parameter. 1512 * 1513 * @param ezcGraphBoundings $boundings Boundings of axis 1514 * @param ezcGraphCoordinate $start Start point of axis 1515 * @param ezcGraphCoordinate $end Endpoint of axis 1516 * @param ezcGraphChartElementAxis $axis Axis to render 1517 * @param ezcGraphAxisLabelRenderer $labelClass Used label renderer 1518 * @apichange 1519 * @return void 1520 */ 1521 protected function legacyDrawAxis( 1522 ezcGraphBoundings $boundings, 1523 ezcGraphCoordinate $start, 1524 ezcGraphCoordinate $end, 1525 ezcGraphChartElementAxis $axis, 1526 ezcGraphAxisLabelRenderer $labelClass = null ) 1527 { 1528 // Store axis space for use by label renderer 1529 switch ( $axis->position ) 1530 { 1531 case ezcGraph::TOP: 1532 case ezcGraph::BOTTOM: 1533 $this->xAxisSpace = ( $boundings->width ) * $axis->axisSpace; 1534 break; 1535 case ezcGraph::LEFT: 1536 case ezcGraph::RIGHT: 1537 $this->yAxisSpace = ( $boundings->height ) * $axis->axisSpace; 1538 break; 1539 } 1540 1541 // Clone boundings because of internal modifications 1542 $boundings = clone $boundings; 1543 1544 $start->x += $boundings->x0; 1545 $start->y += $boundings->y0; 1546 $end->x += $boundings->x0; 1547 $end->y += $boundings->y0; 1548 1549 // Shorten drawn axis, if requested. 1550 if ( ( $this->options->shortAxis === true ) && 1551 ( ( $axis->position === ezcGraph::TOP ) || 1552 ( $axis->position === ezcGraph::BOTTOM ) ) ) 1553 { 1554 $axisStart = clone $start; 1555 $axisEnd = clone $end; 1556 1557 $axisStart->y += $boundings->height * $axis->axisSpace * 1558 ( $axis->position === ezcGraph::TOP ? 1 : -1 ); 1559 $axisEnd->y -= $boundings->height * $axis->axisSpace * 1560 ( $axis->position === ezcGraph::TOP ? 1 : -1 ); 1561 } 1562 elseif ( ( $this->options->shortAxis === true ) && 1563 ( ( $axis->position === ezcGraph::LEFT ) || 1564 ( $axis->position === ezcGraph::RIGHT ) ) ) 1565 { 1566 $axisStart = clone $start; 1567 $axisEnd = clone $end; 1568 1569 $axisStart->x += $boundings->width * $axis->axisSpace * 1570 ( $axis->position === ezcGraph::LEFT ? 1 : -1 ); 1571 $axisEnd->x -= $boundings->width * $axis->axisSpace * 1572 ( $axis->position === ezcGraph::LEFT ? 1 : -1 ); 1573 } 1574 else 1575 { 1576 $axisStart = $start; 1577 $axisEnd = $end; 1578 } 1579 1580 // Determine normalized direction 1581 $direction = new ezcGraphVector( 1582 $start->x - $end->x, 1583 $start->y - $end->y 1584 ); 1585 $direction->unify(); 1586 1587 // Draw axis 1588 $this->driver->drawLine( 1589 $axisStart, 1590 $axisEnd, 1591 $axis->border, 1592 1 1593 ); 1594 1595 // Draw small arrowhead 1596 $this->drawAxisArrowHead( 1597 $axisEnd, 1598 $direction, 1599 max( 1600 $axis->minArrowHeadSize, 1601 min( 1602 $axis->maxArrowHeadSize, 1603 abs( ceil( ( ( $end->x - $start->x ) + ( $end->y - $start->y ) ) * $axis->axisSpace / 4 ) ) 1604 ) 1605 ), 1606 $axis->border 1607 ); 1608 1609 // Draw axis label, if set 1610 $this->drawAxisLabel( $end, $boundings, $axis ); 1611 1612 // Collect axis labels and draw, when all axisSpaces are collected 1613 $this->axisLabels[] = array( 1614 'object' => $labelClass, 1615 'boundings' => $boundings, 1616 'start' => clone $start, 1617 'end' => clone $end, 1618 'axis' => $axis, 1619 ); 1620 1621 if ( $this->xAxisSpace && $this->yAxisSpace ) 1622 { 1623 $this->drawAxisLabels(); 1624 } 1625 } 1626 1627 /** 1628 * Draw all left axis labels 1629 * 1630 * @return void 1631 */ 1632 protected function drawAxisLabels() 1633 { 1634 foreach ( $this->axisLabels as $nr => $axisLabel ) 1635 { 1636 // If font should not be synchronized, use font configuration from 1637 // each axis 1638 if ( $this->options->syncAxisFonts === false ) 1639 { 1640 $this->driver->options->font = $axisLabel['axis']->font; 1641 } 1642 1643 $start = $axisLabel['start']; 1644 $end = $axisLabel['end']; 1645 1646 $direction = new ezcGraphVector( 1647 $end->x - $start->x, 1648 $end->y - $start->y 1649 ); 1650 $direction->unify(); 1651 1652 // Convert elipse to circle for correct angle calculation 1653 $direction->y *= ( $this->xAxisSpace / $this->yAxisSpace ); 1654 $angle = $direction->angle( new ezcGraphVector( 0, 1 ) ); 1655 1656 $movement = new ezcGraphVector( 1657 sin( $angle ) * $this->xAxisSpace * ( $direction->x < 0 ? -1 : 1 ), 1658 cos( $angle ) * $this->yAxisSpace 1659 ); 1660 1661 $start->x += $movement->x; 1662 $start->y += $movement->y; 1663 $end->x -= $movement->x; 1664 $end->y -= $movement->y; 1665 1666 $axisLabel['object']->renderLabels( 1667 $this, 1668 $axisLabel['boundings'], 1669 $start, 1670 $end, 1671 $axisLabel['axis'] 1672 ); 1673 1674 // Prevent from redrawing axis on more then 2 axis. 1675 unset( $this->axisLabels[$nr] ); 1676 } 1677 } 1678 1679 /** 1680 * Draw background image 1681 * 1682 * Draws a background image at the defined position. If repeat is set the 1683 * background image will be repeated like any texture. 1684 * 1685 * @param ezcGraphBoundings $boundings Boundings for the background image 1686 * @param string $file Filename of background image 1687 * @param int $position Position of background image 1688 * @param int $repeat Type of repetition 1689 * @return void 1690 */ 1691 public function drawBackgroundImage( 1692 ezcGraphBoundings $boundings, 1693 $file, 1694 $position = 48, // ezcGraph::CENTER | ezcGraph::MIDDLE 1695 $repeat = ezcGraph::NO_REPEAT ) 1696 { 1697 $imageData = getimagesize( $file ); 1698 $imageWidth = $imageData[0]; 1699 $imageHeight = $imageData[1]; 1700 1701 $imageWidth = min( $imageWidth, $boundings->width ); 1702 $imageHeight = min( $imageHeight, $boundings->height ); 1703 1704 $imagePosition = new ezcGraphCoordinate( 1705 $boundings->x0, 1706 $boundings->y0 1707 ); 1708 1709 // Determine x position 1710 switch ( true ) { 1711 case ( $repeat & ezcGraph::HORIZONTAL ): 1712 // If is repeated on this axis fall back to position zero 1713 case ( $position & ezcGraph::LEFT ): 1714 $imagePosition->x = $boundings->x0; 1715 break; 1716 case ( $position & ezcGraph::RIGHT ): 1717 $imagePosition->x = max( 1718 $boundings->x1 - $imageWidth, 1719 $boundings->x0 1720 ); 1721 break; 1722 default: 1723 $imagePosition->x = max( 1724 $boundings->x0 + ( $boundings->width - $imageWidth ) / 2, 1725 $boundings->x0 1726 ); 1727 break; 1728 } 1729 1730 // Determine y position 1731 switch ( true ) { 1732 case ( $repeat & ezcGraph::VERTICAL ): 1733 // If is repeated on this axis fall back to position zero 1734 case ( $position & ezcGraph::TOP ): 1735 $imagePosition->y = $boundings->y0; 1736 break; 1737 case ( $position & ezcGraph::BOTTOM ): 1738 $imagePosition->y = max( 1739 $boundings->y1 - $imageHeight, 1740 $boundings->y0 1741 ); 1742 break; 1743 default: 1744 $imagePosition->y = max( 1745 $boundings->y0 + ( $boundings->height - $imageHeight ) / 2, 1746 $boundings->y0 1747 ); 1748 break; 1749 } 1750 1751 // Texturize backround based on position and repetition 1752 $position = new ezcGraphCoordinate( 1753 $imagePosition->x, 1754 $imagePosition->y 1755 ); 1756 1757 do 1758 { 1759 $position->y = $imagePosition->y; 1760 1761 do 1762 { 1763 $this->driver->drawImage( 1764 $file, 1765 $position, 1766 $imageWidth, 1767 $imageHeight 1768 ); 1769 1770 $position->y += $imageHeight; 1771 } 1772 while ( ( $position->y < $boundings->y1 ) && 1773 ( $repeat & ezcGraph::VERTICAL ) ); 1774 1775 $position->x += $imageWidth; 1776 } 1777 while ( ( $position->x < $boundings->x1 ) && 1778 ( $repeat & ezcGraph::HORIZONTAL ) ); 1779 } 1780 1781 /** 1782 * Call all postprocessing functions 1783 * 1784 * @return void 1785 */ 1786 protected function finish() 1787 { 1788 $this->finishCircleSectors(); 1789 $this->finishPieSegmentLabels(); 1790 $this->finishLineSymbols(); 1791 1792 return true; 1793 } 1794 1795 /** 1796 * Reset renderer properties 1797 * 1798 * Reset all renderer properties, which were calculated during the 1799 * rendering process, to offer a clean environment for rerendering. 1800 * 1801 * @return void 1802 */ 1803 protected function resetRenderer() 1804 { 1805 parent::resetRenderer(); 1806 1807 // Also reset special 2D renderer options 1808 $this->pieSegmentLabels = array( 1809 0 => array(), 1810 1 => array(), 1811 ); 1812 $this->pieSegmentBoundings = false; 1813 $this->linePostSymbols = array(); 1814 $this->axisLabels = array(); 1815 $this->circleSectors = array(); 1816 } 1817 1818 /** 1819 * Render odometer chart 1820 * 1821 * @param ezcGraphBoundings $boundings 1822 * @param ezcGraphChartElementAxis $axis 1823 * @param ezcGraphOdometerChartOptions $options 1824 * @return ezcGraphBoundings 1825 */ 1826 public function drawOdometer( 1827 ezcGraphBoundings $boundings, 1828 ezcGraphChartElementAxis $axis, 1829 ezcGraphOdometerChartOptions $options ) 1830 { 1831 $height = $boundings->height * $options->odometerHeight; 1832 1833 // Draw axis 1834 $oldAxisSpace = $axis->axisSpace; 1835 $axis->axisSpace = 0; 1836 1837 $axis->render( $this, $boundings ); 1838 1839 // Reset axisspaces to correct values 1840 $this->xAxisSpace = $boundings->width * $oldAxisSpace; 1841 $this->yAxisSpace = ( $boundings->height - $height ) / 2; 1842 1843 $this->drawAxisLabels(); 1844 1845 // Reduce size of chart boundings respecting requested odometer height 1846 $boundings->x0 += $this->xAxisSpace; 1847 $boundings->x1 -= $this->xAxisSpace; 1848 $boundings->y0 += $this->yAxisSpace; 1849 $boundings->y1 -= $this->yAxisSpace; 1850 1851 $gradient = new ezcGraphLinearGradient( 1852 new ezcGraphCoordinate( $boundings->x0, $boundings->y0 ), 1853 new ezcGraphCoordinate( $boundings->x1, $boundings->y0 ), 1854 $options->startColor, 1855 $options->endColor 1856 ); 1857 1858 // Simply draw box with gradient and optional border 1859 $this->drawBox( 1860 $boundings, 1861 $gradient, 1862 $options->borderColor, 1863 $options->borderWidth 1864 ); 1865 1866 // Return modified chart boundings 1867 return $boundings; 1868 } 1869 1870 /** 1871 * Draw a single odometer marker. 1872 * 1873 * @param ezcGraphBoundings $boundings 1874 * @param ezcGraphCoordinate $position 1875 * @param int $symbol 1876 * @param ezcGraphColor $color 1877 * @param int $width 1878 */ 1879 public function drawOdometerMarker( 1880 ezcGraphBoundings $boundings, 1881 ezcGraphCoordinate $position, 1882 $symbol, 1883 ezcGraphColor $color, 1884 $width ) 1885 { 1886 $this->driver->drawLine( 1887 new ezcGraphCoordinate( 1888 $xPos = $boundings->x0 + ( $position->x * $boundings->width ), 1889 $boundings->y0 1890 ), 1891 new ezcGraphCoordinate( 1892 $xPos, 1893 $boundings->y1 1894 ), 1895 $color, 1896 $width 1897 ); 1898 } 1899 } 1900 1901 ?>
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated: Thu Jul 28 15:48:31 2011 | Cross-referenced by PHPXref 0.7 |