311 lines
9.1 KiB
PHP
311 lines
9.1 KiB
PHP
<?php
|
|
// {{{ICINGA_LICENSE_HEADER}}}
|
|
/**
|
|
* This file is part of Icinga 2 Web.
|
|
*
|
|
* Icinga 2 Web - Head for multiple monitoring backends.
|
|
* Copyright (C) 2013 Icinga Development Team
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*
|
|
* @copyright 2013 Icinga Development Team <info@icinga.org>
|
|
* @license http://www.gnu.org/licenses/gpl-2.0.txt GPL, version 2
|
|
* @author Icinga Development Team <info@icinga.org>
|
|
*/
|
|
// {{{ICINGA_LICENSE_HEADER}}}
|
|
|
|
namespace Icinga\Chart\Primitive;
|
|
|
|
use \DOMElement;
|
|
use \Icinga\Chart\Render\RenderContext;
|
|
|
|
/**
|
|
* Component for drawing a pie slice
|
|
*/
|
|
class PieSlice extends Animatable implements Drawable
|
|
{
|
|
/**
|
|
* The radius of this pieslice relative to the canvas
|
|
*
|
|
* @var int
|
|
*/
|
|
private $radius = 50;
|
|
|
|
/**
|
|
* The start radian of the pie slice
|
|
*
|
|
* @var float
|
|
*/
|
|
private $startRadian = 0;
|
|
|
|
/**
|
|
* The end radian of the pie slice
|
|
*
|
|
* @var float
|
|
*/
|
|
private $endRadian= 0;
|
|
|
|
/**
|
|
* The x position of the pie slice's center
|
|
*
|
|
* @var int
|
|
*/
|
|
private $x;
|
|
|
|
/**
|
|
* The y position of the pie slice's center
|
|
*
|
|
* @var int
|
|
*/
|
|
private $y;
|
|
|
|
/**
|
|
* The caption of the pie slice, empty string means no caption
|
|
*
|
|
* @var string
|
|
*/
|
|
private $caption = "";
|
|
|
|
/**
|
|
* The offset of the caption, shifting the indicator from the center of the pie slice
|
|
*
|
|
* This is required for nested pie slices.
|
|
*
|
|
* @var int
|
|
*/
|
|
private $captionOffset = 0;
|
|
|
|
/**
|
|
* The minimum radius the label must respect
|
|
*
|
|
* @var int
|
|
*/
|
|
private $outerCaptionBound = 0;
|
|
|
|
/**
|
|
* An optional group element to add labels to when rendering
|
|
*
|
|
* @var DOMElement
|
|
*/
|
|
private $labelGroup;
|
|
|
|
/**
|
|
* Create a pie slice
|
|
*
|
|
* @param int $radius The radius of the slice
|
|
* @param int $percent The percentage the slice represents
|
|
* @param int $percentStart The percentage where this slice starts
|
|
*/
|
|
public function __construct($radius, $percent, $percentStart = 0)
|
|
{
|
|
$this->x = $this->y = $this->radius = $radius;
|
|
|
|
$this->startRadian = M_PI * $percentStart/50;
|
|
$this->endRadian = M_PI * ($percent + $percentStart)/50;
|
|
}
|
|
|
|
/**
|
|
* Create the path for the pie slice
|
|
*
|
|
* @param int $x The x position of the pie slice
|
|
* @param int $y The y position of the pie slice
|
|
* @param int $r The absolute radius of the pie slice
|
|
*
|
|
* @return string A SVG path string
|
|
*/
|
|
private function getPieSlicePath($x, $y, $r)
|
|
{
|
|
// start at the center of the pieslice
|
|
$pathString = 'M ' . $x . ' ' . $y . ' ';
|
|
|
|
// The coordinate system is mirrored on the Y axis, so we have to flip cos and sin
|
|
$xStart = $x + intval($r * sin($this->startRadian));
|
|
$yStart = $y - intval($r * cos($this->startRadian));
|
|
$xEnd = $x + intval($r * sin($this->endRadian));
|
|
$yEnd = $y - intval($r * cos($this->endRadian));
|
|
|
|
// Draw a straight line to the upper part of the arc
|
|
$pathString .= 'L ' . $xStart . ' ' . $yStart;
|
|
// Instead of directly connecting the upper part of the arc (leaving a triangle), draw a bow with the radius
|
|
$pathString .= ' A ' . $r . ' ' . $r ;
|
|
// These are the flags for the bow, see the SVG path documentation for details
|
|
// http://www.w3.org/TR/SVG/paths.html#PathDataEllipticalArcCommands
|
|
$pathString .= ' 0 ' . (($this->endRadian - $this->startRadian > M_PI) ? '1' : '0 ') . ' 1';
|
|
|
|
// xEnd and yEnd are the lower point of the arc
|
|
$pathString .= ' '.$xEnd . ' ' . $yEnd;
|
|
return $pathString;
|
|
}
|
|
|
|
/**
|
|
* Draw the label handler and the text for this pie slice
|
|
*
|
|
* @param RenderContext $ctx The rendering context to use for coordinate translation
|
|
* @param int $r The radius of the pie in absolute coordinates
|
|
*
|
|
* @return DOMElement The group DOMElement containing the handle and label
|
|
*/
|
|
private function drawDescriptionLabel(RenderContext $ctx, $r)
|
|
{
|
|
$group = $ctx->getDocument()->createElement('g');
|
|
$rOuter = ($ctx->xToAbsolute($this->outerCaptionBound) + $ctx->yToAbsolute($this->outerCaptionBound)) / 2;
|
|
$addOffset = $rOuter - $r ;
|
|
if ($addOffset < 0) {
|
|
$addOffset = 0;
|
|
}
|
|
list($x, $y) = $ctx->toAbsolute($this->x, $this->y);
|
|
$midRadius = $this->startRadian + ($this->endRadian - $this->startRadian) / 2;
|
|
list($offsetX, $offsetY) = $ctx->toAbsolute($this->captionOffset, $this->captionOffset);
|
|
|
|
$midX = $x + intval(($offsetX + $r)/2 * sin($midRadius));
|
|
$midY = $y - intval(($offsetY + $r)/2 * cos($midRadius));
|
|
|
|
// Draw the handle
|
|
$path = new Path(array($midX, $midY));
|
|
|
|
$midX += ($addOffset + $r/1.8) * ($midRadius > M_PI ? -1 : 1);
|
|
$path->append(array($midX, $midY))->toAbsolute();
|
|
|
|
$midX += intval($r/2 * sin(M_PI/7)) * ($midRadius > M_PI ? -1 : 1);
|
|
$midY -= intval($r/2 * cos(M_PI/7)) * ($midRadius < M_PI*1.5 && $midRadius > M_PI/2 ? -1 : 1);
|
|
|
|
if ($ctx->ytoRelative($midY) > 100) {
|
|
$midY = $ctx->yToAbsolute(100);
|
|
} elseif ($ctx->ytoRelative($midY) < 0) {
|
|
$midY = $ctx->yToAbsolute(0);
|
|
}
|
|
|
|
$path->append(array($midX , $midY));
|
|
$rel = $ctx->toRelative($midX, $midY);
|
|
|
|
// Draw the text box
|
|
$text = new Text($rel[0]+1.5, $rel[1], $this->caption);
|
|
$text->setFontSize('2.5em');
|
|
$text->setAlignment(($midRadius > M_PI ? Text::ALIGN_END : Text::ALIGN_START));
|
|
|
|
$group->appendChild($path->toSvg($ctx));
|
|
$group->appendChild($text->toSvg($ctx));
|
|
|
|
return $group;
|
|
}
|
|
|
|
/**
|
|
* Set the x position of the pie slice
|
|
*
|
|
* @param int $x The new x position
|
|
*
|
|
* @return self Fluid interface
|
|
*/
|
|
public function setX($x)
|
|
{
|
|
$this->x = $x;
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Set the y position of the pie slice
|
|
*
|
|
* @param int $y The new y position
|
|
*
|
|
* @return self Fluid interface
|
|
*/
|
|
public function setY($y)
|
|
{
|
|
$this->y = $y;
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Set a root element to be used for drawing labels
|
|
*
|
|
* @param DOMElement $group The label group
|
|
*
|
|
* @return self Fluid interface
|
|
*/
|
|
public function setLabelGroup(DOMElement $group)
|
|
{
|
|
$this->labelGroup = $group;
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Set the caption for this label
|
|
*
|
|
* @param string $caption The caption for this element
|
|
*
|
|
* @return self Fluid interface
|
|
*/
|
|
public function setCaption($caption)
|
|
{
|
|
$this->caption = $caption;
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Set the internal offset of the caption handle
|
|
*
|
|
* @param int $offset The offset for the caption handle
|
|
*
|
|
* @return self Fluid interface
|
|
*/
|
|
public function setCaptionOffset($offset)
|
|
{
|
|
$this->captionOffset = $offset;
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Set the minimum radius to be used for drawing labels
|
|
*
|
|
* @param int $bound The offset for the caption text
|
|
*
|
|
* @return self Fluid interface
|
|
*/
|
|
public function setOuterCaptionBound($bound)
|
|
{
|
|
$this->outerCaptionBound = $bound;
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Create the SVG representation from this Drawable
|
|
*
|
|
* @param RenderContext $ctx The context to use for rendering
|
|
*
|
|
* @return DOMElement The SVG Element
|
|
*/
|
|
public function toSvg(RenderContext $ctx)
|
|
{
|
|
$doc = $ctx->getDocument();
|
|
$group = $doc->createElement('g');
|
|
$r = ($ctx->xToAbsolute($this->radius) + $ctx->yToAbsolute($this->radius)) / 2;
|
|
list($x, $y) = $ctx->toAbsolute($this->x, $this->y);
|
|
|
|
$slicePath = $doc->createElement('path');
|
|
|
|
$slicePath->setAttribute('d', $this->getPieSlicePath($x, $y, $r));
|
|
$slicePath->setAttribute('style', $this->getStyle());
|
|
$slicePath->setAttribute('data-icinga-graph-type', 'pieslice');
|
|
|
|
$this->applyAttributes($slicePath);
|
|
$group->appendChild($slicePath);
|
|
if ($this->caption != "") {
|
|
$lblGroup = ($this->labelGroup ? $this->labelGroup : $group);
|
|
$lblGroup->appendChild($this->drawDescriptionLabel($ctx, $r));
|
|
}
|
|
return $group;
|
|
}
|
|
}
|