mirror of
https://github.com/salesagility/SuiteCRM.git
synced 2024-12-22 20:38:31 +00:00
1053 lines
36 KiB
PHP
1053 lines
36 KiB
PHP
<?php
|
|
/*
|
|
pDraw - class to manipulate data arrays
|
|
|
|
Version : 2.1.4
|
|
Made by : Jean-Damien POGOLOTTI
|
|
Last Update : 19/01/2014
|
|
|
|
This file can be distributed under the license you can find at :
|
|
|
|
http://www.pchart.net/license
|
|
|
|
You can find the whole class documentation on the pChart web site.
|
|
*/
|
|
|
|
/* Axis configuration */
|
|
define("AXIS_FORMAT_DEFAULT", 680001);
|
|
define("AXIS_FORMAT_TIME", 680002);
|
|
define("AXIS_FORMAT_DATE", 680003);
|
|
define("AXIS_FORMAT_METRIC", 680004);
|
|
define("AXIS_FORMAT_CURRENCY", 680005);
|
|
define("AXIS_FORMAT_TRAFFIC", 680006);
|
|
define("AXIS_FORMAT_CUSTOM", 680007);
|
|
|
|
/* Axis position */
|
|
define("AXIS_POSITION_LEFT", 681001);
|
|
define("AXIS_POSITION_RIGHT", 681002);
|
|
define("AXIS_POSITION_TOP", 681001);
|
|
define("AXIS_POSITION_BOTTOM", 681002);
|
|
|
|
/* Families of data points */
|
|
define("SERIE_SHAPE_FILLEDCIRCLE", 681011);
|
|
define("SERIE_SHAPE_FILLEDTRIANGLE", 681012);
|
|
define("SERIE_SHAPE_FILLEDSQUARE", 681013);
|
|
define("SERIE_SHAPE_FILLEDDIAMOND", 681017);
|
|
define("SERIE_SHAPE_CIRCLE", 681014);
|
|
define("SERIE_SHAPE_TRIANGLE", 681015);
|
|
define("SERIE_SHAPE_SQUARE", 681016);
|
|
define("SERIE_SHAPE_DIAMOND", 681018);
|
|
|
|
/* Axis position */
|
|
define("AXIS_X", 682001);
|
|
define("AXIS_Y", 682002);
|
|
|
|
/* Define value limits */
|
|
define("ABSOLUTE_MIN", -10000000000000);
|
|
define("ABSOLUTE_MAX", 10000000000000);
|
|
|
|
/* Replacement to the PHP NULL keyword */
|
|
define("VOID", 0.123456789);
|
|
|
|
/* Euro symbol for GD fonts */
|
|
define("EURO_SYMBOL", mb_convert_encoding("€", 'UTF-8', 'ISO-8859-1'));
|
|
|
|
/* pData class definition */
|
|
#[\AllowDynamicProperties]
|
|
class pData
|
|
{
|
|
public $Data;
|
|
|
|
public $Palette = array("0"=>array("R"=>188,"G"=>224,"B"=>46,"Alpha"=>100),
|
|
"1"=>array("R"=>224,"G"=>100,"B"=>46,"Alpha"=>100),
|
|
"2"=>array("R"=>224,"G"=>214,"B"=>46,"Alpha"=>100),
|
|
"3"=>array("R"=>46,"G"=>151,"B"=>224,"Alpha"=>100),
|
|
"4"=>array("R"=>176,"G"=>46,"B"=>224,"Alpha"=>100),
|
|
"5"=>array("R"=>224,"G"=>46,"B"=>117,"Alpha"=>100),
|
|
"6"=>array("R"=>92,"G"=>224,"B"=>46,"Alpha"=>100),
|
|
"7"=>array("R"=>224,"G"=>176,"B"=>46,"Alpha"=>100));
|
|
|
|
/* Class creator */
|
|
public function __construct()
|
|
{
|
|
$this->Data = "";
|
|
$this->Data["XAxisDisplay"] = AXIS_FORMAT_DEFAULT;
|
|
$this->Data["XAxisFormat"] = NULL;
|
|
$this->Data["XAxisName"] = NULL;
|
|
$this->Data["XAxisUnit"] = NULL;
|
|
$this->Data["Abscissa"] = NULL;
|
|
$this->Data["AbsicssaPosition"] = AXIS_POSITION_BOTTOM;
|
|
|
|
$this->Data["Axis"][0]["Display"] = AXIS_FORMAT_DEFAULT;
|
|
$this->Data["Axis"][0]["Position"] = AXIS_POSITION_LEFT;
|
|
$this->Data["Axis"][0]["Identity"] = AXIS_Y;
|
|
}
|
|
|
|
/* Add a single point or an array to the given serie */
|
|
public function addPoints($Values, $SerieName="Serie1")
|
|
{
|
|
if (!isset($this->Data["Series"][$SerieName])) {
|
|
$this->initialise($SerieName);
|
|
}
|
|
|
|
if (is_array($Values)) {
|
|
foreach ($Values as $Key => $Value) {
|
|
$this->Data["Series"][$SerieName]["Data"][] = $Value;
|
|
}
|
|
} else {
|
|
$this->Data["Series"][$SerieName]["Data"][] = $Values;
|
|
}
|
|
|
|
if ($Values != VOID) {
|
|
$StrippedData = $this->stripVOID($this->Data["Series"][$SerieName]["Data"]);
|
|
if (empty($StrippedData)) {
|
|
$this->Data["Series"][$SerieName]["Max"] = 0;
|
|
$this->Data["Series"][$SerieName]["Min"] =0;
|
|
return(0);
|
|
}
|
|
$this->Data["Series"][$SerieName]["Max"] = max($StrippedData);
|
|
$this->Data["Series"][$SerieName]["Min"] = min($StrippedData);
|
|
}
|
|
}
|
|
|
|
/* Strip VOID values */
|
|
public function stripVOID($Values)
|
|
{
|
|
if (!is_array($Values)) {
|
|
return(array());
|
|
}
|
|
$Result = array();
|
|
foreach ($Values as $Key => $Value) {
|
|
if ($Value != VOID) {
|
|
$Result[] = $Value;
|
|
}
|
|
}
|
|
return($Result);
|
|
}
|
|
|
|
/* Return the number of values contained in a given serie */
|
|
public function getSerieCount($Serie)
|
|
{
|
|
if (isset($this->Data["Series"][$Serie]["Data"])) {
|
|
return(is_countable($this->Data["Series"][$Serie]["Data"]) ? count($this->Data["Series"][$Serie]["Data"]) : 0);
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
/* Remove a serie from the pData object */
|
|
public function removeSerie($Series)
|
|
{
|
|
if (!is_array($Series)) {
|
|
$Series = $this->convertToArray($Series);
|
|
}
|
|
foreach ($Series as $Key => $Serie) {
|
|
if (isset($this->Data["Series"][$Serie])) {
|
|
unset($this->Data["Series"][$Serie]);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Return a value from given serie & index */
|
|
public function getValueAt($Serie, $Index=0)
|
|
{
|
|
if (isset($this->Data["Series"][$Serie]["Data"][$Index])) {
|
|
return($this->Data["Series"][$Serie]["Data"][$Index]);
|
|
}
|
|
return(null);
|
|
}
|
|
|
|
/* Return the values array */
|
|
public function getValues($Serie)
|
|
{
|
|
if (isset($this->Data["Series"][$Serie]["Data"])) {
|
|
return($this->Data["Series"][$Serie]["Data"]);
|
|
}
|
|
return(null);
|
|
}
|
|
|
|
/* Reverse the values in the given serie */
|
|
public function reverseSerie($Series)
|
|
{
|
|
if (!is_array($Series)) {
|
|
$Series = $this->convertToArray($Series);
|
|
}
|
|
foreach ($Series as $Key => $Serie) {
|
|
if (isset($this->Data["Series"][$Serie]["Data"])) {
|
|
$this->Data["Series"][$Serie]["Data"] = array_reverse($this->Data["Series"][$Serie]["Data"]);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Return the sum of the serie values */
|
|
public function getSum($Serie)
|
|
{
|
|
if (isset($this->Data["Series"][$Serie])) {
|
|
return(array_sum($this->Data["Series"][$Serie]["Data"]));
|
|
}
|
|
return(null);
|
|
}
|
|
|
|
/* Return the max value of a given serie */
|
|
public function getMax($Serie)
|
|
{
|
|
if (isset($this->Data["Series"][$Serie]["Max"])) {
|
|
return($this->Data["Series"][$Serie]["Max"]);
|
|
}
|
|
return(null);
|
|
}
|
|
|
|
/* Return the min value of a given serie */
|
|
public function getMin($Serie)
|
|
{
|
|
if (isset($this->Data["Series"][$Serie]["Min"])) {
|
|
return($this->Data["Series"][$Serie]["Min"]);
|
|
}
|
|
return(null);
|
|
}
|
|
|
|
/* Set the description of a given serie */
|
|
public function setSerieShape($Series, $Shape=SERIE_SHAPE_FILLEDCIRCLE)
|
|
{
|
|
if (!is_array($Series)) {
|
|
$Series = $this->convertToArray($Series);
|
|
}
|
|
foreach ($Series as $Key => $Serie) {
|
|
if (isset($this->Data["Series"][$Serie])) {
|
|
$this->Data["Series"][$Serie]["Shape"] = $Shape;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Set the description of a given serie */
|
|
public function setSerieDescription($Series, $Description="My serie")
|
|
{
|
|
if (!is_array($Series)) {
|
|
$Series = $this->convertToArray($Series);
|
|
}
|
|
foreach ($Series as $Key => $Serie) {
|
|
if (isset($this->Data["Series"][$Serie])) {
|
|
$this->Data["Series"][$Serie]["Description"] = $Description;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Set a serie as "drawable" while calling a rendering function */
|
|
public function setSerieDrawable($Series, $Drawable=true)
|
|
{
|
|
if (!is_array($Series)) {
|
|
$Series = $this->convertToArray($Series);
|
|
}
|
|
foreach ($Series as $Key => $Serie) {
|
|
if (isset($this->Data["Series"][$Serie])) {
|
|
$this->Data["Series"][$Serie]["isDrawable"] = $Drawable;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Set the icon associated to a given serie */
|
|
public function setSeriePicture($Series, $Picture=null)
|
|
{
|
|
if (!is_array($Series)) {
|
|
$Series = $this->convertToArray($Series);
|
|
}
|
|
foreach ($Series as $Key => $Serie) {
|
|
if (isset($this->Data["Series"][$Serie])) {
|
|
$this->Data["Series"][$Serie]["Picture"] = $Picture;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Set the name of the X Axis */
|
|
public function setXAxisName($Name)
|
|
{
|
|
$this->Data["XAxisName"] = $Name;
|
|
}
|
|
|
|
/* Set the display mode of the X Axis */
|
|
public function setXAxisDisplay($Mode, $Format=null)
|
|
{
|
|
$this->Data["XAxisDisplay"] = $Mode;
|
|
$this->Data["XAxisFormat"] = $Format;
|
|
}
|
|
|
|
/* Set the unit that will be displayed on the X axis */
|
|
public function setXAxisUnit($Unit)
|
|
{
|
|
$this->Data["XAxisUnit"] = $Unit;
|
|
}
|
|
|
|
/* Set the serie that will be used as abscissa */
|
|
public function setAbscissa($Serie)
|
|
{
|
|
if (isset($this->Data["Series"][$Serie])) {
|
|
$this->Data["Abscissa"] = $Serie;
|
|
}
|
|
}
|
|
|
|
public function setAbsicssaPosition($Position = AXIS_POSITION_BOTTOM)
|
|
{
|
|
$this->Data["AbsicssaPosition"] = $Position;
|
|
}
|
|
|
|
/* Set the name of the abscissa axis */
|
|
public function setAbscissaName($Name)
|
|
{
|
|
$this->Data["AbscissaName"] = $Name;
|
|
}
|
|
|
|
/* Create a scatter group specifyin X and Y data series */
|
|
public function setScatterSerie($SerieX, $SerieY, $ID=0)
|
|
{
|
|
if (isset($this->Data["Series"][$SerieX]) && isset($this->Data["Series"][$SerieY])) {
|
|
$this->initScatterSerie($ID);
|
|
$this->Data["ScatterSeries"][$ID]["X"] = $SerieX;
|
|
$this->Data["ScatterSeries"][$ID]["Y"] = $SerieY;
|
|
}
|
|
}
|
|
|
|
/* Set the shape of a given sctatter serie */
|
|
public function setScatterSerieShape($ID, $Shape=SERIE_SHAPE_FILLEDCIRCLE)
|
|
{
|
|
if (isset($this->Data["ScatterSeries"][$ID])) {
|
|
$this->Data["ScatterSeries"][$ID]["Shape"] = $Shape;
|
|
}
|
|
}
|
|
|
|
/* Set the description of a given scatter serie */
|
|
public function setScatterSerieDescription($ID, $Description="My serie")
|
|
{
|
|
if (isset($this->Data["ScatterSeries"][$ID])) {
|
|
$this->Data["ScatterSeries"][$ID]["Description"] = $Description;
|
|
}
|
|
}
|
|
|
|
/* Set the icon associated to a given scatter serie */
|
|
public function setScatterSeriePicture($ID, $Picture=null)
|
|
{
|
|
if (isset($this->Data["ScatterSeries"][$ID])) {
|
|
$this->Data["ScatterSeries"][$ID]["Picture"] = $Picture;
|
|
}
|
|
}
|
|
|
|
/* Set a scatter serie as "drawable" while calling a rendering function */
|
|
public function setScatterSerieDrawable($ID, $Drawable=true)
|
|
{
|
|
if (isset($this->Data["ScatterSeries"][$ID])) {
|
|
$this->Data["ScatterSeries"][$ID]["isDrawable"] = $Drawable;
|
|
}
|
|
}
|
|
|
|
/* Define if a scatter serie should be draw with ticks */
|
|
public function setScatterSerieTicks($ID, $Width=0)
|
|
{
|
|
if (isset($this->Data["ScatterSeries"][$ID])) {
|
|
$this->Data["ScatterSeries"][$ID]["Ticks"] = $Width;
|
|
}
|
|
}
|
|
|
|
/* Define if a scatter serie should be draw with a special weight */
|
|
public function setScatterSerieWeight($ID, $Weight=0)
|
|
{
|
|
if (isset($this->Data["ScatterSeries"][$ID])) {
|
|
$this->Data["ScatterSeries"][$ID]["Weight"] = $Weight;
|
|
}
|
|
}
|
|
|
|
/* Associate a color to a scatter serie */
|
|
public function setScatterSerieColor($ID, $Format)
|
|
{
|
|
$R = isset($Format["R"]) ? $Format["R"] : 0;
|
|
$G = isset($Format["G"]) ? $Format["G"] : 0;
|
|
$B = isset($Format["B"]) ? $Format["B"] : 0;
|
|
$Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : 100;
|
|
|
|
if (isset($this->Data["ScatterSeries"][$ID])) {
|
|
$this->Data["ScatterSeries"][$ID]["Color"]["R"] = $R;
|
|
$this->Data["ScatterSeries"][$ID]["Color"]["G"] = $G;
|
|
$this->Data["ScatterSeries"][$ID]["Color"]["B"] = $B;
|
|
$this->Data["ScatterSeries"][$ID]["Color"]["Alpha"] = $Alpha;
|
|
}
|
|
}
|
|
|
|
/* Compute the series limits for an individual and global point of view */
|
|
public function limits()
|
|
{
|
|
$GlobalMin = ABSOLUTE_MAX;
|
|
$GlobalMax = ABSOLUTE_MIN;
|
|
|
|
foreach ($this->Data["Series"] as $Key => $Value) {
|
|
if ($this->Data["Abscissa"] != $Key && $this->Data["Series"][$Key]["isDrawable"] == true) {
|
|
if ($GlobalMin > $this->Data["Series"][$Key]["Min"]) {
|
|
$GlobalMin = $this->Data["Series"][$Key]["Min"];
|
|
}
|
|
if ($GlobalMax < $this->Data["Series"][$Key]["Max"]) {
|
|
$GlobalMax = $this->Data["Series"][$Key]["Max"];
|
|
}
|
|
}
|
|
}
|
|
$this->Data["Min"] = $GlobalMin;
|
|
$this->Data["Max"] = $GlobalMax;
|
|
|
|
return(array($GlobalMin,$GlobalMax));
|
|
}
|
|
|
|
/* Mark all series as drawable */
|
|
public function drawAll()
|
|
{
|
|
foreach ($this->Data["Series"] as $Key => $Value) {
|
|
if ($this->Data["Abscissa"] != $Key) {
|
|
$this->Data["Series"][$Key]["isDrawable"]=true;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Return the average value of the given serie */
|
|
public function getSerieAverage($Serie)
|
|
{
|
|
if (isset($this->Data["Series"][$Serie])) {
|
|
$SerieData = $this->stripVOID($this->Data["Series"][$Serie]["Data"]);
|
|
return(array_sum($SerieData)/(is_countable($SerieData) ? count($SerieData) : 0));
|
|
}
|
|
return(null);
|
|
}
|
|
|
|
/* Return the geometric mean of the given serie */
|
|
public function getGeometricMean($Serie)
|
|
{
|
|
if (isset($this->Data["Series"][$Serie])) {
|
|
$SerieData = $this->stripVOID($this->Data["Series"][$Serie]["Data"]);
|
|
$Seriesum = 1;
|
|
foreach ($SerieData as $Key => $Value) {
|
|
$Seriesum = $Seriesum * $Value;
|
|
}
|
|
return(pow($Seriesum, 1/(is_countable($SerieData) ? count($SerieData) : 0)));
|
|
}
|
|
return(null);
|
|
}
|
|
|
|
/* Return the harmonic mean of the given serie */
|
|
public function getHarmonicMean($Serie)
|
|
{
|
|
if (isset($this->Data["Series"][$Serie])) {
|
|
$SerieData = $this->stripVOID($this->Data["Series"][$Serie]["Data"]);
|
|
$Seriesum = 0;
|
|
foreach ($SerieData as $Key => $Value) {
|
|
$Seriesum = $Seriesum + 1/$Value;
|
|
}
|
|
return((is_countable($SerieData) ? count($SerieData) : 0)/$Seriesum);
|
|
}
|
|
return(null);
|
|
}
|
|
|
|
/* Return the standard deviation of the given serie */
|
|
public function getStandardDeviation($Serie)
|
|
{
|
|
if (isset($this->Data["Series"][$Serie])) {
|
|
$Average = $this->getSerieAverage($Serie);
|
|
$SerieData = $this->stripVOID($this->Data["Series"][$Serie]["Data"]);
|
|
|
|
$DeviationSum = 0;
|
|
foreach ($SerieData as $Key => $Value) {
|
|
$DeviationSum = $DeviationSum + ($Value-$Average)*($Value-$Average);
|
|
}
|
|
|
|
$Deviation = sqrt($DeviationSum/(is_countable($SerieData) ? count($SerieData) : 0));
|
|
|
|
return($Deviation);
|
|
}
|
|
return(null);
|
|
}
|
|
|
|
/* Return the Coefficient of variation of the given serie */
|
|
public function getCoefficientOfVariation($Serie)
|
|
{
|
|
if (isset($this->Data["Series"][$Serie])) {
|
|
$Average = $this->getSerieAverage($Serie);
|
|
$StandardDeviation = $this->getStandardDeviation($Serie);
|
|
|
|
if ($StandardDeviation != 0) {
|
|
return($StandardDeviation/$Average);
|
|
}
|
|
return(null);
|
|
}
|
|
return(null);
|
|
}
|
|
|
|
/* Return the median value of the given serie */
|
|
public function getSerieMedian($Serie)
|
|
{
|
|
if (isset($this->Data["Series"][$Serie])) {
|
|
$SerieData = $this->stripVOID($this->Data["Series"][$Serie]["Data"]);
|
|
sort($SerieData);
|
|
$SerieCenter = floor((is_countable($SerieData) ? count($SerieData) : 0)/2);
|
|
|
|
if (isset($SerieData[$SerieCenter])) {
|
|
return($SerieData[$SerieCenter]);
|
|
}
|
|
return(null);
|
|
}
|
|
return(null);
|
|
}
|
|
|
|
/* Return the x th percentil of the given serie */
|
|
public function getSeriePercentile($Serie="Serie1", $Percentil=95)
|
|
{
|
|
if (!isset($this->Data["Series"][$Serie]["Data"])) {
|
|
return(null);
|
|
}
|
|
|
|
$Values = (is_countable($this->Data["Series"][$Serie]["Data"]) ? count($this->Data["Series"][$Serie]["Data"]) : 0)-1;
|
|
if ($Values < 0) {
|
|
$Values = 0;
|
|
}
|
|
|
|
$PercentilID = floor(($Values/100)*$Percentil+.5);
|
|
$SortedValues = $this->Data["Series"][$Serie]["Data"];
|
|
sort($SortedValues);
|
|
|
|
if (is_numeric($SortedValues[$PercentilID])) {
|
|
return($SortedValues[$PercentilID]);
|
|
}
|
|
return(null);
|
|
}
|
|
|
|
/* Add random values to a given serie */
|
|
public function addRandomValues($SerieName="Serie1", $Options="")
|
|
{
|
|
$Values = isset($Options["Values"]) ? $Options["Values"] : 20;
|
|
$Min = isset($Options["Min"]) ? $Options["Min"] : 0;
|
|
$Max = isset($Options["Max"]) ? $Options["Max"] : 100;
|
|
$withFloat = isset($Options["withFloat"]) ? $Options["withFloat"] : false;
|
|
|
|
for ($i=0;$i<=$Values;$i++) {
|
|
if ($withFloat) {
|
|
$Value = mt_rand($Min*100, $Max*100)/100;
|
|
} else {
|
|
$Value = mt_rand($Min, $Max);
|
|
}
|
|
$this->addPoints($Value, $SerieName);
|
|
}
|
|
}
|
|
|
|
/* Test if we have valid data */
|
|
public function containsData()
|
|
{
|
|
if (!isset($this->Data["Series"])) {
|
|
return(false);
|
|
}
|
|
|
|
$Result = false;
|
|
foreach ($this->Data["Series"] as $Key => $Value) {
|
|
if ($this->Data["Abscissa"] != $Key && $this->Data["Series"][$Key]["isDrawable"]==true) {
|
|
$Result=true;
|
|
}
|
|
}
|
|
return($Result);
|
|
}
|
|
|
|
/* Set the display mode of an Axis */
|
|
public function setAxisDisplay($AxisID, $Mode=AXIS_FORMAT_DEFAULT, $Format=null)
|
|
{
|
|
if (isset($this->Data["Axis"][$AxisID])) {
|
|
$this->Data["Axis"][$AxisID]["Display"] = $Mode;
|
|
if ($Format != null) {
|
|
$this->Data["Axis"][$AxisID]["Format"] = $Format;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Set the position of an Axis */
|
|
public function setAxisPosition($AxisID, $Position=AXIS_POSITION_LEFT)
|
|
{
|
|
if (isset($this->Data["Axis"][$AxisID])) {
|
|
$this->Data["Axis"][$AxisID]["Position"] = $Position;
|
|
}
|
|
}
|
|
|
|
/* Associate an unit to an axis */
|
|
public function setAxisUnit($AxisID, $Unit)
|
|
{
|
|
if (isset($this->Data["Axis"][$AxisID])) {
|
|
$this->Data["Axis"][$AxisID]["Unit"] = $Unit;
|
|
}
|
|
}
|
|
|
|
/* Associate a name to an axis */
|
|
public function setAxisName($AxisID, $Name)
|
|
{
|
|
if (isset($this->Data["Axis"][$AxisID])) {
|
|
$this->Data["Axis"][$AxisID]["Name"] = $Name;
|
|
}
|
|
}
|
|
|
|
/* Associate a color to an axis */
|
|
public function setAxisColor($AxisID, $Format)
|
|
{
|
|
$R = isset($Format["R"]) ? $Format["R"] : 0;
|
|
$G = isset($Format["G"]) ? $Format["G"] : 0;
|
|
$B = isset($Format["B"]) ? $Format["B"] : 0;
|
|
$Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : 100;
|
|
|
|
if (isset($this->Data["Axis"][$AxisID])) {
|
|
$this->Data["Axis"][$AxisID]["Color"]["R"] = $R;
|
|
$this->Data["Axis"][$AxisID]["Color"]["G"] = $G;
|
|
$this->Data["Axis"][$AxisID]["Color"]["B"] = $B;
|
|
$this->Data["Axis"][$AxisID]["Color"]["Alpha"] = $Alpha;
|
|
}
|
|
}
|
|
|
|
|
|
/* Design an axis as X or Y member */
|
|
public function setAxisXY($AxisID, $Identity=AXIS_Y)
|
|
{
|
|
if (isset($this->Data["Axis"][$AxisID])) {
|
|
$this->Data["Axis"][$AxisID]["Identity"] = $Identity;
|
|
}
|
|
}
|
|
|
|
/* Associate one data serie with one axis */
|
|
public function setSerieOnAxis($Series, $AxisID)
|
|
{
|
|
if (!is_array($Series)) {
|
|
$Series = $this->convertToArray($Series);
|
|
}
|
|
foreach ($Series as $Key => $Serie) {
|
|
$PreviousAxis = $this->Data["Series"][$Serie]["Axis"];
|
|
|
|
/* Create missing axis */
|
|
if (!isset($this->Data["Axis"][$AxisID])) {
|
|
$this->Data["Axis"][$AxisID]["Position"] = AXIS_POSITION_LEFT;
|
|
$this->Data["Axis"][$AxisID]["Identity"] = AXIS_Y;
|
|
}
|
|
|
|
$this->Data["Series"][$Serie]["Axis"] = $AxisID;
|
|
|
|
/* Cleanup unused axis */
|
|
$Found = false;
|
|
foreach ($this->Data["Series"] as $SerieName => $Values) {
|
|
if ($Values["Axis"] == $PreviousAxis) {
|
|
$Found = true;
|
|
}
|
|
}
|
|
if (!$Found) {
|
|
unset($this->Data["Axis"][$PreviousAxis]);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Define if a serie should be draw with ticks */
|
|
public function setSerieTicks($Series, $Width=0)
|
|
{
|
|
if (!is_array($Series)) {
|
|
$Series = $this->convertToArray($Series);
|
|
}
|
|
foreach ($Series as $Key => $Serie) {
|
|
if (isset($this->Data["Series"][$Serie])) {
|
|
$this->Data["Series"][$Serie]["Ticks"] = $Width;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Define if a serie should be draw with a special weight */
|
|
public function setSerieWeight($Series, $Weight=0)
|
|
{
|
|
if (!is_array($Series)) {
|
|
$Series = $this->convertToArray($Series);
|
|
}
|
|
foreach ($Series as $Key => $Serie) {
|
|
if (isset($this->Data["Series"][$Serie])) {
|
|
$this->Data["Series"][$Serie]["Weight"] = $Weight;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Returns the palette of the given serie */
|
|
public function getSeriePalette($Serie)
|
|
{
|
|
if (!isset($this->Data["Series"][$Serie])) {
|
|
return(null);
|
|
}
|
|
|
|
$Result = "";
|
|
$Result["R"] = $this->Data["Series"][$Serie]["Color"]["R"];
|
|
$Result["G"] = $this->Data["Series"][$Serie]["Color"]["G"];
|
|
$Result["B"] = $this->Data["Series"][$Serie]["Color"]["B"];
|
|
$Result["Alpha"] = $this->Data["Series"][$Serie]["Color"]["Alpha"];
|
|
|
|
return($Result);
|
|
}
|
|
|
|
/* Set the color of one serie */
|
|
public function setPalette($Series, $Format=null)
|
|
{
|
|
if (!is_array($Series)) {
|
|
$Series = $this->convertToArray($Series);
|
|
}
|
|
|
|
foreach ($Series as $Key => $Serie) {
|
|
$R = isset($Format["R"]) ? $Format["R"] : 0;
|
|
$G = isset($Format["G"]) ? $Format["G"] : 0;
|
|
$B = isset($Format["B"]) ? $Format["B"] : 0;
|
|
$Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : 100;
|
|
|
|
if (isset($this->Data["Series"][$Serie])) {
|
|
$OldR = $this->Data["Series"][$Serie]["Color"]["R"];
|
|
$OldG = $this->Data["Series"][$Serie]["Color"]["G"];
|
|
$OldB = $this->Data["Series"][$Serie]["Color"]["B"];
|
|
$this->Data["Series"][$Serie]["Color"]["R"] = $R;
|
|
$this->Data["Series"][$Serie]["Color"]["G"] = $G;
|
|
$this->Data["Series"][$Serie]["Color"]["B"] = $B;
|
|
$this->Data["Series"][$Serie]["Color"]["Alpha"] = $Alpha;
|
|
|
|
/* Do reverse processing on the internal palette array */
|
|
foreach ($this->Palette as $Key => $Value) {
|
|
if ($Value["R"] == $OldR && $Value["G"] == $OldG && $Value["B"] == $OldB) {
|
|
$this->Palette[$Key]["R"] = $R;
|
|
$this->Palette[$Key]["G"] = $G;
|
|
$this->Palette[$Key]["B"] = $B;
|
|
$this->Palette[$Key]["Alpha"] = $Alpha;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Load a palette file */
|
|
public function loadPalette($FileName, $Overwrite=false)
|
|
{
|
|
if (!file_exists($FileName)) {
|
|
return(-1);
|
|
}
|
|
if ($Overwrite) {
|
|
$this->Palette = "";
|
|
}
|
|
|
|
$fileHandle = @fopen($FileName, 'rb');
|
|
if (!$fileHandle) {
|
|
return(-1);
|
|
}
|
|
while (!feof($fileHandle)) {
|
|
$buffer = fgets($fileHandle, 4096);
|
|
if (preg_match("/,/", $buffer)) {
|
|
list($R, $G, $B, $Alpha) = preg_split("/,/", $buffer);
|
|
if ($this->Palette == "") {
|
|
$ID = 0;
|
|
} else {
|
|
$ID = count($this->Palette);
|
|
}
|
|
$this->Palette[$ID] = array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha);
|
|
}
|
|
}
|
|
fclose($fileHandle);
|
|
|
|
/* Apply changes to current series */
|
|
$ID = 0;
|
|
if (isset($this->Data["Series"])) {
|
|
foreach ($this->Data["Series"] as $Key => $Value) {
|
|
if (!isset($this->Palette[$ID])) {
|
|
$this->Data["Series"][$Key]["Color"] = array("R"=>0,"G"=>0,"B"=>0,"Alpha"=>0);
|
|
} else {
|
|
$this->Data["Series"][$Key]["Color"] = $this->Palette[$ID];
|
|
}
|
|
$ID++;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Initialise a given scatter serie */
|
|
public function initScatterSerie($ID)
|
|
{
|
|
if (isset($this->Data["ScatterSeries"][$ID])) {
|
|
return(0);
|
|
}
|
|
|
|
$this->Data["ScatterSeries"][$ID]["Description"] = "Scatter ".$ID;
|
|
$this->Data["ScatterSeries"][$ID]["isDrawable"] = true;
|
|
$this->Data["ScatterSeries"][$ID]["Picture"] = null;
|
|
$this->Data["ScatterSeries"][$ID]["Ticks"] = 0;
|
|
$this->Data["ScatterSeries"][$ID]["Weight"] = 0;
|
|
|
|
if (isset($this->Palette[$ID])) {
|
|
$this->Data["ScatterSeries"][$ID]["Color"] = $this->Palette[$ID];
|
|
} else {
|
|
$this->Data["ScatterSeries"][$ID]["Color"]["R"] = mt_rand(0, 255);
|
|
$this->Data["ScatterSeries"][$ID]["Color"]["G"] = mt_rand(0, 255);
|
|
$this->Data["ScatterSeries"][$ID]["Color"]["B"] = mt_rand(0, 255);
|
|
$this->Data["ScatterSeries"][$ID]["Color"]["Alpha"] = 100;
|
|
}
|
|
}
|
|
|
|
/* Initialise a given serie */
|
|
public function initialise($Serie)
|
|
{
|
|
if (isset($this->Data["Series"])) {
|
|
$ID = is_countable($this->Data["Series"]) ? count($this->Data["Series"]) : 0;
|
|
} else {
|
|
$ID = 0;
|
|
}
|
|
|
|
$this->Data["Series"][$Serie]["Description"] = $Serie;
|
|
$this->Data["Series"][$Serie]["isDrawable"] = true;
|
|
$this->Data["Series"][$Serie]["Picture"] = null;
|
|
$this->Data["Series"][$Serie]["Max"] = null;
|
|
$this->Data["Series"][$Serie]["Min"] = null;
|
|
$this->Data["Series"][$Serie]["Axis"] = 0;
|
|
$this->Data["Series"][$Serie]["Ticks"] = 0;
|
|
$this->Data["Series"][$Serie]["Weight"] = 0;
|
|
$this->Data["Series"][$Serie]["Shape"] = SERIE_SHAPE_FILLEDCIRCLE;
|
|
|
|
if (isset($this->Palette[$ID])) {
|
|
$this->Data["Series"][$Serie]["Color"] = $this->Palette[$ID];
|
|
} else {
|
|
$this->Data["Series"][$Serie]["Color"]["R"] = mt_rand(0, 255);
|
|
$this->Data["Series"][$Serie]["Color"]["G"] = mt_rand(0, 255);
|
|
$this->Data["Series"][$Serie]["Color"]["B"] = mt_rand(0, 255);
|
|
$this->Data["Series"][$Serie]["Color"]["Alpha"] = 100;
|
|
}
|
|
}
|
|
|
|
public function normalize($NormalizationFactor=100, $UnitChange=null, $Round=1)
|
|
{
|
|
$Abscissa = $this->Data["Abscissa"];
|
|
|
|
$SelectedSeries = "";
|
|
$MaxVal = 0;
|
|
foreach ($this->Data["Axis"] as $AxisID => $Axis) {
|
|
if ($UnitChange != null) {
|
|
$this->Data["Axis"][$AxisID]["Unit"] = $UnitChange;
|
|
}
|
|
|
|
foreach ($this->Data["Series"] as $SerieName => $Serie) {
|
|
if ($Serie["Axis"] == $AxisID && $Serie["isDrawable"] == true && $SerieName != $Abscissa) {
|
|
$SelectedSeries[$SerieName] = $SerieName;
|
|
|
|
$count = is_countable($Serie["Data"]) ? count($Serie["Data"]) : 0;
|
|
|
|
if ($count > $MaxVal) {
|
|
$MaxVal = $count;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
for ($i=0;$i<=$MaxVal-1;$i++) {
|
|
$Factor = 0;
|
|
foreach ($SelectedSeries as $Key => $SerieName) {
|
|
$Value = $this->Data["Series"][$SerieName]["Data"][$i];
|
|
if ($Value != VOID) {
|
|
$Factor = $Factor + abs($Value);
|
|
}
|
|
}
|
|
|
|
if ($Factor != 0) {
|
|
$Factor = $NormalizationFactor / $Factor;
|
|
|
|
foreach ($SelectedSeries as $Key => $SerieName) {
|
|
$Value = $this->Data["Series"][$SerieName]["Data"][$i];
|
|
|
|
if ($Value != VOID && $Factor != $NormalizationFactor) {
|
|
$this->Data["Series"][$SerieName]["Data"][$i] = round(abs($Value)*$Factor, $Round);
|
|
} elseif ($Value == VOID || $Value == 0) {
|
|
$this->Data["Series"][$SerieName]["Data"][$i] = VOID;
|
|
} elseif ($Factor == $NormalizationFactor) {
|
|
$this->Data["Series"][$SerieName]["Data"][$i] = $NormalizationFactor;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
foreach ($SelectedSeries as $Key => $SerieName) {
|
|
$this->Data["Series"][$SerieName]["Max"] = max($this->stripVOID($this->Data["Series"][$SerieName]["Data"]));
|
|
$this->Data["Series"][$SerieName]["Min"] = min($this->stripVOID($this->Data["Series"][$SerieName]["Data"]));
|
|
}
|
|
}
|
|
|
|
/* Load data from a CSV (or similar) data source */
|
|
public function importFromCSV($FileName, $Options="")
|
|
{
|
|
$Delimiter = isset($Options["Delimiter"]) ? $Options["Delimiter"] : ",";
|
|
$GotHeader = isset($Options["GotHeader"]) ? $Options["GotHeader"] : false;
|
|
$SkipColumns = isset($Options["SkipColumns"]) ? $Options["SkipColumns"] : array(-1);
|
|
$DefaultSerieName = isset($Options["DefaultSerieName"]) ? $Options["DefaultSerieName"] : "Serie";
|
|
|
|
$Handle = @fopen($FileName, 'rb');
|
|
if ($Handle) {
|
|
$HeaderParsed = false;
|
|
$SerieNames = "";
|
|
while (!feof($Handle)) {
|
|
$Buffer = fgets($Handle, 4096);
|
|
$Buffer = str_replace(chr(10), "", $Buffer);
|
|
$Buffer = str_replace(chr(13), "", $Buffer);
|
|
$Values = preg_split("/".$Delimiter."/", $Buffer);
|
|
|
|
if ($Buffer != "") {
|
|
if ($GotHeader && !$HeaderParsed) {
|
|
foreach ($Values as $Key => $Name) {
|
|
if (!in_array($Key, $SkipColumns)) {
|
|
$SerieNames[$Key] = $Name;
|
|
}
|
|
}
|
|
$HeaderParsed = true;
|
|
} else {
|
|
if ($SerieNames == "") {
|
|
foreach ($Values as $Key => $Name) {
|
|
if (!in_array($Key, $SkipColumns)) {
|
|
$SerieNames[$Key] = $DefaultSerieName.$Key;
|
|
}
|
|
}
|
|
}
|
|
foreach ($Values as $Key => $Value) {
|
|
if (!in_array($Key, $SkipColumns)) {
|
|
$this->addPoints($Value, $SerieNames[$Key]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
fclose($Handle);
|
|
}
|
|
}
|
|
|
|
/* Create a dataset based on a formula */
|
|
public function createFunctionSerie($SerieName, $Formula="", $Options="")
|
|
{
|
|
$return = '';
|
|
$MinX = isset($Options["MinX"]) ? $Options["MinX"] : -10;
|
|
$MaxX = isset($Options["MaxX"]) ? $Options["MaxX"] : 10;
|
|
$XStep = isset($Options["XStep"]) ? $Options["XStep"] : 1;
|
|
$AutoDescription = isset($Options["AutoDescription"]) ? $Options["AutoDescription"] : false;
|
|
$RecordAbscissa = isset($Options["RecordAbscissa"]) ? $Options["RecordAbscissa"] : false;
|
|
$AbscissaSerie = isset($Options["AbscissaSerie"]) ? $Options["AbscissaSerie"] : "Abscissa";
|
|
|
|
if ($Formula == "") {
|
|
return(0);
|
|
}
|
|
|
|
$Result = [];
|
|
$Abscissa = [];
|
|
for ($i=$MinX; $i<=$MaxX; $i=$i+$XStep) {
|
|
$Expression = "\$return = '!'.(".str_replace("z", $i, (string) $Formula).");";
|
|
if (@eval($Expression) === false) {
|
|
$return = VOID;
|
|
}
|
|
if ($return == "!") {
|
|
$return = VOID;
|
|
} else {
|
|
$return = $this->right($return, strlen((string) $return)-1);
|
|
}
|
|
if ($return == "NAN") {
|
|
$return = VOID;
|
|
}
|
|
if ($return == "INF") {
|
|
$return = VOID;
|
|
}
|
|
if ($return == "-INF") {
|
|
$return = VOID;
|
|
}
|
|
|
|
$Abscissa[] = $i;
|
|
$Result[] = $return;
|
|
}
|
|
|
|
$this->addPoints($Result, $SerieName);
|
|
if ($AutoDescription) {
|
|
$this->setSerieDescription($SerieName, $Formula);
|
|
}
|
|
if ($RecordAbscissa) {
|
|
$this->addPoints($Abscissa, $AbscissaSerie);
|
|
}
|
|
}
|
|
|
|
public function negateValues($Series)
|
|
{
|
|
if (!is_array($Series)) {
|
|
$Series = $this->convertToArray($Series);
|
|
}
|
|
foreach ($Series as $Key => $SerieName) {
|
|
if (isset($this->Data["Series"][$SerieName])) {
|
|
$Data = [];
|
|
foreach ($this->Data["Series"][$SerieName]["Data"] as $Key => $Value) {
|
|
if ($Value == VOID) {
|
|
$Data[] = VOID;
|
|
} else {
|
|
$Data[] = -$Value;
|
|
}
|
|
}
|
|
$this->Data["Series"][$SerieName]["Data"] = $Data;
|
|
|
|
$this->Data["Series"][$SerieName]["Max"] = max($this->stripVOID($this->Data["Series"][$SerieName]["Data"]));
|
|
$this->Data["Series"][$SerieName]["Min"] = min($this->stripVOID($this->Data["Series"][$SerieName]["Data"]));
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Return the data & configuration of the series */
|
|
public function getData()
|
|
{
|
|
return($this->Data);
|
|
}
|
|
|
|
/* Save a palette element */
|
|
public function savePalette($ID, $Color)
|
|
{
|
|
$this->Palette[$ID] = $Color;
|
|
}
|
|
|
|
/* Return the palette of the series */
|
|
public function getPalette()
|
|
{
|
|
return($this->Palette);
|
|
}
|
|
|
|
/* Called by the scaling algorithm to save the config */
|
|
public function saveAxisConfig($Axis)
|
|
{
|
|
$this->Data["Axis"]=$Axis;
|
|
}
|
|
|
|
/* Save the Y Margin if set */
|
|
public function saveYMargin($Value)
|
|
{
|
|
$this->Data["YMargin"]=$Value;
|
|
}
|
|
|
|
/* Save extended configuration to the pData object */
|
|
public function saveExtendedData($Tag, $Values)
|
|
{
|
|
$this->Data["Extended"][$Tag]=$Values;
|
|
}
|
|
|
|
/* Called by the scaling algorithm to save the orientation of the scale */
|
|
public function saveOrientation($Orientation)
|
|
{
|
|
$this->Data["Orientation"]=$Orientation;
|
|
}
|
|
|
|
/* Convert a string to a single elements array */
|
|
public function convertToArray($Value)
|
|
{
|
|
$Values = [];
|
|
$Values[] = $Value;
|
|
return($Values);
|
|
}
|
|
|
|
/* Class string wrapper */
|
|
public function __toString()
|
|
{
|
|
return("pData object.");
|
|
}
|
|
|
|
public function left($value, $NbChar)
|
|
{
|
|
return substr((string) $value, 0, $NbChar);
|
|
}
|
|
public function right($value, $NbChar)
|
|
{
|
|
return substr((string) $value, strlen((string) $value)-$NbChar, $NbChar);
|
|
}
|
|
public function mid($value, $Depart, $NbChar)
|
|
{
|
|
return substr((string) $value, $Depart-1, $NbChar);
|
|
}
|
|
}
|