1<?php
2/*
3 * This work is hereby released into the Public Domain.
4 * To view a copy of the public domain dedication,
5 * visit http://creativecommons.org/licenses/publicdomain/ or send a letter to
6 * Creative Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.
7 *
8 */
9
10// Artichow configuration
11/* <php5> */
12if(is_file(dirname(__FILE__)."/Artichow.cfg.php")) { // For PHP 4+5 version
13	require_once dirname(__FILE__)."/Artichow.cfg.php";
14}
15/* </php5> */
16
17// Some useful files
18require_once ARTICHOW."/Component.class.php";
19require_once ARTICHOW."/Image.class.php";
20require_once ARTICHOW."/common.php";
21
22require_once ARTICHOW."/inc/Grid.class.php";
23require_once ARTICHOW."/inc/Tools.class.php";
24require_once ARTICHOW."/inc/Drawer.class.php";
25require_once ARTICHOW."/inc/Math.class.php";
26require_once ARTICHOW."/inc/Tick.class.php";
27require_once ARTICHOW."/inc/Axis.class.php";
28require_once ARTICHOW."/inc/Legend.class.php";
29require_once ARTICHOW."/inc/Mark.class.php";
30require_once ARTICHOW."/inc/Label.class.php";
31require_once ARTICHOW."/inc/Text.class.php";
32require_once ARTICHOW."/inc/Color.class.php";
33require_once ARTICHOW."/inc/Font.class.php";
34require_once ARTICHOW."/inc/Gradient.class.php";
35
36// Catch all errors
37ob_start();
38
39/**
40 * A graph
41 *
42 * @package Artichow
43 */
44class awGraph extends awImage {
45
46	/**
47	 * Graph name
48	 *
49	 * @var string
50	 */
51	protected $name;
52
53	/**
54	 * Cache timeout
55	 *
56	 * @var int
57	 */
58	protected $timeout = 0;
59
60	/**
61	 * Graph timing ?
62	 *
63	 * @var bool
64	 */
65	protected $timing;
66
67	/**
68	 * Components
69	 *
70	 * @var array
71	 */
72	private $components = array();
73
74	/**
75	 * Graph title
76	 *
77	 * @var Label
78	 */
79	public $title;
80
81	/**
82	 * Construct a new awgraph
83	 *
84	 * @param int $width Graph width
85	 * @param int $height Graph height
86	 * @param string $name Graph name for the cache (must be unique). Let it null to not use the cache.
87	 * @param int $timeout Cache timeout (unix timestamp)
88	 */
89	public function __construct($width = NULL, $height = NULL, $name = NULL, $timeout = 0) {
90
91		parent::__construct();
92
93		$this->setSize($width, $height);
94
95		if(ARTICHOW_CACHE) {
96
97			$this->name = $name;
98			$this->timeout = $timeout;
99
100			// Clean sometimes all the cache
101			if(mt_rand(0, 5000) ===  0) {
102				awGraph::cleanCache();
103			}
104
105			if($this->name !== NULL) {
106
107				$file = ARTICHOW."/cache/".$this->name."-time";
108
109				if(is_file($file)) {
110
111					$type = awGraph::cleanGraphCache($file);
112
113					if($type === NULL) {
114						awGraph::deleteFromCache($this->name);
115					} else {
116						header("Content-Type: image/".$type);
117						readfile(ARTICHOW."/cache/".$this->name."");
118						exit;
119					}
120
121				}
122
123			}
124
125		}
126
127
128		$this->title = new awLabel(
129			NULL,
130			new awDejaVuSans(16),
131			NULL,
132			0
133		);
134		$this->title->setAlign(awLabel::CENTER, awLabel::BOTTOM);
135
136	}
137
138	/**
139	 * Delete a graph from the cache
140	 *
141	 * @param string $name Graph name
142	 * @return bool TRUE on success, FALSE on failure
143	 */
144	public static function deleteFromCache($name) {
145
146		if(ARTICHOW_CACHE) {
147
148			if(is_file(ARTICHOW."/cache/".$name."-time")) {
149				unlink(ARTICHOW."/cache/".$name."");
150				unlink(ARTICHOW."/cache/".$name."-time");
151			}
152
153		}
154
155	}
156
157	/**
158	 * Delete all graphs from the cache
159	 */
160	public static function deleteAllCache() {
161
162		if(ARTICHOW_CACHE) {
163
164			$dp = opendir(ARTICHOW."/cache");
165
166			while($file = readdir($dp)) {
167				if($file !== '.' and $file != '..') {
168					unlink(ARTICHOW."/cache/".$file);
169				}
170			}
171
172		}
173
174	}
175
176	/**
177	 * Clean cache
178	 */
179	public static function cleanCache() {
180
181		if(ARTICHOW_CACHE) {
182
183			$glob = glob(ARTICHOW."/cache/*-time");
184
185			foreach($glob as $file) {
186
187				$type = awGraph::cleanGraphCache($file);
188
189				if($type === NULL) {
190					$name = ereg_replace(".*/(.*)\-time", "\\1", $file);
191					awGraph::deleteFromCache($name);
192				}
193
194			}
195
196		}
197
198	}
199
200	/**
201	 * Enable/Disable graph timing
202	 *
203	 * @param bool $timing
204	 */
205	public function setTiming($timing) {
206		$this->timing = (bool)$timing;
207	}
208
209	/**
210	 * Add a component to the graph
211	 *
212	 * @param awComponent $component
213	 */
214	public function add(awComponent $component) {
215
216		$this->components[] = $component;
217
218	}
219
220	/**
221	 * Build the graph and draw component on it
222	 * Image is sent to the user browser
223	 */
224	public function draw() {
225
226		if($this->timing) {
227			$time = microtimeFloat();
228		}
229
230		$this->create();
231
232		foreach($this->components as $component) {
233
234			$this->drawComponent($component);
235
236		}
237
238		$this->drawTitle();
239		$this->drawShadow();
240
241		if($this->timing) {
242			$this->drawTiming(microtimeFloat() - $time);
243		}
244
245		$this->send();
246
247		if(ARTICHOW_CACHE) {
248
249			if($this->name !== NULL) {
250
251				$data = ob_get_contents();
252
253				if(is_writable(ARTICHOW."/cache") === FALSE) {
254					trigger_error("Cache directory is not writable");
255				}
256
257				$file = ARTICHOW."/cache/".$this->name."";
258				file_put_contents($file, $data);
259
260				$file .= "-time";
261				file_put_contents($file, $this->timeout."\n".$this->getFormat());
262
263			}
264
265		}
266
267	}
268
269	private function drawTitle() {
270
271		$drawer = $this->getDrawer();
272
273		$point = new awPoint(
274			$this->width / 2,
275			10
276		);
277
278		$this->title->draw($drawer, $point);
279
280	}
281
282	private function drawTiming($time) {
283
284		$drawer = $this->getDrawer();
285
286		$label = new awLabel;
287		$label->set("(".sprintf("%.3f", $time)." s)");
288		$label->setAlign(awLabel::LEFT, awLabel::TOP);
289		$label->border->show();
290		$label->setPadding(1, 0, 0, 0);
291		$label->setBackgroundColor(new awColor(230, 230, 230, 25));
292
293		$label->draw($drawer, new awPoint(5, $drawer->height - 5));
294
295	}
296
297	private static function cleanGraphCache($file) {
298
299		list(
300			$time,
301			$type
302		) = explode("\n", file_get_contents($file));
303
304		$time = (int)$time;
305
306		if($time !== 0 and $time < time()) {
307			return NULL;
308		} else {
309			return $type;
310		}
311
312
313	}
314
315}
316
317registerClass('Graph');
318
319/*
320 * To preserve PHP 4 compatibility
321 */
322function microtimeFloat() {
323	list($usec, $sec) = explode(" ", microtime());
324	return (float)$usec + (float)$sec;
325}
326?>
327