diff --git a/library/Icinga/Chart/Chart.php b/library/Icinga/Chart/Chart.php
index 13b0114e6..842bb56e8 100644
--- a/library/Icinga/Chart/Chart.php
+++ b/library/Icinga/Chart/Chart.php
@@ -38,11 +38,25 @@ abstract class Chart implements Drawable
*/
protected $palette;
+ /**
+ * The title of this chart, used for providing accessibility features
+ *
+ * @var string
+ */
+ public $title;
+
+ /**
+ * The description for this chart, mandatory for providing accessibility features
+ *
+ * @var string
+ */
+ public $description;
+
/**
* Create a new chart object and create internal objects
*
* If you want to extend this class use the init() method as an extension point,
- * as this will be called at the end o fthe construct call
+ * as this will be called at the end of the construct call
*/
public function __construct()
{
@@ -86,7 +100,6 @@ abstract class Chart implements Drawable
}
/**
- *
* Render this graph and return the created SVG
*
* @return string The SVG created by the SvgRenderer
@@ -105,6 +118,11 @@ abstract class Chart implements Drawable
$this->renderer->setXAspectRatioAlignment(SVGRenderer::X_ASPECT_RATIO_MIN);
$this->renderer->setYAspectRatioAlignment(SVGRenderer::Y_ASPECT_RATIO_MIN);
}
+
+ $this->renderer->setAriaDescription($this->description);
+ $this->renderer->setAriaTitle($this->title);
+ $this->renderer->getCanvas()->setAriaRole('presentation');
+
$this->renderer->getCanvas()->addElement($this);
return $this->renderer->render();
}
diff --git a/library/Icinga/Chart/GridChart.php b/library/Icinga/Chart/GridChart.php
index 7f2794282..20ebb969e 100644
--- a/library/Icinga/Chart/GridChart.php
+++ b/library/Icinga/Chart/GridChart.php
@@ -84,6 +84,13 @@ class GridChart extends Chart
*/
private $tooltips = array();
+ public function __construct()
+ {
+ $this->title = t('Grid Chart');
+ $this->description = t('Contains data in a bar or line chart.');
+ parent::__construct();
+ }
+
/**
* Check if the current dataset has the proper structure for this chart.
*
diff --git a/library/Icinga/Chart/PieChart.php b/library/Icinga/Chart/PieChart.php
index 33ce32927..6b19969c8 100644
--- a/library/Icinga/Chart/PieChart.php
+++ b/library/Icinga/Chart/PieChart.php
@@ -50,6 +50,13 @@ class PieChart extends Chart
*/
private $noCaption = false;
+ public function __construct()
+ {
+ $this->title = t('Pie Chart');
+ $this->description = t('Contains data in a pie chart.');
+ parent::__construct();
+ }
+
/**
* Test if the given pies have the correct format
*
diff --git a/library/Icinga/Chart/Primitive/Canvas.php b/library/Icinga/Chart/Primitive/Canvas.php
index c5617fa35..88e247f02 100644
--- a/library/Icinga/Chart/Primitive/Canvas.php
+++ b/library/Icinga/Chart/Primitive/Canvas.php
@@ -43,6 +43,13 @@ class Canvas implements Drawable
*/
private $rect;
+ /**
+ * The aria role used to describe this canvas' purpose in the accessibility tree
+ *
+ * @var string
+ */
+ private $ariaRole;
+
/**
* Create this canvas
*
@@ -111,6 +118,23 @@ class Canvas implements Drawable
$innerContainer->appendChild($child->toSvg($ctx));
}
+ if (isset($this->ariaRole)) {
+ $outer->setAttribute('role', $this->ariaRole);
+ }
return $outer;
}
+
+ /**
+ * Set the aria role used to determine the meaning of this canvas in the accessibility tree
+ *
+ * The role 'presentation' will indicate that the purpose of this canvas is entirely decorative, while the role
+ * 'img' will indicate that the canvas contains an image, with a possible title or a description. For other
+ * possible roles, see http://www.w3.org/TR/wai-aria/roles
+ *
+ * @param $role string The aria role to set
+ */
+ public function setAriaRole($role)
+ {
+ $this->ariaRole = $role;
+ }
}
diff --git a/library/Icinga/Chart/SVGRenderer.php b/library/Icinga/Chart/SVGRenderer.php
index 5cc223388..98eaa86d6 100644
--- a/library/Icinga/Chart/SVGRenderer.php
+++ b/library/Icinga/Chart/SVGRenderer.php
@@ -48,6 +48,27 @@ class SVGRenderer
*/
private $svg;
+ /**
+ * The description of this SVG, useful for screen readers
+ *
+ * @var string
+ */
+ private $ariaDescription;
+
+ /**
+ * The title of this SVG, useful for screen readers
+ *
+ * @var string
+ */
+ private $ariaTitle;
+
+ /**
+ * The aria role used by this svg element
+ *
+ * @var string
+ */
+ private $ariaRole = 'img';
+
/**
* The root layer for all elements
*
@@ -126,6 +147,7 @@ class SVGRenderer
$svg = $this->document->createElement('svg');
$svg->setAttribute('xmlns', 'http://www.w3.org/2000/svg');
$svg->setAttribute('xmlns:xlink', 'http://www.w3.org/1999/xlink');
+ $svg->setAttribute('role', $this->ariaRole);
$svg->setAttribute('width', '100%');
$svg->setAttribute('height', '100%');
$svg->setAttribute(
@@ -150,6 +172,42 @@ class SVGRenderer
return $svg;
}
+ /**
+ * Add aria title and description
+ *
+ * Adds an aria title and desc element to the given SVG node, which are used to describe this SVG by accessibility
+ * tools such as screen readers.
+ *
+ * @param DOMNode $svg The SVG DOMNode to which the aria attributes should be attached
+ * @param $title The title text
+ * @param $description The description text
+ */
+ private function addAriaDescription (DOMNode $svg, $titleText, $descriptionText)
+ {
+ $doc = $svg->ownerDocument;
+
+ $titleId = $descId = '';
+ if (isset ($this->ariaTitle)) {
+ $titleId = 'aria-title-' . $this->stripNonAlphanumeric($titleText);
+ $title = $doc->createElement('title');
+ $title->setAttribute('id', $titleId);
+
+ $title->appendChild($doc->createTextNode($titleText));
+ $svg->appendChild($title);
+ }
+
+ if (isset ($this->ariaDescription)) {
+ $descId = 'aria-desc-' . $this->stripNonAlphanumeric($descriptionText);
+ $desc = $doc->createElement('desc');
+ $desc->setAttribute('id', $descId);
+
+ $desc->appendChild($doc->createTextNode($descriptionText));
+ $svg->appendChild($desc);
+ }
+
+ $svg->setAttribute('aria-labelledby', join(' ', array($titleId, $descId)));
+ }
+
/**
* Initialises the XML-document, SVG-element and this figure's root canvas
*
@@ -172,6 +230,7 @@ class SVGRenderer
{
$this->createRootDocument();
$ctx = $this->createRenderContext();
+ $this->addAriaDescription($this->svg, $this->ariaTitle, $this->ariaDescription);
$this->svg->appendChild($this->rootCanvas->toSvg($ctx));
$this->document->formatOutput = true;
return $this->document->saveXML();
@@ -232,4 +291,40 @@ class SVGRenderer
{
$this->yAspectRatio = $alignment;
}
+
+ /**
+ * Set the aria description, that is used as a title for this SVG in screen readers
+ *
+ * @param $text
+ */
+ public function setAriaTitle($text)
+ {
+ $this->ariaTitle = $text;
+ }
+
+ /**
+ * Set the aria description, that is used to describe this SVG in screen readers
+ *
+ * @param $text
+ */
+ public function setAriaDescription($text)
+ {
+ $this->ariaDescription = $text;
+ }
+
+ /**
+ * Set the aria role, that is used to describe the purpose of this SVG in screen readers
+ *
+ * @param $text
+ */
+ public function setAriaRole($text)
+ {
+ $this->ariaRole = $text;
+ }
+
+
+ private function stripNonAlphanumeric($str)
+ {
+ return preg_replace('/[^A-Za-z]+/', '', $str);
+ }
}
diff --git a/modules/monitoring/application/controllers/AlertsummaryController.php b/modules/monitoring/application/controllers/AlertsummaryController.php
index 1b3db8093..252a67091 100644
--- a/modules/monitoring/application/controllers/AlertsummaryController.php
+++ b/modules/monitoring/application/controllers/AlertsummaryController.php
@@ -341,6 +341,8 @@ class Monitoring_AlertsummaryController extends Controller
public function createHealingChart()
{
$gridChart = new GridChart();
+ $gridChart->title = t('Healing Chart');
+ $gridChart->description = t('Notifications and average reaction time per hour.');
$gridChart->alignTopLeft();
$gridChart->setAxisLabel($this->createPeriodDescription(), mt('monitoring', 'Notifications'))
@@ -477,6 +479,8 @@ class Monitoring_AlertsummaryController extends Controller
public function createDefectImage()
{
$gridChart = new GridChart();
+ $gridChart->title = t('Defect Chart');
+ $gridChart->description = t('Notifications and defects per hour');
$gridChart->alignTopLeft();
$gridChart->setAxisLabel($this->createPeriodDescription(), mt('monitoring', 'Notifications'))
diff --git a/modules/monitoring/application/controllers/ChartController.php b/modules/monitoring/application/controllers/ChartController.php
index b01702c04..f19d3f458 100644
--- a/modules/monitoring/application/controllers/ChartController.php
+++ b/modules/monitoring/application/controllers/ChartController.php
@@ -236,6 +236,9 @@ class Monitoring_ChartController extends Controller
$unknownBars[] = array($servicegroup->servicegroup, $servicegroup->services_unknown_unhandled);
}
$this->view->chart = new GridChart();
+ $this->view->chart->title = t('Service Group Chart');
+ $this->view->chart->description = t('Contains service states for each service group.');
+
$this->view->chart->alignTopLeft();
$this->view->chart->setAxisLabel('', mt('monitoring', 'Services'))
->setXAxis(new StaticAxis())
@@ -292,6 +295,9 @@ class Monitoring_ChartController extends Controller
}
$tooltip = mt('monitoring', '{title}:
{value} of {sum} hosts are {label}');
$this->view->chart = new GridChart();
+ $this->view->chart->title = t('Host Group Chart');
+ $this->view->chart->description = t('Contains host states of each service group.');
+
$this->view->chart->alignTopLeft();
$this->view->chart->setAxisLabel('', mt('monitoring', 'Hosts'))
->setXAxis(new StaticAxis())