2023-01-23 11:03:31 +01:00

196 lines
5.6 KiB
PHP

<?php
/**
* Piwik - free/libre analytics platform
*
* @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*
*/
namespace Piwik\Visualization;
use Piwik\Common;
use Piwik\Piwik;
use Piwik\View\ViewInterface;
/**
* Renders a sparkline image given a PHP data array.
* Using the Sparkline PHP Graphing Library sparkline.org
*/
class Sparkline implements ViewInterface
{
const DEFAULT_WIDTH = 200;
const DEFAULT_HEIGHT = 50;
const MAX_WIDTH = 1000;
const MAX_HEIGHT = 1000;
/**
* Width of the sparkline
* @var int
*/
protected $_width = self::DEFAULT_WIDTH;
/**
* Height of sparkline
* @var int
*/
protected $_height = self::DEFAULT_HEIGHT;
private $values = array();
/**
* @var \Davaxi\Sparkline
*/
private $sparkline;
/**
* Array with format: array( x, y, z, ... )
* @param array $data
*/
public function setValues($data) {
$this->values = $data;
}
public function main() {
$sparkline = new \Davaxi\Sparkline();
$seconds = Piwik::translate('Intl_NSecondsShort');
$percent = Piwik::translate('Intl_NumberSymbolPercent');
$thousandSeparator = Piwik::translate('Intl_NumberSymbolGroup');
$decimalSeparator = Piwik::translate('Intl_NumberSymbolGroup');
$toRemove = array('%', $percent, str_replace('%s', '', $seconds));
$values = [];
foreach ($this->values as $value) {
// 50% and 50s should be plotted as 50
$value = str_replace($toRemove, '', $value);
// replace localized decimal separator
$value = str_replace($thousandSeparator, '', $value);
$value = str_replace($decimalSeparator, '.', $value);
if ($value == '') {
$value = 0;
}
$values[] = $value;
}
$hasFloat = false;
foreach ($values as $value) {
if (is_numeric($value)
&& is_float($value + 0) // coerce to int/float type before checking
) {
$hasFloat = true;
break;
}
}
// the sparkline lib used converts everything to integers (see the FormatTrait.php file) which means float
// numbers that are close to 1.0 or 0.0 will get floored. this can happen in the average page generation time
// report, and cause some values which are, eg, around ~.9 to appear as 0 in the sparkline. to workaround this, we
// scale the values.
if ($hasFloat) {
$values = array_map(function ($x) {
return $x * 1000.0;
}, $values);
}
$sparkline->setData($values);
$sparkline->setWidth($this->getWidth());
$sparkline->setHeight($this->getHeight());
$this->setSparklineColors($sparkline);
$sparkline->setLineThickness(1);
$sparkline->setPadding('5');
$this->sparkline = $sparkline;
}
/**
* Returns the width of the sparkline
* @return int
*/
public function getWidth() {
return $this->_width;
}
/**
* Sets the width of the sparkline
* @param int $width
*/
public function setWidth($width) {
if (!is_numeric($width) || $width <= 0) {
return;
}
if ($width > self::MAX_WIDTH) {
$this->_width = self::MAX_WIDTH;
} else {
$this->_width = (int)$width;
}
}
/**
* Returns the height of the sparkline
* @return int
*/
public function getHeight() {
return $this->_height;
}
/**
* Sets the height of the sparkline
* @param int $height
*/
public function setHeight($height) {
if (!is_numeric($height) || $height <= 0) {
return;
}
if ($height > self::MAX_HEIGHT) {
$this->_height = self::MAX_HEIGHT;
} else {
$this->_height = (int)$height;
}
}
/**
* Sets the sparkline colors
*
* @param \Davaxi\Sparkline $sparkline
*/
private function setSparklineColors($sparkline) {
$colors = Common::getRequestVar('colors', false, 'json');
if (empty($colors)) { // quick fix so row evolution sparklines will have color in widgetize's iframes
$colors = array(
'backgroundColor' => '#ffffff',
'lineColor' => '#162C4A',
'minPointColor' => '#ff7f7f',
'maxPointColor' => '#75BF7C',
'lastPointColor' => '#55AAFF',
'fillColor' => '#ffffff'
);
}
if (strtolower($colors['backgroundColor']) !== '#ffffff') {
$sparkline->setBackgroundColorHex($colors['backgroundColor']);
} else {
$sparkline->deactivateBackgroundColor();
}
$sparkline->setLineColorHex($colors['lineColor']);
if (strtolower($colors['fillColor'] !== "#ffffff")) {
$sparkline->setFillColorHex($colors['fillColor']);
} else {
$sparkline->deactivateFillColor();
}
if (strtolower($colors['minPointColor'] !== "#ffffff")) {
$sparkline->addPoint("minimum", 5, $colors['minPointColor']);
}
if (strtolower($colors['maxPointColor'] !== "#ffffff")) {
$sparkline->addPoint("maximum", 5, $colors['maxPointColor']);
}
if (strtolower($colors['lastPointColor'] !== "#ffffff")) {
$sparkline->addPoint("last", 5, $colors['lastPointColor']);
}
}
public function render() {
$this->sparkline->display();
$this->sparkline->destroy();
}
}