/lib/pChart2/class/pSurface.class.php

https://github.com/jleyva/moodle-block_configurablereports · PHP · 321 lines · 255 code · 38 blank · 28 comment · 107 complexity · 727536b90ead6d4ae89341d274d66a48 MD5 · raw file

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