Split all files mith multiple classes into multiple files
This commit is contained in:
492
src/GraphAxisGeneral.php
Normal file
492
src/GraphAxisGeneral.php
Normal file
@@ -0,0 +1,492 @@
|
||||
<?php
|
||||
|
||||
/** DomFramework
|
||||
* @package domframework
|
||||
* @author Dominique Fournier <dominique@fournier38.fr>
|
||||
* @license BSD
|
||||
*/
|
||||
|
||||
namespace Domframework;
|
||||
|
||||
/** The general axis management */
|
||||
class GraphAxisGeneral
|
||||
{
|
||||
/** The min value of the axis. Do not use it if the axis is composed of labels
|
||||
*/
|
||||
protected $min = null;
|
||||
|
||||
/** The max value of the axis. Do not use it if the axis is composed of labels
|
||||
*/
|
||||
protected $max = null;
|
||||
|
||||
/** The label max to display
|
||||
*/
|
||||
protected $labelMax;
|
||||
|
||||
/** The label min to display
|
||||
*/
|
||||
protected $labelMin;
|
||||
|
||||
/** The data displayed as values on the axis
|
||||
*/
|
||||
protected $data;
|
||||
|
||||
/** Set if the axis is only numerical (true) or is composed of labels (false)
|
||||
*/
|
||||
protected $numerical;
|
||||
|
||||
/** The minimum bottom position in pixels. Used on vertical axis
|
||||
*/
|
||||
protected $bottom;
|
||||
|
||||
/** The maximum top position in pixels. Used on vertical axis
|
||||
*/
|
||||
protected $top;
|
||||
|
||||
/** The minimum left position in pixels. Used on horizontal axis
|
||||
*/
|
||||
protected $left;
|
||||
|
||||
/** The maximum right position in pixels. Used on horizontal axis
|
||||
*/
|
||||
protected $right;
|
||||
|
||||
/** The fontfile to write the labels
|
||||
*/
|
||||
protected $fontfile;
|
||||
|
||||
/** The fontsize to write the labels
|
||||
*/
|
||||
protected $fontsize = 8;
|
||||
|
||||
/** Axis color
|
||||
*/
|
||||
protected $axisColor;
|
||||
|
||||
/** Grid color on the axis
|
||||
* Can be set to null or "transparent" to not display the grid
|
||||
*/
|
||||
protected $gridColor;
|
||||
|
||||
/** Set the min value of the axis if the parameter is provided.
|
||||
* Get the min value of the axis if the parameter is not provided
|
||||
* @param integer|null $min The min value of the axis
|
||||
*/
|
||||
public function min($min = null)
|
||||
{
|
||||
if ($min === null) {
|
||||
return $this->min;
|
||||
}
|
||||
if (! is_numeric($min)) {
|
||||
throw new \Exception(dgettext(
|
||||
"domframework",
|
||||
"Invalid min provided to graph Axis"
|
||||
) . " " . get_class($this), 406);
|
||||
}
|
||||
$this->min = $min;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/** Set the max value of the axis if the parameter is provided.
|
||||
* Get the max value of the axis if the parameter is not provided
|
||||
* @param integer|null $max The max value of the axis
|
||||
*/
|
||||
public function max($max = null)
|
||||
{
|
||||
if ($max === null) {
|
||||
return $this->max;
|
||||
}
|
||||
if (! is_numeric($max)) {
|
||||
throw new \Exception(dgettext(
|
||||
"domframework",
|
||||
"Invalid max provided to graph Axis"
|
||||
) . " " . get_class($this), 406);
|
||||
}
|
||||
$this->max = $max;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/** Set the data of the axis if the parameter is provided.
|
||||
* Get the data of the axis if the parameter is not provided
|
||||
* @param array|null $data The data of the axis
|
||||
*/
|
||||
public function data($data = null)
|
||||
{
|
||||
if ($data === null) {
|
||||
return $this->data;
|
||||
}
|
||||
if (! is_array($data)) {
|
||||
throw new \Exception(dgettext(
|
||||
"domframework",
|
||||
"Invalid data provided to graph Axis"
|
||||
) . " " . get_class($this), 406);
|
||||
}
|
||||
$this->data = $data;
|
||||
if ($this->numerical === null) {
|
||||
// Look if the provided data are only numerical. Then define the numerical
|
||||
// property
|
||||
foreach ($data as $d) {
|
||||
if (! is_numeric($d)) {
|
||||
$this->numerical = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ($this->numerical === null) {
|
||||
$this->numerical = true;
|
||||
}
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/** Set if the axis is numerical or composed of labels if the parameter is
|
||||
* provided.
|
||||
* Get if the axis is numerical if the parameter is not provided
|
||||
* @param boolean|null $numerical the axis is numerical
|
||||
*/
|
||||
public function numerical($numerical = null)
|
||||
{
|
||||
if ($numerical === null) {
|
||||
return $this->numerical;
|
||||
}
|
||||
if (! is_bool($numerical)) {
|
||||
throw new \Exception(dgettext(
|
||||
"domframework",
|
||||
"Invalid numerical parameter provided to graph Axis"
|
||||
) . " " .
|
||||
get_class($this), 406);
|
||||
}
|
||||
$this->numerical = $numerical;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/** Set the bottom position of the axis if the parameter is provided.
|
||||
* Get the bottom position of the axis if the parameter is not provided
|
||||
* @param integer|null $bottom The bottom position of the axis
|
||||
*/
|
||||
public function bottom($bottom = null)
|
||||
{
|
||||
if ($bottom === null) {
|
||||
return $this->bottom;
|
||||
}
|
||||
if (! is_integer($bottom) || $bottom < 0 || $bottom > 5000) {
|
||||
throw new \Exception(dgettext(
|
||||
"domframework",
|
||||
"Invalid bottom provided to graph Axis"
|
||||
) . " " . get_class($this), 406);
|
||||
}
|
||||
$this->bottom = $bottom;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/** Set the top position of the axis if the parameter is provided.
|
||||
* Get the top position of the axis if the parameter is not provided
|
||||
* @param integer|null $top The top position of the axis
|
||||
*/
|
||||
public function top($top = null)
|
||||
{
|
||||
if ($top === null) {
|
||||
return $this->top;
|
||||
}
|
||||
if (! is_integer($top) || $top < 0 || $top > 5000) {
|
||||
throw new \Exception(dgettext(
|
||||
"domframework",
|
||||
"Invalid top provided to graph Axis"
|
||||
) . " " . get_class($this), 406);
|
||||
}
|
||||
$this->top = $top;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/** Set the left position of the axis if the parameter is provided.
|
||||
* Get the left position of the axis if the parameter is not provided
|
||||
* @param integer|null $left The left position of the axis
|
||||
*/
|
||||
public function left($left = null)
|
||||
{
|
||||
if ($left === null) {
|
||||
return $this->left;
|
||||
}
|
||||
if (! is_integer($left) || $left < 0 || $left > 5000) {
|
||||
throw new \Exception(dgettext(
|
||||
"domframework",
|
||||
"Invalid left provided to graph Axis"
|
||||
) . " " . get_class($this), 406);
|
||||
}
|
||||
$this->left = $left;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/** Set the right position of the axis if the parameter is provided.
|
||||
* Get the right position of the axis if the parameter is not provided
|
||||
* @param integer|null $right The right position of the axis
|
||||
*/
|
||||
public function right($right = null)
|
||||
{
|
||||
if ($right === null) {
|
||||
return $this->right;
|
||||
}
|
||||
if (! is_integer($right) || $right < 0 || $right > 5000) {
|
||||
throw new \Exception(dgettext(
|
||||
"domframework",
|
||||
"Invalid right provided to graph Axis"
|
||||
) . " " . get_class($this), 406);
|
||||
}
|
||||
$this->right = $right;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/** Set the fontfile of the labels if the parameter is provided.
|
||||
* Get the fontfile of the labels if the parameter is not provided
|
||||
* @param string|null $fontfile The fontfile of the title
|
||||
*/
|
||||
public function fontfile($fontfile = null)
|
||||
{
|
||||
if ($fontfile === null) {
|
||||
return $this->fontfile;
|
||||
}
|
||||
if (
|
||||
! is_string($fontfile) || strlen($fontfile) < 0 ||
|
||||
! file_exists($fontfile) || ! is_readable($fontfile)
|
||||
) {
|
||||
throw new \Exception(dgettext(
|
||||
"domframework",
|
||||
"Invalid fontfile provided to graph title"
|
||||
), 406);
|
||||
}
|
||||
$this->fontfile = $fontfile;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/** Set the font size of the labels if the parameter is provided.
|
||||
* Get the font size of the labels if the parameter is not provided
|
||||
* @param integer|null $fontsize The font size of the title
|
||||
*/
|
||||
public function fontsize($fontsize = null)
|
||||
{
|
||||
if ($fontsize === null) {
|
||||
return $this->fontsize;
|
||||
}
|
||||
if (! is_integer($fontsize) || $fontsize < 2 || $fontsize > 100) {
|
||||
throw new \Exception(dgettext(
|
||||
"domframework",
|
||||
"Invalid fontsize provided to graph title"
|
||||
), 406);
|
||||
}
|
||||
$this->fontsize = $fontsize;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/** Set the axis color if the parameter is provided.
|
||||
* Get the axis color if the parameter is not provided
|
||||
* @param string|null $axisColor The axis color
|
||||
*/
|
||||
public function axisColor($axisColor = null)
|
||||
{
|
||||
if ($axisColor === null) {
|
||||
return $this->axisColor;
|
||||
}
|
||||
if (
|
||||
! is_string($axisColor) ||
|
||||
! in_array($axisColor, Color::colorList())
|
||||
) {
|
||||
throw new \Exception(dgettext(
|
||||
"domframework",
|
||||
"Invalid axisColor provided to graph axis"
|
||||
), 406);
|
||||
}
|
||||
$this->axisColor = $axisColor;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/** Set the grid color if the parameter is provided.
|
||||
* Get the grid color if the parameter is not provided
|
||||
* @param string|null $gridColor The grid color
|
||||
*/
|
||||
public function gridColor($gridColor = null)
|
||||
{
|
||||
if ($gridColor === null) {
|
||||
return $this->gridColor;
|
||||
}
|
||||
if (
|
||||
! is_string($gridColor) ||
|
||||
! in_array($gridColor, Color::colorList())
|
||||
) {
|
||||
throw new \Exception(dgettext(
|
||||
"domframework",
|
||||
"Invalid gridColor provided to graph grid"
|
||||
), 406);
|
||||
}
|
||||
$this->gridColor = $gridColor;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/** Calculate the labels that will be displayed on the axis
|
||||
* @param integer $nbMaxValues The maximum number of values to return
|
||||
* @return array The array of labels to display
|
||||
*/
|
||||
protected function labels($nbMaxValues)
|
||||
{
|
||||
// Activate the debug of this method
|
||||
$deb = false;
|
||||
if (! is_int($nbMaxValues)) {
|
||||
throw new \Exception(
|
||||
"Invalid parameter nbMaxValues provided to graphAxisGeneral::labels",
|
||||
500
|
||||
);
|
||||
}
|
||||
if ($deb) {
|
||||
echo "=========== LABELS\n";
|
||||
}
|
||||
if ($this->min > 0) {
|
||||
$minLabel = $this->min * 0.90;
|
||||
} else {
|
||||
$minLabel = $this->min * 1.05;
|
||||
}
|
||||
if ($this->max > 0) {
|
||||
$maxLabel = $this->max * 1.05;
|
||||
} else {
|
||||
$maxLabel = $this->max * 0.90;
|
||||
}
|
||||
|
||||
$minBase = intval(log10($minLabel)) - 1;
|
||||
$maxBase = intval(log10($maxLabel)) - 1;
|
||||
$base = max($minBase, $maxBase);
|
||||
if ($deb) {
|
||||
echo "minBase=$minBase, maxBase=$maxBase ===> base = $base\n";
|
||||
}
|
||||
|
||||
if ($base < 0 && $base > -1) {
|
||||
$base = $base - 1;
|
||||
}
|
||||
// The while loop reduce the base to not explode the number of labels
|
||||
// If there is too much labels, remove one digit and retry
|
||||
while (1) {
|
||||
$this->labelMin = null;
|
||||
$this->labelMax = null;
|
||||
$min = round($minLabel, -1 * $base);
|
||||
$max = round($maxLabel, -1 * $base);
|
||||
if ($deb) {
|
||||
echo "min = $min, max = $max\n";
|
||||
}
|
||||
|
||||
$scale = pow(10, $base);
|
||||
if ($deb) {
|
||||
echo "BASE=" . ($base) . ", SCALE = $scale\n";
|
||||
}
|
||||
if ($scale === 0 || $scale === 0.0) {
|
||||
die("Scale equal 0 on line " . __LINE__ . "\n");
|
||||
}
|
||||
$labels = array();
|
||||
if ($this->min <= 0 && $this->max >= 0) {
|
||||
// Return the 0 label and the values arround it
|
||||
$zeroAlreadyDraw = false;
|
||||
for (
|
||||
$i = 0;
|
||||
\bccomp($i, 1.2 * $max, abs($base) + 1) < 1;
|
||||
$i += $scale
|
||||
) {
|
||||
if ($i === 0) {
|
||||
$zeroAlreadyDraw = true;
|
||||
}
|
||||
if ($deb) {
|
||||
echo "Values with Zero : add pos val $i\n";
|
||||
}
|
||||
$labels[] = $i;
|
||||
}
|
||||
for (
|
||||
$i = 0;
|
||||
\bccomp($i, 1.4 * $min, abs($base) + 1) >= 0;
|
||||
$i -= $scale
|
||||
) {
|
||||
if ($zeroAlreadyDraw === true && $i === 0) {
|
||||
continue;
|
||||
}
|
||||
if ($deb) {
|
||||
echo "Values with Zero : add neg val $i\n";
|
||||
}
|
||||
$labels[] = $i;
|
||||
}
|
||||
} else {
|
||||
// No 0 Axis : From $this->min to $this->max
|
||||
for (
|
||||
$i = $min;
|
||||
\bccomp($i, $max, abs($base) + 1) < 1;
|
||||
$i += $scale
|
||||
) {
|
||||
if ($deb) {
|
||||
echo "Values no Zero : add val $i\n";
|
||||
}
|
||||
$labels[] = $i;
|
||||
}
|
||||
}
|
||||
if (count($labels) <= $nbMaxValues) {
|
||||
foreach ($labels as &$label) {
|
||||
if ($base < 0) {
|
||||
$label = sprintf("%0." . intval(abs($base)) . "f", $label);
|
||||
} else {
|
||||
$label = sprintf("%" . intval($base) . "d", $label);
|
||||
}
|
||||
if (
|
||||
$this->labelMin === null ||
|
||||
\bccomp($this->labelMin, $label, abs($base) + 1) >= 0
|
||||
) {
|
||||
$this->labelMin = $label;
|
||||
}
|
||||
if (
|
||||
$this->labelMax === null ||
|
||||
\bccomp($this->labelMax, $label, abs($base) + 1) <= 0
|
||||
) {
|
||||
$this->labelMax = $label;
|
||||
}
|
||||
}
|
||||
|
||||
if (\bccomp($this->labelMin, $this->min, abs($base) + 1) > 0) {
|
||||
// Add a label in the minimum
|
||||
$this->labelMin = $this->labelMin - $scale;
|
||||
if ($deb) {
|
||||
echo "Force Add Min $this->labelMin\n";
|
||||
}
|
||||
if ($base < 0) {
|
||||
$labels[] = sprintf(
|
||||
"%0." . intval(abs($base)) . "f",
|
||||
$this->labelMin
|
||||
);
|
||||
} else {
|
||||
$labels[] = sprintf("%" . intval($base) . "d", $this->labelMin);
|
||||
}
|
||||
}
|
||||
if (\bccomp($this->labelMax, $this->max, abs($base) + 1) < 0) {
|
||||
$this->labelMax = $this->labelMax + $scale;
|
||||
if ($deb) {
|
||||
echo "Force Add Max $this->labelMax\n";
|
||||
}
|
||||
if ($base < 0) {
|
||||
$labels[] = sprintf(
|
||||
"%0." . intval(abs($base)) . "f",
|
||||
$this->labelMax
|
||||
);
|
||||
} else {
|
||||
$labels[] = sprintf("%" . intval($base) . "d", $this->labelMax);
|
||||
}
|
||||
}
|
||||
if ($this->labelMin > $this->min) {
|
||||
die("labelMin > min ($this->labelMin > $this->min)\n");
|
||||
}
|
||||
if ($this->labelMax < $this->max) {
|
||||
die("labelMax < max ($this->labelMax < $this->max)\n");
|
||||
}
|
||||
if (count($labels) <= $nbMaxValues) {
|
||||
$labels = array_unique($labels);
|
||||
if ($deb) {
|
||||
print_r($labels);
|
||||
}
|
||||
return $labels;
|
||||
}
|
||||
}
|
||||
if ($deb) {
|
||||
echo "LOOP == " . count($labels) . " > $nbMaxValues ==========\n";
|
||||
}
|
||||
$base = $base + 0.1;
|
||||
}
|
||||
}
|
||||
}
|
||||
111
src/GraphAxisHorizontal.php
Normal file
111
src/GraphAxisHorizontal.php
Normal file
@@ -0,0 +1,111 @@
|
||||
<?php
|
||||
|
||||
/** DomFramework
|
||||
* @package domframework
|
||||
* @author Dominique Fournier <dominique@fournier38.fr>
|
||||
* @license BSD
|
||||
*/
|
||||
|
||||
namespace Domframework;
|
||||
|
||||
/** The graph Axis Horizontal class */
|
||||
class GraphAxisHorizontal extends GraphAxisGeneral
|
||||
{
|
||||
/** Calculate the position in pixels for a value
|
||||
* If the value is out of range, return null to not draw the point
|
||||
* @param string|float|integer $value The value to position
|
||||
*/
|
||||
public function position($value)
|
||||
{
|
||||
if ($value === null) {
|
||||
return null;
|
||||
}
|
||||
if (! is_numeric($value) && ! is_string($value)) {
|
||||
throw new \Exception(dgettext(
|
||||
"domframework",
|
||||
"Invalid value provided to graph Axis for position"
|
||||
) . " " .
|
||||
get_class($this), 406);
|
||||
}
|
||||
if ($this->numerical === null) {
|
||||
throw new \Exception(dgettext(
|
||||
"domframework",
|
||||
"No numerical type defined for Axis"
|
||||
) . " " . get_class($this), 406);
|
||||
}
|
||||
if ($this->numerical) {
|
||||
// Numerical axis, use a standard scale
|
||||
if ($value < $this->min || $value > $this->max) {
|
||||
return null;
|
||||
}
|
||||
if (($this->max - $this->min) == 0) {
|
||||
$dividor = 1;
|
||||
} else {
|
||||
$dividor = ($this->max - $this->min);
|
||||
}
|
||||
$scale = ($value - $this->min) / $dividor;
|
||||
return intval($this->left + $scale * ($this->right - $this->left));
|
||||
} else {
|
||||
// Label axis, count them
|
||||
if (! is_array($this->data)) {
|
||||
throw new \Exception(dgettext(
|
||||
"domframework",
|
||||
"No data defined for Axis"
|
||||
) . " " . get_class($this), 406);
|
||||
}
|
||||
$pos = array_search($value, $this->data);
|
||||
if ($pos === false) {
|
||||
return null;
|
||||
}
|
||||
$width = ($this->right - $this->left) / count($this->data);
|
||||
return intval($this->left + $width * $pos + $width / 2);
|
||||
}
|
||||
}
|
||||
|
||||
/** Calculate the positionMin, used for labeled axies
|
||||
* If the value is out of range, return null to not draw the point
|
||||
* @param string|float|integer $value The value to position
|
||||
*/
|
||||
public function positionMin($value)
|
||||
{
|
||||
if ($this->numerical) {
|
||||
return $posCenter;
|
||||
}
|
||||
if (! is_array($this->data)) {
|
||||
throw new \Exception(dgettext(
|
||||
"domframework",
|
||||
"No data defined for Axis"
|
||||
) . " " . get_class($this), 406);
|
||||
}
|
||||
$pos = array_search($value, $this->data);
|
||||
if ($pos === false) {
|
||||
return null;
|
||||
}
|
||||
$width = ($this->right - $this->left) / count($this->data);
|
||||
return intval($this->left + $width * $pos);
|
||||
}
|
||||
|
||||
/** Calculate the positionMax, used for labeled axies
|
||||
* If the value is out of range, return null to not draw the point
|
||||
* @param string|float|integer $value The value to position
|
||||
*/
|
||||
public function positionMax($value)
|
||||
{
|
||||
$posCenter = $this->position($value);
|
||||
if ($this->numerical) {
|
||||
return $posCenter;
|
||||
}
|
||||
if (! is_array($this->data)) {
|
||||
throw new \Exception(dgettext(
|
||||
"domframework",
|
||||
"No data defined for Axis"
|
||||
) . " " . get_class($this), 406);
|
||||
}
|
||||
$pos = array_search($value, $this->data);
|
||||
if ($pos === false) {
|
||||
return null;
|
||||
}
|
||||
$width = ($this->right - $this->left) / count($this->data);
|
||||
return intval($this->left + $width * $pos + $width);
|
||||
}
|
||||
}
|
||||
207
src/GraphAxisVertical.php
Normal file
207
src/GraphAxisVertical.php
Normal file
@@ -0,0 +1,207 @@
|
||||
<?php
|
||||
|
||||
/** DomFramework
|
||||
* @package domframework
|
||||
* @author Dominique Fournier <dominique@fournier38.fr>
|
||||
* @license BSD
|
||||
*/
|
||||
|
||||
namespace Domframework;
|
||||
|
||||
/** Manage the vertical axis */
|
||||
class GraphAxisVertical extends GraphAxisGeneral
|
||||
{
|
||||
/** The angle choosed to draw the graph
|
||||
*/
|
||||
private $angle;
|
||||
|
||||
/** The padding between the label and the axis
|
||||
*/
|
||||
protected $padding = 7;
|
||||
|
||||
/** The width of the labels + padding (it is the base of the graph) in pixels
|
||||
*/
|
||||
protected $width;
|
||||
|
||||
/** The number of chars to be displayed in one label
|
||||
*/
|
||||
protected $nbcharsLabel = 0;
|
||||
|
||||
/** Look for the width of the Y axis
|
||||
* @param resource $gd The resource to modify
|
||||
*/
|
||||
public function getWidth($gd)
|
||||
{
|
||||
if ($this->numerical) {
|
||||
if ($this->max === null) {
|
||||
throw new \Exception(dgettext(
|
||||
"domframework",
|
||||
"The max is not defined for graphAxisVertical"
|
||||
), 406);
|
||||
}
|
||||
// Look at the minimum distance between two labeled values
|
||||
$bbox = imagettfbbox($this->fontsize, 0, $this->fontfile, "NOT");
|
||||
$height = abs($bbox[5] - $bbox[1]) + $this->padding;
|
||||
for ($nbMaxValues = 10; $nbMaxValues > 2; $nbMaxValues--) {
|
||||
if ($nbMaxValues * $height < abs($this->top - $this->bottom)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
$labels = $this->labels($nbMaxValues);
|
||||
$labelBiggest = "";
|
||||
$this->nbcharsLabel = 0;
|
||||
foreach ($labels as $label) {
|
||||
if (strlen($label) > $this->nbcharsLabel) {
|
||||
$this->nbcharsLabel = strlen($label);
|
||||
$labelBiggest = $label;
|
||||
}
|
||||
}
|
||||
$bbox = imagettfbbox(
|
||||
$this->fontsize,
|
||||
$this->angle,
|
||||
$this->fontfile,
|
||||
$labelBiggest
|
||||
);
|
||||
$width = abs($bbox[4] - $bbox[0]);
|
||||
$this->width = $width + 2 * $this->padding;
|
||||
return $this->width;
|
||||
} else {
|
||||
if ($this->data === null) {
|
||||
return $this->padding;
|
||||
}
|
||||
die("TODO : getWidth in labeled line " . __LINE__ . "\n");
|
||||
}
|
||||
}
|
||||
|
||||
/** Calculate the position in pixels for a value
|
||||
* If the value is out of range, return null to not draw the point
|
||||
* @param string|float|integer $value The value to position
|
||||
*/
|
||||
public function position($value)
|
||||
{
|
||||
if ($value === null) {
|
||||
return null;
|
||||
}
|
||||
if (! is_numeric($value) && ! is_string($value)) {
|
||||
throw new \Exception(dgettext(
|
||||
"domframework",
|
||||
"Invalid value provided to graph Axis for position"
|
||||
) . " " .
|
||||
get_class($this), 406);
|
||||
}
|
||||
if ($this->numerical === null) {
|
||||
throw new \Exception(dgettext(
|
||||
"domframework",
|
||||
"No numerical type defined for Axis"
|
||||
) . " " . get_class($this), 406);
|
||||
}
|
||||
if ($this->numerical) {
|
||||
// Numerical axis, use a standard scale
|
||||
if ($value > $this->labelMax || $value < $this->labelMin) {
|
||||
return null;
|
||||
}
|
||||
$scale = ($value - $this->labelMin) / ($this->labelMax - $this->labelMin);
|
||||
$pos = intval($this->bottom + $scale * ($this->top - $this->bottom));
|
||||
return $pos;
|
||||
} else {
|
||||
// Label axis, count them
|
||||
if (! is_array($this->data)) {
|
||||
throw new \Exception(dgettext(
|
||||
"domframework",
|
||||
"No data defined for Axis"
|
||||
) . " " . get_class($this), 406);
|
||||
}
|
||||
$pos = array_search($value, $this->data);
|
||||
if ($pos === false) {
|
||||
return null;
|
||||
}
|
||||
$width = ($this->top - $this->bottom) / count($this->data);
|
||||
$pos = intval($this->bottom + $width * $pos + $width / 2);
|
||||
return $pos;
|
||||
}
|
||||
}
|
||||
|
||||
/** Calculate the positionMin, used for labeled axies
|
||||
* If the value is out of range, return null to not draw the point
|
||||
* @param string|float|integer $value The value to position
|
||||
*/
|
||||
public function positionMin($value)
|
||||
{
|
||||
if ($this->numerical) {
|
||||
return $posCenter;
|
||||
}
|
||||
if (! is_array($this->data)) {
|
||||
throw new \Exception(dgettext(
|
||||
"domframework",
|
||||
"No data defined for Axis"
|
||||
) . " " . get_class($this), 406);
|
||||
}
|
||||
$pos = array_search($value, $this->data);
|
||||
if ($pos === false) {
|
||||
return null;
|
||||
}
|
||||
$width = ($this->top - $this->bottom) / count($this->data);
|
||||
return intval($this->bottom + $width * $pos);
|
||||
}
|
||||
|
||||
/** Calculate the positionMax, used for labeled axies
|
||||
* If the value is out of range, return null to not draw the point
|
||||
* @param string|float|integer $value The value to position
|
||||
*/
|
||||
public function positionMax($value)
|
||||
{
|
||||
$posCenter = $this->position($value);
|
||||
if ($this->numerical) {
|
||||
return $posCenter;
|
||||
}
|
||||
if (! is_array($this->data)) {
|
||||
throw new \Exception(dgettext(
|
||||
"domframework",
|
||||
"No data defined for Axis"
|
||||
) . " " . get_class($this), 406);
|
||||
}
|
||||
$pos = array_search($value, $this->data);
|
||||
if ($pos === false) {
|
||||
return null;
|
||||
}
|
||||
$width = ($this->top - $this->bottom) / count($this->data);
|
||||
return intval($this->bottom + $width * $pos + $width);
|
||||
}
|
||||
|
||||
/** Draw the axis labels and lines
|
||||
* @param resource $gd The resource to modify
|
||||
*/
|
||||
public function draw($gd)
|
||||
{
|
||||
$axisColor = Color::allocateFromText($gd, $this->axisColor);
|
||||
if ($this->numerical) {
|
||||
// Look at the minimum distance between two labeled values
|
||||
$bbox = imagettfbbox($this->fontsize, 0, $this->fontfile, "NOT");
|
||||
$height = abs($bbox[5] - $bbox[1]) + $this->padding;
|
||||
for ($nbMaxValues = 10; $nbMaxValues > 2; $nbMaxValues--) {
|
||||
if ($nbMaxValues * $height < abs($this->top - $this->bottom)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$width = $this->getWidth($gd);
|
||||
$labels = $this->labels($nbMaxValues);
|
||||
if (count($labels) > $nbMaxValues) {
|
||||
die("Too much labels to display (" .
|
||||
count($labels) . " > $nbMaxValues)\n");
|
||||
}
|
||||
foreach ($labels as $label) {
|
||||
$this->drawOne($gd, $width, $label);
|
||||
$this->drawGrid($gd, $width, $label);
|
||||
}
|
||||
$this->drawAxis($gd, $width);
|
||||
} else {
|
||||
// Labeled
|
||||
// If there is no data, there is nothing to draw : return
|
||||
if ($this->data === null) {
|
||||
return;
|
||||
}
|
||||
die("graphAxisVertical::draw labeled TBD line " . __LINE__ . "\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
214
src/GraphAxisX.php
Normal file
214
src/GraphAxisX.php
Normal file
@@ -0,0 +1,214 @@
|
||||
<?php
|
||||
|
||||
/** DomFramework
|
||||
* @package domframework
|
||||
* @author Dominique Fournier <dominique@fournier38.fr>
|
||||
* @license BSD
|
||||
*/
|
||||
|
||||
namespace Domframework;
|
||||
|
||||
/** The X axis management */
|
||||
class GraphAxisX extends GraphAxisHorizontal
|
||||
{
|
||||
/** The angle choosed to draw the graph
|
||||
*/
|
||||
private $angle;
|
||||
|
||||
/** The padding between the label and the axis
|
||||
*/
|
||||
private $padding = 7;
|
||||
|
||||
/** The heigth of the labels + padding (it is the base of the graph) in pixels
|
||||
*/
|
||||
private $height;
|
||||
|
||||
/** The number of chars to be displayed in one label
|
||||
*/
|
||||
protected $nbcharsLabel = 0;
|
||||
|
||||
/** Look for the height of the X axis based on the angle of the text when it
|
||||
* will be drawn
|
||||
* @param resource $gd The resource to modify
|
||||
*/
|
||||
public function getHeight($gd)
|
||||
{
|
||||
// Look for the angle of the value. Start Horizontally (angle=0), then
|
||||
// try 45°, then finish at 90°. As all the values must in the same angle,
|
||||
// test all the values. If one is bad, change the angle and retry all the
|
||||
// values
|
||||
$width = null;
|
||||
if ($this->numerical) {
|
||||
if ($this->max === null) {
|
||||
throw new \Exception(dgettext(
|
||||
"domframework",
|
||||
"The max is not defined for graphAxisHorizontal"
|
||||
), 406);
|
||||
}
|
||||
$powMax = intval(log10($this->max));
|
||||
$tenPercent = round($this->max / pow(10, $powMax), 1) + 0.1;
|
||||
$labelMax = $tenPercent * pow(10, $powMax);
|
||||
$this->nbcharsLabel = strlen($labelMax);
|
||||
$bbox = imagettfbbox(
|
||||
$this->fontsize,
|
||||
$this->angle,
|
||||
$this->fontfile,
|
||||
$labelMax
|
||||
);
|
||||
$height = abs($bbox[4] - $bbox[0]);
|
||||
$this->height = $height + 2 * $this->padding;
|
||||
return $this->height;
|
||||
} else {
|
||||
if ($this->data === null) {
|
||||
return 0;
|
||||
}
|
||||
foreach (array(0, 45, 90) as $this->angle) {
|
||||
$bboxMaxHeight = 0;
|
||||
foreach ($this->data as $key => $value) {
|
||||
if ($width === null) {
|
||||
$width = $this->positionMax($value) - $this->positionMin($value);
|
||||
}
|
||||
// Look for the bounding box around the text. The bounding is not
|
||||
// write on the image and return the coordinates for the text box
|
||||
$bbox = imagettfbbox(
|
||||
$this->fontsize,
|
||||
$this->angle,
|
||||
$this->fontfile,
|
||||
$value
|
||||
);
|
||||
if (abs($bbox[4] - $bbox[0]) > $width) {
|
||||
continue 2;
|
||||
}
|
||||
$bboxMaxHeight = max($bboxMaxHeight, abs($bbox[5] - $bbox[1]));
|
||||
}
|
||||
// All the values are OK : we have found the angle : break the angle
|
||||
// loop
|
||||
break;
|
||||
}
|
||||
}
|
||||
$this->height = $bboxMaxHeight + 2 * $this->padding;
|
||||
return $bboxMaxHeight + 2 * $this->padding;
|
||||
}
|
||||
|
||||
/** Draw the axis
|
||||
* @param resource $gd The resource to modify
|
||||
*/
|
||||
public function draw($gd)
|
||||
{
|
||||
$axisColor = Color::allocateFromText($gd, $this->axisColor);
|
||||
if ($this->numerical) {
|
||||
if ($this->angle === null) {
|
||||
$this->getHeight($gd);
|
||||
}
|
||||
if ($this->data === null) {
|
||||
return;
|
||||
}
|
||||
foreach ($this->data as $key => $value) {
|
||||
$position = $this->position($value);
|
||||
|
||||
// Draw the labels
|
||||
$bbox = imagettfbbox(
|
||||
$this->fontsize,
|
||||
$this->angle,
|
||||
$this->fontfile,
|
||||
$value
|
||||
);
|
||||
$width = abs($bbox[4] - $bbox[0]);
|
||||
$x = $position - $width / 2;
|
||||
$y = $this->bottom - $this->padding;
|
||||
// The font color is forced to black
|
||||
imagettftext(
|
||||
$gd,
|
||||
$this->fontsize,
|
||||
$this->angle,
|
||||
$x,
|
||||
$y,
|
||||
Color::allocateFromText($gd, "black"),
|
||||
$this->fontfile,
|
||||
$value
|
||||
);
|
||||
|
||||
// Draw the scale
|
||||
imageline(
|
||||
$gd,
|
||||
$position,
|
||||
$this->bottom - $this->height + 1,
|
||||
$position,
|
||||
$this->bottom - $this->height + 1 + $this->padding,
|
||||
$axisColor
|
||||
);
|
||||
|
||||
// Draw the grid
|
||||
$this->drawGrid($gd, $this->bottom - $this->height, $position);
|
||||
}
|
||||
|
||||
// Draw the axis
|
||||
$y = $this->bottom - $this->height + 1;
|
||||
imageline($gd, $this->left, $y, $this->right, $y, $axisColor);
|
||||
} else {
|
||||
if ($this->angle === null) {
|
||||
$this->getHeight($gd);
|
||||
}
|
||||
if ($this->data === null) {
|
||||
return;
|
||||
}
|
||||
foreach ($this->data as $key => $value) {
|
||||
$position = $this->position($value);
|
||||
|
||||
// Draw the labels
|
||||
$bbox = imagettfbbox(
|
||||
$this->fontsize,
|
||||
$this->angle,
|
||||
$this->fontfile,
|
||||
$value
|
||||
);
|
||||
$width = abs($bbox[4] - $bbox[0]);
|
||||
$x = $position - $width / 2;
|
||||
$y = $this->bottom - $this->padding;
|
||||
// The font color is forced to black
|
||||
imagettftext(
|
||||
$gd,
|
||||
$this->fontsize,
|
||||
$this->angle,
|
||||
$x,
|
||||
$y,
|
||||
Color::allocateFromText($gd, "black"),
|
||||
$this->fontfile,
|
||||
$value
|
||||
);
|
||||
|
||||
// Draw the separators
|
||||
$y = $this->bottom - $this->height + 1;
|
||||
$xmin = $this->positionMin($value);
|
||||
$xmax = $this->positionMax($value);
|
||||
imageline($gd, $xmin, $y, $xmin, $y + $this->padding, $axisColor);
|
||||
imageline($gd, $xmax, $y, $xmax, $y + $this->padding, $axisColor);
|
||||
|
||||
// Draw the grid
|
||||
$this->drawGrid($gd, $this->bottom - $this->height, $position);
|
||||
}
|
||||
|
||||
// Draw the axis
|
||||
$y = $this->bottom - $this->height + 1;
|
||||
imageline($gd, $this->left, $y, $this->right, $y, $axisColor);
|
||||
}
|
||||
}
|
||||
|
||||
/** Draw the grid
|
||||
* @param resource $gd The resource to modify
|
||||
* @param integer $width The width of the labels on the axis
|
||||
* @param integer|float $position The position to draw
|
||||
*/
|
||||
protected function drawGrid($gd, $width, $position)
|
||||
{
|
||||
if ($this->gridColor === null || $this->gridColor === "transparent") {
|
||||
return;
|
||||
}
|
||||
$gridColor = Color::allocateFromText($gd, $this->gridColor);
|
||||
if ($position === null) {
|
||||
return;
|
||||
}
|
||||
$y = $this->bottom - $this->height;
|
||||
imageline($gd, $position, $y, $position, $this->top, $gridColor);
|
||||
}
|
||||
}
|
||||
94
src/GraphAxisY1.php
Normal file
94
src/GraphAxisY1.php
Normal file
@@ -0,0 +1,94 @@
|
||||
<?php
|
||||
|
||||
/** DomFramework
|
||||
* @package domframework
|
||||
* @author Dominique Fournier <dominique@fournier38.fr>
|
||||
* @license BSD
|
||||
*/
|
||||
|
||||
namespace Domframework;
|
||||
|
||||
/** The Y1 axis management */
|
||||
class GraphAxisY1 extends GraphAxisVertical
|
||||
{
|
||||
/** Draw one value on the axis
|
||||
* @param resource $gd The resource to modify
|
||||
* @param integer $width The width of the labels on the axis
|
||||
* @param integer|float $val The value to draw
|
||||
*/
|
||||
protected function drawOne($gd, $width, $val)
|
||||
{
|
||||
$axisColor = Color::allocateFromText($gd, $this->axisColor);
|
||||
if ($this->numerical) {
|
||||
// Do not allow the label to be longer than $this->max
|
||||
if (strlen($val) > $this->nbcharsLabel) {
|
||||
$itmp = rtrim(substr($val, 0, $this->nbcharsLabel), ".");
|
||||
} else {
|
||||
$itmp = $val;
|
||||
}
|
||||
// Write the labels align to right
|
||||
$bbox = imagettfbbox($this->fontsize, 0, $this->fontfile, $itmp);
|
||||
$labelwidth = abs($bbox[4] - $bbox[0]) + $this->padding;
|
||||
$labelheight = abs($bbox[5] - $bbox[1]);
|
||||
$y = $this->position($val);
|
||||
if ($y === null) {
|
||||
return;
|
||||
}
|
||||
// The color is forced to black
|
||||
imagettftext(
|
||||
$gd,
|
||||
$this->fontsize,
|
||||
0,
|
||||
$width - $labelwidth,
|
||||
$y + $labelheight / 2,
|
||||
Color::allocateFromText($gd, "black"),
|
||||
$this->fontfile,
|
||||
$itmp
|
||||
);
|
||||
|
||||
// Display the separators
|
||||
imageline(
|
||||
$gd,
|
||||
$width - $this->padding,
|
||||
$y,
|
||||
$width,
|
||||
$y,
|
||||
$axisColor
|
||||
);
|
||||
} else {
|
||||
die("graphAxisY1:: drawOne NOT numerical line " . __LINE__ . "\n");
|
||||
}
|
||||
}
|
||||
|
||||
/** Draw the axis
|
||||
* @param resource $gd The resource to modify
|
||||
* @param integer $width The width of the labels on the axis
|
||||
*/
|
||||
protected function drawAxis($gd, $width)
|
||||
{
|
||||
$axisColor = Color::allocateFromText($gd, $this->axisColor);
|
||||
imageline($gd, $width, $this->bottom, $width, $this->top, $axisColor);
|
||||
}
|
||||
|
||||
/** Draw the grid
|
||||
* @param resource $gd The resource to modify
|
||||
* @param integer $width The width of the labels on the axis
|
||||
* @param integer|float $val The value to draw
|
||||
*/
|
||||
protected function drawGrid($gd, $width, $val)
|
||||
{
|
||||
if ($this->gridColor === null || $this->gridColor === "transparent") {
|
||||
return;
|
||||
}
|
||||
$gridColor = Color::allocateFromText($gd, $this->gridColor);
|
||||
if ($this->numerical) {
|
||||
$y = $this->position($val);
|
||||
if ($y === null) {
|
||||
return;
|
||||
}
|
||||
imageline($gd, $width, $y, $this->right, $y, $gridColor);
|
||||
} else {
|
||||
die("graphAxisY1:: drawGrid NOT numerical line " . __LINE__ . "\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
90
src/GraphAxisY2.php
Normal file
90
src/GraphAxisY2.php
Normal file
@@ -0,0 +1,90 @@
|
||||
<?php
|
||||
|
||||
/** DomFramework
|
||||
* @package domframework
|
||||
* @author Dominique Fournier <dominique@fournier38.fr>
|
||||
* @license BSD
|
||||
*/
|
||||
|
||||
namespace Domframework;
|
||||
|
||||
/** The Y2 axis management */
|
||||
class GraphAxisY2 extends GraphAxisVertical
|
||||
{
|
||||
/** Draw one value on the axis
|
||||
* @param resource $gd The resource to modify
|
||||
* @param integer $width The width of the labels on the axis
|
||||
* @param integer|float $val The value to draw
|
||||
*/
|
||||
protected function drawOne($gd, $width, $val)
|
||||
{
|
||||
$axisColor = Color::allocateFromText($gd, $this->axisColor);
|
||||
if ($this->numerical) {
|
||||
// Do not allow the label to be longer than $this->max
|
||||
if (strlen($val) > $this->nbcharsLabel) {
|
||||
$itmp = rtrim(substr($val, 0, $this->nbcharsLabel), ".");
|
||||
} else {
|
||||
$itmp = $val;
|
||||
}
|
||||
// Write the labels align to left
|
||||
$bbox = imagettfbbox($this->fontsize, 0, $this->fontfile, $itmp);
|
||||
$labelwidth = abs($bbox[4] - $bbox[0]) + $this->padding;
|
||||
$labelheight = abs($bbox[5] - $bbox[1]);
|
||||
$y = $this->position($val);
|
||||
if ($y === null) {
|
||||
return;
|
||||
}
|
||||
// The color is forced to black
|
||||
imagettftext(
|
||||
$gd,
|
||||
$this->fontsize,
|
||||
0,
|
||||
$this->left + $this->padding + 3,
|
||||
$y + $labelheight / 2,
|
||||
Color::allocateFromText($gd, "black"),
|
||||
$this->fontfile,
|
||||
$itmp
|
||||
);
|
||||
|
||||
// Display the separators
|
||||
imageline(
|
||||
$gd,
|
||||
$this->left,
|
||||
$y,
|
||||
$this->left + $this->padding,
|
||||
$y,
|
||||
$axisColor
|
||||
);
|
||||
} else {
|
||||
die("graphAxisY2:: drawOne NOT numerical line " . __LINE__ . "\n");
|
||||
}
|
||||
}
|
||||
|
||||
/** Draw the axis
|
||||
* @param resource $gd The resource to modify
|
||||
* @param integer $width The width of the labels on the axis
|
||||
*/
|
||||
protected function drawAxis($gd, $width)
|
||||
{
|
||||
$axisColor = Color::allocateFromText($gd, $this->axisColor);
|
||||
imageline(
|
||||
$gd,
|
||||
$this->left,
|
||||
$this->bottom,
|
||||
$this->left,
|
||||
$this->top,
|
||||
$axisColor
|
||||
);
|
||||
}
|
||||
|
||||
/** Draw the grid
|
||||
* @param resource $gd The resource to modify
|
||||
* @param integer $width The width of the labels on the axis
|
||||
* @param integer|float $val The value to draw
|
||||
*/
|
||||
protected function drawGrid($gd, $width, $val)
|
||||
{
|
||||
// The grid can't be graphed for Y2 axis : only the Y1 axis is allowed
|
||||
return;
|
||||
}
|
||||
}
|
||||
305
src/GraphData.php
Normal file
305
src/GraphData.php
Normal file
@@ -0,0 +1,305 @@
|
||||
<?php
|
||||
|
||||
/** DomFramework
|
||||
* @package domframework
|
||||
* @author Dominique Fournier <dominique@fournier38.fr>
|
||||
* @license BSD
|
||||
*/
|
||||
|
||||
namespace Domframework;
|
||||
|
||||
/** Read the data */
|
||||
class GraphData
|
||||
{
|
||||
/** Store the data when the user provided them. Store them in array form
|
||||
*/
|
||||
private $data;
|
||||
|
||||
/** The titles are on the first line
|
||||
*/
|
||||
private $titlesOnFirstLine = null;
|
||||
|
||||
/** The titles are on the first column
|
||||
*/
|
||||
private $titlesOnFirstColumn = null;
|
||||
|
||||
/** The data are stored horizontally
|
||||
*/
|
||||
private $horizontalData = null;
|
||||
|
||||
/** Get the data from an indexed array
|
||||
* @param array $array The data array to graph
|
||||
*/
|
||||
public function arrayIndexed($array)
|
||||
{
|
||||
$this->data = $array;
|
||||
if (! is_array($this->data)) {
|
||||
throw new \Exception(
|
||||
dgettext(
|
||||
"domframework",
|
||||
"Invalid Array Parameter provided: not an array"
|
||||
),
|
||||
406
|
||||
);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/** Get the data from an associative array
|
||||
* The associative array are provided by database results
|
||||
* @param array $array The data array to graph
|
||||
*/
|
||||
public function arrayAssociative($array)
|
||||
{
|
||||
if (! is_array($array)) {
|
||||
throw new \Exception(
|
||||
dgettext(
|
||||
"domframework",
|
||||
"Invalid Array Parameter provided: not an array"
|
||||
),
|
||||
406
|
||||
);
|
||||
}
|
||||
$titles = array();
|
||||
$this->data = array();
|
||||
foreach ($array as $line => $lineArr) {
|
||||
foreach ($lineArr as $key => $cell) {
|
||||
$titles[$key] = "";
|
||||
$this->data[$line][] = $cell;
|
||||
}
|
||||
}
|
||||
array_unshift($this->data, array_keys($titles));
|
||||
return $this;
|
||||
}
|
||||
|
||||
/** Get the data from a CSV string
|
||||
* @param string $csv The CSV string
|
||||
*/
|
||||
public function csv($csv)
|
||||
{
|
||||
$csv = trim($csv);
|
||||
$lines = preg_split('/( *\R)+/s', $csv);
|
||||
$this->data = array_map('str_getcsv', $lines);
|
||||
if (! is_array($this->data)) {
|
||||
throw new \Exception(
|
||||
dgettext(
|
||||
"domframework",
|
||||
"Invalid CSV provided: not converted to array"
|
||||
),
|
||||
406
|
||||
);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/** Get the data from a JSON string
|
||||
* @param string $json The JSON string
|
||||
*/
|
||||
public function json($json)
|
||||
{
|
||||
$this->data = json_decode($json, true);
|
||||
if (! is_array($this->data)) {
|
||||
throw new \Exception(
|
||||
dgettext(
|
||||
"domframework",
|
||||
"Invalid JSON provided: not converted to array"
|
||||
),
|
||||
406
|
||||
);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/** Titles on first line
|
||||
* Set the value if the parameter is provided, get the value if the parameter
|
||||
* is not set
|
||||
* @param boolean|null $titlesOnFirstLine The titles on first line
|
||||
*/
|
||||
public function titlesOnFirstLine($titlesOnFirstLine = null)
|
||||
{
|
||||
if ($titlesOnFirstLine === null) {
|
||||
return $this->titlesOnFirstLine;
|
||||
}
|
||||
if (! is_bool($titlesOnFirstLine)) {
|
||||
throw new \Exception(
|
||||
dgettext(
|
||||
"domframework",
|
||||
"Invalid titlesOnFirstLine provided to graph titlesOnFirstLine"
|
||||
),
|
||||
406
|
||||
);
|
||||
}
|
||||
$this->titlesOnFirstLine = $titlesOnFirstLine;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/** Titles on first column
|
||||
* Set the value if the parameter is provided, get the value if the parameter
|
||||
* is not set
|
||||
* @param boolean|null $titlesOnFirstColumn The titles on first column
|
||||
*/
|
||||
public function titlesOnFirstColumn($titlesOnFirstColumn = null)
|
||||
{
|
||||
if ($titlesOnFirstColumn === null) {
|
||||
return $this->titlesOnFirstColumn;
|
||||
}
|
||||
if (! is_bool($titlesOnFirstColumn)) {
|
||||
throw new \Exception(
|
||||
dgettext(
|
||||
"domframework",
|
||||
"Invalid titlesOnFirstColumn provided to graph titlesOnFirstColumn"
|
||||
),
|
||||
406
|
||||
);
|
||||
}
|
||||
$this->titlesOnFirstColumn = $titlesOnFirstColumn;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/** The data are stored horizontally in the array
|
||||
* Set the value if the parameter is provided, get the value if the parameter
|
||||
* is not set
|
||||
* @param boolean|null $horizontalData The data are stored horizontally
|
||||
*/
|
||||
public function horizontalData($horizontalData = null)
|
||||
{
|
||||
if ($horizontalData === null) {
|
||||
return $this->horizontalData;
|
||||
}
|
||||
if (! is_bool($horizontalData)) {
|
||||
throw new \Exception(
|
||||
dgettext(
|
||||
"domframework",
|
||||
"Invalid horizontalData provided to graph horizontalData"
|
||||
),
|
||||
406
|
||||
);
|
||||
}
|
||||
$this->horizontalData = $horizontalData;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/** Get the series in an array with the associated values
|
||||
*/
|
||||
public function getSeries()
|
||||
{
|
||||
// 0. If there is no data to graph, nothing to do
|
||||
if (count($this->data) === 0) {
|
||||
return array();
|
||||
}
|
||||
|
||||
// 1. If $this->titlesOnFirstLine === null, look if the first line contains
|
||||
// titles
|
||||
if ($this->titlesOnFirstLine === null) {
|
||||
$this->titlesOnFirstLine = true;
|
||||
if (count($this->data) === 1) {
|
||||
$this->titlesOnFirstLine = false;
|
||||
}
|
||||
if (is_array($this->data[0])) {
|
||||
foreach ($this->data[0] as $cell) {
|
||||
if (is_numeric($cell)) {
|
||||
$this->titlesOnFirstLine = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$this->titlesOnFirstLine = false;
|
||||
}
|
||||
}
|
||||
|
||||
// 2. If $this->titlesOnFirstColumn === null, look if the first column
|
||||
// contains titles
|
||||
if ($this->titlesOnFirstColumn === null) {
|
||||
if (count($this->data[0]) === 1) {
|
||||
$this->titlesOnFirstColumn = false;
|
||||
} else {
|
||||
$this->titlesOnFirstColumn = true;
|
||||
foreach ($this->data as $lineArr) {
|
||||
if (is_numeric($lineArr[0])) {
|
||||
$this->titlesOnFirstColumn = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 3. If $this->horizontalData === null, look for orientation with the
|
||||
// titles states
|
||||
if ($this->horizontalData === null) {
|
||||
if (
|
||||
$this->titlesOnFirstColumn === true ||
|
||||
! array_key_exists(1, $this->data)
|
||||
) {
|
||||
$this->horizontalData = true;
|
||||
} else {
|
||||
$this->horizontalData = false;
|
||||
}
|
||||
}
|
||||
|
||||
// 4. Create the series
|
||||
$colTitles = array();
|
||||
$lineTitles = array();
|
||||
$series = array();
|
||||
foreach ($this->data as $linePos => $lineArr) {
|
||||
if (! is_array($lineArr)) {
|
||||
$lineArr = array($lineArr);
|
||||
}
|
||||
if ($linePos === 0) {
|
||||
if ($this->titlesOnFirstLine) {
|
||||
$colTitles = $lineArr;
|
||||
if ($this->horizontalData === false) {
|
||||
// First line with titles and vertical data: get the series names
|
||||
$series = array_flip($lineArr);
|
||||
foreach ($series as &$value) {
|
||||
$value = array();
|
||||
}
|
||||
if ($this->titlesOnFirstColumn) {
|
||||
array_shift($series);
|
||||
}
|
||||
}
|
||||
continue;
|
||||
} else {
|
||||
foreach ($lineArr as $i => $value) {
|
||||
$colTitles[$i] = $i;
|
||||
}
|
||||
}
|
||||
} elseif (count($lineArr) !== count($colTitles)) {
|
||||
throw new \Exception(sprintf(
|
||||
dgettext(
|
||||
"domframework",
|
||||
"Invalid data provided: line %d doesn't have the same number " .
|
||||
"of elements as the first line (%d != %d elements)"
|
||||
),
|
||||
$linePos + 1,
|
||||
count($lineArr),
|
||||
count($colTitles)
|
||||
), 406);
|
||||
}
|
||||
foreach ($lineArr as $colPos => $cell) {
|
||||
$cell = trim($cell);
|
||||
if ($colPos === 0) {
|
||||
if ($this->titlesOnFirstColumn) {
|
||||
$lineTitles[$linePos] = $cell;
|
||||
if ($this->horizontalData === true) {
|
||||
$series[$cell] = array();
|
||||
}
|
||||
continue;
|
||||
} else {
|
||||
$lineTitles[$linePos] = $linePos;
|
||||
}
|
||||
}
|
||||
if (! is_numeric($cell)) {
|
||||
$cell = null;
|
||||
} else {
|
||||
$cell = $cell + 0.0;
|
||||
}
|
||||
if ($this->horizontalData === false) {
|
||||
$series[$colTitles[$colPos]][$lineTitles[$linePos]] = $cell;
|
||||
} else {
|
||||
$series[$lineTitles[$linePos]][$colTitles[$colPos]] = $cell;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $series;
|
||||
}
|
||||
}
|
||||
271
src/GraphLegend.php
Normal file
271
src/GraphLegend.php
Normal file
@@ -0,0 +1,271 @@
|
||||
<?php
|
||||
|
||||
/** DomFramework
|
||||
* @package domframework
|
||||
* @author Dominique Fournier <dominique@fournier38.fr>
|
||||
* @license BSD
|
||||
*/
|
||||
|
||||
namespace Domframework;
|
||||
|
||||
/** The graphLegend object */
|
||||
class GraphLegend
|
||||
{
|
||||
/** Show the legend (no legend by default)
|
||||
*/
|
||||
private $show = false;
|
||||
|
||||
/** The TTF fontfile to use
|
||||
*/
|
||||
private $fontfile = null;
|
||||
|
||||
/** The font size to use
|
||||
*/
|
||||
private $fontsize = 10;
|
||||
|
||||
/** The legend color for the font
|
||||
*/
|
||||
private $color = "black";
|
||||
|
||||
/** The legend background-color
|
||||
*/
|
||||
private $bgcolor = "white";
|
||||
|
||||
/** The legend border color
|
||||
*/
|
||||
private $borderColor = "black";
|
||||
|
||||
/** The padding arround the title (in px)
|
||||
*/
|
||||
private $padding = 10;
|
||||
|
||||
/** Set the legend display status if the parameter is provided.
|
||||
* Get the legend display status if the parameter is not provided
|
||||
* @param boolean|null $show The legend display status
|
||||
*/
|
||||
public function show($show = null)
|
||||
{
|
||||
if ($show === null) {
|
||||
return $this->show;
|
||||
}
|
||||
if (! is_bool($show)) {
|
||||
throw new \Exception(dgettext(
|
||||
"domframework",
|
||||
"Invalid show value provided to graph legend"
|
||||
), 406);
|
||||
}
|
||||
$this->show = $show;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/** Set the fontfile of the legend if the parameter is provided.
|
||||
* Get the fontfile of the legend if the parameter is not provided
|
||||
* @param string|null $fontfile The fontfile of the legend
|
||||
*/
|
||||
public function fontfile($fontfile = null)
|
||||
{
|
||||
if ($fontfile === null) {
|
||||
return $this->fontfile;
|
||||
}
|
||||
if (
|
||||
! is_string($fontfile) || strlen($fontfile) < 0 ||
|
||||
! file_exists($fontfile) || ! is_readable($fontfile)
|
||||
) {
|
||||
throw new \Exception(dgettext(
|
||||
"domframework",
|
||||
"Invalid fontfile provided to graph legend"
|
||||
), 406);
|
||||
}
|
||||
$this->fontfile = $fontfile;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/** Set the font size of the legend if the parameter is provided.
|
||||
* Get the font size of the legend if the parameter is not provided
|
||||
* @param integer|null $fontsize The font size of the legend
|
||||
*/
|
||||
public function fontsize($fontsize = null)
|
||||
{
|
||||
if ($fontsize === null) {
|
||||
return $this->fontsize;
|
||||
}
|
||||
if (! is_integer($fontsize) || $fontsize < 2 || $fontsize > 100) {
|
||||
throw new \Exception(dgettext(
|
||||
"domframework",
|
||||
"Invalid fontsize provided to graph legend"
|
||||
), 406);
|
||||
}
|
||||
$this->fontsize = $fontsize;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/** Set the color of the legend if the parameter is provided.
|
||||
* Get the color of the legend if the parameter is not provided
|
||||
* @param string|null $color The color of the legend
|
||||
*/
|
||||
public function color($color = null)
|
||||
{
|
||||
if ($color === null) {
|
||||
return $this->color;
|
||||
}
|
||||
if (
|
||||
! is_string($color) ||
|
||||
! in_array($color, Color::colorList())
|
||||
) {
|
||||
throw new \Exception(dgettext(
|
||||
"domframework",
|
||||
"Invalid color provided to graph legend"
|
||||
), 406);
|
||||
}
|
||||
$this->color = $color;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/** Set the background-color of the legend if the parameter is provided.
|
||||
* Get the background-color of the legend if the parameter is not provided
|
||||
* @param string|null $bgcolor The background-color of the legend
|
||||
*/
|
||||
public function bgcolor($bgcolor = null)
|
||||
{
|
||||
if ($bgcolor === null) {
|
||||
return $this->bgcolor;
|
||||
}
|
||||
if (
|
||||
! is_string($bgcolor) ||
|
||||
! in_array($bgcolor, Color::colorList())
|
||||
) {
|
||||
throw new \Exception(dgettext(
|
||||
"domframework",
|
||||
"Invalid bgcolor provided to graph legend"
|
||||
), 406);
|
||||
}
|
||||
$this->bgcolor = $bgcolor;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/** Set the border color of the legend if the parameter is provided.
|
||||
* Get the border color of the legend if the parameter is not provided
|
||||
* @param string|null $borderColor The border color of the legend
|
||||
*/
|
||||
public function borderColor($borderColor = null)
|
||||
{
|
||||
if ($borderColor === null) {
|
||||
return $this->borderColor;
|
||||
}
|
||||
if (
|
||||
! is_string($borderColor) ||
|
||||
! in_array($borderColor, Color::colorList())
|
||||
) {
|
||||
throw new \Exception(dgettext(
|
||||
"domframework",
|
||||
"Invalid borderColor provided to graph legend"
|
||||
), 406);
|
||||
}
|
||||
$this->borderColor = $borderColor;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/** Set the padding of the legend if the parameter is provided.
|
||||
* Get the padding of the legend if the parameter is not provided
|
||||
* @param integer|null $padding The padding of the legend
|
||||
*/
|
||||
public function padding($padding = null)
|
||||
{
|
||||
if ($padding === null) {
|
||||
return $this->padding;
|
||||
}
|
||||
if (! is_integer($padding) || $padding < 0 || $padding > 200) {
|
||||
throw new \Exception(dgettext(
|
||||
"domframework",
|
||||
"Invalid padding provided to graph legend"
|
||||
), 406);
|
||||
}
|
||||
$this->padding = $padding;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/** Draw the legend in the $gd resource provided
|
||||
* @param resource $gd The resource to modify
|
||||
* @param array $free The free space coordinates on the graphic
|
||||
* @param object $series The series to graph
|
||||
* @return array the new free coordinates array
|
||||
*/
|
||||
public function draw($gd, $free, $series)
|
||||
{
|
||||
if ($this->show === false) {
|
||||
return $free;
|
||||
}
|
||||
// Look for maxmimum width of the labels
|
||||
$maxwidth = 0;
|
||||
$height = 0;
|
||||
foreach ($series->getList() as $number => $serie) {
|
||||
$bbox = imagettfbbox($this->fontsize, 0, $this->fontfile, $serie);
|
||||
$width = abs($bbox[4] - $bbox[0]);
|
||||
// TODO : If the serie name is too long, split it !
|
||||
// 20px for the sample + the space before the label
|
||||
if ((20 + $maxwidth) > (($free[2] - $free[0]) / 2)) {
|
||||
throw new \Exception(
|
||||
dgettext(
|
||||
"domframework",
|
||||
"The serie name in legend must not takes more than half of the graph"
|
||||
),
|
||||
500
|
||||
);
|
||||
}
|
||||
if ($number > 0) {
|
||||
$height += $this->padding;
|
||||
}
|
||||
$height += abs($bbox[5] - $bbox[1]);
|
||||
$maxwidth = max($maxwidth, $width);
|
||||
}
|
||||
|
||||
$x1 = $free[2] - $maxwidth - 20 - $this->padding * 2;
|
||||
$x2 = $free[2] - $this->padding;
|
||||
$y1 = $free[1] + $this->padding;
|
||||
$y2 = $y1 + $height + $this->padding;
|
||||
|
||||
// Size of the border : 1px
|
||||
$border = 1;
|
||||
// Draw the background rectangle
|
||||
imagefilledrectangle(
|
||||
$gd,
|
||||
$x1,
|
||||
$y1,
|
||||
$x2,
|
||||
$y2,
|
||||
Color::allocateFromText($gd, $this->borderColor)
|
||||
);
|
||||
imagefilledrectangle(
|
||||
$gd,
|
||||
$x1 + $border,
|
||||
$y1 + $border,
|
||||
$x2 - $border,
|
||||
$y2 - $border,
|
||||
Color::allocateFromText($gd, $this->bgcolor)
|
||||
);
|
||||
|
||||
// Display the serie names
|
||||
$y = $y1;
|
||||
foreach ($series->getList() as $number => $serie) {
|
||||
// Write the label
|
||||
$bbox = imagettfbbox($this->fontsize, 0, $this->fontfile, $serie);
|
||||
$height = abs($bbox[5] - $bbox[1]);
|
||||
$y += $height;
|
||||
imagettftext(
|
||||
$gd,
|
||||
$this->fontsize,
|
||||
0,
|
||||
$x1 + 30,
|
||||
intval($y + $height / 2),
|
||||
Color::allocateFromText($gd, $this->color),
|
||||
$this->fontfile,
|
||||
$serie
|
||||
);
|
||||
// Draw the sample
|
||||
$series->serie($serie)->style()->sample($gd, $x1 + 15, $y);
|
||||
$y += $this->padding;
|
||||
}
|
||||
$free = array($free[0], $free[1], $x1 - 5, $free[3]);
|
||||
return $free;
|
||||
}
|
||||
}
|
||||
40
src/GraphPalette.php
Normal file
40
src/GraphPalette.php
Normal file
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
/** DomFramework
|
||||
* @package domframework
|
||||
* @author Dominique Fournier <dominique@fournier38.fr>
|
||||
* @license BSD
|
||||
*/
|
||||
|
||||
namespace Domframework;
|
||||
|
||||
/** The graphPalette class */
|
||||
class GraphPalette
|
||||
{
|
||||
/** Get the complete palette
|
||||
* @param string $name The palette name to get
|
||||
*/
|
||||
public static function getPalette($name)
|
||||
{
|
||||
$palette = array(
|
||||
"basic" => array(
|
||||
array("bgcolor" => "indianred", "color" => "firebrick"),
|
||||
array("bgcolor" => "lightblue", "color" => "blue"),
|
||||
array("bgcolor" => "peru", "color" => "maroon"),
|
||||
array("bgcolor" => "mediumaquamarine", "color" => "teal"),
|
||||
array("bgcolor" => "orange", "color" => "goldenrod"),
|
||||
array("bgcolor" => "limegreen", "color" => "green"),
|
||||
array("bgcolor" => "darkgrey", "color" => "grey"),
|
||||
array("bgcolor" => "darkyellow1", "color" => "darkyellow2"),
|
||||
array("bgcolor" => "grey", "color" => "black"),
|
||||
),
|
||||
);
|
||||
if (! is_string($name) || ! array_key_exists($name, $palette)) {
|
||||
throw new \Exception(dgettext(
|
||||
"domframework",
|
||||
"Unknown palette name provided"
|
||||
), 406);
|
||||
}
|
||||
return $palette[$name];
|
||||
}
|
||||
}
|
||||
307
src/GraphSerie.php
Normal file
307
src/GraphSerie.php
Normal file
@@ -0,0 +1,307 @@
|
||||
<?php
|
||||
|
||||
/** DomFramework
|
||||
* @package domframework
|
||||
* @author Dominique Fournier <dominique@fournier38.fr>
|
||||
* @license BSD
|
||||
*/
|
||||
|
||||
namespace Domframework;
|
||||
|
||||
/** The serie object */
|
||||
class GraphSerie
|
||||
{
|
||||
/** The name of the serie
|
||||
*/
|
||||
private $name;
|
||||
|
||||
/** The data values for the serie
|
||||
*/
|
||||
private $data;
|
||||
|
||||
/** The numericalKey is true if all the keys are numeric
|
||||
*/
|
||||
private $numericalKey = null;
|
||||
|
||||
/** The minimum key of the serie
|
||||
*/
|
||||
private $minKey = null;
|
||||
|
||||
/** The maximum key of the serie
|
||||
*/
|
||||
private $maxKey = null;
|
||||
|
||||
/** The numericalValue is true if all the values are numeric
|
||||
*/
|
||||
private $numericalValue = null;
|
||||
|
||||
/** The minimum value of the serie
|
||||
*/
|
||||
private $minValue = null;
|
||||
|
||||
/** The maximum value of the serie
|
||||
*/
|
||||
private $maxValue = null;
|
||||
|
||||
/** The style object for the serie
|
||||
*/
|
||||
private $style;
|
||||
/** If set, hide this serie and do not display it
|
||||
*/
|
||||
private $hide;
|
||||
|
||||
/** The axis used to draw the serie.
|
||||
* If false for main Y axis
|
||||
* If true for secondary Y axis
|
||||
*/
|
||||
private $axisYsecondary = false;
|
||||
|
||||
/** When creating the serie, save the name
|
||||
* @param string $name The name of the serie
|
||||
*/
|
||||
public function __construct($name)
|
||||
{
|
||||
if (! is_string($name)) {
|
||||
throw new \Exception(
|
||||
dgettext(
|
||||
"domframework",
|
||||
"Can't create a serie if the name is not a string"
|
||||
),
|
||||
406
|
||||
);
|
||||
}
|
||||
$this->name = $name;
|
||||
}
|
||||
|
||||
/** Set the data for the serie
|
||||
If the parameter is not provided, return the actual $data value
|
||||
* @param array|null $data The data to store in the serie
|
||||
*/
|
||||
public function data($data = null)
|
||||
{
|
||||
if ($data === null) {
|
||||
return $this->data;
|
||||
}
|
||||
if (! is_array($data)) {
|
||||
throw new \Exception(
|
||||
dgettext(
|
||||
"domframework",
|
||||
"Can't create a serie data if the value is not an array"
|
||||
),
|
||||
406
|
||||
);
|
||||
}
|
||||
$this->data = $data;
|
||||
$this->minmax();
|
||||
return $this;
|
||||
}
|
||||
|
||||
/** Get the minimum and maximum values and keys
|
||||
*/
|
||||
private function minmax()
|
||||
{
|
||||
if ($this->data === null) {
|
||||
return null;
|
||||
}
|
||||
foreach ($this->data as $key => $value) {
|
||||
if ($this->minValue === null && is_numeric($value)) {
|
||||
$this->minValue = $value;
|
||||
}
|
||||
if ($this->minKey === null && is_numeric($key)) {
|
||||
$this->minKey = $key;
|
||||
}
|
||||
if (is_numeric($value)) {
|
||||
$this->minValue = min($this->minValue, $value);
|
||||
$this->maxValue = max($this->maxValue, $value);
|
||||
}
|
||||
if (is_numeric($key)) {
|
||||
$this->minKey = min($this->minKey, $key);
|
||||
$this->maxKey = max($this->maxKey, $key);
|
||||
}
|
||||
if (! is_numeric($key) && $this->numericalKey === null) {
|
||||
$this->numericalKey = false;
|
||||
}
|
||||
if (
|
||||
! is_numeric($value) && $value !== null &&
|
||||
$this->numericalValue === null
|
||||
) {
|
||||
$this->numericalValue = false;
|
||||
}
|
||||
}
|
||||
if ($this->numericalKey === null) {
|
||||
$this->numericalKey = true;
|
||||
}
|
||||
if ($this->numericalValue === null) {
|
||||
$this->numericalValue = true;
|
||||
}
|
||||
}
|
||||
|
||||
/** Set/get the numeric value of the serie
|
||||
* If the parameter is not provided, return the actual state
|
||||
* @param boolean|null $numericalValue The state of the numeric value
|
||||
*/
|
||||
public function numericalValue($numericalValue = null)
|
||||
{
|
||||
if ($numericalValue === null) {
|
||||
return $this->numericalValue;
|
||||
}
|
||||
if (! is_bool($numericalValue)) {
|
||||
throw new \Exception(dgettext(
|
||||
"domframework",
|
||||
"Invalid numericalValue provided to serie"
|
||||
), 406);
|
||||
}
|
||||
$this->numericalValue = $numericalValue;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/** The minimum value of the serie
|
||||
*/
|
||||
public function minValue()
|
||||
{
|
||||
if ($this->minValue === null && $this->data !== null) {
|
||||
$this->minmax();
|
||||
}
|
||||
return $this->minValue;
|
||||
}
|
||||
|
||||
/** The maximum value of the serie
|
||||
*/
|
||||
public function maxValue()
|
||||
{
|
||||
if ($this->maxValue === null && $this->data !== null) {
|
||||
$this->minmax();
|
||||
}
|
||||
return $this->maxValue;
|
||||
}
|
||||
|
||||
/** Set/get the numeric key of the serie
|
||||
* If the parameter is not provided, return the actual state
|
||||
* @param boolean|null $numericalKey The state of the numeric key
|
||||
*/
|
||||
public function numericalKey($numericalKey = null)
|
||||
{
|
||||
if ($numericalKey === null) {
|
||||
return $this->numericalKey;
|
||||
}
|
||||
if (! is_bool($numericalKey)) {
|
||||
throw new \Exception(dgettext(
|
||||
"domframework",
|
||||
"Invalid numericalKey provided to serie"
|
||||
), 406);
|
||||
}
|
||||
$this->numericalKey = $numericalKey;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/** The minimum key of the serie
|
||||
*/
|
||||
public function minKey()
|
||||
{
|
||||
if ($this->minKey === null && $this->data !== null) {
|
||||
$this->minmax();
|
||||
}
|
||||
return $this->minKey;
|
||||
}
|
||||
|
||||
/** The maximum key of the serie
|
||||
*/
|
||||
public function maxKey()
|
||||
{
|
||||
if ($this->maxKey === null && $this->data !== null) {
|
||||
$this->minmax();
|
||||
}
|
||||
return $this->maxKey;
|
||||
}
|
||||
|
||||
/** The number of elements in the serie
|
||||
*/
|
||||
public function count()
|
||||
{
|
||||
return count($this->data);
|
||||
}
|
||||
|
||||
/** Set/Get the graph style for the serie
|
||||
* If the parameter is not provided, return the actual state
|
||||
* @param string|object|null $style The graph style
|
||||
*/
|
||||
public function style($style = null)
|
||||
{
|
||||
if ($style === null) {
|
||||
return $this->style;
|
||||
}
|
||||
if (is_object($style)) {
|
||||
$this->style = clone $style;
|
||||
return $this->style;
|
||||
}
|
||||
if (
|
||||
! is_string($style) ||
|
||||
! in_array($style, array("line", "points", "linePoints"))
|
||||
) {
|
||||
throw new \Exception(dgettext(
|
||||
"domframework",
|
||||
"Invalid style provided to serie"
|
||||
), 406);
|
||||
}
|
||||
$styleClass = "GraphStyle" . $style;
|
||||
if ($this->style === null) {
|
||||
$this->style = new $styleClass();
|
||||
}
|
||||
return $this->style;
|
||||
}
|
||||
/** Set/Get the hidden state of the serie
|
||||
* If the parameter is not provided, return the actual state
|
||||
* @param boolean|null $hide The hidden state
|
||||
*/
|
||||
public function hide($hide = null)
|
||||
{
|
||||
if ($hide === null) {
|
||||
return $this->hide;
|
||||
}
|
||||
if (! is_bool($hide)) {
|
||||
throw new \Exception(dgettext(
|
||||
"domframework",
|
||||
"Invalid hide mode provided to serie"
|
||||
), 406);
|
||||
}
|
||||
$this->hide = $hide;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/** The serie is based on the secondary Y axis
|
||||
* Set the value if the parameter is provided, get the value if the parameter
|
||||
* is not set
|
||||
* @param boolean|null $axisYsecondary The Serie on secondary Y axis
|
||||
*/
|
||||
public function axisYsecondary($axisYsecondary = null)
|
||||
{
|
||||
if ($axisYsecondary === null) {
|
||||
return $this->axisYsecondary;
|
||||
}
|
||||
if (! is_bool($axisYsecondary)) {
|
||||
throw new \Exception(
|
||||
dgettext(
|
||||
"domframework",
|
||||
"Invalid axisYsecondary provided to graph axisYsecondary"
|
||||
),
|
||||
406
|
||||
);
|
||||
}
|
||||
$this->axisYsecondary = $axisYsecondary;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/** Draw the serie with the defined style class
|
||||
* @param resource $gd The resource to modify
|
||||
* @param array $free The free space coordinates on the graphic
|
||||
* @param object $axisX The axis X used on the graph
|
||||
* @param object $axisY The axis Y used on the graph
|
||||
*/
|
||||
public function draw($gd, $free, $axisX, $axisY)
|
||||
{
|
||||
if ($this->hide === true) {
|
||||
return;
|
||||
}
|
||||
$this->style->draw($gd, $free, $this->data, $axisX, $axisY);
|
||||
}
|
||||
}
|
||||
73
src/GraphSeries.php
Normal file
73
src/GraphSeries.php
Normal file
@@ -0,0 +1,73 @@
|
||||
<?php
|
||||
|
||||
/** DomFramework
|
||||
* @package domframework
|
||||
* @author Dominique Fournier <dominique@fournier38.fr>
|
||||
* @license BSD
|
||||
*/
|
||||
|
||||
namespace Domframework;
|
||||
|
||||
/** The series objects */
|
||||
class GraphSeries
|
||||
{
|
||||
/** The series stored */
|
||||
private $series = array();
|
||||
|
||||
/** Return the serie object choosed. If doesn't exists, it is created before
|
||||
* be returned
|
||||
* @param string $name The name of the serie to create
|
||||
*/
|
||||
public function serie($name)
|
||||
{
|
||||
if (is_integer($name)) {
|
||||
$name = dgettext("domframework", "Serie") . " $name";
|
||||
}
|
||||
if (! is_string($name)) {
|
||||
throw new \Exception(
|
||||
dgettext(
|
||||
"domframework",
|
||||
"Can't get a serie if the name is not a string"
|
||||
),
|
||||
406
|
||||
);
|
||||
}
|
||||
if (! array_key_exists($name, $this->series)) {
|
||||
$this->series[$name] = new GraphSerie($name);
|
||||
}
|
||||
return $this->series[$name];
|
||||
}
|
||||
|
||||
/** Get the list of the defined series
|
||||
*/
|
||||
public function getList()
|
||||
{
|
||||
$series = [];
|
||||
foreach ($this->series as $name => $serie) {
|
||||
if ($serie->hide() === true) {
|
||||
continue;
|
||||
}
|
||||
$series[] = $name;
|
||||
}
|
||||
return $series;
|
||||
}
|
||||
|
||||
/** Remove an existing serie
|
||||
* @param string $name The name of the serie to remove
|
||||
*/
|
||||
public function remove($name)
|
||||
{
|
||||
if (! is_string($name)) {
|
||||
throw new \Exception(
|
||||
dgettext(
|
||||
"domframework",
|
||||
"Can't remove a serie if the name is not a string"
|
||||
),
|
||||
406
|
||||
);
|
||||
}
|
||||
if (array_key_exists($name, $this->series)) {
|
||||
unset($this->series[$name]);
|
||||
}
|
||||
}
|
||||
}
|
||||
27
src/GraphStyleLine.php
Normal file
27
src/GraphStyleLine.php
Normal file
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
/** DomFramework
|
||||
* @package domframework
|
||||
* @author Dominique Fournier <dominique@fournier38.fr>
|
||||
* @license BSD
|
||||
*/
|
||||
|
||||
namespace Domframework;
|
||||
|
||||
/** The graphStyleLine : draw a graph with line */
|
||||
class GraphStyleLine extends GraphStyleLinePoints
|
||||
{
|
||||
/** The point color background. To hide the points, choose "transparent"
|
||||
*/
|
||||
protected $pointBgcolor = "transparent";
|
||||
|
||||
/** The point color border
|
||||
*/
|
||||
protected $pointColor = "transparent";
|
||||
|
||||
/** Return the name of the style */
|
||||
public function name()
|
||||
{
|
||||
return "line";
|
||||
}
|
||||
}
|
||||
393
src/GraphStyleLinePoints.php
Normal file
393
src/GraphStyleLinePoints.php
Normal file
@@ -0,0 +1,393 @@
|
||||
<?php
|
||||
|
||||
/** DomFramework
|
||||
* @package domframework
|
||||
* @author Dominique Fournier <dominique@fournier38.fr>
|
||||
* @license BSD
|
||||
*/
|
||||
|
||||
namespace Domframework;
|
||||
|
||||
/** The graphStyleLine : draw a graph with lines */
|
||||
class GraphStyleLinePoints
|
||||
{
|
||||
/** The line color. To hide the lines, choose "transparent"
|
||||
*/
|
||||
protected $lineColor;
|
||||
|
||||
/** The point color background. To hide the points, choose "transparent"
|
||||
*/
|
||||
protected $pointBgcolor;
|
||||
|
||||
/** The point color border
|
||||
*/
|
||||
protected $pointColor;
|
||||
|
||||
/** The point shape (square, circle, triangle, lozenge)
|
||||
*/
|
||||
protected $pointShape;
|
||||
|
||||
/** The point width in pixel
|
||||
*/
|
||||
protected $pointWidth;
|
||||
|
||||
/** The number of the colors/shapes to use
|
||||
*/
|
||||
protected $number;
|
||||
|
||||
/** The allowed shapes */
|
||||
protected $allowedShapes = array("square", "circle", "triangle", "lozenge");
|
||||
|
||||
/** The palette to use */
|
||||
protected $palette;
|
||||
|
||||
/** Return the name of the style */
|
||||
public function name()
|
||||
{
|
||||
return "lineAndPoints";
|
||||
}
|
||||
|
||||
/** Set the line color if the parameter is provided.
|
||||
* Get the line color if the parameter is not provided
|
||||
* @param string|null $lineColor The line color
|
||||
*/
|
||||
public function lineColor($lineColor = null)
|
||||
{
|
||||
if ($lineColor === null) {
|
||||
return $this->lineColor;
|
||||
}
|
||||
if (
|
||||
! is_string($lineColor) ||
|
||||
($lineColor !== "transparent" &&
|
||||
! in_array($lineColor, Color::colorList()))
|
||||
) {
|
||||
throw new \Exception(dgettext(
|
||||
"domframework",
|
||||
"Invalid lineColor provided to line style"
|
||||
), 406);
|
||||
}
|
||||
$this->lineColor = $lineColor;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/** Set the palette to use if the parameter is provided
|
||||
* Get the palette if the parameter is not provided
|
||||
* @param string|null $palette The palette to use
|
||||
*/
|
||||
public function palette($palette = null)
|
||||
{
|
||||
if ($palette === null) {
|
||||
return $this->palette;
|
||||
}
|
||||
if (! is_string($palette)) {
|
||||
throw new \Exception(dgettext(
|
||||
"domframework",
|
||||
"Invalid palette provided to line style"
|
||||
), 406);
|
||||
}
|
||||
$this->palette = $palette;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/** Set the point background color if the parameter is provided.
|
||||
* Get the point background color if the parameter is not provided
|
||||
* @param string|null $pointBgcolor The point background color
|
||||
*/
|
||||
public function pointBgcolor($pointBgcolor = null)
|
||||
{
|
||||
if ($pointBgcolor === null) {
|
||||
return $this->pointBgcolor;
|
||||
}
|
||||
if (
|
||||
! is_string($pointBgcolor) ||
|
||||
($pointBgcolor !== "transparent" &&
|
||||
! in_array($pointBgcolor, Color::colorList()))
|
||||
) {
|
||||
throw new \Exception(dgettext(
|
||||
"domframework",
|
||||
"Invalid pointBgcolor provided to line style"
|
||||
), 406);
|
||||
}
|
||||
$this->pointBgcolor = $pointBgcolor;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/** Set the point border color if the parameter is provided.
|
||||
* Get the point border color if the parameter is not provided
|
||||
* @param string|null $pointColor The point border color
|
||||
*/
|
||||
public function pointColor($pointColor = null)
|
||||
{
|
||||
if ($pointColor === null) {
|
||||
return $this->pointColor;
|
||||
}
|
||||
if (
|
||||
! is_string($pointColor) ||
|
||||
($pointColor !== "transparent" &&
|
||||
! in_array($pointColor, Color::colorList()))
|
||||
) {
|
||||
throw new \Exception(dgettext(
|
||||
"domframework",
|
||||
"Invalid pointColor provided to line style"
|
||||
), 406);
|
||||
}
|
||||
$this->pointColor = $pointColor;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/** Set the point shape if the parameter is provided.
|
||||
* Get the point shape if the parameter is not provided
|
||||
* @param string|null $pointShape The point shape
|
||||
*/
|
||||
public function pointShape($pointShape = null)
|
||||
{
|
||||
if ($pointShape === null) {
|
||||
return $this->pointShape;
|
||||
}
|
||||
if (
|
||||
! is_string($pointShape) ||
|
||||
! in_array($pointShape, $this->allowedShapes)
|
||||
) {
|
||||
throw new \Exception(dgettext(
|
||||
"domframework",
|
||||
"Invalid pointShape provided to line style"
|
||||
), 406);
|
||||
}
|
||||
$this->pointShape = $pointShape;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/** Set the point width if the parameter is provided.
|
||||
* Get the point width if the parameter is not provided
|
||||
* @param string|null $pointWidth The point width
|
||||
*/
|
||||
public function pointWidth($pointWidth = null)
|
||||
{
|
||||
if ($pointWidth === null) {
|
||||
return $this->pointWidth;
|
||||
}
|
||||
if (! is_integer($pointWidth) || $pointWidth < 3 || $pointWidth > 20) {
|
||||
throw new \Exception(dgettext(
|
||||
"domframework",
|
||||
"Invalid pointWidth provided to line style"
|
||||
), 406);
|
||||
}
|
||||
$this->pointWidth = $pointWidth;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/** Select the colors, shapes by the serie number.
|
||||
* Do not change any property if the property is already defined
|
||||
* If the parameter is not provided, return the value
|
||||
* @param integer|null $number The serie number
|
||||
*/
|
||||
public function number($number = null)
|
||||
{
|
||||
if ($number === null) {
|
||||
return $this->number;
|
||||
}
|
||||
if (! is_int($number) || $number < 0) {
|
||||
throw new \Exception(dgettext(
|
||||
"domframework",
|
||||
"Invalid number provided to line style number"
|
||||
), 406);
|
||||
}
|
||||
$this->number = $number;
|
||||
if ($this->pointShape === null) {
|
||||
$this->pointShape = $this->allowedShapes[
|
||||
($number % count($this->allowedShapes))];
|
||||
}
|
||||
$palette = graphPalette::getPalette($this->palette);
|
||||
if ($this->pointBgcolor === null) {
|
||||
$this->pointBgcolor = $palette[($number % count($palette))]["bgcolor"];
|
||||
}
|
||||
if ($this->pointColor === null) {
|
||||
$this->pointColor = $palette[($number % count($palette))]["color"];
|
||||
}
|
||||
if ($this->lineColor === null) {
|
||||
$this->lineColor = $palette[($number % count($palette))]["color"];
|
||||
}
|
||||
}
|
||||
|
||||
/** Draw in the $gd resource, in the $free array, the data with the parameter
|
||||
* of the style
|
||||
* @param resource $gd The resource to modify
|
||||
* @param array $free The free space coordinates on the graphic
|
||||
* @param array $data The data to graph
|
||||
* @param object $axisX The X axis used to graph
|
||||
* @param object $axisY The Y axis used to graph
|
||||
*/
|
||||
public function draw($gd, $free, $data, $axisX, $axisY)
|
||||
{
|
||||
if ($this->lineColor !== "transparent") {
|
||||
$lineColor = Color::allocateFromText($gd, $this->lineColor);
|
||||
}
|
||||
$lastX = null;
|
||||
$lastY = null;
|
||||
foreach ($data as $key => $value) {
|
||||
$posX = $axisX->position($key);
|
||||
$posY = $axisY->position($value);
|
||||
if ($posX === null || $posY === null) {
|
||||
// NULL position : skip the point
|
||||
$lastX = null;
|
||||
$lastY = null;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Draw the lines between points (except if the last point was null, or
|
||||
// if the line color is "transparent")
|
||||
if (
|
||||
$lastX !== null && $lastY !== null &&
|
||||
$this->lineColor !== "transparent"
|
||||
) {
|
||||
imageline($gd, $lastX, $lastY, $posX, $posY, $lineColor);
|
||||
// Redraw the old point which was scratch by the new created line
|
||||
$this->drawPoint($gd, $lastX, $lastY);
|
||||
}
|
||||
if ($lastX === null) {
|
||||
$lastX = $posX;
|
||||
}
|
||||
if ($lastY === null) {
|
||||
$lastY = $posY;
|
||||
}
|
||||
|
||||
// Draw the point. Will overwrite the lines
|
||||
if ($this->pointWidth === null) {
|
||||
$this->pointWidth = 6;
|
||||
}
|
||||
$this->drawPoint($gd, $posX, $posY);
|
||||
$lastX = $posX;
|
||||
$lastY = $posY;
|
||||
}
|
||||
}
|
||||
|
||||
/** Draw a point defined in the property of the class
|
||||
* @param resource $gd The resource to modify
|
||||
* @param integer $posX The X position to draw the point
|
||||
* @param integer $posY The Y position to draw the point
|
||||
*/
|
||||
private function drawPoint($gd, $posX, $posY)
|
||||
{
|
||||
if ($this->pointColor !== "transparent") {
|
||||
$pointColor = Color::allocateFromText($gd, $this->pointColor);
|
||||
}
|
||||
if ($this->pointBgcolor !== "transparent") {
|
||||
$pointBgcolor = Color::allocateFromText($gd, $this->pointBgcolor);
|
||||
}
|
||||
$half = intval($this->pointWidth / 2);
|
||||
switch ($this->pointShape) {
|
||||
case "circle":
|
||||
if ($this->pointBgcolor !== "transparent") {
|
||||
imagefilledellipse(
|
||||
$gd,
|
||||
$posX,
|
||||
$posY,
|
||||
$this->pointWidth,
|
||||
$this->pointWidth,
|
||||
$pointBgcolor + 2
|
||||
);
|
||||
}
|
||||
if ($this->pointColor !== "transparent") {
|
||||
imageellipse(
|
||||
$gd,
|
||||
$posX,
|
||||
$posY,
|
||||
$this->pointWidth + 2,
|
||||
$this->pointWidth + 2,
|
||||
$pointColor
|
||||
);
|
||||
}
|
||||
break;
|
||||
case "lozenge":
|
||||
if ($this->pointBgcolor !== "transparent") {
|
||||
imagefilledpolygon(
|
||||
$gd,
|
||||
array($posX - $half - 2, $posY,
|
||||
$posX, $posY - $half - 2,
|
||||
$posX + $half + 2, $posY,
|
||||
$posX, $posY + $half + 2),
|
||||
4,
|
||||
$pointBgcolor
|
||||
);
|
||||
}
|
||||
if ($this->pointColor !== "transparent") {
|
||||
imagepolygon(
|
||||
$gd,
|
||||
array($posX - $half - 2, $posY,
|
||||
$posX, $posY - $half - 2,
|
||||
$posX + $half + 2, $posY,
|
||||
$posX, $posY + $half + 2),
|
||||
4,
|
||||
$pointColor
|
||||
);
|
||||
}
|
||||
break;
|
||||
case "square":
|
||||
if ($this->pointBgcolor !== "transparent") {
|
||||
imagefilledrectangle(
|
||||
$gd,
|
||||
$posX - $half - 1,
|
||||
$posY - $half - 1,
|
||||
$posX + $half + 1,
|
||||
$posY + $half + 1,
|
||||
$pointBgcolor
|
||||
);
|
||||
}
|
||||
if ($this->pointColor !== "transparent") {
|
||||
imagerectangle(
|
||||
$gd,
|
||||
$posX - $half - 1,
|
||||
$posY - $half - 1,
|
||||
$posX + $half + 1,
|
||||
$posY + $half + 1,
|
||||
$pointColor
|
||||
);
|
||||
}
|
||||
break;
|
||||
case "triangle":
|
||||
if ($this->pointBgcolor !== "transparent") {
|
||||
imagefilledpolygon(
|
||||
$gd,
|
||||
array($posX - $half - 2, $posY + $half + 2,
|
||||
$posX, $posY - $half - 2,
|
||||
$posX + $half + 2, $posY + $half + 2),
|
||||
3,
|
||||
$pointBgcolor
|
||||
);
|
||||
}
|
||||
if ($this->pointColor !== "transparent") {
|
||||
imagepolygon(
|
||||
$gd,
|
||||
array($posX - $half - 2, $posY + $half + 2,
|
||||
$posX, $posY - $half - 2,
|
||||
$posX + $half + 2, $posY + $half + 2),
|
||||
3,
|
||||
$pointColor
|
||||
);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new \Exception(dgettext(
|
||||
"domframework",
|
||||
"Unknown pointShape for serie"
|
||||
), 406);
|
||||
}
|
||||
}
|
||||
|
||||
/** Draw a sample of the style for the legend
|
||||
* @param resource $gd The resource to modify
|
||||
* @param integer $x The central position of the sample in x
|
||||
* @param integer $y The central position of the sample in y
|
||||
*/
|
||||
public function sample($gd, $x, $y)
|
||||
{
|
||||
if ($this->lineColor !== "transparent") {
|
||||
$lineColor = Color::allocateFromText($gd, $this->lineColor);
|
||||
imageline($gd, $x - 10, $y, $x + 10, $y, $lineColor);
|
||||
}
|
||||
if ($this->pointWidth === null) {
|
||||
$this->pointWidth = 6;
|
||||
}
|
||||
$this->drawPoint($gd, $x, $y);
|
||||
}
|
||||
}
|
||||
23
src/GraphStylePoints.php
Normal file
23
src/GraphStylePoints.php
Normal file
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
/** DomFramework
|
||||
* @package domframework
|
||||
* @author Dominique Fournier <dominique@fournier38.fr>
|
||||
* @license BSD
|
||||
*/
|
||||
|
||||
namespace Domframework;
|
||||
|
||||
/** The graphStylePoints : draw a graph with points */
|
||||
class GraphStylePoints extends GraphStyleLinePoints
|
||||
{
|
||||
/** The line color : transparent
|
||||
*/
|
||||
protected $lineColor = "transparent";
|
||||
|
||||
/** Return the name of the style */
|
||||
public function name()
|
||||
{
|
||||
return "points";
|
||||
}
|
||||
}
|
||||
167
src/GraphTitle.php
Normal file
167
src/GraphTitle.php
Normal file
@@ -0,0 +1,167 @@
|
||||
<?php
|
||||
|
||||
/** DomFramework
|
||||
* @package domframework
|
||||
* @author Dominique Fournier <dominique@fournier38.fr>
|
||||
* @license BSD
|
||||
*/
|
||||
|
||||
namespace Domframework;
|
||||
|
||||
/** The graphTitle object */
|
||||
class GraphTitle
|
||||
{
|
||||
/** The title text
|
||||
*/
|
||||
private $text = null;
|
||||
|
||||
/** The TTF fontfile to use
|
||||
*/
|
||||
private $fontfile = null;
|
||||
|
||||
/** The font size to use
|
||||
*/
|
||||
private $fontsize = 14;
|
||||
|
||||
/** The title color
|
||||
*/
|
||||
private $color = "black";
|
||||
|
||||
/** The padding arround the title (in px)
|
||||
*/
|
||||
private $padding = 10;
|
||||
|
||||
/** Set the text of the title if the parameter is provided.
|
||||
* Get the text of the title if the parameter is not provided
|
||||
* @param string|null $text The text of the title
|
||||
*/
|
||||
public function text($text = null)
|
||||
{
|
||||
if ($text === null) {
|
||||
return $this->text;
|
||||
}
|
||||
if (! is_string($text) || strlen($text) < 0 || strlen($text) > 50) {
|
||||
throw new \Exception(dgettext(
|
||||
"domframework",
|
||||
"Invalid text provided to graph title"
|
||||
), 406);
|
||||
}
|
||||
$this->text = $text;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/** Set the fontfile of the title if the parameter is provided.
|
||||
* Get the fontfile of the title if the parameter is not provided
|
||||
* @param string|null $fontfile The fontfile of the title
|
||||
*/
|
||||
public function fontfile($fontfile = null)
|
||||
{
|
||||
if ($fontfile === null) {
|
||||
return $this->fontfile;
|
||||
}
|
||||
if (
|
||||
! is_string($fontfile) || strlen($fontfile) < 0 ||
|
||||
! file_exists($fontfile) || ! is_readable($fontfile)
|
||||
) {
|
||||
throw new \Exception(dgettext(
|
||||
"domframework",
|
||||
"Invalid fontfile provided to graph title"
|
||||
), 406);
|
||||
}
|
||||
$this->fontfile = $fontfile;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/** Set the font size of the title if the parameter is provided.
|
||||
* Get the font size of the title if the parameter is not provided
|
||||
* @param integer|null $fontsize The font size of the title
|
||||
*/
|
||||
public function fontsize($fontsize = null)
|
||||
{
|
||||
if ($fontsize === null) {
|
||||
return $this->fontsize;
|
||||
}
|
||||
if (! is_integer($fontsize) || $fontsize < 2 || $fontsize > 100) {
|
||||
throw new \Exception(dgettext(
|
||||
"domframework",
|
||||
"Invalid fontsize provided to graph title"
|
||||
), 406);
|
||||
}
|
||||
$this->fontsize = $fontsize;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/** Set the color of the title if the parameter is provided.
|
||||
* Get the color of the title if the parameter is not provided
|
||||
* @param string|null $color The color of the title
|
||||
*/
|
||||
public function color($color = null)
|
||||
{
|
||||
if ($color === null) {
|
||||
return $this->color;
|
||||
}
|
||||
if (
|
||||
! is_string($color) ||
|
||||
! in_array($color, Color::colorList())
|
||||
) {
|
||||
throw new \Exception(dgettext(
|
||||
"domframework",
|
||||
"Invalid color provided to graph title"
|
||||
), 406);
|
||||
}
|
||||
$this->color = $color;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/** Set the padding of the title if the parameter is provided.
|
||||
* Get the padding of the title if the parameter is not provided
|
||||
* @param integer|null $padding The padding of the title
|
||||
*/
|
||||
public function padding($padding = null)
|
||||
{
|
||||
if ($padding === null) {
|
||||
return $this->padding;
|
||||
}
|
||||
if (! is_integer($padding) || $padding < 0 || $padding > 200) {
|
||||
throw new \Exception(dgettext(
|
||||
"domframework",
|
||||
"Invalid padding provided to graph title"
|
||||
), 406);
|
||||
}
|
||||
$this->padding = $padding;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/** Draw the title in the $gd resource provided
|
||||
* @param resource $gd The resource to modify
|
||||
* @param array $free The free space coordinates on the graphic
|
||||
* @return array the new free coordinates array
|
||||
*/
|
||||
public function draw($gd, $free)
|
||||
{
|
||||
if ($this->text === null) {
|
||||
return $free;
|
||||
}
|
||||
// Look for the bounding box around the text. The bounding is not write on
|
||||
// the image and return the coordinates for the text box
|
||||
$bbox = imagettfbbox($this->fontsize, 0, $this->fontfile, $this->text);
|
||||
// Calculate the position of the text to be centered on the graph
|
||||
// The padding is only on vertical : the x is centered
|
||||
$x = floor(($free[2] - $free[0] - abs($bbox[4] - $bbox[0])) / 2);
|
||||
$y = ceil($free[1] + abs($bbox[5] - $bbox[1])) + $this->padding;
|
||||
$x += $free[0];
|
||||
$y += $free[1];
|
||||
imagettftext(
|
||||
$gd,
|
||||
$this->fontsize,
|
||||
0,
|
||||
$x,
|
||||
$y,
|
||||
Color::allocateFromText($gd, $this->color),
|
||||
$this->fontfile,
|
||||
$this->text
|
||||
);
|
||||
return array(intval($free[0]), intval($free[1] + $y + $this->padding),
|
||||
intval($free[2]), intval($free[3]));
|
||||
}
|
||||
}
|
||||
64
src/HttpConnection.php
Normal file
64
src/HttpConnection.php
Normal file
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
|
||||
/** DomFramework
|
||||
* @package domframework
|
||||
* @author Dominique Fournier <dominique@fournier38.fr>
|
||||
* @license BSD
|
||||
*/
|
||||
|
||||
namespace Domframework;
|
||||
|
||||
/**
|
||||
* Manage the HTTP Connections.
|
||||
* Used by HttpServer
|
||||
*/
|
||||
class HttpConnection
|
||||
{
|
||||
private $tcpserver;
|
||||
private $clientAddress;
|
||||
private $clientPort;
|
||||
private $localAddress;
|
||||
private $localPort;
|
||||
private $logger;
|
||||
|
||||
public function __construct($tcpserver)
|
||||
{
|
||||
$this->tcpserver = $tcpserver;
|
||||
list($clientAddress, $clientPort, $localAddress, $localPort) =
|
||||
$tcpserver->getInfo();
|
||||
// If the address is in IPv4 in IPv6 (syntax : "::ffff:127.0.0.1"),
|
||||
// update it to IPv4 only
|
||||
if (substr($clientAddress, 0, 7) === "::ffff:") {
|
||||
$clientAddress = substr($clientAddress, 7);
|
||||
}
|
||||
$this->clientAddress = $clientAddress;
|
||||
$this->clientPort = $clientPort;
|
||||
$this->localAddress = $localAddress;
|
||||
$this->localPort = $localPort;
|
||||
echo "OK : $localAddress:$localPort";
|
||||
}
|
||||
|
||||
public function __destruct()
|
||||
{
|
||||
}
|
||||
|
||||
public function getClientAddress()
|
||||
{
|
||||
return $this->clientAddress;
|
||||
}
|
||||
|
||||
public function getClientPort()
|
||||
{
|
||||
return $this->clientPort;
|
||||
}
|
||||
|
||||
public function getLocalAddress()
|
||||
{
|
||||
return $this->localAddress;
|
||||
}
|
||||
|
||||
public function getLocalPort()
|
||||
{
|
||||
return $this->localPort;
|
||||
}
|
||||
}
|
||||
144
src/Httpserver.php
Normal file
144
src/Httpserver.php
Normal file
@@ -0,0 +1,144 @@
|
||||
<?php
|
||||
|
||||
/** DomFramework
|
||||
* @package domframework
|
||||
* @author Dominique Fournier <dominique@fournier38.fr>
|
||||
* @license BSD
|
||||
*/
|
||||
|
||||
namespace Domframework;
|
||||
|
||||
/**
|
||||
* Create a HTTP server easily
|
||||
* The server can listen on multiple IP addresses and multiple ports.
|
||||
*
|
||||
* Need HttpConnection
|
||||
*/
|
||||
class Httpserver
|
||||
{
|
||||
private $tcpserver;
|
||||
private $listeners = array();
|
||||
private $runningUser;
|
||||
private $runningGroup;
|
||||
private $logger;
|
||||
private $maxConnection = 500;
|
||||
private $timeout = 30;
|
||||
|
||||
/** Add a new listener. Must all be set before entering in loop
|
||||
* @param string $ip The Listening IP Address
|
||||
* @param integer $port the Listening port
|
||||
* @param callable $callable The method called when a new request enter
|
||||
*/
|
||||
public function addListener($ip, $port, $callable)
|
||||
{
|
||||
$ipaddresses = new Ipaddresses();
|
||||
if (! $ipaddresses->validIPAddress($ip)) {
|
||||
throw new \Exception(
|
||||
"Httpserver : invalid IP address provided to listen",
|
||||
500
|
||||
);
|
||||
}
|
||||
if (
|
||||
! is_numeric($port) || ! ctype_digit($port) || $port < 0 ||
|
||||
$port > 65535
|
||||
) {
|
||||
throw new \Exception(
|
||||
"Httpserver : invalid port provided to listen " .
|
||||
"(must be between 0 and 65535)",
|
||||
500
|
||||
);
|
||||
}
|
||||
if (! is_callable($callable)) {
|
||||
throw new \Exception(
|
||||
"Httpserver : invalid callable function provided to listen " .
|
||||
"(must be callable)",
|
||||
500
|
||||
);
|
||||
}
|
||||
foreach ($this->listeners as $listener) {
|
||||
if ($listener["ip"] === $ip && $listener["port"] === $port) {
|
||||
throw new \Exception("Httpserver : can not add multiple listeners on " .
|
||||
"the same couple IP/Port", 500);
|
||||
}
|
||||
}
|
||||
$this->listeners[] = ["ip" => $ip,
|
||||
"port" => $port,
|
||||
"callable" => $callable];
|
||||
return $this;
|
||||
}
|
||||
|
||||
private function setLogger($logger)
|
||||
{
|
||||
$this->logger = $logger;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getMaxConnection()
|
||||
{
|
||||
return $this->maxConnection;
|
||||
}
|
||||
|
||||
public function setMaxConnection($maxConnection)
|
||||
{
|
||||
$this->maxConnection = $maxConnection;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getTimeout()
|
||||
{
|
||||
return $this->timeout;
|
||||
}
|
||||
|
||||
public function setTimeout($timeout)
|
||||
{
|
||||
$this->timeout = $timeout;
|
||||
return $this;
|
||||
}
|
||||
public function getRunningUser()
|
||||
{
|
||||
return $this->runningUser;
|
||||
}
|
||||
|
||||
public function setRunningUser($user)
|
||||
{
|
||||
$this->runningUser = $user;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getRunningGroup()
|
||||
{
|
||||
return $this->runningGroup;
|
||||
}
|
||||
|
||||
public function setRunningGroup($group)
|
||||
{
|
||||
$this->runningGroup = $group;
|
||||
return $this;
|
||||
}
|
||||
|
||||
final public function loop()
|
||||
{
|
||||
$tcpserver = new Tcpserver();
|
||||
if (empty($this->listeners)) {
|
||||
throw new \Exception("Httpserver : No listener defined");
|
||||
}
|
||||
foreach ($this->listeners as $listener) {
|
||||
$tcpserver->init($listener["ip"], $listener["port"], [$this, "connect"]);
|
||||
}
|
||||
$tcpserver->maxChild($this->maxConnection);
|
||||
$tcpserver->loop();
|
||||
}
|
||||
|
||||
final public function connect($tcpserver)
|
||||
{
|
||||
if ($this->runningUser) {
|
||||
$user = posix_getpwnam($this->runningUser);
|
||||
posix_setuid($user['uid']);
|
||||
}
|
||||
if ($this->runningGroup) {
|
||||
$group = posix_getgrnam($this->runningGroup);
|
||||
posix_setgid($group['gid']);
|
||||
}
|
||||
$httpConnection = new HttpConnection($tcpserver);
|
||||
}
|
||||
}
|
||||
196
src/RssItem.php
Normal file
196
src/RssItem.php
Normal file
@@ -0,0 +1,196 @@
|
||||
<?php
|
||||
|
||||
/** DomFramework
|
||||
* @package domframework
|
||||
* @author Dominique Fournier <dominique@fournier38.fr>
|
||||
* @license BSD
|
||||
*/
|
||||
|
||||
namespace Domframework;
|
||||
|
||||
/**
|
||||
* This class manage one RSS Item
|
||||
*
|
||||
* Called by Rss
|
||||
*/
|
||||
class RssItem
|
||||
{
|
||||
/** The title of the item
|
||||
*/
|
||||
private $title;
|
||||
|
||||
/** The URL of the item
|
||||
*/
|
||||
private $link;
|
||||
|
||||
/** The item synopsis
|
||||
*/
|
||||
private $description;
|
||||
|
||||
/** Email address of the author of the item
|
||||
*/
|
||||
private $author;
|
||||
|
||||
/** URL of a page for comments relating to the item
|
||||
*/
|
||||
private $comments;
|
||||
|
||||
/** A string that uniquely identifies the item
|
||||
*/
|
||||
private $guid;
|
||||
|
||||
/** Indicates when the item was published
|
||||
*/
|
||||
private $pubDate;
|
||||
|
||||
/** Get/Set the value
|
||||
* @param string|null $title The title to get/set
|
||||
*/
|
||||
public function title($title = null)
|
||||
{
|
||||
if ($title === null) {
|
||||
return $this->title;
|
||||
}
|
||||
if (! is_string($title)) {
|
||||
throw new \Exception("Title provided to RSS Item is not a string", 500);
|
||||
}
|
||||
if ($title === "") {
|
||||
$title = null;
|
||||
}
|
||||
$this->title = $title;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/** Get/Set the value
|
||||
* @param string|null $link The link to get/set
|
||||
*/
|
||||
public function link($link = null)
|
||||
{
|
||||
if ($link === null) {
|
||||
return $this->link;
|
||||
}
|
||||
if (! is_string($link)) {
|
||||
throw new \Exception("Link provided to RSS Item is not a string", 500);
|
||||
}
|
||||
$verify = new Verify();
|
||||
if (! $verify->is_URL($link)) {
|
||||
throw new \Exception("Link provided to RSS Item is not an URL", 500);
|
||||
}
|
||||
if ($link === "") {
|
||||
$link = null;
|
||||
}
|
||||
$this->link = $link;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/** Get/Set the value
|
||||
* @param string|null $description The description to get/set
|
||||
*/
|
||||
public function description($description = null)
|
||||
{
|
||||
if ($description === null) {
|
||||
return $this->description;
|
||||
}
|
||||
if (! is_string($description)) {
|
||||
throw new \Exception(
|
||||
"Description provided to RSS Item is not a string",
|
||||
500
|
||||
);
|
||||
}
|
||||
if ($description === "") {
|
||||
$description = null;
|
||||
}
|
||||
$this->description = $description;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/** Get/Set the value
|
||||
* @param string|null $author The author to get/set
|
||||
*/
|
||||
public function author($author = null)
|
||||
{
|
||||
if ($author === null) {
|
||||
return $this->author;
|
||||
}
|
||||
if (! is_string($author)) {
|
||||
throw new \Exception("Author provided to RSS Item is not a string", 500);
|
||||
}
|
||||
if ($author === "") {
|
||||
$author = null;
|
||||
}
|
||||
$this->author = $author;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/** Get/Set the value
|
||||
* @param string|null $comments The comments to get/set
|
||||
*/
|
||||
public function comments($comments = null)
|
||||
{
|
||||
if ($comments === null) {
|
||||
return $this->comments;
|
||||
}
|
||||
if (! is_string($comments)) {
|
||||
throw new \Exception(
|
||||
"Comments provided to RSS Item is not a string",
|
||||
500
|
||||
);
|
||||
}
|
||||
if ($comments === "") {
|
||||
$comments = null;
|
||||
}
|
||||
$this->comments = $comments;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/** Get/Set the value
|
||||
* @param string|null $guid The guid to get/set
|
||||
*/
|
||||
public function guid($guid = null)
|
||||
{
|
||||
if ($guid === null) {
|
||||
return $this->guid;
|
||||
}
|
||||
if (! is_string($guid)) {
|
||||
throw new \Exception("GUID provided to RSS Item is not a string", 500);
|
||||
}
|
||||
if ($guid === "") {
|
||||
$guid = null;
|
||||
}
|
||||
$this->guid = $guid;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/** Get/Set the value
|
||||
* @param string|null $pubDate The pubDate to get/set
|
||||
*/
|
||||
public function pubDate($pubDate = null)
|
||||
{
|
||||
if ($pubDate === null) {
|
||||
return $this->pubDate;
|
||||
}
|
||||
if (! is_string($pubDate)) {
|
||||
throw new \Exception(
|
||||
"pubDate provided to RSS Item is not a string",
|
||||
500
|
||||
);
|
||||
}
|
||||
if (! Verify::staticIs_datetimeSQL($pubDate)) {
|
||||
throw new \Exception(
|
||||
"pubDate provided to RSS Item is not a valid date",
|
||||
500
|
||||
);
|
||||
}
|
||||
if ($pubDate === "") {
|
||||
$pubDate = null;
|
||||
} else {
|
||||
$pubDate = Convert::convertDate(
|
||||
$pubDate,
|
||||
"Y-m-d H:i:s",
|
||||
\DateTime::RFC2822
|
||||
);
|
||||
}
|
||||
$this->pubDate = $pubDate;
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
24
src/StateMachineState.php
Normal file
24
src/StateMachineState.php
Normal file
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
/** DomFramework
|
||||
* @package domframework
|
||||
* @author Dominique Fournier <dominique@fournier38.fr>
|
||||
* @license BSD
|
||||
*/
|
||||
|
||||
namespace Domframework;
|
||||
|
||||
class StateMachineState
|
||||
{
|
||||
private $methodName;
|
||||
|
||||
public function __construct(callable $methodName)
|
||||
{
|
||||
$this->methodName = $methodName;
|
||||
}
|
||||
|
||||
public function run()
|
||||
{
|
||||
return call_user_func($this->methodName);
|
||||
}
|
||||
}
|
||||
43
src/StateMachineTransition.php
Normal file
43
src/StateMachineTransition.php
Normal file
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
/** DomFramework
|
||||
* @package domframework
|
||||
* @author Dominique Fournier <dominique@fournier38.fr>
|
||||
* @license BSD
|
||||
*/
|
||||
|
||||
namespace Domframework;
|
||||
|
||||
class StateMachineTransition
|
||||
{
|
||||
private $fromStateName;
|
||||
private $toStateName;
|
||||
private $methodName;
|
||||
|
||||
public function __construct(string $fromStateName, string $toStateName, callable $methodName)
|
||||
{
|
||||
$this->fromStateName = $fromStateName;
|
||||
$this->toStateName = $toStateName;
|
||||
$this->methodName = $methodName;
|
||||
}
|
||||
|
||||
public function getFromStateName(): string
|
||||
{
|
||||
return $this->fromStateName;
|
||||
}
|
||||
|
||||
public function getToStateName(): string
|
||||
{
|
||||
return $this->toStateName;
|
||||
}
|
||||
|
||||
public function getMethodName(): callable
|
||||
{
|
||||
return $this->methodName;
|
||||
}
|
||||
|
||||
public function run()
|
||||
{
|
||||
return call_user_func($this->methodName);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user