1 |
efrain |
1 |
<?php
|
|
|
2 |
/*
|
|
|
3 |
pSurface - class to draw surface charts
|
|
|
4 |
|
|
|
5 |
Version : 2.1.4
|
|
|
6 |
Made by : Jean-Damien POGOLOTTI
|
|
|
7 |
Last Update : 19/01/2014
|
|
|
8 |
|
|
|
9 |
This file can be distributed under the license you can find at :
|
|
|
10 |
|
|
|
11 |
http://www.pchart.net/license
|
|
|
12 |
|
|
|
13 |
You can find the whole class documentation on the pChart web site.
|
|
|
14 |
*/
|
|
|
15 |
define("UNKNOWN", 0.123456789);
|
|
|
16 |
define("IGNORED", -1);
|
|
|
17 |
define("LABEL_POSITION_LEFT", 880001);
|
|
|
18 |
define("LABEL_POSITION_RIGHT", 880002);
|
|
|
19 |
define("LABEL_POSITION_TOP", 880003);
|
|
|
20 |
define("LABEL_POSITION_BOTTOM", 880004);
|
|
|
21 |
|
|
|
22 |
/* pStock class definition */
|
|
|
23 |
class pSurface
|
|
|
24 |
{
|
|
|
25 |
var $pChartObject;
|
|
|
26 |
var $GridSizeX;
|
|
|
27 |
var $GridSizeY;
|
|
|
28 |
var $Points = [];
|
|
|
29 |
/* Class creator */
|
|
|
30 |
function __construct($pChartObject)
|
|
|
31 |
{
|
|
|
32 |
$this->pChartObject = $pChartObject;
|
|
|
33 |
#$this->GridSize = 10; # UNUSED
|
|
|
34 |
}
|
|
|
35 |
|
|
|
36 |
/* Define the grid size and initialise the 2D matrix */
|
|
|
37 |
function setGrid($XSize = 10, $YSize = 10)
|
|
|
38 |
{
|
|
|
39 |
for ($X = 0; $X <= $XSize; $X++) {
|
|
|
40 |
for ($Y = 0; $Y <= $YSize; $Y++) {
|
|
|
41 |
$this->Points[$X][$Y] = UNKNOWN;
|
|
|
42 |
}
|
|
|
43 |
}
|
|
|
44 |
|
|
|
45 |
$this->GridSizeX = $XSize;
|
|
|
46 |
$this->GridSizeY = $YSize;
|
|
|
47 |
}
|
|
|
48 |
|
|
|
49 |
/* Add a point on the grid */
|
|
|
50 |
function addPoint($X, $Y, $Value, $Force = TRUE)
|
|
|
51 |
{
|
|
|
52 |
if ($X < 0 || $X > $this->GridSizeX) {
|
|
|
53 |
return 0;
|
|
|
54 |
}
|
|
|
55 |
|
|
|
56 |
if ($Y < 0 || $Y > $this->GridSizeY) {
|
|
|
57 |
return 0;
|
|
|
58 |
}
|
|
|
59 |
|
|
|
60 |
if ($this->Points[$X][$Y] == UNKNOWN || $Force) {
|
|
|
61 |
$this->Points[$X][$Y] = $Value;
|
|
|
62 |
} elseif ($this->Points[$X][$Y] == UNKNOWN) {
|
|
|
63 |
$this->Points[$X][$Y] = $Value;
|
|
|
64 |
} else {
|
|
|
65 |
$this->Points[$X][$Y] = ($this->Points[$X][$Y] + $Value) / 2;
|
|
|
66 |
}
|
|
|
67 |
}
|
|
|
68 |
|
|
|
69 |
/* Write the X labels */
|
|
|
70 |
function writeXLabels(array $Format = [])
|
|
|
71 |
{
|
|
|
72 |
$R = $this->pChartObject->FontColorR;
|
|
|
73 |
$G = $this->pChartObject->FontColorG;
|
|
|
74 |
$B = $this->pChartObject->FontColorB;
|
|
|
75 |
$Alpha = $this->pChartObject->FontColorA;
|
|
|
76 |
$Angle = 0;
|
|
|
77 |
$Padding = 5;
|
|
|
78 |
$Position = LABEL_POSITION_TOP;
|
|
|
79 |
$Labels = NULL;
|
|
|
80 |
$CountOffset = 0;
|
|
|
81 |
|
|
|
82 |
/* Override defaults */
|
|
|
83 |
extract($Format);
|
|
|
84 |
|
|
|
85 |
if ($Labels != NULL && !is_array($Labels)) {
|
|
|
86 |
$Labels = [$Labels];
|
|
|
87 |
}
|
|
|
88 |
|
|
|
89 |
$X0 = $this->pChartObject->GraphAreaX1;
|
|
|
90 |
$XSize = ($this->pChartObject->GraphAreaX2 - $this->pChartObject->GraphAreaX1) / ($this->GridSizeX + 1);
|
|
|
91 |
$Settings = ["Angle" => $Angle,"R" => $R,"G" => $G,"B" => $B,"Alpha" => $Alpha];
|
|
|
92 |
if ($Position == LABEL_POSITION_TOP) {
|
|
|
93 |
$YPos = $this->pChartObject->GraphAreaY1 - $Padding;
|
|
|
94 |
$Settings["Align"] = ($Angle == 0) ? TEXT_ALIGN_BOTTOMMIDDLE : TEXT_ALIGN_MIDDLELEFT;
|
|
|
95 |
|
|
|
96 |
} elseif ($Position == LABEL_POSITION_BOTTOM) {
|
|
|
97 |
$YPos = $this->pChartObject->GraphAreaY2 + $Padding;
|
|
|
98 |
$Settings["Align"] = ($Angle == 0) ? TEXT_ALIGN_TOPMIDDLE : TEXT_ALIGN_MIDDLERIGHT;
|
|
|
99 |
|
|
|
100 |
} else {
|
|
|
101 |
return -1;
|
|
|
102 |
}
|
|
|
103 |
|
|
|
104 |
for ($X = 0; $X <= $this->GridSizeX; $X++) {
|
|
|
105 |
$XPos = floor($X0 + $X * $XSize + $XSize / 2);
|
|
|
106 |
$Value = ($Labels == NULL || !isset($Labels[$X])) ? $X + $CountOffset : $Labels[$X];
|
|
|
107 |
$this->pChartObject->drawText($XPos, $YPos, $Value, $Settings);
|
|
|
108 |
}
|
|
|
109 |
}
|
|
|
110 |
|
|
|
111 |
/* Write the Y labels */
|
|
|
112 |
function writeYLabels(array $Format = [])
|
|
|
113 |
{
|
|
|
114 |
$R = $this->pChartObject->FontColorR;
|
|
|
115 |
$G = $this->pChartObject->FontColorG;
|
|
|
116 |
$B = $this->pChartObject->FontColorB;
|
|
|
117 |
$Alpha = $this->pChartObject->FontColorA;
|
|
|
118 |
$Angle = 0;
|
|
|
119 |
$Padding = 5;
|
|
|
120 |
$Position = LABEL_POSITION_LEFT;
|
|
|
121 |
$Labels = NULL;
|
|
|
122 |
$CountOffset = 0;
|
|
|
123 |
|
|
|
124 |
/* Override defaults */
|
|
|
125 |
extract($Format);
|
|
|
126 |
|
|
|
127 |
if ($Labels != NULL && !is_array($Labels)) {
|
|
|
128 |
$Labels = [$Labels];
|
|
|
129 |
}
|
|
|
130 |
|
|
|
131 |
$Y0 = $this->pChartObject->GraphAreaY1;
|
|
|
132 |
$YSize = ($this->pChartObject->GraphAreaY2 - $this->pChartObject->GraphAreaY1) / ($this->GridSizeY + 1);
|
|
|
133 |
$Settings = ["Angle" => $Angle,"R" => $R,"G" => $G,"B" => $B,"Alpha" => $Alpha];
|
|
|
134 |
|
|
|
135 |
if ($Position == LABEL_POSITION_LEFT) {
|
|
|
136 |
$XPos = $this->pChartObject->GraphAreaX1 - $Padding;
|
|
|
137 |
$Settings["Align"] = TEXT_ALIGN_MIDDLERIGHT;
|
|
|
138 |
} elseif ($Position == LABEL_POSITION_RIGHT) {
|
|
|
139 |
$XPos = $this->pChartObject->GraphAreaX2 + $Padding;
|
|
|
140 |
$Settings["Align"] = TEXT_ALIGN_MIDDLELEFT;
|
|
|
141 |
} else {
|
|
|
142 |
return -1;
|
|
|
143 |
}
|
|
|
144 |
|
|
|
145 |
for ($Y = 0; $Y <= $this->GridSizeY; $Y++) {
|
|
|
146 |
$YPos = floor($Y0 + $Y * $YSize + $YSize / 2);
|
|
|
147 |
$Value = ($Labels == NULL || !isset($Labels[$Y])) ? $Y + $CountOffset : $Labels[$Y];
|
|
|
148 |
$this->pChartObject->drawText($XPos, $YPos, $Value, $Settings);
|
|
|
149 |
}
|
|
|
150 |
}
|
|
|
151 |
|
|
|
152 |
/* Draw the area arround the specified Threshold */
|
|
|
153 |
function drawContour($Threshold, array $Format = [])
|
|
|
154 |
{
|
|
|
155 |
$R = 0;
|
|
|
156 |
$G = 0;
|
|
|
157 |
$B = 0;
|
|
|
158 |
$Alpha = 100;
|
|
|
159 |
$Ticks = 3;
|
|
|
160 |
$Padding = 0;
|
|
|
161 |
|
|
|
162 |
/* Override defaults */
|
|
|
163 |
extract($Format);
|
|
|
164 |
|
|
|
165 |
$X0 = $this->pChartObject->GraphAreaX1;
|
|
|
166 |
$Y0 = $this->pChartObject->GraphAreaY1;
|
|
|
167 |
$XSize = ($this->pChartObject->GraphAreaX2 - $this->pChartObject->GraphAreaX1) / ($this->GridSizeX + 1);
|
|
|
168 |
$YSize = ($this->pChartObject->GraphAreaY2 - $this->pChartObject->GraphAreaY1) / ($this->GridSizeY + 1);
|
|
|
169 |
$Color = ["R" => $R,"G" => $G,"B" => $B,"Alpha" => $Alpha,"Ticks" => $Ticks];
|
|
|
170 |
for ($X = 0; $X <= $this->GridSizeX; $X++) {
|
|
|
171 |
for ($Y = 0; $Y <= $this->GridSizeY; $Y++) {
|
|
|
172 |
$Value = $this->Points[$X][$Y];
|
|
|
173 |
if ($Value != UNKNOWN && $Value != IGNORED && $Value >= $Threshold) {
|
|
|
174 |
$X1 = floor($X0 + $X * $XSize) + $Padding;
|
|
|
175 |
$Y1 = floor($Y0 + $Y * $YSize) + $Padding;
|
|
|
176 |
$X2 = floor($X0 + $X * $XSize + $XSize);
|
|
|
177 |
$Y2 = floor($Y0 + $Y * $YSize + $YSize);
|
|
|
178 |
if ($X > 0 && $this->Points[$X - 1][$Y] != UNKNOWN && $this->Points[$X - 1][$Y] != IGNORED && $this->Points[$X - 1][$Y] < $Threshold){
|
|
|
179 |
$this->pChartObject->drawLine($X1, $Y1, $X1, $Y2, $Color);
|
|
|
180 |
}
|
|
|
181 |
if ($Y > 0 && $this->Points[$X][$Y - 1] != UNKNOWN && $this->Points[$X][$Y - 1] != IGNORED && $this->Points[$X][$Y - 1] < $Threshold){
|
|
|
182 |
$this->pChartObject->drawLine($X1, $Y1, $X2, $Y1, $Color);
|
|
|
183 |
}
|
|
|
184 |
if ($X < $this->GridSizeX && $this->Points[$X + 1][$Y] != UNKNOWN && $this->Points[$X + 1][$Y] != IGNORED && $this->Points[$X + 1][$Y] < $Threshold){
|
|
|
185 |
$this->pChartObject->drawLine($X2, $Y1, $X2, $Y2, $Color);
|
|
|
186 |
}
|
|
|
187 |
if ($Y < $this->GridSizeY && $this->Points[$X][$Y + 1] != UNKNOWN && $this->Points[$X][$Y + 1] != IGNORED && $this->Points[$X][$Y + 1] < $Threshold){
|
|
|
188 |
$this->pChartObject->drawLine($X1, $Y2, $X2, $Y2, $Color);
|
|
|
189 |
}
|
|
|
190 |
}
|
|
|
191 |
}
|
|
|
192 |
}
|
|
|
193 |
}
|
|
|
194 |
|
|
|
195 |
/* Draw the surface chart */
|
|
|
196 |
function drawSurface(array $Format = [])
|
|
|
197 |
{
|
|
|
198 |
$Palette = NULL;
|
|
|
199 |
$ShadeR1 = 77;
|
|
|
200 |
$ShadeG1 = 205;
|
|
|
201 |
$ShadeB1 = 21;
|
|
|
202 |
$ShadeA1 = 40;
|
|
|
203 |
$ShadeR2 = 227;
|
|
|
204 |
$ShadeG2 = 135;
|
|
|
205 |
$ShadeB2 = 61;
|
|
|
206 |
$ShadeA2 = 100;
|
|
|
207 |
$Border = FALSE;
|
|
|
208 |
$BorderR = 0;
|
|
|
209 |
$BorderG = 0;
|
|
|
210 |
$BorderB = 0;
|
|
|
211 |
$Surrounding = -1;
|
|
|
212 |
$Padding = 1;
|
|
|
213 |
|
|
|
214 |
/* Override defaults */
|
|
|
215 |
extract($Format);
|
|
|
216 |
|
|
|
217 |
$X0 = $this->pChartObject->GraphAreaX1;
|
|
|
218 |
$Y0 = $this->pChartObject->GraphAreaY1;
|
|
|
219 |
$XSize = ($this->pChartObject->GraphAreaX2 - $this->pChartObject->GraphAreaX1) / ($this->GridSizeX + 1);
|
|
|
220 |
$YSize = ($this->pChartObject->GraphAreaY2 - $this->pChartObject->GraphAreaY1) / ($this->GridSizeY + 1);
|
|
|
221 |
for ($X = 0; $X <= $this->GridSizeX; $X++) {
|
|
|
222 |
for ($Y = 0; $Y <= $this->GridSizeY; $Y++) {
|
|
|
223 |
$Value = $this->Points[$X][$Y];
|
|
|
224 |
if ($Value != UNKNOWN && $Value != IGNORED) {
|
|
|
225 |
|
|
|
226 |
$X1 = floor($X0 + $X * $XSize) + $Padding;
|
|
|
227 |
$Y1 = floor($Y0 + $Y * $YSize) + $Padding;
|
|
|
228 |
$X2 = floor($X0 + $X * $XSize + $XSize);
|
|
|
229 |
$Y2 = floor($Y0 + $Y * $YSize + $YSize);
|
|
|
230 |
|
|
|
231 |
if ($Palette != NULL) {
|
|
|
232 |
$R = (isset($Palette[$Value]) && isset($Palette[$Value]["R"])) ? $Palette[$Value]["R"] : 0;
|
|
|
233 |
$G = (isset($Palette[$Value]) && isset($Palette[$Value]["G"])) ? $Palette[$Value]["G"] : 0;
|
|
|
234 |
$B = (isset($Palette[$Value]) && isset($Palette[$Value]["B"])) ? $Palette[$Value]["B"] : 0;
|
|
|
235 |
$Alpha = (isset($Palette[$Value]) && isset($Palette[$Value]["Alpha"])) ? $Palette[$Value]["Alpha"] : 1000;
|
|
|
236 |
|
|
|
237 |
} else {
|
|
|
238 |
$R = (($ShadeR2 - $ShadeR1) / 100) * $Value + $ShadeR1;
|
|
|
239 |
$G = (($ShadeG2 - $ShadeG1) / 100) * $Value + $ShadeG1;
|
|
|
240 |
$B = (($ShadeB2 - $ShadeB1) / 100) * $Value + $ShadeB1;
|
|
|
241 |
$Alpha = (($ShadeA2 - $ShadeA1) / 100) * $Value + $ShadeA1;
|
|
|
242 |
}
|
|
|
243 |
|
|
|
244 |
$Settings = ["R" => $R,"G" => $G,"B" => $B,"Alpha" => $Alpha];
|
|
|
245 |
|
|
|
246 |
if ($Border) {
|
|
|
247 |
$Settings["BorderR"] = $BorderR;
|
|
|
248 |
$Settings["BorderG"] = $BorderG;
|
|
|
249 |
$Settings["BorderB"] = $BorderB;
|
|
|
250 |
}
|
|
|
251 |
|
|
|
252 |
if ($Surrounding != - 1) {
|
|
|
253 |
$Settings["BorderR"] = $R + $Surrounding;
|
|
|
254 |
$Settings["BorderG"] = $G + $Surrounding;
|
|
|
255 |
$Settings["BorderB"] = $B + $Surrounding;
|
|
|
256 |
}
|
|
|
257 |
|
|
|
258 |
$this->pChartObject->drawFilledRectangle($X1, $Y1, $X2 - 1, $Y2 - 1, $Settings);
|
|
|
259 |
}
|
|
|
260 |
}
|
|
|
261 |
}
|
|
|
262 |
}
|
|
|
263 |
|
|
|
264 |
/* Compute the missing points */
|
|
|
265 |
function computeMissing()
|
|
|
266 |
{
|
|
|
267 |
$Missing = [];
|
|
|
268 |
for ($X = 0; $X <= $this->GridSizeX; $X++) {
|
|
|
269 |
for ($Y = 0; $Y <= $this->GridSizeY; $Y++) {
|
|
|
270 |
if ($this->Points[$X][$Y] == UNKNOWN) {
|
|
|
271 |
$Missing[] = [$X, $Y];
|
|
|
272 |
}
|
|
|
273 |
}
|
|
|
274 |
}
|
|
|
275 |
|
|
|
276 |
shuffle($Missing);
|
|
|
277 |
foreach($Missing as $Pos) {
|
|
|
278 |
$X = $Pos[0];
|
|
|
279 |
$Y = $Pos[1];
|
|
|
280 |
if ($this->Points[$X][$Y] == UNKNOWN) {
|
|
|
281 |
$NearestNeighbor = $this->getNearestNeighbor($X, $Y);
|
|
|
282 |
$Value = 0;
|
|
|
283 |
$Points = 0;
|
|
|
284 |
for ($Xi = $X - $NearestNeighbor; $Xi <= $X + $NearestNeighbor; $Xi++) {
|
|
|
285 |
for ($Yi = $Y - $NearestNeighbor; $Yi <= $Y + $NearestNeighbor; $Yi++) {
|
|
|
286 |
if ($Xi >= 0 && $Yi >= 0 && $Xi <= $this->GridSizeX && $Yi <= $this->GridSizeY && $this->Points[$Xi][$Yi] != UNKNOWN && $this->Points[$Xi][$Yi] != IGNORED) {
|
|
|
287 |
$Value = $Value + $this->Points[$Xi][$Yi];
|
|
|
288 |
$Points++;
|
|
|
289 |
}
|
|
|
290 |
}
|
|
|
291 |
}
|
|
|
292 |
|
|
|
293 |
if ($Points != 0) {
|
|
|
294 |
$this->Points[$X][$Y] = $Value / $Points;
|
|
|
295 |
}
|
|
|
296 |
}
|
|
|
297 |
}
|
|
|
298 |
}
|
|
|
299 |
|
|
|
300 |
/* Return the nearest Neighbor distance of a point */
|
|
|
301 |
function getNearestNeighbor($Xp, $Yp)
|
|
|
302 |
{
|
|
|
303 |
$Nearest = UNKNOWN;
|
|
|
304 |
for ($X = 0; $X <= $this->GridSizeX; $X++) {
|
|
|
305 |
for ($Y = 0; $Y <= $this->GridSizeY; $Y++) {
|
|
|
306 |
if ($this->Points[$X][$Y] != UNKNOWN && $this->Points[$X][$Y] != IGNORED) {
|
|
|
307 |
$DistanceX = max($Xp, $X) - min($Xp, $X);
|
|
|
308 |
$DistanceY = max($Yp, $Y) - min($Yp, $Y);
|
|
|
309 |
$Distance = max($DistanceX, $DistanceY);
|
|
|
310 |
if ($Distance < $Nearest || $Nearest == UNKNOWN) {
|
|
|
311 |
$Nearest = $Distance;
|
|
|
312 |
}
|
|
|
313 |
}
|
|
|
314 |
}
|
|
|
315 |
}
|
|
|
316 |
|
|
|
317 |
return $Nearest;
|
|
|
318 |
}
|
|
|
319 |
}
|
|
|
320 |
|
|
|
321 |
?>
|