├── README.md ├── bin └── phpGraph.php ├── composer.json └── samples.php /README.md: -------------------------------------------------------------------------------- 1 | phpGraph 2 | ======== 3 | 4 | Writing svg histogram with php 5 | 6 | How to use ? 7 | ------------ 8 | 9 | First, data must be in an php array (one or two dimensions). 10 | Then, an instance of phpGraph class have to be called after an inclusion of phpGraph.php file in your project. 11 | Then, the main method called draw is used, with or withour options. It's up to you. 12 | 13 | Add phpGraph_style.css to header of your page for display graph. 14 | 15 | 16 | 17 | 18 | 19 | 20 | phpGraph 21 | 22 | 23 | (...) 24 | 25 | By default, it's a line histogram which is displaying. 26 | 27 | To resume : 28 | 29 | 10, 34 | 'serie 2' => 38, 35 | 'serie 3' => 23, 36 | 'serie 4' => -15 37 | ); 38 | 39 | $G = new phpGraph(); 40 | 41 | echo $G->draw($data); 42 | ?> 43 | 44 | Options available : 45 | ------------------- 46 | 47 | //All options available 48 | $options = array( 49 | 'width' => null,// (int) width of grid 50 | 'height' => null,// (int) height of grid 51 | 'paddingTop' => 10,// (int) 52 | 'type' => 'line',// (string) line, bar, pie, ring, stock or h-stock (todo curve) 53 | 'steps' => null,// (int) 2 graduations on y-axis are separated by $steps units. "steps" is automatically calculated but we can set the value with integer. No effect on stock and h-stock charts 54 | 'filled' => true,// (bool) to fill lines/histograms/disks 55 | 'tooltips' => false,// (bool) to show tooltips 56 | 'circles' => true,// (bool) to show circles on graph (lines or histograms). No effect on stock and h-stock charts 57 | 'stroke' => '#3cc5f1',// (string) color of lines by default. Use an array to personalize each line 58 | 'background' => "#ffffff",// (string) color of grid background. Don't use short notation (#fff) because of $this->__genColor(); 59 | 'opacity' => '0.5',// (float) between 0 and 1. No effect on stock and h-stock charts 60 | 'gradient' => null,// (array) 2 colors from left to right 61 | 'titleHeight' => 0,// (int) Height of main title 62 | 'tooltipLegend' => null,// (string or array) Text display in tooltip with y value. Each text can be personalized using an array. No effect on stock and h-stock charts 63 | 'legends' => null,// (string or array or bool) General legend for each line/histogram/disk displaying under diagram 64 | 'title' => null,// (string) Main title. Title wil be displaying in a tooltip too. 65 | 'radius' => 100,// (int) Radius of pie 66 | 'diskLegends' => false,// (bool) to display legends around a pie 67 | 'diskLegendsType' => 'label',// (string) data, pourcent or label to display around a pie as legend 68 | 'diskLegendsLineColor' => 'darkgrey',// (string) color of lines which join pie to legends 69 | 'responsive' => true,// (bool) to avoid svg to be responsive (dimensions fixed) 70 | 'paddingLegendX' => 10,//We add 10 units in viewbox to display x legend correctly 71 | ); 72 | 73 | See [samples.php](http://www.ecyseo.net/?static8/phpgraph) for more details. 74 | 75 | [Page of project on github](http://jerrywham.github.io/phpGraph/) 76 | 77 | Licence : 78 | --------- 79 | [CONTRAT DE LICENCE DE LOGICIEL LIBRE CeCILL version 2.1](http://www.cecill.info/licences/Licence_CeCILL_V2.1-fr.txt) 80 | 81 | Change log : 82 | --------- 83 | 2015-01-29 84 | * [BUG] calcul of position of points for lines and bars 85 | * [BUG] position of legend for pies and rings 86 | * [BUG] put in cache 87 | 88 | 2015-01-28 89 | * [+] css file is not mandatory. Style is included in svg and can be modified via setCss() method 90 | * [+] new option : diskLegendsLineColor 91 | * [BUG] colors of legends 92 | * [BUG] position of lines between pie and labels 93 | -------------------------------------------------------------------------------- /bin/phpGraph.php: -------------------------------------------------------------------------------- 1 | 25 | * @copyright 2009-2019 Cyril MAGUIRE, 26 | * @license Licensed under the CeCILL v2.1 license. http://www.cecill.info/licences.fr.html 27 | */ 28 | 29 | class phpGraph { 30 | 31 | # Basic css style 32 | protected $css = ' 33 | /**/.draw { 34 | width:70%;/*Adjust this value to resize svg automatically*/ 35 | margin:auto; 36 | } 37 | /**/svg {/*width and height of svg is 100% of dimension of its parent (draw class here)*/ 38 | display: block; 39 | margin:auto; 40 | margin-bottom: 50px; 41 | } 42 | /**/.graph-title { 43 | stroke-width:4; 44 | stroke:transparent; 45 | fill:#000033; 46 | font-size: 1.2em; 47 | } 48 | /**/.graph-grid { 49 | stroke-width:1; 50 | stroke:#c4c4c4; 51 | } 52 | /**/.graph-stroke { 53 | stroke-width:2; 54 | stroke:#424242; 55 | } 56 | /**/.graph-legends {} 57 | /**/.graph-x text, 58 | /**/.graph-y text { 59 | font-size:0.5em; 60 | } 61 | /**/.graph-active .graph-legend { 62 | font-size:0.6em; 63 | } 64 | /**/.graph-legend-stroke {} 65 | /**/.graph-line { 66 | stroke-linejoin:round; 67 | stroke-width:2; 68 | } 69 | /**/.graph-fill { 70 | stroke-width:0; 71 | } 72 | /**/.graph-bar {} 73 | /**/.graph-point { 74 | stroke-width:1; 75 | fill:#fff; 76 | fill-opacity:1; 77 | stroke-opacity:1; 78 | } 79 | /**/.graph-point-active:hover { 80 | stroke-width:5; 81 | transition-duration:.9s; 82 | cursor: pointer; 83 | } 84 | /**/title.graph-tooltip { 85 | background-color:#d6d6d6; 86 | } 87 | /**/.graph-pie { 88 | cursor: pointer; 89 | stroke-width:1; 90 | stroke:#fff; 91 | } 92 | /**/text { 93 | fill:#000; 94 | font-size:0.7em; 95 | } 96 | '; 97 | 98 | protected $options = array( 99 | 'width' => null,// (int) width of grid 100 | 'height' => null,// (int) height of grid 101 | 'paddingTop' => 10,// (int) 102 | 'type' => 'line',// (string) line, bar, pie, ring, stock or h-stock (todo curve) 103 | 'steps' => null,// (int) 2 graduations on y-axis are separated by $steps units. "steps" is automatically calculated but we can set the value with integer. No effect on stock and h-stock charts 104 | 'filled' => true,// (bool) to fill lines/histograms/disks 105 | 'tooltips' => false,// (bool) to show tooltips 106 | 'circles' => true,// (bool) to show circles on graph (lines or histograms). No effect on stock and h-stock charts 107 | 'stroke' => '#3cc5f1',// (string) color of lines by default. Use an array to personalize each line 108 | 'background' => "#ffffff",// (string) color of grid background. Don't use short notation (#fff) because of $this->__genColor(); 109 | 'opacity' => '0.5',// (float) between 0 and 1. No effect on stock and h-stock charts 110 | 'gradient' => null,// (array) 2 colors from left to right 111 | 'titleHeight' => 0,// (int) Height of main title 112 | 'tooltipLegend' => null,// (string or array) Text display in tooltip with y value. Each text can be personalized using an array. No effect on stock and h-stock charts 113 | 'legends' => null,// (string or array or bool) General legend for each line/histogram/disk displaying under diagram 114 | 'title' => null,// (string) Main title. Title wil be displaying in a tooltip too. 115 | 'radius' => 100,// (int) Radius of pie 116 | 'diskLegends' => false,// (bool) to display legends around a pie 117 | 'diskLegendsType' => 'label',// (string) data, pourcent or label to display around a pie as legend 118 | 'diskLegendsLineColor' => 'darkgrey',// (string) color of lines which join pie to legends 119 | 'responsive' => true,// (bool) to avoid svg to be responsive (dimensions fixed) 120 | 'paddingLegendX' => 10,//We add 10 units in viewbox to display x legend correctly 121 | 'paddingLegendY' => 0,//Padding to display y legend correctly, if needed, for pie and ring 122 | 'transform' => null,//Transformation of the text of the legend 123 | 'marginTop' => 0,//Margin of the legend when use transform 124 | ); 125 | # authorized types 126 | protected $types = array('line','line','bar','pie','ring','stock','h-stock'); 127 | protected $periodOfCache = 1;//A REGLER ET A VERIFIER 128 | 129 | private $DEBUG = false; 130 | private $L_ERROR_FILE_NOT_FOUND = 'ERROR FILE NOT FOUND'; 131 | private $SIG_ROOT = dirname(__FILE__).DIRECTORY_SEPARATOR; 132 | private $SIG_CORE = 'core'.DIRECTORY_SEPARATOR; 133 | 134 | 135 | //protected $colors = array(); 136 | 137 | /** 138 | * Constructor 139 | * 140 | * @param $width integer Width of grid 141 | * @param $height integer Height of grid 142 | * @param $options array Options 143 | * @return stdio 144 | * 145 | * @author Cyril MAGUIRE 146 | **/ 147 | public function __construct($width=600,$height=300,$options=array()) { 148 | if (isset($options['ROOT']) && is_string($options['ROOT'])) { 149 | $this->SIG_ROOT = $options['ROOT']; 150 | unset($options['ROOT']); 151 | } 152 | $this->SIG_CORE = $this->SIG_ROOT.$this->SIG_CORE; 153 | if (!empty($options)) { 154 | $this->options = $options; 155 | } 156 | if (!empty($width)) { 157 | $this->options['width'] = $width; 158 | } 159 | if (!empty($height)) { 160 | $this->options['height'] = $height; 161 | } 162 | if (is_string($this->options['stroke']) && substr($this->options['stroke'], 0,1) == '#') { 163 | $this->options['stroke'] = array(0=>substr($this->options['stroke'],0,7)); 164 | } 165 | if (is_string($this->options['type']) && in_array($this->options['type'], $this->types)) { 166 | $this->options['type'] = array(0=>$this->options['type']); 167 | } 168 | } 169 | 170 | /** 171 | * To add your own style 172 | * @param $css string your css 173 | * @return string css 174 | * 175 | * @author Cyril MAGUIRE 176 | */ 177 | public function setCss($css) { 178 | if (is_string($css) && !empty($css)) { 179 | $this->css .= $css; 180 | } 181 | } 182 | 183 | /** 184 | * Main function 185 | * @param $data array Uni or bidimensionnal array 186 | * @param $options array Array of options 187 | * @param $putInCache string path of directory where cache will be recorded 188 | * @param $id string index of svg tag 189 | * @return string SVG 190 | * 191 | * @author Cyril MAGUIRE 192 | */ 193 | public function draw($data,$options=array(),$putInCache=false,$id=false,$txt=false) { 194 | 195 | if ($id) { 196 | $this->css = str_replace('/**/', '#'.$id.' ', $this->css); 197 | } 198 | 199 | # Cache 200 | $nameOfFiles = glob($putInCache.'*.svg'); 201 | if ($putInCache != false && isset($nameOfFiles[0])) { 202 | $stat = stat($nameOfFiles[0]); 203 | if ($stat['mtime'] > (time() - $this->periodOfCache) ) { 204 | return file_get_contents($nameOfFiles[0]).($id ? $downloadLink : ''); 205 | } 206 | } 207 | $return = ''; 208 | 209 | $options = array_merge($this->options,$options); 210 | 211 | extract($options); 212 | 213 | if ($title) { 214 | $options['titleHeight'] = $titleHeight = 40; 215 | } 216 | if ($opacity < 0 || $opacity > 1) { 217 | $options['opacity'] = 0.5; 218 | } 219 | if (!is_string($diskLegendsLineColor)) { 220 | $diskLegendsLineColor = 'darkgrey'; 221 | } 222 | 223 | $HEIGHT = $height+$titleHeight+$paddingTop; 224 | 225 | $heightLegends = 0; 226 | if (isset($legends) && !empty($legends)) { 227 | $heightLegends = count($legends)*30+2*$paddingTop; 228 | } 229 | 230 | $pie = ''; 231 | 232 | if ($type != 'pie' && $type != 'ring') { 233 | # looking for min and max 234 | extract($this->__minMax($data,$type)); 235 | $options['type'] = $type; 236 | 237 | extract($this->__xAxisConfig($type,$width,$max,$Xmax,$Xmin,$lenght,$options)); 238 | 239 | $base10 = strlen(abs($max)); 240 | $steps = 2 * (($base10 >= 2 && $max >= 50) ? str_pad(1,($base10-1),0,STR_PAD_RIGHT) : 1); 241 | 242 | $options['steps'] = $steps; 243 | 244 | if ($min < 0) { 245 | $unitY = round($height/abs(($max+$steps)-$min),PHP_ROUND_HALF_UP); 246 | } else { 247 | $unitY = round($height/($max+$steps),PHP_ROUND_HALF_UP); 248 | } 249 | $gridV = $gridH = ''; 250 | $x = $y = ''; 251 | 252 | $headerDimensions = $this->__headerDimensions($widthViewBox,$HEIGHT,$heightLegends,$titleHeight,$paddingTop,$paddingLegendX,$lenght,$stepX); 253 | 254 | # Size of canevas will be bigger than grid size to display legends 255 | $return = $this->__header($headerDimensions,$responsive,$id); 256 | 257 | if ($type == 'stock' || (is_array($type) && in_array('stock',$type)) ) { 258 | $plotLimit = $this->__stockDef(); 259 | } 260 | if ($type == 'h-stock' || (is_array($type) && in_array('h-stock',$type)) ) { 261 | $plotLimit = $this->__hstockDef(); 262 | } 263 | # we draw the grid 264 | $return .= $this->__svgGrid($gradient,$width,($height+$paddingTop),($paddingTop+$titleHeight)); 265 | 266 | if ($title) { 267 | $return .= $this->__titleDef($title,$width,$titleHeight); 268 | } 269 | # Legends x axis and vertical grid 270 | extract($this->__XAxisDef($type,$Xmin,$Xmax,$XM,$stepX,$unitX,$HEIGHT,$paddingTop,$titleHeight,$labels,$lenght, $transform)); 271 | 272 | # Legendes y axis and horizontal grid 273 | extract($this->__YAxisDef($type,$width,$min,$max,$steps,$HEIGHT,$titleHeight,$paddingTop,$paddingLegendX,$unitY,$labels)); 274 | //Grid 275 | $return .= "\t".''."\n"; 276 | $return .= $gridH."\n"; 277 | $return .= $gridV; 278 | $return .= "\t".''."\n"; 279 | 280 | $return .= $x; 281 | $return .= $y; 282 | if (!$multi) { 283 | if (is_array($type) && count($type) == 1) { 284 | $type = $type[0]; 285 | $options['type'] = $type; 286 | } 287 | $options['stroke'] = is_array($stroke) ? $stroke[0] : $stroke; 288 | switch ($type) { 289 | case 'line': 290 | $return .= $this->__drawLine($data,$height,$HEIGHT,$stepX,$unitY,$lenght,$min,$max,$options); 291 | break; 292 | case 'bar': 293 | $return .= $this->__drawBar($data,$height,$HEIGHT,$stepX,$unitY,$lenght,$min,$max,$options); 294 | break; 295 | default: 296 | $return .= $this->__drawLine($data,$height,$HEIGHT,$stepX,$unitY,$lenght,$min,$max,$options); 297 | break; 298 | } 299 | } else { 300 | $i = 1; 301 | foreach ($data as $line => $datas) { 302 | if (!isset($type[$line]) && !is_string($type) && is_numeric($line)) { 303 | $type[$line] = 'line'; 304 | } 305 | if (!isset($type[$line]) && !is_string($type) && !is_numeric($line)) { 306 | $type[$line] = 'stock'; 307 | } 308 | if (is_string($options['type'])) { 309 | $type = array(); 310 | $type[$line] = $options['type']; 311 | } 312 | if (!isset($tooltipLegend[$line])) { 313 | $options['tooltipLegend'] = ''; 314 | } else { 315 | $options['tooltipLegend'] = $tooltipLegend[$line]; 316 | } 317 | if (!isset($stroke[$line])) { 318 | $stroke[$line] = $this->__genColor(); 319 | } 320 | $options['stroke'] = $STROKE = $stroke[$line]; 321 | $options['fill'] = $stroke[$line]; 322 | switch ($type[$line]) { 323 | case 'line': 324 | $return .= $this->__drawLine($datas,$height,$HEIGHT,$stepX,$unitY,$lenght,$min,$max,$options); 325 | break; 326 | case 'bar': 327 | $return .= $this->__drawBar($datas,$height,$HEIGHT,$stepX,$unitY,$lenght,$min,$max,$options); 328 | break; 329 | case 'stock': 330 | $id = rand(); 331 | $return .= str_replace(array('id="plotLimit"','stroke=""'), array('id="plotLimit'.$id.'"','stroke="'.$stroke[$line].'"'), $plotLimit); 332 | $return .= $this->__drawStock($data,$height,$HEIGHT,$stepX,$unitY,$lenght,$min,$max,$options,$i,$labels,$id); 333 | $i++; 334 | break; 335 | case 'h-stock': 336 | $id = rand(); 337 | $return .= str_replace(array('id="plotLimit"','stroke=""'), array('id="plotLimit'.$id.'"','stroke="'.$stroke[$line].'"'), $plotLimit); 338 | $return .= $this->__drawHstock($data,$HEIGHT,$stepX,$unitX,$unitY,$lenght,$Xmin,$Xmax,$options,$i,$labels,$id); 339 | $i++; 340 | break; 341 | case 'ring': 342 | $options['subtype'] = 'ring'; 343 | case 'pie': 344 | $options['multi'] = $multi; 345 | if (is_array($stroke)) { 346 | $options['stroke'] = $stroke[$line]; 347 | $options['fill'] = $stroke; 348 | } 349 | if (is_array($legends)) { 350 | $options['legends'] = $legends[$line]; 351 | } 352 | $pie .= $this->__drawDisk($datas,$options,$id); 353 | $pie .= "\n".''."\n"; 354 | break; 355 | default: 356 | $return .= $this->__drawLine($datas,$height,$HEIGHT,$stepX,$unitY,$lenght,$min,$max,$options); 357 | break; 358 | } 359 | } 360 | } 361 | # legends 362 | $return .= $this->__legendsDef($legends,$type,$stroke,$HEIGHT,$paddingTop,$marginTop); 363 | $return .= "\n".''."\n"; 364 | $return .= $pie; 365 | } else { 366 | $options['tooltipLegend'] = array(); 367 | if ($tooltipLegend && !is_array($tooltipLegend)) { 368 | foreach ($data as $key => $value) { 369 | $options['tooltipLegend'][] = $tooltipLegend; 370 | } 371 | } 372 | if ($tooltipLegend && is_array($tooltipLegend)) { 373 | $options['tooltipLegend'] = $tooltipLegend; 374 | } 375 | $options['stroke'] = array(); 376 | if (isset($stroke) && !is_array($stroke)) { 377 | foreach ($data as $key => $value) { 378 | $options['stroke'][] = $stroke; 379 | } 380 | } 381 | if (isset($stroke) && is_array($stroke)) { 382 | $options['stroke'] = $stroke; 383 | } 384 | foreach ($data as $line => $datas) { 385 | if (is_array($datas)) { 386 | if (is_array($stroke)) { 387 | $options['stroke'] = $stroke[$line]; 388 | $options['fill'] = $stroke; 389 | } 390 | if (is_array($legends)) { 391 | $options['legends'] = $legends[$line]; 392 | } 393 | $return .= $this->__drawDisk($datas,$options,$id); 394 | $return .= "\n".''."\n"; 395 | $multi = true; 396 | } else { 397 | $multi = false; 398 | } 399 | } 400 | if (!$multi) { 401 | if (is_array($stroke)) { 402 | $options['stroke'] = $stroke; 403 | $options['fill'] = $stroke; 404 | } 405 | if (is_array($legends)) { 406 | $options['legends'] = $legends; 407 | } 408 | $return .= $this->__drawDisk($data,$options,$id); 409 | $return .= "\n".''."\n"; 410 | } 411 | 412 | } 413 | 414 | $this->colors = array(); 415 | if ($putInCache && $stat['mtime'] > (time() - $this->periodOfCache) ) { 416 | $this->putInCache(trim($return),md5(implode('',$nameOfFile)),$putInCache); 417 | //file_put_contents($putInCache, trim($return)); 418 | } 419 | return $return.($id ? $downloadLink : ''); 420 | } 421 | 422 | /** 423 | * To draw lines 424 | * @param $data array Unidimensionnal array 425 | * @param $height integer Height of grid 426 | * @param $HEIGHT integer Height of grid + title + padding top 427 | * @param $stepX integer Unit of x-axis 428 | * @param $unitY integer Unit of y-axis 429 | * @param $lenght integer Size of data array 430 | * @param $min integer Minimum value of data 431 | * @param $max integer Maximum value of data 432 | * @param $options array Options 433 | * @return string Path of lines (with options) 434 | * 435 | * @author Cyril MAGUIRE 436 | */ 437 | protected function __drawLine($data,$height,$HEIGHT,$stepX,$unitY,$lenght,$min,$max,$options) { 438 | $return = ''; 439 | 440 | extract($options); 441 | 442 | $this->colors[] = $options['stroke']; 443 | 444 | //Ligne 445 | $i = 0; 446 | $c = ''; 447 | $t = ''; 448 | $path = "\t\t".''; 479 | } 480 | # Line 481 | $c1 = $this->__c($coordonneesCircle1,$stroke); 482 | $c2 = $this->__c($coordonneesCircle2,$stroke); 483 | if ($value != $max) { 484 | if ($value == $min) { 485 | if ($i == 0) { 486 | // if ($min<=0) { 487 | // $path .= 'M '.$coordonnees2.' L'; 488 | // //Tooltips and circles 489 | // $c .= $c2; 490 | // } else { 491 | $path .= 'M '.$coordonnees1.' L'; 492 | //Tooltips and circles 493 | $c .= $c1; 494 | // } 495 | } else { 496 | $path .= "\n\t\t\t\t".$coordonnees1; 497 | //Tooltips and circles 498 | $c .= $c1; 499 | } 500 | } else { 501 | if ($i == 0) { 502 | $path .= 'M '.$coordonnees1.' L'; 503 | //Tooltips and circles 504 | $c .= $c1; 505 | } else { 506 | $path .= "\n\t\t\t\t".$coordonnees1; 507 | //Tooltips and circles 508 | $c .= $c1; 509 | } 510 | } 511 | } else { 512 | //Line 513 | if ($i == 0) { 514 | $path .= 'M '.($i * $stepX + 50).' '.($V == 0 ? $HEIGHT + $paddingTop : ($titleHeight + ($HEIGHT - $unitY*$V))).' L'; 515 | //Tooltips and circles 516 | $c .= "\n\t\t\t".''; 517 | } else { 518 | $path .= "\n\t\t\t\t".$coordonnees1; 519 | //Tooltips and circles 520 | $c .= "\n\t\t\t".''; 521 | } 522 | 523 | } 524 | $i++; 525 | //End tooltips 526 | if($tooltips == true) { 527 | $c .= "\n\t\t\t".''.(is_array($tooltipLegend) ? $tooltipLegend[$i] : $tooltipLegend).$value.''."\n\t\t".''; 528 | } 529 | } 530 | if ($opacity > 0.8 && $filled === true) { 531 | $tmp = $stroke; 532 | $stroke = '#a1a1a1'; 533 | } 534 | //End of line 535 | $pathLine = '" class="graph-line" stroke="'.$stroke.'" fill="#fff" fill-opacity="0"/>'."\n"; 536 | //Filling 537 | if ($filled === true) { 538 | if ($min<=0) { 539 | $path .= "\n\t\t\t\t".(($i - 1) * $stepX + 50).' '.($HEIGHT + ($unitY)*($min-$value) + ($unitY * $value)).' 50 '.($HEIGHT + ($unitY)*($min-$value) + ($unitY * $value))."\n\t\t\t\t"; 540 | } else { 541 | $path .= "\n\t\t\t\t".(($i - 1) * $stepX + 50).' '.$HEIGHT.' 50 '.$HEIGHT."\n\t\t\t\t"; 542 | } 543 | if ($opacity > 0.8) { 544 | $stroke = $tmp; 545 | } 546 | $return .= $path.'" class="graph-fill" fill="'.$stroke.'" fill-opacity="'.$opacity.'"/>'."\n"; 547 | } 548 | //Display line 549 | $return .= $path.$pathLine; 550 | 551 | if($circles == true) { 552 | $return .= "\t".''; 553 | $return .= $c; 554 | $return .= "\n\t".''."\n"; 555 | } 556 | return $return; 557 | } 558 | 559 | /** 560 | * To draw histograms 561 | * @param $data array Unidimensionnal array 562 | * @param $height integer Height of grid 563 | * @param $HEIGHT integer Height of grid + title + padding top 564 | * @param $stepX integer Unit of x-axis 565 | * @param $unitY integer Unit of y-axis 566 | * @param $lenght integer Size of data array 567 | * @param $min integer Minimum value of data 568 | * @param $max integer Maximum value of data 569 | * @param $options array Options 570 | * @return string Path of lines (with options) 571 | * 572 | * @author Cyril MAGUIRE 573 | */ 574 | protected function __drawBar($data,$height,$HEIGHT,$stepX,$unitY,$lenght,$min,$max,$options) { 575 | $return = ''; 576 | 577 | extract($options); 578 | 579 | $this->colors[] = $options['stroke']; 580 | 581 | //Bar 582 | $bar = ''; 583 | $i = 0; 584 | $c = ''; 585 | $t = ''; 586 | foreach ($data as $label => $value) { 587 | 588 | if ($min <=0) { 589 | $V = ($value-$min); 590 | } else { 591 | $V = $value; 592 | } 593 | 594 | //Tooltips and circles 595 | if($tooltips == true) { 596 | $c .= "\n\t\t".''; 597 | } 598 | 599 | $stepY = $V*$unitY; 600 | 601 | //$min>=0 602 | $coordonnees1 = 'x="'.($i * $stepX + 50).'" y="'.($HEIGHT + $paddingTop - $unitY*$V).'"'; 603 | //On recule d'un demi pas pour que la valeur de x soit au milieu de la barre de diagramme 604 | $coordonnees2 = 'x="'.($i * $stepX + 50 - $stepX/2).'" y="'.($HEIGHT + $paddingTop - $stepY).'"'; 605 | //$min<0 606 | $coordonnees3 = 'x="'.($i * $stepX + 50 - $stepX/2).'" y="'.($HEIGHT + $paddingTop - $unitY*$V).'"'; 607 | //$min<0 et $value<0 608 | $coordonnees4 = 'x="'.($i * $stepX + 50 - $stepX/2).'" y="'.($HEIGHT + $paddingTop - $unitY*$V + $stepY).'"'; 609 | $coordonnees5 = 'x="'.($i * $stepX + 50).'" y="'.($HEIGHT + $paddingTop - $unitY*$V + $stepY).'"'; 610 | //$min>=0 et $value == $max 611 | $coordonnees6 = 'x="'.($i * $stepX + 50).'" y="'.($paddingTop + $titleHeight + ($height - $stepY) + $paddingTop).'"'; 612 | //$value == 0 613 | $coordonnees7 = 'x="50" y="'.($HEIGHT + $paddingTop + $unitY*$min).'"'; 614 | if ($value == 0) { 615 | $stepY = 1; 616 | } 617 | //Diagramme 618 | //On est sur la première valeur, on divise la largeur de la barre en deux 619 | if ($i == 0) { 620 | if ($value == $max) { 621 | $bar .= "\n\t".''; 622 | 623 | $c .= "\n\t\t\t".''; 624 | 625 | } else { 626 | if ($min>=0) { 627 | $bar .= "\n\t".''; 628 | 629 | $c .= "\n\t\t\t".''; 630 | 631 | } else { 632 | if ($value == $min) { 633 | $bar .= "\n\t".''; 634 | } else { 635 | if ($value == 0) { 636 | $bar .= "\n\t".''; 637 | } else { 638 | $bar .= "\n\t".''; 639 | } 640 | } 641 | 642 | $c .= "\n\t\t\t".''; 643 | 644 | } 645 | 646 | } 647 | } else { 648 | if ($value == $max) { 649 | if ($min>=0) { 650 | //Si on n'est pas sur la dernière valeur 651 | if ($i != $lenght-1) { 652 | $bar .= "\n\t".''; 653 | 654 | } else { 655 | $bar .= "\n\t".''; 656 | } 657 | $c .= "\n\t\t\t".''; 658 | } else { 659 | if ($value >= 0) { 660 | //Si on n'est pas sur la dernière valeur 661 | if ($i != $lenght-1) { 662 | $bar .= "\n\t".''; 663 | } else { 664 | $bar .= "\n\t".''; 665 | } 666 | } else { 667 | //Si on n'est pas sur la dernière valeur 668 | if ($i != $lenght-1) { 669 | $bar .= "\n\t".''; 670 | } else { 671 | $bar .= "\n\t".''; 672 | } 673 | } 674 | 675 | $c .= "\n\t\t\t".''; 676 | 677 | } 678 | }else { 679 | if ($min>=0) { 680 | //Si on n'est pas sur la dernière valeur 681 | if ($i != $lenght-1) { 682 | $bar .= "\n\t".''; 683 | } else { 684 | $bar .= "\n\t".''; 685 | } 686 | 687 | $c .= "\n\t\t\t".''; 688 | 689 | } else { 690 | if ($value >= 0) { 691 | //Si on n'est pas sur la dernière valeur 692 | if ($i != $lenght-1) { 693 | $bar .= "\n\t".''; 694 | } else { 695 | $bar .= "\n\t".''; 696 | } 697 | } else { 698 | //Si on n'est pas sur la dernière valeur 699 | if ($i != $lenght-1) { 700 | $bar .= "\n\t".''; 701 | } else { 702 | $bar .= "\n\t".''; 703 | } 704 | } 705 | 706 | $c .= "\n\t\t\t".''; 707 | 708 | } 709 | } 710 | } 711 | $i++; 712 | //End of tooltips 713 | if($tooltips == true) { 714 | $c .= ''.(is_array($tooltipLegend) ? $tooltipLegend[$i] : $tooltipLegend).$value.''."\n\t\t".''; 715 | } 716 | } 717 | 718 | //Filling 719 | if ($filled === true) { 720 | if ($opacity == 1) { 721 | $opacity = '1" stroke="#424242'; 722 | } 723 | $barFilled = str_replace(' class="graph-bar" stroke="'.$stroke.'" fill="#fff" fill-opacity="0"/>', ' class="graph-bar" fill="'.$stroke.'" fill-opacity="'.$opacity.'"/>',$bar); 724 | $return .= $barFilled; 725 | } 726 | 727 | $return .= $bar; 728 | 729 | if($circles == true) { 730 | $return .= "\n\t".''; 731 | $return .= $c; 732 | $return .= "\n\t".''."\n"; 733 | } 734 | return $return; 735 | } 736 | 737 | /** 738 | * To draw pie diagrams 739 | * @param $data array Unidimensionnal array 740 | * @param $options array Options 741 | * @return string Path of lines (with options) 742 | * 743 | * @author Cyril MAGUIRE 744 | */ 745 | protected function __drawDisk($data,$options=array(),$id=false) { 746 | 747 | $options = array_merge($this->options,$options); 748 | 749 | extract($options); 750 | 751 | if (is_string($legends)) { 752 | $mainLegend = $legends; 753 | } else { 754 | $mainLegend = null; 755 | } 756 | if (is_string($stroke)) { 757 | $mainStroke = $stroke; 758 | } else { 759 | $mainStroke = $this->__genColor(); 760 | } 761 | 762 | $lenght = count($data); 763 | $max = max($data); 764 | 765 | $total = 0; 766 | foreach ($data as $label => $value) { 767 | if ($value < 0) {$value = 0;} 768 | $total += $value; 769 | } 770 | $deg = array(); 771 | $i = 0; 772 | foreach ($data as $label => $value) { 773 | 774 | if ($value < 0) {$value = 0;} 775 | if ($total == 0) { 776 | $deg[] = array( 777 | 'pourcent' => 0, 778 | 'val' => $value, 779 | 'label' => $label, 780 | 'tooltipLegend' => (is_array($tooltipLegend) && isset($tooltipLegend[$i])) ? $tooltipLegend[$i] : (isset($tooltipLegend) && is_string($tooltipLegend) ? $tooltipLegend : ''), 781 | 'stroke' => (is_array($stroke) && isset($stroke[$i]))? $stroke[$i] : $this->__genColor(), 782 | ); 783 | } else { 784 | $deg[] = array( 785 | 'pourcent' => round(((($value * 100)/$total)/100),2), 786 | 'val' => $value, 787 | 'label' => $label, 788 | 'tooltipLegend' => (is_array($tooltipLegend) && isset($tooltipLegend[$i])) ? $tooltipLegend[$i] : (isset($tooltipLegend) && is_string($tooltipLegend) ? $tooltipLegend : ''), 789 | 'stroke' => (is_array($stroke) && isset($stroke[$i]) ) ? $stroke[$i] : $this->__genColor(), 790 | ); 791 | } 792 | $i++; 793 | } 794 | if (isset($legends)) { 795 | if (!is_array($legends) && !empty($legends) && !is_bool($legends)) { 796 | $Legends = array(); 797 | for ($l=0;$l<$lenght;$l++) { 798 | $Legends[$l] = array( 799 | 'label' => $deg[$l]['label'].' : '.$deg[$l]['val'], 800 | 'stroke' => $deg[$l]['stroke'] 801 | ); 802 | } 803 | $legends = $Legends; 804 | unset($Legends); 805 | } elseif (empty($legends)) { 806 | $notDisplayLegends = true; 807 | } elseif (is_bool($legends)) { 808 | $legends = array(); 809 | } 810 | foreach ($deg as $k => $v) { 811 | if (!isset($legends[$k]) || !is_array($legends[$k])) { 812 | $legends[$k] = array( 813 | 'label' => $v['label'].' : '.$v['val'], 814 | 'stroke' => $v['stroke'] 815 | ); 816 | } 817 | } 818 | } 819 | $deg = array_reverse($deg); 820 | 821 | $heightLegends = 0; 822 | if (isset($legends) && !empty($legends)) { 823 | $heightLegends = count($legends)*30+2*$paddingTop+80; 824 | } else { 825 | $heightLegends = 2*$paddingTop+100; 826 | } 827 | 828 | $this->colors[] = $options['stroke']; 829 | 830 | $originX = (2*$radius+400)/2; 831 | $originY = 10+$titleHeight+2*$paddingTop; 832 | 833 | 834 | //Size of canevas will be bigger than grid size to display legends 835 | $return = "\n".''."\n"; 836 | $return .= "\n\t".' 837 | '."\n"; 840 | // $return .= "\n\t\t".''; 846 | // $return .= "\n\t\t\t".''; 847 | // $return .= "\n\t\t".''; 848 | if (is_array($gradient)) { 849 | $id = 'BackgroundGradient'.rand(); 850 | $return .= "\n\t\t".''; 851 | $return .= "\n\t\t\t".''; 852 | $return .= "\n\t\t\t".''; 853 | $return .= "\n\t\t".''; 854 | $return .= "\n\t".''."\n"; 855 | $background = 'url(#'.$id.')'; 856 | $return .= "\t".''."\n"; 857 | } else { 858 | $return .= "\n\t".''."\n"; 859 | } 860 | 861 | if (isset($title)) { 862 | $return .= "\t".''.$title.''."\n"; 863 | } 864 | 865 | $ox = $prevOriginX = $originX; 866 | $oy = $prevOriginY = $originY; 867 | $total = 1; 868 | 869 | $i = 0; 870 | while ($i <= $lenght-1) { 871 | 872 | if ($deg[0]['val'] != 0) { 873 | $t = (2-$deg[0]['pourcent'])/2; 874 | $cosOrigine = cos((-90 + 360 * $t) * M_PI / 180)*$radius; 875 | $sinOrigine = sin((-90 + 360 * $t) * M_PI / 180)*$radius; 876 | $cosLegOrigine = cos((-90 + 360 * $t) * M_PI / 180)*(2*$radius); 877 | $sinLegOrigine = sin((-90 + 360 * $t) * M_PI / 180)*(2*$radius); 878 | } else { 879 | $cosOrigine = 0; 880 | $sinOrigine = 0; 881 | $cosLegOrigine = 0; 882 | $sinLegOrigine = 0; 883 | } 884 | 885 | if ($deg[$i]['val'] != 0) { 886 | //Tooltips 887 | if($tooltips == true) { 888 | $return .= "\n\t\t".''; 889 | } 890 | $color = $deg[0]['stroke']; 891 | $return .= "\n\t\t\t".''."\n\t\t\t"; 892 | 893 | if ($diskLegends == true && $deg[0]['val'] != 0 ){ 894 | 895 | if ($deg[0]['pourcent'] >= 0 && $deg[0]['pourcent'] <= 0.5 || $deg[0]['pourcent'] == 1) { 896 | $gapx = $gapy = 0; 897 | $pathGap = 2; 898 | } 899 | if($deg[0]['pourcent'] > 0.5 && $deg[0]['pourcent'] < 1) { 900 | $gapx = $gapy = 1; 901 | $pathGap = 1; 902 | } 903 | 904 | $LABEL = ($diskLegendsType == 'label' ? $deg[$i]['label'] : ($diskLegendsType == 'pourcent' ? ($deg[$i]['pourcent']*100).'%' : $deg[$i]['val'])); 905 | 906 | if ($gapx == -1) { 907 | $gapx = strlen($LABEL)*$gapx*12; 908 | $gapy = 5; 909 | } 910 | 911 | $return .= "\n\t\t\t".''; 912 | 913 | $return .= "\n\t\t\t".''.$LABEL.''."\n\t\t\t"; 914 | } 915 | 916 | //End tooltips 917 | if($tooltips == true) { 918 | $return .= ''.$deg[$i]['tooltipLegend']. $deg[$i]['label'].' : '.$deg[$i]['val'].''; 919 | $return .= "\n\t\t".''; 920 | } 921 | //$i = $deg[$i]['label']; 922 | break; 923 | } 924 | $i++; 925 | } 926 | // $tmp = array(); 927 | // if (is_array($legends)) { 928 | // foreach($legends as &$ma) { 929 | // $tmp[] = &$ma['label']; 930 | // } 931 | // array_multisort($tmp, $legends); 932 | // } 933 | 934 | foreach ($deg as $key => $value) { 935 | 936 | $total -= $value['pourcent']; 937 | $total2 = $total; 938 | 939 | $cos = cos((-90 + 360 * $total) * M_PI / 180)*$radius; 940 | $sin = sin((-90 + 360 * $total) * M_PI / 180)*$radius; 941 | 942 | $cosLeg = cos((-90 + 360 * $total) * M_PI / 180)*(2*$radius); 943 | $sinLeg = sin((-90 + 360 * $total) * M_PI / 180)*(2*$radius); 944 | 945 | if (isset($deg[$key+1])) { 946 | $total2 -= $deg[$key+1]['pourcent']; 947 | $t = (($total - $total2)/2) + $total2; 948 | $cos2 = cos((-90 + 360 * $t) * M_PI / 180)*$radius; 949 | $sin2 = sin((-90 + 360 * $t) * M_PI / 180)*$radius; 950 | $cosLeg2 = cos((-90 + 360 * $t) * M_PI / 180)*(2*$radius); 951 | $sinLeg2 = sin((-90 + 360 * $t) * M_PI / 180)*(2*$radius); 952 | } else { 953 | $cos2 = 0; 954 | $sin2 = 0; 955 | $cosLeg2 = 0; 956 | $sinLeg2 = 0; 957 | } 958 | 959 | //Tooltips 960 | if($tooltips == true && $key < ($lenght-1)) { 961 | $return .= "\n\t\t".''; 962 | } 963 | 964 | if ($total >= 0 && $total <= 0.5 || $total == 1) { 965 | $arc = 0; 966 | $gapx = $gapy = 0; 967 | $signe = 1; 968 | $pathGap = 1; 969 | } 970 | if($total > 0.5 && $total < 1) { 971 | $arc = 1; 972 | $signe = -1; 973 | $pathGap = 2.5; 974 | } 975 | $index = ($key == $lenght-1 ? 0 : $key+1); 976 | 977 | if ($key != $lenght-1 && $deg[$index]['val'] != 0) { 978 | $return .= "\n\t\t\t".''."\n\t\t\t"; 979 | } 980 | 981 | if ($key < ($lenght-1) && $deg[$key+1]['val'] != 0 && $diskLegends == true ) { 982 | 983 | $LABEL = ($diskLegendsType == 'label' ? $deg[$key+1]['label'] : ($diskLegendsType == 'pourcent' ? ($deg[$key+1]['pourcent']*100).'%' : $deg[$key+1]['val'])); 984 | 985 | if ($arc == 1) { 986 | $gapx = strlen($LABEL)*$gapx*12; 987 | $gapy = 5; 988 | } 989 | 990 | $return .= "\n\t\t\t".''; 991 | 992 | $return .= "\n\t\t\t".'  '.$LABEL.''."\n\t\t\t"; 993 | } 994 | //End tooltips 995 | if($tooltips == true && $key < ($lenght-1)) { 996 | $return .= ''.$deg[$key+1]['tooltipLegend'].$deg[$key+1]['label'].' : '.$deg[$key+1]['val'].''."\n\t\t".''; 997 | } 998 | } 999 | 1000 | if ($mainLegend) { 1001 | $return .= ' 1002 | '.$mainLegend.''; 1003 | $paddingLegendY += 70; 1004 | } 1005 | if (isset($legends) && !empty($legends) && !isset($notDisplayLegends)) { 1006 | $leg = "\t".''; 1007 | foreach ($legends as $key => $value) { 1008 | $colorToFillWith = ($key == 0 ? $value['stroke'] : $deg[$lenght-$key-1]['stroke']); 1009 | $leg .= "\n\t\t".''; 1010 | $leg .= "\n\t\t".''.$value['label'].''; 1011 | } 1012 | $leg .= "\n\t".''; 1013 | 1014 | $return .= $leg; 1015 | } 1016 | if ($type == 'ring' || isset($subtype)) { 1017 | $return .= ''; 1018 | } 1019 | 1020 | return $return; 1021 | } 1022 | 1023 | /** 1024 | * To draw vertical stock chart 1025 | * @param $data array Array with structure equal to array('index'=> array('open'=>val,'close'=>val,'min'=>val,'max'=>val)) 1026 | * @param $height integer Height of grid 1027 | * @param $HEIGHT integer Height of grid + title + padding top 1028 | * @param $stepX integer Distance between two graduations on x-axis 1029 | * @param $unitY integer Unit of y-axis 1030 | * @param $lenght integer Number of graduations on x-axis 1031 | * @param $min integer Minimum value of data 1032 | * @param $max integer Maximum value of data 1033 | * @param $options array Options 1034 | * @param $i integer index of current data 1035 | * @param $labels array labels of x-axis 1036 | * @param $id integer index of plotLimit 1037 | * @return string Path of lines (with options) 1038 | * 1039 | * @author Cyril MAGUIRE 1040 | */ 1041 | protected function __drawStock($data,$height,$HEIGHT,$stepX,$unitY,$lenght,$min,$max,$options,$i,$labels,$id) { 1042 | $error = null; 1043 | if (!isset($data[$labels[$i]]['open'])) { 1044 | $data[$labels[$i]]['open'] = 0; 1045 | //$error[] = 'open'; 1046 | } 1047 | if (!isset($data[$labels[$i]]['close'])) { 1048 | $data[$labels[$i]]['close'] = 0; 1049 | //$error[] = 'close'; 1050 | } 1051 | if (!isset($data[$labels[$i]]['max'])) { 1052 | $data[$labels[$i]]['max'] = 0; 1053 | //$error[] = 'max'; 1054 | } 1055 | if (!isset($data[$labels[$i]]['min'])) { 1056 | $data[$labels[$i]]['min'] = 0; 1057 | //$error[] = 'min'; 1058 | } 1059 | if ($error) { 1060 | $return = "\t\t".''."\n"; 1061 | $return .= "\t\t".'Error : "'; 1062 | foreach ($error as $key => $value) { 1063 | $return .= $value.(count($error)>1? ' ' : ''); 1064 | } 1065 | $return .= '" missing'."\n"; 1066 | return $return; 1067 | } 1068 | $options = array_merge($this->options,$options); 1069 | 1070 | extract($options); 1071 | 1072 | $return = ''; 1073 | if($data[$labels[$i]]['close'] < $data[$labels[$i]]['open']) { 1074 | $return .= "\n\t".''; 1075 | } 1076 | if($data[$labels[$i]]['close'] == $data[$labels[$i]]['open']) { 1077 | $return .= "\n\t".''; 1078 | } 1079 | //Limit Up 1080 | $return .= "\n\t".''; 1081 | $return .= ''; 1082 | //Limit Down 1083 | $return .= "\n\t".''; 1084 | $return .= ''; 1085 | if($tooltips == true) { 1086 | //Open 1087 | $return .= $this->__circle($i,$stepX,($HEIGHT - $unitY*$data[$labels[$i]]['open']),$data[$labels[$i]]['open'],$stroke); 1088 | //Close 1089 | $return .= $this->__circle($i,$stepX,($HEIGHT - $unitY*$data[$labels[$i]]['close']),$data[$labels[$i]]['close'],$stroke); 1090 | //Max 1091 | $return .= $this->__circle($i,$stepX,($HEIGHT - $unitY*$data[$labels[$i]]['max']),$data[$labels[$i]]['max'],$stroke); 1092 | //Min 1093 | $return .= $this->__circle($i,$stepX,($HEIGHT - $unitY*$data[$labels[$i]]['min']),$data[$labels[$i]]['min'],$stroke); 1094 | } 1095 | return $return; 1096 | } 1097 | 1098 | /** 1099 | * To draw horizontal stock chart 1100 | * @param $data array Array with structure equal to array('index'=> array('open'=>val,'close'=>val,'min'=>val,'max'=>val)) 1101 | * @param $HEIGHT integer Height of grid + title + padding top 1102 | * @param $stepX integer Distance between two graduations on x-axis 1103 | * @param $unitX integer Unit of x-axis 1104 | * @param $unitY integer Unit of y-axis 1105 | * @param $lenght integer Number of graduations on y-axis 1106 | * @param $Xmin integer Minimum value of data 1107 | * @param $Xmax integer Maximum value of data 1108 | * @param $options array Options 1109 | * @param $i integer index of current data 1110 | * @param $labels array labels of y-axis 1111 | * @param $id integer index of plotLimit 1112 | * @return string Path of lines (with options) 1113 | * 1114 | * @author Cyril MAGUIRE 1115 | */ 1116 | protected function __drawHstock($data,$HEIGHT,$stepX,$unitX,$unitY,$lenght,$Xmin,$Xmax,$options,$i,$labels,$id) { 1117 | if($i>0) {$i--;} 1118 | 1119 | $stepY = $HEIGHT - ($unitY*($i+1)); 1120 | 1121 | $error = null; 1122 | if (!isset($data[$labels[$i]]['open'])) { 1123 | $error[] = 'open'; 1124 | } 1125 | if (!isset($data[$labels[$i]]['close'])) { 1126 | $error[] = 'close'; 1127 | } 1128 | if (!isset($data[$labels[$i]]['max'])) { 1129 | $error[] = 'max'; 1130 | } 1131 | if (!isset($data[$labels[$i]]['min'])) { 1132 | $error[] = 'min'; 1133 | } 1134 | if ($error) { 1135 | $return = "\t\t".''."\n"; 1136 | $return .= "\t\t".'Error : "'; 1137 | foreach ($error as $key => $value) { 1138 | $return .= $value.(count($error)>1? ' ' : ''); 1139 | } 1140 | $return .= '" missing'."\n"; 1141 | return $return; 1142 | } 1143 | $options = array_merge($this->options,$options); 1144 | 1145 | extract($options); 1146 | 1147 | $return = ''; 1148 | if($data[$labels[$i]]['close'] > $data[$labels[$i]]['open']) { 1149 | $return .= "\n\t".''; 1150 | } 1151 | if($data[$labels[$i]]['close'] == $data[$labels[$i]]['open']) { 1152 | $return .= "\n\t".''; 1153 | } 1154 | // //Limit Up 1155 | $return .= "\n\t".''; 1156 | $return .= ''; 1157 | // //Limit Down 1158 | $return .= "\n\t".''; 1159 | $return .= ''; 1160 | if($tooltips == true) { 1161 | //Open 1162 | $return .= $this->__circle($unitX,$data[$labels[$i]]['open'],$stepY,$data[$labels[$i]]['open'],$stroke); 1163 | //Close 1164 | $return .= $this->__circle($unitX,$data[$labels[$i]]['close'],$stepY,$data[$labels[$i]]['close'],$stroke); 1165 | //Max 1166 | $return .= $this->__circle($unitX,$data[$labels[$i]]['max'],$stepY,$data[$labels[$i]]['max'],$stroke); 1167 | //Min 1168 | $return .= $this->__circle($unitX,$data[$labels[$i]]['min'],$stepY,$data[$labels[$i]]['min'],$stroke); 1169 | } 1170 | return $return; 1171 | } 1172 | 1173 | /** 1174 | * To add circles on histogram 1175 | * @param $unitX integer index of current data 1176 | * @param $cx integer Distance between two graduations on x-axis 1177 | * @param $cy integer Distance between two graduations on y-axis 1178 | * @param $label string label of tooltip 1179 | * @param $stroke string color of circle 1180 | * @return string path of circle 1181 | * 1182 | * @author Cyril MAGUIRE 1183 | */ 1184 | protected function __circle($unitX,$cx,$cy,$label,$stroke) { 1185 | $return = "\n\t\t".''; 1186 | $return .= "\n\t\t\t".''; 1187 | $return .= "\n\t".''.$label.''."\n\t\t".''; 1188 | return $return; 1189 | } 1190 | 1191 | /** 1192 | * To research min and max values of data depends on type of graph 1193 | * @param $data array data 1194 | * @param $type string line, bar, pie, ring, stock or h-stock 1195 | * @return array of variables needed for draw method 1196 | * 1197 | * @author Cyril MAGUIRE 1198 | */ 1199 | protected function __minMax($data,$type) { 1200 | $arrayOfMin = $arrayOfMax = $arrayOfLenght = $labels = $tmp['type'] = array(); 1201 | $valuesMax = $valuesMin = ''; 1202 | $Xmin = $Xmax = null; 1203 | $multi = false; 1204 | //For each diagrams with several lines/histograms 1205 | foreach ($data as $line => $datas) { 1206 | if ($type == 'stock' || (is_array($type) && in_array('stock',$type))|| $type == 'h-stock' || (is_array($type) && in_array('h-stock',$type)) ) { 1207 | $arrayOfMin[] = isset($datas['min']) ? floor($datas['min']):0; 1208 | $arrayOfMax[] = isset($datas['max']) ? ceil($datas['max']) : 0; 1209 | $arrayOfLenght[] = count($data); 1210 | $labels = array_merge(array_keys($data),$labels); 1211 | if (is_string($type)) { 1212 | $tmp['type'][$line] = $type; 1213 | } 1214 | $multi = true; 1215 | } else { 1216 | if (is_array($datas)) { 1217 | $valuesMax = array_map('ceil', $datas); 1218 | $valuesMin = array_map('ceil', $datas); 1219 | $arrayOfMin[] = min($valuesMin); 1220 | $arrayOfMax[] = max($valuesMax); 1221 | $arrayOfLenght[] = count($datas); 1222 | $labels = array_merge(array_keys($datas),$labels); 1223 | if (is_string($type)) { 1224 | $tmp['type'][] = $type; 1225 | } 1226 | $multi = true; 1227 | } else { 1228 | $multi = false; 1229 | } 1230 | } 1231 | } 1232 | 1233 | if ($multi == true) { 1234 | if (!empty($tmp['type'])) { 1235 | $type = $tmp['type']; 1236 | } 1237 | unset($tmp); 1238 | 1239 | $labels = array_unique($labels); 1240 | 1241 | if ($type == 'h-stock' || (is_array($type) && in_array('h-stock',$type)) ) { 1242 | $min = 0; 1243 | $max = count($labels); 1244 | $Xmax = max($arrayOfMax); 1245 | $Xmin = min($arrayOfMin); 1246 | $lenght = $Xmax - $Xmin; 1247 | } else { 1248 | $min = min($arrayOfMin); 1249 | $max = max($arrayOfMax); 1250 | $lenght = max($arrayOfLenght); 1251 | } 1252 | if ($type == 'stock' || (is_array($type) && in_array('stock',$type)) ) { 1253 | array_unshift($labels,''); 1254 | $labels[] = ''; 1255 | $lenght += 2; 1256 | } 1257 | } else { 1258 | $labels = array_keys($data); 1259 | $lenght = count($data); 1260 | $min = min($data); 1261 | $max = max($data); 1262 | } 1263 | return array('min'=>$min, 'max'=>$max, 'lenght'=>$lenght, 'labels'=>$labels, 'multi'=>$multi, 'valuesMax'=>$valuesMax, 'valuesMin'=>$valuesMin, 'Xmin'=>$Xmin, 'Xmax'=>$Xmax, 'type' => $type); 1264 | } 1265 | 1266 | /** 1267 | * Calcul of variables needed for x-axis configuration 1268 | * @param $type string type of graph 1269 | * @param $width integer width of grid 1270 | * @param $max integer max of values in data 1271 | * @param $Xmax integer max of values in x-axis 1272 | * @param $Xmin integer min of values in x-axis 1273 | * @param $lenght integer distance between min and max values 1274 | * @param $options array options 1275 | * @return array of variables needed for draw method 1276 | * 1277 | * @author Cyril MAGUIRE 1278 | */ 1279 | protected function __xAxisConfig($type,$width,$max,$Xmax,$Xmin,$lenght,$options=false) { 1280 | $XM = $stepX = $unitX = null; 1281 | if ($type == 'h-stock' || (is_array($type) && in_array('h-stock',$type)) ) { 1282 | 1283 | $l = strlen(abs($Xmax))-1; 1284 | if ($l == 0) { 1285 | $l = 1; 1286 | $XM = ceil($Xmax); # Max value to display in x axis 1287 | $stepX = 1; 1288 | $M = $lenght+1; # temporary max 1289 | $steps = 1; 1290 | if($XM == 0) {$XM = 1;} 1291 | $unitX = $width/$XM; 1292 | $widthViewBox = $width+$XM+50; 1293 | } else { 1294 | $XM = ceil($Xmax/($l*10))*($l*10); 1295 | $stepX = $l*10; 1296 | $M = $lenght+1; 1297 | $steps = 1; 1298 | if ($Xmin>0 || ($Xmin<0 && $Xmax<0)) { 1299 | $Xmin = 0; 1300 | } 1301 | if($XM == 0) {$XM = 1;} 1302 | $unitX = ($width/$XM); 1303 | $widthViewBox = $width + ($XM/$stepX)*$unitX; 1304 | } 1305 | } else { 1306 | 1307 | $l = strlen(abs($max))-1; 1308 | if ($l == 0) { 1309 | $l = 1; 1310 | $M = ceil($max); 1311 | $steps = 1; 1312 | }else { 1313 | $M = ceil($max/($l*10))*($l*10); 1314 | $steps = $l*10; 1315 | } 1316 | 1317 | $max = $M; 1318 | if (isset($options['steps']) && is_int($steps)) { 1319 | $steps = $options['steps']; 1320 | } 1321 | 1322 | $stepX = $width / ($lenght - 1); 1323 | $widthViewBox = $lenght*$stepX+$stepX; 1324 | } 1325 | return array('XM'=>$XM,'stepX'=>$stepX,'steps'=>$steps,'unitX'=>$unitX,'widthViewBox'=>$widthViewBox,'Xmin'=>$Xmin); 1326 | } 1327 | 1328 | /** 1329 | * To draw x-axis of the grid 1330 | * @param $type string type of graph 1331 | * @param $Xmin integer min of values in x-axis 1332 | * @param $Xmax integer max of values in x-axis 1333 | * @param $XM integer Max value to display in x axis 1334 | * @param $stepX integer Distance between two graduations on x-axis 1335 | * @param $unitX integer index of current data 1336 | * @param $HEIGHT integer height of the entire svg tag 1337 | * @param $paddingTop integer padding on top 1338 | * @param $titleHeight integer height of title 1339 | * @param $labels array Array of labels 1340 | * @param $lenght integer distance between min and max values 1341 | * @param $transform integer, rotation of text of legend 1342 | * @return array of variables needed for draw method 1343 | * 1344 | * @author Cyril MAGUIRE 1345 | */ 1346 | protected function __XAxisDef($type,$Xmin,$Xmax,$XM,$stepX,$unitX,$HEIGHT,$paddingTop,$titleHeight,$labels,$lenght,$transform) { 1347 | $gridV = $x = ''; 1348 | $x .= "\t".''."\n"; 1349 | if (is_array($type) && in_array('h-stock', $type) ) { 1350 | for ($i=$Xmin; $i <= $XM; $i+=$stepX) { 1351 | //1 graduation every $steps units 1352 | $step = $unitX*$i; 1353 | 1354 | $x .= "\t\t".''.$i.''."\n"; 1355 | //Vertical grid 1356 | if ($i != $Xmax) { 1357 | $gridV .= "\t\t".''."\n" ; 1358 | } 1359 | } 1360 | } else { 1361 | $i=0; 1362 | foreach ($labels as $key => $label) { 1363 | //We add a gap of 50 units 1364 | $x .= "\t\t".''.$label.''."\n"; 1365 | //Vertical grid 1366 | if ($i != 0 && $i != $lenght) { 1367 | $gridV .= "\t\t".''."\n" ; 1368 | } 1369 | $i++; 1370 | } 1371 | } 1372 | $x .= "\t".''."\n"; 1373 | return array('x'=>$x, 'gridV'=>$gridV); 1374 | } 1375 | 1376 | /** 1377 | * To draw y-axis of the grid 1378 | * @param $type string type of graph 1379 | * @param $width integer width of grid 1380 | * @param $min integer min of values in data 1381 | * @param $max integer max of values in data 1382 | * @param $steps integer Distance between two graduations 1383 | * @param $HEIGHT integer height of the entire svg tag 1384 | * @param $titleHeight integer height of title 1385 | * @param $paddingTop integer padding on top 1386 | * @param $paddingLegendX integer padding between legend and x axis 1387 | * @param $unitY integer unit of y graduations 1388 | * @param $labels array Array of labels 1389 | * @return array of variables needed for draw method 1390 | * 1391 | * @author Cyril MAGUIRE 1392 | */ 1393 | protected function __YAxisDef($type,$width,$min,$max,$steps,$HEIGHT,$titleHeight,$paddingTop,$paddingLegendX,$unitY,$labels) { 1394 | $gridH = $y = ''; 1395 | $y .= "\t".''."\n"; 1396 | if ($min>0 || ($min<0 && $max<0)) { 1397 | $min = 0; 1398 | } 1399 | for ($i=$min; $i <= ($max+$steps); $i+=$steps) { 1400 | //1 graduation every $steps units 1401 | if ($min<0) { 1402 | $stepY = round($HEIGHT + $unitY*($min-$i),PHP_ROUND_HALF_UP)+$paddingTop; 1403 | } else { 1404 | $stepY = round($HEIGHT - ($unitY*$i),PHP_ROUND_HALF_UP)+$paddingTop; 1405 | } 1406 | 1407 | if ($stepY >= $min) { 1408 | if (is_array($type) && in_array('h-stock', $type) && isset($labels[$i-1])) { 1409 | $y .= "\t\t".''.($i > 0 ? (strlen($labels[$i-1]) > 3 ? substr($labels[$i-1],0,3).'.'.$labels[$i-1].'' : $labels[$i-1].'') : '')."\n"; 1410 | } else { 1411 | $y .= "\t\t".''.$i.''; 1412 | } 1413 | //Horizontal grid 1414 | $gridH .= "\t\t".''."\n" ; 1415 | } 1416 | } 1417 | $y .= "\t".''."\n"; 1418 | return array('y'=>$y,'gridH'=>$gridH); 1419 | } 1420 | 1421 | /** 1422 | * To draw legends under the grid 1423 | * @param $legends array Array of legends 1424 | * @param $type string type of graph 1425 | * @param $stroke string color of legends 1426 | * @param $HEIGHT integer height of the entire svg tag 1427 | * @param $paddingTop integer padding on top 1428 | * @return string path of legends 1429 | * 1430 | * @author Cyril MAGUIRE 1431 | */ 1432 | protected function __legendsDef($legends,$type,$stroke,$HEIGHT,$paddingTop,$marginTop=0) { 1433 | if (isset($legends) && !empty($legends)) { 1434 | $leg = "\n\t".''; 1435 | if (!is_array($legends)) { 1436 | $legends = array(0 => $legends); 1437 | } 1438 | 1439 | foreach ($legends as $key => $value) { 1440 | if (is_array($type) && isset($type[$key]) && $type[$key] != 'pie' && $type[$key] != 'ring') { 1441 | if (is_array($stroke) && isset($stroke[$key])) { 1442 | $leg .= "\n\t\t".''; 1443 | } else { 1444 | $leg .= "\n\t\t".''; 1445 | } 1446 | $leg .= "\n\t\t".''.$value.''; 1447 | } 1448 | if (!is_array($type) && $type != 'pie' && $type != 'ring') { 1449 | if (is_array($stroke) && isset($stroke[$key])) { 1450 | $leg .= "\n\t\t".''; 1451 | } else { 1452 | $leg .= "\n\t\t".''; 1453 | } 1454 | $leg .= "\n\t\t".''.$value.''; 1455 | } 1456 | if (is_array($type) && (in_array('stock', $type) || in_array('h-stock', $type))) { 1457 | if (is_array($stroke)) { 1458 | $stroke = array_values($stroke); 1459 | if(isset($stroke[$key+1])) { 1460 | $leg .= "\n\t\t".''; 1461 | } 1462 | } 1463 | $leg .= "\n\t\t".''.$value.''; 1464 | } 1465 | } 1466 | $leg .= "\n\t".''; 1467 | 1468 | } else { 1469 | $leg = ''; 1470 | } 1471 | return $leg; 1472 | } 1473 | 1474 | /** 1475 | * To generate hexadecimal code for color 1476 | * @param null 1477 | * @return string hexadecimal code 1478 | * 1479 | * @author Cyril MAGUIRE 1480 | */ 1481 | protected function __genColor() { 1482 | $val = array("0","1","2","3","4","5","6","7","8","9","A","B","C","D","E","F"); 1483 | shuffle($val); 1484 | $rand = array_rand($val,6); 1485 | $hexa = ''; 1486 | foreach ($rand as $key => $keyOfVal) { 1487 | $hexa .= $val[$keyOfVal]; 1488 | } 1489 | if ('#'.$hexa == $this->options['background']) { 1490 | return $this->__genColor(); 1491 | } 1492 | if (!in_array($hexa, $this->colors)) { 1493 | $this->colors[] = $hexa; 1494 | return '#'.$hexa; 1495 | } else { 1496 | return $this->__genColor(); 1497 | } 1498 | } 1499 | 1500 | protected function __stockDef() { 1501 | $return = "\n\t".''; 1502 | $return .= "\n\t\t".''; 1503 | $return .= "\n\t\t\t".''; 1504 | $return .= "\n\t\t".''; 1505 | $return .= "\n\t".''."\n"; 1506 | return $return; 1507 | } 1508 | 1509 | protected function __hstockDef() { 1510 | $return = "\n\t".''; 1511 | $return .= "\n\t\t".''; 1512 | $return .= "\n\t\t\t".''; 1513 | $return .= "\n\t\t".''; 1514 | $return .= "\n\t".''."\n"; 1515 | return $return; 1516 | } 1517 | 1518 | protected function __gradientDef($gradient,$id) { 1519 | $return ="\n\t".''; 1520 | $return .= "\n\t\t".''; 1521 | $return .= "\n\t\t\t".''; 1522 | $return .= "\n\t\t\t".''; 1523 | $return .= "\n\t\t".''; 1524 | $return .= "\n\t".''."\n"; 1525 | return $return; 1526 | } 1527 | 1528 | protected function __header($dimensions=array('width'=>'100%','height'=>'100%','widthViewBox'=>685,'heightViewBox'=>420), $responsive=true,$id=false) { 1529 | if ($responsive == true) { 1530 | $return = "\n".''."\n"; 1531 | } else { 1532 | $return = "\n".''."\n"; 1533 | } 1534 | $return .= ' 1535 | '."\n".''."\n"; 1538 | return $return; 1539 | } 1540 | 1541 | protected function __svgGrid($gradient,$width,$height,$yHeight) { 1542 | $return = ''; 1543 | $background = '#ffffff'; 1544 | if (is_array($gradient) && count($gradient) == 2) { 1545 | $id = 'BackgroundGradient'.rand(); 1546 | $return .= $this->__gradientDef($gradient,$id); 1547 | $background = 'url(#'.$id.')'; 1548 | } 1549 | //Grid is beginning at 50 units from the left 1550 | return $return .= "\t".''."\n"; 1551 | } 1552 | 1553 | protected function __titleDef($title,$width,$titleHeight) { 1554 | $return = "\t".''.$title.''."\n"; 1555 | $return .= "\t".''.$title.''."\n"; 1556 | return $return; 1557 | } 1558 | 1559 | protected function __headerDimensions($widthViewBox,$HEIGHT,$heightLegends,$titleHeight,$paddingTop,$paddingLegendX,$lenght,$stepX) { 1560 | return array( 1561 | 'widthViewBox' => $widthViewBox, 1562 | 'heightViewBox' => $HEIGHT+$heightLegends+$titleHeight+2*$paddingTop+$paddingLegendX, 1563 | 'width' => $lenght*$stepX+$stepX, 1564 | 'height' => $HEIGHT+$heightLegends+$titleHeight+2*$paddingTop, 1565 | ); 1566 | } 1567 | 1568 | protected function __c($coordonnees,$stroke) { 1569 | return "\n\t\t\t".''; 1570 | } 1571 | 1572 | /** 1573 | * Méthode permettant de trier un tableau multidimensionnel sur un ou deux index 1574 | * @param $array array le tableau à trier 1575 | * @param $keys mixed (array ou string) l'index ou le tableau des deux index sur le(s)quel(s) va(vont) se faire le tri 1576 | * 1577 | * @return array 1578 | * 1579 | * @author Cyril MAGUIRE 1580 | */ 1581 | public function arraySort(&$array,$keys) { 1582 | if (!is_array($keys)) $keys = array(0=>$keys); 1583 | $c = count($keys); 1584 | $cmp = function ($a, $b) use ($keys,$c) { 1585 | $i = 0; 1586 | if ($c>1){ 1587 | if (strcasecmp($a[$keys[$i]], $b[$keys[$i]]) == 0){ 1588 | if (isset($keys[$i+1]) && isset($a[$keys[$i+1]])){ 1589 | return strcasecmp($a[$keys[$i+1]], $b[$keys[$i+1]]); 1590 | } else { 1591 | return strcasecmp($a[$keys[$c-1]], $b[$keys[$c-1]]); 1592 | } 1593 | } else { 1594 | return strcasecmp($a[$keys[$i]], $b[$keys[$i]]); 1595 | } 1596 | } else { 1597 | return strcasecmp($a[$keys[0]], $b[$keys[0]]); 1598 | } 1599 | }; 1600 | return usort($array,$cmp); 1601 | } 1602 | 1603 | /** 1604 | * Transform svg file into vml file for internet explorer 1605 | * 1606 | * @param $svg string svg to transform 1607 | * @param $vml string path to vml file 1608 | * @param $root string path of root of app 1609 | * @param $url string url of site 1610 | * @return vml string 1611 | * 1612 | * @author Cyril MAGUIRE 1613 | */ 1614 | public function svg2vml($svg,$vml,$root,$xsl='vendors/svg2vml/svg2vml.xsl',$xslpath='/svg2vml/') { 1615 | if(is_string($svg)){ 1616 | $xsl = str_replace('include href="XSL2', 'include href="'.$xslpath.'XSL2', file_get_contents($xsl)); 1617 | # for $xsl, see http://vectorconverter.sourceforge.net/index.html 1618 | $xml_contents=$svg; 1619 | $from="/(]*[^\/]?)>/i"; 1620 | $xml_contents=preg_replace($from,"$1/>",$xml_contents); 1621 | $from="/\/(\/>)/i"; 1622 | $xml_contents=preg_replace($from,"$1",$xml_contents); 1623 | $xml_contents=preg_replace("/<\!DOCTYPE[^>]+\>/i","",$xml_contents); 1624 | $xml_contents=preg_replace("/<\?xml-stylesheet[^>]+\>/i","",$xml_contents); 1625 | $xml_contents=preg_replace("/(\r\n|\n|\r)/s", '', $xml_contents); 1626 | $xml_contents=str_replace(array("\r\n","\n","\r",CHR(10),CHR(13)), '', trim($xml_contents)); 1627 | $xml_contents=preg_replace("/\(\s*)\(\s*)\<\/defs\>/", "", $xml_contents); 1628 | 1629 | $xh=xslt_create(); 1630 | if ($xh === false) {return false;} 1631 | xslt_set_base($xh,$this->SIG_ROOT); 1632 | $arguments=array('/_xml' =>$xml_contents,'/_xsl' => $xsl); 1633 | $result=xslt_process($xh, 'arg:/_xml', 'arg:/_xsl', NULL, $arguments); 1634 | xslt_free($xh); 1635 | if ($result !== false) { 1636 | $result = str_replace(''."\n", '', $result); 1637 | $result = str_replace('><',">\n<",$result); 1638 | file_put_contents($root.$vml, $result); 1639 | $output = "
"; 1640 | $output .= "
\n"; 1641 | $output = $this->wmodeTransparent($output); 1642 | return $output; 1643 | } else { 1644 | if ($this->DEBUG == 1) { 1645 | libxml_use_internal_errors(true); 1646 | echo '
'; print_r(libxml_get_last_error());print_r(libxml_get_errors());echo('
'); 1647 | } else { 1648 | return false; 1649 | } 1650 | } 1651 | } else{ 1652 | return $this->L_ERROR_FILE_NOT_FOUND; 1653 | } 1654 | } 1655 | 1656 | /** 1657 | * Méthode pour prendre en compte le mode transparent des iframes 1658 | * 1659 | * @parm html chaine de caractères à scanner 1660 | * @return string chaine de caractères modifiée 1661 | * @author Stephane F 1662 | **/ 1663 | public function wmodeTransparent($html) { 1664 | 1665 | if(strpos($html, " $file) { 1692 | unlink($file); 1693 | } 1694 | // Then, we record only one file 1695 | file_put_contents($outputDir.$outputName.'.svg', $svg); 1696 | } 1697 | 1698 | # Work in progress...... 1699 | public function svgToPng($svg,$outputName='svg',$outputDir='data/img/',$width=800,$height=600) { 1700 | // exit(); 1701 | exec("convert -version", $out);//On teste la présence d'imagick sur le serveur 1702 | if (!empty($out) && class_exists('Imagick')) { 1703 | $im = new Imagick(); 1704 | $imagick->setBackgroundColor(new ImagickPixel('transparent')); 1705 | $im->readImageBlob($svg); 1706 | /*png settings*/ 1707 | $im->setImageFormat("png24"); 1708 | $im->resizeImage($width, $height, imagick::FILTER_LANCZOS, 1); /*Optional, if you need to resize*/ 1709 | 1710 | /*jpeg*/ 1711 | $im->setImageFormat("jpeg"); 1712 | $im->adaptiveResizeImage($width, $height); /*Optional, if you need to resize*/ 1713 | 1714 | $im->writeImage($this->SIG_ROOT.$outputDir.$outputName.'.png'); 1715 | $im->writeImage($this->SIG_ROOT.$outputDir.$outputName.'.jpg'); 1716 | $im->clear(); 1717 | $im->destroy(); 1718 | echo ''.$outputName.'.png'; 1719 | } else { 1720 | $return = array(); 1721 | exec(escapeshellcmd('python '.$this->SIG_CORE.'vendors/convertPython/svgtopng --'.$width.' --'.$height.' --o '.$this->SIG_ROOT.$outputDir.$outputName.'.png '.$svg)); 1722 | } 1723 | } 1724 | } 1725 | ?> 1726 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "didungar/php-graph", 3 | "type": "library", 4 | "description": "PHP Graph (from: https://github.com/jerrywham/phpGraph)", 5 | "keywords": [ 6 | "graph", 7 | "php", 8 | "svg" 9 | ], 10 | "homepage": "https://github.com/didungar/phpGraph", 11 | "license": "libre", 12 | "autoload": { 13 | "psr-4": { 14 | "DidUngar\\": "src/" 15 | } 16 | }, 17 | "config": { 18 | "bin-dir": "bin" 19 | }, 20 | "authors": [ 21 | { 22 | "name": "jerrywham", 23 | "homepage": "https://github.com/jerrywham/phpGraph" 24 | }, 25 | { 26 | "name": "didungar", 27 | "homepage": "https://github.com/didungar/phpGraph" 28 | } 29 | ] 30 | } 31 | -------------------------------------------------------------------------------- /samples.php: -------------------------------------------------------------------------------- 1 | [ 32 | "0" => 2000, 33 | "1" => 10, 34 | ], 35 | 36 | "1" => [ 37 | "0" => 2002, 38 | "1" => 39, 39 | ], 40 | 41 | "2" => [ 42 | "0" => 2003, 43 | "1" => 47, 44 | ], 45 | 46 | "3" => [ 47 | "0" => 2004, 48 | "1" => 53, 49 | ], 50 | 51 | "4" => [ 52 | "0" => 2005, 53 | "1" => 46, 54 | ], 55 | 56 | "5" => [ 57 | "0" => 2006, 58 | "1" => 10, 59 | ], 60 | 61 | "6" => [ 62 | "0" => 2007, 63 | "1" => 98, 64 | ], 65 | 66 | "7" => [ 67 | "0" => 2008, 68 | "1" => -20, 69 | ], 70 | 71 | "8" => [ 72 | "0" => 2009, 73 | "1" => 16, 74 | ], 75 | 76 | "9" => [ 77 | "0" => 2010, 78 | "1" => 16, 79 | ], 80 | 81 | "10" => [ 82 | "0" => 2011, 83 | "1" => 12, 84 | ], 85 | 86 | "11" => [ 87 | "0" => 2012, 88 | "1" => 12, 89 | ], 90 | 91 | "12" => [ 92 | "0" => 2013, 93 | "1" => 2, 94 | ], 95 | 96 | ]; 97 | //We transforme multidimensionnal array to unidimensionnal array 98 | $dataFirst = []; 99 | foreach ($flot as $key => $value) { 100 | $dataFirst[ $value[0] ] = $value[1]; 101 | } 102 | 103 | //An other array 104 | $data = [ 105 | "0" => [ 106 | "2000" => 0, 107 | "2002" => 25, 108 | "2003" => 32, 109 | "2004" => 1, 110 | "2005" => 58, 111 | "2006" => 31, 112 | "2007" => 79, 113 | "2008" => 51, 114 | "2009" => 54, 115 | "2010" => 12, 116 | "2011" => 17, 117 | "2012" => 14, 118 | "2013" => 13, 119 | ], 120 | "1" => [ 121 | "2000" => 0, 122 | "2002" => 0, 123 | "2003" => 0, 124 | "2004" => 20, 125 | "2005" => 0, 126 | "2006" => 40, 127 | "2007" => 50, 128 | "2008" => 0, 129 | "2009" => 60, 130 | "2010" => 0, 131 | "2011" => 0, 132 | "2012" => 0, 133 | "2013" => 0, 134 | ], 135 | "2" => [ 136 | "2000" => 0, 137 | "2002" => -20, 138 | "2003" => -30, 139 | "2004" => 65, 140 | "2005" => 0, 141 | "2006" => 10, 142 | "2007" => 10, 143 | "2008" => 18, 144 | "2009" => 39, 145 | "2010" => 0, 146 | "2011" => 23, 147 | "2012" => 36, 148 | "2013" => 54, 149 | ], 150 | "3" => [ 151 | "2001" => 0, 152 | "2002" => 10, 153 | "2003" => 3, 154 | "2004" => 1, 155 | "2005" => 5, 156 | "2006" => 2, 157 | "2007" => 3, 158 | "2008" => 3, 159 | "2009" => -5, 160 | "2010" => 8, 161 | "2011" => 9, 162 | "2012" => 5, 163 | "2013" => 20, 164 | ], 165 | "4" => [ 166 | "2000" => 0, 167 | "2002" => 0, 168 | "2003" => 0, 169 | "2004" => 0, 170 | "2005" => 0, 171 | "2006" => 0, 172 | "2007" => 46, 173 | "2008" => 10, 174 | "2009" => 7, 175 | "2010" => 4, 176 | "2011" => 5, 177 | "2012" => 6, 178 | "2013" => 0, 179 | ], 180 | ]; 181 | $d = [ 182 | "2000" => -7, 183 | "2001" => 15, 184 | "2002" => 39, 185 | "2003" => 26, 186 | "2004" => 36, 187 | "2005" => 18, 188 | "2006" => 32, 189 | "2007" => 56, 190 | "2008" => 38, 191 | "2009" => 103, 192 | "2010" => 105, 193 | "2011" => 126, 194 | "2012" => 125, 195 | "2013" => 76, 196 | ]; 197 | //Be carefull, for stock graph, array structure must be the same as the array below 198 | $stock = [ 199 | 'Jan' => [ 200 | 'open' => 35, 201 | 'close' => 20, 202 | 'min' => 10, 203 | 'max' => 37, 204 | ], 205 | 'Feb' => [ 206 | 'open' => 28, 207 | 'close' => 17, 208 | 'min' => 11, 209 | 'max' => 32, 210 | ], 211 | 'Mar' => [ 212 | 'open' => 17, 213 | 'close' => 25, 214 | 'min' => 14, 215 | 'max' => 33, 216 | ], 217 | 'Apr' => [ 218 | 'open' => 27, 219 | 'close' => 20, 220 | 'min' => 11, 221 | 'max' => 29, 222 | ], 223 | 'May' => [ 224 | 'open' => 12, 225 | 'close' => 25, 226 | 'min' => 9, 227 | 'max' => 29, 228 | ], 229 | 'Jun' => [ 230 | 'open' => 12, 231 | 'close' => 23, 232 | 'min' => 4, 233 | 'max' => 25, 234 | ], 235 | 'Jul' => [ 236 | 'open' => 20, 237 | 'close' => 16, 238 | 'min' => 3, 239 | 'max' => 22, 240 | ], 241 | 'Aug' => [ 242 | 'open' => 15, 243 | 'close' => 29, 244 | 'min' => 7, 245 | 'max' => 34, 246 | ], 247 | 'Sep' => [ 248 | 'open' => 20, 249 | 'close' => 26, 250 | 'min' => 9, 251 | 'max' => 29, 252 | ], 253 | 'Oct' => [ 254 | 'open' => 28, 255 | 'close' => 17, 256 | 'min' => 5, 257 | 'max' => 31, 258 | ], 259 | 'Nov' => [ 260 | 'open' => 15, 261 | 'close' => 29, 262 | 'min' => 8, 263 | 'max' => 37, 264 | ], 265 | 'Dec' => [ 266 | 'open' => 12, 267 | 'close' => 60, 268 | 'min' => 10, 269 | 'max' => 67, 270 | ], 271 | ]; 272 | $stock2 = [ 273 | "Série 1" => [ 274 | 'open' => 34, 275 | 'close' => 42, 276 | 'min' => 27, 277 | 'max' => 45, 278 | ], 279 | "Série 2" => [ 280 | 'open' => 55, 281 | 'close' => 25, 282 | 'min' => 14, 283 | 'max' => 59, 284 | ], 285 | "Série 3" => [ 286 | 'open' => 15, 287 | 'close' => 40, 288 | 'min' => 12, 289 | 'max' => 47, 290 | ], 291 | "Série 4" => [ 292 | 'open' => 62, 293 | 'close' => 38, 294 | 'min' => 25, 295 | 'max' => 65, 296 | ], 297 | "Série 5" => [ 298 | 'open' => 38, 299 | 'close' => 49, 300 | 'min' => 32, 301 | 'max' => 64, 302 | ], 303 | "Série 6" => [ 304 | 'open' => 40, 305 | 'close' => 40, 306 | 'min' => 32, 307 | 'max' => 48, 308 | ], 309 | ]; 310 | $stock3 = [ 311 | "aplasie" => [ 312 | 'open' => 1.04, 313 | 'close' => 1.04, 314 | 'min' => 0.87, 315 | 'max' => 1.24, 316 | ], 317 | "thrombopénie" => [ 318 | 'open' => 1.09, 319 | 'close' => 1.09, 320 | 'min' => 0.95, 321 | 'max' => 1.25, 322 | ], 323 | "anorexie" => [ 324 | 'open' => 1.02, 325 | 'close' => 1.02, 326 | 'min' => 0.86, 327 | 'max' => 1.21, 328 | ], 329 | "mucites" => [ 330 | 'open' => 0.87, 331 | 'close' => 0.87, 332 | 'min' => 0.71, 333 | 'max' => 1.06, 334 | ], 335 | "leucopénie" => [ 336 | 'open' => 0.90, 337 | 'close' => 0.90, 338 | 'min' => 0.1, 339 | 'max' => 1.34, 340 | ], 341 | "neutropénie" => [ 342 | 'open' => 1, 343 | 'close' => 1, 344 | 'min' => 0.78, 345 | 'max' => 1.20, 346 | ], 347 | ]; 348 | //All options available 349 | $options = [ 350 | 'width' => null,// (int) width of grid 351 | 'height' => null,// (int) height of grid 352 | 'paddingTop' => 10,// (int) 353 | 'type' => 'line',// (string) line, bar, pie or ring 354 | 'steps' => 5,// (int) 2 graduations on y-axis are separated by $steps units 355 | 'filled' => true,// (bool) to fill lines/histograms/disks 356 | 'tooltips' => false,// (bool) to show tooltips 357 | 'circles' => true,// (bool) to show circles on graph (lines or histograms) 358 | 'stroke' => '#3cc5f1',// (string) color of lines by default. Use an array to personalize each line 359 | 'background' => "#ffffff",// (string) color of grid background. Don't use short notation (#fff) because of $this->__genColor(); 360 | 'gradient' => null,// (array) 2 colors from left to right 361 | 'titleHeight' => 0,// (int) Height of main title 362 | 'tooltipLegend' => '',// (string or array) Text display in tooltip with y value. Each text can be personalized using an array. 363 | 'legends' => '',// (string or array) General legend for each line/histogram/disk displaying under diagram 364 | 'title' => null,// (string) Main title. Title wil be displaying in a tooltip too. 365 | 'radius' => 100,// (int) Radius of pie 366 | 'diskLegends' => false,// (bool) to display legends around a pie 367 | 'diskLegendsType' => 'label',// (string) "data", "pourcent" or "label" to display around a pie as legend 368 | ]; 369 | 370 | //We call an instance of phpGraph() class 371 | $G = new phpGraph(); 372 | ?> 373 | 374 | 375 | 376 | 377 | 378 | phpGraph 379 | 380 | 381 | 382 |
383 | draw($data[0], [ 389 | 'type' => 'curve', 390 | 'tooltips' => true, 391 | ] 392 | ); 393 | echo '

