forked from SimplesIP/pabx-app
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1190 lines
46 KiB
1190 lines
46 KiB
<?php |
|
/*======================================================================= |
|
// File: JPGRAPH_BAR.PHP |
|
// Description: Bar plot extension for JpGraph |
|
// Created: 2001-01-08 |
|
// Ver: $Id: jpgraph_bar.php 1905 2009-10-06 18:00:21Z ljp $ |
|
// |
|
// Copyright (c) Asial Corporation. All rights reserved. |
|
//======================================================================== |
|
*/ |
|
|
|
require_once('jpgraph_plotband.php'); |
|
|
|
// Pattern for Bars |
|
DEFINE('PATTERN_DIAG1',1); |
|
DEFINE('PATTERN_DIAG2',2); |
|
DEFINE('PATTERN_DIAG3',3); |
|
DEFINE('PATTERN_DIAG4',4); |
|
DEFINE('PATTERN_CROSS1',5); |
|
DEFINE('PATTERN_CROSS2',6); |
|
DEFINE('PATTERN_CROSS3',7); |
|
DEFINE('PATTERN_CROSS4',8); |
|
DEFINE('PATTERN_STRIPE1',9); |
|
DEFINE('PATTERN_STRIPE2',10); |
|
|
|
//=================================================== |
|
// CLASS BarPlot |
|
// Description: Main code to produce a bar plot |
|
//=================================================== |
|
class BarPlot extends Plot { |
|
public $fill=false,$fill_color="lightblue"; // Default is to fill with light blue |
|
public $iPattern=-1,$iPatternDensity=80,$iPatternColor='black'; |
|
public $valuepos='top'; |
|
public $grad=false,$grad_style=1; |
|
public $grad_fromcolor=array(50,50,200),$grad_tocolor=array(255,255,255); |
|
public $ymin=0; |
|
protected $width=0.4; // in percent of major ticks |
|
protected $abswidth=-1; // Width in absolute pixels |
|
protected $ybase=0; // Bars start at 0 |
|
protected $align="center"; |
|
protected $bar_shadow=false; |
|
protected $bar_shadow_color="black"; |
|
protected $bar_shadow_hsize=3,$bar_shadow_vsize=3; |
|
protected $bar_3d=false; |
|
protected $bar_3d_hsize=3,$bar_3d_vsize=3; |
|
|
|
//--------------- |
|
// CONSTRUCTOR |
|
function __construct($datay,$datax=false) { |
|
parent::__construct($datay,$datax); |
|
++$this->numpoints; |
|
} |
|
|
|
//--------------- |
|
// PUBLIC METHODS |
|
|
|
// Set a drop shadow for the bar (or rather an "up-right" shadow) |
|
function SetShadow($aColor="black",$aHSize=3,$aVSize=3,$aShow=true) { |
|
$this->bar_shadow=$aShow; |
|
$this->bar_shadow_color=$aColor; |
|
$this->bar_shadow_vsize=$aVSize; |
|
$this->bar_shadow_hsize=$aHSize; |
|
|
|
// Adjust the value margin to compensate for shadow |
|
$this->value->margin += $aVSize; |
|
} |
|
|
|
function Set3D($aHSize=3,$aVSize=3,$aShow=true) { |
|
$this->bar_3d=$aShow; |
|
$this->bar_3d_vsize=$aVSize; |
|
$this->bar_3d_hsize=$aHSize; |
|
|
|
$this->value->margin += $aVSize; |
|
} |
|
|
|
// DEPRECATED use SetYBase instead |
|
function SetYMin($aYStartValue) { |
|
//die("JpGraph Error: Deprecated function SetYMin. Use SetYBase() instead."); |
|
$this->ybase=$aYStartValue; |
|
} |
|
|
|
// Specify the base value for the bars |
|
function SetYBase($aYStartValue) { |
|
$this->ybase=$aYStartValue; |
|
} |
|
|
|
// The method will take the specified pattern anre |
|
// return a pattern index that corresponds to the original |
|
// patterm being rotated 90 degreees. This is needed when plottin |
|
// Horizontal bars |
|
function RotatePattern($aPat,$aRotate=true) { |
|
$rotate = array(1 => 2, 2 => 1, 3 => 3, 4 => 5, 5 => 4, 6 => 6, 7 => 7, 8 => 8); |
|
if( $aRotate ) { |
|
return $rotate[$aPat]; |
|
} |
|
else { |
|
return $aPat; |
|
} |
|
} |
|
|
|
function Legend($graph) { |
|
if( $this->grad && $this->legend!="" && !$this->fill ) { |
|
$color=array($this->grad_fromcolor,$this->grad_tocolor); |
|
// In order to differentiate between gradients and cooors specified as an RGB triple |
|
$graph->legend->Add($this->legend,$color,"",-$this->grad_style, |
|
$this->legendcsimtarget,$this->legendcsimalt,$this->legendcsimwintarget); |
|
} |
|
elseif( $this->legend!="" && ($this->iPattern > -1 || is_array($this->iPattern)) ) { |
|
if( is_array($this->iPattern) ) { |
|
$p1 = $this->RotatePattern( $this->iPattern[0], $graph->img->a == 90 ); |
|
$p2 = $this->iPatternColor[0]; |
|
$p3 = $this->iPatternDensity[0]; |
|
} |
|
else { |
|
$p1 = $this->RotatePattern( $this->iPattern, $graph->img->a == 90 ); |
|
$p2 = $this->iPatternColor; |
|
$p3 = $this->iPatternDensity; |
|
} |
|
if( $p3 < 90 ) $p3 += 5; |
|
$color = array($p1,$p2,$p3,$this->fill_color); |
|
// A kludge: Too mark that we add a pattern we use a type value of < 100 |
|
$graph->legend->Add($this->legend,$color,"",-101, |
|
$this->legendcsimtarget,$this->legendcsimalt,$this->legendcsimwintarget); |
|
} |
|
elseif( $this->fill_color && $this->legend!="" ) { |
|
if( is_array($this->fill_color) ) { |
|
$graph->legend->Add($this->legend,$this->fill_color[0],"",0, |
|
$this->legendcsimtarget,$this->legendcsimalt,$this->legendcsimwintarget); |
|
} |
|
else { |
|
$graph->legend->Add($this->legend,$this->fill_color,"",0, |
|
$this->legendcsimtarget,$this->legendcsimalt,$this->legendcsimwintarget); |
|
} |
|
} |
|
} |
|
|
|
// Gets called before any axis are stroked |
|
function PreStrokeAdjust($graph) { |
|
parent::PreStrokeAdjust($graph); |
|
|
|
// If we are using a log Y-scale we want the base to be at the |
|
// minimum Y-value unless the user have specifically set some other |
|
// value than the default. |
|
if( substr($graph->axtype,-3,3)=="log" && $this->ybase==0 ) |
|
$this->ybase = $graph->yaxis->scale->GetMinVal(); |
|
|
|
// For a "text" X-axis scale we will adjust the |
|
// display of the bars a little bit. |
|
if( substr($graph->axtype,0,3)=="tex" ) { |
|
// Position the ticks between the bars |
|
$graph->xaxis->scale->ticks->SetXLabelOffset(0.5,0); |
|
|
|
// Center the bars |
|
if( $this->abswidth > -1 ) { |
|
$graph->SetTextScaleAbsCenterOff($this->abswidth); |
|
} |
|
else { |
|
if( $this->align == "center" ) |
|
$graph->SetTextScaleOff(0.5-$this->width/2); |
|
elseif( $this->align == "right" ) |
|
$graph->SetTextScaleOff(1-$this->width); |
|
} |
|
} |
|
elseif( ($this instanceof AccBarPlot) || ($this instanceof GroupBarPlot) ) { |
|
// We only set an absolute width for linear and int scale |
|
// for text scale the width will be set to a fraction of |
|
// the majstep width. |
|
if( $this->abswidth == -1 ) { |
|
// Not set |
|
// set width to a visuable sensible default |
|
$this->abswidth = $graph->img->plotwidth/(2*$this->numpoints); |
|
} |
|
} |
|
} |
|
|
|
function Min() { |
|
$m = parent::Min(); |
|
if( $m[1] >= $this->ybase ) $m[1] = $this->ybase; |
|
return $m; |
|
} |
|
|
|
function Max() { |
|
$m = parent::Max(); |
|
if( $m[1] <= $this->ybase ) $m[1] = $this->ybase; |
|
return $m; |
|
} |
|
|
|
// Specify width as fractions of the major stepo size |
|
function SetWidth($aWidth) { |
|
if( $aWidth > 1 ) { |
|
// Interpret this as absolute width |
|
$this->abswidth=$aWidth; |
|
} |
|
else { |
|
$this->width=$aWidth; |
|
} |
|
} |
|
|
|
// Specify width in absolute pixels. If specified this |
|
// overrides SetWidth() |
|
function SetAbsWidth($aWidth) { |
|
$this->abswidth=$aWidth; |
|
} |
|
|
|
function SetAlign($aAlign) { |
|
$this->align=$aAlign; |
|
} |
|
|
|
function SetNoFill() { |
|
$this->grad = false; |
|
$this->fill_color=false; |
|
$this->fill=false; |
|
} |
|
|
|
function SetFillColor($aColor) { |
|
// Do an extra error check if the color is specified as an RGB array triple |
|
// In that case convert it to a hex string since it will otherwise be |
|
// interpretated as an array of colors for each individual bar. |
|
|
|
$aColor = RGB::tryHexConversion($aColor); |
|
$this->fill = true ; |
|
$this->fill_color=$aColor; |
|
|
|
} |
|
|
|
function SetFillGradient($aFromColor,$aToColor=null,$aStyle=null) { |
|
$this->grad = true; |
|
$this->grad_fromcolor = $aFromColor; |
|
$this->grad_tocolor = $aToColor; |
|
$this->grad_style = $aStyle; |
|
} |
|
|
|
function SetValuePos($aPos) { |
|
$this->valuepos = $aPos; |
|
} |
|
|
|
function SetPattern($aPattern, $aColor='black'){ |
|
if( is_array($aPattern) ) { |
|
$n = count($aPattern); |
|
$this->iPattern = array(); |
|
$this->iPatternDensity = array(); |
|
if( is_array($aColor) ) { |
|
$this->iPatternColor = array(); |
|
if( count($aColor) != $n ) { |
|
JpGraphError::RaiseL(2001);//('NUmber of colors is not the same as the number of patterns in BarPlot::SetPattern()'); |
|
} |
|
} |
|
else { |
|
$this->iPatternColor = $aColor; |
|
} |
|
for( $i=0; $i < $n; ++$i ) { |
|
$this->_SetPatternHelper($aPattern[$i], $this->iPattern[$i], $this->iPatternDensity[$i]); |
|
if( is_array($aColor) ) { |
|
$this->iPatternColor[$i] = $aColor[$i]; |
|
} |
|
} |
|
} |
|
else { |
|
$this->_SetPatternHelper($aPattern, $this->iPattern, $this->iPatternDensity); |
|
$this->iPatternColor = $aColor; |
|
} |
|
} |
|
|
|
function _SetPatternHelper($aPattern, &$aPatternValue, &$aDensity){ |
|
switch( $aPattern ) { |
|
case PATTERN_DIAG1: |
|
$aPatternValue= 1; |
|
$aDensity = 92; |
|
break; |
|
case PATTERN_DIAG2: |
|
$aPatternValue= 1; |
|
$aDensity = 78; |
|
break; |
|
case PATTERN_DIAG3: |
|
$aPatternValue= 2; |
|
$aDensity = 92; |
|
break; |
|
case PATTERN_DIAG4: |
|
$aPatternValue= 2; |
|
$aDensity = 78; |
|
break; |
|
case PATTERN_CROSS1: |
|
$aPatternValue= 8; |
|
$aDensity = 90; |
|
break; |
|
case PATTERN_CROSS2: |
|
$aPatternValue= 8; |
|
$aDensity = 78; |
|
break; |
|
case PATTERN_CROSS3: |
|
$aPatternValue= 8; |
|
$aDensity = 65; |
|
break; |
|
case PATTERN_CROSS4: |
|
$aPatternValue= 7; |
|
$aDensity = 90; |
|
break; |
|
case PATTERN_STRIPE1: |
|
$aPatternValue= 5; |
|
$aDensity = 94; |
|
break; |
|
case PATTERN_STRIPE2: |
|
$aPatternValue= 5; |
|
$aDensity = 85; |
|
break; |
|
default: |
|
JpGraphError::RaiseL(2002); |
|
//('Unknown pattern specified in call to BarPlot::SetPattern()'); |
|
} |
|
} |
|
|
|
function Stroke($img,$xscale,$yscale) { |
|
|
|
$numpoints = count($this->coords[0]); |
|
if( isset($this->coords[1]) ) { |
|
if( count($this->coords[1])!=$numpoints ) { |
|
JpGraphError::RaiseL(2003,count($this->coords[1]),$numpoints); |
|
//"Number of X and Y points are not equal. Number of X-points:".count($this->coords[1])."Number of Y-points:$numpoints"); |
|
} |
|
else { |
|
$exist_x = true; |
|
} |
|
} |
|
else { |
|
$exist_x = false; |
|
} |
|
|
|
|
|
$numbars=count($this->coords[0]); |
|
|
|
// Use GetMinVal() instead of scale[0] directly since in the case |
|
// of log scale we get a correct value. Log scales will have negative |
|
// values for values < 1 while still not representing negative numbers. |
|
if( $yscale->GetMinVal() >= 0 ) |
|
$zp=$yscale->scale_abs[0]; |
|
else { |
|
$zp=$yscale->Translate(0); |
|
} |
|
|
|
if( $this->abswidth > -1 ) { |
|
$abswidth=$this->abswidth; |
|
} |
|
else { |
|
$abswidth=round($this->width*$xscale->scale_factor,0); |
|
} |
|
|
|
// Count pontetial pattern array to avoid doing the count for each iteration |
|
if( is_array($this->iPattern) ) { |
|
$np = count($this->iPattern); |
|
} |
|
|
|
$grad = null; |
|
for($i=0; $i < $numbars; ++$i) { |
|
|
|
// If value is NULL, or 0 then don't draw a bar at all |
|
if ($this->coords[0][$i] === null || $this->coords[0][$i] === '' ) |
|
continue; |
|
|
|
if( $exist_x ) { |
|
$x=$this->coords[1][$i]; |
|
} |
|
else { |
|
$x=$i; |
|
} |
|
|
|
$x=$xscale->Translate($x); |
|
|
|
// Comment Note: This confuses the positioning when using acc together with |
|
// grouped bars. Workaround for fixing #191 |
|
/* |
|
if( !$xscale->textscale ) { |
|
if($this->align=="center") |
|
$x -= $abswidth/2; |
|
elseif($this->align=="right") |
|
$x -= $abswidth; |
|
} |
|
*/ |
|
// Stroke fill color and fill gradient |
|
$pts=array( |
|
$x,$zp, |
|
$x,$yscale->Translate($this->coords[0][$i]), |
|
$x+$abswidth,$yscale->Translate($this->coords[0][$i]), |
|
$x+$abswidth,$zp); |
|
if( $this->grad ) { |
|
if( $grad === null ) { |
|
$grad = new Gradient($img); |
|
} |
|
if( is_array($this->grad_fromcolor) ) { |
|
// The first argument (grad_fromcolor) can be either an array or a single color. If it is an array |
|
// then we have two choices. It can either a) be a single color specified as an RGB triple or it can be |
|
// an array to specify both (from, to style) for each individual bar. The way to know the difference is |
|
// to investgate the first element. If this element is an integer [0,255] then we assume it is an RGB |
|
// triple. |
|
$ng = count($this->grad_fromcolor); |
|
if( $ng === 3 ) { |
|
if( is_numeric($this->grad_fromcolor[0]) && $this->grad_fromcolor[0] > 0 && $this->grad_fromcolor[0] < 256 ) { |
|
// RGB Triple |
|
$fromcolor = $this->grad_fromcolor; |
|
$tocolor = $this->grad_tocolor; |
|
$style = $this->grad_style; |
|
} |
|
else { |
|
$fromcolor = $this->grad_fromcolor[$i % $ng][0]; |
|
$tocolor = $this->grad_fromcolor[$i % $ng][1]; |
|
$style = $this->grad_fromcolor[$i % $ng][2]; |
|
} |
|
} |
|
else { |
|
$fromcolor = $this->grad_fromcolor[$i % $ng][0]; |
|
$tocolor = $this->grad_fromcolor[$i % $ng][1]; |
|
$style = $this->grad_fromcolor[$i % $ng][2]; |
|
} |
|
$grad->FilledRectangle($pts[2],$pts[3], |
|
$pts[6],$pts[7], |
|
$fromcolor,$tocolor,$style); |
|
} |
|
else { |
|
$grad->FilledRectangle($pts[2],$pts[3], |
|
$pts[6],$pts[7], |
|
$this->grad_fromcolor,$this->grad_tocolor,$this->grad_style); |
|
} |
|
} |
|
elseif( !empty($this->fill_color) ) { |
|
if(is_array($this->fill_color)) { |
|
$img->PushColor($this->fill_color[$i % count($this->fill_color)]); |
|
} else { |
|
$img->PushColor($this->fill_color); |
|
} |
|
$img->FilledPolygon($pts); |
|
$img->PopColor(); |
|
} |
|
|
|
/////////////////////////kokorahen rectangle polygon////////////////////// |
|
|
|
// Remember value of this bar |
|
$val=$this->coords[0][$i]; |
|
|
|
if( !empty($val) && !is_numeric($val) ) { |
|
JpGraphError::RaiseL(2004,$i,$val); |
|
//'All values for a barplot must be numeric. You have specified value['.$i.'] == \''.$val.'\''); |
|
} |
|
|
|
// Determine the shadow |
|
if( $this->bar_shadow && $val != 0) { |
|
|
|
$ssh = $this->bar_shadow_hsize; |
|
$ssv = $this->bar_shadow_vsize; |
|
// Create points to create a "upper-right" shadow |
|
if( $val > 0 ) { |
|
$sp[0]=$pts[6]; $sp[1]=$pts[7]; |
|
$sp[2]=$pts[4]; $sp[3]=$pts[5]; |
|
$sp[4]=$pts[2]; $sp[5]=$pts[3]; |
|
$sp[6]=$pts[2]+$ssh; $sp[7]=$pts[3]-$ssv; |
|
$sp[8]=$pts[4]+$ssh; $sp[9]=$pts[5]-$ssv; |
|
$sp[10]=$pts[6]+$ssh; $sp[11]=$pts[7]-$ssv; |
|
} |
|
elseif( $val < 0 ) { |
|
$sp[0]=$pts[4]; $sp[1]=$pts[5]; |
|
$sp[2]=$pts[6]; $sp[3]=$pts[7]; |
|
$sp[4]=$pts[0]; $sp[5]=$pts[1]; |
|
$sp[6]=$pts[0]+$ssh; $sp[7]=$pts[1]-$ssv; |
|
$sp[8]=$pts[6]+$ssh; $sp[9]=$pts[7]-$ssv; |
|
$sp[10]=$pts[4]+$ssh; $sp[11]=$pts[5]-$ssv; |
|
} |
|
if( is_array($this->bar_shadow_color) ) { |
|
$numcolors = count($this->bar_shadow_color); |
|
if( $numcolors == 0 ) { |
|
JpGraphError::RaiseL(2005);//('You have specified an empty array for shadow colors in the bar plot.'); |
|
} |
|
$img->PushColor($this->bar_shadow_color[$i % $numcolors]); |
|
} |
|
else { |
|
$img->PushColor($this->bar_shadow_color); |
|
} |
|
$img->FilledPolygon($sp); |
|
$img->PopColor(); |
|
|
|
} elseif( $this->bar_3d && $val != 0) { |
|
// Determine the 3D |
|
|
|
$ssh = $this->bar_3d_hsize; |
|
$ssv = $this->bar_3d_vsize; |
|
|
|
// Create points to create a "upper-right" shadow |
|
if( $val > 0 ) { |
|
$sp1[0]=$pts[6]; $sp1[1]=$pts[7]; |
|
$sp1[2]=$pts[4]; $sp1[3]=$pts[5]; |
|
$sp1[4]=$pts[4]+$ssh; $sp1[5]=$pts[5]-$ssv; |
|
$sp1[6]=$pts[6]+$ssh; $sp1[7]=$pts[7]-$ssv; |
|
|
|
$sp2[0]=$pts[4]; $sp2[1]=$pts[5]; |
|
$sp2[2]=$pts[2]; $sp2[3]=$pts[3]; |
|
$sp2[4]=$pts[2]+$ssh; $sp2[5]=$pts[3]-$ssv; |
|
$sp2[6]=$pts[4]+$ssh; $sp2[7]=$pts[5]-$ssv; |
|
|
|
} |
|
elseif( $val < 0 ) { |
|
$sp1[0]=$pts[4]; $sp1[1]=$pts[5]; |
|
$sp1[2]=$pts[6]; $sp1[3]=$pts[7]; |
|
$sp1[4]=$pts[6]+$ssh; $sp1[5]=$pts[7]-$ssv; |
|
$sp1[6]=$pts[4]+$ssh; $sp1[7]=$pts[5]-$ssv; |
|
|
|
$sp2[0]=$pts[6]; $sp2[1]=$pts[7]; |
|
$sp2[2]=$pts[0]; $sp2[3]=$pts[1]; |
|
$sp2[4]=$pts[0]+$ssh; $sp2[5]=$pts[1]-$ssv; |
|
$sp2[6]=$pts[6]+$ssh; $sp2[7]=$pts[7]-$ssv; |
|
} |
|
|
|
$base_color = $this->fill_color; |
|
|
|
$img->PushColor($base_color . ':0.7'); |
|
$img->FilledPolygon($sp1); |
|
$img->PopColor(); |
|
|
|
$img->PushColor($base_color . ':1.1'); |
|
$img->FilledPolygon($sp2); |
|
$img->PopColor(); |
|
} |
|
|
|
// Stroke the pattern |
|
if( is_array($this->iPattern) ) { |
|
$f = new RectPatternFactory(); |
|
if( is_array($this->iPatternColor) ) { |
|
$pcolor = $this->iPatternColor[$i % $np]; |
|
} |
|
else { |
|
$pcolor = $this->iPatternColor; |
|
} |
|
$prect = $f->Create($this->iPattern[$i % $np],$pcolor,1); |
|
$prect->SetDensity($this->iPatternDensity[$i % $np]); |
|
|
|
if( $val < 0 ) { |
|
$rx = $pts[0]; |
|
$ry = $pts[1]; |
|
} |
|
else { |
|
$rx = $pts[2]; |
|
$ry = $pts[3]; |
|
} |
|
$width = abs($pts[4]-$pts[0])+1; |
|
$height = abs($pts[1]-$pts[3])+1; |
|
$prect->SetPos(new Rectangle($rx,$ry,$width,$height)); |
|
$prect->Stroke($img); |
|
} |
|
else { |
|
if( $this->iPattern > -1 ) { |
|
$f = new RectPatternFactory(); |
|
$prect = $f->Create($this->iPattern,$this->iPatternColor,1); |
|
$prect->SetDensity($this->iPatternDensity); |
|
if( $val < 0 ) { |
|
$rx = $pts[0]; |
|
$ry = $pts[1]; |
|
} |
|
else { |
|
$rx = $pts[2]; |
|
$ry = $pts[3]; |
|
} |
|
$width = abs($pts[4]-$pts[0])+1; |
|
$height = abs($pts[1]-$pts[3])+1; |
|
$prect->SetPos(new Rectangle($rx,$ry,$width,$height)); |
|
$prect->Stroke($img); |
|
} |
|
} |
|
|
|
// Stroke the outline of the bar |
|
if( is_array($this->color) ) { |
|
$img->SetColor($this->color[$i % count($this->color)]); |
|
} |
|
else { |
|
$img->SetColor($this->color); |
|
} |
|
|
|
$pts[] = $pts[0]; |
|
$pts[] = $pts[1]; |
|
|
|
if( $this->weight > 0 ) { |
|
$img->SetLineWeight($this->weight); |
|
$img->Polygon($pts); |
|
} |
|
|
|
// Determine how to best position the values of the individual bars |
|
$x=$pts[2]+($pts[4]-$pts[2])/2; |
|
$this->value->SetMargin(5); |
|
|
|
if( $this->valuepos=='top' ) { |
|
$y=$pts[3]; |
|
if( $img->a === 90 ) { |
|
if( $val < 0 ) { |
|
$this->value->SetAlign('right','center'); |
|
} |
|
else { |
|
$this->value->SetAlign('left','center'); |
|
} |
|
|
|
} |
|
else { |
|
if( $val < 0 ) { |
|
$this->value->SetMargin(-5); |
|
$y=$pts[1]; |
|
$this->value->SetAlign('center','bottom'); |
|
} |
|
else { |
|
$this->value->SetAlign('center','bottom'); |
|
} |
|
|
|
} |
|
$this->value->Stroke($img,$val,$x,$y); |
|
} |
|
elseif( $this->valuepos=='max' ) { |
|
$y=$pts[3]; |
|
if( $img->a === 90 ) { |
|
if( $val < 0 ) |
|
$this->value->SetAlign('left','center'); |
|
else |
|
$this->value->SetAlign('right','center'); |
|
} |
|
else { |
|
if( $val < 0 ) { |
|
$this->value->SetAlign('center','bottom'); |
|
} |
|
else { |
|
$this->value->SetAlign('center','top'); |
|
} |
|
} |
|
$this->value->SetMargin(-5); |
|
$this->value->Stroke($img,$val,$x,$y); |
|
} |
|
elseif( $this->valuepos=='center' ) { |
|
$y = ($pts[3] + $pts[1])/2; |
|
$this->value->SetAlign('center','center'); |
|
$this->value->SetMargin(0); |
|
$this->value->Stroke($img,$val,$x,$y); |
|
} |
|
elseif( $this->valuepos=='bottom' || $this->valuepos=='min' ) { |
|
$y=$pts[1]; |
|
if( $img->a === 90 ) { |
|
if( $val < 0 ) |
|
$this->value->SetAlign('right','center'); |
|
else |
|
$this->value->SetAlign('left','center'); |
|
} |
|
$this->value->SetMargin(3); |
|
$this->value->Stroke($img,$val,$x,$y); |
|
} |
|
else { |
|
JpGraphError::RaiseL(2006,$this->valuepos); |
|
//'Unknown position for values on bars :'.$this->valuepos); |
|
} |
|
// Create the client side image map |
|
$rpts = $img->ArrRotate($pts); |
|
$csimcoord=round($rpts[0]).", ".round($rpts[1]); |
|
for( $j=1; $j < 4; ++$j){ |
|
$csimcoord .= ", ".round($rpts[2*$j]).", ".round($rpts[2*$j+1]); |
|
} |
|
if( !empty($this->csimtargets[$i]) ) { |
|
$this->csimareas .= '<area shape="poly" coords="'.$csimcoord.'" '; |
|
$this->csimareas .= " href=\"".htmlentities($this->csimtargets[$i])."\""; |
|
|
|
if( !empty($this->csimwintargets[$i]) ) { |
|
$this->csimareas .= " target=\"".$this->csimwintargets[$i]."\" "; |
|
} |
|
|
|
$sval=''; |
|
if( !empty($this->csimalts[$i]) ) { |
|
$sval=sprintf($this->csimalts[$i],$this->coords[0][$i]); |
|
$this->csimareas .= " title=\"$sval\" alt=\"$sval\" "; |
|
} |
|
$this->csimareas .= " />\n"; |
|
} |
|
} |
|
return true; |
|
} |
|
} // Class |
|
|
|
//=================================================== |
|
// CLASS GroupBarPlot |
|
// Description: Produce grouped bar plots |
|
//=================================================== |
|
class GroupBarPlot extends BarPlot { |
|
public $plots; |
|
private $nbrplots=0; |
|
//--------------- |
|
// CONSTRUCTOR |
|
function GroupBarPlot($plots) { |
|
$this->width=0.7; |
|
$this->plots = $plots; |
|
$this->nbrplots = count($plots); |
|
if( $this->nbrplots < 1 ) { |
|
JpGraphError::RaiseL(2007);//('Cannot create GroupBarPlot from empty plot array.'); |
|
} |
|
for($i=0; $i < $this->nbrplots; ++$i ) { |
|
if( empty($this->plots[$i]) || !isset($this->plots[$i]) ) { |
|
JpGraphError::RaiseL(2008,$i);//("Group bar plot element nbr $i is undefined or empty."); |
|
} |
|
} |
|
$this->numpoints = $plots[0]->numpoints; |
|
$this->width=0.7; |
|
} |
|
|
|
//--------------- |
|
// PUBLIC METHODS |
|
function Legend($graph) { |
|
$n = count($this->plots); |
|
for($i=0; $i < $n; ++$i) { |
|
$c = get_class($this->plots[$i]); |
|
if( !($this->plots[$i] instanceof BarPlot) ) { |
|
JpGraphError::RaiseL(2009,$c); |
|
//('One of the objects submitted to GroupBar is not a BarPlot. Make sure that you create the Group Bar plot from an array of BarPlot or AccBarPlot objects. (Class = '.$c.')'); |
|
} |
|
$this->plots[$i]->DoLegend($graph); |
|
} |
|
} |
|
|
|
function Min() { |
|
list($xmin,$ymin) = $this->plots[0]->Min(); |
|
$n = count($this->plots); |
|
for($i=0; $i < $n; ++$i) { |
|
list($xm,$ym) = $this->plots[$i]->Min(); |
|
$xmin = max($xmin,$xm); |
|
$ymin = min($ymin,$ym); |
|
} |
|
return array($xmin,$ymin); |
|
} |
|
|
|
function Max() { |
|
list($xmax,$ymax) = $this->plots[0]->Max(); |
|
$n = count($this->plots); |
|
for($i=0; $i < $n; ++$i) { |
|
list($xm,$ym) = $this->plots[$i]->Max(); |
|
$xmax = max($xmax,$xm); |
|
$ymax = max($ymax,$ym); |
|
} |
|
return array($xmax,$ymax); |
|
} |
|
|
|
function GetCSIMareas() { |
|
$n = count($this->plots); |
|
$csimareas=''; |
|
for($i=0; $i < $n; ++$i) { |
|
$csimareas .= $this->plots[$i]->csimareas; |
|
} |
|
return $csimareas; |
|
} |
|
|
|
// Stroke all the bars next to each other |
|
function Stroke($img,$xscale,$yscale) { |
|
$tmp=$xscale->off; |
|
$n = count($this->plots); |
|
$subwidth = $this->width/$this->nbrplots ; |
|
|
|
for( $i=0; $i < $n; ++$i ) { |
|
$this->plots[$i]->ymin=$this->ybase; |
|
$this->plots[$i]->SetWidth($subwidth); |
|
|
|
// If the client have used SetTextTickInterval() then |
|
// major_step will be > 1 and the positioning will fail. |
|
// If we assume it is always one the positioning will work |
|
// fine with a text scale but this will not work with |
|
// arbitrary linear scale |
|
$xscale->off = $tmp+$i*round($xscale->scale_factor* $subwidth); |
|
$this->plots[$i]->Stroke($img,$xscale,$yscale); |
|
} |
|
$xscale->off=$tmp; |
|
} |
|
} // Class |
|
|
|
//=================================================== |
|
// CLASS AccBarPlot |
|
// Description: Produce accumulated bar plots |
|
//=================================================== |
|
class AccBarPlot extends BarPlot { |
|
public $plots=null; |
|
private $nbrplots=0; |
|
//--------------- |
|
// CONSTRUCTOR |
|
function __construct($plots) { |
|
$this->plots = $plots; |
|
$this->nbrplots = count($plots); |
|
if( $this->nbrplots < 1 ) { |
|
JpGraphError::RaiseL(2010);//('Cannot create AccBarPlot from empty plot array.'); |
|
} |
|
for($i=0; $i < $this->nbrplots; ++$i ) { |
|
if( empty($this->plots[$i]) || !isset($this->plots[$i]) ) { |
|
JpGraphError::RaiseL(2011,$i);//("Acc bar plot element nbr $i is undefined or empty."); |
|
} |
|
} |
|
|
|
// We can only allow individual plost which do not have specified X-positions |
|
for($i=0; $i < $this->nbrplots; ++$i ) { |
|
if( !empty($this->plots[$i]->coords[1]) ) { |
|
JpGraphError::RaiseL(2015); |
|
//'Individual bar plots in an AccBarPlot or GroupBarPlot can not have specified X-positions.'); |
|
} |
|
} |
|
|
|
// Use 0 weight by default which means that the individual bar |
|
// weights will be used per part n the accumulated bar |
|
$this->SetWeight(0); |
|
|
|
$this->numpoints = $plots[0]->numpoints; |
|
$this->value = new DisplayValue(); |
|
} |
|
|
|
//--------------- |
|
// PUBLIC METHODS |
|
function Legend($graph) { |
|
$n = count($this->plots); |
|
for( $i=$n-1; $i >= 0; --$i ) { |
|
$c = get_class($this->plots[$i]); |
|
if( !($this->plots[$i] instanceof BarPlot) ) { |
|
JpGraphError::RaiseL(2012,$c); |
|
//('One of the objects submitted to AccBar is not a BarPlot. Make sure that you create the AccBar plot from an array of BarPlot objects.(Class='.$c.')'); |
|
} |
|
$this->plots[$i]->DoLegend($graph); |
|
} |
|
} |
|
|
|
function Max() { |
|
list($xmax) = $this->plots[0]->Max(); |
|
$nmax=0; |
|
for($i=0; $i < count($this->plots); ++$i) { |
|
$n = count($this->plots[$i]->coords[0]); |
|
$nmax = max($nmax,$n); |
|
list($x) = $this->plots[$i]->Max(); |
|
$xmax = max($xmax,$x); |
|
} |
|
for( $i = 0; $i < $nmax; $i++ ) { |
|
// Get y-value for bar $i by adding the |
|
// individual bars from all the plots added. |
|
// It would be wrong to just add the |
|
// individual plots max y-value since that |
|
// would in most cases give to large y-value. |
|
$y=0; |
|
if( !isset($this->plots[0]->coords[0][$i]) ) { |
|
JpGraphError::RaiseL(2014); |
|
} |
|
if( $this->plots[0]->coords[0][$i] > 0 ) |
|
$y=$this->plots[0]->coords[0][$i]; |
|
for( $j = 1; $j < $this->nbrplots; $j++ ) { |
|
if( !isset($this->plots[$j]->coords[0][$i]) ) { |
|
JpGraphError::RaiseL(2014); |
|
} |
|
if( $this->plots[$j]->coords[0][$i] > 0 ) |
|
$y += $this->plots[$j]->coords[0][$i]; |
|
} |
|
$ymax[$i] = $y; |
|
} |
|
$ymax = max($ymax); |
|
|
|
// Bar always start at baseline |
|
if( $ymax <= $this->ybase ) |
|
$ymax = $this->ybase; |
|
return array($xmax,$ymax); |
|
} |
|
|
|
function Min() { |
|
$nmax=0; |
|
list($xmin,$ysetmin) = $this->plots[0]->Min(); |
|
for($i=0; $i < count($this->plots); ++$i) { |
|
$n = count($this->plots[$i]->coords[0]); |
|
$nmax = max($nmax,$n); |
|
list($x,$y) = $this->plots[$i]->Min(); |
|
$xmin = Min($xmin,$x); |
|
$ysetmin = Min($y,$ysetmin); |
|
} |
|
for( $i = 0; $i < $nmax; $i++ ) { |
|
// Get y-value for bar $i by adding the |
|
// individual bars from all the plots added. |
|
// It would be wrong to just add the |
|
// individual plots max y-value since that |
|
// would in most cases give to large y-value. |
|
$y=0; |
|
if( $this->plots[0]->coords[0][$i] < 0 ) |
|
$y=$this->plots[0]->coords[0][$i]; |
|
for( $j = 1; $j < $this->nbrplots; $j++ ) { |
|
if( $this->plots[$j]->coords[0][$i] < 0 ) |
|
$y += $this->plots[ $j ]->coords[0][$i]; |
|
} |
|
$ymin[$i] = $y; |
|
} |
|
$ymin = Min($ysetmin,Min($ymin)); |
|
// Bar always start at baseline |
|
if( $ymin >= $this->ybase ) |
|
$ymin = $this->ybase; |
|
return array($xmin,$ymin); |
|
} |
|
|
|
// Stroke acc bar plot |
|
function Stroke($img,$xscale,$yscale) { |
|
$pattern=NULL; |
|
$img->SetLineWeight($this->weight); |
|
$grad=null; |
|
for($i=0; $i < $this->numpoints-1; $i++) { |
|
$accy = 0; |
|
$accy_neg = 0; |
|
for($j=0; $j < $this->nbrplots; ++$j ) { |
|
$img->SetColor($this->plots[$j]->color); |
|
|
|
if ( $this->plots[$j]->coords[0][$i] >= 0) { |
|
$yt=$yscale->Translate($this->plots[$j]->coords[0][$i]+$accy); |
|
$accyt=$yscale->Translate($accy); |
|
$accy+=$this->plots[$j]->coords[0][$i]; |
|
} |
|
else { |
|
//if ( $this->plots[$j]->coords[0][$i] < 0 || $accy_neg < 0 ) { |
|
$yt=$yscale->Translate($this->plots[$j]->coords[0][$i]+$accy_neg); |
|
$accyt=$yscale->Translate($accy_neg); |
|
$accy_neg+=$this->plots[$j]->coords[0][$i]; |
|
} |
|
|
|
$xt=$xscale->Translate($i); |
|
|
|
if( $this->abswidth > -1 ) { |
|
$abswidth=$this->abswidth; |
|
} |
|
else { |
|
$abswidth=round($this->width*$xscale->scale_factor,0); |
|
} |
|
|
|
$pts=array($xt,$accyt,$xt,$yt,$xt+$abswidth,$yt,$xt+$abswidth,$accyt); |
|
|
|
if( $this->bar_shadow ) { |
|
$ssh = $this->bar_shadow_hsize; |
|
$ssv = $this->bar_shadow_vsize; |
|
|
|
// We must also differ if we are a positive or negative bar. |
|
if( $j === 0 ) { |
|
// This gets extra complicated since we have to |
|
// see all plots to see if we are negative. It could |
|
// for example be that all plots are 0 until the very |
|
// last one. We therefore need to save the initial setup |
|
// for both the negative and positive case |
|
|
|
// In case the final bar is positive |
|
$sp[0]=$pts[6]+1; $sp[1]=$pts[7]; |
|
$sp[2]=$pts[6]+$ssh; $sp[3]=$pts[7]-$ssv; |
|
|
|
// In case the final bar is negative |
|
$nsp[0]=$pts[0]; $nsp[1]=$pts[1]; |
|
$nsp[2]=$pts[0]+$ssh; $nsp[3]=$pts[1]-$ssv; |
|
$nsp[4]=$pts[6]+$ssh; $nsp[5]=$pts[7]-$ssv; |
|
$nsp[10]=$pts[6]+1; $nsp[11]=$pts[7]; |
|
} |
|
|
|
if( $j === $this->nbrplots-1 ) { |
|
// If this is the last plot of the bar and |
|
// the total value is larger than 0 then we |
|
// add the shadow. |
|
if( is_array($this->bar_shadow_color) ) { |
|
$numcolors = count($this->bar_shadow_color); |
|
if( $numcolors == 0 ) { |
|
JpGraphError::RaiseL(2013);//('You have specified an empty array for shadow colors in the bar plot.'); |
|
} |
|
$img->PushColor($this->bar_shadow_color[$i % $numcolors]); |
|
} |
|
else { |
|
$img->PushColor($this->bar_shadow_color); |
|
} |
|
|
|
if( $accy > 0 ) { |
|
$sp[4]=$pts[4]+$ssh; $sp[5]=$pts[5]-$ssv; |
|
$sp[6]=$pts[2]+$ssh; $sp[7]=$pts[3]-$ssv; |
|
$sp[8]=$pts[2]; $sp[9]=$pts[3]-1; |
|
$sp[10]=$pts[4]+1; $sp[11]=$pts[5]; |
|
$img->FilledPolygon($sp,4); |
|
} |
|
elseif( $accy_neg < 0 ) { |
|
$nsp[6]=$pts[4]+$ssh; $nsp[7]=$pts[5]-$ssv; |
|
$nsp[8]=$pts[4]+1; $nsp[9]=$pts[5]; |
|
$img->FilledPolygon($nsp,4); |
|
} |
|
$img->PopColor(); |
|
} |
|
} |
|
|
|
|
|
// If value is NULL or 0, then don't draw a bar at all |
|
if ($this->plots[$j]->coords[0][$i] == 0 ) continue; |
|
|
|
if( $this->plots[$j]->grad ) { |
|
if( $grad === null ) { |
|
$grad = new Gradient($img); |
|
} |
|
if( is_array($this->plots[$j]->grad_fromcolor) ) { |
|
// The first argument (grad_fromcolor) can be either an array or a single color. If it is an array |
|
// then we have two choices. It can either a) be a single color specified as an RGB triple or it can be |
|
// an array to specify both (from, to style) for each individual bar. The way to know the difference is |
|
// to investgate the first element. If this element is an integer [0,255] then we assume it is an RGB |
|
// triple. |
|
$ng = count($this->plots[$j]->grad_fromcolor); |
|
if( $ng === 3 ) { |
|
if( is_numeric($this->plots[$j]->grad_fromcolor[0]) && $this->plots[$j]->grad_fromcolor[0] > 0 && |
|
$this->plots[$j]->grad_fromcolor[0] < 256 ) { |
|
// RGB Triple |
|
$fromcolor = $this->plots[$j]->grad_fromcolor; |
|
$tocolor = $this->plots[$j]->grad_tocolor; |
|
$style = $this->plots[$j]->grad_style; |
|
} |
|
else { |
|
$fromcolor = $this->plots[$j]->grad_fromcolor[$i % $ng][0]; |
|
$tocolor = $this->plots[$j]->grad_fromcolor[$i % $ng][1]; |
|
$style = $this->plots[$j]->grad_fromcolor[$i % $ng][2]; |
|
} |
|
} |
|
else { |
|
$fromcolor = $this->plots[$j]->grad_fromcolor[$i % $ng][0]; |
|
$tocolor = $this->plots[$j]->grad_fromcolor[$i % $ng][1]; |
|
$style = $this->plots[$j]->grad_fromcolor[$i % $ng][2]; |
|
} |
|
$grad->FilledRectangle($pts[2],$pts[3], |
|
$pts[6],$pts[7], |
|
$fromcolor,$tocolor,$style); |
|
} |
|
else { |
|
$grad->FilledRectangle($pts[2],$pts[3], |
|
$pts[6],$pts[7], |
|
$this->plots[$j]->grad_fromcolor, |
|
$this->plots[$j]->grad_tocolor, |
|
$this->plots[$j]->grad_style); |
|
} |
|
} else { |
|
if (is_array($this->plots[$j]->fill_color) ) { |
|
$numcolors = count($this->plots[$j]->fill_color); |
|
$fillcolor = $this->plots[$j]->fill_color[$i % $numcolors]; |
|
// If the bar is specified to be non filled then the fill color is false |
|
if( $fillcolor !== false ) { |
|
$img->SetColor($this->plots[$j]->fill_color[$i % $numcolors]); |
|
} |
|
} |
|
else { |
|
$fillcolor = $this->plots[$j]->fill_color; |
|
if( $fillcolor !== false ) { |
|
$img->SetColor($this->plots[$j]->fill_color); |
|
} |
|
} |
|
if( $fillcolor !== false ) { |
|
$img->FilledPolygon($pts); |
|
} |
|
} |
|
|
|
$img->SetColor($this->plots[$j]->color); |
|
|
|
// Stroke the pattern |
|
if( $this->plots[$j]->iPattern > -1 ) { |
|
if( $pattern===NULL ) { |
|
$pattern = new RectPatternFactory(); |
|
} |
|
|
|
$prect = $pattern->Create($this->plots[$j]->iPattern,$this->plots[$j]->iPatternColor,1); |
|
$prect->SetDensity($this->plots[$j]->iPatternDensity); |
|
if( $this->plots[$j]->coords[0][$i] < 0 ) { |
|
$rx = $pts[0]; |
|
$ry = $pts[1]; |
|
} |
|
else { |
|
$rx = $pts[2]; |
|
$ry = $pts[3]; |
|
} |
|
$width = abs($pts[4]-$pts[0])+1; |
|
$height = abs($pts[1]-$pts[3])+1; |
|
$prect->SetPos(new Rectangle($rx,$ry,$width,$height)); |
|
$prect->Stroke($img); |
|
} |
|
|
|
|
|
// CSIM array |
|
|
|
if( $i < count($this->plots[$j]->csimtargets) ) { |
|
// Create the client side image map |
|
$rpts = $img->ArrRotate($pts); |
|
$csimcoord=round($rpts[0]).", ".round($rpts[1]); |
|
for( $k=1; $k < 4; ++$k){ |
|
$csimcoord .= ", ".round($rpts[2*$k]).", ".round($rpts[2*$k+1]); |
|
} |
|
if( ! empty($this->plots[$j]->csimtargets[$i]) ) { |
|
$this->csimareas.= '<area shape="poly" coords="'.$csimcoord.'" '; |
|
$this->csimareas.= " href=\"".$this->plots[$j]->csimtargets[$i]."\" "; |
|
|
|
if( ! empty($this->plots[$j]->csimwintargets[$i]) ) { |
|
$this->csimareas.= " target=\"".$this->plots[$j]->csimwintargets[$i]."\" "; |
|
} |
|
|
|
$sval=''; |
|
if( !empty($this->plots[$j]->csimalts[$i]) ) { |
|
$sval=sprintf($this->plots[$j]->csimalts[$i],$this->plots[$j]->coords[0][$i]); |
|
$this->csimareas .= " title=\"$sval\" "; |
|
} |
|
$this->csimareas .= " alt=\"$sval\" />\n"; |
|
} |
|
} |
|
|
|
$pts[] = $pts[0]; |
|
$pts[] = $pts[1]; |
|
$img->SetLineWeight($this->plots[$j]->weight); |
|
$img->Polygon($pts); |
|
$img->SetLineWeight(1); |
|
} |
|
|
|
// Daw potential bar around the entire accbar bar |
|
if( $this->weight > 0 ) { |
|
$y=$yscale->Translate(0); |
|
$img->SetColor($this->color); |
|
$img->SetLineWeight($this->weight); |
|
$img->Rectangle($pts[0],$y,$pts[6],$pts[5]); |
|
} |
|
|
|
// Draw labels for each acc.bar |
|
|
|
$x=$pts[2]+($pts[4]-$pts[2])/2; |
|
if($this->bar_shadow) $x += $ssh; |
|
|
|
// First stroke the accumulated value for the entire bar |
|
// This value is always placed at the top/bottom of the bars |
|
if( $accy_neg < 0 ) { |
|
$y=$yscale->Translate($accy_neg); |
|
$this->value->Stroke($img,$accy_neg,$x,$y); |
|
} |
|
else { |
|
$y=$yscale->Translate($accy); |
|
$this->value->Stroke($img,$accy,$x,$y); |
|
} |
|
|
|
$accy = 0; |
|
$accy_neg = 0; |
|
for($j=0; $j < $this->nbrplots; ++$j ) { |
|
|
|
// We don't print 0 values in an accumulated bar plot |
|
if( $this->plots[$j]->coords[0][$i] == 0 ) continue; |
|
|
|
if ($this->plots[$j]->coords[0][$i] > 0) { |
|
$yt=$yscale->Translate($this->plots[$j]->coords[0][$i]+$accy); |
|
$accyt=$yscale->Translate($accy); |
|
if( $this->plots[$j]->valuepos=='center' ) { |
|
$y = $accyt-($accyt-$yt)/2; |
|
} |
|
elseif( $this->plots[$j]->valuepos=='bottom' ) { |
|
$y = $accyt; |
|
} |
|
else { // top or max |
|
$y = $accyt-($accyt-$yt); |
|
} |
|
$accy+=$this->plots[$j]->coords[0][$i]; |
|
if( $this->plots[$j]->valuepos=='center' ) { |
|
$this->plots[$j]->value->SetAlign("center","center"); |
|
$this->plots[$j]->value->SetMargin(0); |
|
} |
|
elseif( $this->plots[$j]->valuepos=='bottom' ) { |
|
$this->plots[$j]->value->SetAlign('center','bottom'); |
|
$this->plots[$j]->value->SetMargin(2); |
|
} |
|
else { |
|
$this->plots[$j]->value->SetAlign('center','top'); |
|
$this->plots[$j]->value->SetMargin(1); |
|
} |
|
} else { |
|
$yt=$yscale->Translate($this->plots[$j]->coords[0][$i]+$accy_neg); |
|
$accyt=$yscale->Translate($accy_neg); |
|
$accy_neg+=$this->plots[$j]->coords[0][$i]; |
|
if( $this->plots[$j]->valuepos=='center' ) { |
|
$y = $accyt-($accyt-$yt)/2; |
|
} |
|
elseif( $this->plots[$j]->valuepos=='bottom' ) { |
|
$y = $accyt; |
|
} |
|
else { |
|
$y = $accyt-($accyt-$yt); |
|
} |
|
if( $this->plots[$j]->valuepos=='center' ) { |
|
$this->plots[$j]->value->SetAlign("center","center"); |
|
$this->plots[$j]->value->SetMargin(0); |
|
} |
|
elseif( $this->plots[$j]->valuepos=='bottom' ) { |
|
$this->plots[$j]->value->SetAlign('center',$j==0 ? 'bottom':'top'); |
|
$this->plots[$j]->value->SetMargin(-2); |
|
} |
|
else { |
|
$this->plots[$j]->value->SetAlign('center','bottom'); |
|
$this->plots[$j]->value->SetMargin(-1); |
|
} |
|
} |
|
$this->plots[$j]->value->Stroke($img,$this->plots[$j]->coords[0][$i],round($x),round($y)); |
|
} |
|
|
|
} |
|
return true; |
|
} |
|
} // Class |
|
|
|
/* EOF */ |
|
?>
|
|
|