Blame | Last modification | View Log | RSS feed
<?php/*=======================================================================// File: JPGRAPH_LINE.PHP// Description: Line plot extension for JpGraph// Created: 2001-01-08// Author: Johan Persson (johanp@aditus.nu)// Ver: $Id: jpgraph_line.php,v 1.1 2004/06/15 10:13:19 jpm Exp $//// License: This code is released under QPL// Copyright (C) 2001,2002 Johan Persson//========================================================================*/// constants for the (filled) areaDEFINE("LP_AREA_FILLED", true);DEFINE("LP_AREA_NOT_FILLED", false);DEFINE("LP_AREA_BORDER",false);DEFINE("LP_AREA_NO_BORDER",true);//===================================================// CLASS LinePlot// Description://===================================================class LinePlot extends Plot{var $filled=false;var $fill_color='blue';var $mark=null;var $step_style=false, $center=false;var $line_style=1; // Default to solidvar $filledAreas = array(); // array of arrays(with min,max,col,filled in them)var $barcenter=false; // When we mix line and bar. Should we center the line in the bar.var $fillFromMin = false ;//---------------// CONSTRUCTORfunction LinePlot(&$datay,$datax=false) {$this->Plot($datay,$datax);$this->mark = new PlotMark();}//---------------// PUBLIC METHODS// Set style, filled or openfunction SetFilled($aFlag=true) {JpGraphError::Raise('LinePlot::SetFilled() is deprecated. Use SetFillColor()');}function SetBarCenter($aFlag=true) {$this->barcenter=$aFlag;}function SetStyle($aStyle) {$this->line_style=$aStyle;}function SetStepStyle($aFlag=true) {$this->step_style = $aFlag;}function SetColor($aColor) {parent::SetColor($aColor);}function SetFillFromYMin($f = true ) {$this->fillFromMin = $f ;}function SetFillColor($aColor,$aFilled=true) {$this->fill_color=$aColor;$this->filled=$aFilled;}function Legend(&$graph) {if( $this->legend!="" ) {if( $this->filled ) {$graph->legend->Add($this->legend,$this->fill_color,$this->mark,0,$this->legendcsimtarget,$this->legendcsimalt);} else {$graph->legend->Add($this->legend,$this->color,$this->mark,$this->line_style,$this->legendcsimtarget,$this->legendcsimalt);}}}function AddArea($aMin=0,$aMax=0,$aFilled=LP_AREA_NOT_FILLED,$aColor="gray9",$aBorder=LP_AREA_BORDER) {if($aMin > $aMax) {// swap$tmp = $aMin;$aMin = $aMax;$aMax = $tmp;}$this->filledAreas[] = array($aMin,$aMax,$aColor,$aFilled,$aBorder);}// Gets called before any axis are strokedfunction PreStrokeAdjust(&$graph) {// If another plot type have already adjusted the// offset we don't touch it.// (We check for empty in case the scale is a log scale// and hence doesn't contain any xlabel_offset)if( empty($graph->xaxis->scale->ticks->xlabel_offset) ||$graph->xaxis->scale->ticks->xlabel_offset == 0 ) {if( $this->center ) {++$this->numpoints;$a=0.5; $b=0.5;} else {$a=0; $b=0;}$graph->xaxis->scale->ticks->SetXLabelOffset($a);$graph->SetTextScaleOff($b);//$graph->xaxis->scale->ticks->SupressMinorTickMarks();}}function Stroke(&$img,&$xscale,&$yscale) {$numpoints=count($this->coords[0]);if( isset($this->coords[1]) ) {if( count($this->coords[1])!=$numpoints )JpGraphError::Raise("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;if( $this->barcenter )$textadj = 0.5-$xscale->text_scale_off;else$textadj = 0;// Find the first numeric data point$startpoint=0;while( $startpoint < $numpoints && !is_numeric($this->coords[0][$startpoint]) )++$startpoint;// Bail out if no data pointsif( $startpoint == $numpoints )return;if( $exist_x )$xs=$this->coords[1][$startpoint];else$xs= $textadj+$startpoint;$img->SetStartPoint($xscale->Translate($xs),$yscale->Translate($this->coords[0][$startpoint]));if( $this->filled ) {$cord[] = $xscale->Translate($xs);$min = $yscale->GetMinVal();if( $min > 0 || $this->fillFromMin )$cord[] = $yscale->Translate($min);else$cord[] = $yscale->Translate(0);}$xt = $xscale->Translate($xs);$yt = $yscale->Translate($this->coords[0][$startpoint]);$cord[] = $xt;$cord[] = $yt;$yt_old = $yt;$this->value->Stroke($img,$this->coords[0][$startpoint],$xt,$yt);$img->SetColor($this->color);$img->SetLineWeight($this->weight);$img->SetLineStyle($this->line_style);for( $pnts=$startpoint+1; $pnts<$numpoints; ++$pnts) {if( $exist_x ) $x=$this->coords[1][$pnts];else $x=$pnts+$textadj;$xt = $xscale->Translate($x);$yt = $yscale->Translate($this->coords[0][$pnts]);$y=$this->coords[0][$pnts];if( $this->step_style && is_numeric($y) ) {$img->StyleLineTo($xt,$yt_old);$img->StyleLineTo($xt,$yt);$cord[] = $xt;$cord[] = $yt_old;$cord[] = $xt;$cord[] = $yt;}else {if( is_numeric($y) || (is_string($y) && $y != "-") ) {$tmp1=$this->coords[0][$pnts];$tmp2=$this->coords[0][$pnts-1];if( is_numeric($tmp1) && (is_numeric($tmp2) || $tmp2=="-" ) ) {$img->StyleLineTo($xt,$yt);}else {$img->SetStartPoint($xt,$yt);}if( is_numeric($tmp1) &&(is_numeric($tmp2) || $tmp2=="-" || ($this->filled && $tmp2=='') ) ) {$cord[] = $xt;$cord[] = $yt;}}}$yt_old = $yt;$this->StrokeDataValue($img,$this->coords[0][$pnts],$xt,$yt);}if( $this->filled ) {$cord[] = $xt;if( $min > 0 || $this->fillFromMin )$cord[] = $yscale->Translate($min);else$cord[] = $yscale->Translate(0);$img->SetColor($this->fill_color);$img->FilledPolygon($cord);$img->SetColor($this->color);$img->Polygon($cord);}if(!empty($this->filledAreas)) {$minY = $yscale->Translate($yscale->GetMinVal());$factor = ($this->step_style ? 4 : 2);for($i = 0; $i < sizeof($this->filledAreas); ++$i) {// go through all filled area elements ordered by insertion// fill polygon array$areaCoords[] = $cord[$this->filledAreas[$i][0] * $factor];$areaCoords[] = $minY;$areaCoords =array_merge($areaCoords,array_slice($cord,$this->filledAreas[$i][0] * $factor,($this->filledAreas[$i][1] - $this->filledAreas[$i][0] + ($this->step_style ? 0 : 1)) * $factor));$areaCoords[] = $areaCoords[sizeof($areaCoords)-2]; // last x$areaCoords[] = $minY; // last yif($this->filledAreas[$i][3]) {$img->SetColor($this->filledAreas[$i][2]);$img->FilledPolygon($areaCoords);$img->SetColor($this->color);}// Check if we should draw the frame.// If not we still re-draw the line since it might have been// partially overwritten by the filled area and it doesn't look// very good.// TODO: The behaviour is undefined if the line does not have// any line at the position of the area.if( $this->filledAreas[$i][4] )$img->Polygon($areaCoords);else$img->Polygon($cord);$areaCoords = array();}}if( $this->mark->type == -1 || $this->mark->show == false )return;for( $pnts=0; $pnts<$numpoints; ++$pnts) {if( $exist_x ) $x=$this->coords[1][$pnts];else $x=$pnts+$textadj;$xt = $xscale->Translate($x);$yt = $yscale->Translate($this->coords[0][$pnts]);if( is_numeric($this->coords[0][$pnts]) ) {if( !empty($this->csimtargets[$pnts]) ) {$this->mark->SetCSIMTarget($this->csimtargets[$pnts]);$this->mark->SetCSIMAlt($this->csimalts[$pnts]);}if( $exist_x )$x=$this->coords[1][$pnts];else$x=$pnts;$this->mark->SetCSIMAltVal($this->coords[0][$pnts],$x);$this->mark->Stroke($img,$xt,$yt);$this->csimareas .= $this->mark->GetCSIMAreas();$this->StrokeDataValue($img,$this->coords[0][$pnts],$xt,$yt);}}}} // Class//===================================================// CLASS AccLinePlot// Description://===================================================class AccLinePlot extends Plot {var $plots=null,$nbrplots=0,$numpoints=0;//---------------// CONSTRUCTORfunction AccLinePlot($plots) {$this->plots = $plots;$this->nbrplots = count($plots);$this->numpoints = $plots[0]->numpoints;}//---------------// PUBLIC METHODSfunction Legend(&$graph) {foreach( $this->plots as $p )$p->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 line $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=$this->plots[0]->coords[0][$i];for( $j = 1; $j < $this->nbrplots; $j++ ) {$y += $this->plots[ $j ]->coords[0][$i];}$ymax[$i] = $y;}$ymax = max($ymax);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 line $i by adding the// individual bars from all the plots added.// It would be wrong to just add the// individual plots min y-value since that// would in most cases give to small y-value.$y=$this->plots[0]->coords[0][$i];for( $j = 1; $j < $this->nbrplots; $j++ ) {$y += $this->plots[ $j ]->coords[0][$i];}$ymin[$i] = $y;}$ymin = Min($ysetmin,Min($ymin));return array($xmin,$ymin);}// Gets called before any axis are strokedfunction PreStrokeAdjust(&$graph) {// If another plot type have already adjusted the// offset we don't touch it.// (We check for empty in case the scale is a log scale// and hence doesn't contain any xlabel_offset)if( empty($graph->xaxis->scale->ticks->xlabel_offset) ||$graph->xaxis->scale->ticks->xlabel_offset == 0 ) {if( $this->center ) {++$this->numpoints;$a=0.5; $b=0.5;} else {$a=0; $b=0;}$graph->xaxis->scale->ticks->SetXLabelOffset($a);$graph->SetTextScaleOff($b);$graph->xaxis->scale->ticks->SupressMinorTickMarks();}}// To avoid duplicate of line drawing code here we just// change the y-values for each plot and then restore it// after we have made the stroke. We must do this copy since// it wouldn't be possible to create an acc line plot// with the same graphs, i.e AccLinePlot(array($pl,$pl,$pl));// since this method would have a side effect.function Stroke(&$img,&$xscale,&$yscale) {$img->SetLineWeight($this->weight);$this->numpoints = count($this->plots[0]->coords[0]);// Allocate array$coords[$this->nbrplots][$this->numpoints]=0;for($i=0; $i<$this->numpoints; $i++) {$coords[0][$i]=$this->plots[0]->coords[0][$i];$accy=$coords[0][$i];for($j=1; $j<$this->nbrplots; ++$j ) {$coords[$j][$i] = $this->plots[$j]->coords[0][$i]+$accy;$accy = $coords[$j][$i];}}for($j=$this->nbrplots-1; $j>=0; --$j) {$p=$this->plots[$j];for( $i=0; $i<$this->numpoints; ++$i) {$tmp[$i]=$p->coords[0][$i];$p->coords[0][$i]=$coords[$j][$i];}$p->Stroke($img,$xscale,$yscale);for( $i=0; $i<$this->numpoints; ++$i)$p->coords[0][$i]=$tmp[$i];$p->coords[0][]=$tmp;}}} // Class/* EOF */?>