1<?php 2/** 3 * Matomo - free/libre analytics platform 4 * 5 * @link https://matomo.org 6 * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later 7 * 8 */ 9namespace Piwik\Plugins\ImageGraph\StaticGraph; 10use Piwik\Piwik; 11 12/** 13 * 14 */ 15class HorizontalBar extends GridGraph 16{ 17 const INTERLEAVE = 0.30; 18 const PADDING_CHARS = ' '; 19 const LEGEND_SQUARE_WIDTH = 11; 20 const MIN_SPACE_BETWEEN_HORIZONTAL_VALUES = 5; 21 const LOGO_MIN_RIGHT_MARGIN = 3; 22 23 public function renderGraph() 24 { 25 $verticalLegend = false; 26 27 // create resized copies of logo to match maximum width / height 28 foreach ($this->abscissaLogos as &$logoPath) { 29 $logoPath = $this->createResizedImageCopyIfNeeded($logoPath); 30 list($logoWidth, $logoHeight) = self::getLogoSize($logoPath); 31 $logoPathToHeight[$logoPath] = $logoHeight; 32 } 33 34 // determine the maximum logo width & height 35 list($maxLogoWidth, $maxLogoHeight) = self::getMaxLogoSize($this->abscissaLogos); 36 37 // truncate report 38 $graphHeight = $this->getGraphBottom($horizontalGraph = true) - $this->getGridTopMargin($horizontalGraph = true, $verticalLegend); 39 40 list($abscissaMaxWidth, $abscissaMaxHeight) = $this->getMaximumTextWidthHeight($this->abscissaSeries); 41 list($ordinateMaxWidth, $ordinateMaxHeight) = $this->getMaximumTextWidthHeight($this->ordinateSeries); 42 43 $numberOfSeries = count($this->ordinateSeries); 44 $ordinateMaxHeight = $ordinateMaxHeight * $numberOfSeries; 45 46 $textMaxHeight = $abscissaMaxHeight > $ordinateMaxHeight ? $abscissaMaxHeight : $ordinateMaxHeight; 47 48 $minLineWidth = ($textMaxHeight > $maxLogoHeight ? $textMaxHeight : $maxLogoHeight) + (self::MIN_SPACE_BETWEEN_HORIZONTAL_VALUES * $numberOfSeries); 49 $maxNumOfValues = floor($graphHeight / $minLineWidth); 50 $abscissaSeriesCount = count($this->abscissaSeries); 51 52 if ($maxNumOfValues < $abscissaSeriesCount - 1) { 53 $sumOfOthers = array(); 54 $truncatedOrdinateSeries = array(); 55 $truncatedAbscissaLogos = array(); 56 $truncatedAbscissaSeries = array(); 57 foreach ($this->ordinateSeries as $column => $data) { 58 $truncatedOrdinateSeries[$column] = array(); 59 $sumOfOthers[$column] = 0; 60 } 61 62 $i = 0; 63 for (; $i < $maxNumOfValues; $i++) { 64 foreach ($this->ordinateSeries as $column => $data) { 65 $truncatedOrdinateSeries[$column][] = $data[$i]; 66 } 67 68 $truncatedAbscissaLogos[] = isset($this->abscissaLogos[$i]) ? $this->abscissaLogos[$i] : null; 69 $truncatedAbscissaSeries[] = $this->abscissaSeries[$i]; 70 } 71 72 for (; $i < $abscissaSeriesCount; $i++) { 73 foreach ($this->ordinateSeries as $column => $data) { 74 $sumOfOthers[$column] += $data[$i]; 75 } 76 } 77 78 foreach ($this->ordinateSeries as $column => $data) { 79 $truncatedOrdinateSeries[$column][] = $sumOfOthers[$column]; 80 } 81 82 $truncatedAbscissaSeries[] = Piwik::translate('General_Others'); 83 $this->abscissaSeries = $truncatedAbscissaSeries; 84 $this->ordinateSeries = $truncatedOrdinateSeries; 85 $this->abscissaLogos = $truncatedAbscissaLogos; 86 } 87 88 // blank characters are used to pad labels so the logo can be displayed 89 $paddingText = ''; 90 $paddingWidth = 0; 91 if ($maxLogoWidth > 0) { 92 while ($paddingWidth < $maxLogoWidth + self::LOGO_MIN_RIGHT_MARGIN) { 93 $paddingText .= self::PADDING_CHARS; 94 list($paddingWidth, $paddingHeight) = $this->getTextWidthHeight($paddingText); 95 } 96 } 97 98 // determine the maximum label width according to the minimum comfortable graph size 99 $gridRightMargin = $this->getGridRightMargin($horizontalGraph = true); 100 $minGraphSize = ($this->width - $gridRightMargin) / 2; 101 102 $metricLegendWidth = 0; 103 foreach ($this->ordinateLabels as $column => $label) { 104 list($textWidth, $textHeight) = $this->getTextWidthHeight($label); 105 $metricLegendWidth += $textWidth; 106 } 107 108 $legendWidth = $metricLegendWidth + ((self::HORIZONTAL_LEGEND_LEFT_MARGIN + self::LEGEND_SQUARE_WIDTH) * $numberOfSeries); 109 if ($this->showLegend) { 110 if ($legendWidth > $minGraphSize) { 111 $minGraphSize = $legendWidth; 112 } 113 } 114 115 $gridLeftMarginWithoutLabels = $this->getGridLeftMargin($horizontalGraph = true, $withLabel = false); 116 $labelWidthLimit = 117 $this->width 118 - $gridLeftMarginWithoutLabels 119 - $gridRightMargin 120 - $paddingWidth 121 - $minGraphSize; 122 123 // truncate labels if needed 124 foreach ($this->abscissaSeries as &$label) { 125 $label = $this->truncateLabel($label, $labelWidthLimit); 126 } 127 128 $gridLeftMarginBeforePadding = $this->getGridLeftMargin($horizontalGraph = true, $withLabel = true); 129 130 // pad labels for logo space 131 foreach ($this->abscissaSeries as &$label) { 132 $label .= $paddingText; 133 } 134 135 $this->initGridChart( 136 $displayVerticalGridLines = false, 137 $bulletType = LEGEND_FAMILY_BOX, 138 $horizontalGraph = true, 139 $showTicks = false, 140 $verticalLegend 141 ); 142 143 $valueColor = $this->textColor; 144 $this->pImage->drawBarChart( 145 array( 146 'DisplayValues' => true, 147 'Interleave' => self::INTERLEAVE, 148 'DisplayR' => $valueColor['R'], 149 'DisplayG' => $valueColor['G'], 150 'DisplayB' => $valueColor['B'], 151 ) 152 ); 153 154// // display icons 155 $graphData = $this->pData->getData(); 156 $numberOfRows = count($this->abscissaSeries); 157 $logoInterleave = $this->getGraphHeight(true, $verticalLegend) / $numberOfRows; 158 for ($i = 0; $i < $numberOfRows; $i++) { 159 if (isset($this->abscissaLogos[$i])) { 160 $currentLogoPath = $this->abscissaLogos[$i]; 161 162 if (isset($logoPathToHeight[$currentLogoPath])) { 163 $logoHeight = $logoPathToHeight[$currentLogoPath]; 164 165 $pathInfo = pathinfo($currentLogoPath); 166 $logoExtension = strtoupper($pathInfo['extension']); 167 $drawingFunction = 'drawFrom' . $logoExtension; 168 169 $logoYPosition = 170 ($logoInterleave * $i) 171 + $this->getGridTopMargin(true, $verticalLegend) 172 + $graphData['Axis'][1]['Margin'] 173 - $logoHeight / 2 174 + 1; 175 176 if (method_exists($this->pImage, $drawingFunction)) { 177 $this->pImage->$drawingFunction( 178 $gridLeftMarginBeforePadding, 179 $logoYPosition, 180 $currentLogoPath 181 ); 182 } 183 } 184 } 185 } 186 } 187} 188