Skip to content

Commit

Permalink
Merge branch 'feature/improve-chart-implementation-7841'
Browse files Browse the repository at this point in the history
  • Loading branch information
majentsch committed Jan 19, 2015
2 parents 5ccd290 + 4dfad96 commit 8c8e3e4
Show file tree
Hide file tree
Showing 12 changed files with 604 additions and 142 deletions.
198 changes: 133 additions & 65 deletions library/Icinga/Chart/Axis.php
Original file line number Diff line number Diff line change
Expand Up @@ -78,24 +78,23 @@ class Axis implements Drawable
private $yUnit = null;

/**
* If the displayed labels should be aligned horizontally or diagonally
* The minimum amount of units each step must take up
*
* @var int
*/
private $labelRotationStyle = self::LABEL_ROTATE_DIAGONAL;
public $minUnitsPerStep = 80;

/**
* Set the label rotation style for the horizontal axis
* The minimum amount of units each tick must take up
*
* <ul>
* <li><b>LABEL_ROTATE_HORIZONTAL</b>: Labels will be displayed horizontally </li>
* <li><b>LABEL_ROTATE_DIAGONAL</b>: Labels will be rotated by 45° </li>
* </ul>
*
* @param $style The rotation mode
* @var int
*/
public function setHorizontalLabelRotationStyle($style)
{
$this->labelRotationStyle = $style;
}
public $minUnitsPerTick = 15;

/**
* If the displayed labels should be aligned horizontally or diagonally
*/
protected $labelRotationStyle = self::LABEL_ROTATE_HORIZONTAL;

