1<?php 2/*======================================================================= 3 // File: JPGRAPH_CANVTOOLS.PHP 4 // Description: Some utilities for text and shape drawing on a canvas 5 // Created: 2002-08-23 6 // Ver: $Id: jpgraph_canvtools.php 1857 2009-09-28 14:38:14Z ljp $ 7 // 8 // Copyright (c) Asial Corporation. All rights reserved. 9 //======================================================================== 10 */ 11 12define('CORNER_TOPLEFT',0); 13define('CORNER_TOPRIGHT',1); 14define('CORNER_BOTTOMRIGHT',2); 15define('CORNER_BOTTOMLEFT',3); 16 17 18//=================================================== 19// CLASS CanvasScale 20// Description: Define a scale for canvas so we 21// can abstract away with absolute pixels 22//=================================================== 23 24class CanvasScale { 25 private $g; 26 private $w,$h; 27 private $ixmin=0,$ixmax=10,$iymin=0,$iymax=10; 28 29 function __construct($graph,$xmin=0,$xmax=10,$ymin=0,$ymax=10) { 30 $this->g = $graph; 31 $this->w = $graph->img->width; 32 $this->h = $graph->img->height; 33 $this->ixmin = $xmin; 34 $this->ixmax = $xmax; 35 $this->iymin = $ymin; 36 $this->iymax = $ymax; 37 } 38 39 function Set($xmin=0,$xmax=10,$ymin=0,$ymax=10) { 40 $this->ixmin = $xmin; 41 $this->ixmax = $xmax; 42 $this->iymin = $ymin; 43 $this->iymax = $ymax; 44 } 45 46 function Get() { 47 return array($this->ixmin,$this->ixmax,$this->iymin,$this->iymax); 48 } 49 50 function Translate($x,$y) { 51 $xp = round(($x-$this->ixmin)/($this->ixmax - $this->ixmin) * $this->w); 52 $yp = round(($y-$this->iymin)/($this->iymax - $this->iymin) * $this->h); 53 return array($xp,$yp); 54 } 55 56 function TranslateX($x) { 57 $xp = round(($x-$this->ixmin)/($this->ixmax - $this->ixmin) * $this->w); 58 return $xp; 59 } 60 61 function TranslateY($y) { 62 $yp = round(($y-$this->iymin)/($this->iymax - $this->iymin) * $this->h); 63 return $yp; 64 } 65 66} 67 68 69//=================================================== 70// CLASS Shape 71// Description: Methods to draw shapes on canvas 72//=================================================== 73class Shape { 74 private $img,$scale; 75 76 function __construct($aGraph,$scale) { 77 $this->img = $aGraph->img; 78 $this->img->SetColor('black'); 79 $this->scale = $scale; 80 } 81 82 function SetColor($aColor) { 83 $this->img->SetColor($aColor); 84 } 85 86 function Line($x1,$y1,$x2,$y2) { 87 list($x1,$y1) = $this->scale->Translate($x1,$y1); 88 list($x2,$y2) = $this->scale->Translate($x2,$y2); 89 $this->img->Line($x1,$y1,$x2,$y2); 90 } 91 92 function SetLineWeight($aWeight) { 93 $this->img->SetLineWeight($aWeight); 94 } 95 96 function Polygon($p,$aClosed=false) { 97 $n=count($p); 98 for($i=0; $i < $n; $i+=2 ) { 99 $p[$i] = $this->scale->TranslateX($p[$i]); 100 $p[$i+1] = $this->scale->TranslateY($p[$i+1]); 101 } 102 $this->img->Polygon($p,$aClosed); 103 } 104 105 function FilledPolygon($p) { 106 $n=count($p); 107 for($i=0; $i < $n; $i+=2 ) { 108 $p[$i] = $this->scale->TranslateX($p[$i]); 109 $p[$i+1] = $this->scale->TranslateY($p[$i+1]); 110 } 111 $this->img->FilledPolygon($p); 112 } 113 114 115 // Draw a bezier curve with defining points in the $aPnts array 116 // using $aSteps steps. 117 // 0=x0, 1=y0 118 // 2=x1, 3=y1 119 // 4=x2, 5=y2 120 // 6=x3, 7=y3 121 function Bezier($p,$aSteps=40) { 122 $x0 = $p[0]; 123 $y0 = $p[1]; 124 // Calculate coefficients 125 $cx = 3*($p[2]-$p[0]); 126 $bx = 3*($p[4]-$p[2])-$cx; 127 $ax = $p[6]-$p[0]-$cx-$bx; 128 $cy = 3*($p[3]-$p[1]); 129 $by = 3*($p[5]-$p[3])-$cy; 130 $ay = $p[7]-$p[1]-$cy-$by; 131 132 // Step size 133 $delta = 1.0/$aSteps; 134 135 $x_old = $x0; 136 $y_old = $y0; 137 for($t=$delta; $t<=1.0; $t+=$delta) { 138 $tt = $t*$t; $ttt=$tt*$t; 139 $x = $ax*$ttt + $bx*$tt + $cx*$t + $x0; 140 $y = $ay*$ttt + $by*$tt + $cy*$t + $y0; 141 $this->Line($x_old,$y_old,$x,$y); 142 $x_old = $x; 143 $y_old = $y; 144 } 145 $this->Line($x_old,$y_old,$p[6],$p[7]); 146 } 147 148 function Rectangle($x1,$y1,$x2,$y2) { 149 list($x1,$y1) = $this->scale->Translate($x1,$y1); 150 list($x2,$y2) = $this->scale->Translate($x2,$y2); 151 $this->img->Rectangle($x1,$y1,$x2,$y2); 152 } 153 154 function FilledRectangle($x1,$y1,$x2,$y2) { 155 list($x1,$y1) = $this->scale->Translate($x1,$y1); 156 list($x2,$y2) = $this->scale->Translate($x2,$y2); 157 $this->img->FilledRectangle($x1,$y1,$x2,$y2); 158 } 159 160 function Circle($x1,$y1,$r) { 161 list($x1,$y1) = $this->scale->Translate($x1,$y1); 162 if( $r >= 0 ) 163 $r = $this->scale->TranslateX($r); 164 else 165 $r = -$r; 166 $this->img->Circle($x1,$y1,$r); 167 } 168 169 function FilledCircle($x1,$y1,$r) { 170 list($x1,$y1) = $this->scale->Translate($x1,$y1); 171 if( $r >= 0 ) 172 $r = $this->scale->TranslateX($r); 173 else 174 $r = -$r; 175 $this->img->FilledCircle($x1,$y1,$r); 176 } 177 178 function RoundedRectangle($x1,$y1,$x2,$y2,$r=null) { 179 list($x1,$y1) = $this->scale->Translate($x1,$y1); 180 list($x2,$y2) = $this->scale->Translate($x2,$y2); 181 182 if( $r == null ) 183 $r = 5; 184 elseif( $r >= 0 ) 185 $r = $this->scale->TranslateX($r); 186 else 187 $r = -$r; 188 $this->img->RoundedRectangle($x1,$y1,$x2,$y2,$r); 189 } 190 191 function FilledRoundedRectangle($x1,$y1,$x2,$y2,$r=null) { 192 list($x1,$y1) = $this->scale->Translate($x1,$y1); 193 list($x2,$y2) = $this->scale->Translate($x2,$y2); 194 195 if( $r == null ) 196 $r = 5; 197 elseif( $r > 0 ) 198 $r = $this->scale->TranslateX($r); 199 else 200 $r = -$r; 201 $this->img->FilledRoundedRectangle($x1,$y1,$x2,$y2,$r); 202 } 203 204 function ShadowRectangle($x1,$y1,$x2,$y2,$fcolor=false,$shadow_width=null,$shadow_color=array(102,102,102)) { 205 list($x1,$y1) = $this->scale->Translate($x1,$y1); 206 list($x2,$y2) = $this->scale->Translate($x2,$y2); 207 if( $shadow_width == null ) 208 $shadow_width=4; 209 else 210 $shadow_width=$this->scale->TranslateX($shadow_width); 211 $this->img->ShadowRectangle($x1,$y1,$x2,$y2,$fcolor,$shadow_width,$shadow_color); 212 } 213 214 function SetTextAlign($halign,$valign="bottom") { 215 $this->img->SetTextAlign($halign,$valign="bottom"); 216 } 217 218 function StrokeText($x1,$y1,$txt,$dir=0,$paragraph_align="left") { 219 list($x1,$y1) = $this->scale->Translate($x1,$y1); 220 $this->img->StrokeText($x1,$y1,$txt,$dir,$paragraph_align); 221 } 222 223 // A rounded rectangle where one of the corner has been moved "into" the 224 // rectangle 'iw' width and 'ih' height. Corners: 225 // 0=Top left, 1=top right, 2=bottom right, 3=bottom left 226 function IndentedRectangle($xt,$yt,$w,$h,$iw=0,$ih=0,$aCorner=3,$aFillColor="",$r=4) { 227 228 list($xt,$yt) = $this->scale->Translate($xt,$yt); 229 list($w,$h) = $this->scale->Translate($w,$h); 230 list($iw,$ih) = $this->scale->Translate($iw,$ih); 231 232 $xr = $xt + $w - 0; 233 $yl = $yt + $h - 0; 234 235 switch( $aCorner ) { 236 case 0: // Upper left 237 238 // Bottom line, left & right arc 239 $this->img->Line($xt+$r,$yl,$xr-$r,$yl); 240 $this->img->Arc($xt+$r,$yl-$r,$r*2,$r*2,90,180); 241 $this->img->Arc($xr-$r,$yl-$r,$r*2,$r*2,0,90); 242 243 // Right line, Top right arc 244 $this->img->Line($xr,$yt+$r,$xr,$yl-$r); 245 $this->img->Arc($xr-$r,$yt+$r,$r*2,$r*2,270,360); 246 247 // Top line, Top left arc 248 $this->img->Line($xt+$iw+$r,$yt,$xr-$r,$yt); 249 $this->img->Arc($xt+$iw+$r,$yt+$r,$r*2,$r*2,180,270); 250 251 // Left line 252 $this->img->Line($xt,$yt+$ih+$r,$xt,$yl-$r); 253 254 // Indent horizontal, Lower left arc 255 $this->img->Line($xt+$r,$yt+$ih,$xt+$iw-$r,$yt+$ih); 256 $this->img->Arc($xt+$r,$yt+$ih+$r,$r*2,$r*2,180,270); 257 258 // Indent vertical, Indent arc 259 $this->img->Line($xt+$iw,$yt+$r,$xt+$iw,$yt+$ih-$r); 260 $this->img->Arc($xt+$iw-$r,$yt+$ih-$r,$r*2,$r*2,0,90); 261 262 if( $aFillColor != '' ) { 263 $bc = $this->img->current_color_name; 264 $this->img->PushColor($aFillColor); 265 $this->img->FillToBorder($xr-$r,$yl-$r,$bc); 266 $this->img->PopColor(); 267 } 268 269 break; 270 271 case 1: // Upper right 272 273 // Bottom line, left & right arc 274 $this->img->Line($xt+$r,$yl,$xr-$r,$yl); 275 $this->img->Arc($xt+$r,$yl-$r,$r*2,$r*2,90,180); 276 $this->img->Arc($xr-$r,$yl-$r,$r*2,$r*2,0,90); 277 278 // Left line, Top left arc 279 $this->img->Line($xt,$yt+$r,$xt,$yl-$r); 280 $this->img->Arc($xt+$r,$yt+$r,$r*2,$r*2,180,270); 281 282 // Top line, Top right arc 283 $this->img->Line($xt+$r,$yt,$xr-$iw-$r,$yt); 284 $this->img->Arc($xr-$iw-$r,$yt+$r,$r*2,$r*2,270,360); 285 286 // Right line 287 $this->img->Line($xr,$yt+$ih+$r,$xr,$yl-$r); 288 289 // Indent horizontal, Lower right arc 290 $this->img->Line($xr-$iw+$r,$yt+$ih,$xr-$r,$yt+$ih); 291 $this->img->Arc($xr-$r,$yt+$ih+$r,$r*2,$r*2,270,360); 292 293 // Indent vertical, Indent arc 294 $this->img->Line($xr-$iw,$yt+$r,$xr-$iw,$yt+$ih-$r); 295 $this->img->Arc($xr-$iw+$r,$yt+$ih-$r,$r*2,$r*2,90,180); 296 297 if( $aFillColor != '' ) { 298 $bc = $this->img->current_color_name; 299 $this->img->PushColor($aFillColor); 300 $this->img->FillToBorder($xt+$r,$yl-$r,$bc); 301 $this->img->PopColor(); 302 } 303 304 break; 305 306 case 2: // Lower right 307 // Top line, Top left & Top right arc 308 $this->img->Line($xt+$r,$yt,$xr-$r,$yt); 309 $this->img->Arc($xt+$r,$yt+$r,$r*2,$r*2,180,270); 310 $this->img->Arc($xr-$r,$yt+$r,$r*2,$r*2,270,360); 311 312 // Left line, Bottom left arc 313 $this->img->Line($xt,$yt+$r,$xt,$yl-$r); 314 $this->img->Arc($xt+$r,$yl-$r,$r*2,$r*2,90,180); 315 316 // Bottom line, Bottom right arc 317 $this->img->Line($xt+$r,$yl,$xr-$iw-$r,$yl); 318 $this->img->Arc($xr-$iw-$r,$yl-$r,$r*2,$r*2,0,90); 319 320 // Right line 321 $this->img->Line($xr,$yt+$r,$xr,$yl-$ih-$r); 322 323 // Indent horizontal, Lower right arc 324 $this->img->Line($xr-$r,$yl-$ih,$xr-$iw+$r,$yl-$ih); 325 $this->img->Arc($xr-$r,$yl-$ih-$r,$r*2,$r*2,0,90); 326 327 // Indent vertical, Indent arc 328 $this->img->Line($xr-$iw,$yl-$r,$xr-$iw,$yl-$ih+$r); 329 $this->img->Arc($xr-$iw+$r,$yl-$ih+$r,$r*2,$r*2,180,270); 330 331 if( $aFillColor != '' ) { 332 $bc = $this->img->current_color_name; 333 $this->img->PushColor($aFillColor); 334 $this->img->FillToBorder($xt+$r,$yt+$r,$bc); 335 $this->img->PopColor(); 336 } 337 338 break; 339 340 case 3: // Lower left 341 // Top line, Top left & Top right arc 342 $this->img->Line($xt+$r,$yt,$xr-$r,$yt); 343 $this->img->Arc($xt+$r,$yt+$r,$r*2,$r*2,180,270); 344 $this->img->Arc($xr-$r,$yt+$r,$r*2,$r*2,270,360); 345 346 // Right line, Bottom right arc 347 $this->img->Line($xr,$yt+$r,$xr,$yl-$r); 348 $this->img->Arc($xr-$r,$yl-$r,$r*2,$r*2,0,90); 349 350 // Bottom line, Bottom left arc 351 $this->img->Line($xt+$iw+$r,$yl,$xr-$r,$yl); 352 $this->img->Arc($xt+$iw+$r,$yl-$r,$r*2,$r*2,90,180); 353 354 // Left line 355 $this->img->Line($xt,$yt+$r,$xt,$yl-$ih-$r); 356 357 // Indent horizontal, Lower left arc 358 $this->img->Line($xt+$r,$yl-$ih,$xt+$iw-$r,$yl-$ih); 359 $this->img->Arc($xt+$r,$yl-$ih-$r,$r*2,$r*2,90,180); 360 361 // Indent vertical, Indent arc 362 $this->img->Line($xt+$iw,$yl-$ih+$r,$xt+$iw,$yl-$r); 363 $this->img->Arc($xt+$iw-$r,$yl-$ih+$r,$r*2,$r*2,270,360); 364 365 if( $aFillColor != '' ) { 366 $bc = $this->img->current_color_name; 367 $this->img->PushColor($aFillColor); 368 $this->img->FillToBorder($xr-$r,$yt+$r,$bc); 369 $this->img->PopColor(); 370 } 371 372 break; 373 } 374 } 375} 376 377 378//=================================================== 379// CLASS RectangleText 380// Description: Draws a text paragraph inside a 381// rounded, possible filled, rectangle. 382//=================================================== 383class CanvasRectangleText { 384 private $ix,$iy,$iw,$ih,$ir=4; 385 private $iTxt,$iColor='black',$iFillColor='',$iFontColor='black'; 386 private $iParaAlign='center'; 387 private $iAutoBoxMargin=5; 388 private $iShadowWidth=3,$iShadowColor=''; 389 390 function __construct($aTxt='',$xl=0,$yt=0,$w=0,$h=0) { 391 $this->iTxt = new Text($aTxt); 392 $this->ix = $xl; 393 $this->iy = $yt; 394 $this->iw = $w; 395 $this->ih = $h; 396 } 397 398 function SetShadow($aColor='gray',$aWidth=3) { 399 $this->iShadowColor = $aColor; 400 $this->iShadowWidth = $aWidth; 401 } 402 403 function SetFont($FontFam,$aFontStyle,$aFontSize=12) { 404 $this->iTxt->SetFont($FontFam,$aFontStyle,$aFontSize); 405 } 406 407 function SetTxt($aTxt) { 408 $this->iTxt->Set($aTxt); 409 } 410 411 function ParagraphAlign($aParaAlign) { 412 $this->iParaAlign = $aParaAlign; 413 } 414 415 function SetFillColor($aFillColor) { 416 $this->iFillColor = $aFillColor; 417 } 418 419 function SetAutoMargin($aMargin) { 420 $this->iAutoBoxMargin=$aMargin; 421 } 422 423 function SetColor($aColor) { 424 $this->iColor = $aColor; 425 } 426 427 function SetFontColor($aColor) { 428 $this->iFontColor = $aColor; 429 } 430 431 function SetPos($xl=0,$yt=0,$w=0,$h=0) { 432 $this->ix = $xl; 433 $this->iy = $yt; 434 $this->iw = $w; 435 $this->ih = $h; 436 } 437 438 function Pos($xl=0,$yt=0,$w=0,$h=0) { 439 $this->ix = $xl; 440 $this->iy = $yt; 441 $this->iw = $w; 442 $this->ih = $h; 443 } 444 445 function Set($aTxt,$xl,$yt,$w=0,$h=0) { 446 $this->iTxt->Set($aTxt); 447 $this->ix = $xl; 448 $this->iy = $yt; 449 $this->iw = $w; 450 $this->ih = $h; 451 } 452 453 function SetCornerRadius($aRad=5) { 454 $this->ir = $aRad; 455 } 456 457 function Stroke($aImg,$scale) { 458 459 // If coordinates are specifed as negative this means we should 460 // treat them as abolsute (pixels) coordinates 461 if( $this->ix > 0 ) { 462 $this->ix = $scale->TranslateX($this->ix) ; 463 } 464 else { 465 $this->ix = -$this->ix; 466 } 467 468 if( $this->iy > 0 ) { 469 $this->iy = $scale->TranslateY($this->iy) ; 470 } 471 else { 472 $this->iy = -$this->iy; 473 } 474 475 list($this->iw,$this->ih) = $scale->Translate($this->iw,$this->ih) ; 476 477 if( $this->iw == 0 ) 478 $this->iw = round($this->iTxt->GetWidth($aImg) + $this->iAutoBoxMargin); 479 if( $this->ih == 0 ) { 480 $this->ih = round($this->iTxt->GetTextHeight($aImg) + $this->iAutoBoxMargin); 481 } 482 483 if( $this->iShadowColor != '' ) { 484 $aImg->PushColor($this->iShadowColor); 485 $aImg->FilledRoundedRectangle($this->ix+$this->iShadowWidth, 486 $this->iy+$this->iShadowWidth, 487 $this->ix+$this->iw-1+$this->iShadowWidth, 488 $this->iy+$this->ih-1+$this->iShadowWidth, 489 $this->ir); 490 $aImg->PopColor(); 491 } 492 493 if( $this->iFillColor != '' ) { 494 $aImg->PushColor($this->iFillColor); 495 $aImg->FilledRoundedRectangle($this->ix,$this->iy, 496 $this->ix+$this->iw-1, 497 $this->iy+$this->ih-1, 498 $this->ir); 499 $aImg->PopColor(); 500 } 501 502 if( $this->iColor != '' ) { 503 $aImg->PushColor($this->iColor); 504 $aImg->RoundedRectangle($this->ix,$this->iy, 505 $this->ix+$this->iw-1, 506 $this->iy+$this->ih-1, 507 $this->ir); 508 $aImg->PopColor(); 509 } 510 511 $this->iTxt->Align('center','center'); 512 $this->iTxt->ParagraphAlign($this->iParaAlign); 513 $this->iTxt->SetColor($this->iFontColor); 514 $this->iTxt->Stroke($aImg, $this->ix+$this->iw/2, $this->iy+$this->ih/2); 515 516 return array($this->iw, $this->ih); 517 518 } 519 520} 521 522 523?> 524