1<?php
2// (c) Copyright by authors of the Tiki Wiki CMS Groupware Project
3//
4// All Rights Reserved. See copyright.txt for details and a complete list of authors.
5// Licensed under the GNU LESSER GENERAL PUBLIC LICENSE. See license.txt for details.
6// $Id$
7
8require_once 'lib/graph-engine/abstract.gridbased.php';
9
10class BarBasedGraphic extends GridBasedGraphic // {{{1
11{
12	var $columns;
13	var $styleMap;
14	var $columnMap;
15
16	function __construct() // {{{2
17	{
18		parent::__construct();
19		$this->columns = [];
20		$this->styleMap = [];
21		$this->columnMap = [];
22	}
23
24	function getRequiredSeries() // {{{2
25	{
26		return [
27						'label' => false,
28						'color' => false,
29						'style' => false,
30						'x' => true,
31						'y0' => true
32		];
33	}
34
35	function _getMinValue($type) // {{{2
36	{
37		switch ($type) {
38			case 'dependant':
39				$extremes = [];
40				foreach ($this->columns as $line) {
41					$extremes[] = min($line);
42				}
43
44				$min = min($extremes);
45				break;
46			case 'independant':
47				$min = min(array_keys($this->columns));
48		}
49
50		if ($min > 0) {
51			$min = 0;
52		}
53
54		return $min;
55	}
56
57	function _getMaxValue($type) // {{{2
58	{
59		switch ($type) {
60			case 'dependant':
61				$extremes = [];
62				foreach ($this->columns as $line) {
63					$extremes[] = max($line);
64				}
65
66				return max($extremes);
67			case 'independant':
68				return max(array_keys($this->columns));
69		}
70	}
71
72	function _getLabels($type) // {{{2
73	{
74		switch ($type) {
75			case 'dependant':
76				return [];
77			case 'independant':
78				return array_keys($this->columns);
79		}
80	}
81
82	function _handleData($data) // {{{2
83	{
84		$columns = [];
85
86		for ($i = 0; isset($data['y' . $i]); ++$i) {
87			$columns[] = $data['y' . $i];
88		}
89
90		$count = count($columns);
91
92		if (! isset($data['color'])) {
93			$data['color'] = [];
94
95			for ($i = 0; $count > $i; ++$i) {
96				$data['color'][] = $this->_getColor();
97			}
98		}
99
100		if (! isset($data['style'])) {
101			for ($i = 0; $count > $i; ++$i) {
102				$data['style'][] = 'FillStroke-' . $data['color'][$i];
103			}
104		}
105
106		if (isset($data['label'])) {
107			foreach ($data['label'] as $key => $label) {
108				$this->addLegend(
109					$data['color'][$key],
110					$label,
111					(isset($data['link']) && isset($data['link'][$key])) ? $data['link'][$key] : 0
112				);
113			}
114		}
115
116		foreach ($columns as $key => $line) {
117			$style = $data['style'][$key];
118			$this->styleMap[$style] = "y$key";
119
120			foreach ($line as $key => $value) {
121				$x = $data['x'][$key];
122				$this->columnMap[$x] = $key;
123
124				if (! isset($this->columns[$x])) {
125					$this->columns[$x] = [];
126				}
127
128				if (! empty($value)) {
129					$this->columns[$x][$style] = $value;
130				} else {
131					$this->columns[$x][$style] = 0;
132				}
133			}
134		}
135
136		return true;
137	}
138
139	function _drawGridContent(&$renderer) // {{{2
140	{
141		$layout = $this->_layout();
142		$zero = $this->dependant->getLocation(0);
143
144		foreach ($this->columns as $label => $values) {
145			$range = $this->independant->getRange($label);
146
147			switch ($this->independant->orientation) {
148				case 'vertical':
149					$ren = new Fake_GRenderer($renderer, 0, $range[0], 1, $range[1]);
150					break;
151				case 'horizontal':
152					$ren = new Fake_GRenderer($renderer, $range[0], 0, $range[1], 1);
153					break;
154			}
155
156			$positions = $this->_drawColumn($ren, $values, $zero);
157
158			if (is_array($positions)) {
159				$index = $this->columnMap[$label];
160				foreach ($positions as $style => $positionData) {
161					$series = $this->styleMap[$style];
162					$this->_notify($ren, $positionData, $series, $index);
163				}
164			}
165		}
166	}
167
168	function _drawColumn(&$renderer, $values, $zero)
169	{
170		die("Abstract Function Call");
171	}
172
173	function _drawBox(&$renderer, $left, $top, $right, $bottom, $style)
174	{
175		$style = $renderer->getStyle($style);
176
177		switch ($this->independant->orientation) {
178			case 'vertical':
179				$renderer->drawRectangle($bottom, $left, $top, $right, $style);
180				break;
181			case 'horizontal':
182				$renderer->drawRectangle($left, $top, $right, $bottom, $style);
183				break;
184		}
185	}
186
187	function _drawLegendBox(&$renderer, $color) // {{{2
188	{
189		$renderer->drawRectangle(0, 1, 1, 0, $renderer->getStyle("FillStroke-$color"));
190	}
191
192	function _default() // {{{2
193	{
194		return array_merge(
195			parent::_default(),
196			[
197				'grid-independant-scale' => 'static',
198				'grid-independant-major-guide' => 'Thin-LineStroke-Black'
199			]
200		);
201	}
202} // }}}1
203
204class BarStackGraphic extends BarBasedGraphic // {{{1
205{
206	function __construct() // {{{2
207	{
208		parent::__construct();
209	}
210
211	function _getMinValue($type) // {{{2
212	{
213		switch ($type) {
214			case 'dependant':
215				$extremes = [];
216				foreach ($this->columns as $line) {
217					$extremes[] = array_sum($line);
218				}
219
220				$min = min($extremes);
221			case 'independant':
222				$min = min(array_keys($this->columns));
223		}
224
225		if ($min > 0) {
226			$min = 0;
227		}
228
229		return $min;
230	}
231
232	function _getMaxValue($type) // {{{2
233	{
234		switch ($type) {
235			case 'dependant':
236				$extremes = [];
237				foreach ($this->columns as $line) {
238					$extremes[] = array_sum($line);
239				}
240
241				return max($extremes);
242
243			case 'independant':
244				return max(array_keys($this->columns));
245		}
246	}
247
248	function _drawColumn(&$renderer, $values, $zero) // {{{2
249	{
250		$layout = $this->_layout();
251		$begin = ( 1 - $layout['stack-column-width'] ) / 2;
252		$end = $begin + $layout['stack-column-width'];
253
254		$positive = 0;
255		$negative = 0;
256		foreach ($values as $style => $value) {
257			if ($value == 0) {
258				continue;
259			}
260
261			if ($value > 0) {
262				$bottom = $positive;
263				$positive += $value;
264				$top = $positive;
265			} else {
266				$top = $negative;
267				$negative += $value;
268				$bottom = $negative;
269			}
270
271			$this->_drawBox(
272				$renderer,
273				$begin,
274				$this->dependant->getLocation($top),
275				$end,
276				$this->dependant->getLocation($bottom),
277				$style
278			);
279		}
280	}
281
282	function _default() // {{{2
283	{
284		return array_merge(
285			parent::_default(),
286			['stack-column-width' => 0.6]
287		);
288	}
289} // }}}1
290
291class MultibarGraphic extends BarBasedGraphic // {{{1
292{
293	function __construct() // {{{2
294	{
295		parent::__construct();
296	}
297
298	function _drawColumn(&$renderer, $values, $zero) // {{{2
299	{
300		$layout = $this->_layout();
301		$count = count($values);
302		$width = $layout['multi-columns-width'] / $count;
303		$pad = ( 1 - $layout['multi-columns-width'] ) / 2;
304
305		$positions = [];
306		$i = 0;
307
308		foreach ($values as $style => $value) {
309			$base = $pad + $width * $i++;
310
311			if ($value == 0) {
312				continue;
313			}
314
315			$bottom = $this->dependant->getLocation($value);
316			$this->_drawBox($renderer, $base, $zero, $base + $width, $bottom, $style);
317			$positions[$style] = [
318							'left' => $base,
319							'top' => $zero,
320							'right' => $base + $width,
321							'bottom' => $bottom
322			];
323		}
324
325		return $positions;
326	}
327
328	function _default() // {{{2
329	{
330		return array_merge(
331			parent::_default(),
332			['multi-columns-width' => 0.8]
333		);
334	}
335} // }}}1
336