Location: PHPKode > projects > Skat Statistics > skatstat-1.7.1/skatstat/inc/jpgraph/jpgraph_plotband.php
```<?php
//=======================================================================
// File:	JPGRAPH_PLOTBAND.PHP
// Description:	PHP4 Graph Plotting library. Extension module.
// Created: 	2004-02-18
// Ver:		\$Id: jpgraph_plotband.php 782 2006-10-08 08:09:02Z ljp \$
//
//========================================================================

// 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 {
var \$x,\$y,\$w,\$h;
var \$xe, \$ye;
function Rectangle(\$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 {
var \$color;
var \$weight;
var \$rect=null;
var \$doframe=true;
var \$linespacing;	// Line spacing in pixels
var \$iBackgroundColor=-1;  // Default is no background fill

function RectPattern(\$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;
}

//(" Desity for pattern must be between 1 and 100. (You tried \$aDens)");
// 1% corresponds to linespacing=50
// 100 % corresponds to linespacing 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 RectPatternSolid(\$aColor="black",\$aWeight=1) {
parent::RectPattern(\$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 RectPatternHor(\$aColor="black",\$aWeight=1,\$aLineSpacing=7) {
parent::RectPattern(\$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 {
var \$linespacing=10;	// Line spacing in pixels

function RectPatternVert(\$aColor="black",\$aWeight=1,\$aLineSpacing=7) {
parent::RectPattern(\$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 {
var \$linespacing;	// Line spacing in pixels

function RectPatternRDiag(\$aColor="black",\$aWeight=1,\$aLineSpacing=12) {
parent::RectPattern(\$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 {
var \$linespacing;	// Line spacing in pixels

function RectPatternLDiag(\$aColor="black",\$aWeight=1,\$aLineSpacing=12) {
\$this->linespacing = \$aLineSpacing;
parent::RectPattern(\$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 {
var \$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 RectPattern3DPlane(\$aColor="black",\$aWeight=1) {
parent::RectPattern(\$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
\$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);
\$dist += \$hls;
}
}
}

//=====================================================================
// Class RectPatternCross
// Vert/Hor crosses
//=====================================================================
class RectPatternCross extends RectPattern {
var \$vert=null;
var \$hor=null;
function RectPatternCross(\$aColor="black",\$aWeight=1) {
parent::RectPattern(\$aColor,\$aWeight);
\$this->vert = new RectPatternVert(\$aColor,\$aWeight);
\$this->hor  = new RectPatternHor(\$aColor,\$aWeight);
}

}

function SetPos(&\$aRect) {
parent::SetPos(\$aRect);
\$this->vert->SetPos(\$aRect);
\$this->hor->SetPos(\$aRect);
}

}

function DoPattern(&\$aImg) {
\$this->vert->DoPattern(\$aImg);
\$this->hor->DoPattern(\$aImg);
}
}

//=====================================================================
// Class RectPatternDiagCross
// Vert/Hor crosses
//=====================================================================

class RectPatternDiagCross extends RectPattern {
var \$left=null;
var \$right=null;
function RectPatternDiagCross(\$aColor="black",\$aWeight=1) {
parent::RectPattern(\$aColor,\$aWeight);
\$this->right = new RectPatternRDiag(\$aColor,\$aWeight);
\$this->left  = new RectPatternLDiag(\$aColor,\$aWeight);
}

}

function SetPos(&\$aRect) {
parent::SetPos(\$aRect);
\$this->left->SetPos(\$aRect);
\$this->right->SetPos(\$aRect);
}

}

function DoPattern(&\$aImg) {
\$this->left->DoPattern(\$aImg);
\$this->right->DoPattern(\$aImg);
}

}

//=====================================================================
// Class RectPatternFactory
// Factory class for rectangular pattern
//=====================================================================
class RectPatternFactory {
function RectPatternFactory() {
// 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 {
var \$prect=null;
var \$depth;
var \$dir, \$min, \$max;

\$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->min = \$aMin;
\$this->max = \$aMax;
}

// 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 GetDir() {
return \$this->dir;
}

function GetMin() {
return \$this->min;
}

function GetMax() {
return \$this->max;
}

// 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);
}
}
}
}

?>
```