diff options
Diffstat (limited to 'library/Icinga/Chart/Render')
-rw-r--r-- | library/Icinga/Chart/Render/LayoutBox.php | 200 | ||||
-rw-r--r-- | library/Icinga/Chart/Render/RenderContext.php | 225 | ||||
-rw-r--r-- | library/Icinga/Chart/Render/Rotator.php | 80 |
3 files changed, 505 insertions, 0 deletions
diff --git a/library/Icinga/Chart/Render/LayoutBox.php b/library/Icinga/Chart/Render/LayoutBox.php new file mode 100644 index 0000000..fa49461 --- /dev/null +++ b/library/Icinga/Chart/Render/LayoutBox.php @@ -0,0 +1,200 @@ +<?php +/* Icinga Web 2 | (c) 2013 Icinga Development Team | GPLv2+ */ + +namespace Icinga\Chart\Render; + +use Icinga\Chart\Format; + +/** + * Layout class encapsulating size, padding and margin information + */ +class LayoutBox +{ + /** + * Padding index for top padding + */ + const PADDING_TOP = 0; + + /** + * Padding index for right padding + */ + const PADDING_RIGHT = 1; + + /** + * Padding index for bottom padding + */ + const PADDING_BOTTOM = 2; + + /** + * Padding index for left padding + */ + const PADDING_LEFT = 3; + + /** + * The height of this layout element + * + * @var int + */ + private $height; + + /** + * The width of this layout element + * + * @var int + */ + private $width; + + /** + * The x position of this layout + * + * @var int + */ + private $x; + + /** + * The y position of this layout + * + * @var int + */ + private $y; + + /** + * The padding of this layout + * + * @var array + */ + private $padding = array(0, 0, 0, 0); + + /** + * Create this layout box + * + * Note that x, y, width and height are relative: x with 0 means leftmost, x with 100 means rightmost + * + * @param int $x The relative x coordinate + * @param int $y The relative y coordinate + * @param int $width The optional, relative width + * @param int $height The optional, relative height + */ + public function __construct($x, $y, $width = null, $height = null) + { + $this->height = $height ? $height : 100; + $this->width = $width ? $width : 100; + $this->x = $x; + $this->y = $y; + } + + /** + * Set a padding to all four sides uniformly + * + * @param int $padding The padding to set for all four sides + */ + public function setUniformPadding($padding) + { + $this->padding = array($padding, $padding, $padding, $padding); + } + + /** + * Set the padding for this LayoutBox + * + * @param int $top The top side padding + * @param int $right The right side padding + * @param int $bottom The bottom side padding + * @param int $left The left side padding + */ + public function setPadding($top, $right, $bottom, $left) + { + $this->padding = array($top, $right, $bottom, $left); + } + + /** + * Return a string containing the SVG transform attribute values for the padding + * + * @param RenderContext $ctx The context to determine the translation coordinates + * + * @return string The transformation string + */ + public function getInnerTransform(RenderContext $ctx) + { + list($translateX, $translateY) = $ctx->toAbsolute( + $this->padding[self::PADDING_LEFT] + $this->getX(), + $this->padding[self::PADDING_TOP] + $this->getY() + ); + list($scaleX, $scaleY) = $ctx->paddingToScaleFactor($this->padding); + + $scaleX *= $this->getWidth()/100; + $scaleY *= $this->getHeight()/100; + return sprintf( + 'translate(%s, %s) scale(%s, %s)', + Format::formatSVGNumber($translateX), + Format::formatSVGNumber($translateY), + Format::formatSVGNumber($scaleX), + Format::formatSVGNumber($scaleY) + ); + } + + /** + * String representation for this Layout, for debug purposes + * + * @return string A string containing the bounds of this LayoutBox + */ + public function __toString() + { + return sprintf( + 'Rectangle: x: %s y: %s, height: %s, width: %s', + $this->x, + $this->y, + $this->height, + $this->width + ); + } + + /** + * Return a four element array with the padding + * + * @return array The padding of this LayoutBox + */ + public function getPadding() + { + return $this->padding; + } + + /** + * Return the height of this LayoutBox + * + * @return int The height of this box + */ + public function getHeight() + { + return $this->height; + } + + /** + * Return the width of this LayoutBox + * + * @return int The width of this box + */ + public function getWidth() + { + return $this->width; + } + + /** + * Return the x position of this LayoutBox + * + * @return int The x position of this box + */ + public function getX() + { + return $this->x; + } + + /** + * Return the y position of this LayoutBox + * + * @return int The y position of this box + */ + public function getY() + { + return $this->y; + } +} diff --git a/library/Icinga/Chart/Render/RenderContext.php b/library/Icinga/Chart/Render/RenderContext.php new file mode 100644 index 0000000..457fbf3 --- /dev/null +++ b/library/Icinga/Chart/Render/RenderContext.php @@ -0,0 +1,225 @@ +<?php +/* Icinga Web 2 | (c) 2013 Icinga Development Team | GPLv2+ */ + + +namespace Icinga\Chart\Render; + +use DOMDocument; + +/** + * Context for rendering, handles ratio based coordinate calculations. + * + * The most important functions when rendering are the toAbsolute and roRelative + * values, taking world coordinates and translating them into local coordinates. + */ +class RenderContext +{ + + /** + * The base size of the viewport, i.e. how many units are available on a 1:1 ratio + * + * @var array + */ + private $viewBoxSize = array(1000, 1000); + + + /** + * The DOMDocument for modifying the elements + * + * @var DOMDocument + */ + private $document; + + /** + * If true no ratio correction will be made + * + * @var bool + */ + private $respectRatio = false; + + /** + * The ratio on the x side. A x ration of 2 means that the width of the SVG is divided in 2000 + * units (see $viewBox) + * + * @var int + */ + private $xratio = 1; + + /** + * The ratio on the y side. A y ration of 2 means that the height of the SVG is divided in 2000 + * units (see $viewBox) + * + * @var int + */ + private $yratio = 1; + + /** + * Creates a new context for the given DOM Document + * + * @param DOMDocument $document The DOM document represented by this context + * @param int $width The width (may be approximate) of the document + * (only required for ratio calculation) + * @param int $height The height (may be approximate) of the document + * (only required for ratio calculation) + */ + public function __construct(DOMDocument $document, $width, $height) + { + $this->document = $document; + if ($width > $height) { + $this->xratio = $width / $height; + } elseif ($height > $width) { + $this->yratio = $height / $width; + } + } + + /** + * Return the document represented by this Rendering context + * + * @return DOMDocument The DOMDocument for creating files + */ + public function getDocument() + { + return $this->document; + } + + /** + * Let successive toAbsolute operations ignore ratio correction + * + * This can be called to avoid distortion on certain elements like rectangles. + */ + public function keepRatio() + { + $this->respectRatio = true; + } + + /** + * Let successive toAbsolute operations perform ratio correction + * + * This will cause distortion on certain elements like rectangles. + */ + public function ignoreRatio() + { + $this->respectRatio = false; + } + + /** + * Return how many unit s are available in the Y axis + * + * @return int The number of units available on the y axis + */ + public function getNrOfUnitsY() + { + return intval($this->viewBoxSize[1] * $this->yratio); + } + + /** + * Return how many unit s are available in the X axis + * + * @return int The number of units available on the x axis + */ + public function getNrOfUnitsX() + { + return intval($this->viewBoxSize[0] * $this->xratio); + } + + /** + * Transforms the x,y coordinate from relative coordinates to absolute world coordinates + * + * (50, 50) would be a point in the middle of the document and map to 500, 1000 on a + * 1000 x 1000 viewbox with a 1:2 ratio. + * + * @param int $x The relative x coordinate + * @param int $y The relative y coordinate + * + * @return array An x,y tuple containing absolute coordinates + * @see RenderContext::toRelative + */ + public function toAbsolute($x, $y) + { + return array($this->xToAbsolute($x), $this->yToAbsolute($y)); + } + + /** + * Transforms the x,y coordinate from absolute coordinates to relative world coordinates + * + * This is the inverse function of toAbsolute + * + * @param int $x The absolute x coordinate + * @param int $y The absolute y coordinate + * + * @return array An x,y tupel containing absolute coordinates + * @see RenderContext::toAbsolute + */ + public function toRelative($x, $y) + { + return array($this->xToRelative($x), $this->yToRelative($y)); + } + + /** + * Calculates the scale transformation required to apply the padding on an Canvas + * + * @param array $padding A 4 element array containing top, right, bottom and left padding + * + * @return array An array containing the x and y scale + */ + public function paddingToScaleFactor(array $padding) + { + list($horizontalPadding, $verticalPadding) = $this->toAbsolute( + $padding[LayoutBox::PADDING_RIGHT] + $padding[LayoutBox::PADDING_LEFT], + $padding[LayoutBox::PADDING_TOP] + $padding[LayoutBox::PADDING_BOTTOM] + ); + + return array( + ($this->getNrOfUnitsX() - $horizontalPadding) / $this->getNrOfUnitsX(), + ($this->getNrOfUnitsY() - $verticalPadding) / $this->getNrOfUnitsY() + ); + } + + /** + * Transform a relative x coordinate to an absolute one + * + * @param int $x A relative x coordinate + * + * @return int An absolute x coordinate + **/ + public function xToAbsolute($x) + { + return $this->getNrOfUnitsX() / 100 * $x / ($this->respectRatio ? $this->xratio : 1); + } + + /** + * Transform a relative y coordinate to an absolute one + * + * @param int $y A relative y coordinate + * + * @return int An absolute y coordinate + */ + public function yToAbsolute($y) + { + return $this->getNrOfUnitsY() / 100 * $y / ($this->respectRatio ? $this->yratio : 1); + } + + /** + * Transform a absolute x coordinate to an relative one + * + * @param int $x An absolute x coordinate + * + * @return int A relative x coordinate + */ + public function xToRelative($x) + { + return $x / $this->getNrOfUnitsX() * 100 * ($this->respectRatio ? $this->xratio : 1); + } + + /** + * Transform a absolute y coordinate to an relative one + * + * @param int $y An absolute x coordinate + * + * @return int A relative x coordinate + */ + public function yToRelative($y) + { + return $y / $this->getNrOfUnitsY() * 100 * ($this->respectRatio ? $this->yratio : 1); + } +} diff --git a/library/Icinga/Chart/Render/Rotator.php b/library/Icinga/Chart/Render/Rotator.php new file mode 100644 index 0000000..3e7071c --- /dev/null +++ b/library/Icinga/Chart/Render/Rotator.php @@ -0,0 +1,80 @@ +<?php +/* Icinga Web 2 | (c) 2014 Icinga Development Team | GPLv2+ */ + +namespace Icinga\Chart\Render; + +use Icinga\Chart\Render\RenderContext; +use Icinga\Chart\Primitive\Drawable; +use DOMElement; + +/** + * Class Rotator + * @package Icinga\Chart\Render + */ +class Rotator implements Drawable +{ + /** + * The drawable element to rotate + * + * @var Drawable + */ + private $element; + + /** + * @var int + */ + private $degrees; + + /** + * Wrap an element into a new instance of Rotator + * + * @param Drawable $element The element to rotate + * @param int $degrees The amount of degrees + */ + public function __construct(Drawable $element, $degrees) + { + $this->element = $element; + $this->degrees = $degrees; + } + + /** + * Rotate the given element. + * + * @param RenderContext $ctx The rendering context + * @param DOMElement $el The element to rotate + * @param $degrees The amount of degrees + * + * @return DOMElement The rotated DOMElement + */ + private function rotate(RenderContext $ctx, DOMElement $el, $degrees) + { + // Create a box containing the rotated element relative to the original element position + $container = $ctx->getDocument()->createElement('g'); + $x = $el->getAttribute('x'); + $y = $el->getAttribute('y'); + $container->setAttribute('transform', 'translate(' . $x . ',' . $y . ')'); + $el->removeAttribute('x'); + $el->removeAttribute('y'); + + // Put the element into a rotated group + //$rotate = $ctx->getDocument()->createElement('g'); + $el->setAttribute('transform', 'rotate(' . $degrees . ')'); + //$rotate->appendChild($el); + + $container->appendChild($el); + return $container; + } + + /** + * 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) + { + $el = $this->element->toSvg($ctx); + return $this->rotate($ctx, $el, $this->degrees); + } +} |