Multi lines with histogram and pie

'; 394 | 395 | echo $G->draw($data, [ 396 | 'steps' => 50, 397 | 'filled' => false, 398 | 'tooltips' => true, 399 | 'diskLegends' => true, 400 | 'diskLegendsType' => 'label', 401 | 'type' => [ 402 | '2' => 'bar', 403 | '3' => 'pie', 404 | '4' => 'ring', 405 | ], 406 | 'stroke' => [ 407 | '0' => 'red', 408 | '1' => 'blue', 409 | '2' => 'orange', 410 | '3' => 'green', 411 | '4' => 'deeppink', 412 | ], 413 | 'legends' => [ 414 | '0' => 'Serie 1', 415 | '1' => 'Serie 2', 416 | '2' => 'Serie 3', 417 | '3' => 'Serie 4', 418 | '4' => 'Serie 5', 419 | ], 420 | 'tooltipLegend' => [ 421 | '0' => 'Sample of legend : ', 422 | '1' => 'Sample of legend : ', 423 | '2' => 'Sample of legend : ', 424 | '3' => 'Sample of legend : ', 425 | '4' => 'Sample of legend : ', 426 | ], 427 | 'title' => 'Amazing phpGraph', 428 | ] 429 | ); 430 | echo '

Multi lines filled with no legend nor tooltip. Gradient as background