/**
* Inform the axis about an added dataset
Expand Down Expand Up @@ -160,58 +159,74 @@ public function getRequiredPadding()
*/
private function renderHorizontalAxis(RenderContext $ctx, DOMElement $group)
{
$steps = $this->ticksPerX($this->xUnit->getTicks(), $ctx->getNrOfUnitsX(), $this->minUnitsPerStep);
$ticks = $this->ticksPerX($this->xUnit->getTicks(), $ctx->getNrOfUnitsX(), $this->minUnitsPerTick);

// Steps should always be ticks
if ($ticks !== $steps) {
$steps = $ticks * 5;
}

// Check whether there is enough room for regular labels
$labelRotationStyle = $this->labelRotationStyle;
if ($this->labelsOversized($this->xUnit, 6)) {
$labelRotationStyle = self::LABEL_ROTATE_DIAGONAL;
}

/*
$line = new Line(0, 100, 100, 100);
$line->setStrokeWidth(2);
$group->appendChild($line->toSvg($ctx));
*/

// contains the approximate end position of the last label
$lastLabelEnd = -1;
$shift = 0;

$i = 0;
foreach ($this->xUnit as $label => $pos) {
if ($this->labelRotationStyle === self::LABEL_ROTATE_HORIZONTAL) {
// If the last label would overlap this label we shift the y axis a bit
if ($lastLabelEnd > $pos) {
$shift = ($shift + 5) % 10;
} else {
$shift = 0;
}

if ($i % $ticks === 0) {
/*
$tick = new Line($pos, 100, $pos, 101);
$group->appendChild($tick->toSvg($ctx));
*/
}

$tick = new Line($pos, 100, $pos, 102);
$group->appendChild($tick->toSvg($ctx));
if ($i % $steps === 0) {
if ($labelRotationStyle === self::LABEL_ROTATE_HORIZONTAL) {
// If the last label would overlap this label we shift the y axis a bit
if ($lastLabelEnd > $pos) {
$shift = ($shift + 5) % 10;
} else {
$shift = 0;
}
}

$labelField = new Text($pos + 0.5, ($this->xLabel ? 107 : 105) + $shift, $label);
if ($this->labelRotationStyle === self::LABEL_ROTATE_HORIZONTAL) {
$labelField->setAlignment(Text::ALIGN_MIDDLE)
->setFontSize('1.8em');
} else {
$labelField->setFontSize('2.5em');
}
$labelField = new Text($pos + 0.5, ($this->xLabel ? 107 : 105) + $shift, $label);
if ($labelRotationStyle === self::LABEL_ROTATE_HORIZONTAL) {
$labelField->setAlignment(Text::ALIGN_MIDDLE)
->setFontSize('2.5em');
} else {
$labelField->setFontSize('2.5em');
}

if ($this->labelRotationStyle === self::LABEL_ROTATE_DIAGONAL) {
$labelField = new Rotator($labelField, 45);
}
$labelField = $labelField->toSvg($ctx);
if ($labelRotationStyle === self::LABEL_ROTATE_DIAGONAL) {
$labelField = new Rotator($labelField, 45);
}
$labelField = $labelField->toSvg($ctx);

$group->appendChild($labelField);
$group->appendChild($labelField);

if ($this->drawYGrid) {
$bgLine = new Line($pos, 0, $pos, 100);
$bgLine->setStrokeWidth(0.5)
->setStrokeColor('#232');
$group->appendChild($bgLine->toSvg($ctx));
if ($this->drawYGrid) {
$bgLine = new Line($pos, 0, $pos, 100);
$bgLine->setStrokeWidth(0.5)
->setStrokeColor('#BFBFBF');
$group->appendChild($bgLine->toSvg($ctx));
}
$lastLabelEnd = $pos + strlen($label) * 1.2;
}
$lastLabelEnd = $pos + strlen($label) * 1.2;
}

// render the label for this axis
if ($this->xLabel) {
$axisLabel = new Text(50, 104, $this->xLabel);
$axisLabel->setFontSize('2em')
->setFontWeight('bold')
->setAlignment(Text::ALIGN_MIDDLE);
$group->appendChild($axisLabel->toSvg($ctx));
$i++;
}
}

Expand All @@ -223,34 +238,59 @@ private function renderHorizontalAxis(RenderContext $ctx, DOMElement $group)
*/
private function renderVerticalAxis(RenderContext $ctx, DOMElement $group)
{
$steps = $this->ticksPerX($this->yUnit->getTicks(), $ctx->getNrOfUnitsY(), $this->minUnitsPerStep);
$ticks = $this->ticksPerX($this->yUnit->getTicks(), $ctx->getNrOfUnitsY(), $this->minUnitsPerTick);

// Steps should always be ticks
if ($ticks !== $steps) {
$steps = $ticks * 5;
}
/*
$line = new Line(0, 0, 0, 100);
$line->setStrokeWidth(2);
$group->appendChild($line->toSvg($ctx));
*/

$i = 0;
foreach ($this->yUnit as $label => $pos) {
$pos = 100 - $pos;
$tick = new Line(0, $pos, -1, $pos);
$group->appendChild($tick->toSvg($ctx));

$labelField = new Text(-0.5, $pos+0.5, $label);
$labelField->setFontSize('1.8em')
->setAlignment(Text::ALIGN_END);

$group->appendChild($labelField->toSvg($ctx));
if ($this->drawXGrid) {
$bgLine = new Line(0, $pos, 100, $pos);
$bgLine->setStrokeWidth(0.5)
->setStrokeColor('#343');
$group->appendChild($bgLine->toSvg($ctx));

if ($i % $ticks === 0) {
// draw a tick
//$tick = new Line(0, $pos, -1, $pos);
//$group->appendChild($tick->toSvg($ctx));
}

if ($i % $steps === 0) {
// draw a step
$labelField = new Text(-0.5, $pos + 0.5, $label);
$labelField->setFontSize('2.5em')
->setAlignment(Text::ALIGN_END);

$group->appendChild($labelField->toSvg($ctx));
if ($this->drawXGrid) {
$bgLine = new Line(0, $pos, 100, $pos);
$bgLine->setStrokeWidth(0.5)
->setStrokeColor('#BFBFBF');
$group->appendChild($bgLine->toSvg($ctx));
}
}
$i++;
}

if ($this->yLabel) {
$axisLabel = new Text(-8, 50, $this->yLabel);
if ($this->yLabel || $this->xLabel) {
if ($this->yLabel && $this->xLabel) {
$txt = $this->yLabel . ' / ' . $this->xLabel;
} else if ($this->xLabel) {
$txt = $this->xLabel;
} else {
$txt = $this->yLabel;
}

$axisLabel = new Text(50, -3, $txt);
$axisLabel->setFontSize('2em')
->setFontWeight('bold')
->setAlignment(Text::ALIGN_MIDDLE);
$axisLabel = new Rotator($axisLabel, 90);

$group->appendChild($axisLabel->toSvg($ctx));
}
Expand Down Expand Up @@ -416,4 +456,32 @@ public function toSvg(RenderContext $ctx)
$this->renderVerticalAxis($ctx, $group);
return $group;
}

protected function ticksPerX($ticks, $units, $min)
{
$per = 1;
while ($per * $units / $ticks < $min) {
$per++;
}
return $per;
}

/**
* Returns whether at least one label of the given Axis
* is bigger than the given maxLength
*
* @param AxisUnit $axis The axis that contains the labels that will be checked
*
* @return boolean Whether at least one label is bigger than maxLength
*/
private function labelsOversized(AxisUnit $axis, $maxLength = 5)
{
$oversized = false;
foreach ($axis as $label => $pos) {
if (strlen($label) > $maxLength) {
$oversized = true;
}
}
return $oversized;
}
}
10 changes: 9 additions & 1 deletion library/Icinga/Chart/Graph/BarGraph.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ class BarGraph extends Styleable implements Drawable
*
* @var int
*/
private $barWidth = 4;
private $barWidth = 3;

/**
* The dataset to use for this bar graph
Expand Down Expand Up @@ -122,6 +122,14 @@ public function toSvg(RenderContext $ctx)
$doc = $ctx->getDocument();
$group = $doc->createElement('g');
$idx = 0;

if (count($this->dataSet) > 15) {
$this->barWidth = 2;
}
if (count($this->dataSet) > 25) {
$this->barWidth = 1;
}

foreach ($this->dataSet as $x => $point) {
// add white background bar, to prevent other bars from altering transparency effects
$bar = $this->drawSingleBar($point, $idx++, 'white', $this->strokeWidth, $idx)->toSvg($ctx);
Expand Down
11 changes: 9 additions & 2 deletions library/Icinga/Chart/Graph/LineGraph.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,13 @@ class LineGraph extends Styleable implements Drawable
*/
public $strokeWidth = 5;

/**
* The size of the displayed dots
*
* @var int
*/
public $dotWith = 0;

/**
* Create a new LineGraph displaying the given dataset
*
Expand Down Expand Up @@ -138,8 +145,8 @@ public function toSvg(RenderContext $ctx)
$group = $path->toSvg($ctx);
if ($this->showDataPoints === true) {
foreach ($this->dataset as $point) {
$dot = new Circle($point[0], $point[1], $this->strokeWidth*5);
$dot->setFill('black');
$dot = new Circle($point[0], $point[1], $this->dotWith);
$dot->setFill($this->strokeColor);

$group->appendChild($dot->toSvg($ctx));
}
Expand Down
3 changes: 2 additions & 1 deletion library/Icinga/Chart/Legend.php
Original file line number Diff line number Diff line change
Expand Up @@ -66,13 +66,14 @@ public function toSvg(RenderContext $ctx)
$outer->getLayout()->setPadding(2, 2, 2, 2);
$nrOfColumns = 4;

$leftstep = 100 / $nrOfColumns;
$topstep = 10 / $nrOfColumns + 2;

$top = 0;
$left = 0;
$lastLabelEndPos = -1;
foreach ($this->dataset as $color => $text) {
$leftstep = 100 / $nrOfColumns + strlen($text);

// Make sure labels don't overlap each other
while ($lastLabelEndPos >= $left) {
$left += $leftstep;
Expand Down
2 changes: 1 addition & 1 deletion library/Icinga/Chart/Primitive/Circle.php
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ public function toSvg(RenderContext $ctx)
$circle = $ctx->getDocument()->createElement('circle');
$circle->setAttribute('cx', Format::formatSVGNumber($coords[0]));
$circle->setAttribute('cy', Format::formatSVGNumber($coords[1]));
$circle->setAttribute('r', 5);
$circle->setAttribute('r', $this->radius);
$circle->setAttribute('style', $this->getStyle());
$this->applyAttributes($circle);
return $circle;
Expand Down
10 changes: 9 additions & 1 deletion library/Icinga/Chart/Unit/AxisUnit.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,14 @@
/**
* Base class for Axis Units
*
* An AxisUnit takes a set of values and places them on a given range
*
* Concrete subclasses must implement the iterator interface, with
* getCurrent returning the axis relative position and getValue the label
* that will be displayed
*/
interface AxisUnit extends Iterator
{

/**
* Add a dataset to this AxisUnit, required for dynamic min and max vlaues
*
Expand Down Expand Up @@ -46,4 +47,11 @@ public function setMin($min);
* @param int $max The new maximum value
*/
public function setMax($max);

/**
* Get the amount of ticks of this axis
*
* @return int
*/
public function getTicks();
}
Loading

0 comments on commit 8c8e3e4

Please sign in to comment.