1<?php
2/* Icinga Web 2 | (c) 2013 Icinga Development Team | GPLv2+ */
3
4namespace Icinga\Chart\Graph;
5
6use DOMElement;
7use Icinga\Chart\Primitive\Animation;
8use Icinga\Chart\Primitive\Drawable;
9use Icinga\Chart\Primitive\Rect;
10use Icinga\Chart\Primitive\Styleable;
11use Icinga\Chart\Render\RenderContext;
12
13/**
14 * Bar graph implementation
15 */
16class BarGraph extends Styleable implements Drawable
17{
18    /**
19     * The dataset order
20     *
21     * @var int
22     */
23    private $order = 0;
24
25    /**
26     * The width of the bars.
27     *
28     * @var int
29     */
30    private $barWidth = 3;
31
32    /**
33     * The dataset to use for this bar graph
34     *
35     * @var array
36     */
37    private $dataSet;
38
39    /**
40     * The tooltips
41     *
42     * @var
43     */
44    private $tooltips;
45
46    /**
47     * All graphs
48     *
49     * @var
50     */
51    private $graphs;
52
53    /**
54     * Create a new BarGraph with the given dataset
55     *
56     * @param array $dataSet    An array of data points
57     * @param int   $order      The graph number displayed by this BarGraph
58     * @param array $tooltips   The tooltips to display for each value
59     */
60    public function __construct(
61        array $dataSet,
62        array &$graphs,
63        $order,
64        array $tooltips = null
65    ) {
66        $this->order = $order;
67        $this->dataSet = $dataSet;
68
69        $this->tooltips = $tooltips;
70        foreach ($this->tooltips as $value) {
71            $ts[] = $value;
72        }
73        $this->tooltips = $ts;
74
75        $this->graphs = $graphs;
76    }
77
78    /**
79     * Apply configuration styles from the $cfg
80     *
81     * @param array $cfg        The configuration as given in the drawBars call
82     */
83    public function setStyleFromConfig(array $cfg)
84    {
85        foreach ($cfg as $elem => $value) {
86            if ($elem === 'color') {
87                $this->setFill($value);
88            } elseif ($elem === 'width') {
89                $this->setStrokeWidth($value);
90            }
91        }
92    }
93
94    /**
95     * Draw a single rectangle
96     *
97     * @param array     $point          The
98     * @param string    $fill           The fill color to use
99     * @param           $strokeWidth
100     * @param null      $index
101     *
102     * @return Rect
103     */
104    private function drawSingleBar($point, $fill, $strokeWidth, $index = null)
105    {
106        $rect = new Rect($point[0] - ($this->barWidth / 2), $point[1], $this->barWidth, 100 - $point[1]);
107        $rect->setFill($fill);
108        $rect->setStrokeWidth($strokeWidth);
109        $rect->setStrokeColor('black');
110        if (isset($index)) {
111            $rect->setAttribute('data-icinga-graph-index', $index);
112        }
113        $rect->setAttribute('data-icinga-graph-type', 'bar');
114        $rect->setAdditionalStyle('clip-path: url(#clip);');
115        return $rect;
116    }
117
118    /**
119     * Render this BarChart
120     *
121     * @param   RenderContext   $ctx    The rendering context to use for drawing
122     *
123     * @return  DOMElement      $dom    Element
124     */
125    public function toSvg(RenderContext $ctx)
126    {
127        $doc = $ctx->getDocument();
128        $group = $doc->createElement('g');
129        $idx = 0;
130
131        if (count($this->dataSet) > 15) {
132            $this->barWidth = 2;
133        }
134        if (count($this->dataSet) > 25) {
135            $this->barWidth = 1;
136        }
137
138        foreach ($this->dataSet as $x => $point) {
139            // add white background bar, to prevent other bars from altering transparency effects
140            $bar = $this->drawSingleBar($point, 'white', $this->strokeWidth, $idx++)->toSvg($ctx);
141            $group->appendChild($bar);
142
143            // draw actual bar
144            $bar = $this->drawSingleBar($point, $this->fill, $this->strokeWidth)->toSvg($ctx);
145            if (isset($this->tooltips[$x])) {
146                $data = array(
147                    'label' => isset($this->graphs[$this->order]['label']) ?
148                            strtolower($this->graphs[$this->order]['label']) : '',
149                    'color' => isset($this->graphs[$this->order]['color']) ?
150                            strtolower($this->graphs[$this->order]['color']) : '#fff'
151                );
152                $format = isset($this->graphs[$this->order]['tooltip'])
153                    ? $this->graphs[$this->order]['tooltip'] : null;
154                $title = $ctx->getDocument()->createElement('title');
155                $title->textContent = $this->tooltips[$x]->renderNoHtml($this->order, $data, $format);
156                $bar->appendChild($title);
157            }
158            $group->appendChild($bar);
159        }
160        return $group;
161    }
162}
163