'; 431 | 432 | echo $G->draw($data, [ 433 | //'steps' => 50, 434 | 'filled' => true, 435 | 'circles' => false, 436 | 'gradient' => ['green', 'yellow'], 437 | ] 438 | ); 439 | 440 | echo '

Histogram

'; 441 | 442 | echo $G->draw($dataFirst, [ 443 | 'filled' => true, 444 | 'type' => 'bar', 445 | 'tooltips' => true, 446 | 'legends' => 'Visits by year', 447 | 'tooltipLegend' => 'Total : ', 448 | 'title' => '', 449 | 'width' => 900, 450 | 'height' => 900, 451 | ]); 452 | 453 | echo '

Same data as a pie

'; 454 | 455 | echo $G->draw($dataFirst, [ 456 | 'type' => 'pie', 457 | 'title' => 'A beautifull pie with phpGraph', 458 | 'tooltips' => true, 459 | 'tooltipLegend' => 'Happy users : ', 460 | 'stroke' => [ 461 | '0' => 'red', 462 | '1' => 'blue', 463 | '2' => 'orange', 464 | '3' => 'green', 465 | '4' => 'deeppink', 466 | ], 467 | 'legends' => true, 468 | 'diskLegends' => true, 469 | 'diskLegendsType' => 'pourcent', 470 | 'gradient' => ['grey', 'white'], 471 | 'diskLegendsLineColor' => '#fd4263', 472 | 'paddingLegendY' => 70, 473 | ] 474 | ); 475 | echo $G->draw($d, [ 476 | 'responsive' => false, 477 | 'filled' => true, 478 | 'opacity' => 0.9, 479 | 'tooltips' => true, 480 | 'type' => 'pie', 481 | 'legends' => 'Nombre de patients par an', 482 | 'diskLegends' => true, 483 | ]); 484 | 485 | echo '

