InlinePie: Utilize SVG to render charts instantly

Inline pie charts usually don't contain that much
data and the SVG should be rather small in size.
So it doesn't hurt rendering them instantly.
This commit is contained in:
Johannes Meyer 2020-09-28 16:40:39 +02:00
parent 37fb455977
commit 8c73f0462e
3 changed files with 32 additions and 59 deletions

View File

@ -73,23 +73,7 @@ class InlinePie extends AbstractWidget
* *
* @var string * @var string
*/ */
private $template =<<<'EOD' private $template = '<div class="inline-pie {class}">{svg}</div>';
<span sparkType="pie" class="sparkline {class}" title="{title}" role="img" aria-label="{title}"
sparkSliceColors="[{colors}]" values="{data}"></span>
{noscript}
EOD;
private $noscript =<<<'EOD'
<noscript>
<img width={size} height={size} class="inlinepie {class}" title="{title}" role="img" aria-label="{title}"
src="{url}" data-icinga-colors="{colors}" data-icinga-values="{data}"/>
</noscript>
EOD;
/**
* @var Url
*/
private $url;
/** /**
* The colors used to display the slices of this pie-chart. * The colors used to display the slices of this pie-chart.
@ -106,9 +90,9 @@ EOD;
private $title; private $title;
/** /**
* @var * @var int
*/ */
private $size; private $size = 16;
/** /**
* The data displayed by the pie-chart * The data displayed by the pie-chart
@ -132,7 +116,7 @@ EOD;
public function setData(array $data) public function setData(array $data)
{ {
$this->data = $data; $this->data = $data;
$this->url->setParam('data', implode(',', $data));
return $this; return $this;
} }
@ -146,15 +130,17 @@ EOD;
public function setSize($size = null) public function setSize($size = null)
{ {
$this->size = $size; $this->size = $size;
return $this; return $this;
} }
/** /**
* Do not display the NoScript fallback html * Do not display the NoScript fallback html
*
* @deprecated noop
*/ */
public function disableNoScript() public function disableNoScript()
{ {
$this->noscript = '';
} }
/** /**
@ -167,6 +153,7 @@ EOD;
public function setSparklineClass($class) public function setSparklineClass($class)
{ {
$this->class = $class; $this->class = $class;
return $this; return $this;
} }
@ -180,11 +167,7 @@ EOD;
public function setColors(array $colors = null) public function setColors(array $colors = null)
{ {
$this->colors = $colors; $this->colors = $colors;
if (isset($colors)) {
$this->url->setParam('colors', implode(',', $colors));
} else {
$this->url->setParam('colors', null);
}
return $this; return $this;
} }
@ -198,6 +181,7 @@ EOD;
public function setTitle($title) public function setTitle($title)
{ {
$this->title = $this->view()->escape($title); $this->title = $this->view()->escape($title);
return $this; return $this;
} }
@ -211,7 +195,7 @@ EOD;
public function __construct(array $data, $title, $colors = null) public function __construct(array $data, $title, $colors = null)
{ {
$this->setTitle($title); $this->setTitle($title);
$this->url = Url::fromPath('svg/chart.php');
if (array_key_exists('data', $data)) { if (array_key_exists('data', $data)) {
$this->data = $data['data']; $this->data = $data['data'];
if (array_key_exists('colors', $data)) { if (array_key_exists('colors', $data)) {
@ -220,12 +204,14 @@ EOD;
} else { } else {
$this->setData($data); $this->setData($data);
} }
if (isset($colors)) { if (isset($colors)) {
$this->setColors($colors); $this->setColors($colors);
} else { } else {
$this->setColors($this->colors); $this->setColors($this->colors);
} }
} }
/** /**
* Renders this widget via the given view and returns the * Renders this widget via the given view and returns the
* HTML as a string * HTML as a string
@ -234,14 +220,15 @@ EOD;
*/ */
public function render() public function render()
{ {
if ($this->view()->layout()->getLayout() === 'pdf') {
$pie = new PieChart(); $pie = new PieChart();
$pie->alignTopLeft(); $pie->alignTopLeft();
$pie->disableLegend(); $pie->disableLegend();
$pie->drawPie(array( $pie->drawPie([
'data' => $this->data, 'colors' => $this->colors 'data' => $this->data,
)); 'colors' => $this->colors
]);
if ($this->view()->layout()->getLayout() === 'pdf') {
try { try {
$png = $pie->toPng($this->size, $this->size); $png = $pie->toPng($this->size, $this->size);
return '<img class="inlinepie" src="data:image/png;base64,' . base64_encode($png) . '" />'; return '<img class="inlinepie" src="data:image/png;base64,' . base64_encode($png) . '" />';
@ -250,39 +237,27 @@ EOD;
} }
} }
$pie->title = $this->title;
$pie->description = $this->title;
$template = $this->template; $template = $this->template;
// TODO: Check whether we are XHR and don't send
$template = str_replace('{noscript}', $this->noscript, $template);
$template = str_replace('{url}', $this->url, $template);
$template = str_replace('{class}', $this->class, $template); $template = str_replace('{class}', $this->class, $template);
$template = str_replace('{svg}', $pie->render(), $template);
// style
$template = str_replace('{size}', isset($this->size) ? $this->size : 16, $template);
$template = str_replace('{title}', $this->title, $template);
$template = str_replace('{colors}', implode(',', $this->colors), $template);
// Locale-ignorant string cast. Please. Do. NOT. Remove. This. Again.
// Problem is that implode respects locales when casting floats. This means
// that implode(',', array(1.1, 1.2)) would read '1,1,1,2'.
$data = array();
foreach ($this->data as $dat) {
$data[] = sprintf('%F', $dat);
}
$template = str_replace('{data}', htmlspecialchars(implode(',', $data)), $template);
return $template; return $template;
} }
public static function createFromStateSummary(stdClass $states, $title, array $colors) public static function createFromStateSummary(stdClass $states, $title, array $colors)
{ {
$handledUnhandledStates = array(); $handledUnhandledStates = [];
foreach ($states as $key => $value) { foreach ($states as $key => $value) {
if (StringHelper::endsWith($key, '_handled') || StringHelper::endsWith($key, '_unhandled')) { if (StringHelper::endsWith($key, '_handled') || StringHelper::endsWith($key, '_unhandled')) {
$handledUnhandledStates[$key] = $value; $handledUnhandledStates[$key] = $value;
} }
} }
$chart = new self(array_values($handledUnhandledStates), $title, $colors); $chart = new self(array_values($handledUnhandledStates), $title, $colors);
return $chart return $chart
->setSize(50) ->setSize(50)
->setTitle('') ->setTitle('')

View File

@ -425,9 +425,6 @@ class Perfdata
$pieChart = new InlinePie($data, $this); $pieChart = new InlinePie($data, $this);
$pieChart->setColors(array('#44bb77', '#ffaa44', '#ff5566', '#ddccdd')); $pieChart->setColors(array('#44bb77', '#ffaa44', '#ff5566', '#ddccdd'));
if (Zend_Controller_Front::getInstance()->getRequest()->isXmlHttpRequest()) {
$pieChart->disableNoScript();
}
return $pieChart; return $pieChart;
} }

View File

@ -147,12 +147,13 @@
} }
// Performance data pie charts // Performance data pie charts
.sparkline { .inline-pie {
height: 1em; display: inline-block;
height: 14/12em;
margin-right: 0.1em; margin-right: 0.1em;
position: relative; position: relative;
top: 0.1em; top: 0.1em;
width: 1em; width: 14/12em;
} }
// Host and service summaries in detail and list views // Host and service summaries in detail and list views