| <?php |
| /** |
| * File containing the two dimensional renderer |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| * @package Graph |
| * @version //autogentag// |
| * @copyright Copyright (C) 2005-2010 eZ Systems AS. All rights reserved. |
| * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0 |
| */ |
| /** |
| * Class to transform chart primitives into image primitives. Renders charts in |
| * a two dimensional view. |
| * |
| * The class options are defined in the class {@link ezcGraphRenderer2dOptions} |
| * extending the basic renderer options in {@link ezcGraphRendererOptions}. |
| * |
| * <code> |
| * $graph = new ezcGraphPieChart(); |
| * $graph->palette = new ezcGraphPaletteBlack(); |
| * $graph->title = 'Access statistics'; |
| * $graph->options->label = '%2$d (%3$.1f%%)'; |
| * |
| * $graph->data['Access statistics'] = new ezcGraphArrayDataSet( array( |
| * 'Mozilla' => 19113, |
| * 'Explorer' => 10917, |
| * 'Opera' => 1464, |
| * 'Safari' => 652, |
| * 'Konqueror' => 474, |
| * ) ); |
| * $graph->data['Access statistics']->highlight['Explorer'] = true; |
| * |
| * // $graph->renderer = new ezcGraphRenderer2d(); |
| * |
| * $graph->renderer->options->moveOut = .2; |
| * |
| * $graph->renderer->options->pieChartOffset = 63; |
| * |
| * $graph->renderer->options->pieChartGleam = .3; |
| * $graph->renderer->options->pieChartGleamColor = '#FFFFFF'; |
| * $graph->renderer->options->pieChartGleamBorder = 2; |
| * |
| * $graph->renderer->options->pieChartShadowSize = 3; |
| * $graph->renderer->options->pieChartShadowColor = '#000000'; |
| * |
| * $graph->renderer->options->legendSymbolGleam = .5; |
| * $graph->renderer->options->legendSymbolGleamSize = .9; |
| * $graph->renderer->options->legendSymbolGleamColor = '#FFFFFF'; |
| * |
| * $graph->renderer->options->pieChartSymbolColor = '#BABDB688'; |
| * |
| * $graph->render( 400, 150, 'tutorial_pie_chart_pimped.svg' ); |
| * </code> |
| * |
| * @version //autogentag// |
| * @package Graph |
| * @mainclass |
| */ |
| class ezcGraphRenderer2d |
| extends |
| ezcGraphRenderer |
| implements |
| ezcGraphRadarRenderer, ezcGraphStackedBarsRenderer, ezcGraphOdometerRenderer |
| { |
| |
| /** |
| * Pie segment labels divided into two array, containing the labels on the |
| * left and right side of the pie chart center. |
| * |
| * @var array |
| */ |
| protected $pieSegmentLabels = array( |
| 0 => array(), |
| 1 => array(), |
| ); |
| |
| /** |
| * Contains the boundings used for pie segments |
| * |
| * @var ezcGraphBoundings |
| */ |
| protected $pieSegmentBoundings = false; |
| |
| /** |
| * Array with symbols for post processing, which ensures, that the symbols |
| * are rendered topmost. |
| * |
| * @var array |
| */ |
| protected $linePostSymbols = array(); |
| |
| /** |
| * Options |
| * |
| * @var ezcGraphRenderer2dOptions |
| */ |
| protected $options; |
| |
| /** |
| * Collect axis labels, so that the axis are drawn, when all axis spaces |
| * are known. |
| * |
| * @var array |
| */ |
| protected $axisLabels = array(); |
| |
| /** |
| * Collects circle sectors to draw shadow in background of all circle |
| * sectors. |
| * |
| * @var array |
| */ |
| protected $circleSectors = array(); |
| |
| /** |
| * Constructor |
| * |
| * @param array $options Default option array |
| * @return void |
| * @ignore |
| */ |
| public function __construct( array $options = array() ) |
| { |
| $this->options = new ezcGraphRenderer2dOptions( $options ); |
| } |
| |
| /** |
| * __get |
| * |
| * @param mixed $propertyName |
| * @throws ezcBasePropertyNotFoundException |
| * If a the value for the property options is not an instance of |
| * @return mixed |
| * @ignore |
| */ |
| public function __get( $propertyName ) |
| { |
| switch ( $propertyName ) |
| { |
| case 'options': |
| return $this->options; |
| default: |
| return parent::__get( $propertyName ); |
| } |
| } |
| |
| /** |
| * Draw pie segment |
| * |
| * Draws a single pie segment |
| * |
| * @param ezcGraphBoundings $boundings Chart boundings |
| * @param ezcGraphContext $context Context of call |
| * @param ezcGraphColor $color Color of pie segment |
| * @param float $startAngle Start angle |
| * @param float $endAngle End angle |
| * @param mixed $label Label of pie segment |
| * @param bool $moveOut Move out from middle for hilighting |
| * @return void |
| */ |
| public function drawPieSegment( |
| ezcGraphBoundings $boundings, |
| ezcGraphContext $context, |
| ezcGraphColor $color, |
| $startAngle = .0, |
| $endAngle = 360., |
| $label = false, |
| $moveOut = false ) |
| { |
| // Apply offset |
| $startAngle += $this->options->pieChartOffset; |
| $endAngle += $this->options->pieChartOffset; |
| |
| // Calculate position and size of pie |
| $center = new ezcGraphCoordinate( |
| $boundings->x0 + ( $boundings->width ) / 2, |
| $boundings->y0 + ( $boundings->height ) / 2 |
| ); |
| |
| // Limit radius to fourth of width and half of height at maximum |
| $radius = min( |
| ( $boundings->width ) * $this->options->pieHorizontalSize, |
| ( $boundings->height ) * $this->options->pieVerticalSize |
| ); |
| |
| // Move pie segment out of the center |
| if ( $moveOut ) |
| { |
| $direction = ( $endAngle + $startAngle ) / 2; |
| |
| $center = new ezcGraphCoordinate( |
| $center->x + $this->options->moveOut * $radius * cos( deg2rad( $direction ) ), |
| $center->y + $this->options->moveOut * $radius * sin( deg2rad( $direction ) ) |
| ); |
| } |
| |
| // Add circle sector to queue |
| $this->circleSectors[] = array( |
| 'center' => $center, |
| 'context' => $context, |
| 'width' => $radius * 2 * ( 1 - $this->options->moveOut ), |
| 'height' => $radius * 2 * ( 1 - $this->options->moveOut ), |
| 'start' => $startAngle, |
| 'end' => $endAngle, |
| 'color' => $color, |
| ); |
| |
| if ( $label ) |
| { |
| // Determine position of label |
| $direction = ( $endAngle + $startAngle ) / 2; |
| $pieSegmentCenter = new ezcGraphCoordinate( |
| $center->x + cos( deg2rad( $direction ) ) * $radius, |
| $center->y + sin( deg2rad( $direction ) ) * $radius |
| ); |
| |
| // Split labels up into left an right size and index them on their |
| // y position |
| $this->pieSegmentLabels[(int) ($pieSegmentCenter->x > $center->x)][$pieSegmentCenter->y] = array( |
| new ezcGraphCoordinate( |
| $center->x + cos( deg2rad( $direction ) ) * $radius * 2 / 3, |
| $center->y + sin( deg2rad( $direction ) ) * $radius * 2 / 3 |
| ), |
| $label, |
| $context |
| ); |
| } |
| |
| if ( !$this->pieSegmentBoundings ) |
| { |
| $this->pieSegmentBoundings = $boundings; |
| } |
| } |
| |
| /** |
| * Draws the collected circle sectors |
| * |
| * All circle sectors are collected and drawn later to be able to render |
| * the shadows of the pie segments in the back of all pie segments. |
| * |
| * @return void |
| */ |
| protected function finishCircleSectors() |
| { |
| // Add circle sector sides to simple z buffer prioriry list |
| if ( $this->options->pieChartShadowSize > 0 ) |
| { |
| foreach ( $this->circleSectors as $circleSector ) |
| { |
| $this->driver->drawCircleSector( |
| new ezcGraphCoordinate( |
| $circleSector['center']->x + $this->options->pieChartShadowSize, |
| $circleSector['center']->y + $this->options->pieChartShadowSize |
| ), |
| $circleSector['width'], |
| $circleSector['height'], |
| $circleSector['start'], |
| $circleSector['end'], |
| $this->options->pieChartShadowColor->transparent( $this->options->pieChartShadowTransparency ), |
| true |
| ); |
| } |
| } |
| |
| foreach ( $this->circleSectors as $circleSector ) |
| { |
| // Draw circle sector |
| $this->addElementReference( |
| $circleSector['context'], |
| $this->driver->drawCircleSector( |
| $circleSector['center'], |
| $circleSector['width'], |
| $circleSector['height'], |
| $circleSector['start'], |
| $circleSector['end'], |
| $circleSector['color'], |
| true |
| ) |
| ); |
| |
| $darkenedColor = $circleSector['color']->darken( $this->options->dataBorder ); |
| $this->driver->drawCircleSector( |
| $circleSector['center'], |
| $circleSector['width'], |
| $circleSector['height'], |
| $circleSector['start'], |
| $circleSector['end'], |
| $darkenedColor, |
| false |
| ); |
| |
| if ( $this->options->pieChartGleam !== false ) |
| { |
| $gradient = new ezcGraphLinearGradient( |
| $circleSector['center'], |
| new ezcGraphCoordinate( |
| $circleSector['center']->x, |
| $circleSector['center']->y - $circleSector['height'] / 2 |
| ), |
| $this->options->pieChartGleamColor->transparent( 1 ), |
| $this->options->pieChartGleamColor->transparent( $this->options->pieChartGleam ) |
| ); |
| |
| $this->addElementReference( $circleSector['context'], |
| $this->driver->drawCircleSector( |
| $circleSector['center'], |
| $circleSector['width'] - $this->options->pieChartGleamBorder * 2, |
| $circleSector['height'] - $this->options->pieChartGleamBorder * 2, |
| $circleSector['start'], |
| $circleSector['end'], |
| $gradient, |
| true |
| ) |
| ); |
| |
| $gradient = new ezcGraphLinearGradient( |
| new ezcGraphCoordinate( |
| $circleSector['center']->x, |
| $circleSector['center']->y + $circleSector['height'] / 4 |
| ), |
| new ezcGraphCoordinate( |
| $circleSector['center']->x, |
| $circleSector['center']->y + $circleSector['height'] / 2 |
| ), |
| $this->options->pieChartGleamColor->transparent( 1 ), |
| $this->options->pieChartGleamColor->transparent( $this->options->pieChartGleam ) |
| ); |
| |
| $this->addElementReference( $circleSector['context'], |
| $this->driver->drawCircleSector( |
| $circleSector['center'], |
| $circleSector['width'] - $this->options->pieChartGleamBorder * 2, |
| $circleSector['height'] - $this->options->pieChartGleamBorder * 2, |
| $circleSector['start'], |
| $circleSector['end'], |
| $gradient, |
| true |
| ) |
| ); |
| } |
| } |
| } |
| |
| /** |
| * Draws the collected pie segment labels |
| * |
| * All labels are collected and drawn later to be able to partition the |
| * available space for the labels woth knowledge of the overall label |
| * count and their required size and optimal position. |
| * |
| * @return void |
| */ |
| protected function finishPieSegmentLabels() |
| { |
| if ( $this->pieSegmentBoundings === false ) |
| { |
| return true; |
| } |
| |
| $boundings = $this->pieSegmentBoundings; |
| |
| // Calculate position and size of pie |
| $center = new ezcGraphCoordinate( |
| $boundings->x0 + ( $boundings->width ) / 2, |
| $boundings->y0 + ( $boundings->height ) / 2 |
| ); |
| |
| // Limit radius to fourth of width and half of height at maximum |
| $radius = min( |
| ( $boundings->width ) * $this->options->pieHorizontalSize, |
| ( $boundings->height ) * $this->options->pieVerticalSize |
| ); |
| |
| $pieChartHeight = min( |
| $radius * 2 + $radius / max( 1, count ( $this->pieSegmentLabels[0] ), count( $this->pieSegmentLabels[1] ) ) * 4, |
| $boundings->height |
| ); |
| $pieChartYPosition = $boundings->y0 + ( ( $boundings->height ) - $pieChartHeight ) / 2; |
| |
| // Calculate maximum height of labels |
| $labelHeight = min( |
| ( count( $this->pieSegmentLabels[0] ) |
| ? $pieChartHeight / count( $this->pieSegmentLabels[0] ) |
| : $pieChartHeight |
| ), |
| ( count( $this->pieSegmentLabels[1] ) |
| ? $pieChartHeight / count( $this->pieSegmentLabels[1] ) |
| : $pieChartHeight |
| ), |
| ( $pieChartHeight ) * $this->options->maxLabelHeight |
| ); |
| |
| $symbolSize = $this->options->symbolSize; |
| |
| foreach ( $this->pieSegmentLabels as $side => $labelPart ) |
| { |
| $minHeight = $pieChartYPosition; |
| $toShare = $pieChartHeight - count( $labelPart ) * $labelHeight; |
| |
| // Sort to draw topmost label first |
| ksort( $labelPart ); |
| $sign = ( $side ? -1 : 1 ); |
| |
| foreach ( $labelPart as $height => $label ) |
| { |
| if ( ( $height - $labelHeight / 2 ) > $minHeight ) |
| { |
| $share = min( $toShare, ( $height - $labelHeight / 2) - $minHeight ); |
| $minHeight += $share; |
| $toShare -= $share; |
| } |
| |
| // Determine position of label |
| $minHeight += max( 0, $height - $minHeight - $labelHeight ) / $pieChartHeight * $toShare; |
| $verticalDistance = ( $center->y - $minHeight - $labelHeight / 2 ) / $radius; |
| |
| $labelPosition = new ezcGraphCoordinate( |
| $center->x - |
| $sign * ( |
| abs( $verticalDistance ) > 1 |
| // If vertical distance to center is greater then the |
| // radius, use the centerline for the horizontal |
| // position |
| ? max ( |
| 5, |
| abs( $label[0]->x - $center->x ) |
| ) |
| // Else place the label outside of the pie chart |
| : ( cos ( asin ( $verticalDistance ) ) * $radius + |
| $symbolSize * (int) $this->options->showSymbol |
| ) |
| ), |
| $minHeight + $labelHeight / 2 |
| ); |
| |
| if ( $this->options->showSymbol ) |
| { |
| // Draw label |
| $this->driver->drawLine( |
| $label[0], |
| $labelPosition, |
| $this->options->pieChartSymbolColor, |
| 1 |
| ); |
| |
| $this->driver->drawCircle( |
| $label[0], |
| $symbolSize, |
| $symbolSize, |
| $this->options->pieChartSymbolColor, |
| true |
| ); |
| $this->driver->drawCircle( |
| $labelPosition, |
| $symbolSize, |
| $symbolSize, |
| $this->options->pieChartSymbolColor, |
| true |
| ); |
| } |
| |
| $this->addElementReference( |
| $label[2], |
| $this->driver->drawTextBox( |
| $label[1], |
| new ezcGraphCoordinate( |
| ( !$side ? $boundings->x0 : $labelPosition->x + $symbolSize ), |
| $minHeight |
| ), |
| ( !$side ? $labelPosition->x - $boundings->x0 - $symbolSize : $boundings->x1 - $labelPosition->x - $symbolSize ), |
| $labelHeight, |
| ( !$side ? ezcGraph::RIGHT : ezcGraph::LEFT ) | ezcGraph::MIDDLE |
| ) |
| ); |
| |
| // Add used space to minHeight |
| $minHeight += $labelHeight; |
| } |
| } |
| } |
| |
| /** |
| * Draw the collected line symbols |
| * |
| * Symbols for the data lines are collected and delayed to ensure that |
| * they are not covered and hidden by other data lines. |
| * |
| * @return void |
| */ |
| protected function finishLineSymbols() |
| { |
| foreach ( $this->linePostSymbols as $symbol ) |
| { |
| $this->addElementReference( |
| $symbol['context'], |
| $this->drawSymbol( |
| $symbol['boundings'], |
| $symbol['color'], |
| $symbol['symbol'] |
| ) |
| ); |
| } |
| } |
| |
| /** |
| * Draw bar |
| * |
| * Draws a bar as a data element in a line chart |
| * |
| * @param ezcGraphBoundings $boundings Chart boundings |
| * @param ezcGraphContext $context Context of call |
| * @param ezcGraphColor $color Color of line |
| * @param ezcGraphCoordinate $position Position of data point |
| * @param float $stepSize Space which can be used for bars |
| * @param int $dataNumber Number of dataset |
| * @param int $dataCount Count of datasets in chart |
| * @param int $symbol Symbol to draw for line |
| * @param float $axisPosition Position of axis for drawing filled lines |
| * @return void |
| */ |
| public function drawBar( |
| ezcGraphBoundings $boundings, |
| ezcGraphContext $context, |
| ezcGraphColor $color, |
| ezcGraphCoordinate $position, |
| $stepSize, |
| $dataNumber = 1, |
| $dataCount = 1, |
| $symbol = ezcGraph::NO_SYMBOL, |
| $axisPosition = 0. ) |
| { |
| // Apply margin |
| $margin = $stepSize * $this->options->barMargin; |
| $padding = $stepSize * $this->options->barPadding; |
| $barWidth = ( $stepSize - $margin ) / $dataCount - $padding; |
| $offset = - $stepSize / 2 + $margin / 2 + ( $dataCount - $dataNumber - 1 ) * ( $padding + $barWidth ) + $padding / 2; |
| |
| $barPointArray = array( |
| new ezcGraphCoordinate( |
| $boundings->x0 + ( $boundings->width ) * $position->x + $offset, |
| $boundings->y0 + ( $boundings->height ) * $axisPosition |
| ), |
| new ezcGraphCoordinate( |
| $boundings->x0 + ( $boundings->width ) * $position->x + $offset, |
| $boundings->y0 + ( $boundings->height ) * $position->y |
| ), |
| new ezcGraphCoordinate( |
| $boundings->x0 + ( $boundings->width ) * $position->x + $offset + $barWidth, |
| $boundings->y0 + ( $boundings->height ) * $position->y |
| ), |
| new ezcGraphCoordinate( |
| $boundings->x0 + ( $boundings->width ) * $position->x + $offset + $barWidth, |
| $boundings->y0 + ( $boundings->height ) * $axisPosition |
| ), |
| ); |
| |
| $this->addElementReference( |
| $context, |
| $this->driver->drawPolygon( |
| $barPointArray, |
| $color, |
| true |
| ) |
| ); |
| |
| if ( $this->options->dataBorder > 0 ) |
| { |
| $darkened = $color->darken( $this->options->dataBorder ); |
| $this->driver->drawPolygon( |
| $barPointArray, |
| $darkened, |
| false, |
| 1 |
| ); |
| } |
| } |
| |
| /** |
| * Draw stacked bar |
| * |
| * Draws a stacked bar part as a data element in a line chart |
| * |
| * @param ezcGraphBoundings $boundings Chart boundings |
| * @param ezcGraphContext $context Context of call |
| * @param ezcGraphColor $color Color of line |
| * @param ezcGraphCoordinate $start |
| * @param ezcGraphCoordinate $position |
| * @param float $stepSize Space which can be used for bars |
| * @param int $symbol Symbol to draw for line |
| * @param float $axisPosition Position of axis for drawing filled lines |
| * @return void |
| */ |
| public function drawStackedBar( |
| ezcGraphBoundings $boundings, |
| ezcGraphContext $context, |
| ezcGraphColor $color, |
| ezcGraphCoordinate $start, |
| ezcGraphCoordinate $position, |
| $stepSize, |
| $symbol = ezcGraph::NO_SYMBOL, |
| $axisPosition = 0. ) |
| { |
| // Apply margin |
| $margin = $stepSize * $this->options->barMargin; |
| $barWidth = $stepSize - $margin; |
| $offset = - $stepSize / 2 + $margin / 2; |
| |
| $barPointArray = array( |
| new ezcGraphCoordinate( |
| $boundings->x0 + ( $boundings->width ) * $position->x + $offset, |
| $boundings->y0 + ( $boundings->height ) * $start->y |
| ), |
| new ezcGraphCoordinate( |
| $boundings->x0 + ( $boundings->width ) * $position->x + $offset, |
| $boundings->y0 + ( $boundings->height ) * $position->y |
| ), |
| new ezcGraphCoordinate( |
| $boundings->x0 + ( $boundings->width ) * $position->x + $offset + $barWidth, |
| $boundings->y0 + ( $boundings->height ) * $position->y |
| ), |
| new ezcGraphCoordinate( |
| $boundings->x0 + ( $boundings->width ) * $position->x + $offset + $barWidth, |
| $boundings->y0 + ( $boundings->height ) * $start->y |
| ), |
| ); |
| |
| $this->addElementReference( |
| $context, |
| $this->driver->drawPolygon( |
| $barPointArray, |
| $color, |
| true |
| ) |
| ); |
| |
| if ( $this->options->dataBorder > 0 ) |
| { |
| $darkened = $color->darken( $this->options->dataBorder ); |
| $this->driver->drawPolygon( |
| $barPointArray, |
| $darkened, |
| false, |
| 1 |
| ); |
| } |
| } |
| |
| /** |
| * Draw data line |
| * |
| * Draws a line as a data element in a line chart |
| * |
| * @param ezcGraphBoundings $boundings Chart boundings |
| * @param ezcGraphContext $context Context of call |
| * @param ezcGraphColor $color Color of line |
| * @param ezcGraphCoordinate $start Starting point |
| * @param ezcGraphCoordinate $end Ending point |
| * @param int $dataNumber Number of dataset |
| * @param int $dataCount Count of datasets in chart |
| * @param int $symbol Symbol to draw for line |
| * @param ezcGraphColor $symbolColor Color of the symbol, defaults to linecolor |
| * @param ezcGraphColor $fillColor Color to fill line with |
| * @param float $axisPosition Position of axis for drawing filled lines |
| * @param float $thickness Line thickness |
| * @return void |
| */ |
| public function drawDataLine( |
| ezcGraphBoundings $boundings, |
| ezcGraphContext $context, |
| ezcGraphColor $color, |
| ezcGraphCoordinate $start, |
| ezcGraphCoordinate $end, |
| $dataNumber = 1, |
| $dataCount = 1, |
| $symbol = ezcGraph::NO_SYMBOL, |
| ezcGraphColor $symbolColor = null, |
| ezcGraphColor $fillColor = null, |
| $axisPosition = 0., |
| $thickness = 1. ) |
| { |
| // Perhaps fill up line |
| if ( $fillColor !== null && |
| $start->x != $end->x ) |
| { |
| $startValue = $axisPosition - $start->y; |
| $endValue = $axisPosition - $end->y; |
| |
| if ( ( $startValue == 0 ) || |
| ( $endValue == 0 ) || |
| ( $startValue / abs( $startValue ) == $endValue / abs( $endValue ) ) ) |
| { |
| // Values have the same sign or are on the axis |
| $this->driver->drawPolygon( |
| array( |
| new ezcGraphCoordinate( |
| $boundings->x0 + ( $boundings->width ) * $start->x, |
| $boundings->y0 + ( $boundings->height ) * $start->y |
| ), |
| new ezcGraphCoordinate( |
| $boundings->x0 + ( $boundings->width ) * $end->x, |
| $boundings->y0 + ( $boundings->height ) * $end->y |
| ), |
| new ezcGraphCoordinate( |
| $boundings->x0 + ( $boundings->width ) * $end->x, |
| $boundings->y0 + ( $boundings->height ) * $axisPosition |
| ), |
| new ezcGraphCoordinate( |
| $boundings->x0 + ( $boundings->width ) * $start->x, |
| $boundings->y0 + ( $boundings->height ) * $axisPosition |
| ), |
| ), |
| $fillColor, |
| true |
| ); |
| } |
| else |
| { |
| // values are on differente sides of the axis - split the filled polygon |
| $startDiff = abs( $axisPosition - $start->y ); |
| $endDiff = abs( $axisPosition - $end->y ); |
| |
| $cuttingPosition = $startDiff / ( $endDiff + $startDiff ); |
| $cuttingPoint = new ezcGraphCoordinate( |
| $start->x + ( $end->x - $start->x ) * $cuttingPosition, |
| $axisPosition |
| ); |
| |
| $this->driver->drawPolygon( |
| array( |
| new ezcGraphCoordinate( |
| $boundings->x0 + ( $boundings->width ) * $start->x, |
| $boundings->y0 + ( $boundings->height ) * $axisPosition |
| ), |
| new ezcGraphCoordinate( |
| $boundings->x0 + ( $boundings->width ) * $start->x, |
| $boundings->y0 + ( $boundings->height ) * $start->y |
| ), |
| new ezcGraphCoordinate( |
| $boundings->x0 + ( $boundings->width ) * $cuttingPoint->x, |
| $boundings->y0 + ( $boundings->height ) * $cuttingPoint->y |
| ), |
| ), |
| $fillColor, |
| true |
| ); |
| |
| $this->driver->drawPolygon( |
| array( |
| new ezcGraphCoordinate( |
| $boundings->x0 + ( $boundings->width ) * $end->x, |
| $boundings->y0 + ( $boundings->height ) * $axisPosition |
| ), |
| new ezcGraphCoordinate( |
| $boundings->x0 + ( $boundings->width ) * $end->x, |
| $boundings->y0 + ( $boundings->height ) * $end->y |
| ), |
| new ezcGraphCoordinate( |
| $boundings->x0 + ( $boundings->width ) * $cuttingPoint->x, |
| $boundings->y0 + ( $boundings->height ) * $cuttingPoint->y |
| ), |
| ), |
| $fillColor, |
| true |
| ); |
| } |
| } |
| |
| // Draw line |
| $this->driver->drawLine( |
| new ezcGraphCoordinate( |
| $boundings->x0 + ( $boundings->width ) * $start->x, |
| $boundings->y0 + ( $boundings->height ) * $start->y |
| ), |
| new ezcGraphCoordinate( |
| $boundings->x0 + ( $boundings->width ) * $end->x, |
| $boundings->y0 + ( $boundings->height ) * $end->y |
| ), |
| $color, |
| $thickness |
| ); |
| |
| // Draw line symbol |
| if ( $symbol !== ezcGraph::NO_SYMBOL ) |
| { |
| if ( $symbolColor === null ) |
| { |
| $symbolColor = $color; |
| } |
| |
| $this->linePostSymbols[] = array( |
| 'boundings' => new ezcGraphBoundings( |
| $boundings->x0 + ( $boundings->width ) * $end->x - $this->options->symbolSize / 2, |
| $boundings->y0 + ( $boundings->height ) * $end->y - $this->options->symbolSize / 2, |
| $boundings->x0 + ( $boundings->width ) * $end->x + $this->options->symbolSize / 2, |
| $boundings->y0 + ( $boundings->height ) * $end->y + $this->options->symbolSize / 2 |
| ), |
| 'color' => $symbolColor, |
| 'context' => $context, |
| 'symbol' => $symbol, |
| ); |
| } |
| } |
| |
| /** |
| * Returns a coordinate in the given bounding box for the given angle |
| * radius with the center as base point. |
| * |
| * @param ezcGraphBoundings $boundings |
| * @param ezcGraphCoordinate $center |
| * @param float $angle |
| * @param float $radius |
| * @return float |
| */ |
| protected function getCoordinateFromAngleAndRadius( |
| ezcGraphBoundings $boundings, |
| ezcGraphCoordinate $center, |
| $angle, |
| $radius |
| ) |
| { |
| $direction = new ezcGraphCoordinate( |
| sin( $angle ) * $boundings->width / 2, |
| -cos( $angle ) * $boundings->height / 2 |
| ); |
| |
| $offset = new ezcGraphCoordinate( |
| sin( $angle ) * $this->xAxisSpace, |
| -cos( $angle ) * $this->yAxisSpace |
| ); |
| |
| $direction->x -= 2 * $offset->x; |
| $direction->y -= 2 * $offset->y; |
| |
| return new ezcGraphCoordinate( |
| $boundings->x0 + |
| $center->x + |
| $offset->x + |
| $direction->x * $radius, |
| $boundings->y0 + |
| $center->y + |
| $offset->y + |
| $direction->y * $radius |
| ); |
| } |
| |
| /** |
| * Draw radar chart data line |
| * |
| * Draws a line as a data element in a radar chart |
| * |
| * @param ezcGraphBoundings $boundings Chart boundings |
| * @param ezcGraphContext $context Context of call |
| * @param ezcGraphColor $color Color of line |
| * @param ezcGraphCoordinate $center Center of radar chart |
| * @param ezcGraphCoordinate $start Starting point |
| * @param ezcGraphCoordinate $end Ending point |
| * @param int $dataNumber Number of dataset |
| * @param int $dataCount Count of datasets in chart |
| * @param int $symbol Symbol to draw for line |
| * @param ezcGraphColor $symbolColor Color of the symbol, defaults to linecolor |
| * @param ezcGraphColor $fillColor Color to fill line with |
| * @param float $thickness Line thickness |
| * @return void |
| */ |
| public function drawRadarDataLine( |
| ezcGraphBoundings $boundings, |
| ezcGraphContext $context, |
| ezcGraphColor $color, |
| ezcGraphCoordinate $center, |
| ezcGraphCoordinate $start, |
| ezcGraphCoordinate $end, |
| $dataNumber = 1, |
| $dataCount = 1, |
| $symbol = ezcGraph::NO_SYMBOL, |
| ezcGraphColor $symbolColor = null, |
| ezcGraphColor $fillColor = null, |
| $thickness = 1. |
| ) |
| { |
| // Calculate line points from chart coordinates |
| $start = $this->getCoordinateFromAngleAndRadius( |
| $boundings, |
| $center, |
| $start->x * 2 * M_PI, |
| $start->y |
| ); |
| $end = $this->getCoordinateFromAngleAndRadius( |
| $boundings, |
| $center, |
| $end->x * 2 * M_PI, |
| $end->y |
| ); |
| |
| // Fill line |
| if ( $fillColor !== null ) |
| { |
| $this->driver->drawPolygon( |
| array( |
| $start, |
| $end, |
| new ezcGraphCoordinate( |
| $boundings->x0 + $center->x, |
| $boundings->y0 + $center->y |
| ), |
| ), |
| $fillColor, |
| true |
| ); |
| } |
| |
| // Draw line |
| $this->driver->drawLine( |
| $start, |
| $end, |
| $color, |
| $thickness |
| ); |
| |
| if ( $symbol !== ezcGraph::NO_SYMBOL ) |
| { |
| $this->drawSymbol( |
| new ezcGraphBoundings( |
| $end->x - $this->options->symbolSize / 2, |
| $end->y - $this->options->symbolSize / 2, |
| $end->x + $this->options->symbolSize / 2, |
| $end->y + $this->options->symbolSize / 2 |
| ), |
| $symbolColor, |
| $symbol |
| ); |
| } |
| } |
| |
| /** |
| * Draws a highlight textbox for a datapoint. |
| * |
| * A highlight textbox for line and bar charts means a box with the current |
| * value in the graph. |
| * |
| * @param ezcGraphBoundings $boundings Chart boundings |
| * @param ezcGraphContext $context Context of call |
| * @param ezcGraphCoordinate $end Ending point |
| * @param float $axisPosition Position of axis for drawing filled lines |
| * @param int $dataNumber Number of dataset |
| * @param int $dataCount Count of datasets in chart |
| * @param ezcGraphFontOptions $font Font used for highlight string |
| * @param string $text Acutual value |
| * @param int $size Size of highlight text |
| * @param ezcGraphColor $markLines |
| * @param int $xOffset |
| * @param int $yOffset |
| * @param float $stepSize |
| * @param int $type |
| * @return void |
| */ |
| public function drawDataHighlightText( |
| ezcGraphBoundings $boundings, |
| ezcGraphContext $context, |
| ezcGraphCoordinate $end, |
| $axisPosition = 0., |
| $dataNumber = 1, |
| $dataCount = 1, |
| ezcGraphFontOptions $font, |
| $text, |
| $size, |
| ezcGraphColor $markLines = null, |
| $xOffset = 0, |
| $yOffset = 0, |
| $stepSize = 0., |
| $type = ezcGraph::LINE ) |
| { |
| // Bar specific calculations |
| if ( $type !== ezcGraph::LINE ) |
| { |
| $margin = $stepSize * $this->options->barMargin; |
| $padding = $stepSize * $this->options->barPadding; |
| $barWidth = ( $stepSize - $margin ) / $dataCount - $padding; |
| $offset = -( $dataNumber + ( $dataCount - 1 ) / -2 ) * ( $barWidth + $padding ); |
| } |
| |
| $this->driver->options->font = $font; |
| $width = $boundings->width / $dataCount; |
| |
| $dataPoint = new ezcGraphCoordinate( |
| $boundings->x0 + ( $boundings->width ) * $end->x + $xOffset + |
| ( $type === ezcGraph::LINE ? 0 : $offset ), |
| $boundings->y0 + ( $boundings->height ) * $end->y + $yOffset |
| ); |
| |
| if ( $end->y < $axisPosition ) |
| { |
| $this->driver->drawTextBox( |
| $text, |
| new ezcGraphCoordinate( |
| $dataPoint->x - $width / 2, |
| $dataPoint->y - $size - $font->padding - $this->options->symbolSize |
| ), |
| $width, |
| $size, |
| ezcGraph::CENTER | ezcGraph::BOTTOM |
| ); |
| } |
| else |
| { |
| $this->driver->drawTextBox( |
| $text, |
| new ezcGraphCoordinate( |
| $dataPoint->x - $width / 2, |
| $dataPoint->y + $font->padding + $this->options->symbolSize |
| ), |
| $width, |
| $size, |
| ezcGraph::CENTER | ezcGraph::TOP |
| ); |
| } |
| } |
| |
| /** |
| * Draw legend |
| * |
| * Will draw a legend in the bounding box |
| * |
| * @param ezcGraphBoundings $boundings Bounding of legend |
| * @param ezcGraphChartElementLegend $legend Legend to draw; |
| * @param int $type Type of legend: Protrait or landscape |
| * @return void |
| */ |
| public function drawLegend( |
| ezcGraphBoundings $boundings, |
| ezcGraphChartElementLegend $legend, |
| $type = ezcGraph::VERTICAL ) |
| { |
| $labels = $legend->labels; |
| |
| // Calculate boundings of each label |
| if ( $type & ezcGraph::VERTICAL ) |
| { |
| $labelWidth = $boundings->width; |
| $labelHeight = min( |
| ( $boundings->height ) / count( $labels ) - $legend->spacing, |
| $legend->symbolSize + 2 * $legend->padding |
| ); |
| } |
| else |
| { |
| $labelWidth = ( $boundings->width ) / count( $labels ) - $legend->spacing; |
| $labelHeight = min( |
| $boundings->height, |
| $legend->symbolSize + 2 * $legend->padding |
| ); |
| } |
| |
| $symbolSize = $labelHeight - 2 * $legend->padding; |
| |
| // Draw all labels |
| $labelPosition = new ezcGraphCoordinate( $boundings->x0, $boundings->y0 ); |
| foreach ( $labels as $label ) |
| { |
| $this->elements['legend_url'][$label['label']] = $label['url']; |
| |
| $this->elements['legend'][$label['label']]['symbol'] = $this->drawSymbol( |
| new ezcGraphBoundings( |
| $labelPosition->x + $legend->padding, |
| $labelPosition->y + $legend->padding, |
| $labelPosition->x + $legend->padding + $symbolSize, |
| $labelPosition->y + $legend->padding + $symbolSize |
| ), |
| $label['color'], |
| $label['symbol'] |
| ); |
| |
| $this->elements['legend'][$label['label']]['text'] = $this->driver->drawTextBox( |
| $label['label'], |
| new ezcGraphCoordinate( |
| $labelPosition->x + 2 * $legend->padding + $symbolSize, |
| $labelPosition->y + $legend->padding |
| ), |
| $labelWidth - $symbolSize - 3 * $legend->padding, |
| $labelHeight - 2 * $legend->padding, |
| ezcGraph::LEFT | ezcGraph::MIDDLE |
| ); |
| |
| $labelPosition->x += ( $type === ezcGraph::VERTICAL ? 0 : $labelWidth + $legend->spacing ); |
| $labelPosition->y += ( $type === ezcGraph::VERTICAL ? $labelHeight + $legend->spacing : 0 ); |
| } |
| } |
| |
| /** |
| * Draw box |
| * |
| * Box are wrapping each major chart element and draw border, background |
| * and title to each chart element. |
| * |
| * Optionally a padding and margin for each box can be defined. |
| * |
| * @param ezcGraphBoundings $boundings Boundings of the box |
| * @param ezcGraphColor $background Background color |
| * @param ezcGraphColor $borderColor Border color |
| * @param int $borderWidth Border width |
| * @param int $margin Margin |
| * @param int $padding Padding |
| * @param mixed $title Title of the box |
| * @param int $titleSize Size of title in the box |
| * @return ezcGraphBoundings Remaining inner boundings |
| */ |
| public function drawBox( |
| ezcGraphBoundings $boundings, |
| ezcGraphColor $background = null, |
| ezcGraphColor $borderColor = null, |
| $borderWidth = 0, |
| $margin = 0, |
| $padding = 0, |
| $title = false, |
| $titleSize = 16 ) |
| { |
| // Apply margin |
| $boundings->x0 += $margin; |
| $boundings->y0 += $margin; |
| $boundings->x1 -= $margin; |
| $boundings->y1 -= $margin; |
| |
| if ( $background instanceof ezcGraphColor ) |
| { |
| // Draw box background |
| $this->driver->drawPolygon( |
| array( |
| new ezcGraphCoordinate( $boundings->x0, $boundings->y0 ), |
| new ezcGraphCoordinate( $boundings->x1, $boundings->y0 ), |
| new ezcGraphCoordinate( $boundings->x1, $boundings->y1 ), |
| new ezcGraphCoordinate( $boundings->x0, $boundings->y1 ), |
| ), |
| $background, |
| true |
| ); |
| } |
| |
| if ( ( $borderColor instanceof ezcGraphColor ) && |
| ( $borderWidth > 0 ) ) |
| { |
| // Draw border |
| $this->driver->drawPolygon( |
| array( |
| new ezcGraphCoordinate( $boundings->x0, $boundings->y0 ), |
| new ezcGraphCoordinate( $boundings->x1, $boundings->y0 ), |
| new ezcGraphCoordinate( $boundings->x1, $boundings->y1 ), |
| new ezcGraphCoordinate( $boundings->x0, $boundings->y1 ), |
| ), |
| $borderColor, |
| false, |
| $borderWidth |
| ); |
| |
| // Reduce local boundings by borderWidth |
| $boundings->x0 += $borderWidth; |
| $boundings->y0 += $borderWidth; |
| $boundings->x1 -= $borderWidth; |
| $boundings->y1 -= $borderWidth; |
| } |
| |
| // Apply padding |
| $boundings->x0 += $padding; |
| $boundings->y0 += $padding; |
| $boundings->x1 -= $padding; |
| $boundings->y1 -= $padding; |
| |
| // Add box title |
| if ( $title !== false ) |
| { |
| switch ( $this->options->titlePosition ) |
| { |
| case ezcGraph::TOP: |
| $this->driver->drawTextBox( |
| $title, |
| new ezcGraphCoordinate( $boundings->x0, $boundings->y0 ), |
| $boundings->width, |
| $titleSize, |
| $this->options->titleAlignement |
| ); |
| |
| $boundings->y0 += $titleSize + $padding; |
| $boundings->y1 -= $titleSize + $padding; |
| break; |
| case ezcGraph::BOTTOM: |
| $this->driver->drawTextBox( |
| $title, |
| new ezcGraphCoordinate( $boundings->x0, $boundings->y1 - $titleSize ), |
| $boundings->width, |
| $titleSize, |
| $this->options->titleAlignement |
| ); |
| |
| $boundings->y1 -= $titleSize + $padding; |
| break; |
| } |
| } |
| |
| return $boundings; |
| } |
| |
| /** |
| * Draw text |
| * |
| * Draws the provided text in the boundings |
| * |
| * @param ezcGraphBoundings $boundings Boundings of text |
| * @param string $text Text |
| * @param int $align Alignement of text |
| * @param ezcGraphRotation $rotation |
| * @return void |
| */ |
| public function drawText( |
| ezcGraphBoundings $boundings, |
| $text, |
| $align = ezcGraph::LEFT, |
| ezcGraphRotation $rotation = null ) |
| { |
| $this->driver->drawTextBox( |
| $text, |
| new ezcGraphCoordinate( $boundings->x0, $boundings->y0 ), |
| $boundings->width, |
| $boundings->height, |
| $align, |
| $rotation |
| ); |
| } |
| |
| /** |
| * Draw grid line |
| * |
| * Draw line for the grid in the chart background |
| * |
| * @param ezcGraphCoordinate $start Start point |
| * @param ezcGraphCoordinate $end End point |
| * @param ezcGraphColor $color Color of the grid line |
| * @return void |
| */ |
| public function drawGridLine( ezcGraphCoordinate $start, ezcGraphCoordinate $end, ezcGraphColor $color ) |
| { |
| $this->driver->drawLine( |
| $start, |
| $end, |
| $color, |
| 1 |
| ); |
| } |
| |
| /** |
| * Draw step line |
| * |
| * Draw a step (marker for label position) on a axis. |
| * |
| * @param ezcGraphCoordinate $start Start point |
| * @param ezcGraphCoordinate $end End point |
| * @param ezcGraphColor $color Color of the grid line |
| * @return void |
| */ |
| public function drawStepLine( ezcGraphCoordinate $start, ezcGraphCoordinate $end, ezcGraphColor $color ) |
| { |
| $this->driver->drawLine( |
| $start, |
| $end, |
| $color, |
| 1 |
| ); |
| } |
| |
| /** |
| * Draw axis |
| * |
| * Draws an axis form the provided start point to the end point. A specific |
| * angle of the axis is not required. |
| * |
| * For the labeleing of the axis a sorted array with major steps and an |
| * array with minor steps is expected, which are build like this: |
| * array( |
| * array( |
| * 'position' => (float), |
| * 'label' => (string), |
| * ) |
| * ) |
| * where the label is optional. |
| * |
| * The label renderer class defines how the labels are rendered. For more |
| * documentation on this topic have a look at the basic label renderer |
| * class. |
| * |
| * Additionally it can be specified if a major and minor grid are rendered |
| * by defining a color for them. The axis label is used to add a caption |
| * for the axis. |
| * |
| * @param ezcGraphBoundings $boundings Boundings of axis |
| * @param ezcGraphCoordinate $start Start point of axis |
| * @param ezcGraphCoordinate $end Endpoint of axis |
| * @param ezcGraphChartElementAxis $axis Axis to render |
| * @param ezcGraphAxisLabelRenderer $labelClass Used label renderer |
| * @return void |
| */ |
| public function drawAxis( |
| ezcGraphBoundings $boundings, |
| ezcGraphCoordinate $start, |
| ezcGraphCoordinate $end, |
| ezcGraphChartElementAxis $axis, |
| ezcGraphAxisLabelRenderer $labelClass = null, |
| ezcGraphBoundings $innerBoundings = null ) |
| { |
| // Legacy axis drawing for BC reasons |
| if ( $innerBoundings === null ) |
| { |
| return $this->legacyDrawAxis( $boundings, $start, $end, $axis, $labelClass ); |
| } |
| |
| // Calculate axis start and end points depending on inner boundings |
| if ( ( $axis->position === ezcGraph::TOP ) || |
| ( $axis->position === ezcGraph::BOTTOM ) ) |
| { |
| $innerStart = new ezcGraphCoordinate( |
| $start->x + $boundings->x0, |
| ( $axis->position === ezcGraph::TOP ? $innerBoundings->y0 : $innerBoundings->y1 ) |
| ); |
| $innerEnd = new ezcGraphCoordinate( |
| $end->x + $boundings->x0, |
| ( $axis->position === ezcGraph::TOP ? $innerBoundings->y1 : $innerBoundings->y0 ) |
| ); |
| } |
| else |
| { |
| $innerStart = new ezcGraphCoordinate( |
| ( $axis->position === ezcGraph::LEFT ? $innerBoundings->x0 : $innerBoundings->x1 ), |
| $start->y + $boundings->y0 |
| ); |
| $innerEnd = new ezcGraphCoordinate( |
| ( $axis->position === ezcGraph::LEFT ? $innerBoundings->x1 : $innerBoundings->x0 ), |
| $end->y + $boundings->y0 |
| ); |
| } |
| |
| // Shorten axis, if requested |
| if ( $this->options->shortAxis ) |
| { |
| $start = clone $innerStart; |
| $end = clone $innerEnd; |
| } |
| else |
| { |
| $start->x += $boundings->x0; |
| $start->y += $boundings->y0; |
| $end->x += $boundings->x0; |
| $end->y += $boundings->y0; |
| } |
| |
| // Determine normalized direction |
| $direction = new ezcGraphVector( |
| $start->x - $end->x, |
| $start->y - $end->y |
| ); |
| $direction->unify(); |
| |
| // Draw axis |
| $this->driver->drawLine( |
| $start, |
| $end, |
| $axis->border, |
| 1 |
| ); |
| |
| // Draw small arrowhead |
| $this->drawAxisArrowHead( |
| $end, |
| $direction, |
| max( |
| $axis->minArrowHeadSize, |
| min( |
| $axis->maxArrowHeadSize, |
| abs( ceil( ( ( $end->x - $start->x ) + ( $end->y - $start->y ) ) * $axis->axisSpace / 4 ) ) |
| ) |
| ), |
| $axis->border |
| ); |
| |
| // Draw axis label, if set |
| $this->drawAxisLabel( $end, $innerBoundings, $axis ); |
| |
| // If font should not be synchronized, use font configuration from |
| // each axis |
| if ( $this->options->syncAxisFonts === false ) |
| { |
| $this->driver->options->font = $axis->font; |
| } |
| |
| $labelClass->renderLabels( |
| $this, |
| $boundings, |
| $innerStart, |
| $innerEnd, |
| $axis, |
| $innerBoundings |
| ); |
| } |
| |
| /** |
| * Draw axis label |
| * |
| * Draw labels at the end of an axis. |
| * |
| * @param ezcGraphCoordinate $position |
| * @param ezcGraphBoundings $boundings |
| * @param ezcGraphChartElementAxis $axis |
| * @return void |
| */ |
| protected function drawAxisLabel( ezcGraphCoordinate $position, ezcGraphBoundings $boundings, ezcGraphChartElementAxis $axis ) |
| { |
| if ( $axis->label === false ) |
| { |
| return; |
| } |
| |
| $width = $boundings->width; |
| switch ( $axis->position ) |
| { |
| case ezcGraph::TOP: |
| $this->driver->drawTextBox( |
| $axis->label, |
| new ezcGraphCoordinate( |
| $position->x + $axis->labelMargin - $width * ( 1 - $axis->axisSpace * 2 ), |
| $position->y - $axis->labelMargin - $axis->labelSize |
| ), |
| $width * ( 1 - $axis->axisSpace * 2 ) - $axis->labelMargin, |
| $axis->labelSize, |
| ezcGraph::TOP | ezcGraph::RIGHT, |
| new ezcGraphRotation( $axis->labelRotation, new ezcGraphCoordinate( |
| $position->x + $axis->labelSize / 2, |
| $position->y - $axis->labelSize / 2 |
| ) ) |
| ); |
| break; |
| case ezcGraph::BOTTOM: |
| $this->driver->drawTextBox( |
| $axis->label, |
| new ezcGraphCoordinate( |
| $position->x + $axis->labelMargin, |
| $position->y + $axis->labelMargin |
| ), |
| $width * ( 1 - $axis->axisSpace * 2 ) - $axis->labelMargin, |
| $axis->labelSize, |
| ezcGraph::TOP | ezcGraph::LEFT, |
| new ezcGraphRotation( $axis->labelRotation, new ezcGraphCoordinate( |
| $position->x + $axis->labelSize / 2, |
| $position->y + $axis->labelSize / 2 |
| ) ) |
| ); |
| break; |
| case ezcGraph::LEFT: |
| $this->driver->drawTextBox( |
| $axis->label, |
| new ezcGraphCoordinate( |
| $position->x - $width, |
| $position->y - $axis->labelSize - $axis->labelMargin |
| ), |
| $width - $axis->labelMargin, |
| $axis->labelSize, |
| ezcGraph::BOTTOM | ezcGraph::RIGHT, |
| new ezcGraphRotation( $axis->labelRotation, new ezcGraphCoordinate( |
| $position->x - $axis->labelSize / 2, |
| $position->y - $axis->labelSize / 2 |
| ) ) |
| ); |
| break; |
| case ezcGraph::RIGHT: |
| $this->driver->drawTextBox( |
| $axis->label, |
| new ezcGraphCoordinate( |
| $position->x, |
| $position->y - $axis->labelSize - $axis->labelMargin |
| ), |
| $width - $axis->labelMargin, |
| $axis->labelSize, |
| ezcGraph::BOTTOM | ezcGraph::LEFT, |
| new ezcGraphRotation( $axis->labelRotation, new ezcGraphCoordinate( |
| $position->x + $axis->labelSize / 2, |
| $position->y - $axis->labelSize / 2 |
| ) ) |
| ); |
| break; |
| } |
| } |
| |
| /** |
| * Draw axis |
| * |
| * Draws an axis form the provided start point to the end point. A specific |
| * angle of the axis is not required. |
| * |
| * For the labeleing of the axis a sorted array with major steps and an |
| * array with minor steps is expected, which are build like this: |
| * array( |
| * array( |
| * 'position' => (float), |
| * 'label' => (string), |
| * ) |
| * ) |
| * where the label is optional. |
| * |
| * The label renderer class defines how the labels are rendered. For more |
| * documentation on this topic have a look at the basic label renderer |
| * class. |
| * |
| * Additionally it can be specified if a major and minor grid are rendered |
| * by defining a color for them. The axis label is used to add a caption |
| * for the axis. |
| * |
| * This function is deprecated and will be removed in favor of its |
| * reimplementation using the innerBoundings parameter. |
| * |
| * @param ezcGraphBoundings $boundings Boundings of axis |
| * @param ezcGraphCoordinate $start Start point of axis |
| * @param ezcGraphCoordinate $end Endpoint of axis |
| * @param ezcGraphChartElementAxis $axis Axis to render |
| * @param ezcGraphAxisLabelRenderer $labelClass Used label renderer |
| * @apichange |
| * @return void |
| */ |
| protected function legacyDrawAxis( |
| ezcGraphBoundings $boundings, |
| ezcGraphCoordinate $start, |
| ezcGraphCoordinate $end, |
| ezcGraphChartElementAxis $axis, |
| ezcGraphAxisLabelRenderer $labelClass = null ) |
| { |
| // Store axis space for use by label renderer |
| switch ( $axis->position ) |
| { |
| case ezcGraph::TOP: |
| case ezcGraph::BOTTOM: |
| $this->xAxisSpace = ( $boundings->width ) * $axis->axisSpace; |
| break; |
| case ezcGraph::LEFT: |
| case ezcGraph::RIGHT: |
| $this->yAxisSpace = ( $boundings->height ) * $axis->axisSpace; |
| break; |
| } |
| |
| // Clone boundings because of internal modifications |
| $boundings = clone $boundings; |
| |
| $start->x += $boundings->x0; |
| $start->y += $boundings->y0; |
| $end->x += $boundings->x0; |
| $end->y += $boundings->y0; |
| |
| // Shorten drawn axis, if requested. |
| if ( ( $this->options->shortAxis === true ) && |
| ( ( $axis->position === ezcGraph::TOP ) || |
| ( $axis->position === ezcGraph::BOTTOM ) ) ) |
| { |
| $axisStart = clone $start; |
| $axisEnd = clone $end; |
| |
| $axisStart->y += $boundings->height * $axis->axisSpace * |
| ( $axis->position === ezcGraph::TOP ? 1 : -1 ); |
| $axisEnd->y -= $boundings->height * $axis->axisSpace * |
| ( $axis->position === ezcGraph::TOP ? 1 : -1 ); |
| } |
| elseif ( ( $this->options->shortAxis === true ) && |
| ( ( $axis->position === ezcGraph::LEFT ) || |
| ( $axis->position === ezcGraph::RIGHT ) ) ) |
| { |
| $axisStart = clone $start; |
| $axisEnd = clone $end; |
| |
| $axisStart->x += $boundings->width * $axis->axisSpace * |
| ( $axis->position === ezcGraph::LEFT ? 1 : -1 ); |
| $axisEnd->x -= $boundings->width * $axis->axisSpace * |
| ( $axis->position === ezcGraph::LEFT ? 1 : -1 ); |
| } |
| else |
| { |
| $axisStart = $start; |
| $axisEnd = $end; |
| } |
| |
| // Determine normalized direction |
| $direction = new ezcGraphVector( |
| $start->x - $end->x, |
| $start->y - $end->y |
| ); |
| $direction->unify(); |
| |
| // Draw axis |
| $this->driver->drawLine( |
| $axisStart, |
| $axisEnd, |
| $axis->border, |
| 1 |
| ); |
| |
| // Draw small arrowhead |
| $this->drawAxisArrowHead( |
| $axisEnd, |
| $direction, |
| max( |
| $axis->minArrowHeadSize, |
| min( |
| $axis->maxArrowHeadSize, |
| abs( ceil( ( ( $end->x - $start->x ) + ( $end->y - $start->y ) ) * $axis->axisSpace / 4 ) ) |
| ) |
| ), |
| $axis->border |
| ); |
| |
| // Draw axis label, if set |
| $this->drawAxisLabel( $end, $boundings, $axis ); |
| |
| // Collect axis labels and draw, when all axisSpaces are collected |
| $this->axisLabels[] = array( |
| 'object' => $labelClass, |
| 'boundings' => $boundings, |
| 'start' => clone $start, |
| 'end' => clone $end, |
| 'axis' => $axis, |
| ); |
| |
| if ( $this->xAxisSpace && $this->yAxisSpace ) |
| { |
| $this->drawAxisLabels(); |
| } |
| } |
| |
| /** |
| * Draw all left axis labels |
| * |
| * @return void |
| */ |
| protected function drawAxisLabels() |
| { |
| foreach ( $this->axisLabels as $nr => $axisLabel ) |
| { |
| // If font should not be synchronized, use font configuration from |
| // each axis |
| if ( $this->options->syncAxisFonts === false ) |
| { |
| $this->driver->options->font = $axisLabel['axis']->font; |
| } |
| |
| $start = $axisLabel['start']; |
| $end = $axisLabel['end']; |
| |
| $direction = new ezcGraphVector( |
| $end->x - $start->x, |
| $end->y - $start->y |
| ); |
| $direction->unify(); |
| |
| // Convert elipse to circle for correct angle calculation |
| $direction->y *= ( $this->xAxisSpace / $this->yAxisSpace ); |
| $angle = $direction->angle( new ezcGraphVector( 0, 1 ) ); |
| |
| $movement = new ezcGraphVector( |
| sin( $angle ) * $this->xAxisSpace * ( $direction->x < 0 ? -1 : 1 ), |
| cos( $angle ) * $this->yAxisSpace |
| ); |
| |
| $start->x += $movement->x; |
| $start->y += $movement->y; |
| $end->x -= $movement->x; |
| $end->y -= $movement->y; |
| |
| $axisLabel['object']->renderLabels( |
| $this, |
| $axisLabel['boundings'], |
| $start, |
| $end, |
| $axisLabel['axis'] |
| ); |
| |
| // Prevent from redrawing axis on more then 2 axis. |
| unset( $this->axisLabels[$nr] ); |
| } |
| } |
| |
| /** |
| * Draw background image |
| * |
| * Draws a background image at the defined position. If repeat is set the |
| * background image will be repeated like any texture. |
| * |
| * @param ezcGraphBoundings $boundings Boundings for the background image |
| * @param string $file Filename of background image |
| * @param int $position Position of background image |
| * @param int $repeat Type of repetition |
| * @return void |
| */ |
| public function drawBackgroundImage( |
| ezcGraphBoundings $boundings, |
| $file, |
| $position = 48, // ezcGraph::CENTER | ezcGraph::MIDDLE |
| $repeat = ezcGraph::NO_REPEAT ) |
| { |
| $imageData = getimagesize( $file ); |
| $imageWidth = $imageData[0]; |
| $imageHeight = $imageData[1]; |
| |
| $imageWidth = min( $imageWidth, $boundings->width ); |
| $imageHeight = min( $imageHeight, $boundings->height ); |
| |
| $imagePosition = new ezcGraphCoordinate( |
| $boundings->x0, |
| $boundings->y0 |
| ); |
| |
| // Determine x position |
| switch ( true ) { |
| case ( $repeat & ezcGraph::HORIZONTAL ): |
| // If is repeated on this axis fall back to position zero |
| case ( $position & ezcGraph::LEFT ): |
| $imagePosition->x = $boundings->x0; |
| break; |
| case ( $position & ezcGraph::RIGHT ): |
| $imagePosition->x = max( |
| $boundings->x1 - $imageWidth, |
| $boundings->x0 |
| ); |
| break; |
| default: |
| $imagePosition->x = max( |
| $boundings->x0 + ( $boundings->width - $imageWidth ) / 2, |
| $boundings->x0 |
| ); |
| break; |
| } |
| |
| // Determine y position |
| switch ( true ) { |
| case ( $repeat & ezcGraph::VERTICAL ): |
| // If is repeated on this axis fall back to position zero |
| case ( $position & ezcGraph::TOP ): |
| $imagePosition->y = $boundings->y0; |
| break; |
| case ( $position & ezcGraph::BOTTOM ): |
| $imagePosition->y = max( |
| $boundings->y1 - $imageHeight, |
| $boundings->y0 |
| ); |
| break; |
| default: |
| $imagePosition->y = max( |
| $boundings->y0 + ( $boundings->height - $imageHeight ) / 2, |
| $boundings->y0 |
| ); |
| break; |
| } |
| |
| // Texturize backround based on position and repetition |
| $position = new ezcGraphCoordinate( |
| $imagePosition->x, |
| $imagePosition->y |
| ); |
| |
| do |
| { |
| $position->y = $imagePosition->y; |
| |
| do |
| { |
| $this->driver->drawImage( |
| $file, |
| $position, |
| $imageWidth, |
| $imageHeight |
| ); |
| |
| $position->y += $imageHeight; |
| } |
| while ( ( $position->y < $boundings->y1 ) && |
| ( $repeat & ezcGraph::VERTICAL ) ); |
| |
| $position->x += $imageWidth; |
| } |
| while ( ( $position->x < $boundings->x1 ) && |
| ( $repeat & ezcGraph::HORIZONTAL ) ); |
| } |
| |
| /** |
| * Call all postprocessing functions |
| * |
| * @return void |
| */ |
| protected function finish() |
| { |
| $this->finishCircleSectors(); |
| $this->finishPieSegmentLabels(); |
| $this->finishLineSymbols(); |
| |
| return true; |
| } |
| |
| /** |
| * Reset renderer properties |
| * |
| * Reset all renderer properties, which were calculated during the |
| * rendering process, to offer a clean environment for rerendering. |
| * |
| * @return void |
| */ |
| protected function resetRenderer() |
| { |
| parent::resetRenderer(); |
| |
| // Also reset special 2D renderer options |
| $this->pieSegmentLabels = array( |
| 0 => array(), |
| 1 => array(), |
| ); |
| $this->pieSegmentBoundings = false; |
| $this->linePostSymbols = array(); |
| $this->axisLabels = array(); |
| $this->circleSectors = array(); |
| } |
| |
| /** |
| * Render odometer chart |
| * |
| * @param ezcGraphBoundings $boundings |
| * @param ezcGraphChartElementAxis $axis |
| * @param ezcGraphOdometerChartOptions $options |
| * @return ezcGraphBoundings |
| */ |
| public function drawOdometer( |
| ezcGraphBoundings $boundings, |
| ezcGraphChartElementAxis $axis, |
| ezcGraphOdometerChartOptions $options ) |
| { |
| $height = $boundings->height * $options->odometerHeight; |
| |
| // Draw axis |
| $oldAxisSpace = $axis->axisSpace; |
| $axis->axisSpace = 0; |
| |
| $axis->render( $this, $boundings ); |
| |
| // Reset axisspaces to correct values |
| $this->xAxisSpace = $boundings->width * $oldAxisSpace; |
| $this->yAxisSpace = ( $boundings->height - $height ) / 2; |
| |
| $this->drawAxisLabels(); |
| |
| // Reduce size of chart boundings respecting requested odometer height |
| $boundings->x0 += $this->xAxisSpace; |
| $boundings->x1 -= $this->xAxisSpace; |
| $boundings->y0 += $this->yAxisSpace; |
| $boundings->y1 -= $this->yAxisSpace; |
| |
| $gradient = new ezcGraphLinearGradient( |
| new ezcGraphCoordinate( $boundings->x0, $boundings->y0 ), |
| new ezcGraphCoordinate( $boundings->x1, $boundings->y0 ), |
| $options->startColor, |
| $options->endColor |
| ); |
| |
| // Simply draw box with gradient and optional border |
| $this->drawBox( |
| $boundings, |
| $gradient, |
| $options->borderColor, |
| $options->borderWidth |
| ); |
| |
| // Return modified chart boundings |
| return $boundings; |
| } |
| |
| /** |
| * Draw a single odometer marker. |
| * |
| * @param ezcGraphBoundings $boundings |
| * @param ezcGraphCoordinate $position |
| * @param int $symbol |
| * @param ezcGraphColor $color |
| * @param int $width |
| */ |
| public function drawOdometerMarker( |
| ezcGraphBoundings $boundings, |
| ezcGraphCoordinate $position, |
| $symbol, |
| ezcGraphColor $color, |
| $width ) |
| { |
| $this->driver->drawLine( |
| new ezcGraphCoordinate( |
| $xPos = $boundings->x0 + ( $position->x * $boundings->width ), |
| $boundings->y0 |
| ), |
| new ezcGraphCoordinate( |
| $xPos, |
| $boundings->y1 |
| ), |
| $color, |
| $width |
| ); |
| } |
| } |
| |
| ?> |