Draw stock charts

'; 486 | echo '

Vertical stock charts

'; 487 | 488 | echo $G->draw($stock, [ 489 | 'type' => 'stock', 490 | 'tooltips' => true, 491 | ]); 492 | echo '

Vertical stock charts with legend

'; 493 | echo $G->draw($stock2, [ 494 | 'type' => 'stock', 495 | 'tooltips' => true, 496 | 'legends' => [ 497 | '0' => 'Serie 1', 498 | '1' => 'Serie 2', 499 | '2' => 'Serie 3', 500 | '3' => 'Serie 4', 501 | '4' => 'Serie 5', 502 | '5' => 'Serie 6', 503 | ], 504 | ] 505 | ); 506 | 507 | echo '

Horizontal stock charts

'; 508 | echo '

Horizontal stock charts with legend

'; 509 | echo $G->draw($stock2, [ 510 | 'type' => 'h-stock', 511 | 'tooltips' => true, 512 | 'legends' => [ 513 | '0' => 'Serie 1', 514 | '1' => 'Serie 2', 515 | '2' => 'Serie 3', 516 | '3' => 'Serie 4', 517 | '4' => 'Serie 5', 518 | '5' => 'Serie 6', 519 | ], 520 | ] 521 | ); 522 | echo $G->draw($stock3, [ 523 | 'type' => 'h-stock', 524 | 'tooltips' => true, 525 | 'title' => 'Effets secondaires liés au traitement (IC à 95%)', 526 | 'legends' => [ 527 | '0' => 'aplasie 1.04 (0.87 à 1.24)', 528 | '1' => 'thrombopénie 1.09 (0.95 à 1.25)', 529 | '2' => 'anorexie 1.02 (0.86 à 1.21)', 530 | '3' => 'mucites 0.87 (0.71 à 1.06)', 531 | '4' => 'leucopénie 0.90 (0.1 à 1.34)', 532 | '5' => 'neutropénie 1 (0.78 à 1.20)', 533 | ], 534 | ] 535 | ); 536 | $disk = ['occupe' => 40, 'libre' => 60]; 537 | echo $G->draw($disk, [ 538 | 'type' => 'pie', 539 | 'title' => 'Gestion mémoire :', 540 | 'tooltips' => true, 541 | 'tooltipLegend' => 'Capacité : ', 542 | 'stroke' => [ 543 | 0 => 'red', 544 | 1 => 'green', 545 | ], 546 | 'legends' => [0 => 'Occupé', 1 => 'Libre'], //conflit entre les deux. voir pour légende non affichée 547 | 'diskLegends' => true, 548 | 'diskLegendsType' => 'label', 549 | 'gradient' => ['grey', 'white'], 550 | 'diskLegendsLineColor' => '#fd4263', 551 | ] 552 | ); 553 | $p = [ 554 | '2000' => 7, 555 | '2001' => 15, 556 | '2002' => 39, 557 | '2003' => 26, 558 | '2004' => 36, 559 | '2005' => 18, 560 | '2006' => 32, 561 | '2007' => 56, 562 | '2008' => 38, 563 | '2009' => 103, 564 | '2010' => 105, 565 | '2011' => 126, 566 | '2012' => 125, 567 | '2013' => 76, 568 | '2014' => 10, 569 | ]; 570 | echo $G->draw($p, [ 571 | 'tooltips' => true, 572 | 'type' => 'line', 573 | ]); 574 | //Results above... 575 | ?> 576 | 577 |
578 | 579 | 580 | --------------------------------------------------------------------------------