Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/matomo-org/matomo.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/ImageGraph/StaticGraph/GridGraph.php')
-rw-r--r--plugins/ImageGraph/StaticGraph/GridGraph.php851
1 files changed, 405 insertions, 446 deletions
diff --git a/plugins/ImageGraph/StaticGraph/GridGraph.php b/plugins/ImageGraph/StaticGraph/GridGraph.php
index 8e150054c5..dd70094106 100644
--- a/plugins/ImageGraph/StaticGraph/GridGraph.php
+++ b/plugins/ImageGraph/StaticGraph/GridGraph.php
@@ -16,452 +16,411 @@
*/
abstract class Piwik_ImageGraph_StaticGraph_GridGraph extends Piwik_ImageGraph_StaticGraph
{
- const GRAPHIC_COLOR_KEY = 'GRAPHIC_COLOR';
- const VALUE_COLOR_KEY = 'VALUE_COLOR';
- const GRID_COLOR_KEY = 'GRID_COLOR';
-
- const TRUNCATION_TEXT = '...';
-
- const DEFAULT_TICK_ALPHA = 20;
- const DEFAULT_SERIE_WEIGHT = 0.5;
- const LEFT_GRID_MARGIN = 4;
- const BOTTOM_GRID_MARGIN = 10;
- const TOP_GRID_MARGIN_HORIZONTAL_GRAPH = 1;
- const RIGHT_GRID_MARGIN_HORIZONTAL_GRAPH = 4;
- const OUTER_TICK_WIDTH = 5;
- const INNER_TICK_WIDTH = 0;
- const LABEL_SPACE_VERTICAL_GRAPH = 7;
-
- const HORIZONTAL_LEGEND_TOP_MARGIN = 5;
- const HORIZONTAL_LEGEND_LEFT_MARGIN = 10;
- const HORIZONTAL_LEGEND_BOTTOM_MARGIN = 10;
- const VERTICAL_LEGEND_TOP_MARGIN = 8;
- const VERTICAL_LEGEND_LEFT_MARGIN = 6;
- const VERTICAL_LEGEND_MAX_WIDTH_PCT = 0.70;
- const LEGEND_LINE_BULLET_WIDTH = 14;
- const LEGEND_BOX_BULLET_WIDTH = 5;
- const LEGEND_BULLET_RIGHT_PADDING = 5;
- const LEGEND_ITEM_HORIZONTAL_INTERSTICE = 6;
- const LEGEND_ITEM_VERTICAL_INTERSTICE_OFFSET = 4;
- const LEGEND_SHADOW_OPACITY = 25;
- const LEGEND_VERTICAL_SHADOW_PADDING = 3;
- const LEGEND_HORIZONTAL_SHADOW_PADDING = 2;
- const PCHART_HARD_CODED_VERTICAL_LEGEND_INTERSTICE = 5;
-
- protected function getDefaultColors()
- {
- return array(
- self::VALUE_COLOR_KEY => '444444',
- self::GRID_COLOR_KEY => 'CCCCCC',
- self::GRAPHIC_COLOR_KEY . '1' => '5170AE',
- self::GRAPHIC_COLOR_KEY . '2' => 'F29007',
- self::GRAPHIC_COLOR_KEY . '3' => 'CC3399',
- self::GRAPHIC_COLOR_KEY . '4' => '9933CC',
- self::GRAPHIC_COLOR_KEY . '5' => '80A033',
- self::GRAPHIC_COLOR_KEY . '6' => '246AD2'
- );
- }
-
- protected function initGridChart(
- $displayVerticalGridLines,
- $bulletType,
- $horizontalGraph,
- $showTicks,
- $verticalLegend
- )
- {
- $this->initpData();
-
- $colorIndex = 1;
- foreach($this->ordinateSeries as $column => $data)
- {
- $this->pData->setSerieWeight($column, self::DEFAULT_SERIE_WEIGHT);
- $graphicColor = $this->colors[self::GRAPHIC_COLOR_KEY . $colorIndex++];
- $this->pData->setPalette($column, $graphicColor);
- }
-
- $this->initpImage();
-
- // graph area coordinates
- $topLeftXValue = $this->getGridLeftMargin($horizontalGraph, $withLabel = true);
- $topLeftYValue = $this->getGridTopMargin($horizontalGraph, $verticalLegend);
- $bottomRightXValue = $this->width - $this->getGridRightMargin($horizontalGraph);
- $bottomRightYValue = $this->getGraphBottom($horizontalGraph);
-
- $this->pImage->setGraphArea(
- $topLeftXValue,
- $topLeftYValue,
- $bottomRightXValue,
- $bottomRightYValue
- );
-
- // determine how many labels need to be skipped
- $skippedLabels = 0;
- if(!$horizontalGraph)
- {
- list($abscissaMaxWidth, $abscissaMaxHeight) = $this->getMaximumTextWidthHeight($this->abscissaSeries);
- $graphWidth = $bottomRightXValue - $topLeftXValue;
- $maxNumOfLabels = floor($graphWidth / ($abscissaMaxWidth + self::LABEL_SPACE_VERTICAL_GRAPH));
-
- $abscissaSeriesCount = count($this->abscissaSeries);
- if($maxNumOfLabels < $abscissaSeriesCount)
- {
- for($candidateSkippedLabels = 1 ; $candidateSkippedLabels < $abscissaSeriesCount; $candidateSkippedLabels++)
- {
- $numberOfSegments = $abscissaSeriesCount / ($candidateSkippedLabels + 1);
- $numberOfCompleteSegments = floor($numberOfSegments);
-
- $numberOfLabels = $numberOfCompleteSegments;
- if($numberOfSegments > $numberOfCompleteSegments)
- {
- $numberOfLabels++;
- }
-
- if($numberOfLabels <= $maxNumOfLabels )
- {
- $skippedLabels = $candidateSkippedLabels;
- break;
- }
- }
- }
-
- if($this->forceSkippedLabels
- && $skippedLabels
- && $skippedLabels < $this->forceSkippedLabels
- && $abscissaSeriesCount > $this->forceSkippedLabels + 1
- )
- {
- $skippedLabels = $this->forceSkippedLabels;
- }
- }
-
- $ordinateAxisLength =
- $horizontalGraph ? $bottomRightXValue - $topLeftXValue : $this->getGraphHeight($horizontalGraph, $verticalLegend);
-
- $maxOrdinateValue = 0;
- foreach($this->ordinateSeries as $column => $data)
- {
- $currentMax = $this->pData->getMax($column);
-
- if($currentMax > $maxOrdinateValue)
- {
- $maxOrdinateValue = $currentMax;
- }
- }
-
- // rounding top scale value to the next multiple of 10
- if($maxOrdinateValue > 10)
- {
- $modTen = $maxOrdinateValue % 10;
- if($modTen) $maxOrdinateValue += 10 - $modTen;
- }
-
- $gridColor = $this->colors[self::GRID_COLOR_KEY];
- $this->pImage->drawScale(
- array(
- 'Mode' => SCALE_MODE_MANUAL,
- 'GridTicks' => 0,
- 'LabelSkip' => $skippedLabels,
- 'DrawXLines' => $displayVerticalGridLines,
- 'Factors' => array(ceil($maxOrdinateValue / 2)),
- 'MinDivHeight' => $ordinateAxisLength / 2,
- 'AxisAlpha' => 0,
- 'SkippedAxisAlpha' => 0,
- 'TickAlpha' => $showTicks ? self::DEFAULT_TICK_ALPHA : 0,
- 'InnerTickWidth' => self::INNER_TICK_WIDTH,
- 'OuterTickWidth' => self::OUTER_TICK_WIDTH,
- 'GridR' => $gridColor['R'],
- 'GridG' => $gridColor['G'],
- 'GridB' => $gridColor['B'],
- 'GridAlpha' => 100,
- 'ManualScale' => array(
- 0 => array(
- 'Min' => 0,
- 'Max' => $maxOrdinateValue
- )
- ),
- 'Pos' => $horizontalGraph ? SCALE_POS_TOPBOTTOM : SCALE_POS_LEFTRIGHT,
- )
- );
-
- if($this->showLegend)
- {
- switch($bulletType)
- {
- case LEGEND_FAMILY_LINE:
- $bulletWidth = self::LEGEND_LINE_BULLET_WIDTH;
-
- // measured using a picture editing software
- $iconOffsetAboveLabelSymmetryAxis = -2;
- break;
-
- case LEGEND_FAMILY_BOX:
- $bulletWidth = self::LEGEND_BOX_BULLET_WIDTH;
-
- // measured using a picture editing software
- $iconOffsetAboveLabelSymmetryAxis = 3;
- break;
- }
-
- // pChart requires two coordinates to draw the legend $legendTopLeftXValue & $legendTopLeftYValue
- // $legendTopLeftXValue = legend's left padding
- $legendTopLeftXValue = $topLeftXValue + ($verticalLegend ? self::VERTICAL_LEGEND_LEFT_MARGIN : self::HORIZONTAL_LEGEND_LEFT_MARGIN);
-
- // $legendTopLeftYValue = y coordinate of the top edge of the legend's icons
- // Caution :
- // - pChart will silently add some value (see $paddingAddedByPChart) to $legendTopLeftYValue depending on multiple criterias
- // - pChart will not take into account the size of the text. Setting $legendTopLeftYValue = 0 will crop the legend's labels
- // The following section of code determines the value of $legendTopLeftYValue while taking into account the following paremeters :
- // - whether legend items have icons
- // - whether icons are bigger than the legend's labels
- // - how much colored shadow padding is required
- list($maxLogoWidth, $maxLogoHeight) = self::getMaxLogoSize(array_values($this->ordinateLogos));
- if($maxLogoHeight >= $this->legendFontSize)
- {
- $heightOfTextAboveBulletTop = 0;
- $paddingCreatedByLogo = $maxLogoHeight - $this->legendFontSize;
- $effectiveShadowPadding = $paddingCreatedByLogo < self::LEGEND_VERTICAL_SHADOW_PADDING * 2 ? self::LEGEND_VERTICAL_SHADOW_PADDING - ($paddingCreatedByLogo / 2) : 0;
- }
- else
- {
- if($maxLogoHeight)
- {
- // measured using a picture editing software
- $iconOffsetAboveLabelSymmetryAxis = 5;
- }
- $heightOfTextAboveBulletTop = $this->legendFontSize / 2 - $iconOffsetAboveLabelSymmetryAxis;
- $effectiveShadowPadding = self::LEGEND_VERTICAL_SHADOW_PADDING;
- }
-
- $effectiveLegendItemVerticalInterstice = $this->legendFontSize + self::LEGEND_ITEM_VERTICAL_INTERSTICE_OFFSET;
- $effectiveLegendItemHorizontalInterstice = self::LEGEND_ITEM_HORIZONTAL_INTERSTICE + self::LEGEND_HORIZONTAL_SHADOW_PADDING;
-
- $legendTopMargin = $verticalLegend ? self::VERTICAL_LEGEND_TOP_MARGIN : self::HORIZONTAL_LEGEND_TOP_MARGIN;
- $requiredPaddingAboveItemBullet = $legendTopMargin + $heightOfTextAboveBulletTop + $effectiveShadowPadding;
-
- $paddingAddedByPChart = 0;
- if($verticalLegend)
- {
- if($maxLogoHeight)
- {
- // see line 1691 of pDraw.class.php
- if($maxLogoHeight < $effectiveLegendItemVerticalInterstice)
- {
- $paddingAddedByPChart = ($effectiveLegendItemVerticalInterstice / 2) - ($maxLogoHeight / 2);
- }
- }
- else
- {
- // see line 1711 of pDraw.class.php ($Y+$IconAreaHeight/2)
- $paddingAddedByPChart = $effectiveLegendItemVerticalInterstice / 2;
- }
- }
-
- $legendTopLeftYValue = $paddingAddedByPChart < $requiredPaddingAboveItemBullet ? $requiredPaddingAboveItemBullet - $paddingAddedByPChart : 0;
-
- // add colored background to each legend item
- if(count($this->ordinateLabels) > 1)
- {
- $currentPosition = $verticalLegend ? $legendTopMargin : $legendTopLeftXValue;
- $colorIndex = 1;
- foreach($this->ordinateLabels as $metricCode => &$label)
- {
- $color = $this->colors[self::GRAPHIC_COLOR_KEY . $colorIndex++];
-
- $paddedBulletWidth = $bulletWidth;
- if(isset($this->ordinateLogos[$metricCode]))
- {
- $paddedBulletWidth = $maxLogoWidth;
- }
- $paddedBulletWidth += self::LEGEND_BULLET_RIGHT_PADDING;
-
- // truncate labels if required
- if($verticalLegend)
- {
- $label = $this->truncateLabel($label, ($this->width * self::VERTICAL_LEGEND_MAX_WIDTH_PCT) - $legendTopLeftXValue - $paddedBulletWidth, $this->legendFontSize);
- $this->pData->setSerieDescription($metricCode, $label);
- }
-
- $rectangleTopLeftXValue = ($verticalLegend ? $legendTopLeftXValue : $currentPosition) + $paddedBulletWidth - self::LEGEND_HORIZONTAL_SHADOW_PADDING;
- $rectangleTopLeftYValue = $verticalLegend ? $currentPosition : $legendTopMargin;
-
- list($labelWidth, $labelHeight) = $this->getTextWidthHeight($label, $this->legendFontSize);
- $legendItemWidth = $paddedBulletWidth + $labelWidth + $effectiveLegendItemHorizontalInterstice;
- $rectangleBottomRightXValue = $rectangleTopLeftXValue + $labelWidth + (self::LEGEND_HORIZONTAL_SHADOW_PADDING * 2);
-
- $legendItemHeight = max($maxLogoHeight, $this->legendFontSize) + ($effectiveShadowPadding * 2);
- $rectangleBottomRightYValue = $rectangleTopLeftYValue + $legendItemHeight;
-
- $this->pImage->drawFilledRectangle(
- $rectangleTopLeftXValue,
- $rectangleTopLeftYValue,
- $rectangleBottomRightXValue,
- $rectangleBottomRightYValue,
- array(
- 'Alpha' => self::LEGEND_SHADOW_OPACITY,
- 'R' => $color['R'],
- 'G' => $color['G'],
- 'B' => $color['B'],
- )
- );
-
- if($verticalLegend)
- {
- $currentPositionIncrement = max($maxLogoHeight, $effectiveLegendItemVerticalInterstice, $this->legendFontSize) + self::PCHART_HARD_CODED_VERTICAL_LEGEND_INTERSTICE;
- }
- else
- {
- $currentPositionIncrement = $legendItemWidth;
- }
-
- $currentPosition += $currentPositionIncrement;
- }
- }
-
- // draw legend
- $legendColor = $this->colors[self::VALUE_COLOR_KEY];
- $this->pImage->drawLegend(
- $legendTopLeftXValue,
- $legendTopLeftYValue,
- array(
- 'Style' => LEGEND_NOBORDER,
- 'FontSize' => $this->legendFontSize,
- 'BoxWidth' => $bulletWidth,
- 'XSpacing' => $effectiveLegendItemHorizontalInterstice, // not effective when vertical
- 'Mode' => $verticalLegend ? LEGEND_VERTICAL : LEGEND_HORIZONTAL,
- 'BoxHeight' => $verticalLegend ? $effectiveLegendItemVerticalInterstice : null,
- 'Family' => $bulletType,
- 'FontR' => $legendColor['R'],
- 'FontG' => $legendColor['G'],
- 'FontB' => $legendColor['B'],
- )
- );
- }
- }
-
- protected static function getMaxLogoSize($logoPaths)
- {
- $maxLogoWidth = 0;
- $maxLogoHeight = 0;
- foreach($logoPaths as $logoPath)
- {
- list($logoWidth, $logoHeight) = self::getLogoSize($logoPath);
-
- if($logoWidth > $maxLogoWidth)
- {
- $maxLogoWidth = $logoWidth;
- }
- if($logoHeight > $maxLogoHeight)
- {
- $maxLogoHeight = $logoHeight;
- }
- }
-
- return array($maxLogoWidth, $maxLogoHeight);
- }
-
- protected static function getLogoSize($logoPath)
- {
- $pathInfo = getimagesize($logoPath);
- return array($pathInfo[0], $pathInfo[1]);
- }
-
- protected function getGridLeftMargin($horizontalGraph, $withLabel)
- {
- $gridLeftMargin = self::LEFT_GRID_MARGIN + self::OUTER_TICK_WIDTH;
-
- if($withLabel)
- {
- list($maxTextWidth, $maxTextHeight) = $this->getMaximumTextWidthHeight($horizontalGraph ? $this->abscissaSeries : $this->ordinateSeries);
- $gridLeftMargin += $maxTextWidth;
- }
-
- return $gridLeftMargin;
- }
-
- protected function getGridTopMargin($horizontalGraph, $verticalLegend)
- {
- list($ordinateMaxWidth, $ordinateMaxHeight) = $this->getMaximumTextWidthHeight($this->ordinateSeries);
-
- if($horizontalGraph)
- {
- $topMargin = $ordinateMaxHeight + self::TOP_GRID_MARGIN_HORIZONTAL_GRAPH + self::OUTER_TICK_WIDTH;
- }
- else
- {
- $topMargin = $ordinateMaxHeight / 2;
- }
-
- if($this->showLegend && !$verticalLegend)
- {
- $topMargin += $this->getHorizontalLegendHeight();
- }
-
- return $topMargin;
- }
-
- private function getHorizontalLegendHeight()
- {
- list($maxMetricLegendWidth, $maxMetricLegendHeight) =
- $this->getMaximumTextWidthHeight(array_values($this->ordinateLabels), $this->legendFontSize);
-
- return $maxMetricLegendHeight + self::HORIZONTAL_LEGEND_BOTTOM_MARGIN + self::HORIZONTAL_LEGEND_TOP_MARGIN;
- }
-
- protected function getGraphHeight($horizontalGraph, $verticalLegend)
- {
- return $this->getGraphBottom($horizontalGraph) - $this->getGridTopMargin($horizontalGraph, $verticalLegend);
- }
-
- private function getGridBottomMargin($horizontalGraph)
- {
- $gridBottomMargin = self::BOTTOM_GRID_MARGIN;
- if(!$horizontalGraph)
- {
- list($abscissaMaxWidth, $abscissaMaxHeight) = $this->getMaximumTextWidthHeight($this->abscissaSeries);
- $gridBottomMargin += $abscissaMaxHeight;
- }
- return $gridBottomMargin;
- }
-
- protected function getGridRightMargin($horizontalGraph)
- {
- if($horizontalGraph)
- {
- // in horizontal graphs, metric values are displayed on the far right of the bar
- list($ordinateMaxWidth, $ordinateMaxHeight) = $this->getMaximumTextWidthHeight($this->ordinateSeries);
- return self::RIGHT_GRID_MARGIN_HORIZONTAL_GRAPH + $ordinateMaxWidth;
- }
- else
- {
- return 0;
- }
- }
-
- protected function getGraphBottom($horizontalGraph)
- {
- return $this->height - $this->getGridBottomMargin($horizontalGraph);
- }
-
- protected function truncateLabel($label, $labelWidthLimit, $fontSize = false)
- {
- list($truncationTextWidth, $truncationTextHeight) = $this->getTextWidthHeight(self::TRUNCATION_TEXT, $fontSize);
- list($labelWidth, $labelHeight) = $this->getTextWidthHeight($label, $fontSize);
-
- if($labelWidth > $labelWidthLimit)
- {
- $averageCharWidth = $labelWidth / strlen($label);
- $charsToKeep = floor(($labelWidthLimit - $truncationTextWidth) / $averageCharWidth);
- $label = substr($label, 0, $charsToKeep) . self::TRUNCATION_TEXT;
- }
- return $label;
- }
-
- // display min & max values
- // can not currently be used because pChart's label design is not flexible enough
- // e.g: it is not possible to remove the box border & the square icon
- // it would require modifying pChart code base which we try to avoid
- // see http://dev.piwik.org/trac/ticket/3396
+ const GRAPHIC_COLOR_KEY = 'GRAPHIC_COLOR';
+ const VALUE_COLOR_KEY = 'VALUE_COLOR';
+ const GRID_COLOR_KEY = 'GRID_COLOR';
+
+ const TRUNCATION_TEXT = '...';
+
+ const DEFAULT_TICK_ALPHA = 20;
+ const DEFAULT_SERIE_WEIGHT = 0.5;
+ const LEFT_GRID_MARGIN = 4;
+ const BOTTOM_GRID_MARGIN = 10;
+ const TOP_GRID_MARGIN_HORIZONTAL_GRAPH = 1;
+ const RIGHT_GRID_MARGIN_HORIZONTAL_GRAPH = 4;
+ const OUTER_TICK_WIDTH = 5;
+ const INNER_TICK_WIDTH = 0;
+ const LABEL_SPACE_VERTICAL_GRAPH = 7;
+
+ const HORIZONTAL_LEGEND_TOP_MARGIN = 5;
+ const HORIZONTAL_LEGEND_LEFT_MARGIN = 10;
+ const HORIZONTAL_LEGEND_BOTTOM_MARGIN = 10;
+ const VERTICAL_LEGEND_TOP_MARGIN = 8;
+ const VERTICAL_LEGEND_LEFT_MARGIN = 6;
+ const VERTICAL_LEGEND_MAX_WIDTH_PCT = 0.70;
+ const LEGEND_LINE_BULLET_WIDTH = 14;
+ const LEGEND_BOX_BULLET_WIDTH = 5;
+ const LEGEND_BULLET_RIGHT_PADDING = 5;
+ const LEGEND_ITEM_HORIZONTAL_INTERSTICE = 6;
+ const LEGEND_ITEM_VERTICAL_INTERSTICE_OFFSET = 4;
+ const LEGEND_SHADOW_OPACITY = 25;
+ const LEGEND_VERTICAL_SHADOW_PADDING = 3;
+ const LEGEND_HORIZONTAL_SHADOW_PADDING = 2;
+ const PCHART_HARD_CODED_VERTICAL_LEGEND_INTERSTICE = 5;
+
+ protected function getDefaultColors()
+ {
+ return array(
+ self::VALUE_COLOR_KEY => '444444',
+ self::GRID_COLOR_KEY => 'CCCCCC',
+ self::GRAPHIC_COLOR_KEY . '1' => '5170AE',
+ self::GRAPHIC_COLOR_KEY . '2' => 'F29007',
+ self::GRAPHIC_COLOR_KEY . '3' => 'CC3399',
+ self::GRAPHIC_COLOR_KEY . '4' => '9933CC',
+ self::GRAPHIC_COLOR_KEY . '5' => '80A033',
+ self::GRAPHIC_COLOR_KEY . '6' => '246AD2'
+ );
+ }
+
+ protected function initGridChart(
+ $displayVerticalGridLines,
+ $bulletType,
+ $horizontalGraph,
+ $showTicks,
+ $verticalLegend
+ )
+ {
+ $this->initpData();
+
+ $colorIndex = 1;
+ foreach ($this->ordinateSeries as $column => $data) {
+ $this->pData->setSerieWeight($column, self::DEFAULT_SERIE_WEIGHT);
+ $graphicColor = $this->colors[self::GRAPHIC_COLOR_KEY . $colorIndex++];
+ $this->pData->setPalette($column, $graphicColor);
+ }
+
+ $this->initpImage();
+
+ // graph area coordinates
+ $topLeftXValue = $this->getGridLeftMargin($horizontalGraph, $withLabel = true);
+ $topLeftYValue = $this->getGridTopMargin($horizontalGraph, $verticalLegend);
+ $bottomRightXValue = $this->width - $this->getGridRightMargin($horizontalGraph);
+ $bottomRightYValue = $this->getGraphBottom($horizontalGraph);
+
+ $this->pImage->setGraphArea(
+ $topLeftXValue,
+ $topLeftYValue,
+ $bottomRightXValue,
+ $bottomRightYValue
+ );
+
+ // determine how many labels need to be skipped
+ $skippedLabels = 0;
+ if (!$horizontalGraph) {
+ list($abscissaMaxWidth, $abscissaMaxHeight) = $this->getMaximumTextWidthHeight($this->abscissaSeries);
+ $graphWidth = $bottomRightXValue - $topLeftXValue;
+ $maxNumOfLabels = floor($graphWidth / ($abscissaMaxWidth + self::LABEL_SPACE_VERTICAL_GRAPH));
+
+ $abscissaSeriesCount = count($this->abscissaSeries);
+ if ($maxNumOfLabels < $abscissaSeriesCount) {
+ for ($candidateSkippedLabels = 1; $candidateSkippedLabels < $abscissaSeriesCount; $candidateSkippedLabels++) {
+ $numberOfSegments = $abscissaSeriesCount / ($candidateSkippedLabels + 1);
+ $numberOfCompleteSegments = floor($numberOfSegments);
+
+ $numberOfLabels = $numberOfCompleteSegments;
+ if ($numberOfSegments > $numberOfCompleteSegments) {
+ $numberOfLabels++;
+ }
+
+ if ($numberOfLabels <= $maxNumOfLabels) {
+ $skippedLabels = $candidateSkippedLabels;
+ break;
+ }
+ }
+ }
+
+ if ($this->forceSkippedLabels
+ && $skippedLabels
+ && $skippedLabels < $this->forceSkippedLabels
+ && $abscissaSeriesCount > $this->forceSkippedLabels + 1
+ ) {
+ $skippedLabels = $this->forceSkippedLabels;
+ }
+ }
+
+ $ordinateAxisLength =
+ $horizontalGraph ? $bottomRightXValue - $topLeftXValue : $this->getGraphHeight($horizontalGraph, $verticalLegend);
+
+ $maxOrdinateValue = 0;
+ foreach ($this->ordinateSeries as $column => $data) {
+ $currentMax = $this->pData->getMax($column);
+
+ if ($currentMax > $maxOrdinateValue) {
+ $maxOrdinateValue = $currentMax;
+ }
+ }
+
+ // rounding top scale value to the next multiple of 10
+ if ($maxOrdinateValue > 10) {
+ $modTen = $maxOrdinateValue % 10;
+ if ($modTen) $maxOrdinateValue += 10 - $modTen;
+ }
+
+ $gridColor = $this->colors[self::GRID_COLOR_KEY];
+ $this->pImage->drawScale(
+ array(
+ 'Mode' => SCALE_MODE_MANUAL,
+ 'GridTicks' => 0,
+ 'LabelSkip' => $skippedLabels,
+ 'DrawXLines' => $displayVerticalGridLines,
+ 'Factors' => array(ceil($maxOrdinateValue / 2)),
+ 'MinDivHeight' => $ordinateAxisLength / 2,
+ 'AxisAlpha' => 0,
+ 'SkippedAxisAlpha' => 0,
+ 'TickAlpha' => $showTicks ? self::DEFAULT_TICK_ALPHA : 0,
+ 'InnerTickWidth' => self::INNER_TICK_WIDTH,
+ 'OuterTickWidth' => self::OUTER_TICK_WIDTH,
+ 'GridR' => $gridColor['R'],
+ 'GridG' => $gridColor['G'],
+ 'GridB' => $gridColor['B'],
+ 'GridAlpha' => 100,
+ 'ManualScale' => array(
+ 0 => array(
+ 'Min' => 0,
+ 'Max' => $maxOrdinateValue
+ )
+ ),
+ 'Pos' => $horizontalGraph ? SCALE_POS_TOPBOTTOM : SCALE_POS_LEFTRIGHT,
+ )
+ );
+
+ if ($this->showLegend) {
+ switch ($bulletType) {
+ case LEGEND_FAMILY_LINE:
+ $bulletWidth = self::LEGEND_LINE_BULLET_WIDTH;
+
+ // measured using a picture editing software
+ $iconOffsetAboveLabelSymmetryAxis = -2;
+ break;
+
+ case LEGEND_FAMILY_BOX:
+ $bulletWidth = self::LEGEND_BOX_BULLET_WIDTH;
+
+ // measured using a picture editing software
+ $iconOffsetAboveLabelSymmetryAxis = 3;
+ break;
+ }
+
+ // pChart requires two coordinates to draw the legend $legendTopLeftXValue & $legendTopLeftYValue
+ // $legendTopLeftXValue = legend's left padding
+ $legendTopLeftXValue = $topLeftXValue + ($verticalLegend ? self::VERTICAL_LEGEND_LEFT_MARGIN : self::HORIZONTAL_LEGEND_LEFT_MARGIN);
+
+ // $legendTopLeftYValue = y coordinate of the top edge of the legend's icons
+ // Caution :
+ // - pChart will silently add some value (see $paddingAddedByPChart) to $legendTopLeftYValue depending on multiple criterias
+ // - pChart will not take into account the size of the text. Setting $legendTopLeftYValue = 0 will crop the legend's labels
+ // The following section of code determines the value of $legendTopLeftYValue while taking into account the following paremeters :
+ // - whether legend items have icons
+ // - whether icons are bigger than the legend's labels
+ // - how much colored shadow padding is required
+ list($maxLogoWidth, $maxLogoHeight) = self::getMaxLogoSize(array_values($this->ordinateLogos));
+ if ($maxLogoHeight >= $this->legendFontSize) {
+ $heightOfTextAboveBulletTop = 0;
+ $paddingCreatedByLogo = $maxLogoHeight - $this->legendFontSize;
+ $effectiveShadowPadding = $paddingCreatedByLogo < self::LEGEND_VERTICAL_SHADOW_PADDING * 2 ? self::LEGEND_VERTICAL_SHADOW_PADDING - ($paddingCreatedByLogo / 2) : 0;
+ } else {
+ if ($maxLogoHeight) {
+ // measured using a picture editing software
+ $iconOffsetAboveLabelSymmetryAxis = 5;
+ }
+ $heightOfTextAboveBulletTop = $this->legendFontSize / 2 - $iconOffsetAboveLabelSymmetryAxis;
+ $effectiveShadowPadding = self::LEGEND_VERTICAL_SHADOW_PADDING;
+ }
+
+ $effectiveLegendItemVerticalInterstice = $this->legendFontSize + self::LEGEND_ITEM_VERTICAL_INTERSTICE_OFFSET;
+ $effectiveLegendItemHorizontalInterstice = self::LEGEND_ITEM_HORIZONTAL_INTERSTICE + self::LEGEND_HORIZONTAL_SHADOW_PADDING;
+
+ $legendTopMargin = $verticalLegend ? self::VERTICAL_LEGEND_TOP_MARGIN : self::HORIZONTAL_LEGEND_TOP_MARGIN;
+ $requiredPaddingAboveItemBullet = $legendTopMargin + $heightOfTextAboveBulletTop + $effectiveShadowPadding;
+
+ $paddingAddedByPChart = 0;
+ if ($verticalLegend) {
+ if ($maxLogoHeight) {
+ // see line 1691 of pDraw.class.php
+ if ($maxLogoHeight < $effectiveLegendItemVerticalInterstice) {
+ $paddingAddedByPChart = ($effectiveLegendItemVerticalInterstice / 2) - ($maxLogoHeight / 2);
+ }
+ } else {
+ // see line 1711 of pDraw.class.php ($Y+$IconAreaHeight/2)
+ $paddingAddedByPChart = $effectiveLegendItemVerticalInterstice / 2;
+ }
+ }
+
+ $legendTopLeftYValue = $paddingAddedByPChart < $requiredPaddingAboveItemBullet ? $requiredPaddingAboveItemBullet - $paddingAddedByPChart : 0;
+
+ // add colored background to each legend item
+ if (count($this->ordinateLabels) > 1) {
+ $currentPosition = $verticalLegend ? $legendTopMargin : $legendTopLeftXValue;
+ $colorIndex = 1;
+ foreach ($this->ordinateLabels as $metricCode => &$label) {
+ $color = $this->colors[self::GRAPHIC_COLOR_KEY . $colorIndex++];
+
+ $paddedBulletWidth = $bulletWidth;
+ if (isset($this->ordinateLogos[$metricCode])) {
+ $paddedBulletWidth = $maxLogoWidth;
+ }
+ $paddedBulletWidth += self::LEGEND_BULLET_RIGHT_PADDING;
+
+ // truncate labels if required
+ if ($verticalLegend) {
+ $label = $this->truncateLabel($label, ($this->width * self::VERTICAL_LEGEND_MAX_WIDTH_PCT) - $legendTopLeftXValue - $paddedBulletWidth, $this->legendFontSize);
+ $this->pData->setSerieDescription($metricCode, $label);
+ }
+
+ $rectangleTopLeftXValue = ($verticalLegend ? $legendTopLeftXValue : $currentPosition) + $paddedBulletWidth - self::LEGEND_HORIZONTAL_SHADOW_PADDING;
+ $rectangleTopLeftYValue = $verticalLegend ? $currentPosition : $legendTopMargin;
+
+ list($labelWidth, $labelHeight) = $this->getTextWidthHeight($label, $this->legendFontSize);
+ $legendItemWidth = $paddedBulletWidth + $labelWidth + $effectiveLegendItemHorizontalInterstice;
+ $rectangleBottomRightXValue = $rectangleTopLeftXValue + $labelWidth + (self::LEGEND_HORIZONTAL_SHADOW_PADDING * 2);
+
+ $legendItemHeight = max($maxLogoHeight, $this->legendFontSize) + ($effectiveShadowPadding * 2);
+ $rectangleBottomRightYValue = $rectangleTopLeftYValue + $legendItemHeight;
+
+ $this->pImage->drawFilledRectangle(
+ $rectangleTopLeftXValue,
+ $rectangleTopLeftYValue,
+ $rectangleBottomRightXValue,
+ $rectangleBottomRightYValue,
+ array(
+ 'Alpha' => self::LEGEND_SHADOW_OPACITY,
+ 'R' => $color['R'],
+ 'G' => $color['G'],
+ 'B' => $color['B'],
+ )
+ );
+
+ if ($verticalLegend) {
+ $currentPositionIncrement = max($maxLogoHeight, $effectiveLegendItemVerticalInterstice, $this->legendFontSize) + self::PCHART_HARD_CODED_VERTICAL_LEGEND_INTERSTICE;
+ } else {
+ $currentPositionIncrement = $legendItemWidth;
+ }
+
+ $currentPosition += $currentPositionIncrement;
+ }
+ }
+
+ // draw legend
+ $legendColor = $this->colors[self::VALUE_COLOR_KEY];
+ $this->pImage->drawLegend(
+ $legendTopLeftXValue,
+ $legendTopLeftYValue,
+ array(
+ 'Style' => LEGEND_NOBORDER,
+ 'FontSize' => $this->legendFontSize,
+ 'BoxWidth' => $bulletWidth,
+ 'XSpacing' => $effectiveLegendItemHorizontalInterstice, // not effective when vertical
+ 'Mode' => $verticalLegend ? LEGEND_VERTICAL : LEGEND_HORIZONTAL,
+ 'BoxHeight' => $verticalLegend ? $effectiveLegendItemVerticalInterstice : null,
+ 'Family' => $bulletType,
+ 'FontR' => $legendColor['R'],
+ 'FontG' => $legendColor['G'],
+ 'FontB' => $legendColor['B'],
+ )
+ );
+ }
+ }
+
+ protected static function getMaxLogoSize($logoPaths)
+ {
+ $maxLogoWidth = 0;
+ $maxLogoHeight = 0;
+ foreach ($logoPaths as $logoPath) {
+ list($logoWidth, $logoHeight) = self::getLogoSize($logoPath);
+
+ if ($logoWidth > $maxLogoWidth) {
+ $maxLogoWidth = $logoWidth;
+ }
+ if ($logoHeight > $maxLogoHeight) {
+ $maxLogoHeight = $logoHeight;
+ }
+ }
+
+ return array($maxLogoWidth, $maxLogoHeight);
+ }
+
+ protected static function getLogoSize($logoPath)
+ {
+ $pathInfo = getimagesize($logoPath);
+ return array($pathInfo[0], $pathInfo[1]);
+ }
+
+ protected function getGridLeftMargin($horizontalGraph, $withLabel)
+ {
+ $gridLeftMargin = self::LEFT_GRID_MARGIN + self::OUTER_TICK_WIDTH;
+
+ if ($withLabel) {
+ list($maxTextWidth, $maxTextHeight) = $this->getMaximumTextWidthHeight($horizontalGraph ? $this->abscissaSeries : $this->ordinateSeries);
+ $gridLeftMargin += $maxTextWidth;
+ }
+
+ return $gridLeftMargin;
+ }
+
+ protected function getGridTopMargin($horizontalGraph, $verticalLegend)
+ {
+ list($ordinateMaxWidth, $ordinateMaxHeight) = $this->getMaximumTextWidthHeight($this->ordinateSeries);
+
+ if ($horizontalGraph) {
+ $topMargin = $ordinateMaxHeight + self::TOP_GRID_MARGIN_HORIZONTAL_GRAPH + self::OUTER_TICK_WIDTH;
+ } else {
+ $topMargin = $ordinateMaxHeight / 2;
+ }
+
+ if ($this->showLegend && !$verticalLegend) {
+ $topMargin += $this->getHorizontalLegendHeight();
+ }
+
+ return $topMargin;
+ }
+
+ private function getHorizontalLegendHeight()
+ {
+ list($maxMetricLegendWidth, $maxMetricLegendHeight) =
+ $this->getMaximumTextWidthHeight(array_values($this->ordinateLabels), $this->legendFontSize);
+
+ return $maxMetricLegendHeight + self::HORIZONTAL_LEGEND_BOTTOM_MARGIN + self::HORIZONTAL_LEGEND_TOP_MARGIN;
+ }
+
+ protected function getGraphHeight($horizontalGraph, $verticalLegend)
+ {
+ return $this->getGraphBottom($horizontalGraph) - $this->getGridTopMargin($horizontalGraph, $verticalLegend);
+ }
+
+ private function getGridBottomMargin($horizontalGraph)
+ {
+ $gridBottomMargin = self::BOTTOM_GRID_MARGIN;
+ if (!$horizontalGraph) {
+ list($abscissaMaxWidth, $abscissaMaxHeight) = $this->getMaximumTextWidthHeight($this->abscissaSeries);
+ $gridBottomMargin += $abscissaMaxHeight;
+ }
+ return $gridBottomMargin;
+ }
+
+ protected function getGridRightMargin($horizontalGraph)
+ {
+ if ($horizontalGraph) {
+ // in horizontal graphs, metric values are displayed on the far right of the bar
+ list($ordinateMaxWidth, $ordinateMaxHeight) = $this->getMaximumTextWidthHeight($this->ordinateSeries);
+ return self::RIGHT_GRID_MARGIN_HORIZONTAL_GRAPH + $ordinateMaxWidth;
+ } else {
+ return 0;
+ }
+ }
+
+ protected function getGraphBottom($horizontalGraph)
+ {
+ return $this->height - $this->getGridBottomMargin($horizontalGraph);
+ }
+
+ protected function truncateLabel($label, $labelWidthLimit, $fontSize = false)
+ {
+ list($truncationTextWidth, $truncationTextHeight) = $this->getTextWidthHeight(self::TRUNCATION_TEXT, $fontSize);
+ list($labelWidth, $labelHeight) = $this->getTextWidthHeight($label, $fontSize);
+
+ if ($labelWidth > $labelWidthLimit) {
+ $averageCharWidth = $labelWidth / strlen($label);
+ $charsToKeep = floor(($labelWidthLimit - $truncationTextWidth) / $averageCharWidth);
+ $label = substr($label, 0, $charsToKeep) . self::TRUNCATION_TEXT;
+ }
+ return $label;
+ }
+
+ // display min & max values
+ // can not currently be used because pChart's label design is not flexible enough
+ // e.g: it is not possible to remove the box border & the square icon
+ // it would require modifying pChart code base which we try to avoid
+ // see http://dev.piwik.org/trac/ticket/3396
// protected function displayMinMaxValues()
// {
// if($displayMinMax)