summaryrefslogtreecommitdiffstats
path: root/library/Icinga/Chart/Render
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--library/Icinga/Chart/Render/LayoutBox.php200
-rw-r--r--library/Icinga/Chart/Render/RenderContext.php225
-rw-r--r--library/Icinga/Chart/Render/Rotator.php80
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);
+ }
+}