Download plugins/ImageGraph/StaticGraph/GridGraph.php from Leon4gr45/matomo: direct link, hf CLI and curl.
- Browser
- Download file 21.3 kB
-
https://huggingface.co/spaces/Leon4gr45/matomo/resolve/main/plugins/ImageGraph/StaticGraph/GridGraph.php
- Command line
-
hf download hf://spaces/Leon4gr45/matomo/plugins/ImageGraph/StaticGraph/GridGraph.php
-
curl -L -o GridGraph.php https://huggingface.co/spaces/Leon4gr45/matomo/resolve/main/plugins/ImageGraph/StaticGraph/GridGraph.php
21.3 kB
| /** | |
| * Matomo - free/libre analytics platform | |
| * | |
| * @link https://matomo.org | |
| * @license https://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later | |
| */ | |
| namespace Piwik\Plugins\ImageGraph\StaticGraph; | |
| use Piwik\Exception\InvalidDimensionException; | |
| use Piwik\Plugins\ImageGraph\StaticGraph; | |
| abstract class GridGraph extends StaticGraph | |
| { | |
| public const GRAPHIC_COLOR_KEY = 'GRAPHIC_COLOR'; | |
| public const TRUNCATION_TEXT = '...'; | |
| public const DEFAULT_TICK_ALPHA = 20; | |
| public const DEFAULT_SERIE_WEIGHT = 0.5; | |
| public const LEFT_GRID_MARGIN = 20; | |
| public const BOTTOM_GRID_MARGIN = 10; | |
| public const TOP_GRID_MARGIN_HORIZONTAL_GRAPH = 10; | |
| public const RIGHT_GRID_MARGIN_HORIZONTAL_GRAPH = 20; | |
| public const OUTER_TICK_WIDTH = 5; | |
| public const INNER_TICK_WIDTH = 0; | |
| public const LABEL_SPACE_VERTICAL_GRAPH = 7; | |
| public const HORIZONTAL_LEGEND_TOP_MARGIN = 5; | |
| public const HORIZONTAL_LEGEND_LEFT_MARGIN = 10; | |
| public const HORIZONTAL_LEGEND_BOTTOM_MARGIN = 10; | |
| public const VERTICAL_LEGEND_TOP_MARGIN = 10; | |
| public const VERTICAL_LEGEND_LEFT_MARGIN = 6; | |
| public const VERTICAL_LEGEND_MAX_WIDTH_PCT = 0.70; | |
| public const LEGEND_LINE_BULLET_WIDTH = 14; | |
| public const LEGEND_BOX_BULLET_WIDTH = 5; | |
| public const LEGEND_BULLET_RIGHT_PADDING = 5; | |
| public const LEGEND_ITEM_HORIZONTAL_INTERSTICE = 6; | |
| public const LEGEND_ITEM_VERTICAL_INTERSTICE_OFFSET = 4; | |
| public const LEGEND_SHADOW_OPACITY = 25; | |
| public const LEGEND_VERTICAL_SHADOW_PADDING = 3; | |
| public const LEGEND_HORIZONTAL_SHADOW_PADDING = 2; | |
| public const PCHART_HARD_CODED_VERTICAL_LEGEND_INTERSTICE = 5; | |
| protected function getDefaultColors() | |
| { | |
| return array( | |
| 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->drawBackground(); | |
| $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 = ceil($currentMax); | |
| } | |
| } | |
| // rounding top scale value to the next multiple of 10 | |
| if ($maxOrdinateValue > 10) { | |
| $modTen = $maxOrdinateValue % 10; | |
| if ($modTen) { | |
| $maxOrdinateValue += 10 - $modTen; | |
| } | |
| } | |
| if ($ordinateAxisLength <= 0 || $bottomRightYValue - $topLeftYValue <= 0) { | |
| throw new InvalidDimensionException('Error: the graph dimension is not valid. Please try larger width and height values or use 0 for default values.'); | |
| } | |
| $gridColor = $this->gridColor; | |
| $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 criteria | |
| // - 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 parameters : | |
| // - 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->textColor; | |
| $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 + self::TOP_GRID_MARGIN_HORIZONTAL_GRAPH; | |
| } | |
| if ($this->showLegend && !$verticalLegend) { | |
| $topMargin += $this->getHorizontalLegendHeight(); | |
| } | |
| return $topMargin; | |
| } | |
| private function getHorizontalLegendHeight() | |
| { | |
| list($maxMetricLegendWidth, $maxMetricLegendHeight) = | |
| $this->getMaximumTextWidthHeight(array_values($this->ordinateLabels)); | |
| 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 self::RIGHT_GRID_MARGIN_HORIZONTAL_GRAPH; | |
| } | |
| } | |
| 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 https://github.com/piwik/piwik/issues/3396 | |
| // protected function displayMinMaxValues() | |
| // { | |
| // if ($displayMinMax) | |
| // { | |
| // // when plotting multiple metrics, display min & max on both series | |
| // // to fix: in vertical bars, labels are hidden when multiple metrics are plotted, hence the restriction on count($this->ordinateSeries) == 1 | |
| // if ($this->multipleMetrics && count($this->ordinateSeries) == 1) | |
| // { | |
| // $colorIndex = 1; | |
| // foreach($this->ordinateSeries as $column => $data) | |
| // { | |
| // $color = $this->colors[self::GRAPHIC_COLOR_KEY . $colorIndex++]; | |
| // | |
| // $this->pImage->writeLabel( | |
| // $column, | |
| // self::locateMinMaxValue($data), | |
| // $Format = array( | |
| // 'NoTitle' => true, | |
| // 'DrawPoint' => false, | |
| // 'DrawSerieColor' => true, | |
| // 'TitleMode' => LABEL_TITLE_NOBACKGROUND, | |
| // 'GradientStartR' => $color['R'], | |
| // 'GradientStartG' => $color['G'], | |
| // 'GradientStartB' => $color['B'], | |
| // 'GradientEndR' => 255, | |
| // 'GradientEndG' => 255, | |
| // 'GradientEndB' => 255, | |
| // 'BoxWidth' => 0, | |
| // 'VerticalMargin' => 9, | |
| // 'HorizontalMargin' => 7, | |
| // ) | |
| // ); | |
| // } | |
| // } | |
| // else | |
| // { | |
| // // display only one min & max label | |
| // } | |
| // } | |
| // } | |
| // protected static function locateMinMaxValue($data) | |
| // { | |
| // $firstValue = $data[0]; | |
| // $minValue = $firstValue; | |
| // $minValueIndex = 0; | |
| // $maxValue = $firstValue; | |
| // $maxValueIndex = 0; | |
| // foreach($data as $index => $value) | |
| // { | |
| // if ($value > $maxValue) | |
| // { | |
| // $maxValue = $value; | |
| // $maxValueIndex = $index; | |
| // } | |
| // | |
| // if ($value < $minValue) | |
| // { | |
| // $minValue = $value; | |
| // $minValueIndex = $index; | |
| // } | |
| // } | |
| // | |
| // return array($minValueIndex, $maxValueIndex); | |
| // } | |
| } | |