PageRenderTime 63ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 0ms

/www/advgraph/advgraph4.class.php

https://github.com/jonathankhoo/pulsar-distance
PHP | 2179 lines | 1687 code | 442 blank | 50 comment | 375 complexity | a9e8f2e0c7feec3d5ef4b24f183f8729 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

  1. <?php
  2. /*
  3. +-------------------------------------------------------------------------+
  4. | Copyright (C) 2006-2007 Zack Bloom |
  5. | |
  6. | This program is free software; you can redistribute it and/or |
  7. | modify it under the terms of the GNU Lesser General Public |
  8. | License as published by the Free Software Foundation; either |
  9. | version 2.1 of the License, or (at your option) any later version. |
  10. | |
  11. | This program is distributed in the hope that it will be useful, |
  12. | but WITHOUT ANY WARRANTY; without even the implied warranty of |
  13. | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
  14. | GNU Lesser General Public License for more details. |
  15. | |
  16. | You should have received a copy of the GNU Lesser General Public |
  17. | License along with this library; if not, write to the Free Software |
  18. | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
  19. | 02110-1301, USA |
  20. | |
  21. +-------------------------------------------------------------------------+
  22. | Version 1.8.0 - April 7th, 2007 |
  23. +-------------------------------------------------------------------------+
  24. | Special Thanks to: |
  25. | Miles Kaufmann - EvalMath Class Library |
  26. | Walter Zorn - Javascript Graph Library |
  27. | Andreas Gorh - PHP4 Backport |
  28. | All Those Who Love PHP :) |
  29. +-------------------------------------------------------------------------+
  30. | Code updates and additional features are released frequently, the most |
  31. | updated version can always be found at: http://www.zackbloom.org. |
  32. | |
  33. | Email me at: zackbloom@gmail.com with any comments, questions and bugs |
  34. | |
  35. | Works with PHP5 with GD and TTF support. |
  36. +-------------------------------------------------------------------------+
  37. | - Advanced Graph Class Library - http://www.zackbloom.org/ |
  38. +-------------------------------------------------------------------------+
  39. */
  40. global $numGraphs;
  41. class graph {
  42. var $width, $height, $numPoints, $xPts, $yPts, $iVars, $dVars, $ids, $props, $time, $xMax, $yMax, $xMin, $yMin;
  43. var $img, $imgCache, $fileCache, $imgCacheFile, $lines, $errors, $div, $evalmath, $mode;
  44. var $constructed;
  45. var $font_name, $keyfont_name;
  46. function graph($x_width = 400, $x_height = 200, $xScale = 10, $yScale = 6, $mode = 'image', $div = 'jg') {
  47. global $numGraphs;
  48. if ($this->constructed !== true) {
  49. /* set defaults */
  50. $this->props = array();
  51. $this->xPts = array();
  52. $this->yPts = array();
  53. $this->iVars[0] = array();
  54. $this->dVars[0] = array();
  55. $this->errors = array();
  56. $this->width = $x_width;
  57. $this->height = $x_height;
  58. $this->numPoints[0] = 0;
  59. $this->xMax = 1;
  60. $this->yMax = 1;
  61. $this->xMin = 0;
  62. $this->yMin = 0;
  63. $this->lines = 1;
  64. $this->mode = $mode;
  65. $this->font_name = "arial.ttf";
  66. $this->keyfont_name = "arial.ttf";
  67. $this->setProp('font', dirname(__FILE__) . "/" . $this->font_name);
  68. $this->setProp('keyfont', dirname(__FILE__) . "/" . $this->keyfont_name);
  69. if ($this->mode=='div') {
  70. $this->div = new jgwrap($div, str_replace(".ttf", "", str_replace("fonts/", "", $this->font_name)), $numGraphs);
  71. }
  72. $this->evalmath = new EvalMath;
  73. $this->setBulkProps("xsclpts:$xScale, ysclpts:$yScale, xsclpts:10, ysclpts:6, xsclmax:1, xsclmin:0,
  74. ysclmax:1, ysclmin:0, xSclInc:1, ySclInc:.165, sclline:5, onfreq:.2, actwidth:".($x_width+30).",
  75. actheight:".($x_height+30).", xincpts:10, yincpts:6, autoscl:true");
  76. $this->setProp("color", array(0,0,255,0));
  77. $this->setProp("backcolor", array(255,255,255));
  78. $this->img = imagecreatetruecolor($this->width,$this->height);
  79. /* register the destructor */
  80. register_shutdown_function(array($this,'__destruct'));
  81. $this->constructed = true;
  82. } else {
  83. $this->internalGraph();
  84. }
  85. }
  86. /* remove cached images if the cache is disabled */
  87. function __destruct() {
  88. if (isset($this->fileCache) && !$this->getProp("keepcache",true)) {
  89. unlink($this->fileCache);
  90. }
  91. if (isset($this->imgCache) && !$this->getProp("keepcache",true)) {
  92. unlink($this->imgCache);
  93. }
  94. unset($numGraphs);
  95. }
  96. function setProp($name,$value,$l=-1) {
  97. if ($l+1 > $this->lines) $this->lines++;
  98. $this->props[$l][strtolower($this->strim($name))] = $this->strim($value);
  99. }
  100. function __set($name,$value) {
  101. $this->setProp($name,$value);
  102. }
  103. function storeGraph($file="graphCache.data", $image=false) {
  104. $this->fileCache = $file;
  105. if ($image) {
  106. $this->imgCacheFile = $image;
  107. ob_start();
  108. imagepng($this->img);
  109. unset($this->img);
  110. $img = ob_get_flush();
  111. file_put_contents($image,$img);
  112. }
  113. file_put_contents($file,serialize($this));
  114. if ($image)
  115. return array($file, $image);
  116. else
  117. return $file;
  118. }
  119. function retriveGraph($file="graphCache.data"){
  120. return unserialize(file_get_contents($file));
  121. }
  122. function retriveImage($image){
  123. $this->img = imagecreatefrompng($image);
  124. }
  125. function setBulkProps($str) {
  126. if ($str=="") return false;
  127. if (func_num_args() == 1) {
  128. $str = str_replace(
  129. array(":red", ":green", ":blue", ":orange", ":yellow", ":pink", ":purple", ":teal", ":black", ":white", ":lightgray", ":darkgray"),
  130. array(":230-60-60", ":100-200-100", ":60-60-230", ":255-160-15", ":255-255-0", ":255-0-170", ":216-0-255", ":0-255-255", ":0-0-0", ":255-255-255", ":150-150-150", ":80-80-80"),
  131. $str);
  132. foreach (explode(",",$str) as $e) {
  133. $d = explode(":",$e);
  134. if (strpos($d[0],"|")){
  135. $g = explode("|",$d[0]);
  136. $d[0] = $g[1];
  137. $d[2] = $g[0];
  138. } else {
  139. $d[2] = -1;
  140. }
  141. if (strpos($d[0],"color")!==false) {
  142. $d[1] = explode("-",$d[1]);
  143. }
  144. $this->setProp($d[0],$d[1],$d[2]);
  145. }
  146. } else {
  147. $arg = func_get_args();
  148. foreach ($arg as $e) {
  149. if (is_string($e)) {
  150. $e = explode(":",$e);
  151. if (strpos("|",$e[0])) {
  152. $g = explode("|",$e[0]);
  153. $e[0] = $e[1];
  154. $e[2] = $e[0];
  155. } else {
  156. $e[2] = -1;
  157. }
  158. } else {
  159. if (isset($e[2])==false) {
  160. $e[2] = -1;
  161. }
  162. }
  163. $this->setProp($e[0],$e[1],$e[2]);
  164. }
  165. }
  166. return true;
  167. }
  168. function strim($a) {
  169. if (is_string($a)) {
  170. return trim($a);
  171. } else {
  172. return $a;
  173. }
  174. }
  175. function storePropArr($arr) {
  176. $this->props = $arr;
  177. }
  178. function getPropArr() {
  179. return $this->props;
  180. }
  181. /* getProp - retrieves the values from the properties array. Otherwise
  182. returns the default value.
  183. @arg $name - the property name to be searched
  184. @arg $asu - the default value if not found
  185. @arg $l - the property name array offset */
  186. function getProp($name, $asu = false, $l=0) {
  187. $name = strtolower($this->strim($name));
  188. if (isset($this->props[$l][$name])) {
  189. return $this->props[$l][$name];
  190. } else {
  191. if (isset($this->props[-1][$name])) {
  192. return $this->props[-1][$name];
  193. } else {
  194. if ($asu===-9) {
  195. $this->error('The required property '.$name.' was not set');
  196. }elseif ($asu===-8) {
  197. $this->error('The property '.$name.' was not found');
  198. }elseif (isset($this->$name)) {
  199. return $this->$name;
  200. } else {
  201. return $this->strim($asu);
  202. }
  203. }
  204. }
  205. return false;
  206. }
  207. function __get($name) {
  208. return $this->getProp($name,-8);
  209. }
  210. function __call($name, $args) {
  211. if (count($args)!=2) {
  212. $this->error("Method $name not found.",true);
  213. }
  214. return $this->getProp($name, $args[0], $args[1]);
  215. }
  216. function setColor($obj, $l, $r, $g=-1, $b=-1, $a=0) {
  217. if (substr($obj,-5)!="color") {
  218. $obj.="color";
  219. }
  220. if (is_string($r) && $g==-1 && $b==-1) {
  221. $colors = array("red","green","blue","orange","yellow","pink","purple","teal","black","white","lightgray","darkgray");
  222. $cid = array(array(230,60,60),array(100,200,100),array(60,60,230),array(255,160,15),array(255,255,0),array(255,0,170),array(216,0,255),array(0,255,255),array(0,0,0),array(255,255,255),array(150,150,150),array(80,80,80));
  223. $x=array_search(strtolower($r),$colors);
  224. if ($x!==false) {
  225. $this->setColor($obj,$l,$cid[$x][0],$cid[$x][1],$cid[$x][2],0);
  226. } else {
  227. $this->error("Color not found");
  228. }
  229. } else {
  230. $this->setProp($obj,array($r,$g,$b,$a),$l);
  231. }
  232. }
  233. function xScale($x) {
  234. if (($this->xMax-$this->xMin)>0) {
  235. return $this->width * (($x-$this->xMin)/($this->xMax-$this->xMin));
  236. } else {
  237. return 0;
  238. }
  239. }
  240. function yScale($y) {
  241. if ((($this->yMax-$this->yMin))>0) {
  242. return $this->height * (($y-$this->yMin)/($this->yMax-$this->yMin));
  243. } else {
  244. return 0;
  245. }
  246. }
  247. function addPoint($d,$i=-5,$l=0) {
  248. if ($l+1>$this->lines) {
  249. $this->lines++;
  250. $this->numPoints[$l] = 0;
  251. $this->iVars[$l] = array();
  252. $this->dVars[$l] = array();
  253. }
  254. if (is_array($d)) {
  255. if (count($d)==3)
  256. return $this->addPoint($d[0],$d[1],$d[2]);
  257. elseif (count($d)==2 && isset($d[1]))
  258. return $this->addPoint($d[0],$d[1]);
  259. elseif (count($d)==2)
  260. return $this->addPoint($d[0],-5,$d[2]);
  261. else
  262. return $this->addPoint($d[0]);
  263. }
  264. if ($i==-5) {
  265. $i=(count($this->iVars[$l])>0?max($this->iVars[$l])+1:0);
  266. }
  267. $this->iVars[$l][] = $i;
  268. $this->dVars[$l][] = $d;
  269. $id = rand(1,10000000);
  270. $this->ids[$l][] = $id;
  271. $this->numPoints[$l]++;
  272. return $id;
  273. }
  274. function addBulkPoints($a,$sep=":") {
  275. if (is_string($a)) {
  276. $cDataSet = 0;
  277. foreach (explode(",",$a) as $e) {
  278. $e = explode($sep,$e);
  279. if (strpos($e[0],"|")) {
  280. $d = explode('|',$e[0]);
  281. $e[0] = $d[1];
  282. $cDataSet = $d[0];
  283. }
  284. $e[2] = $cDataSet;
  285. if (isset($e[1])) {
  286. if (strpos($e[1],'-')) {
  287. $e[1] = strtotime($e[1]);
  288. }
  289. }
  290. $ids[] = $this->addPoint($e);
  291. }
  292. }elseif (func_num_args()>1) {
  293. $arg = func_get_args();
  294. foreach ($arg as $e)
  295. $ids[] = $this->addPoint($e);
  296. }elseif (is_array($a)) {
  297. foreach ($a as $e)
  298. $ids[] = $this->addPoint($e);
  299. } else {
  300. return false;
  301. }
  302. return $ids;
  303. }
  304. function delBulkPoints($a) {
  305. if (is_string($a)) {
  306. foreach (explode(",",$a) as $e) {
  307. $ids[] = $this->delPoint($e);
  308. }
  309. }elseif (is_array($a)){
  310. foreach ($a as $e)
  311. $ids[] = $this->delPoint($e);
  312. } else {
  313. $arg = func_get_args();
  314. foreach ($arg as $e) {
  315. $ids[] = $this->delPoint($e);
  316. }
  317. }
  318. return $ids;
  319. }
  320. function idSearch($b) {
  321. foreach ($this->ids as $k => $v) {
  322. $e = array_search($b,$v);
  323. if ($e!==false) {
  324. return array($e,$k);
  325. }
  326. }
  327. return false;
  328. }
  329. function delPoint($id,$k=-1) {
  330. if ($k==-1) {
  331. $k = $this->idSearch($id);
  332. }
  333. if ($k === false) {
  334. return $k;
  335. }
  336. unset($this->dVars[$k[1]][$k[0]],$this->iVars[$k[1]][$k[0]],$this->ids[$k[1]][$k[0]]);
  337. $this->numPoints[$k[1]]--;
  338. return true;
  339. }
  340. function clearPoints() {
  341. $this->dVars = array();
  342. $this->iVars = array();
  343. $this->ids = array();
  344. foreach ($this->numPoints as $k => $e) {
  345. $this->numPoints[$k]=0;
  346. }
  347. }
  348. function demoData($i=10,$mi=0,$ma=10) {
  349. for($j=0;$j<$i;$j++) {
  350. $this->addPoint(rand($mi,$ma));
  351. }
  352. }
  353. function error($x="Error",$ext=false) {
  354. $log = $this->getProp("logfile",false);
  355. if ($x!==true) {
  356. $this->errors[] = $x;
  357. } else {
  358. if (!$this->getProp("production",false)) {
  359. foreach ($this->errors as $k => $x) {
  360. imagestring($this->img,2,10,10+$k*12,$x,imagecolorallocate($this->img,255,0,0));
  361. }
  362. }
  363. if ($log) {
  364. $l = fopen($log,'a');
  365. if ($this->errors) {
  366. fwrite($l,"\nSESSION ".date("D M j G:i:s T Y").', '.$_SERVER['REMOTE_ADDR']."\n");
  367. }
  368. foreach ($this->errors as $k => $x) {
  369. fwrite($l,$x."\n");
  370. }
  371. fclose($l);
  372. }
  373. }
  374. if ($log && $ext) {
  375. $l = fopen($log,'a');
  376. fwrite($l,'FATAL ERROR: '.$x."\n".date("D M j G:i:s T Y").', '.$_SERVER['REMOTE_ADDR']."\n\n");
  377. }
  378. if (!$this->getProp("production",false)) {
  379. if ($ext==true) {
  380. trigger_error($x,E_USER_ERROR);
  381. }
  382. } else {
  383. trigger_error("Their was an error, please contact the webmaster",E_USER_ERROR);
  384. }
  385. }
  386. function importMySQL($table,$field,$rcodb=null,$user=null,$pass=null,$server="localhost",$freq=true){
  387. if (!is_resource($rcodb)) {
  388. $m = mysql_connect($server,$user,$pass);
  389. if (!$m) {
  390. $this->error("Could not connect to MySQL server.",true);
  391. }
  392. $d = mysql_select_db($rcodb,$m);
  393. if (!$d) {
  394. $this->error("Could not select MySQL database.",true);
  395. }
  396. $rcodb = $m;
  397. }
  398. $q = mysql_query("SELECT `$field` FROM $table");
  399. if (!$q) {
  400. $this->error("Error querying MySQL database, check table and field.",true);
  401. }
  402. while ($r = mysql_fetch_array($q, MYSQL_NUM)) {
  403. $a[] = $r[0];
  404. }
  405. if ($freq==true) {
  406. $s = array_count_values($a);
  407. foreach ($s as $e) {
  408. $this->addPoint($e);
  409. }
  410. $this->setProp("key",array_keys($s));
  411. $this->setProp("showkey",true);
  412. } else {
  413. $this->addBulkPoints($a);
  414. }
  415. }
  416. function importCSV($file, $format='l,d,i', $dl=0) { //Read the readme
  417. @$handle = fopen($file,"r");
  418. if (!$handle) {
  419. $this->error("Error opening CSV!", E_USER_ERROR);
  420. return false;
  421. }
  422. foreach (explode(',',$format) as $k => $s) {
  423. $pos[$s] = $k;
  424. }
  425. while (($data[] = fgetcsv($handle, 1000)) !== FALSE) {
  426. /* load data array from file contents */
  427. }
  428. foreach ($data as $k => $d) {
  429. if (isset($pos['i'])) {
  430. $i = $d[$pos['i']];
  431. } else {
  432. $i = -5;
  433. }
  434. if (isset($pos['l'])) {
  435. $l = $d[$pos['l']];
  436. } else {
  437. $l = $dl;
  438. }
  439. if ($d[$pos['d']] && $i) {
  440. $idArr[] = $this->addPoint($d[$pos['d']],$i,$l);
  441. }
  442. }
  443. return $idArr;
  444. }
  445. function importXML($file,$ind="i",$dep="d",$block="",$dl=0) { //Read the readme
  446. if ($block!="") {
  447. $eblock = "</".$block.">";
  448. $block = "<".$block."( $dl=([0-9])*)?>";
  449. }
  450. $str = file_get_contents($file);
  451. if ($str==false) {
  452. $this->error("Error opening XML File!",E_USER_ERROR);
  453. return false;
  454. }
  455. $str = trim($str);
  456. $arr = array();
  457. if (preg_match_all("[$block<([$ind|$dep])>([0-9])*</[($ind|$dep)]><([$ind|$dep])>([0-9])*</[($ind|$dep)]>$eblock]",$str,$arr)==0) {
  458. $this->error("No data found in XML file, check format",true);
  459. }
  460. $i=($arr[3][0]==$ind?4:6);
  461. $d=($arr[3][0]==$ind?6:4);
  462. foreach ($arr[$d] as $k => $r) {
  463. $idArr[] = $this->addPoint($arr[$d][$k],$arr[$i][$k],(is_string($dl)?$arr[2][$k]:$dl));
  464. }
  465. return $idArr;
  466. }
  467. function graphFunction($func, $minX, $maxX, $l=0) {
  468. $inv = $this->getProp('funcinterval',.0625);
  469. $inv += .005;
  470. $this->evalmath->evaluate('graph(x)='.str_replace('$x','x',$func));
  471. for($x=$minX;$x<=$maxX;$x+=$inv) {
  472. $pts[] = $this->addPoint($this->evalmath->evaluate("graph($x)"),$x,$l);
  473. }
  474. $this->setProp('sort',false);
  475. return $pts;
  476. }
  477. function evaluate($f) {
  478. return $this->evalmath->evaluate($f);
  479. }
  480. function cacheImg($img=0) {
  481. if (isset($this->imgCache)) {
  482. return $this->imgCache;
  483. } else {
  484. $this->imgCache = $img;
  485. }
  486. return false;
  487. }
  488. /* determine the maximum value in a single dimensional array */
  489. function multiMax($a) {
  490. $max = -1000000000;
  491. foreach ($a as $e) {
  492. if (max($e)>$max) {
  493. $max = max($e);
  494. }
  495. }
  496. return $max;
  497. }
  498. /* determine the mimimum value in a single dimensional array */
  499. function multiMin($a) {
  500. $min = 100000000;
  501. foreach ($a as $e) {
  502. if (min($e)<$min) {
  503. $min = min($e);
  504. }
  505. }
  506. return $min;
  507. }
  508. /* interesting array index value checker */
  509. function actSort($a,$b) {
  510. return ($a[0] == $b[0] ? 0 : ($a[0] < $b[0] ? -1 : 1) );
  511. }
  512. function indSort($e) {
  513. for($i=0; $i<$this->numPoints[$e]; $i++) {
  514. $tiVars[] = array($this->iVars[$e][$i], $this->dVars[$e][$i], $this->ids[$e][$i]);
  515. }
  516. usort($tiVars, array("graph", "actSort"));
  517. foreach ($tiVars as $k => $g) {
  518. $this->iVars[$e][$k] = $g[0];
  519. $this->dVars[$e][$k] = $g[1];
  520. $this->ids[$e][$k] = $g[2];
  521. }
  522. }
  523. function drawBar($x1, $y1, $x2, $y2, $ccol) {
  524. $mode = $this->getProp("barstyle",0);
  525. $colorlist = $this->getProp("colorlist",false);
  526. if ($colorlist === true || $colorlist === 1 || $colorlist === "true") {
  527. $colorlist = array(array(255, 203, 3),array(220, 101, 29),array(189, 24, 51),array(214, 0, 127),array(98, 1, 96),array(0, 62, 136),array(0, 102, 179),array(0, 145, 195),array(0, 115, 106),array(178, 210, 52),array(137, 91, 74),array(82, 56, 47));
  528. }
  529. if ($colorlist) {
  530. $color = $colorlist[$ccol];
  531. }
  532. if (!isset($color[3])) {
  533. $color[3] = 0;
  534. } else {
  535. $color = $this->getProp("color", array(0,0,255,0));
  536. }
  537. $bord = $this->getProp("bordercolor",array(0,0,0,0));
  538. switch ($mode) {
  539. case 0:
  540. if ($this->mode!="div") {
  541. imagefilledrectangle($this->img,$x1,$y1,$x2,$y2,imagecolorallocatealpha($this->img,$color[0],$color[1],$color[2],$color[3]));
  542. imagerectangle($this->img,$x1,$y1,$x2,$y2,imagecolorallocatealpha($this->img,$bord[0],$bord[1],$bord[2],$bord[3]));
  543. } else {
  544. $this->div->setColor($color[0],$color[1],$color[2]);
  545. $this->div->drawFilledRect($x1,$y1,$x2-$x1,$y2-$y1);
  546. $this->div->setColor($bord[0],$bord[1],$bord[2]);
  547. $this->div->drawRect($x1,$y1,$x2-$x1,$y2-$y1);
  548. }
  549. break;
  550. case 1:
  551. $ge = $this->getProp("gendcolor",array(0,0,0,0));
  552. $gs = $this->getProp("gstartcolor",array(255,255,255,0));
  553. for($i=0;$i<4;$i++) {
  554. $c[$i] = ($ge[$i]-$gs[$i])/($y2-$y1);
  555. $cc[$i] = $gs[$i];
  556. }
  557. for($y=$y1;$y<$y2;$y++) {
  558. for($i=0;$i<4;$i++) {
  559. $cc[$i] += $c[$i];
  560. }
  561. if ($this->mode!="div") {
  562. imageline($this->img,$x1,$y,$x2,$y,imagecolorallocatealpha($this->img,$cc[0],$cc[1],$cc[2],$cc[3]));
  563. } else {
  564. $this->div->setColor($cc[0],$cc[1],$cc[2]);
  565. $this->div->drawLine($x1+1,$y,$x2,$y);
  566. }
  567. }
  568. break;
  569. default:
  570. $this->error("Bar style not understood.");
  571. break;
  572. }
  573. }
  574. function flipMulti(&$arr) {
  575. foreach ($arr as $i => $e) {
  576. foreach ($e as $j => $k) {
  577. $n[$j][$i] = $k;
  578. }
  579. }
  580. $arr = $n;
  581. }
  582. function pieSort($a,$b) {
  583. return ($a==$b ? 0 : (abs($a-90) > abs($b-90) ? -1 : 1));
  584. }
  585. function drawPie($ex) {
  586. $cx = $this->width/2;
  587. $cy = $this->height/2+20;
  588. $ang = $this->getProp("pieangle",35);
  589. if ($ang>90) {
  590. $this->error("Angles over 90 cannot be properly graphed.");
  591. }
  592. $h = min($this->width,$this->height-10);
  593. $h = ($h*((90-$ang)/90))+3;
  594. $w = min(min($this->width,$this->height-10)+$ang*1.5,$this->width);
  595. $colorlist = $this->getProp('colorlist',array(array(125, 203, 3),array(220, 101, 29),array(189, 24, 51),array(34, 78, 120),array(120, 1, 60),array(0, 62, 136),array(0, 102, 179),array(0, 145, 195),array(0, 115, 106),array(178, 210, 52),array(137, 91, 74),array(82, 56, 47)));
  596. $da['data'] = $this->dVars[$ex];
  597. $da['key'] = $this->iVars[$ex];
  598. foreach ($da['data'] as $i => $e){ //Allocate colors
  599. $rcolor[$i] = imagecolorallocate($this->img,$colorlist[$i][0],$colorlist[$i][1],$colorlist[$i][2]);
  600. $dcolor[$i] = imagecolorallocate($this->img,abs($colorlist[$i][0]-30),abs($colorlist[$i][1]-30),abs($colorlist[$i][2]-30));
  601. }
  602. $datasum = array_sum($da['data']);
  603. for($i=0;$i<count($da['data']);$i++){
  604. $da['part'][$i] = $da['data'][$i] / $datasum; //Get percents
  605. }
  606. if (($fd=array_sum($da['part']))<1) {
  607. $da['part'][count($da['part'])-1] += 1-$fd;
  608. }
  609. for($i=0;$i<count($da['data']);$i++) {
  610. $da['angle'][$i] = $da['part'][$i] * 360; //Get angles
  611. }
  612. for($i=0;$i<count($da['data']);$i++) {
  613. @$da['ansum'][$i] = array_sum(array_slice($da['angle'],0,$i+1)); //Get sums from 0 to each angle
  614. }
  615. for($i=1;$i<count($da['ansum'])+1;$i++) {
  616. $sortkeys[] = $da['ansum'][$i-1]; //Create sort array to make sure pie is graphed back to front
  617. }
  618. for($i=1;$i<count($sortkeys)+1;$i++) {
  619. if ($sortkeys[$i-1]<90 && $sortkeys[$i]>90) { // Make sure the one that actually crosses 90 is last
  620. $sortkeys[$i] = 90;
  621. }
  622. }
  623. uasort($sortkeys,array('graph','piesort'));
  624. $sk = array_keys($sortkeys);
  625. for($p=0;$p<=count($da['data'])-1;$p++) {
  626. $n = $sk[$p];
  627. $f = $n - 1;
  628. if ($da['angle'][$n] != 0) {
  629. for ($i = 0; $i < $ang; $i++) {
  630. if (($da['ansum'][$n]<=180 || $da['ansum'][$f]<=180) || ($n == count($da['data'])-1)) { //Draw 3d
  631. @imagefilledarc($this->img, $cx, $cy+$i, $w, $h, $da['ansum'][$f], $da['ansum'][$n], ($n==count($da['data'])-1?$rcolor[$n]:$dcolor[$n]), IMG_ARC_PIE);
  632. }
  633. }
  634. }
  635. }
  636. for($i=0;$i<=count($da['data'])-1;$i++) {
  637. $n = $i - 1;
  638. if ($da['angle'][$i] != 0) { //Draw top
  639. @imagefilledarc($this->img, $cx, $cy, $w, $h, $da['ansum'][$n], $da['ansum'][$i], $rcolor[$i], IMG_ARC_PIE);
  640. }
  641. }
  642. for($i=0;$i<count($da['data']);$i++) {
  643. @$da['ansum'][$i] = array_sum(array_slice($da['angle'],0,$i+1));
  644. }
  645. for($i=0;$i<count($da['data']);$i++) { //Draw keys
  646. $text = ($this->getProp("useval",false)? $da['data'][$i] : round($da['part'][$i]*100,0).'%');
  647. $size = imagettfbbox($this->getProp("textsize",8),$this->getProp("textAngle",0),$this->getProp("font",realpath($this->font_name)),$text);
  648. if (!isset($da['ansum'][$i-1])) {
  649. $valuea = 0;
  650. } else {
  651. $valuea = $da['ansum'][$i-1];
  652. }
  653. if (!isset($da['ansum'][$i])) {
  654. $valueb = 0;
  655. } else {
  656. $valueb = $da['ansum'][$i];
  657. }
  658. $avang = ($valuea+$valueb)/2;
  659. imagettftext($this->img,
  660. $this->getProp("textsize",8),
  661. $this->getProp("textAngle",0),
  662. cos(deg2rad($avang))*$w/2+$cx+($avang<90||$avang>270?$this->getProp("numspace",5):-$size[2]-$this->getProp("numspace",5)),
  663. sin(deg2rad($avang))*$h/2+$cy+($avang<180&&$avang>0?-$size[5]+$ang:$size[5]),imagecolorallocate($this->img,0,0,0),
  664. $this->getProp("font",realpath($this->font_name)),
  665. $text);
  666. }
  667. }
  668. function internalGraph() {
  669. if ($this->getProp("scale","numeric")=="date") {
  670. $start = $this->getProp("startdate",-9);
  671. $end = $this->getProp("enddate",time());
  672. if (is_string($start)) {
  673. $start = strtotime($start);
  674. }
  675. if (is_string($end)) {
  676. $end = strtotime($end);
  677. }
  678. }
  679. foreach ($this->iVars as $e => $g) {
  680. foreach ($g as $k => $i) {
  681. if (substr($this->iVars[$e][$k],0,2)=='d:') {
  682. $this->iVars[$e][$k] = strtotime(substr($this->iVars[$e][$k],2))/($end-$start);
  683. }
  684. }
  685. }
  686. for($i=0;$i<count($this->numPoints);$i++) {
  687. if ($this->getProp("reverse",0,$i)==1) {
  688. $this->dVars = array_reverse($this->dVars[$i]);
  689. }
  690. if ($this->getProp("flip",0,$i)==1) {
  691. $this->dVars = array_reverse($this->dVars[$i]);
  692. $this->iVars = array_reverse($this->iVars[$i]);
  693. }
  694. if ($this->getProp("sort",true,$i)==true) {
  695. $this->indSort($i);
  696. }
  697. }
  698. $time = microtime(true);
  699. $nu = ($this->getProp('type','line') != 'line'?1:2);
  700. for($k=0;$k<$this->lines;$k++) {
  701. if (isset($this->numPoints[$k])==false || $this->numPoints[$k]<$nu) {
  702. $this->error("Not enough points in dataset ".$k);
  703. }
  704. }
  705. if ($this->getProp("autoSize",true)) {
  706. if ($this->getProp("autoSizeX",true)) {
  707. $this->xMax = $this->multiMax($this->iVars);
  708. $this->xMin = $this->multiMin($this->iVars);
  709. }
  710. if ($this->getProp("autoSizeY",true)) {
  711. $this->yMax = $this->multiMax($this->dVars);
  712. $this->yMin = $this->multiMin($this->dVars);
  713. }
  714. }
  715. if ($this->getProp("type","line")=="bar" && $this->getProp("barnone",true)) {
  716. $this->yMin = 0;
  717. $this->setProp("xincpts",$this->numPoints[0]);
  718. }
  719. if ($this->getProp("autoScl",true)) {
  720. if ($this->getProp("autoSclX",true)) {
  721. round($this->setProp("xsclmax",$this->xMax),1);
  722. round($this->setProp("xsclmin",$this->xMin),1);
  723. }
  724. if ($this->getProp("autoSclY",true)) {
  725. round($this->setProp("ysclmax",$this->yMax),1);
  726. round($this->setProp("ysclmin",$this->yMin),1);
  727. }
  728. }
  729. @($this->setProp("xSclInc",(($this->getProp("xsclmax")-$this->getProp("xsclmin"))/(float)$this->getProp("xsclpts"))*$this->width/(float)($this->getProp("xsclmax")-$this->getProp("xsclmin"))));
  730. @($this->setProp("ySclInc",(($this->getProp("ysclmax")-$this->getProp("ysclmin"))/(float)$this->getProp("ysclpts"))*$this->height/(float)($this->getProp("ysclmax")-$this->getProp("ysclmin"))));
  731. $this->xPts = array();
  732. $this->yPts = array();
  733. foreach ($this->iVars as $e => $g) {
  734. foreach ($g as $k => $i) {
  735. $f = $this->xScale($i);
  736. $this->xPts[$e][] = $f;
  737. }
  738. }
  739. foreach ($this->dVars as $e => $g) {
  740. foreach ($g as $k => $i) {
  741. $f = $this->yScale($i);
  742. $this->yPts[$e][] = $f;
  743. }
  744. }
  745. $backcolor = $this->getProp("backcolor");
  746. $grids = $this->getProp("gridcolor",array(80,80,80));
  747. if ($this->getProp("showvertscale",true)) {
  748. for($i=0;$i<$this->getProp("yincpts")+1;$i++) { //Generate scale information for use in the graph image creation
  749. $vertScaleText[$i] = trim(round((($i/$this->getProp("yincpts"))*($this->yMax-$this->yMin))+$this->yMin,1));
  750. $vertScaleSize[$i] = imagettfbbox($this->getProp("textsize",8),
  751. $this->getProp("textAngle",0),
  752. $this->getProp("font",realpath($this->font_name)),
  753. $vertScaleText[$i]);
  754. $cSize[$i] = $vertScaleSize[$i][4];
  755. }
  756. $max = max($cSize);
  757. $this->setProp('actwidth',$this->width+10+$max);
  758. }
  759. $this->img = imagecreatetruecolor($this->getProp("actwidth"),$this->getProp("actheight")); // Create image.
  760. $back = imagecolorallocate($this->img,$backcolor[0],$backcolor[1],$backcolor[2]);
  761. $grid = imagecolorallocate($this->img,$grids[0],$grids[1],$grids[2]);
  762. imagefill($this->img,0,0,$back); //Fill with back color
  763. if ($this->getProp("showgrid",true)) {
  764. for($i=0;$i<round($this->getProp("sclline")*$this->getProp("onfreq"),0);$i++) { //Create grid line style
  765. $style[] = $grid;
  766. }
  767. for($i=0;$i<round($this->getProp("sclline")*(1-$this->getProp("onfreq")),0);$i++) {
  768. $style[] = IMG_COLOR_TRANSPARENT;
  769. }
  770. imagesetstyle($this->img, $style);
  771. if ($this->getProp("showxgrid",true)) {
  772. for($i=1;$i<$this->getProp("xsclpts");$i++) { //Create grid
  773. if ($this->mode=='image') {
  774. imageline($this->img, round($i*$this->getProp("xSclInc"),0), 0, round($i*$this->getProp("xSclInc"),0), $this->height, IMG_COLOR_STYLED);
  775. } else {
  776. $this->div->setColor($grids[0],$grids[1],$grids[2]);
  777. $this->div->setStyle('dotted');
  778. $this->div->drawLine(round($i*$this->getProp("xSclInc"),0),0,round($i*$this->getProp("xSclInc"),0),$this->height);
  779. }
  780. }
  781. }
  782. if ($this->getProp("showygrid",true)) {
  783. for($i=1;$i<$this->getProp("ysclpts");$i++) {
  784. if ($this->mode=='image') {
  785. imageline($this->img, 0, round($i*$this->getProp("ySclInc"),0), $this->width, round($i*$this->getProp("ySclInc"),0), IMG_COLOR_STYLED);
  786. } else {
  787. $this->div->drawLine(0,round($i*$this->getProp("ySclInc"),0),$this->width,round($i*$this->getProp("ySclInc"),0));
  788. }
  789. }
  790. }
  791. if ($this->mode=='image') {
  792. imageline($this->img, 0, $this->height-1, $this->width-1, $this->height-1, IMG_COLOR_STYLED); //Last lines
  793. imageline($this->img, $this->width-1, $this->height-1, $this->width-1, 0, IMG_COLOR_STYLED);
  794. imageline($this->img, 0, $this->height, 0, 0, IMG_COLOR_STYLED);
  795. imageline($this->img, 0, 0, $this->width, 0, IMG_COLOR_STYLED);
  796. } else {
  797. $this->div->drawLine(0,$this->height-1,$this->width-1,$this->height-1);
  798. $this->div->drawLine($this->width-1,$this->height-1,$this->width-1,0);
  799. $this->div->drawLine(0,$this->height,0,0);
  800. $this->div->drawLine(0,0,$this->width,0);
  801. $this->div->setStyle(1);
  802. }
  803. }
  804. if ($this->getProp("type","line")!="pie") {
  805. if ($this->getProp("showhorizscale",true)) {
  806. if ($this->getProp("scale","numeric")=="date") {
  807. $start = $this->getProp("startdate",-9);
  808. $end = $this->getProp("enddate",time());
  809. if (is_string($start)) {
  810. $start = strtotime($start);
  811. }
  812. if (is_string($end)) {
  813. $end = strtotime($end);
  814. }
  815. $start = getdate($start);
  816. $end = getdate($end);
  817. $dDate = ($end[0] - $start[0])/$this->getProp("xincpts");
  818. $showyr = $this->getProp("showyear",($start['year']!=$end['year']));
  819. $format = $this->getProp("dateformat",1);
  820. }elseif (is_array($this->getProp("scale","numeric"))) {
  821. $scale = $this->getProp("scale");
  822. $this->setProp("xincpts",count($scale)-1);
  823. }
  824. for($i=0;$i<$this->getProp("xincpts")+1;$i++) { //Create horiz scale
  825. if ($this->getProp("scale","numeric")=="numeric") {
  826. $text = ($this->getProp("type","line")=="bar"?$i:trim(round((($i/$this->getProp("xincpts"))*($this->xMax-$this->xMin))+$this->xMin,1)));
  827. }elseif ($this->getProp("scale","numeric")=="date") {
  828. $date = getdate($start[0]+($i*$dDate));
  829. if ($date['mday']>15 && $this->getProp('rounddateto',false)=='month') {
  830. $date = getdate($start[0]+(($i+0.5)*$dDate));
  831. }
  832. $text = ($format<=2?substr($date['month'],0,3):$date['month']);
  833. if ($showyr) {
  834. $text .= " ".substr($date['year'],($format==4 || $format==2?0:2),($format==4 || $format==2?4:2));
  835. }
  836. }elseif (is_array($this->getProp("scale","numeric"))) {
  837. $text = $scale[$i];
  838. } else {
  839. $this->error("Scale format not understood.");
  840. }
  841. $size = imagettfbbox($this->getProp("textsize",8),
  842. $this->getProp("textAngle",0),
  843. $this->getProp("font",realpath($this->font_name)),
  844. $text);
  845. if ($this->mode=="image") {
  846. imagettftext($this->img,$this->getProp("textsize",8),
  847. $this->getProp("textAngle",0),
  848. round(($i*($this->width/$this->getProp("xincpts")))-($i!=$this->getProp("xincpts")?($i!=0?(.5*$size[2]):0):$size[2]),0)-($this->getProp("type","line")=="bar"?.5*($this->width/count($this->xPts[0])):0),
  849. $this->height+abs($size[5])+3,
  850. $grid,
  851. $this->getProp("font",realpath($this->font_name)),
  852. $text);
  853. } else {
  854. $this->div->setFontSize(8);
  855. $this->div->drawString(round(($i*($this->width/$this->getProp("xincpts")))-($i!=$this->getProp("xincpts")?($i!=0?(.5*$size[2]):0):$size[2]),0)-($this->getProp("type","line")=="bar"?.5*($this->width/count($this->xPts[0])):0),$this->height,$text);
  856. }
  857. }
  858. }
  859. if ($this->getProp("showvertscale",true)) {
  860. for($i=0;$i<$this->getProp("yincpts")+1;$i++) { //Create vert scale
  861. $text = $vertScaleText[$i];
  862. $size = $vertScaleSize[$i];
  863. if ($this->mode=="image") {
  864. imagettftext($this->img,
  865. $this->getProp("textsize",8),
  866. $this->getProp("textAngle",0),
  867. $this->width+3,round((($this->getProp("yincpts")-$i)*($this->height/$this->getProp("yincpts")))-($text!=$this->yMax?($text!=$this->yMin?(.5*$size[5]):0):$size[5]),0),
  868. $grid,
  869. $this->getProp("font",realpath($this->font_name)),
  870. $text);
  871. } else {
  872. $this->div->setFontSize(8);
  873. $this->div->drawString($this->width+3,
  874. round((($this->getProp("yincpts")-$i)*($this->height/$this->getProp("yincpts")))-($i==0?abs($size[5]):0),0),
  875. $text);
  876. }
  877. }
  878. }
  879. }
  880. foreach ($this->xPts as $ex => $ind) {
  881. $xPts = $this->xPts[$ex];
  882. $yPts = $this->yPts[$ex];
  883. $g = $this->width/count($xPts);
  884. $color = $this->getProp("color",array(0,0,255,0),$ex);
  885. $fore = imagecolorallocatealpha($this->img,$color[0],$color[1],$color[2],$color[3]);
  886. if ($this->getProp("type","line")=="line") { //Draw graph
  887. for($i=1;$i<$this->numPoints[$ex];$i++) {
  888. $this->imageSmoothAlphaLine($this->img,$xPts[$i-1],$this->height-$yPts[$i-1],$xPts[$i],$this->height-$yPts[$i],$color[0],$color[1],$color[2],$color[3]);
  889. }
  890. }elseif ($this->getProp("type","line")=="bar") {
  891. for($i=0;$i<$this->numPoints[$ex];$i++) {
  892. $this->drawBar($g*$i+($i==0?$g*(1-$this->getProp("barwidth",1)):0),$this->height-$yPts[$i],$g*$i+$this->getProp("barwidth",1)*$g,$this->height-1,$i);
  893. }
  894. }elseif ($this->getProp("type","line")=="pie"){
  895. $this->drawPie($ex);
  896. }elseif ($this->getProp("type","line")!="dot") {
  897. $this->error("Type property not understood.",E_USER_ERROR);
  898. }
  899. $width = $this->getProp("pointwidth",5,$ex);
  900. $height = $this->getProp("pointheight",$width,$ex);
  901. $point = $this->getProp("pointcolor",$color,$ex);
  902. $col = imagecolorallocatealpha($this->img,$point[0],$point[1],$point[2],$point[3]);
  903. if ($this->getProp("pointstyle",0,$ex)!=0) {
  904. foreach ($xPts as $k => $xpt) {
  905. $x = $xPts[$k];
  906. $y = $this->height-$yPts[$k];
  907. if ($this->getProp("endstyle",0,$ex)!=0 && $k==count($xPts)-1) {
  908. continue;
  909. }
  910. switch ($this->getProp("pointstyle",0,$ex)) { //Draw points
  911. case 1: //Filled rectangle
  912. imagefilledrectangle($this->img,$x-.5*$width,$y-.5*$height,$x+.5*$width,$y+.5*$height,$col);
  913. break;
  914. case 2: //Open rectangle
  915. if (!$this->getProp("clearback",false,$ex)) {
  916. imagefilledrectangle($this->img,$x-.5*$width,$y-.5*$height,$x+.5*$width,$y+.5*$height,$back);
  917. }
  918. imagerectangle($this->img,$x-.5*$width,$y-.5*$height,$x+.5*$width,$y+.5*$height,$col);
  919. break;
  920. case 3: //Filled Triangle
  921. imagefilledpolygon($this->img,array($x-.5*$width,$y+.5*$height,$x+.5*$width,$y+.5*$height,$x,$y-.5*$height),3,$col);
  922. break;
  923. case 4: //Open Triangle
  924. if (!$this->getProp("clearback",false,$ex)) {
  925. imagefilledpolygon($this->img,array($x-.5*$width,$y+.5*$height,$x+.5*$width,$y+.5*$height,$x,$y-.5*$height),3,$back);
  926. }
  927. imagepolygon($this->img,array($x-.5*$width,$y+.5*$height,$x+.5*$width,$y+.5*$height,$x,$y-.5*$height),3,$col);
  928. break;
  929. case 5: //Filled n-gon, for testing only!
  930. $n = $this->getProp("pointsides",7);
  931. if ($n<7) {
  932. $this->error("Point shape must be 7 or more sides!");
  933. }elseif ($n>30){
  934. $this->error("Just use a circle ;)");
  935. }
  936. $s = $width;
  937. unset($points);
  938. for($i=1;$i<$n+1;$i++) {
  939. $o=($i)*(360/$n);
  940. $points[] = ($s*cos($o))+$x;
  941. $points[] = ($s*sin($o))+$y;
  942. }
  943. imagefilledpolygon($this->img,$points,$n,$col);
  944. break;
  945. case 6: //Open n-gon, for testing only!
  946. $n = $this->getProp("pointsides",7,$ex);
  947. if ($n<7) {
  948. $this->error("Point shape must be 7 or more sides!");
  949. }elseif ($n>30) {
  950. $this->error("Just use a circle ;)");
  951. }
  952. $s = $width;
  953. unset($points);
  954. for($i=1;$i<$n+1;$i++) {
  955. $o=($i)*(360/$n);
  956. $points[] = ($s*cos($o))+$x;
  957. $points[] = ($s*sin($o))+$y;
  958. }
  959. if (!$this->getProp("clearback",false,$ex)) {
  960. imagefilledpolygon($this->img,$points,$n,$back);
  961. }
  962. imagepolygon($this->img,$points,$n,$col);
  963. break;
  964. case 7: //Filled ellipse, make width = height for a circle
  965. imagefilledellipse($this->img,$x,$y,$width,$height,$col);
  966. break;
  967. case 8: //Open ellipse
  968. if (!$this->getProp("clearback",false,$ex)) {
  969. imagefilledellipse($this->img,$x,$y,$width,$height,$back);
  970. }
  971. imageellipse($this->img,$x,$y,$width,$height,$col);
  972. break;
  973. case 9: //Image
  974. if ($this->getProp("pointimgsrc",false,$ex)===false) {
  975. $this->error("You must set the pointimgsrc property before using the image point style",true);
  976. }
  977. if (!isset($this->imgCache)) {
  978. $im = $this->loadimg($this->getProp("pointimgsrc",false,$ex));
  979. if ($this->getProp("pointimgscale",false,$ex)) {
  980. $height = round($width*(ImageSX($im)/ImageSY($im)),0);
  981. }
  982. $tmp = imagecreatetruecolor($width,$height);
  983. if (!imagecopyresized($tmp,$im,0,0,0,0,$width,$height,ImageSX($im),ImageSY($im))) {
  984. $this->error("Error resizing point image");
  985. }
  986. $this->cacheImg($tmp);
  987. }
  988. $tmp = $this->cacheImg();
  989. if (!imagecopy($this->img,$tmp,$x-.5*$width,$y-.5*$height,0,0,$width,$height)) {
  990. $this->error("Error inserting point image");
  991. }
  992. break;
  993. }
  994. }
  995. unset($this->imgCache);
  996. }
  997. $arrow = $this->getProp("arrowcolor",$color,$ex);
  998. $col = imagecolorallocatealpha($this->img,$arrow[0],$arrow[1],$arrow[2],$arrow[3]);
  999. $x2 = $xPts[count($xPts)-1];
  1000. $y2 = $this->height-$yPts[count($yPts)-1];
  1001. $x1 = $xPts[count($xPts)-2];
  1002. $y1 = $this->height-$yPts[count($yPts)-2];
  1003. switch ($this->getProp("endstyle",0,$ex)){ //Draw end
  1004. case 1: //Open arrow
  1005. $arrhead = $this->getProp("arrowwidth",25,$ex);
  1006. $arrang = $this->getProp("arrowangle",14,$ex);
  1007. $arrow = $this->drawArrowheads ($x1, $y1, $x2, $y2, $arrhead, $arrang);
  1008. if (!$this->getProp("clearback",false,$ex)) {
  1009. imagefilledpolygon($this->img,array (
  1010. $arrow['x1'], $arrow['y1'],
  1011. $arrow['x2'], $arrow['y2'],
  1012. $x2, $y2
  1013. ),3,$back);
  1014. }
  1015. imageline($this->img, $arrow['x1'], $arrow['y1'], $arrow['x2'], $arrow['y2'], $col);
  1016. imageline($this->img, $x2, $y2, $arrow['x1'], $arrow['y1'], $col);
  1017. imageline($this->img, $x2, $y2, $arrow['x2'], $arrow['y2'], $col);
  1018. break;
  1019. case 2: //Filled arrow
  1020. $arrhead = $this->getProp("arrowwidth",25,$ex);
  1021. $arrang = $this->getProp("arrowangle",14,$ex);
  1022. $arrow = $this->drawArrowheads ($x1, $y1, $x2, $y2, $arrhead, $arrang);
  1023. imagefilledpolygon($this->img,array (
  1024. $arrow['x1'], $arrow['y1'],
  1025. $arrow['x2'], $arrow['y2'],
  1026. $x2, $y2
  1027. ),3,$col);
  1028. break;
  1029. }
  1030. }
  1031. $sX = ImageSX($this->img);
  1032. $sY = ImageSY($this->img);
  1033. $font = $this->getProp("font", realpath($this->font_name));
  1034. $labels = $this->getProp("labelcolor", array(0,0,0,0));
  1035. $label = imagecolorallocatealpha($this->img, $labels[0], $labels[1], $labels[2], $labels[3]);
  1036. $fX = $sX;
  1037. $fY = $sY;
  1038. $tB = 0;
  1039. if ($this->getProp("title",false)!==false) {
  1040. $title = $this->getProp("title");
  1041. $tsize = imagettfbbox($this->getProp("titlesize",24),0,$font,$title);
  1042. $tB = abs($tsize[5])+10;
  1043. $fY += $tB + 5;
  1044. }
  1045. if ($this->getProp("xlabel",false)!==false) {
  1046. $xlabel = $this->getProp("xlabel");
  1047. $xsize = imagettfbbox($this->getProp("labelsize",14),0,$font,$xlabel);
  1048. $fY += abs($xsize[5])+10;
  1049. }
  1050. if ($this->getProp("ylabel",false)!==false) {
  1051. $ylabel = $this->getProp("ylabel");
  1052. $ysize = imagettfbbox($this->getProp("labelsize",14),90,$font,$ylabel);
  1053. $fX += abs($ysize[2])+15;
  1054. }
  1055. if ($fX != $sX || $fY != $sY) {
  1056. $timg = imagecreatetruecolor($fX,$fY);
  1057. imagecopy($timg,$this->img,0,$tB,0,0,$sX,$sY);
  1058. imagefill($timg,0,0,$back);
  1059. if ($this->getProp("ylabel",false)!==false) {
  1060. imagettftext($timg,$this->getProp("labelsize",14),90,$sX+10,round(($fY-$ysize[5])/2,0),$label,$font,$ylabel);
  1061. }
  1062. if ($this->getProp("xlabel",false)!==false) {
  1063. imagettftext($timg,$this->getProp("labelsize",14),0,round(($fX-abs($xsize[2]))/2,0),$sY+$tB+5,$label,$font,$xlabel);
  1064. }
  1065. if ($this->getProp("title",false)!==false) {
  1066. imagettftext($timg,$this->getProp("titlesize",24),0,round(($fX-abs($tsize[2]))/2,0),abs($tsize[5]),$label,$font,$title);
  1067. }
  1068. $this->img = $timg;
  1069. }
  1070. if ($this->getProp("benchmark",false)) {
  1071. echo (round(microtime(true) - $time,3)*1000)."ms";
  1072. }
  1073. if ($this->getProp("showkey",false)) {
  1074. $acthei = $this->getProp("actheight",$this->height);
  1075. $actwid = $this->getProp("actwidth",$this->width);
  1076. $size = $this->getProp("keysize", 10);
  1077. $font = $this->getProp("keyfont", realpath($this->keyfont_name));
  1078. $indhei = 0;
  1079. $indwid = 0;
  1080. $type = $this->getProp("type",'line');
  1081. if ($type!='line') {
  1082. $keys = $this->getProp('key',false);
  1083. $num = $this->numPoints[0];
  1084. $dis = $this->getProp("keyinfo",0);
  1085. if ($dis>3 || $dis<0) {
  1086. $this->error("keyinfo not understood.");
  1087. }
  1088. if ($dis!=0) {
  1089. $d = $this->dVars[0];
  1090. $g = array_sum($d);
  1091. foreach ($d as $i => $e) {
  1092. $pr[] = ($e/$g)*100;
  1093. }
  1094. if (($fd=array_sum($pr))<1) {
  1095. $pr[count($pr)-1] += 1-$fd;
  1096. }
  1097. foreach ($d as $i => $e) {
  1098. $p[] = round($pr[$i],0).'%';
  1099. }
  1100. if ($dis==1 || $dis==3) {
  1101. foreach ($keys as $i => $k) {
  1102. $keys[$i] = $p[$i].' '.$k;
  1103. }
  1104. }
  1105. if ($dis==2 || $dis==3) {
  1106. foreach ($keys as $i => $k) {
  1107. $keys[$i] = $d[$i].' '.$k;
  1108. }
  1109. }
  1110. }
  1111. } else {
  1112. $num = $this->lines;
  1113. }
  1114. for($i=0;$i<$num;$i++) {
  1115. if ($type=='line') {
  1116. $keys[$i] = $this->getProp("key",false,$i);
  1117. if ($keys[$i]==false) {
  1118. $this->error("You must set the keys property for dataset $i.");
  1119. }
  1120. }
  1121. $ksize[$i]['size'] = imagettfbbox($size, 0, $font, $keys[$i]);
  1122. $indhei = max($indhei,$ksize[$i]['height'] = abs($ksize[$i]['size'][5]));
  1123. $indwid = max($indwid,$ksize[$i]['width'] = abs($ksize[$i]['size'][2])+$indhei+5);
  1124. }
  1125. $indhei += 4;
  1126. $indwid += 10;
  1127. $wspc = $this->getProp("keywidspc",10);
  1128. $oldwid = $actwid;
  1129. $oldhei = $acthei;
  1130. $khei = $indhei*$num+14;
  1131. $actwid = $actwid+$indwid+$wspc;
  1132. $acthei = max($acthei,$khei);
  1133. $timg = imagecreatetruecolor($actwid,$acthei);
  1134. $backcolor = $this->getProp("backcolor");
  1135. $back = imagecolorallocate($this->img,$backcolor[0],$backcolor[1],$backcolor[2]);
  1136. imagefill($timg,0,0,$back);
  1137. imagecopy($timg,$this->img,0,0,0,0,$oldwid,$oldhei);
  1138. $this->img = $timg;
  1139. $y = ($acthei-$khei)/2;
  1140. $x = $oldwid+$wspc+4;
  1141. imagerectangle($this->img,$x-4,$y,$actwid-1,$khei+($acthei-$khei)/2+4,imagecolorallocate($this->img,0,0,0));
  1142. $black = imagecolorallocate($this->img,0,0,0);
  1143. if ($this->getProp('type','line')=='bar') {
  1144. $colorlist = $this->getProp("colorlist",false);
  1145. if ($colorlist === true || $colorlist === 1 || $colorlist === "true") {
  1146. $colorlist = array(array(255, 203, 3),array(220, 101, 29),array(189, 24, 51),array(214, 0, 127),array(98, 1, 96),array(0, 62, 136),array(0, 102, 179),array(0, 145, 195),array(0, 115, 106),array(178, 210, 52),array(137, 91, 74),array(82, 56, 47));
  1147. }
  1148. if ($colorlist) {
  1149. $col = $colorlist[$i-1];
  1150. } else {
  1151. $this->error("colorlist must be set for keys to work.",E_USER_ERROR);
  1152. }
  1153. } else {
  1154. $colorlist = $this->getProp('colorlist',array(array(125, 203, 3),array(220, 101, 29),array(189, 24, 51),array(34, 78, 120),array(120, 1, 60),array(0, 62, 136),array(0, 102, 179),array(0, 145, 195),array(0, 115, 106),array(178, 210, 52),array(137, 91, 74),array(82, 56, 47)));
  1155. }
  1156. foreach ($keys as $i => $k) {
  1157. if ($type=='line') {
  1158. $col = $this->getProp("color",array(0,0,255,0),$i);
  1159. } else {
  1160. $col = $colorlist[$i];
  1161. }
  1162. if (isset($col[3])) {
  1163. $alpha = $col[3];
  1164. } else {
  1165. $alpha = 0;
  1166. }
  1167. $fco = imagecolorallocatealpha($this->img, $col[0], $col[1], $col[2], $alpha);
  1168. imagefilledrectangle($this->img,$x,$y+=4,$x+$indhei-4,$y+=$indhei-2,$fco);
  1169. $y-=$indhei-2+4;
  1170. imagerectangle($this->img,$x,$y+=4,$x+$indhei-4,$y+=$indhei-2,$black);
  1171. imagettftext($this->img,$size,0,$x+$indhei,$y-1,$black,$font,$k);
  1172. }
  1173. }
  1174. $this->error(true);
  1175. return true;
  1176. }
  1177. function loadimg($file) {
  1178. if (substr($file,-4)==".png") {
  1179. $im = imagecreatefrompng($file);
  1180. }elseif (substr($file,-4)==".gif") {
  1181. $im = imagecreatefromgif ($file);
  1182. }elseif (substr($file,-4)==".jpg" || substr($file,-5)==".jpeg") {
  1183. $im = imagecreatefromjpeg($file);
  1184. }elseif (substr($file,-4)==".bmp") {
  1185. $im = imagecreatefromwbmp($file);
  1186. } else {
  1187. $this->error("Image format not understood",true);
  1188. }
  1189. return $im;
  1190. }
  1191. function imageSmoothAlphaLine ($image, $x1, $y1, $x2, $y2, $r, $g, $b, $alpha=0) { //Thanks php.net poster
  1192. if ($this->mode=='image') {
  1193. if ($x2==$x1) {
  1194. $x2++;
  1195. }
  1196. if ($y2==$y1) {
  1197. $y2++;
  1198. }
  1199. $icr = $r;$icg = $g;$icb = $b;$dcol = imagecolorallocatealpha($image, $icr, $icg, $icb, $alpha);$m = ($y2 - $y1) / ($x2 - $x1);$b = $y1 - $m * $x1;
  1200. if (abs ($m) <2) {
  1201. $x = min($x1, $x2);$endx = max($x1, $x2) + 1;
  1202. while ($x < $endx) {
  1203. $y = $m * $x + $b;$ya = ($y == floor($y) ? 1: $y - floor($y));$yb = ceil($y) - $y;$trgb = ImageColorAt($image, $x, floor(abs($y)));$tcr = ($trgb >> 16) & 0xFF;$tcg = ($trgb >> 8) & 0xFF;$tcb = $trgb & 0xFF;imagesetpixel($image, $x, floor($y), imagecolorallocatealpha($image, ($tcr * $ya + $icr * $yb), ($tcg * $ya + $icg * $yb), ($tcb * $ya + $icb * $yb), $alpha));$trgb = ImageColorAt($image, $x, ceil(abs($y)));$tcr = ($trgb >> 16) & 0xFF;$tcg = ($trgb >> 8) & 0xFF;$tcb = $trgb & 0xFF;imagesetpixel($image, $x, ceil($y), imagecolorallocatealpha($image, ($tcr * $yb + $icr * $ya), ($tcg * $yb + $icg * $ya), ($tcb * $yb + $icb * $ya), $alpha));$x++;
  1204. }
  1205. } else {
  1206. $y = min($y1, $y2);$endy = max($y1, $y2) + 1;
  1207. while ($y < $endy) {
  1208. @$x = ($y - $b) / $m;
  1209. $xa = ($x == floor($x) ? 1: $x - floor($x));$xb = ceil($x) - $x;$trgb = ImageColorAt($image, floor(abs($x)), $y);$tcr = ($trgb >> 16) & 0xFF;$tcg = ($trgb >> 8) & 0xFF;$tcb = $trgb & 0xFF;
  1210. imagesetpixel($image, floor($x), $y, imagecolorallocatealpha($image, ($tcr * $xa + $icr * $xb), ($tcg * $xa + $icg * $xb), ($tcb * $xa + $icb * $xb), $alpha));$trgb = ImageColorAt($image, ceil(abs($x)), $y);$tcr = ($trgb >> 16) & 0xFF;$tcg = ($trgb >> 8) & 0xFF;$tcb = $trgb & 0xFF;imagesetpixel ($image, ceil(abs($x)), $y, imagecolorallocatealpha($image, ($tcr * $xb + $icr * $xa), ($tcg * $xb + $icg * $xa), ($tcb * $xb + $icb * $xa), $alpha));$y++;
  1211. }
  1212. }
  1213. } else {
  1214. $this->div->setColor($r,$g,$b);
  1215. $this->div->drawLine($x1,$y1,$x2,$y2);
  1216. }
  1217. }
  1218. function drawArrowheads ($x1, $y1, $x2, $y2, $arrhead, $arrang) { //Thanks php.net poster (tried to do the math myself, not fun :()
  1219. $debug = false;
  1220. if (($x2-$x1)==0) {
  1221. if ($y1 == 0) {
  1222. $slope = 0;
  1223. } else {
  1224. $slope = 'INFINITE';
  1225. }
  1226. } else {
  1227. $slope = -($y2-$y1)/($x2-$x1);
  1228. }
  1229. if ($debug) {
  1230. echo ("Values of xy.. before add/sub</br>");
  1231. echo ("$x1, $y1 $x2, $y2</br>");
  1232. }
  1233. if ($slope == 'INFINITE') {
  1234. $ang = 90;
  1235. } else {
  1236. $ang = atan ($slope);
  1237. $ang = ($ang * 180)/pi();
  1238. }
  1239. $arrang1 = ($ang - $arrang);
  1240. $arrang1 = ($arrang1*pi())/180;
  1241. $arrang2 = ($ang + $arrang);
  1242. $arrang2 = ($arrang2*pi())/180;
  1243. $arx1 = (floor(cos($arrang1)*$arrhead));
  1244. $ary1 = (floor(sin($arrang1)*$arrhead));
  1245. $arx2 = (floor(cos($arrang2)*$arrhead));
  1246. $ary2 = (floor(sin($arrang2)*$arrhead));
  1247. if ($ang==0) {
  1248. if ($x2>$x1) {
  1249. $arx1=$x2-$arx1;$ary1=$y2-$ary1;$arx2=$x2-$arx2;$ary2=$y2-$ary2;
  1250. }elseif ($x2<$x1) {
  1251. $arx1=$x2+$arx1;$ary1=$y2-$ary1;$arx2=$x2+$arx2;$ary2=$y2-$ary2;
  1252. }
  1253. }
  1254. if ($ang>0&&$ang<90) {
  1255. if (($x2>$x1)&&($y2<$y1)) {
  1256. $arx1=$x2-$arx1;$ary1=$y2+$ary1;$arx2=$x2-$arx2;$ary2=$y2+$ary2;
  1257. }elseif (($x2<$x1)&&($y2>$y1)) {
  1258. $arx1=$x2+$arx1;$ary1=$y2-$ary1;$arx2=$x2+$arx2;$ary2=$y2-$ary2;
  1259. }
  1260. }
  1261. if ($ang==90) {
  1262. if (($y2>$y1)) {
  1263. $arx1=$x2-$arx1;$ary1=$y2-$ary1;$arx2=$x2-$arx2;$ary2=$y2-$ary2;
  1264. }elseif (($y2<$y1)) {
  1265. $arx1=$x2-$arx1;$ary1=$y2+$ary1;$arx2=$x2-$arx2;$ary2=$y2+$ary2;
  1266. }
  1267. }
  1268. if ($ang>-90&&$ang<0) {
  1269. if (($x2>$x1)&&($y2>$y1)) {
  1270. $arx1=$x2-$arx1;$ary1=$y2+$ary1;$arx2=$x2-$arx2;$ary2=$y2+$ary2;
  1271. }elseif (($x2<$x1)&&($y2<$y1)) {
  1272. $arx1=$x2+$arx1;$ary1=$y2-$ary1;$arx2=$x2+$arx2;$ary2=$y2-$ary2;
  1273. }
  1274. }
  1275. $array_arrows=array('x1'=>$arx1,'y1'=>$ary1,'x2'=>$arx2,'y2'=>$ary2);
  1276. return $array_arrows;
  1277. }
  1278. function showGraph($show = true) {
  1279. if ($this->mode=='image') {
  1280. if ($show === true) {
  1281. if (!$this->getProp("noheader",false)) {
  1282. header('Content-type: image/'.$this->getProp('imagetype','png'));
  1283. }
  1284. switch ($this->getProp("imagetype","png")){
  1285. case 'png':
  1286. imagepng($this->img);
  1287. break;
  1288. case 'jpeg':
  1289. imagejpeg($this->img);
  1290. break;
  1291. case 'gif':
  1292. imagegif ($this->img);
  1293. break;
  1294. default:
  1295. $this->error('imagetype not understood.');
  1296. }
  1297. return true;
  1298. }elseif ($show == "random" || $show === false) {
  1299. $name = $this->getProp("imagepre","")."graphImage".($show=="random"?rand(1000000,10000000):"").'.'.$this->getProp('imagetype','png');
  1300. switch ($this->getProp("imagetype","png")) {
  1301. case 'png':
  1302. imagepng($this->img,$name);
  1303. break;
  1304. case 'jpeg':
  1305. imagejpeg($this->img,$name);

Large files files are truncated, but you can click here to view the full file