[3594] | 1 | <?php |
---|
| 2 | /*======================================================================= |
---|
| 3 | // File: JPGRAPH_BAR.PHP |
---|
| 4 | // Description: Bar plot extension for JpGraph |
---|
| 5 | // Created: 2001-01-08 |
---|
| 6 | // Author: Johan Persson (johanp@aditus.nu) |
---|
| 7 | // Ver: $Id: jpgraph_bar.php 18250 2005-05-07 14:13:43Z ralfbecker $ |
---|
| 8 | // |
---|
| 9 | // License: This code is released under QPL |
---|
| 10 | // Copyright (C) 2001 Johan Persson |
---|
| 11 | //======================================================================== |
---|
| 12 | */ |
---|
| 13 | |
---|
| 14 | //=================================================== |
---|
| 15 | // CLASS Gradient |
---|
| 16 | // Description: Handles gradient fills. This is to be |
---|
| 17 | // considered a "friend" class of Class Image. The |
---|
| 18 | // Gradient takes care of production a gradient fill for |
---|
| 19 | // the bars. |
---|
| 20 | //=================================================== |
---|
| 21 | class Gradient { |
---|
| 22 | var $img=null; |
---|
| 23 | //--------------- |
---|
| 24 | // CONSTRUCTOR |
---|
| 25 | function Gradient(&$img) { |
---|
| 26 | $this->img = $img; |
---|
| 27 | } |
---|
| 28 | |
---|
| 29 | //--------------- |
---|
| 30 | // PUBLIC METHODS |
---|
| 31 | // Produce a gradient filled rectangle with a smooth transition between |
---|
| 32 | // two colors. |
---|
| 33 | // ($xl,$yt) Top left corner |
---|
| 34 | // ($xr,$yb) Bottom right |
---|
| 35 | // $from_color Starting color in gradient |
---|
| 36 | // $to_color End color in the gradient |
---|
| 37 | // $style Which way is the gradient oriented? |
---|
| 38 | function FilledRectangle($xl,$yt,$xr,$yb,$from_color,$to_color,$style=1) { |
---|
| 39 | switch( $style ) { |
---|
| 40 | case 1: // HORIZONTAL |
---|
| 41 | $steps = abs($xr-$xl); |
---|
| 42 | $delta = $xr>=$xl ? 1 : -1; |
---|
| 43 | $this->GetColArray($from_color,$to_color,$steps,$colors); |
---|
| 44 | for( $i=0, $x=$xl; $i<$steps; ++$i ) { |
---|
| 45 | $this->img->current_color = $colors[$i]; |
---|
| 46 | $this->img->Line($x,$yt,$x,$yb); |
---|
| 47 | $x += $delta; |
---|
| 48 | } |
---|
| 49 | break; |
---|
| 50 | |
---|
| 51 | case 2: // VERTICAL |
---|
| 52 | $steps = abs($yb-$yt); |
---|
| 53 | $delta = $yb>=$yt ? 1 : -1; |
---|
| 54 | $this->GetColArray($from_color,$to_color,$steps,$colors); |
---|
| 55 | for($i=0,$y=$yt; $i<$steps; ++$i) { |
---|
| 56 | $this->img->current_color = $colors[$i]; |
---|
| 57 | $this->img->Line($xl,$y,$xr,$y); |
---|
| 58 | $y += $delta; |
---|
| 59 | } |
---|
| 60 | break; |
---|
| 61 | |
---|
| 62 | case 3: // VERTICAL FROM MIDDLE |
---|
| 63 | $steps = abs($yb-$yt)/2; |
---|
| 64 | $delta = $yb>=$yt ? 1 : -1; |
---|
| 65 | $this->GetColArray($from_color,$to_color,$steps,$colors); |
---|
| 66 | for($y=$yt, $i=0; $i<$steps; ++$i) { |
---|
| 67 | $this->img->current_color = $colors[$i]; |
---|
| 68 | $this->img->Line($xl,$y,$xr,$y); |
---|
| 69 | $y += $delta; |
---|
| 70 | } |
---|
| 71 | --$i; |
---|
| 72 | for($j=0; $j<$steps; ++$j, --$i) { |
---|
| 73 | $this->img->current_color = $colors[$i]; |
---|
| 74 | $this->img->Line($xl,$y,$xr,$y); |
---|
| 75 | $y += $delta; |
---|
| 76 | } |
---|
| 77 | $this->img->Line($xl,$y,$xr,$y); |
---|
| 78 | break; |
---|
| 79 | |
---|
| 80 | case 4: // HORIZONTAL FROM MIDDLE |
---|
| 81 | $steps = abs($xr-$xl)/2; |
---|
| 82 | $delta = $xr>=$xl ? 1 : -1; |
---|
| 83 | $this->GetColArray($from_color,$to_color,$steps,$colors); |
---|
| 84 | for($x=$xl, $i=0; $i<$steps; ++$i) { |
---|
| 85 | $this->img->current_color = $colors[$i]; |
---|
| 86 | $this->img->Line($x,$yb,$x,$yt); |
---|
| 87 | $x += $delta; |
---|
| 88 | } |
---|
| 89 | --$i; |
---|
| 90 | for($j=0; $j<$steps; ++$j, --$i) { |
---|
| 91 | $this->img->current_color = $colors[$i]; |
---|
| 92 | $this->img->Line($x,$yb,$x,$yt); |
---|
| 93 | $x += $delta; |
---|
| 94 | } |
---|
| 95 | $this->img->Line($x,$yb,$x,$yt); |
---|
| 96 | break; |
---|
| 97 | |
---|
| 98 | case 6: // HORIZONTAL WIDER MIDDLE |
---|
| 99 | $steps = abs($xr-$xl)/3; |
---|
| 100 | $delta = $xr>=$xl ? 1 : -1; |
---|
| 101 | $this->GetColArray($from_color,$to_color,$steps,$colors); |
---|
| 102 | for($x=$xl, $i=0; $i<$steps; ++$i) { |
---|
| 103 | $this->img->current_color = $colors[$i]; |
---|
| 104 | $this->img->Line($x,$yb,$x,$yt); |
---|
| 105 | $x += $delta; |
---|
| 106 | } |
---|
| 107 | --$i; |
---|
| 108 | $this->img->current_color = $colors[$i]; |
---|
| 109 | for($j=0; $j< $steps; ++$j) { |
---|
| 110 | $this->img->Line($x,$yb,$x,$yt); |
---|
| 111 | $x += $delta; |
---|
| 112 | } |
---|
| 113 | |
---|
| 114 | for($j=0; $j<$steps; ++$j, --$i) { |
---|
| 115 | $this->img->current_color = $colors[$i]; |
---|
| 116 | $this->img->Line($x,$yb,$x,$yt); |
---|
| 117 | $x += $delta; |
---|
| 118 | } |
---|
| 119 | break; |
---|
| 120 | |
---|
| 121 | case 7: // VERTICAL WIDER MIDDLE |
---|
| 122 | $steps = abs($yb-$yt)/3; |
---|
| 123 | $delta = $yb>=$yt? 1 : -1; |
---|
| 124 | $this->GetColArray($from_color,$to_color,$steps,$colors); |
---|
| 125 | for($y=$yt, $i=0; $i<$steps; ++$i) { |
---|
| 126 | $this->img->current_color = $colors[$i]; |
---|
| 127 | $this->img->Line($xl,$y,$xr,$y); |
---|
| 128 | $y += $delta; |
---|
| 129 | } |
---|
| 130 | --$i; |
---|
| 131 | $this->img->current_color = $colors[$i]; |
---|
| 132 | for($j=0; $j< $steps; ++$j) { |
---|
| 133 | $this->img->Line($xl,$y,$xr,$y); |
---|
| 134 | $y += $delta; |
---|
| 135 | } |
---|
| 136 | for($j=0; $j<$steps; ++$j, --$i) { |
---|
| 137 | $this->img->current_color = $colors[$i]; |
---|
| 138 | $this->img->Line($xl,$y,$xr,$y); |
---|
| 139 | $y += $delta; |
---|
| 140 | } |
---|
| 141 | break; |
---|
| 142 | |
---|
| 143 | case 5: // Rectangle |
---|
| 144 | $steps = floor(min(($yb-$yt)+1,($xr-$xl)+1)/2); |
---|
| 145 | $this->GetColArray($from_color,$to_color,$steps,$colors); |
---|
| 146 | $dx = ($xr-$xl)/2; |
---|
| 147 | $dy = ($yb-$yt)/2; |
---|
| 148 | $x=$xl;$y=$yt;$x2=$xr;$y2=$yb; |
---|
| 149 | for($x=$xl, $i=0; $x<$xl+$dx && $y<$yt+$dy ; ++$x, ++$y, --$x2, --$y2, ++$i) { |
---|
| 150 | assert($i<count($colors)); |
---|
| 151 | $this->img->current_color = $colors[$i]; |
---|
| 152 | $this->img->Rectangle($x,$y,$x2,$y2); |
---|
| 153 | } |
---|
| 154 | $this->img->Line($x,$y,$x2,$y2); |
---|
| 155 | break; |
---|
| 156 | |
---|
| 157 | default: |
---|
| 158 | die("JpGraph Error: Unknown gradient style (=$style)."); |
---|
| 159 | break; |
---|
| 160 | } |
---|
| 161 | } |
---|
| 162 | |
---|
| 163 | //--------------- |
---|
| 164 | // PRIVATE METHODS |
---|
| 165 | // Add to the image color map the necessary colors to do the transition |
---|
| 166 | // between the two colors using $numcolors intermediate colors |
---|
| 167 | function GetColArray($from_color,$to_color,$arr_size,&$colors,$numcols=100) { |
---|
| 168 | if( $arr_size==0 ) return; |
---|
| 169 | // If color is give as text get it's corresponding r,g,b values |
---|
| 170 | $from_color = $this->img->rgb->Color($from_color); |
---|
| 171 | $to_color = $this->img->rgb->Color($to_color); |
---|
| 172 | |
---|
| 173 | $rdelta=($to_color[0]-$from_color[0])/$numcols; |
---|
| 174 | $gdelta=($to_color[1]-$from_color[1])/$numcols; |
---|
| 175 | $bdelta=($to_color[2]-$from_color[2])/$numcols; |
---|
| 176 | $stepspercolor = $numcols/$arr_size; |
---|
| 177 | $prevcolnum = -1; |
---|
| 178 | for ($i=0; $i<$arr_size; ++$i) { |
---|
| 179 | $colnum = floor($stepspercolor*$i); |
---|
| 180 | if ( $colnum == $prevcolnum ) |
---|
| 181 | $colors[$i] = $colidx; |
---|
| 182 | else { |
---|
| 183 | $r = floor($from_color[0] + $colnum*$rdelta); |
---|
| 184 | $g = floor($from_color[1] + $colnum*$gdelta); |
---|
| 185 | $b = floor($from_color[2] + $colnum*$bdelta); |
---|
| 186 | $colidx = $this->img->rgb->Allocate(sprintf("#%02x%02x%02x",$r,$g,$b)); |
---|
| 187 | $colors[$i] = $colidx; |
---|
| 188 | } |
---|
| 189 | $prevcolnum = $colnum; |
---|
| 190 | } |
---|
| 191 | } |
---|
| 192 | } // Class |
---|
| 193 | |
---|
| 194 | |
---|
| 195 | //=================================================== |
---|
| 196 | // CLASS BarPlot |
---|
| 197 | // Description: Main code to produce a bar plot |
---|
| 198 | //=================================================== |
---|
| 199 | class BarPlot extends Plot { |
---|
| 200 | var $width=0.4; // in percent of major ticks |
---|
| 201 | var $abswidth=-1; // Width in absolute pixels |
---|
| 202 | var $fill_color="lightblue"; // Default is to fill with light blue |
---|
| 203 | var $ybase=0; // Bars start at 0 |
---|
| 204 | var $align="left"; |
---|
| 205 | var $grad=false,$grad_style=1; |
---|
| 206 | var $grad_fromcolor=array(50,50,200),$grad_tocolor=array(255,255,255); |
---|
| 207 | var $bar_shadow=false; |
---|
| 208 | var $bar_shadow_color="black"; |
---|
| 209 | var $bar_shadow_hsize=3,$bar_shadow_vsize=3; |
---|
| 210 | var $show_value=false,$show_value_format="%d",$show_value_angle=0; |
---|
| 211 | var $show_value_ff=FF_FONT1,$show_value_fs=FS_NORMAL,$show_value_fsize=12; |
---|
| 212 | var $show_value_color="black",$show_value_margin=3; |
---|
| 213 | |
---|
| 214 | //--------------- |
---|
| 215 | // CONSTRUCTOR |
---|
| 216 | function BarPlot(&$datay,$datax=false) { |
---|
| 217 | $this->Plot($datay,$datax); |
---|
| 218 | ++$this->numpoints; |
---|
| 219 | } |
---|
| 220 | |
---|
| 221 | //--------------- |
---|
| 222 | // PUBLIC METHODS |
---|
| 223 | |
---|
| 224 | // Set a drop shadow for the bar (or rather an "up-right" shadow) |
---|
| 225 | function SetShadow($color="black",$hsize=3,$vsize=3) { |
---|
| 226 | $this->bar_shadow=true; |
---|
| 227 | $this->bar_shadow_color=$color; |
---|
| 228 | $this->bar_shadow_vsize=$vsize; |
---|
| 229 | $this->bar_shadow_hsize=$hsize; |
---|
| 230 | |
---|
| 231 | // Adjust the value margin to compensate for shadow |
---|
| 232 | $this->show_value_margin += $vsize; |
---|
| 233 | } |
---|
| 234 | |
---|
| 235 | // Display the value of the bar at the top of bar |
---|
| 236 | function ShowValue($f=true) { |
---|
| 237 | $this->show_value = $f; |
---|
| 238 | } |
---|
| 239 | |
---|
| 240 | function SetValueFormat($format="%d",$angle=0) { |
---|
| 241 | $this->show_value_format = $format; |
---|
| 242 | $this->show_value_angle = $angle; |
---|
| 243 | } |
---|
| 244 | |
---|
| 245 | function SetValueFont($ff=FF_FONT1,$fs=FS_NORMAL,$size=10) { |
---|
| 246 | $this->show_value_ff=$ff; |
---|
| 247 | $this->show_value_fs=$fs; |
---|
| 248 | $this->show_value_fsize=$size; |
---|
| 249 | } |
---|
| 250 | |
---|
| 251 | function SetValueColor($color) { |
---|
| 252 | $this->show_value_color=$color; |
---|
| 253 | } |
---|
| 254 | |
---|
| 255 | function SetValueMargin($m) { |
---|
| 256 | $this->show_value_margin=$m; |
---|
| 257 | } |
---|
| 258 | |
---|
| 259 | function SetYStart($y) { |
---|
| 260 | die("JpGraph Error: Deprecated function SetYStart. Use SetYMin() instead."); |
---|
| 261 | } |
---|
| 262 | |
---|
| 263 | // DEPRECATED use SetYBase instead |
---|
| 264 | function SetYMin($y) { |
---|
| 265 | $this->ybase=$y; |
---|
| 266 | } |
---|
| 267 | |
---|
| 268 | // |
---|
| 269 | function SetYBase($y) { |
---|
| 270 | $this->ybase=$y; |
---|
| 271 | } |
---|
| 272 | |
---|
| 273 | function Legend(&$graph) { |
---|
| 274 | if( $this->fill_color && $this->legend!="" ) { |
---|
| 275 | if( is_array($this->fill_color) ) |
---|
| 276 | $graph->legend->Add($this->legend,$this->fill_color[0]); |
---|
| 277 | else |
---|
| 278 | $graph->legend->Add($this->legend,$this->fill_color); |
---|
| 279 | } |
---|
| 280 | } |
---|
| 281 | |
---|
| 282 | // Gets called before any axis are stroked |
---|
| 283 | function PreStrokeAdjust(&$graph) { |
---|
| 284 | parent::PreStrokeAdjust($graph); |
---|
| 285 | |
---|
| 286 | // For a "text" X-axis scale we will adjust the |
---|
| 287 | // display of the bars a little bit. |
---|
| 288 | if( substr($graph->axtype,0,3)=="tex" ) { |
---|
| 289 | // Position the ticks between the bars |
---|
| 290 | $graph->xaxis->scale->ticks->SetXLabelOffset(0.5,0); |
---|
| 291 | |
---|
| 292 | // Position the labels under each bar in the middle of the |
---|
| 293 | // major steps. |
---|
| 294 | $graph->SetTextScaleOff(0.5-$this->width/2); |
---|
| 295 | } |
---|
| 296 | else { |
---|
| 297 | // We only set an absolute width for linear and int scale |
---|
| 298 | // for text scale the width will be set to a fraction of |
---|
| 299 | // the majstep width. |
---|
| 300 | if( $this->abswidth == -1 ) // Not set |
---|
| 301 | // set width to a visuable sensible default |
---|
| 302 | $this->abswidth = $graph->img->plotwidth/(2*count($this->coords[0])); |
---|
| 303 | } |
---|
| 304 | } |
---|
| 305 | |
---|
| 306 | function Min() { |
---|
| 307 | $m = parent::Min(); |
---|
| 308 | if( $m[1] >= $this->ybase ) |
---|
| 309 | $m[1] = $this->ybase; |
---|
| 310 | return $m; |
---|
| 311 | } |
---|
| 312 | |
---|
| 313 | function Max() { |
---|
| 314 | $m = parent::Max(); |
---|
| 315 | if( $m[1] <= $this->ybase ) |
---|
| 316 | $m[1] = $this->ybase; |
---|
| 317 | return $m; |
---|
| 318 | } |
---|
| 319 | |
---|
| 320 | // Specify width as fractions of the major stepo size |
---|
| 321 | function SetWidth($w) { |
---|
| 322 | assert($w > 0 && $w <= 1.0); |
---|
| 323 | $this->width=$w; |
---|
| 324 | } |
---|
| 325 | |
---|
| 326 | // Specify width in absolute pixels. If specified this |
---|
| 327 | // overrides SetWidth() |
---|
| 328 | function SetAbsWidth($w) { |
---|
| 329 | $this->abswidth=$w; |
---|
| 330 | } |
---|
| 331 | |
---|
| 332 | function SetAlign($a) { |
---|
| 333 | $this->align=$a; |
---|
| 334 | } |
---|
| 335 | |
---|
| 336 | function SetNoFill() { |
---|
| 337 | $this->grad = false; |
---|
| 338 | $this->fill_color=false; |
---|
| 339 | } |
---|
| 340 | |
---|
| 341 | function SetFillColor($c) { |
---|
| 342 | $this->fill_color=$c; |
---|
| 343 | } |
---|
| 344 | |
---|
| 345 | function SetFillGradient($from_color,$to_color,$style) { |
---|
| 346 | $this->grad=true; |
---|
| 347 | $this->grad_fromcolor=$from_color; |
---|
| 348 | $this->grad_tocolor=$to_color; |
---|
| 349 | $this->grad_style=$style; |
---|
| 350 | } |
---|
| 351 | |
---|
| 352 | function Stroke(&$img,&$xscale,&$yscale) { |
---|
| 353 | |
---|
| 354 | $numpoints = count($this->coords[0]); |
---|
| 355 | if( isset($this->coords[1]) ) { |
---|
| 356 | if( count($this->coords[1])!=$numpoints ) |
---|
| 357 | die("JpGraph Error: Number of X and Y points are not equal.<br> |
---|
| 358 | Number of X-points:".count($this->coords[1])."<br> |
---|
| 359 | Number of Y-points:$numpoints"); |
---|
| 360 | else |
---|
| 361 | $exist_x = true; |
---|
| 362 | } |
---|
| 363 | else |
---|
| 364 | $exist_x = false; |
---|
| 365 | |
---|
| 366 | |
---|
| 367 | $numbars=count($this->coords[0]); |
---|
| 368 | if( $yscale->scale[0] >= 0 ) |
---|
| 369 | $zp=$yscale->scale_abs[0]; |
---|
| 370 | else |
---|
| 371 | $zp=$yscale->Translate(0.0); |
---|
| 372 | |
---|
| 373 | if( $this->abswidth > -1 ) |
---|
| 374 | $abswidth=$this->abswidth; |
---|
| 375 | else |
---|
| 376 | $abswidth=round($this->width*$xscale->scale_factor,0); |
---|
| 377 | |
---|
| 378 | |
---|
| 379 | for($i=0; $i<$numbars; $i++) { |
---|
| 380 | if( $exist_x ) $x=$this->coords[1][$i]; |
---|
| 381 | else $x=$i; |
---|
| 382 | |
---|
| 383 | $x=$xscale->Translate($x); |
---|
| 384 | |
---|
| 385 | if($this->align=="center") |
---|
| 386 | $x -= $abswidth/2; |
---|
| 387 | elseif($this->align=="right") |
---|
| 388 | $x -= $abswidth; |
---|
| 389 | $pts=array( |
---|
| 390 | $x,$zp, |
---|
| 391 | $x,$yscale->Translate($this->coords[0][$i]), |
---|
| 392 | $x+$abswidth,$yscale->Translate($this->coords[0][$i]), |
---|
| 393 | $x+$abswidth,$zp); |
---|
| 394 | if( $this->grad ) { |
---|
| 395 | $grad = new Gradient($img); |
---|
| 396 | $grad->FilledRectangle($pts[2],$pts[3], |
---|
| 397 | $pts[6],$pts[7], |
---|
| 398 | $this->grad_fromcolor,$this->grad_tocolor,$this->grad_style); |
---|
| 399 | } |
---|
| 400 | elseif( !empty($this->fill_color) ) { |
---|
| 401 | if(is_array($this->fill_color)) { |
---|
| 402 | $img->PushColor($this->fill_color[$i % count($this->fill_color)]); |
---|
| 403 | } else { |
---|
| 404 | $img->PushColor($this->fill_color); |
---|
| 405 | } |
---|
| 406 | $img->FilledPolygon($pts); |
---|
| 407 | $img->PopColor(); |
---|
| 408 | } |
---|
| 409 | |
---|
| 410 | // Remember value of this bar |
---|
| 411 | $val=$this->coords[0][$i]; |
---|
| 412 | |
---|
| 413 | if( $this->bar_shadow && $val != 0 ) { |
---|
| 414 | $ssh = $this->bar_shadow_hsize; |
---|
| 415 | $ssv = $this->bar_shadow_vsize; |
---|
| 416 | // Create points to create a "upper-right" shadow |
---|
| 417 | if( $val > 0 ) { |
---|
| 418 | $sp[0]=$pts[6]; $sp[1]=$pts[7]; |
---|
| 419 | $sp[2]=$pts[4]; $sp[3]=$pts[5]; |
---|
| 420 | $sp[4]=$pts[2]; $sp[5]=$pts[3]; |
---|
| 421 | $sp[6]=$pts[2]+$ssh; $sp[7]=$pts[3]-$ssv; |
---|
| 422 | $sp[8]=$pts[4]+$ssh; $sp[9]=$pts[5]-$ssv; |
---|
| 423 | $sp[10]=$pts[6]+$ssh; $sp[11]=$pts[7]-$ssv; |
---|
| 424 | } |
---|
| 425 | elseif( $val < 0 ) { |
---|
| 426 | $sp[0]=$pts[4]; $sp[1]=$pts[5]; |
---|
| 427 | $sp[2]=$pts[6]; $sp[3]=$pts[7]; |
---|
| 428 | $sp[4]=$pts[0]; $sp[5]=$pts[1]; |
---|
| 429 | $sp[6]=$pts[0]+$ssh; $sp[7]=$pts[1]-$ssv; |
---|
| 430 | $sp[8]=$pts[6]+$ssh; $sp[9]=$pts[7]-$ssv; |
---|
| 431 | $sp[10]=$pts[4]+$ssh; $sp[11]=$pts[5]-$ssv; |
---|
| 432 | } |
---|
| 433 | |
---|
| 434 | $img->PushColor($this->bar_shadow_color); |
---|
| 435 | $img->FilledPolygon($sp); |
---|
| 436 | $img->PopColor(); |
---|
| 437 | } |
---|
| 438 | |
---|
| 439 | // Stroke the outline of the bar |
---|
| 440 | if( is_array($this->color) ) |
---|
| 441 | $img->SetColor($this->color[$i % count($this->color)]); |
---|
| 442 | else |
---|
| 443 | $img->SetColor($this->color); |
---|
| 444 | $img->SetLineWeight($this->weight); |
---|
| 445 | $img->Polygon($pts); |
---|
| 446 | |
---|
| 447 | if( $this->show_value) { |
---|
| 448 | $sval=sprintf($this->show_value_format,$val); |
---|
| 449 | $txt = new Text($sval); |
---|
| 450 | $txt->SetFont($this->show_value_ff,$this->show_value_fs,$this->show_value_fsize); |
---|
| 451 | $txt->SetColor($this->show_value_color); |
---|
| 452 | $x=$pts[2]+($pts[4]-$pts[2])/2; |
---|
| 453 | if($this->bar_shadow) |
---|
| 454 | $x += $ssh; |
---|
| 455 | |
---|
| 456 | if( $val >= 0 ) { |
---|
| 457 | $txt->Pos($x,$pts[3]-$this->show_value_margin); |
---|
| 458 | $txt->Align("center","bottom"); |
---|
| 459 | } |
---|
| 460 | else { |
---|
| 461 | $txt->Pos($x,$pts[3]+$this->show_value_margin); |
---|
| 462 | $txt->Align("center","top"); |
---|
| 463 | } |
---|
| 464 | $txt->SetOrientation($this->show_value_angle); |
---|
| 465 | $txt->Stroke($img); |
---|
| 466 | } |
---|
| 467 | |
---|
| 468 | // Create the client side image map |
---|
| 469 | $this->csimareas.= "<area shape=\"rect\" coords=\""; |
---|
| 470 | // Hmmm, this is fishy. Fixes a bug in Opera whereby if Y2<Y1 or X2<X1 the csim doesn't work |
---|
| 471 | if ($pts[3] < $pts[7]) { |
---|
| 472 | if ($pts[2] < $pts[6]) |
---|
| 473 | $this->csimareas .= "$pts[2], $pts[3], $pts[6], $pts[7]\""; |
---|
| 474 | else |
---|
| 475 | $this->csimareas .= "$pts[6], $pts[3], $pts[2], $pts[7]\""; |
---|
| 476 | } else { |
---|
| 477 | if ($pts[2] < $pts[6]) |
---|
| 478 | $this->csimareas .= "$pts[2], $pts[7], $pts[6], $pts[3]\""; |
---|
| 479 | else |
---|
| 480 | $this->csimareas .= "$pts[6], $pts[7], $pts[2], $pts[3]\""; |
---|
| 481 | } |
---|
| 482 | if( !empty($this->csimtargets[$i]) ) |
---|
| 483 | $this->csimareas .= " href=\"".$this->csimtargets[$i]."\""; |
---|
| 484 | if( !empty($this->csimalts[$i]) ) { |
---|
| 485 | $sval=sprintf($this->csimalts[$i],$this->coords[0][$i]); |
---|
| 486 | $this->csimareas .= " alt=\"$sval\" title=\"$sval\" "; |
---|
| 487 | } |
---|
| 488 | $this->csimareas .= ">\r\n"; |
---|
| 489 | } |
---|
| 490 | return true; |
---|
| 491 | } |
---|
| 492 | } // Class |
---|
| 493 | |
---|
| 494 | //=================================================== |
---|
| 495 | // CLASS GroupBarPlot |
---|
| 496 | // Description: Produce grouped bar plots |
---|
| 497 | //=================================================== |
---|
| 498 | class GroupBarPlot extends BarPlot { |
---|
| 499 | var $plots; |
---|
| 500 | var $width=0.7; |
---|
| 501 | var $nbrplots=0; |
---|
| 502 | var $numpoints; |
---|
| 503 | //--------------- |
---|
| 504 | // CONSTRUCTOR |
---|
| 505 | function GroupBarPlot($plots) { |
---|
| 506 | $this->plots = $plots; |
---|
| 507 | $this->nbrplots = count($plots); |
---|
| 508 | $this->numpoints = $plots[0]->numpoints; |
---|
| 509 | } |
---|
| 510 | |
---|
| 511 | //--------------- |
---|
| 512 | // PUBLIC METHODS |
---|
| 513 | function Legend(&$graph) { |
---|
| 514 | $n = count($this->plots); |
---|
| 515 | for($i=0; $i<$n; ++$i) |
---|
| 516 | $this->plots[$i]->Legend($graph); |
---|
| 517 | } |
---|
| 518 | |
---|
| 519 | function Min() { |
---|
| 520 | list($xmin,$ymin) = $this->plots[0]->Min(); |
---|
| 521 | $n = count($this->plots); |
---|
| 522 | for($i=0; $i<$n; ++$i) { |
---|
| 523 | list($xm,$ym) = $this->plots[$i]->Min(); |
---|
| 524 | $xmin = max($xmin,$xm); |
---|
| 525 | $ymin = min($ymin,$ym); |
---|
| 526 | } |
---|
| 527 | return array($xmin,$ymin); |
---|
| 528 | } |
---|
| 529 | |
---|
| 530 | function Max() { |
---|
| 531 | list($xmax,$ymax) = $this->plots[0]->Max(); |
---|
| 532 | $n = count($this->plots); |
---|
| 533 | for($i=0; $i<$n; ++$i) { |
---|
| 534 | list($xm,$ym) = $this->plots[$i]->Max(); |
---|
| 535 | $xmax = max($xmax,$xm); |
---|
| 536 | $ymax = max($ymax,$ym); |
---|
| 537 | } |
---|
| 538 | return array($xmax,$ymax); |
---|
| 539 | } |
---|
| 540 | |
---|
| 541 | function GetCSIMareas() { |
---|
| 542 | $n = count($this->plots); |
---|
| 543 | for($i=0; $i<$n; ++$i) { |
---|
| 544 | $csimareas.= $this->plots[$i]->csimareas; |
---|
| 545 | } |
---|
| 546 | return $csimareas; |
---|
| 547 | } |
---|
| 548 | |
---|
| 549 | // Stroke all the bars next to each other |
---|
| 550 | function Stroke(&$img,&$xscale,&$yscale) { |
---|
| 551 | $tmp=$xscale->off; |
---|
| 552 | $n = count($this->plots); |
---|
| 553 | for( $i=0; $i<$n; ++$i ) { |
---|
| 554 | $this->plots[$i]->ymin=$this->ybase; |
---|
| 555 | $this->plots[$i]->SetWidth($this->width/$this->nbrplots); |
---|
| 556 | $xscale->off = $tmp+$i*round($xscale->ticks->major_step*$xscale->scale_factor*$this->width/$this->nbrplots); |
---|
| 557 | $this->plots[$i]->Stroke($img,$xscale,$yscale); |
---|
| 558 | } |
---|
| 559 | $xscale->off=$tmp; |
---|
| 560 | } |
---|
| 561 | } // Class |
---|
| 562 | |
---|
| 563 | //=================================================== |
---|
| 564 | // CLASS AccBarPlot |
---|
| 565 | // Description: Produce accumulated bar plots |
---|
| 566 | //=================================================== |
---|
| 567 | class AccBarPlot extends BarPlot { |
---|
| 568 | var $plots=null,$nbrplots=0,$numpoints=0; |
---|
| 569 | //--------------- |
---|
| 570 | // CONSTRUCTOR |
---|
| 571 | function AccBarPlot($plots) { |
---|
| 572 | $this->plots = $plots; |
---|
| 573 | $this->nbrplots = count($plots); |
---|
| 574 | $this->numpoints = $plots[0]->numpoints; |
---|
| 575 | } |
---|
| 576 | |
---|
| 577 | //--------------- |
---|
| 578 | // PUBLIC METHODS |
---|
| 579 | function Legend(&$graph) { |
---|
| 580 | $n = count($this->plots); |
---|
| 581 | for( $i=0; $i<$n; ++$i ) |
---|
| 582 | $this->plots[$i]->Legend($graph); |
---|
| 583 | } |
---|
| 584 | |
---|
| 585 | function Max() { |
---|
| 586 | list($xmax) = $this->plots[0]->Max(); |
---|
| 587 | $nmax=0; |
---|
| 588 | for($i=0; $i<count($this->plots); ++$i) { |
---|
| 589 | $n = count($this->plots[$i]->coords[0]); |
---|
| 590 | $nmax = max($nmax,$n); |
---|
| 591 | list($x) = $this->plots[$i]->Max(); |
---|
| 592 | $xmax = Max($xmax,$x); |
---|
| 593 | } |
---|
| 594 | for( $i = 0; $i < $nmax; $i++ ) { |
---|
| 595 | // Get y-value for bar $i by adding the |
---|
| 596 | // individual bars from all the plots added. |
---|
| 597 | // It would be wrong to just add the |
---|
| 598 | // individual plots max y-value since that |
---|
| 599 | // would in most cases give to large y-value. |
---|
| 600 | $y=$this->plots[0]->coords[0][$i]; |
---|
| 601 | for( $j = 1; $j < $this->nbrplots; $j++ ) { |
---|
| 602 | $y += $this->plots[ $j ]->coords[0][$i]; |
---|
| 603 | } |
---|
| 604 | $ymax[$i] = $y; |
---|
| 605 | } |
---|
| 606 | $ymax = max($ymax); |
---|
| 607 | |
---|
| 608 | // Bar always start at baseline |
---|
| 609 | if( $ymax <= $this->ybase ) |
---|
| 610 | $ymax = $this->ybase; |
---|
| 611 | return array($xmax,$ymax); |
---|
| 612 | } |
---|
| 613 | |
---|
| 614 | function Min() { |
---|
| 615 | $nmax=0; |
---|
| 616 | list($xmin,$ysetmin) = $this->plots[0]->Min(); |
---|
| 617 | for($i=0; $i<count($this->plots); ++$i) { |
---|
| 618 | $n = count($this->plots[$i]->coords[0]); |
---|
| 619 | $nmax = max($nmax,$n); |
---|
| 620 | list($x,$y) = $this->plots[$i]->Min(); |
---|
| 621 | $xmin = Min($xmin,$x); |
---|
| 622 | $ysetmin = Min($y,$ysetmin); |
---|
| 623 | } |
---|
| 624 | for( $i = 0; $i < $nmax; $i++ ) { |
---|
| 625 | // Get y-value for bar $i by adding the |
---|
| 626 | // individual bars from all the plots added. |
---|
| 627 | // It would be wrong to just add the |
---|
| 628 | // individual plots max y-value since that |
---|
| 629 | // would in most cases give to large y-value. |
---|
| 630 | $y=$this->plots[0]->coords[0][$i]; |
---|
| 631 | for( $j = 1; $j < $this->nbrplots; $j++ ) { |
---|
| 632 | $y += $this->plots[ $j ]->coords[0][$i]; |
---|
| 633 | } |
---|
| 634 | $ymin[$i] = $y; |
---|
| 635 | } |
---|
| 636 | $ymin = Min($ysetmin,Min($ymin)); |
---|
| 637 | // Bar always start at baseline |
---|
| 638 | if( $ymin >= $this->ybase ) |
---|
| 639 | $ymin = $this->ybase; |
---|
| 640 | return array($xmin,$ymin); |
---|
| 641 | } |
---|
| 642 | |
---|
| 643 | // Method description |
---|
| 644 | function Stroke(&$img,&$xscale,&$yscale) { |
---|
| 645 | $img->SetLineWeight($this->weight); |
---|
| 646 | for($i=0; $i<$this->numpoints-1; $i++) { |
---|
| 647 | $accy = 0; |
---|
| 648 | $accy_neg = 0; |
---|
| 649 | for($j=0; $j<$this->nbrplots; ++$j ) { |
---|
| 650 | $img->SetColor($this->plots[$j]->color); |
---|
| 651 | if ($this->plots[$j]->coords[0][$i] > 0) { |
---|
| 652 | $yt=$yscale->Translate($this->plots[$j]->coords[0][$i]+$accy); |
---|
| 653 | $accyt=$yscale->Translate($accy); |
---|
| 654 | $accy+=$this->plots[$j]->coords[0][$i]; |
---|
| 655 | } else { |
---|
| 656 | $yt=$yscale->Translate($this->plots[$j]->coords[0][$i]+$accy_neg); |
---|
| 657 | $accyt=$yscale->Translate($accy_neg); |
---|
| 658 | $accy_neg+=$this->plots[$j]->coords[0][$i]; |
---|
| 659 | } |
---|
| 660 | |
---|
| 661 | $xt=$xscale->Translate($i); |
---|
| 662 | $abswidth=round($this->width*$xscale->scale_factor,0); |
---|
| 663 | $pts=array($xt,$accyt,$xt,$yt,$xt+$abswidth,$yt,$xt+$abswidth,$accyt); |
---|
| 664 | |
---|
| 665 | if( $this->plots[$j]->grad ) { |
---|
| 666 | $grad = new Gradient($img); |
---|
| 667 | $grad->FilledRectangle( |
---|
| 668 | $pts[2],$pts[3], |
---|
| 669 | $pts[6],$pts[7], |
---|
| 670 | $this->plots[$j]->grad_fromcolor, |
---|
| 671 | $this->plots[$j]->grad_tocolor, |
---|
| 672 | $this->plots[$j]->grad_style); |
---|
| 673 | } elseif ($this->plots[$j]->fill_color ) { |
---|
| 674 | $img->SetColor($this->plots[$j]->fill_color); |
---|
| 675 | $img->FilledPolygon($pts,4); |
---|
| 676 | $img->SetColor($this->plots[$j]->color); |
---|
| 677 | } |
---|
| 678 | |
---|
| 679 | if( $this->bar_shadow ) { |
---|
| 680 | $ssh = $this->bar_shadow_hsize; |
---|
| 681 | $ssv = $this->bar_shadow_vsize; |
---|
| 682 | // Create points to create a "upper-right" shadow |
---|
| 683 | $sp[0]=$pts[6]; $sp[1]=$pts[7]; |
---|
| 684 | $sp[2]=$pts[4]; $sp[3]=$pts[5]; |
---|
| 685 | $sp[4]=$pts[2]; $sp[5]=$pts[3]; |
---|
| 686 | $sp[6]=$pts[2]+$ssh; $sp[7]=$pts[3]-$ssv; |
---|
| 687 | $sp[8]=$pts[4]+$ssh; $sp[9]=$pts[5]-$ssv; |
---|
| 688 | $sp[10]=$pts[6]+$ssh; $sp[11]=$pts[7]-$ssv; |
---|
| 689 | $img->SetColor($this->bar_shadow_color); |
---|
| 690 | $img->FilledPolygon($sp,4); |
---|
| 691 | } |
---|
| 692 | |
---|
| 693 | if( $i < count($this->plots[$j]->csimtargets) ) { |
---|
| 694 | $this->csimareas.= "<area shape=\"rect\" coords=\""; |
---|
| 695 | // Hmmm, this is fishy. Fixes a bug in Opera whereby if Y2<Y1 or X2<X1 the csim doesn't work |
---|
| 696 | // This means that the area MUST specify top left and bottom right corners |
---|
| 697 | if ($pts[3] < $pts[7]) { |
---|
| 698 | if ($pts[2] < $pts[6]) { |
---|
| 699 | $this->csimareas.= "$pts[2], $pts[3], $pts[6], $pts[7]\""; |
---|
| 700 | } else { |
---|
| 701 | $this->csimareas.= "$pts[6], $pts[3], $pts[2], $pts[7]\""; |
---|
| 702 | } |
---|
| 703 | } else { |
---|
| 704 | if ($pts[2] < $pts[6]) { |
---|
| 705 | $this->csimareas.= "$pts[2], $pts[7], $pts[6], $pts[3]\""; |
---|
| 706 | } else { |
---|
| 707 | $this->csimareas.= "$pts[6], $pts[7], $pts[2], $pts[3]\""; |
---|
| 708 | } |
---|
| 709 | } |
---|
| 710 | $this->csimareas.= " href=\"".$this->plots[$j]->csimtargets[$i]."\""; |
---|
| 711 | if( !empty($this->plots[$j]->csimalts[$i]) ) { |
---|
| 712 | $sval=sprintf($this->plots[$j]->csimalts[$i],$this->plots[$j]->coords[0][$i]); |
---|
| 713 | $this->csimareas .= " alt=\"$sval\" title=\"$sval\" "; |
---|
| 714 | } |
---|
| 715 | $this->csimareas .= ">\r\n"; |
---|
| 716 | } |
---|
| 717 | |
---|
| 718 | $img->Polygon($pts,4); |
---|
| 719 | } |
---|
| 720 | |
---|
| 721 | $yt=$yscale->Translate($accy); |
---|
| 722 | |
---|
| 723 | if( $this->show_value) { |
---|
| 724 | $sval=sprintf($this->show_value_format,$accy); |
---|
| 725 | $txt = new Text($sval); |
---|
| 726 | $txt->SetFont($this->show_value_ff,$this->show_value_fs,$this->show_value_fsize); |
---|
| 727 | $txt->SetColor($this->show_value_color); |
---|
| 728 | $x=$pts[2]+($pts[4]-$pts[2])/2; |
---|
| 729 | if($this->bar_shadow) |
---|
| 730 | $x += $ssh; |
---|
| 731 | $txt->Pos($x,$yt-$this->show_value_margin); |
---|
| 732 | $txt->Align("center","bottom"); |
---|
| 733 | $txt->SetOrientation($this->show_value_angle); |
---|
| 734 | $txt->Stroke($img); |
---|
| 735 | } |
---|
| 736 | } |
---|
| 737 | return true; |
---|
| 738 | } |
---|
| 739 | } // Class |
---|
| 740 | |
---|
| 741 | /* EOF */ |
---|
| 742 | ?> |
---|