mirror of
https://github.com/OpenXE-org/OpenXE.git
synced 2024-12-26 14:40:29 +01:00
282 lines
7.3 KiB
PHP
282 lines
7.3 KiB
PHP
|
<?php
|
||
|
|
||
|
namespace Xentral\Widgets\Chart;
|
||
|
|
||
|
use InvalidArgumentException;
|
||
|
use JsonSerializable;
|
||
|
|
||
|
class Dataset implements JsonSerializable
|
||
|
{
|
||
|
const LINE_STYLE_SOLID = 'solid';
|
||
|
const LINE_STYLE_DASHED = 'dashed';
|
||
|
const LINE_STYLE_DOTTED = 'dotted';
|
||
|
|
||
|
const COLOR_GREEN = 'green';
|
||
|
const COLOR_BLUE = 'blue';
|
||
|
const COLOR_ORANGE = 'orange';
|
||
|
const COLOR_DARKBLUE = 'darkblue';
|
||
|
|
||
|
/** @var array $validLineStyles */
|
||
|
protected static $validLineStyles = [
|
||
|
self::LINE_STYLE_SOLID,
|
||
|
self::LINE_STYLE_DOTTED,
|
||
|
self::LINE_STYLE_DASHED,
|
||
|
];
|
||
|
|
||
|
/** @var array $colorMap */
|
||
|
protected static $colorMap = [
|
||
|
self::COLOR_GREEN => [162, 197, 90],
|
||
|
self::COLOR_BLUE => [69, 185, 211],
|
||
|
self::COLOR_ORANGE => [246, 158, 6],
|
||
|
self::COLOR_DARKBLUE => [14, 131, 148],
|
||
|
];
|
||
|
|
||
|
/** @var array $defaultOptions Standardwerte für Dataset-Optionen */
|
||
|
protected static $defaultOptions = [
|
||
|
'pointBorderWidth' => 1,
|
||
|
'pointHoverBorderWidth' => 2,
|
||
|
'pointRadius' => 1,
|
||
|
'pointHoverRadius' => 5,
|
||
|
'pointHitRadius' => 15,
|
||
|
'lineTension' => 0.2,
|
||
|
'fill' => true,
|
||
|
'borderWidth' => 3,
|
||
|
'borderDash' => [],
|
||
|
'borderCapStyle' => 'butt',
|
||
|
'borderColor' => 'rgba(0, 0, 0, 0.1)',
|
||
|
'backgroundColor' => 'rgba(0, 0, 0, 0.1)',
|
||
|
'pointBackgroundColor' => 'rgba(0, 0, 0, 0.1)',
|
||
|
];
|
||
|
|
||
|
/** @var array $defaultAlphaValues Transparenz-Werte */
|
||
|
protected static $defaultAlphaValues = [
|
||
|
'borderColor' => 1.0,
|
||
|
'backgroundColor' => 0.1,
|
||
|
'pointBackgroundColor' => 1.0,
|
||
|
];
|
||
|
|
||
|
protected $data;
|
||
|
protected $label;
|
||
|
protected $options;
|
||
|
|
||
|
/** @var bool $isDataAccumulated Gibt an ob Daten bereits kumuliert wurden */
|
||
|
protected $isDataAccumulated = false;
|
||
|
|
||
|
/** @var bool $hasColorSet Gibt an ob bereits eine Farbe manuell gesetzt wurde */
|
||
|
protected $hasColorAssigned = false;
|
||
|
|
||
|
/**
|
||
|
* @param string $label
|
||
|
* @param array $data
|
||
|
* @param array $options
|
||
|
*/
|
||
|
public function __construct($label, $data, array $options = [])
|
||
|
{
|
||
|
// Ungültige Werte in leeres Array wandeln
|
||
|
if (!is_array($data)) {
|
||
|
$data = [];
|
||
|
}
|
||
|
|
||
|
$this->data = $data;
|
||
|
$this->label = $label;
|
||
|
$this->options = array_replace(self::$defaultOptions, $options);
|
||
|
|
||
|
$defaultColor = new Color(0, 0, 0, 0.1);
|
||
|
if (!is_object($this->options['borderColor'])) {
|
||
|
$this->options['borderColor'] = $defaultColor;
|
||
|
}
|
||
|
if (!is_object($this->options['backgroundColor'])) {
|
||
|
$this->options['backgroundColor'] = $defaultColor;
|
||
|
}
|
||
|
if (!is_object($this->options['pointBackgroundColor'])) {
|
||
|
$this->options['pointBackgroundColor'] = $defaultColor;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @return int
|
||
|
*/
|
||
|
public function getDataCount()
|
||
|
{
|
||
|
return count($this->data);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @return bool Wurde bereits eine Farbe gesetzt
|
||
|
*/
|
||
|
public function hasColorAssigned()
|
||
|
{
|
||
|
return $this->hasColorAssigned;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @return void
|
||
|
*/
|
||
|
public function accumulateData()
|
||
|
{
|
||
|
if ($this->isDataAccumulated === true) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
$sum = 0;
|
||
|
foreach ($this->data as $key => $value) {
|
||
|
$sum += (float)$value;
|
||
|
$this->data[$key] = $sum;
|
||
|
}
|
||
|
|
||
|
$this->isDataAccumulated = true;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param string $lineStyle
|
||
|
*
|
||
|
* @return void
|
||
|
*/
|
||
|
public function setLineStyle($lineStyle)
|
||
|
{
|
||
|
if (!in_array($lineStyle, self::$validLineStyles, true)) {
|
||
|
throw new InvalidArgumentException(sprintf(
|
||
|
'Line style "%s" is not valid.', $lineStyle
|
||
|
));
|
||
|
}
|
||
|
|
||
|
if ($lineStyle === self::LINE_STYLE_DOTTED) {
|
||
|
$this->options['borderDash'] = [1, 15];
|
||
|
$this->options['borderCapStyle'] = 'round';
|
||
|
}
|
||
|
if ($lineStyle === self::LINE_STYLE_DASHED) {
|
||
|
$this->options['borderDash'] = [15, 10];
|
||
|
$this->options['borderCapStyle'] = 'butt';
|
||
|
}
|
||
|
if ($lineStyle === self::LINE_STYLE_SOLID) {
|
||
|
$this->options['borderDash'] = [];
|
||
|
$this->options['borderCapStyle'] = 'butt';
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param Color $color
|
||
|
*
|
||
|
* @return void
|
||
|
*/
|
||
|
public function setColor(Color $color)
|
||
|
{
|
||
|
$borderColor = clone $color;
|
||
|
$backgroundColor = clone $color;
|
||
|
$pointBackgroundColor = clone $color;
|
||
|
|
||
|
$borderColor->setAlpha($this->getDefaultAlphaValue('borderColor'));
|
||
|
$backgroundColor->setAlpha($this->getDefaultAlphaValue('backgroundColor'));
|
||
|
$pointBackgroundColor->setAlpha($this->getDefaultAlphaValue('pointBackgroundColor'));
|
||
|
|
||
|
$this->options['borderColor'] = $borderColor;
|
||
|
$this->options['backgroundColor'] = $backgroundColor;
|
||
|
$this->options['pointBackgroundColor'] = $pointBackgroundColor;
|
||
|
|
||
|
$this->hasColorAssigned = true;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param int $red
|
||
|
* @param int $green
|
||
|
* @param int $blue
|
||
|
*
|
||
|
* @return void
|
||
|
*/
|
||
|
public function setColorByRgb($red, $green, $blue)
|
||
|
{
|
||
|
$this->setColor(new Color($red, $green, $blue, 1.0));
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param string $hexColor
|
||
|
*
|
||
|
* @return void
|
||
|
*/
|
||
|
public function setColorByHex($hexColor)
|
||
|
{
|
||
|
$hexColor = str_replace('#', '', $hexColor);
|
||
|
if (strlen($hexColor) !== 6) {
|
||
|
throw new InvalidArgumentException('Only full length hex values are supported.');
|
||
|
}
|
||
|
|
||
|
$parts = str_split($hexColor, 2);
|
||
|
$red = hexdec($parts[0]);
|
||
|
$green = hexdec($parts[1]);
|
||
|
$blue = hexdec($parts[2]);
|
||
|
|
||
|
$this->setColorByRgb($red, $green, $blue);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param string $colorName
|
||
|
*
|
||
|
* @return void
|
||
|
*/
|
||
|
public function setColorByName($colorName)
|
||
|
{
|
||
|
if (!isset(self::$colorMap[$colorName])) {
|
||
|
throw new InvalidArgumentException(sprintf(
|
||
|
'Color name "%s" is not valid.', $colorName
|
||
|
));
|
||
|
}
|
||
|
|
||
|
$rgb = self::$colorMap[$colorName];
|
||
|
$this->setColorByRgb(...$rgb);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Zufällige ID generieren; wird für Multiple Axes Config benötigt
|
||
|
*
|
||
|
* @see http://www.chartjs.org/docs/latest/axes/cartesian/#axis-id
|
||
|
*
|
||
|
* @return string
|
||
|
*/
|
||
|
public function generateYAxisId()
|
||
|
{
|
||
|
if (!isset($this->options['yAxisID'])) {
|
||
|
$this->options['yAxisID'] = uniqid('', false);
|
||
|
}
|
||
|
|
||
|
return $this->options['yAxisID'];
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @return array
|
||
|
*/
|
||
|
public function jsonSerialize()
|
||
|
{
|
||
|
return $this->toArray();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @return array
|
||
|
*/
|
||
|
public function toArray()
|
||
|
{
|
||
|
$result = $this->options;
|
||
|
$result['data'] = $this->data;
|
||
|
if (!empty($this->label)) {
|
||
|
$result['label'] = $this->label;
|
||
|
}
|
||
|
|
||
|
return $result;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param string $colorType
|
||
|
*
|
||
|
* @return float
|
||
|
*/
|
||
|
protected function getDefaultAlphaValue($colorType)
|
||
|
{
|
||
|
if (!isset(static::$defaultAlphaValues[$colorType])) {
|
||
|
return 1.0;
|
||
|
}
|
||
|
|
||
|
// Wichtig: static nicht self!
|
||
|
// Sonst hat Überschreiben von $defaultAlphaValues in abgeleiteten Klassen keine Auswirkung.
|
||
|
return static::$defaultAlphaValues[$colorType];
|
||
|
}
|
||
|
}
|