1<?php
2
3require_once(dirname(__FILE__).'/../../lib/plugins.php');
4require_once(dirname(__FILE__).'/../../lib/project_file.php');
5require_once(dirname(__FILE__).'/../file/plot_dependency.php');
6require_once(dirname(__FILE__).'/../../pchart/pchart/pchart.php');
7require_once(dirname(__FILE__).'/../../pchart/pchart/pdata.php');
8
9class projects_plugin_plot extends MakeRule {
10	/**
11	 * The name of the rule, a human readable string, a unique identifier
12	 */
13	public function name() { return "Plot"; }
14
15	/**
16	 * whether this rule can make a given target
17	 */
18	public function can_handle($project, $file) {
19		if (!has_extension($file->name(), '.png')) return false;
20		$plot = $this->replace_extension($file->name(), '.png', '.plot');
21		return $project->file($plot) != NULL;
22	}
23
24	/**
25	 * returns a project file that can make $name
26	 */
27	public function handle($project, $file) {
28		$plot = $this->replace_extension($file->name(), '.png', '.plot');
29		$source = new PlotDefinition(array('type' => SOURCE,
30			'name' => $plot));
31		$source->add_content(file_get_contents($project->path() . $plot));
32		$target = new PlotTarget($project, $file, $source);
33		return $target;
34	}
35
36}
37
38class PlotTarget extends ProjectGenerated {
39	private $plot = NULL;
40	public function __construct($project, $file, $source) {
41		$deps = $file->dependency();
42		if (!in_array($source->name(), $deps)) $deps[] = $source->name();
43		$this->deps = $deps;
44		$this->name = $file->name();
45		$this->plot = $source;
46	}
47
48	public function makable() { return true; }
49
50	public function make($working_path) {
51		// This will import the file http://my.domain.com/myData.csv using each column as a serie
52		if (!$this->plot->valid()) {
53			$file = $this->plot->name();
54			$error = $this->plot->error();
55			$this->log($working_path, "Plot file $file is invalid: $error");
56			return 1;
57		}
58		$data = new pData();
59		$columns = array();
60		$all_columns = array();
61
62		$x_column = $this->plot->property('x_column') - 1;
63		if ($x_column === NULL) $x_column = 0;
64		$data_file = $this->plot->data_property('name');
65		$deliminator = $this->plot->data_property('deliminator');
66		$has_header = $this->plot->data_property('header') == 'yes';
67		foreach ($this->plot->columns() as $column => $name) {
68			if ($column != $x_column + 1) $columns[] = $column - 1;
69			$all_columns[] = $column - 1;
70		}
71		$data->ImportFromCSV($working_path . $data_file,
72			$deliminator, $all_columns, $has_header);
73		foreach ($columns as $column) {
74			$name = $this->plot->column($column + 1);
75			$data->AddSerie('Serie' . $column);
76			$data->SetSerieName($name, "Serie" . $column);
77		}
78		$max_col = -1;
79		$max_val = NULL;
80		foreach ($data->GetData() as $record) {
81			foreach ($columns as $column) {
82				$point = $record['Serie' .$column];
83				if ($max_val === NULL || $point > $max_val) {
84					$max_val = $point;
85					$max_col = $column;
86				}
87			}
88		}
89		$x_label = $this->plot->axis_property('x', 'label');
90		if ($x_label)
91			$data->SetXAxisName($x_label);
92		else
93			$data->SetXAxisName($this->plot->column($x_column + 1));
94		$x_unit = $this->plot->axis_property('x', 'unit');
95		if ($x_unit) $data->SetXAxisUnit($x_unit);
96		$y_label = $this->plot->axis_property('y', 'label');
97		reset($columns);
98		if ($y_label)
99			$data->SetYAxisName($y_label);
100		else
101			$data->SetYAxisName($this->plot->column(current($columns) + 1));
102		$y_unit = $this->plot->axis_property('y', 'unit');
103		if ($y_unit) $data->SetyAxisUnit($y_unit);
104
105		$width = $this->plot->property('width');
106		if (!$width) $width = 640;
107		$height = $this->plot->property('height');
108		if (!$height) $height = 480;
109		$plot = new pChart($width, $height);
110		$font_name = $this->plot->property('font-name');
111		if (!$font_name) $font_name = 'tahoma.ttf';
112		$font_name = 'lib/plugins/projects/pchart/fonts/' . $font_name;
113		$font_size = $this->plot->property('font_size');
114		if (!$font_size) $font_size = 12;
115		$plot->setFontProperties($font_name, $font_size);
116		$h = $font_size + 10;
117		$left_margin = 0;
118		foreach ($data->GetData() as $record) {
119	    	$position   = imageftbbox($font_size, 0, $font_name,
120	    		$record['Serie' . $max_col]);
121	    	$text_width  = $position[2] - $position[0];
122			if ($text_width > $left_margin) $left_margin = $text_width;
123		}
124		$left_margin += 2 * $h;
125		$plot->setGraphArea($left_margin, 2 * $h, $width - $h, $height - 2 * $h);
126		$background = $this->plot->property('background');
127		if (!$background)
128			$background = array('R' => 255, 'G' => 255, 'B' => 255);
129		else $background = html_color_to_RGB($background);
130		$plot->drawGraphArea($background['R'], $background['G'],
131			$background['B']);
132		// pick the largest scale
133		$plot->drawXYScale($data->GetData(), $data->GetDataDescription(),
134			'Serie' . $max_col, 'Serie' . $x_column,
135			0, 0, 0, TRUE, 0, 0);
136		$line_no = 0;
137		$colors = array();
138		foreach ($columns as $column) {
139			$name = $this->plot->column($column + 1);
140			$style = $this->plot->line_style($name, 'style');
141			$line_color = $this->plot->line_style($name, 'color');
142			if (!$line_color)
143				$colors[$name] = array('R' => 0, 'G' => 0, 'B' => 0);
144			else $colors[$name] = html_color_to_RGB($line_color);
145			$plot->setColorPalette($line_no, $colors[$name]['R'],
146				$colors[$name]['G'], $colors[$name]['B']);
147			if (!$style || $style == 'line' || $style == 'both') {
148				$line_width = $this->plot->line_style($name, 'width');
149				if (!$line_width) $line_width = 1;
150				$dot_size = $this->plot->line_style($name, 'dot-size');
151				if (!$dot_size) $dot_size = 0;
152				$plot->setLineStyle($line_width, $dot_size);
153				$plot->drawXYGraph($data->GetData(),
154					$data->GetDataDescription(),
155					'Serie' . $column, 'Serie' . $x_column, $line_no);
156			}
157			if ($style == 'point' || $style == 'both') {
158				$radius = $this->plot->line_style($name, 'radius');
159				if (!$radius) $radius = 5;
160				$plot->drawXYPlotGraph($data->GetData(),
161					$data->GetDataDescription(),
162					'Serie' . $column, 'Serie' . $x_column, $line_no,
163					$radius, $radius - 2);
164			}
165			$line_no++;
166		}
167
168		$title = $this->plot->property('title');
169
170		foreach ($columns as $column)
171			$data->removeSerie('Serie' . $column);
172		$in_legend = array();
173		$description = $data->GetDataDescription();
174		$description['Description'] = array();
175		$palette_id = 0;
176		foreach ($columns as $column) {
177			$name = $this->plot->column($column + 1);
178			if (in_array($name, $in_legend)) continue;
179			$in_legend[] = $name;
180			$description['Description']['Serie' . $column] = $name;
181			$plot->setColorPalette($palette_id, $colors[$name]['R'],
182				$colors[$name]['G'], $colors[$name]['B']);
183			++$palette_id;
184		}
185		$legend_box_size =$plot->getLegendBoxSize($description);
186		$legend_position = $this->plot->property('legend-position');
187		if (!$legend_position) $legend_position = 'top-left';
188		switch ($legend_position) {
189			case 'top-left':
190				$legend_left = 0;
191				$legend_top = 0;
192				break;
193			case 'top':
194				$legend_left = ($width - $h - $left_margin - $legend_box_size[0]) / 2;
195				$legend_top = 0;
196				break;
197			case 'top-right':
198				$legend_left = $width - $left_margin - $h - $legend_box_size[0];
199				$legend_top = 0;
200				break;
201			case 'left':
202				$legend_left = 0;
203				$legend_top = ($height - 4 * $h - $legend_box_size[1]) / 2;
204				break;
205			case 'center':
206				$legend_left = ($width - $h - $left_margin - $legend_box_size[0]) / 2;
207				$legend_top = ($height - 4 * $h - $legend_box_size[1]) / 2;
208				break;
209			case 'right':
210				$legend_left = $width - $left_margin - $h - $legend_box_size[0];
211				$legend_top = ($height - 4 * $h  - $legend_box_size[1]) / 2;
212				break;
213			case 'bottom-left':
214				$legend_left = 0;
215				$legend_top = $height - 4 * $h - $legend_box_size[1];
216				break;
217			case 'bottom':
218				$legend_left = ($width - $h - $left_margin - $legend_box_size[0]) / 2;
219				$legend_top = $height - 4 * $h - $legend_box_size[1];
220				break;
221			case 'bottom-right':
222				$legend_left = $width - $left_margin - $h - $legend_box_size[0];
223				$legend_top = $height - 4 * $h - $legend_box_size[1];
224				break;
225		}
226		$plot->drawLegend($left_margin + $legend_left, 2 * $h + $legend_top, $description,
227			255, 255, 255, 100, 100, 100, 0, 0, 0, true);
228		$plot->drawTitle($h, 0, $title, 0, 0, 0, $width-$h, $h * 2, 100);
229		$plot->Render($this->path($working_path));
230
231		$file_name =$this->plot->name();
232		$plot_name =$this->name();
233		$this->log($working_path, "Successfully plotted $file_name as $plot_name\ntitle: $title\n");
234		return 0;
235	}
236}
237
238?>