diff options
Diffstat (limited to 'html/jpgraph/jpgraph_plotband.php')
-rw-r--r-- | html/jpgraph/jpgraph_plotband.php | 635 |
1 files changed, 635 insertions, 0 deletions
diff --git a/html/jpgraph/jpgraph_plotband.php b/html/jpgraph/jpgraph_plotband.php new file mode 100644 index 0000000..b7aef75 --- /dev/null +++ b/html/jpgraph/jpgraph_plotband.php @@ -0,0 +1,635 @@ +<?php +//======================================================================= +// File: JPGRAPH_PLOTBAND.PHP +// Description: PHP4 Graph Plotting library. Extension module. +// Created: 2004-02-18 +// Ver: $Id: jpgraph_plotband.php 1106 2009-02-22 20:16:35Z ljp $ +// +// Copyright (c) Asial Corporation. All rights reserved. +//======================================================================== + +// Constants for types of static bands in plot area +define("BAND_RDIAG",1); // Right diagonal lines +define("BAND_LDIAG",2); // Left diagonal lines +define("BAND_SOLID",3); // Solid one color +define("BAND_VLINE",4); // Vertical lines +define("BAND_HLINE",5); // Horizontal lines +define("BAND_3DPLANE",6); // "3D" Plane +define("BAND_HVCROSS",7); // Vertical/Hor crosses +define("BAND_DIAGCROSS",8); // Diagonal crosses + + +// Utility class to hold coordinates for a rectangle +class Rectangle { + public $x,$y,$w,$h; + public $xe, $ye; + function __construct($aX,$aY,$aWidth,$aHeight) { + $this->x=$aX; + $this->y=$aY; + $this->w=$aWidth; + $this->h=$aHeight; + $this->xe=$aX+$aWidth-1; + $this->ye=$aY+$aHeight-1; + } +} + +//===================================================================== +// Class RectPattern +// Base class for pattern hierarchi that is used to display patterned +// bands on the graph. Any subclass that doesn't override Stroke() +// must at least implement method DoPattern($aImg) which is responsible +// for drawing the pattern onto the graph. +//===================================================================== +class RectPattern { + protected $color; + protected $weight; + protected $rect=null; + protected $doframe=true; + protected $linespacing; // Line spacing in pixels + protected $iBackgroundColor=-1; // Default is no background fill + + function __construct($aColor,$aWeight=1) { + $this->color = $aColor; + $this->weight = $aWeight; + } + + function SetBackground($aBackgroundColor) { + $this->iBackgroundColor=$aBackgroundColor; + } + + function SetPos($aRect) { + $this->rect = $aRect; + } + + function ShowFrame($aShow=true) { + $this->doframe=$aShow; + } + + function SetDensity($aDens) { + if( $aDens < 1 || $aDens > 100 ) + JpGraphError::RaiseL(16001,$aDens); + //(" Desity for pattern must be between 1 and 100. (You tried $aDens)"); + // 1% corresponds to linespacing=50 + // 100 % corresponds to linespacing 1 + $this->linespacing = floor(((100-$aDens)/100.0)*50)+1; + + } + + function Stroke($aImg) { + if( $this->rect == null ) + JpGraphError::RaiseL(16002); + //(" No positions specified for pattern."); + + if( !(is_numeric($this->iBackgroundColor) && $this->iBackgroundColor==-1) ) { + $aImg->SetColor($this->iBackgroundColor); + $aImg->FilledRectangle($this->rect->x,$this->rect->y,$this->rect->xe,$this->rect->ye); + } + + $aImg->SetColor($this->color); + $aImg->SetLineWeight($this->weight); + + // Virtual function implemented by subclass + $this->DoPattern($aImg); + + // Frame around the pattern area + if( $this->doframe ) + $aImg->Rectangle($this->rect->x,$this->rect->y,$this->rect->xe,$this->rect->ye); + } + +} + + +//===================================================================== +// Class RectPatternSolid +// Implements a solid band +//===================================================================== +class RectPatternSolid extends RectPattern { + + function __construct($aColor="black",$aWeight=1) { + parent::__construct($aColor,$aWeight); + } + + function DoPattern($aImg) { + $aImg->SetColor($this->color); + $aImg->FilledRectangle($this->rect->x,$this->rect->y, + $this->rect->xe,$this->rect->ye); + } +} + +//===================================================================== +// Class RectPatternHor +// Implements horizontal line pattern +//===================================================================== +class RectPatternHor extends RectPattern { + + function __construct($aColor="black",$aWeight=1,$aLineSpacing=7) { + parent::__construct($aColor,$aWeight); + $this->linespacing = $aLineSpacing; + } + + function DoPattern($aImg) { + $x0 = $this->rect->x; + $x1 = $this->rect->xe; + $y = $this->rect->y; + while( $y < $this->rect->ye ) { + $aImg->Line($x0,$y,$x1,$y); + $y += $this->linespacing; + } + } +} + +//===================================================================== +// Class RectPatternVert +// Implements vertical line pattern +//===================================================================== +class RectPatternVert extends RectPattern { + + function __construct($aColor="black",$aWeight=1,$aLineSpacing=7) { + parent::__construct($aColor,$aWeight); + $this->linespacing = $aLineSpacing; + } + + //-------------------- + // Private methods + // + function DoPattern($aImg) { + $x = $this->rect->x; + $y0 = $this->rect->y; + $y1 = $this->rect->ye; + while( $x < $this->rect->xe ) { + $aImg->Line($x,$y0,$x,$y1); + $x += $this->linespacing; + } + } +} + + +//===================================================================== +// Class RectPatternRDiag +// Implements right diagonal pattern +//===================================================================== +class RectPatternRDiag extends RectPattern { + + function __construct($aColor="black",$aWeight=1,$aLineSpacing=12) { + parent::__construct($aColor,$aWeight); + $this->linespacing = $aLineSpacing; + } + + function DoPattern($aImg) { + // -------------------- + // | / / / / /| + // |/ / / / / | + // | / / / / | + // -------------------- + $xe = $this->rect->xe; + $ye = $this->rect->ye; + $x0 = $this->rect->x + round($this->linespacing/2); + $y0 = $this->rect->y; + $x1 = $this->rect->x; + $y1 = $this->rect->y + round($this->linespacing/2); + + while($x0<=$xe && $y1<=$ye) { + $aImg->Line($x0,$y0,$x1,$y1); + $x0 += $this->linespacing; + $y1 += $this->linespacing; + } + + if( $xe-$x1 > $ye-$y0 ) { + // Width larger than height + $x1 = $this->rect->x + ($y1-$ye); + $y1 = $ye; + $y0 = $this->rect->y; + while( $x0 <= $xe ) { + $aImg->Line($x0,$y0,$x1,$y1); + $x0 += $this->linespacing; + $x1 += $this->linespacing; + } + + $y0=$this->rect->y + ($x0-$xe); + $x0=$xe; + } + else { + // Height larger than width + $diff = $x0-$xe; + $y0 = $diff+$this->rect->y; + $x0 = $xe; + $x1 = $this->rect->x; + while( $y1 <= $ye ) { + $aImg->Line($x0,$y0,$x1,$y1); + $y1 += $this->linespacing; + $y0 += $this->linespacing; + } + + $diff = $y1-$ye; + $y1 = $ye; + $x1 = $diff + $this->rect->x; + } + + while( $y0 <= $ye ) { + $aImg->Line($x0,$y0,$x1,$y1); + $y0 += $this->linespacing; + $x1 += $this->linespacing; + } + } +} + +//===================================================================== +// Class RectPatternLDiag +// Implements left diagonal pattern +//===================================================================== +class RectPatternLDiag extends RectPattern { + + function __construct($aColor="black",$aWeight=1,$aLineSpacing=12) { + $this->linespacing = $aLineSpacing; + parent::__construct($aColor,$aWeight); + } + + function DoPattern($aImg) { + // -------------------- + // |\ \ \ \ \ | + // | \ \ \ \ \| + // | \ \ \ \ | + // |------------------| + $xe = $this->rect->xe; + $ye = $this->rect->ye; + $x0 = $this->rect->x + round($this->linespacing/2); + $y0 = $this->rect->ye; + $x1 = $this->rect->x; + $y1 = $this->rect->ye - round($this->linespacing/2); + + while($x0<=$xe && $y1>=$this->rect->y) { + $aImg->Line($x0,$y0,$x1,$y1); + $x0 += $this->linespacing; + $y1 -= $this->linespacing; + } + if( $xe-$x1 > $ye-$this->rect->y ) { + // Width larger than height + $x1 = $this->rect->x + ($this->rect->y-$y1); + $y0=$ye; $y1=$this->rect->y; + while( $x0 <= $xe ) { + $aImg->Line($x0,$y0,$x1,$y1); + $x0 += $this->linespacing; + $x1 += $this->linespacing; + } + + $y0=$this->rect->ye - ($x0-$xe); + $x0=$xe; + } + else { + // Height larger than width + $diff = $x0-$xe; + $y0 = $ye-$diff; + $x0 = $xe; + while( $y1 >= $this->rect->y ) { + $aImg->Line($x0,$y0,$x1,$y1); + $y0 -= $this->linespacing; + $y1 -= $this->linespacing; + } + $diff = $this->rect->y - $y1; + $x1 = $this->rect->x + $diff; + $y1 = $this->rect->y; + } + while( $y0 >= $this->rect->y ) { + $aImg->Line($x0,$y0,$x1,$y1); + $y0 -= $this->linespacing; + $x1 += $this->linespacing; + } + } +} + +//===================================================================== +// Class RectPattern3DPlane +// Implements "3D" plane pattern +//===================================================================== +class RectPattern3DPlane extends RectPattern { + private $alpha=50; // Parameter that specifies the distance + // to "simulated" horizon in pixel from the + // top of the band. Specifies how fast the lines + // converge. + + function __construct($aColor="black",$aWeight=1) { + parent::__construct($aColor,$aWeight); + $this->SetDensity(10); // Slightly larger default + } + + function SetHorizon($aHorizon) { + $this->alpha=$aHorizon; + } + + function DoPattern($aImg) { + // "Fake" a nice 3D grid-effect. + $x0 = $this->rect->x + $this->rect->w/2; + $y0 = $this->rect->y; + $x1 = $x0; + $y1 = $this->rect->ye; + $x0_right = $x0; + $x1_right = $x1; + + // BTW "apa" means monkey in Swedish but is really a shortform for + // "alpha+a" which was the labels I used on paper when I derived the + // geometric to get the 3D perspective right. + // $apa is the height of the bounding rectangle plus the distance to the + // artifical horizon (alpha) + $apa = $this->rect->h + $this->alpha; + + // Three cases and three loops + // 1) The endpoint of the line ends on the bottom line + // 2) The endpoint ends on the side + // 3) Horizontal lines + + // Endpoint falls on bottom line + $middle=$this->rect->x + $this->rect->w/2; + $dist=$this->linespacing; + $factor=$this->alpha /($apa); + while($x1>$this->rect->x) { + $aImg->Line($x0,$y0,$x1,$y1); + $aImg->Line($x0_right,$y0,$x1_right,$y1); + $x1 = $middle - $dist; + $x0 = $middle - $dist * $factor; + $x1_right = $middle + $dist; + $x0_right = $middle + $dist * $factor; + $dist += $this->linespacing; + } + + // Endpoint falls on sides + $dist -= $this->linespacing; + $d=$this->rect->w/2; + $c = $apa - $d*$apa/$dist; + while( $x0>$this->rect->x ) { + $aImg->Line($x0,$y0,$this->rect->x,$this->rect->ye-$c); + $aImg->Line($x0_right,$y0,$this->rect->xe,$this->rect->ye-$c); + $dist += $this->linespacing; + $x0 = $middle - $dist * $factor; + $x1 = $middle - $dist; + $x0_right = $middle + $dist * $factor; + $c = $apa - $d*$apa/$dist; + } + + // Horizontal lines + // They need some serious consideration since they are a function + // of perspective depth (alpha) and density (linespacing) + $x0=$this->rect->x; + $x1=$this->rect->xe; + $y=$this->rect->ye; + + // The first line is drawn directly. Makes the loop below slightly + // more readable. + $aImg->Line($x0,$y,$x1,$y); + $hls = $this->linespacing; + + // A correction factor for vertical "brick" line spacing to account for + // a) the difference in number of pixels hor vs vert + // b) visual apperance to make the first layer of "bricks" look more + // square. + $vls = $this->linespacing*0.6; + + $ds = $hls*($apa-$vls)/$apa; + // Get the slope for the "perspective line" going from bottom right + // corner to top left corner of the "first" brick. + + // Uncomment the following lines if you want to get a visual understanding + // of what this helpline does. BTW this mimics the way you would get the + // perspective right when drawing on paper. + /* + $x0 = $middle; + $y0 = $this->rect->ye; + $len=floor(($this->rect->ye-$this->rect->y)/$vls); + $x1 = $middle+round($len*$ds); + $y1 = $this->rect->ye-$len*$vls; + $aImg->PushColor("red"); + $aImg->Line($x0,$y0,$x1,$y1); + $aImg->PopColor(); + */ + + $y -= $vls; + $k=($this->rect->ye-($this->rect->ye-$vls))/($middle-($middle-$ds)); + $dist = $hls; + while( $y>$this->rect->y ) { + $aImg->Line($this->rect->x,$y,$this->rect->xe,$y); + $adj = $k*$dist/(1+$dist*$k/$apa); + if( $adj < 2 ) $adj=1; + $y = $this->rect->ye - round($adj); + $dist += $hls; + } + } +} + +//===================================================================== +// Class RectPatternCross +// Vert/Hor crosses +//===================================================================== +class RectPatternCross extends RectPattern { + private $vert=null; + private $hor=null; + function __construct($aColor="black",$aWeight=1) { + parent::__construct($aColor,$aWeight); + $this->vert = new RectPatternVert($aColor,$aWeight); + $this->hor = new RectPatternHor($aColor,$aWeight); + } + + function SetOrder($aDepth) { + $this->vert->SetOrder($aDepth); + $this->hor->SetOrder($aDepth); + } + + function SetPos($aRect) { + parent::SetPos($aRect); + $this->vert->SetPos($aRect); + $this->hor->SetPos($aRect); + } + + function SetDensity($aDens) { + $this->vert->SetDensity($aDens); + $this->hor->SetDensity($aDens); + } + + function DoPattern($aImg) { + $this->vert->DoPattern($aImg); + $this->hor->DoPattern($aImg); + } +} + +//===================================================================== +// Class RectPatternDiagCross +// Vert/Hor crosses +//===================================================================== + +class RectPatternDiagCross extends RectPattern { + private $left=null; + private $right=null; + function __construct($aColor="black",$aWeight=1) { + parent::__construct($aColor,$aWeight); + $this->right = new RectPatternRDiag($aColor,$aWeight); + $this->left = new RectPatternLDiag($aColor,$aWeight); + } + + function SetOrder($aDepth) { + $this->left->SetOrder($aDepth); + $this->right->SetOrder($aDepth); + } + + function SetPos($aRect) { + parent::SetPos($aRect); + $this->left->SetPos($aRect); + $this->right->SetPos($aRect); + } + + function SetDensity($aDens) { + $this->left->SetDensity($aDens); + $this->right->SetDensity($aDens); + } + + function DoPattern($aImg) { + $this->left->DoPattern($aImg); + $this->right->DoPattern($aImg); + } + +} + +//===================================================================== +// Class RectPatternFactory +// Factory class for rectangular pattern +//===================================================================== +class RectPatternFactory { + function __construct() { + // Empty + } + function Create($aPattern,$aColor,$aWeight=1) { + switch($aPattern) { + case BAND_RDIAG: + $obj = new RectPatternRDiag($aColor,$aWeight); + break; + case BAND_LDIAG: + $obj = new RectPatternLDiag($aColor,$aWeight); + break; + case BAND_SOLID: + $obj = new RectPatternSolid($aColor,$aWeight); + break; + case BAND_VLINE: + $obj = new RectPatternVert($aColor,$aWeight); + break; + case BAND_HLINE: + $obj = new RectPatternHor($aColor,$aWeight); + break; + case BAND_3DPLANE: + $obj = new RectPattern3DPlane($aColor,$aWeight); + break; + case BAND_HVCROSS: + $obj = new RectPatternCross($aColor,$aWeight); + break; + case BAND_DIAGCROSS: + $obj = new RectPatternDiagCross($aColor,$aWeight); + break; + default: + JpGraphError::RaiseL(16003,$aPattern); + //(" Unknown pattern specification ($aPattern)"); + } + return $obj; + } +} + + +//===================================================================== +// Class PlotBand +// Factory class which is used by the client. +// It is responsible for factoring the corresponding pattern +// concrete class. +//===================================================================== +class PlotBand { + public $depth; // Determine if band should be over or under the plots + private $prect=null; + private $dir, $min, $max; + + function __construct($aDir,$aPattern,$aMin,$aMax,$aColor="black",$aWeight=1,$aDepth=DEPTH_BACK) { + $f = new RectPatternFactory(); + $this->prect = $f->Create($aPattern,$aColor,$aWeight); + if( is_numeric($aMin) && is_numeric($aMax) && ($aMin > $aMax) ) + JpGraphError::RaiseL(16004); + //('Min value for plotband is larger than specified max value. Please correct.'); + $this->dir = $aDir; + $this->min = $aMin; + $this->max = $aMax; + $this->depth=$aDepth; + } + + // Set position. aRect contains absolute image coordinates + function SetPos($aRect) { + assert( $this->prect != null ) ; + $this->prect->SetPos($aRect); + } + + function ShowFrame($aFlag=true) { + $this->prect->ShowFrame($aFlag); + } + + // Set z-order. In front of pplot or in the back + function SetOrder($aDepth) { + $this->depth=$aDepth; + } + + function SetDensity($aDens) { + $this->prect->SetDensity($aDens); + } + + function GetDir() { + return $this->dir; + } + + function GetMin() { + return $this->min; + } + + function GetMax() { + return $this->max; + } + + function PreStrokeAdjust($aGraph) { + // Nothing to do + } + + // Display band + function Stroke($aImg,$aXScale,$aYScale) { + assert( $this->prect != null ) ; + if( $this->dir == HORIZONTAL ) { + if( $this->min === 'min' ) $this->min = $aYScale->GetMinVal(); + if( $this->max === 'max' ) $this->max = $aYScale->GetMaxVal(); + + // Only draw the bar if it actually appears in the range + if ($this->min < $aYScale->GetMaxVal() && $this->max > $aYScale->GetMinVal()) { + + // Trucate to limit of axis + $this->min = max($this->min, $aYScale->GetMinVal()); + $this->max = min($this->max, $aYScale->GetMaxVal()); + + $x=$aXScale->scale_abs[0]; + $y=$aYScale->Translate($this->max); + $width=$aXScale->scale_abs[1]-$aXScale->scale_abs[0]+1; + $height=abs($y-$aYScale->Translate($this->min))+1; + $this->prect->SetPos(new Rectangle($x,$y,$width,$height)); + $this->prect->Stroke($aImg); + } + } + else { // VERTICAL + if( $this->min === 'min' ) $this->min = $aXScale->GetMinVal(); + if( $this->max === 'max' ) $this->max = $aXScale->GetMaxVal(); + + // Only draw the bar if it actually appears in the range + if ($this->min < $aXScale->GetMaxVal() && $this->max > $aXScale->GetMinVal()) { + + // Trucate to limit of axis + $this->min = max($this->min, $aXScale->GetMinVal()); + $this->max = min($this->max, $aXScale->GetMaxVal()); + + $y=$aYScale->scale_abs[1]; + $x=$aXScale->Translate($this->min); + $height=abs($aYScale->scale_abs[1]-$aYScale->scale_abs[0]); + $width=abs($x-$aXScale->Translate($this->max)); + $this->prect->SetPos(new Rectangle($x,$y,$width,$height)); + $this->prect->Stroke($aImg); + } + } + } +} + + +?> |