jpgraph-1.5.2/0040755000076400001440000000000007437550434011701 5ustar ljpusersjpgraph-1.5.2/src/0040755000076400001440000000000007437550012012460 5ustar ljpusersjpgraph-1.5.2/src/Todo0100644000076400001440000000653707437547531013334 0ustar ljpusersVersion: $Id: Todo,v 1.3 2002/01/24 23:27:32 aditus Exp $ Before 1.6 release ==================== Documentation update -------------------- * Rewrite preferred way to handle client side image maps * Add documentation for Stroke($aFileName) * Document the addition of SetCenter() for line plots * Revise documentation of classes. Class diagram update * Add documentation on how to use background image * Review of theme management for pie Additions --------- * Add possibility to set the default start value for text labels * More examples of how to plot images and extended tutorial * Add date/time scale/axis type Verifications/Investigations: ----------------------------- * Possible bug when mixing grouped bar and lineplots * Have really all 0-value bugs been squashed? * Implement multi line text for legends * Check legends for grouped bar plots. Can we make that easier to use? * Check labels for 3d pies. * Check autoscaling with several scatterplots in a graph * Check if Setting manual scale in spider plot is a problem * Check potential problem with linlin and supplying both X and Y coordinates for a line plot * Check what happens with negative values for impuls plots when adding a line y=0. Possible scale bug? * Check the GroupBar and AccBar plot still work after the changes in BarPlot? Verification * Add testcase for negative/positive accumulated bar graphs * Fix error in documentation SetColor() is not a method of Class Legend * Fix problem whereby the first label on the x-axis is hidden when Y-axis has negative values and x-axis is positioned at 0 and setcenter() is used for the lineplot. Add a check to see if Setcenter is used and if that is the case the first label should not be hidden even if position is 0. * Merge the patch to make it possible to do CSIM without running the script off-line. * CSIM for Plot marks * CSIM for legends. Does this make sense? * Investigate the following report Also, I have discovered that in a graph with bars and lines, if the values are low (<50), the graph goes wrong (oversized bars, wrong scale, very big parse-time...). I have solved this. But if the values are lower (<10), the scale gets crazy. For example, for 0 to 3, the Y-Scale say : "blank-0-0-1-2-2-3" or similar. Also the graph takes VERY more time to generate. Also, I did notice that in sections 6.3.25 and 6.3.26 in the manual, the headings on the charts say "SpiderGraph" rather than "PieGraph." The General Description paragraph in both of those sections needs to be changed, too. * Possibility to just plot ticks/labels where the label is != "". Does this make sense? How should it work? * Linear scale investigation: Many datapoints and only show a grouped name for all values, for example sampling every hour but label each day (which is centered) * Filled line plots with negative values. What is the way to handle this? * Possibility to add text-labels directly in the new xxPlot() creation? Sometimes: ========== * Scientific plots. Investigate some use cases and see what changes needs to be done * Difference between minor/major tick marks for text-scale, i.e. ticks with and without text labels * Add pole-zero plots * Re factoring of the way Y and X axis are implemented. Redo the OOD so that we separate the notion of horizontal and vertical axis. This will get rid of the horrible non-oo tests axis=="x" jpgraph-1.5.2/src/jpgraph_error.php0100644000076400001440000000532407437547531016052 0ustar ljpusersPlot($datay,$datax); $this->numpoints /= 2; } //--------------- // PUBLIC METHODS function SetCenter($c=true) { $this->center=$c; } // Gets called before any axis are stroked function PreStrokeAdjust(&$graph) { if( $this->center ) { $a=0.5; $b=0.5; ++$this->numpoints; } else { $a=0; $b=0; } $graph->xaxis->scale->ticks->SetXLabelOffset($a); $graph->SetTextScaleOff($b); $graph->xaxis->scale->ticks->SupressMinorTickMarks(); } // Method description function Stroke(&$img,&$xscale,&$yscale) { $numpoints=count($this->coords[0])/2; $img->SetColor($this->color); $img->SetLineWeight($this->weight); for( $i=0; $i<$numpoints; ++$i) { $xt = $xscale->Translate($i); $yt1 = $yscale->Translate($this->coords[0][$i*2]); $yt2 = $yscale->Translate($this->coords[0][$i*2+1]); $img->Line($xt,$yt1,$xt,$yt2); $img->Line($xt-$this->errwidth,$yt1,$xt+$this->errwidth,$yt1); $img->Line($xt-$this->errwidth,$yt2,$xt+$this->errwidth,$yt2); } return true; } } // Class //=================================================== // CLASS ErrorLinePlot // Description: Combine a line and error plot //=================================================== class ErrorLinePlot extends ErrorPlot { var $line=null; //--------------- // CONSTRUCTOR function ErrorLinePlot(&$datay,$datax=false) { $this->ErrorPlot($datay); // Calculate line coordinates as the average of the error limits for($i=0; $iline=new LinePlot($ly); } //--------------- // PUBLIC METHODS function Legend(&$graph) { if( $this->legend != "" ) $graph->legend->Add($this->legend,$this->color); $this->line->Legend($graph); } function Stroke(&$img,&$xscale,&$yscale) { parent::Stroke($img,$xscale,$yscale); $this->line->Stroke($img,$xscale,$yscale); } } // Class /* EOF */ ?>jpgraph-1.5.2/src/jpgraph_pie.php0100644000076400001440000003072407437547531015500 0ustar ljpusers array(10,34,40,45,46,62,63,134,74,77,120,136,141,168,180,209,218,346,395,89,430), "pastel" => array(27,38,42,58,66,79,105,110,128,147,152,230,236,240,331,337,405,415), "water" => array(8,370,10,40,335,56,213,237,268,14,326,387,24,388), "sand" => array(27,168,34,170,19,50,65,72,131,209,46,393)); var $theme="earth"; var $setslicecolors=array(); var $labelformat="%01.0f"; // Default format for labels var $labeltype=0; // Default to percentage var $pie_border=true,$pie_interior_border=true; //--------------- // CONSTRUCTOR function PiePlot(&$data) { $this->data = $data; $this->title = new Text(""); $this->title->SetFont(FF_FONT1,FS_BOLD); } //--------------- // PUBLIC METHODS function SetCenter($x,$y=0.5) { $this->posx = $x; $this->posy = $y; } function SetCSIMTargets(&$targets,$alts=null) { $this->csimtargets=$targets; $this->csimalts=$alts; } function GetCSIMareas() { return $this->csimareas; } function AddSliceToCSIM($i,$xc,$yc,$radius,$sa,$ea) { //Slice number, ellipse centre (x,y), height, width, start angle, end angle //add coordinates of the centre to the map $coords = "$xc, $yc"; //add coordinates of the first point on the arc to the map $xp = floor(($radius*cos($sa))+$xc); $yp = floor($yc-$radius*sin($sa)); $coords.= ", $xp, $yp"; //add coordinates every 0.2 radians $a=$sa+0.2; while ($a<$ea) { $xp = floor($radius*cos($a)+$xc); $yp = floor($yc-$radius*sin($a)); $coords.= ", $xp, $yp"; $a += 0.2; } //Add the last point on the arc $xp = floor($radius*cos($ea)+$xc); $yp = floor($yc-$radius*sin($ea)); $coords.= ", $xp, $yp"; if( !empty($this->csimtargets[$i]) ) $this->csimareas .= "csimtargets[$i]."\""; if( !empty($this->csimalts[$i]) ) { $tmp=sprintf($this->csimalts[$i],$this->data[$i]); $this->csimareas .= " alt=\"$tmp\""; } $this->csimareas .= ">\r\n"; } function SetTheme($t) { if( in_array($t,array_keys($this->themearr)) ) $this->theme = $t; else JpGraphError::Raise("JpGraph Error: Unknown theme: $t"); } function ExplodeSlice($e) { $this->explode_radius[$e]=20; } function ExplodeAll($radius=-1) { $this->explode_all=true; if( $radius==-1 ) $this->explode_r = 20; else $this->explode_r = $radius; } function Explode($radarr) { $this->explode_radius = $radarr; } function SetSliceColors($c) { $this->setslicecolors = $c; } function SetStartAngle($a) { assert($a>=0 && $a<2*M_PI); $this->startangle = $a; } function SetFont($family,$style=FS_NORMAL,$size=10) { $this->font_family=$family; $this->font_style=$style; $this->font_size=$size; } // Size in percentage function SetSize($size) { if( ($size>0 && $size<=0.5) || ($size>10 && $size<1000) ) $this->radius = $size; else JpGraphError::Raise("JpGraph Error: Size (radius) for pie must either be specified as a fraction [0, 0.5] of the size of the image or as an absolute size in pixels in the range [10, 1000]"); } function SetFontColor($color) { $this->font_color = $color; } // Set label arrays function SetLegends($l) { $this->legends = $l; } // Should the values be displayed? function HideLabels($f=true) { $this->show_labels = !$f; } // Specify label format as a "C" printf string function SetLabelFormat($f) { $this->labelformat=$f; // If format is specified don't add any %-sign $this->show_psign=0; } // Should we display actual value or percentage? function SetLabelType($t) { if( $t<0 || $t>1 ) JpGraphError::Raise("JpGraph Error: Label type for pie plots must be 0 or 1 (not $t)."); $this->labeltype=$t; // Don't show percentage value when displaying absolute values if( $t==1 ) $this->show_psign=0; } // Should the circle around a pie plot be displayed function ShowBorder($exterior=true,$interior=true) { $this->pie_border = $exterior; $this->pie_interior_border = $interior; } // Setup the legends function Legend(&$graph) { $colors = array_keys($graph->img->rgb->rgb_table); sort($colors); $ta=$this->themearr[$this->theme]; if( $this->setslicecolors==null ) $numcolors=count($ta); else $numcolors=count($this->setslicecolors); $sum=0; for($i=0; $idata); ++$i) $sum += $this->data[$i]; $i=0; if( count($this->legends)>0 ) { foreach( $this->legends as $l ) { // Replace possible format with actual values if( $this->labeltype==0 ) $l = sprintf($l,100*$this->data[$i]/$sum); else $l = sprintf($l,$this->data[$i]); if( $this->setslicecolors==null ) $graph->legend->Add($l,$colors[$ta[$i%$numcolors]]); else $graph->legend->Add($l,$this->setslicecolors[$i%$numcolors]); ++$i; // Breakout if there are more legends then values if( $i==count($this->data) ) return; } } } // Specify precision for labels. This is almost a deprecated function // nowadays since the introduction of SetLabelFormat() function SetPrecision($p,$psign=true) { if( $p<0 || $p>8 ) JpGraphError::Raise("JpGraph Error: Pie label Precision must be between 0 and 8"); $this->labelformat="%01.".$p."f"; $this->show_psign=$psign; } function Stroke(&$img) { $colors = array_keys($img->rgb->rgb_table); sort($colors); $ta=$this->themearr[$this->theme]; if( $this->setslicecolors==null ) $numcolors=count($ta); else $numcolors=count($this->setslicecolors); // Draw the slices $sum=0; for($i=0; $idata); ++$i) $sum += $this->data[$i]; // Format the titles for each slice for( $i=0; $idata); ++$i) { if( $this->labeltype==0 ) if( $sum != 0 ) $l = round(100*$this->data[$i]/$sum,$this->precision); else $l = 0; else $l = $this->data[$i]; $l = sprintf($this->labelformat,$l); if( $this->show_psign ) $l .= "%"; $this->labels[$i]=$l; } // Set up the pic-circle if( $this->radius < 1 ) $radius = floor($this->radius*min($img->width,$img->height)); else $radius = $this->radius; $xc = $this->posx*$img->width; $yc = $this->posy*$img->height; $accsum=0; $angle2 = $this->startangle; $img->SetColor($this->color); if( $this->explode_all ) for($i=0;$idata);++$i) $this->explode_radius[$i]=$this->explode_r; for($i=0; $sum>0 && $idata); ++$i) { $d = $this->data[$i]; $angle1 = $angle2; $accsum += $d; $angle2 = $this->startangle+2.0*M_PI*$accsum/$sum; if( $this->setslicecolors==null ) $slicecolor=$colors[$ta[$i%$numcolors]]; else $slicecolor=$this->setslicecolors[$i%$numcolors]; if( $this->pie_interior_border ) $img->SetColor($this->color); else $img->SetColor($slicecolor); $arccolor = $this->pie_border ? $this->color : $slicecolor; $la = abs($angle2-$angle1)/2.0+$angle1; if( empty($this->explode_radius[$i]) ) $this->explode_radius[$i]=0; $xcm = $xc + $this->explode_radius[$i]*cos($la); $ycm = $yc - $this->explode_radius[$i]*sin($la); $img->CakeSlice($xcm,$ycm,$radius-1,$radius-1,$angle1,$angle2, $slicecolor,$arccolor); if( $this->show_labels ) $this->StrokeLabels($this->labels[$i],$img,$xc,$yc,$la, $radius+$this->explode_radius[$i]); if ($this->csimtargets) { $this->AddSliceToCSIM($i,$xcm,$ycm,$radius,$angle1,$angle2); } } // Adjust title position $this->title->Pos($xc,$yc-$img->GetFontHeight()-$radius,"center","bottom"); $this->title->Stroke($img); } //--------------- // PRIVATE METHODS // Position the labels of each slice function StrokeLabels($label,$img,$xc,$yc,$a,$r) { $img->SetFont($this->font_family,$this->font_style,$this->font_size); $img->SetColor($this->font_color); $img->SetTextAlign("left","top"); $marg=6; $r += $img->GetFontHeight()/2; $xt=round($r*cos($a)+$xc); $yt=round($yc-$r*sin($a)); // Position the axis title. // dx, dy is the offset from the top left corner of the bounding box that sorrounds the text // that intersects with the extension of the corresponding axis. The code looks a little // bit messy but this is really the only way of having a reasonable position of the // axis titles. $h=$img->GetTextHeight($label); $w=$img->GetTextWidth($label); while( $a > 2*M_PI ) $a -= 2*M_PI; if( $a>=7*M_PI/4 || $a <= M_PI/4 ) $dx=0; if( $a>=M_PI/4 && $a <= 3*M_PI/4 ) $dx=($a-M_PI/4)*2/M_PI; if( $a>=3*M_PI/4 && $a <= 5*M_PI/4 ) $dx=1; if( $a>=5*M_PI/4 && $a <= 7*M_PI/4 ) $dx=(1-($a-M_PI*5/4)*2/M_PI); if( $a>=7*M_PI/4 ) $dy=(($a-M_PI)-3*M_PI/4)*2/M_PI; if( $a<=M_PI/4 ) $dy=(1-$a*2/M_PI); if( $a>=M_PI/4 && $a <= 3*M_PI/4 ) $dy=1; if( $a>=3*M_PI/4 && $a <= 5*M_PI/4 ) $dy=(1-($a-3*M_PI/4)*2/M_PI); if( $a>=5*M_PI/4 && $a <= 7*M_PI/4 ) $dy=0; $img->StrokeText($xt-$dx*$w,$yt-$dy*$h,$label); } } // Class //=================================================== // CLASS PieGraph // Description: //=================================================== class PieGraph extends Graph { var $posx, $posy, $radius; var $legends=array(); var $plots=array(); //--------------- // CONSTRUCTOR function PieGraph($width=300,$height=200,$cachedName="",$timeout=0,$inline=1) { $this->Graph($width,$height,$cachedName,$timeout,$inline); $this->posx=$width/2; $this->posy=$height/2; $this->SetColor(array(255,255,255)); } //--------------- // PUBLIC METHODS function Add(&$pie) { $this->plots[] = $pie; } function SetColor($c) { $this->SetMarginColor($c); } // Method description function Stroke($aStrokeFileName="") { $this->StrokeFrame(); for($i=0; $iplots); ++$i) $this->plots[$i]->Stroke($this->img); foreach( $this->plots as $p) $p->Legend($this); $this->legend->Stroke($this->img); $this->title->Center($this->img->left_margin,$this->img->width-$this->img->right_margin,5); $this->title->Stroke($this->img); // Stroke texts if( $this->texts != null ) foreach( $this->texts as $t) $t->Stroke($this->img); if ($this->showcsim) { foreach($this->plots as $p ) { $csim.= $p->GetCSIMareas(); } //$csim.= $this->legend->GetCSIMareas(); if (preg_match_all("/area shape=\"(\w+)\" coords=\"([0-9\, ]+)\"/", $csim, $coords)) { $this->img->SetColor($this->csimcolor); for ($i=0; $iimg->SetStartPoint($pts[1][count($pts[0])-1],$pts[2][count($pts[0])-1]); for ($j=0; $jimg->LineTo($pts[1][$j],$pts[2][$j]); } } else if ($coords[1][$i]=="rect") { $pts = preg_split('/,/', $coords[2][$i]); $this->img->SetStartPoint($pts[0],$pts[1]); $this->img->LineTo($pts[2],$pts[1]); $this->img->LineTo($pts[2],$pts[3]); $this->img->LineTo($pts[0],$pts[3]); $this->img->LineTo($pts[0],$pts[1]); } } } } // Finally output the image $this->cache->PutAndStream($this->img,$this->cache_name,$this->inline,$aStrokeFileName); } } // Class /* EOF */ ?> jpgraph-1.5.2/src/jpgraph_pie3d.php0100644000076400001440000002177107437547531015731 0ustar ljpusersdata = $data; $this->title = new Text(""); $this->title->SetFont(FF_FONT1,FS_BOLD); } //--------------- // PUBLIC METHODS // Specify projection angle for 3D in degrees // Must be between 20 and 70 degrees function SetAngle($a) { if( $a<30 || $a>70 ) JpGraphError::Raise("JpGraph: 3D Pie projection angle must be between 30 and 70 degrees."); else $this->angle = $a; } function AddSliceToCSIM($i,$xc,$yc,$height,$width,$thick,$sa,$ea) { //Slice number, ellipse centre (x,y), height, width, start angle, end angle //add coordinates of the centre to the map $coords = "$xc, $yc"; //add coordinates of the first point on the arc to the map $xp = floor($width*cos($sa)/2+$xc); $yp = floor($yc-$height*sin($sa)/2); $coords.= ", $xp, $yp"; //If on the front half, add the thickness offset if ($sa >= M_PI && $sa <= 2*M_PI*1.01) { $yp = floor($yp+($thick*$width)); $coords.= ", $xp, $yp"; } //add coordinates every 0.2 radians $a=$sa+0.2; while ($a<$ea) { $xp = floor($width*cos($a)/2+$xc); if ($a >= M_PI && $a <= 2*M_PI*1.01) { $yp = floor($yc-($height*sin($a)/2)+$thick*$width); } else { $yp = floor($yc-$height*sin($a)/2); } $coords.= ", $xp, $yp"; $a += 0.2; } //Add the last point on the arc $xp = floor($width*cos($ea)/2+$xc); $yp = floor($yc-$height*sin($ea)/2); //If on the front half, add the thickness offset if ($ea >= M_PI && $ea <= 2*M_PI*1.01) { $coords.= ", $xp, ".floor($yp+($thick*$width)); } $coords.= ", $xp, $yp"; if( !empty($this->csimalts[$i]) ) { $tmp=sprintf($this->csimalts[$i],$this->data[$i]); $alt="alt=\"$tmp\""; } if( !empty($this->csimtargets[$i]) ) $this->csimareas .= "csimtargets[$i]."\" $alt>\r\n"; } function ExplodeSlice($e) { JpGraphError::Raise("JpGraph Error: Exploding slices are not (yet) implemented for 3d pies graphs."); //$this->explode_slice=$e; } // Distance from the pie to the labels function SetLabelMargin($m) { assert($m>0 && $m<1); $this->labelmargin=$m; } // Show a thin line from the pie to the label for a specific slice function ShowLabelHint($f=true) { $this->showlabelhint=$f; } // Set color of hint line to label for each slice function SetLabelHintColor($c) { $this->labelhintcolor=$c; } function Stroke(&$img) { $colors = array_keys($img->rgb->rgb_table); sort($colors); $ta=$this->themearr[$this->theme]; if( $this->setslicecolors==null ) $numcolors=count($ta); else $numcolors=count($this->setslicecolors); // Draw the slices $sum=0; foreach($this->data as $d) $sum += $d; // Format the titles for each slice for( $i=0; $idata); ++$i) { if( $this->labeltype==0 ) if( $sum != 0 ) $l = round(100*$this->data[$i]/$sum,$this->precision); else $l=0; else $l = $this->data[$i]; $l = sprintf($this->labelformat,$l); if( $this->show_psign ) $l .= "%"; $this->labels[$i]=$l; } // Set up the pie-circle with some heuristic constants $thick=0.16-($this->angle-20)/60*0.07; $width = floor(2.0*$this->radius*min($img->width,$img->height)); $height = ($this->angle/90.0)*$width; $xc = $this->posx*$img->width; $yc = $this->posy*$img->height; $img->SetColor($this->color); $img->Ellipse($xc,$yc,$width,$height); $img->Arc($xc,$yc+$width*$thick,$width,$height,0,180); $img->Line($xc+$width/2,$yc,$xc+$width/2,$yc+$width*$thick); $img->Line($xc-$width/2,$yc,$xc-$width/2,$yc+$width*$thick); $fillPerimeter[0] = array('x' => round((($xc - ($width / 2)) + 1)), 'y' => round(($yc + ($width * $thick) / 2))); // Draw the first slice first line $img->SetColor($this->color); $img->SetLineWeight($this->weight); $a = $this->startangle; $xp = $width*cos($a)/2+$xc; $yp = $yc-$height*sin($a)/2; $img->Line($xc,$yc,$xp,$yp); for($i=0; $sum>0 && $idata); $i++) { $img->SetColor($this->color); $d = $this->data[$i]; $la = $a + M_PI*$d/$sum; $old_a = $a; $a += 2*M_PI*$d/$sum; if ($this->csimtargets[$i]) { $this->AddSliceToCSIM($i,$xc,$yc,$height,$width,$thick,$old_a,$a); } $xp = $width*cos($a)/2+$xc; $yp = $yc-$height*sin($a)/2; if( $idata)-1) $img->Line($xc,$yc,$xp,$yp); if( $a > M_PI && $a < 0.999*2*M_PI ) $img->Line($xp,$yp,$xp,$yp+$width*$thick-1); if($a < M_PI) { $fillPerimeter[$i + 1] = $fillPerimeter[$i]; } else { $fillPerimeter[$i + 1] = array('x' => round(($xp + 1)), 'y' => round(($yp + ($width * $thick) / 2))); } if( $this->setslicecolors==null ) $slicecolor=$colors[$ta[$i%$numcolors]]; else $slicecolor=$this->setslicecolors[$i%$numcolors]; if( $this->show_labels ) { $margin = 1 + $this->labelmargin; $xp = $width*cos($la)/2*$margin; $yp = $height*sin($la)/2*$margin; if( ($la >= 0 && $la <= M_PI) || $la>2*M_PI*0.98 ) { $this->StrokeLabels($this->labels[$i],$img,$la,$xc+$xp,$yc-$yp); if( $this->showlabelhint ) { $img->SetColor($this->labelhintcolor); $img->Line($xc+$xp/$margin,$yc-$yp/$margin,$xc+$xp,$yc-$yp); } } else { $this->StrokeLabels($this->labels[$i],$img,$la,$xc+$xp,$yc-$yp+$width*$thick); if( $this->showlabelhint ) { $img->SetColor($this->labelhintcolor); $img->Line($xc+$xp/$margin,$yc-$yp/$margin+$width*$thick,$xc+$xp,$yc-$yp+$width*$thick); } } $img->SetColor($slicecolor); $xp = $width*cos($la)/3+$xc; $yp = $yc-$height*sin($la)/3; $img->Fill(round($xp), round($yp)); // Make the edge color 35% darker $img->SetColor($slicecolor.":0.65"); if($fillPerimeter[$i]['x'] <= $xc + ($width / 2)) { $img->Fill($fillPerimeter[$i]['x'],$fillPerimeter[$i]['y']); } } } // Adjust title position $this->title->Pos($xc,$yc-$img->GetFontHeight()-$this->radius,"center","bottom"); $this->title->Stroke($img); // Draw the pie ellipse one more time since the filling might have // written partly on the lines due to the filling in the edges. $img->SetColor($this->color); $img->Ellipse($xc,$yc,$width,$height); $img->Arc($xc,$yc+$width*$thick,$width,$height,0,180); // Draw the first slice first line $a = $this->startangle; $xp = $width*cos($a)/2+$xc; $yp = $yc-$height*sin($a)/2; $img->Line($xc,$yc,$xp,$yp); // Draw the rest of the slice lines for($i=0, $a=0; $sum>0 && $idata); $i++) { $d = $this->data[$i]; $la = $a + M_PI*$d/$sum; $old_a = $a; $a += 2*M_PI*$d/$sum; $xp = $width*cos($a)/2+$xc; $yp = $yc-$height*sin($a)/2; if( $a > M_PI && $a < 0.999*2*M_PI ) $img->Line($xp,$yp,$xp,$yp+$width*$thick-1); if( $idata)-1) $img->Line($xc,$yc,$xp,$yp); } $img->Line($xc+$width/2,$yc,$xc+$width/2,$yc+$width*$thick); $img->Line($xc-$width/2,$yc,$xc-$width/2,$yc+$width*$thick); } //--------------- // PRIVATE METHODS // Position the labels of each slice function StrokeLabels($label,$img,$a,$xp,$yp) { $img->SetFont($this->font_family,$this->font_style,$this->font_size); $img->SetColor($this->font_color); $img->SetTextAlign("left","top"); $marg=6; // Position the axis title. // dx, dy is the offset from the top left corner of the bounding box that sorrounds the text // that intersects with the extension of the corresponding axis. The code looks a little // bit messy but this is really the only way of having a reasonable position of the // axis titles. $h=$img->GetTextHeight($label); $w=$img->GetTextWidth($label); while( $a > 2*M_PI ) $a -= 2*M_PI; if( $a>=7*M_PI/4 || $a <= M_PI/4 ) $dx=0; if( $a>=M_PI/4 && $a <= 3*M_PI/4 ) $dx=($a-M_PI/4)*2/M_PI; if( $a>=3*M_PI/4 && $a <= 5*M_PI/4 ) $dx=1; if( $a>=5*M_PI/4 && $a <= 7*M_PI/4 ) $dx=(1-($a-M_PI*5/4)*2/M_PI); if( $a>=7*M_PI/4 ) $dy=(($a-M_PI)-3*M_PI/4)*2/M_PI; if( $a<=M_PI/4 ) $dy=(1-$a*2/M_PI); if( $a>=M_PI/4 && $a <= 3*M_PI/4 ) $dy=1; if( $a>=3*M_PI/4 && $a <= 5*M_PI/4 ) $dy=(1-($a-3*M_PI/4)*2/M_PI); if( $a>=5*M_PI/4 && $a <= 7*M_PI/4 ) $dy=0; $img->StrokeText($xp-$dx*$w,$yp-$dy*$h,$label); } } // Class /* EOF */ ?> jpgraph-1.5.2/src/jpgraph_dir.php0100644000076400001440000000226207437547531015475 0ustar ljpusers jpgraph-1.5.2/src/jpgraph_line.php0100644000076400001440000001651507437547531015654 0ustar ljpusersshow=$f; } function SetColor($color) { $this->color = $color; } function SetFont($ff,$fs=FS_NORMAL,$fsize=10) { $this->ff=$ff; $this->fs=$fs; $this->fsize=$fsize; } function SetMargin($m) { $this->margin = $m; } function SetFormat($format,$angle=0) { $this->format= $format; $this->angle = $angle; } } //=================================================== // CLASS LinePlot // Description: //=================================================== class LinePlot extends Plot{ var $filled=false; var $fill_color; var $mark=null; var $step_style=false, $center=false; var $line_style=1; // Default to solid var $value; //--------------- // CONSTRUCTOR function LinePlot(&$datay,$datax=false) { $this->Plot($datay,$datax); $this->mark = new PlotMark(); $this->mark->SetColor($this->color); $this->value = new DisplayValue(); } //--------------- // PUBLIC METHODS // Set style, filled or open function SetFilled($f=true) { $this->filled=$f; } function SetStyle($s) { $this->line_style=$s; } function SetStepStyle($f=true) { $this->step_style = $f; } function SetColor($c) { parent::SetColor($c); $this->mark->SetColor($this->color); } function SetFillColor($c,$f=true) { $this->fill_color=$c; $this->filled=$f; } function Legend(&$graph) { if( $this->legend!="" ) { if( $this->filled ) { $graph->legend->Add($this->legend, $this->fill_color,$this->mark); } else { $graph->legend->Add($this->legend, $this->color,$this->mark,$this->line_style); } } } function SetCenter($c=true) { $this->center=$c; } // Gets called before any axis are stroked function PreStrokeAdjust(&$graph) { 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("JpGraph Error: 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( $exist_x ) $xs=$this->coords[1][0]; else $xs=0; $img->SetStartPoint($xscale->Translate($xs), $yscale->Translate($this->coords[0][0])); if( $this->filled ) { $cord[] = $xscale->Translate($xs); $cord[] = $yscale->Translate($yscale->GetMinVal()); } $cord[] = $xscale->Translate($xs); $cord[] = $yscale->Translate($this->coords[0][0]); $yt_old = $yscale->Translate($this->coords[0][0]); $img->SetColor($this->color); $img->SetLineWeight($this->weight); $img->SetLineStyle($this->line_style); for( $pnts=1; $pnts<$numpoints; ++$pnts) { if( $exist_x ) $x=$this->coords[1][$pnts]; else $x=$pnts; $xt = $xscale->Translate($x); $yt = $yscale->Translate($this->coords[0][$pnts]); $cord[] = $xt; $cord[] = $yt; if( $this->step_style ) { $img->StyleLineTo($xt,$yt_old); $img->StyleLineTo($xt,$yt); } else { $y=$this->coords[0][$pnts]; 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); } } } $yt_old = $yt; if( $this->value->show) { $sval=sprintf($this->value->format,$this->coords[0][$pnts]); $txt = new Text($sval,$xt,$yt-$this->value->margin); $txt->SetFont($this->value->ff,$this->value->fs,$this->value->fsize); $txt->Align("center","bottom"); $txt->SetOrientation($this->value->angle); $txt->SetColor($this->value->color); $txt->Stroke($img); } } if( $this->filled ) { $cord[] = $xt; $cord[] = $yscale->Translate($yscale->GetMinVal()); $img->SetColor($this->fill_color); $img->FilledPolygon($cord); $img->SetColor($this->color); $img->Polygon($cord); } $adjust=0; if( $this->filled ) $adjust=2; for($i=$adjust; $icoords[0][($i-$adjust)/2]) ) $this->mark->Stroke($img,$cord[$i],$cord[$i+1]); } } //--------------- // PRIVATE METHODS } // Class //=================================================== // CLASS AccLinePlot // Description: //=================================================== class AccLinePlot extends Plot { var $plots=null,$nbrplots=0,$numpoints=0; //--------------- // CONSTRUCTOR function AccLinePlot($plots) { $this->plots = $plots; $this->nbrplots = count($plots); $this->numpoints = $plots[0]->numpoints; } //--------------- // PUBLIC METHODS function Legend(&$graph) { foreach( $this->plots as $p ) $p->Legend($graph); } function Max() { $accymax=0; list($xmax,$dummy) = $this->plots[0]->Max(); foreach($this->plots as $p) { list($xm,$ym) = $p->Max(); $xmax = max($xmax,$xm); $accymax += $ym; } return array($xmax,$accymax); } function Min() { list($xmin,$ymin)=$this->plots[0]->Min(); foreach( $this->plots as $p ) { list($xm,$ym)=$p->Min(); $xmin=Min($xmin,$xm); $ymin=Min($ymin,$ym); } return array($xmin,$ymin); } // 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); // 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 */ ?> jpgraph-1.5.2/src/jpgraph.php0100644000076400001440000050031107437547531014635 0ustar ljpusers You can't have both background images and truetype fonts in the same // image until these bugs has been fixed in GD 2.01 DEFINE('USE_TRUECOLOR',false); //------------------------------------------------------------------ // Constants which are used as parameters for the method calls //------------------------------------------------------------------ // TTF Font families DEFINE("FF_COURIER",10); DEFINE("FF_VERDANA",11); DEFINE("FF_TIMES",12); DEFINE("FF_HANDWRT",13); DEFINE("FF_COMIC",14); DEFINE("FF_ARIAL",15); DEFINE("FF_BOOK",16); // TTF Font styles DEFINE("FS_NORMAL",1); DEFINE("FS_BOLD",2); DEFINE("FS_ITALIC",3); DEFINE("FS_BOLDIT",4); //Definitions for internal font, new style DEFINE("FF_FONT0",1); DEFINE("FF_FONT1",2); DEFINE("FF_FONT2",4); //Definitions for internal font, old style // (Only defined here to be able to generate an error mesage // when used) DEFINE("FONT0",99); // Deprecated from 1.2 DEFINE("FONT1",98); // Deprecated from 1.2 DEFINE("FONT1_BOLD",97); // Deprecated from 1.2 DEFINE("FONT2",96); // Deprecated from 1.2 DEFINE("FONT2_BOLD",95); // Deprecated from 1.2 // Tick density DEFINE("TICKD_DENSE",1); DEFINE("TICKD_NORMAL",2); DEFINE("TICKD_SPARSE",3); DEFINE("TICKD_VERYSPARSE",4); // Side for ticks and labels. DEFINE("SIDE_LEFT",-1); DEFINE("SIDE_RIGHT",1); DEFINE("SIDE_DOWN",-1); DEFINE("SIDE_UP",1); // Legend type stacked vertical or horizontal DEFINE("LEGEND_VERT",0); DEFINE("LEGEND_HOR",1); // Mark types for plot marks DEFINE("MARK_SQUARE",1); DEFINE("MARK_UTRIANGLE",2); DEFINE("MARK_DTRIANGLE",3); DEFINE("MARK_DIAMOND",4); DEFINE("MARK_CIRCLE",5); DEFINE("MARK_FILLEDCIRCLE",6); DEFINE("MARK_CROSS",7); DEFINE("MARK_STAR",8); DEFINE("MARK_X",9); // Styles for gradient color fill DEFINE("GRAD_VER",1); DEFINE("GRAD_HOR",2); DEFINE("GRAD_MIDHOR",3); DEFINE("GRAD_MIDVER",4); DEFINE("GRAD_CENTER",5); DEFINE("GRAD_WIDE_MIDVER",6); DEFINE("GRAD_WIDE_MIDHOR",7); // Inline defines DEFINE("INLINE_YES",1); DEFINE("INLINE_NO",0); // Format for background images DEFINE("BGIMG_FILLPLOT",1); DEFINE("BGIMG_FILLFRAME",2); DEFINE("BGIMG_COPY",3); DEFINE("BGIMG_CENTER",4); // Depth of objects DEFINE("DEPTH_BACK",0); DEFINE("DEPTH_FRONT",1); // Direction DEFINE("VERTICAL",1); DEFINE("HORIZONTAL",0); // 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_LVERT",4); // Vertical lines DEFINE("BAND_LHOR",5); // Horizontal lines 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 // // First of all set up a default error handler // //============================================================= // The default trivial error handler. // A production quality error handler should generate an image // containing the text of the error. //============================================================= class JpGraphErrObject { function JpGraphErrObject() { // Empty. Reserved for future use } // If aHalt is true then execution can't continue. Typical used for // fatal errors function Raise($aMsg,$aHalt=true) { if( $aHalt ) die($aMsg); else echo $aMsg."

"; } } // // A wrapper class that is used to access the specified error object // (to hide the global error parameter and avoid having a GLOBAL directive // in all methods. // class JpGraphError { function Install($aErrObject) { GLOBAL $__jpg_err; $__jpg_err = $aErrObject; } function Raise($aMsg,$aHalt=true){ GLOBAL $__jpg_err; $tmp = new $__jpg_err; $tmp->Raise($aMsg,$aHalt); } } // // ... and install the default error handler // JpGraphError::Install("JpGraphErrObject"); // //Check if there were any warnings, perhaps some wrong includes by the //user // if( isset($GLOBALS['php_errormsg']) ) { JpGraphError::Raise("General PHP error:
".$GLOBALS['php_errormsg']); } // // Check what version of the GD library is being used // if(function_exists('imagecopyresampled') ) { $gd2 = true; $copyfunc = "imagecopyresampled"; } elseif(function_exists('imagecopyresized')) { $copyfunc = "imagecopyresized"; $gd2 = false; } else { JpGraphError::Raise("JpGraph Error: Your PHP installation does not have the required GD library. Please see the PHP documentation on how to install and enable the GD library."); } // Usefull mathematical function function sign($a) {if( $a>=0) return 1; else return -1;} // Utility function to generate an image name based on the filename we // are running from AND assuming we use auto detection of graphic format // (top level), i.e it is safe to call this function // from a script that uses JpGraph function GenImgName() { global $HTTP_SERVER_VARS; $supported = imagetypes(); if( $supported & IMG_PNG ) $img_format="png"; elseif( $supported & IMG_GIF ) $img_format="gif"; elseif( $supported & IMG_JPG ) $img_format="jpeg"; if( !isset($HTTP_SERVER_VARS['PHP_SELF']) ) JpGraphError::Raise("JpGraph Error: Can't access PHP_SELF, PHP global variable. You can't run PHP from command line if you want to use the 'auto' naming of cache or image files."); $fname=basename($HTTP_SERVER_VARS['PHP_SELF']); // Replace the ".php" extension with the image format extension return substr($fname,0,strlen($fname)-4).".".$img_format; } class LanguageConv { // Translate iso encoding to unicode function iso2uni ($isoline){ for ($i=0; $i < strlen($isoline); $i++){ $thischar=substr($isoline,$i,1); $charcode=ord($thischar); $uniline.=($charcode>175) ? "&#" . (1040+($charcode-176)). ";" : $thischar; } return $uniline; } function ToCyrillic($aTxt) { $koistring = $aTxt; $isostring = convert_cyr_string($koistring, "k", "i"); $unistring = LanguageConv::iso2uni($isostring); $this->t = $unistring; return $aTxt; } } //=================================================== // CLASS JpgTimer // Description: General timing utility class to handle // timne measurement of generating graphs. Multiple // timers can be started by pushing new on a stack. //=================================================== class JpgTimer { var $start; var $idx; //--------------- // CONSTRUCTOR function JpgTimer() { $this->idx=0; } //--------------- // PUBLIC METHODS // Push a new timer start on stack function Push() { list($ms,$s)=explode(" ",microtime()); $this->start[$this->idx++]=floor($ms*1000) + 1000*$s; } // Pop the latest timer start and return the diff with the // current time function Pop() { assert($this->idx>0); list($ms,$s)=explode(" ",microtime()); $etime=floor($ms*1000) + (1000*$s); $this->idx--; return $etime-$this->start[$this->idx]; } } // Class //=================================================== // CLASS Graph // Description: Main class to handle graphs //=================================================== class Graph { var $cache=null; // Cache object (singleton) var $img=null; // Img object (singleton) var $plots=array(); // Array of all plot object in the graph (for Y 1 axis) var $y2plots=array();// Array of all plot object in the graph (for Y 2 axis) var $xscale=null; // X Scale object (could be instance of LinearScale or LogScale var $yscale=null,$y2scale=null; var $cache_name; // File name to be used for the current graph in the cache directory var $xgrid=null; // X Grid object (linear or logarithmic) var $ygrid=null,$y2grid=null; //dito for Y var $doframe=true,$frame_color=array(0,0,0), $frame_weight=1; // Frame around graph var $boxed=false, $box_color=array(0,0,0), $box_weight=1; // Box around plot area var $doshadow=false,$shadow_width=4,$shadow_color=array(102,102,102); // Shadow for graph var $xaxis=null; // X-axis (instane of Axis class) var $yaxis=null, $y2axis=null; // Y axis (instance of Axis class) var $margin_color=array(198,198,198); // Margin coor of graph var $plotarea_color=array(255,255,255); // Plot area color var $title,$subtitle; // Title and subtitle text object var $axtype="linlin"; // Type of axis var $xtick_factor; // Factot to determine the maximum number of ticks depending on the plot with var $texts=null; // Text object to ge shown in the graph var $lines=null; var $bands=null; var $text_scale_off=0; // Text scale offset in world coordinates var $background_image="",$background_image_type=-1,$background_image_format="png"; var $background_image_bright=0,$background_image_contr=0,$background_image_sat=0; var $image_bright=0, $image_contr=0, $image_sat=0; var $inline; var $showcsim=0,$csimcolor="red"; //debug stuff, draw the csim boundaris on the image if <>0 var $grid_depth=DEPTH_BACK; // Draw grid under all plots as default //--------------- // CONSTRUCTOR // aWIdth Width in pixels of image // aHeight Height in pixels of image // aCachedName Name for image file in cache directory // aTimeOut Timeout in minutes for image in cache // aInline If true the image is streamed back in the call to Stroke() // If false the image is just created in the cache function Graph($aWidth=300,$aHeight=200,$aCachedName="",$aTimeOut=0,$aInline=true) { // If timing is used create a new timing object if( BRAND_TIMING ) { global $tim; $tim = new JpgTimer(); $tim->Push(); } // Automtically generate the image file name based on the name of the script that // generates the graph if( $aCachedName=="auto" ) $aCachedName=GenImgName(); // Should the image be streamed back to the browser or only to the cache? $this->inline=$aInline; $this->img = new RotImage($aWidth,$aHeight); $this->cache = new ImgStreamCache($this->img); $this->cache->SetTimeOut($aTimeOut); $this->title = new Text(); $this->subtitle = new Text(); $this->legend = new Legend(); // If the cached version exist just read it directly from the // cache, stream it back to browser and exit if( $aCachedName!="" && READ_CACHE && $aInline ) if( $this->cache->GetAndStream($aCachedName) ) { exit(); } $this->cache_name = $aCachedName; $this->SetTickDensity(); // Normal density } //--------------- // PUBLIC METHODS // Should the grid be in front or back of the plot? function SetGridDepth($aDepth) { $this->grid_depth=$aDepth; } // Specify graph angle 0-360 degrees. function SetAngle($aAngle) { $this->img->SetAngle($aAngle); } // Add a plot object to the graph function Add(&$aPlot) { if( $aPlot == null ) JpGraphError::Raise("JpGraph Error: Graph::Add() You tried to add a null plot to the graph."); $this->plots[] = &$aPlot; } // Add plot to second Y-scale function AddY2(&$aPlot) { if( $aPlot == null ) JpGraphError::Raise("JpGraph Error: Graph::AddY2() You tried to add a null plot to the graph."); $this->y2plots[] = &$aPlot; } // Add text object to the graph function AddText(&$aTxt) { if( $aTxt == null ) JpGraphError::Raise("JpGraph Error: Graph::AddText() You tried to add a null text to the graph."); if( is_array($aTxt) ) { for($i=0; $itexts[]=&$aTxt[$i]; } else $this->texts[] = &$aTxt; } // Add a line object (class PlotLine) to the graph function AddLine(&$aLine) { if( $aLine == null ) JpGraphError::Raise("JpGraph Error: Graph::AddLine() You tried to add a null line to the graph."); if( is_array($aLine) ) { for($i=0; $ilines[]=&$aLine[$i]; } else $this->lines[] = &$aLine; } // Add vertical or horizontal band function AddBand(&$aBand) { if( $aBand == null ) JpGraphError::Raise("JpGraph Error: Graph::AddBand() You tried to add a null band to the graph."); if( is_array($aBand) ) { for($i=0; $ibands[] = &$aBand[$i]; } else $this->bands[] = &$aBand; } // Specify a background image function SetBackgroundImage($aFileName,$aBgType=BKIMG_FILLPLOT,$aImgFormat="png") { if( $GLOBALS["gd2"] && !USE_TRUECOLOR ) { JpGraphError::Raise("JpGraph Error:You are using GD 2.x and are trying to use a background images on a non truecolor image.
To use background images with GD 2.x you must enable truecolor by setting the USE_TRUECOLOR constant to TRUE.
Note: Due to a bug in GD 2.0.1 using any truetype fonts with truecolor images will result in very poor quality fonts."); } $this->background_image = $aFileName; $this->background_image_type=$aBgType; $this->background_image_format=$aImgFormat; } // Adjust brightness and constrast for background image function AdjBackgroundImage($aBright,$aContr=0,$aSat=0) { $this->background_image_bright=$aBright; $this->background_image_contr=$aContr; $this->background_image_sat=$aSat; } // Adjust brightness and constrast for image function AdjImage($aBright,$aContr=0,$aSat=0) { $this->image_bright=$aBright; $this->image_contr=$aContr; $this->image_sat=$aSat; } // Set a frame around the plot area function SetBox($aDrawPlotFrame=true,$aPlotFrameColor=array(0,0,0),$aPlotFrameWeight=1) { $this->boxed = $aDrawPlotFrame; $this->box_weight = $aPlotFrameWeight; $this->box_color = $aPlotFrameColor; } // Specify color for the plotarea (not the margins) function SetColor($aColor) { $this->plotarea_color=$aColor; } // Specify color for the margins (all areas outside the plotarea) function SetMarginColor($aColor) { $this->margin_color=$aColor; } // Set a frame around the entire image function SetFrame($aDrawImgFrame=true,$aImgFrameColor=array(0,0,0),$aImgFrameWeight=1) { $this->doframe = $aDrawImgFrame; $this->frame_color = $aImgFrameColor; $this->frame_weight = $aImgFrameWeight; } // Set the shadow around the whole image function SetShadow($aShowShadow=true,$aShadowWidth=5,$aShadowColor=array(102,102,102)) { $this->doshadow = $aShowShadow; $this->shadow_color = $aShadowColor; $this->shadow_width = $aShadowWidth; } // Specify x,y scale. Note that if you manually specify the scale // you must also specify the tick distance with a call to Ticks::Set() function SetScale($aAxisType,$aYMin=1,$aYMax=1,$aXMin=1,$aXMax=1) { $this->axtype = $aAxisType; $yt=substr($aAxisType,-3,3); if( $yt=="lin" ) $this->yscale = new LinearScale($aYMin,$aYMax); elseif( $yt == "int" ) { $this->yscale = new LinearScale($aYMin,$aYMax); $this->yscale->SetIntScale(); } elseif( $yt=="log" ) $this->yscale = new LogScale($aYMin,$aYMax); else JpGraphError::Raise("JpGraph Error: Unknown scale specification for Y-scale. ($axtype)"); $xt=substr($aAxisType,0,3); if( $xt == "lin" || $xt == "tex" ) $this->xscale = new LinearScale($aXMin,$aXMax,"x"); elseif( $xt == "int" ) { $this->xscale = new LinearScale($aXMin,$aXMax,"x"); $this->xscale->SetIntScale(); } elseif( $xt == "log" ) $this->xscale = new LogScale($aXMin,$aXMax,"x"); else JpGraphError::Raise("JpGraph Error: Unknown scale specification for X-scale. ($aAxisType)"); $this->xscale->Init($this->img); $this->yscale->Init($this->img); $this->xaxis = new Axis($this->img,$this->xscale); $this->yaxis = new Axis($this->img,$this->yscale); $this->xgrid = new Grid($this->xaxis); $this->ygrid = new Grid($this->yaxis); $this->ygrid->Show(); } // Specify secondary Y scale function SetY2Scale($aAxisType="lin",$aY2Min=1,$aY2Max=1) { if( $aAxisType=="lin" ) $this->y2scale = new LinearScale($aY2Min,$aY2Max); elseif( $aAxisType=="log" ) { $this->y2scale = new LogScale($aY2Min,$aY2Max); } else JpGraphError::Raise("JpGraph: Unsupported Y2 axis type: $axtype
"); $this->y2scale->Init($this->img); $this->y2axis = new Axis($this->img,$this->y2scale); $this->y2axis->scale->ticks->SetDirection(SIDE_LEFT); $this->y2axis->SetLabelPos(SIDE_RIGHT); // Deafult position is the max x-value $this->y2axis->SetPos($this->xscale->GetMaxVal()); $this->y2grid = new Grid($this->y2axis); } // Specify density of ticks when autoscaling 'normal', 'dense', 'sparse', 'verysparse' // The dividing factor have been determined heuristically according to my aesthetic // sense (or lack off) y.m.m.v ! function SetTickDensity($aYDensity=TICKD_NORMAL,$aXDensity=TICKD_NORMAL) { $this->xtick_factor=30; $this->ytick_factor=25; switch( $aYDensity ) { case TICKD_DENSE: $this->ytick_factor=12; break; case TICKD_NORMAL: $this->ytick_factor=25; break; case TICKD_SPARSE: $this->ytick_factor=40; break; case TICKD_VERYSPARSE: $this->ytick_factor=100; break; default: JpGraphError::Raise("JpGraph: Unsupported Tick density: $densy"); } switch( $aXDensity ) { case TICKD_DENSE: $this->xtick_factor=18; break; case TICKD_NORMAL: $this->xtick_factor=30; break; case TICKD_SPARSE: $this->xtick_factor=45; break; case TICKD_VERYSPARSE: $this->xtick_factor=60; break; default: JpGraphError::Raise("JpGraph: Unsupported Tick density: $densx"); } } // Get a string of all image map areas function GetCSIMareas() { $csim=""; foreach ($this->plots as $p) { $csim.= $p->GetCSIMareas(); } return $csim; } // Get a complete .. tag for the final image map function GetHTMLImageMap($aMapName) { $im = "\n"; $im .= $this->GetCSIMareas(); $im .= ""; return $im; } // Stroke the graph // $aStrokeFileName If != "" the image will be written to this file and NOT // streamed back to the browser function Stroke($aStrokeFileName="") { // Do any pre-stroke adjustment that is needed by the different plot types // (i.e bar plots want's to add an offset to the x-labels etc) for($i=0; $iplots) ; ++$i ) { $this->plots[$i]->PreStrokeAdjust($this); $this->plots[$i]->Legend($this); } // Any plots on the second Y scale? if( $this->y2scale != null ) { for($i=0; $iy2plots) ; ++$i ) { $this->y2plots[$i]->PreStrokeAdjust($this); $this->y2plots[$i]->Legend($this); } } // Bail out if any of the Y-axis not been specified and // has no plots. (This means it is impossible to do autoscaling and // no other scale was given so we can't possible draw anything). If you use manual // scaling you also have to supply the tick steps as well. if( (!$this->yscale->IsSpecified() && count($this->plots)==0) || ($this->y2scale!=null && !$this->y2scale->IsSpecified() && count($this->y2plots)==0) ) { JpGraphError::Raise("JpGraph: Can't draw unspecified Y-scale.
You have either:
* Specified an Y axis for autoscaling but have not supplied any plots
* Specified a scale manually but have forgot to specify the tick steps"); } // Bail out if no plots and no specified X-scale if( (!$this->xscale->IsSpecified() && count($this->plots)==0 && count($this->y2plots)==0) ) JpGraphError::Raise("JpGraph: Can't draw unspecified X-scale.
No plots.
"); //Check if we should autoscale y-axis if( !$this->yscale->IsSpecified() && count($this->plots)>0 ) { list($min,$max) = $this->GetPlotsYMinMax($this->plots); $this->yscale->AutoScale($this->img,$min,$max,$this->img->plotheight/$this->ytick_factor); } if( $this->y2scale != null) if( !$this->y2scale->IsSpecified() && count($this->y2plots)>0 ) { list($min,$max) = $this->GetPlotsYMinMax($this->y2plots); $this->y2scale->AutoScale($this->img,$min,$max,$this->img->plotheight/$this->ytick_factor); } //Check if we should autoscale x-axis if( !$this->xscale->IsSpecified() ) { if( substr($this->axtype,0,4) == "text" ) { $max=0; foreach( $this->plots as $p ) $max=max($max,$p->numpoints-1); $min=0; $this->xscale->Update($this->img,$min,$max); $this->xscale->ticks->Set($this->xaxis->tick_step,1); $this->xscale->ticks->SupressMinorTickMarks(); } else { list($min,$ymin) = $this->plots[0]->Min(); list($max,$ymax) = $this->plots[0]->Max(); foreach( $this->plots as $p ) { list($xmin,$ymin) = $p->Min(); list($xmax,$ymax) = $p->Max(); $min = Min($xmin,$min); $max = Max($xmax,$max); } $this->xscale->AutoScale($this->img,$min,$max,$this->img->plotwidth/$this->xtick_factor); } //Adjust position of y-axis and y2-axis to minimum/maximum of x-scale $this->yaxis->SetPos($this->xscale->GetMinVal()); if( $this->y2axis != null ) { $this->y2axis->SetPos($this->xscale->GetMaxVal()); $this->y2axis->SetTitleSide(SIDE_RIGHT); } } // If we have a negative values and x-axis position is at 0 // we need to supress the first and possible the last tick since // they will be drawn on top of the y-axis (and possible y2 axis) // The test below might seem strange the reasone being that if // the user hasn't specified a value for position this will not // be set until we do the stroke for the axis so as of now it // is undefined. if( !$this->xaxis->pos && $this->yscale->GetMinVal() < 0 ) { $this->yscale->ticks->SupressZeroLabel(false); $this->xscale->ticks->SupressFirst(); if( $this->y2axis != null ) { $this->xscale->ticks->SupressLast(); } } $this->StrokePlotArea(); // Stroke axis $this->xaxis->Stroke($this->yscale); $this->yaxis->Stroke($this->xscale); // Stroke bands if( $this->bands != null ) for($i=0; $ibands); ++$i) { // Stroke all bands that asks to be in the background if( $this->bands[$i]->depth == DEPTH_BACK ) $this->bands[$i]->Stroke($this->img,$this->xscale,$this->yscale); } if( $this->grid_depth == DEPTH_BACK ) { $this->ygrid->Stroke(); $this->xgrid->Stroke(); } // Stroke Y2-axis if( $this->y2axis != null ) { $this->y2axis->Stroke($this->xscale); $this->y2grid->Stroke(); } $oldoff=$this->xscale->off; if(substr($this->axtype,0,4)=="text") { $this->xscale->off += ceil($this->xscale->scale_factor*$this->text_scale_off*$this->xscale->ticks->minor_step); } // Stroke all plots for Y1 axis for($i=0; $iplots) ; ++$i ) { $this->plots[$i]->Stroke($this->img,$this->xscale,$this->yscale); $this->plots[$i]->StrokeMargin($this->img); } // Stroke all plots for Y2 axis if( $this->y2scale != null ) for($i=0; $i< count($this->y2plots); ++$i ) { $this->y2plots[$i]->Stroke($this->img,$this->xscale,$this->y2scale); } $this->xscale->off=$oldoff; if( $this->grid_depth == DEPTH_FRONT ) { $this->ygrid->Stroke(); $this->xgrid->Stroke(); } // Stroke bands if( $this->bands!= null ) for($i=0; $ibands); ++$i) { // Stroke all bands that asks to be in the foreground if( $this->bands[$i]->depth == DEPTH_FRONT ) $this->bands[$i]->Stroke($this->img,$this->xscale,$this->yscale); } // Stroke any lines added if( $this->lines != null ) { for($i=0; $ilines); ++$i) { $this->lines[$i]->Stroke($this->img,$this->xscale,$this->yscale); } } // Finally draw the axis again since some plots may have nagged // the axis in the edges. $this->yaxis->Stroke($this->xscale); $this->xaxis->Stroke($this->yscale); if( $this->y2scale != null) $this->y2axis->Stroke($this->xscale); $this->StrokePlotBox(); // The titles and legends never gets rotated so make sure // that the angle is 0 before stroking them $aa = $this->img->SetAngle(0); $this->StrokeTitles(); $this->legend->Stroke($this->img); $this->StrokeTexts(); $this->img->SetAngle($aa); // Draw an outline around the image map if(JPG_DEBUG) $this->DisplayClientSideaImageMapAreas(); // Adjust the appearance of the image $this->AdjustSaturationBrightnessContrast(); // Finally stream the generated picture $this->cache->PutAndStream($this->img,$this->cache_name,$this->inline,$aStrokeFileName); } //--------------- // PRIVATE METHODS // Private helper function for backgound image function LoadBkgImage($aImgFormat="png",$aBright=0,$aContr=0) { $f = "imagecreatefrom".$aImgFormat; $imgtag = $aImgFormat; if( $aImgFormat == "jpeg" ) $imgtag = "jpg"; if( !strstr($this->background_image,$imgtag) && strstr($this->background_image,".") ) JpGraphError::Raise("JpGraph Error: Background image seems to be of different type (has different file extension) than specified imagetype.
Specified: '".$aImgFormat."'
File: '".$this->background_image."'"); $img = $f($this->background_image); if( !$img ) { JpGraphError::Raise("JpGraph Error: Can't read background image: '".$this->background_image."'"); } return $img; } // Private // Stroke the plot area with either a solid color or a background image function StrokePlotArea() { // Copy in background image if( $this->background_image != "" ) { $bkgimg = $this->LoadBkgImage($this->background_image_format); $this->img->_AdjBrightContrast($bkgimg,$this->background_image_bright, $this->background_image_contr); $this->img->_AdjSat($bkgimg,$this->background_image_sat); $bw = ImageSX($bkgimg); $bh = ImageSY($bkgimg); $aa = $this->img->SetAngle(0); switch( $this->background_image_type ) { case BGIMG_FILLPLOT: // Resize to just fill the plotarea $this->StrokeFrame(); $GLOBALS["copyfunc"]($this->img->img,$bkgimg, $this->img->left_margin,$this->img->top_margin, 0,0,$this->img->plotwidth,$this->img->plotheight, $bw,$bh); break; case BGIMG_FILLFRAME: // Fill the whole area from upper left corner, resize to just fit $GLOBALS["copyfunc"]($this->img->img,$bkgimg, 0,0,0,0, $this->img->width,$this->img->height, $bw,$bh); $this->StrokeFrame(); break; case BGIMG_COPY: // Just copy the image from left corner, no resizing $GLOBALS["copyfunc"]($this->img->img,$bkgimg, 0,0,0,0, $bw,$bh, $bw,$bh); $this->StrokeFrame(); break; case BGIMG_CENTER: // Center original image in the plot area $centerx = round($this->img->plotwidth/2+$this->img->left_margin-$bw/2); $centery = round($this->img->plotheight/2+$this->img->top_margin-$bh/2); $GLOBALS["copyfunc"]($this->img->img,$bkgimg, $centerx,$centery, 0,0, $bw,$bh, $bw,$bh); $this->StrokeFrame(); break; default: JpGraphError::Raise("JpGraph Error: Unknown background image layout"); } $this->img->SetAngle($aa); } else { $aa = $this->img->SetAngle(0); $this->StrokeFrame(); $this->img->SetAngle($aa); $this->img->PushColor($this->plotarea_color); // Note: To be consistent we really should take a possible shadow // into account. However, that causes some problem for the LinearScale class // since in the current design it does not have any links to class Graph which // means it has no way of compensating for the adjusted plotarea in case of a // shadow. So, until I redesign LinearScale we can't compensate for this. // So just set the two adjustment parameters to zero for now. $boxadj = 0; //$this->doframe ? $this->frame_weight : 0 ; $adj = 0; //$this->doshadow ? $this->shadow_width : 0 ; $this->img->FilledRectangle($this->img->left_margin+$boxadj, $this->img->top_margin+$boxadj, $this->img->width-$this->img->right_margin-$adj-2*$boxadj, $this->img->height-$this->img->bottom_margin-$adj-2*$boxadj); $this->img->PopColor(); } $this->img->SetAngle($aa); } function StrokePlotBox() { // Should we draw a box around the plot area? if( $this->boxed ) { $this->img->SetLineWeight($this->box_weight); $this->img->SetColor($this->box_color); $this->img->Rectangle( $this->img->left_margin,$this->img->top_margin, $this->img->width-$this->img->right_margin, $this->img->height-$this->img->bottom_margin); } } function StrokeTitles() { // Stroke title $this->title->Center($this->img->left_margin,$this->img->width-$this->img->right_margin,5); $this->title->Stroke($this->img); // ... and subtitle $this->subtitle->Center($this->img->left_margin,$this->img->width-$this->img->right_margin, 7+$this->title->GetFontHeight($this->img)); $this->subtitle->Stroke($this->img); } function StrokeTexts() { // Stroke any user added text objects if( $this->texts != null ) { for($i=0; $itexts); ++$i) { $this->texts[$i]->Stroke($this->img); } } } function DisplayClientSideaImageMapAreas() { // Debug stuff - display the outline of the image map areas foreach ($this->plots as $p) { $csim.= $p->GetCSIMareas(); } $csim.= $this->legend->GetCSIMareas(); if (preg_match_all("/area shape=\"(\w+)\" coords=\"([0-9\, ]+)\"/", $csim, $coords)) { $this->img->SetColor($this->csimcolor); for ($i=0; $iimg->SetStartPoint($pts[1][count($pts[0])-1],$pts[2][count($pts[0])-1]); for ($j=0; $jimg->LineTo($pts[1][$j],$pts[2][$j]); } } else if ($coords[1][$i]=="rect") { $pts = preg_split('/,/', $coords[2][$i]); $this->img->SetStartPoint($pts[0],$pts[1]); $this->img->LineTo($pts[2],$pts[1]); $this->img->LineTo($pts[2],$pts[3]); $this->img->LineTo($pts[0],$pts[3]); $this->img->LineTo($pts[0],$pts[1]); } } } } function AdjustSaturationBrightnessContrast() { // Adjust the brightness and contrast of the image if( $this->image_contr || $this->image_bright ) $this->img->AdjBrightContrast($this->image_bright,$this->image_contr); if( $this->image_sat ) $this->img->AdjSat($this->image_sat); } // Text scale offset in world coordinates function SetTextScaleOff($aOff) { $this->text_scale_off = $aOff; } // Get min and max values for all included plots function GetPlotsYMinMax(&$aPlots) { list($xmax,$max) = $aPlots[0]->Max(); list($xmin,$min) = $aPlots[0]->Min(); for($i=0; $iMax(); list($xmin,$ymin)=$aPlots[$i]->Min(); if (!is_string($ymax) || $ymax != "") $max=max($max,$ymax); if (!is_string($ymin) || $ymin != "") $min=min($min,$ymin); } if( $min == "" ) $min = 0; if( $max == "" ) $max = 0; if( $min == 0 && $max == 0 ) { // Special case if all values are 0 $min=0;$max=1; } return array($min,$max); } // Draw a frame around the image function StrokeFrame() { if( !$this->doframe ) return; if( $this->doshadow ) { $this->img->SetColor($this->frame_color); if( $this->background_image_type <= 1 ) $c = $this->margin_color; else $c = false; $this->img->ShadowRectangle(0,0,$this->img->width,$this->img->height, $c,$this->shadow_width); } else { $this->img->SetLineWeight($this->frame_weight); if( $this->background_image_type <= 1 ) { $this->img->SetColor($this->margin_color); $this->img->FilledRectangle(1,1,$this->img->width-2,$this->img->height-2); } $this->img->SetColor($this->frame_color); $this->img->Rectangle(0,0,$this->img->width-1,$this->img->height-1); } } } // Class //=================================================== // CLASS TTF // Description: Handle TTF font names //=================================================== class TTF { var $font_fam; //--------------- // CONSTRUCTOR function TTF() { // Base file names for available fonts $this->font_fam=array( FF_COURIER => TTF_DIR."courier", FF_VERDANA => TTF_DIR."verdana", FF_TIMES => TTF_DIR."times", FF_HANDWRT => TTF_DIR."handwriting", FF_COMIC => TTF_DIR."comic", FF_ARIAL => TTF_DIR."arial", FF_BOOK => TTF_DIR."bookant"); } //--------------- // PUBLIC METHODS // Create the TTF file from the font specification function File($fam,$style=FS_NORMAL) { $f=$this->font_fam[$fam]; if( !$f ) JpGraphError::Raise("JpGraph Error: Unknown TTF font family."); switch( $style ) { case FS_NORMAL: break; case FS_BOLD: $f .= "bd"; break; case FS_ITALIC: $f .= "i"; break; case FS_BOLDIT: $f .= "bi"; break; default: JpGraphError::Raise("JpGraph Error: Unknown TTF Style."); } $f .= ".ttf"; // Check that file exist if( !file_exists($f) ) JpGraphError::Raise("JpGraph Error: Can't open font file \"$f\". Wrong directory?"); return $f; } } // Class //=================================================== // CLASS LineProperty // Description: Holds properties for a line //=================================================== class LineProperty { var $iWeight=1, $iColor="black",$iStyle="solid"; var $iShow=true; //--------------- // PUBLIC METHODS function SetColor($aColor) { $this->iColor = $aColor; } function SetWeight($aWeight) { $this->iWeight = $aWeight; } function SetStyle($aStyle) { $this->iStyle = $aStyle; } function Show($aShow=true) { $this->iShow=$aShow; } function Stroke($aImg,$aX1,$aY1,$aX2,$aY2) { if( $this->iShow ) { $aImg->SetColor($this->iColor); $aImg->SetLineWeight($this->iWeight); $aImg->SetLineStyle($this->iStyle); $aImg->StyleLine($aX1,$aY1,$aX2,$aY2); } } } //=================================================== // CLASS Text // Description: Arbitrary text object that can be added to the graph //=================================================== class Text { var $t,$x=0,$y=0,$halign="left",$valign="top",$color=array(0,0,0); var $font_family=FF_FONT1,$font_style=FS_NORMAL,$font_size=12,$hide=false,$dir=0; var $boxed=false; // Should the text be boxed var $paragraph_align="left"; //--------------- // CONSTRUCTOR // Create new text at absolute pixel coordinates function Text($aTxt="",$aXAbsPos=0,$aYAbsPos=0) { $this->t = $aTxt; $this->x = $aXAbsPos; $this->y = $aYAbsPos; } //--------------- // PUBLIC METHODS // Set the string in the text object function Set($aTxt) { $this->t = $aTxt; } // Specify the position and alignment for the text object function Pos($aXAbsPos=0,$aYAbsPos=0,$aHAlign="left",$aVAlign="top") { $this->x = $aXAbsPos; $this->y = $aYAbsPos; $this->halign = $aHAlign; $this->valign = $aVAlign; } // Specify alignment for the text function Align($aHAlign,$aVAlign="top") { $this->halign = $aHAlign; $this->valign = $aVAlign; } // Specifies the alignment for a multi line text function ParagraphAlign($aAlign) { $this->paragraph_align = $aAlign; } // Specify that the text should be boxed. fcolor=frame color, bcolor=border color, // $shadow=drop shadow should be added around the text. function SetBox($aFrameColor=array(255,255,255),$aBorderColor=array(0,0,0),$aShadow=false) { if( $aFrameColor==false ) $this->boxed=false; else $this->boxed=true; $this->fcolor=$aFrameColor; $this->bcolor=$aBorderColor; $this->shadow=$aShadow; } // Hide the text function Hide($aHide=true) { $this->hide=$aHide; } // This looks ugly since it's not a very orthogonal design // but I added this "inverse" of Hide() to harmonize // with some classes which I designed more recently (especially) // jpgraph_gantt function Show($aShow=true) { $this->hide=!$aShow; } // Specify font function SetFont($aFamily,$aStyle=FS_NORMAL,$aSize=10) { $this->font_family=$aFamily; $this->font_style=$aStyle; $this->font_size=$aSize; } // Center the text between $left and $right coordinates function Center($aLeft,$aRight,$aYAbsPos=false) { $this->x = $aLeft + ($aRight-$aLeft )/2; $this->halign = "center"; if( is_numeric($aYAbsPos) ) $this->y = $aYAbsPos; } // Set text color function SetColor($aColor) { $this->color = $aColor; } // Orientation of text. Note only TTF fonts can have an arbitrary angle function SetOrientation($aDirection=0) { if( is_numeric($aDirection) ) $this->dir=$aDirection; elseif( $aDirection=="h" ) $this->dir = 0; elseif( $aDirection=="v" ) $this->dir = 90; else JpGraphError::Raise("JpGraph Error: Invalid direction specified for text."); } // Total width of text function GetWidth(&$aImg) { $aImg->SetFont($this->font_family,$this->font_style,$this->font_size); return $aImg->GetTextWidth($this->t); } // Hight of font function GetFontHeight(&$aImg) { $aImg->SetFont($this->font_family,$this->font_style,$this->font_size); return $aImg->GetFontHeight(); } function GetTextHeight(&$aImg) { $aImg->SetFont($this->font_family,$this->font_style,$this->font_size); return $aImg->GetTextHeight($this->t); } // Display text in image function Stroke(&$aImg,$x=-1,$y=-1) { if( $x>-1 ) $this->x = $x; if( $y>-1 ) $this->y = $y; // If position been given as a fraction of the image size // calculate the absolute position if( $this->x < 1 ) $this->x *= $aImg->width; if( $this->y < 1 ) $this->y *= $aImg->height; $aImg->PushColor($this->color); $aImg->SetFont($this->font_family,$this->font_style,$this->font_size); $aImg->SetTextAlign($this->halign,$this->valign); if( $this->boxed ) { if( $this->fcolor=="nofill" ) $this->fcolor=false; $aImg->StrokeBoxedText($this->x,$this->y,$this->t, $this->dir,$this->fcolor,$this->bcolor,$this->shadow, $this->paragraph_align); } else { $aImg->StrokeText($this->x,$this->y,$this->t,$this->dir, $this->paragraph_align); } $aImg->PopColor($this->color); } } // Class //=================================================== // CLASS Grid // Description: responsible for drawing grid lines in graph //=================================================== class Grid { var $img; var $scale; var $grid_color=array(196,196,196); var $type="solid"; var $show=false, $showMinor=false,$weight=1; //--------------- // CONSTRUCTOR function Grid(&$aAxis) { $this->scale = &$aAxis->scale; $this->img = &$aAxis->img; } //--------------- // PUBLIC METHODS function SetColor($aColor) { $this->grid_color=$aColor; } function SetWeight($aWeight) { $this->weight=$aWeight; } // Specify if grid should be dashed, dotted or solid function SetLineStyle($aType) { $this->type = $aType; } // Decide if both major and minor grid should be displayed function Show($aShowMajor=true,$aShowMinor=false) { $this->show=$aShowMajor; $this->showMinor=$aShowMinor; } // Display the grid function Stroke() { if( $this->showMinor ) $this->DoStroke($this->scale->ticks->ticks_pos); else $this->DoStroke($this->scale->ticks->maj_ticks_pos); } //-------------- // Private methods // Draw the grid function DoStroke(&$aTicksPos) { if( !$this->show ) return; $this->img->SetColor($this->grid_color); $this->img->SetLineWeight($this->weight); $nbrgrids = count($aTicksPos); if( $this->scale->type=="y" ) { $xl=$this->img->left_margin; $xr=$this->img->width-$this->img->right_margin; for($i=0; $i<$nbrgrids; ++$i) { $y=$aTicksPos[$i]; if( $this->type == "solid" ) $this->img->Line($xl,$y,$xr,$y); elseif( $this->type == "dotted" ) $this->img->DashedLine($xl,$y,$xr,$y,1,6); elseif( $this->type == "dashed" ) $this->img->DashedLine($xl,$y,$xr,$y,2,4); elseif( $this->type == "longdashed" ) $this->img->DashedLine($xl,$y,$xr,$y,8,6); } } if( $this->scale->type=="x" ) { $yu=$this->img->top_margin; $yl=$this->img->height-$this->img->bottom_margin; $x=$aTicksPos[0]; $limit=$this->img->width-$this->img->right_margin; $i=0; // We must also test for limit since we might have // an offset and the number of ticks is calculated with // assumption offset==0 so we might end up drawing one // to many gridlines while( $x<=$limit && $itype == "solid" ) $this->img->Line($x,$yl,$x,$yu); elseif( $this->type == "dotted" ) $this->img->DashedLine($x,$yl,$x,$yu,1,6); elseif( $this->type == "dashed" ) $this->img->DashedLine($x,$yl,$x,$yu,2,4); elseif( $this->type == "longdashed" ) $this->img->DashedLine($x,$yl,$x,$yu,8,6); ++$i; } } return true; } } // Class //=================================================== // CLASS Axis // Description: Defines X and Y axis. Notes that at the // moment the code is not really good since the axis on // several occasion must know wheter it's an X or Y axis. // This was a design decision to make the code easier to // follow. //=================================================== class Axis { var $pos = false; var $weight=1; var $color=array(0,0,0),$label_color=array(0,0,0); var $img=null,$scale=null; var $hide=false; var $ticks_label=false; var $show_first_label=true; var $label_step=1; // Used by a text axis to specify what multiple of major steps // should be labeled. var $tick_step=1; var $labelPos=0; // Which side of the axis should the labels be? var $title=null,$title_adjust,$title_margin,$title_side=SIDE_LEFT; var $font_family=FF_FONT1,$font_style=FS_NORMAL,$font_size=12,$label_angle=0; var $tick_label_margin=6; //--------------- // CONSTRUCTOR function Axis(&$img,&$aScale,$color=array(0,0,0)) { $this->img = &$img; $this->scale = &$aScale; $this->color = $color; $this->title=new Text(""); if( $aScale->type=="y" ) { $this->title_margin = 25; $this->title_adjust="middle"; $this->title->SetOrientation(90); $this->tick_label_margin=6; } else { $this->title_margin = 5; $this->title_adjust="high"; $this->title->SetOrientation(0); $this->tick_label_margin=3; } } //--------------- // PUBLIC METHODS // Utility function to set the direction for tick marks function SetTickDirection($aDir) { $this->scale->ticks->SetDirection($aDir); } function SetLabelFormatString($aFormStr) { $this->scale->ticks->SetLabelFormat($aFormStr); } function SetLabelFormatCallback($aFuncName) { $this->scale->ticks->SetFormatCallback($aFuncName); } // Don't display the first label function HideFirstTickLabel($aHide=false) { $this->show_first_label=$aHide; } // Hide the axis function Hide($aHide=true) { $this->hide=$aHide; } // Weight of axis function SetWeight($aWeight) { $this->weight = $aWeight; } // Axis color function SetColor($aColor,$aLabelColor=false) { $this->color = $aColor; if( !$aLabelColor ) $this->label_color = $aColor; else $this->label_color = $aLabelColor; } // Title on axis function SetTitle($aTitle,$aAdjustAlign="high") { $this->title->Set($aTitle); $this->title_adjust=$aAdjustAlign; } // Specify distance from the axis function SetTitleMargin($aMargin) { $this->title_margin=$aMargin; } // Specify text labels for the ticks. One label for each data point function SetTickLabels($aLabelArray) { $this->ticks_label = $aLabelArray; } // How far from the axis should the labels be drawn function SetTickLabelMargin($aMargin) { $this->tick_label_margin=$aMargin; } // Specify that every $step of the ticks should be displayed starting // at $start // DEPRECATED FUNCTION: USE SetTextTickInterval() INSTEAD function SetTextTicks($step,$start=0) { JpGraphError::Raise("JpGraph Error: SetTextTicks() is deprecated. Use SetTextTickInterval() instead."); } // Specify that every $step of the ticks should be displayed starting // at $start function SetTextTickInterval($aStep,$aStart=0) { $this->scale->ticks->SetTextLabelStart($aStart); $this->tick_step=$aStep; } // Specify that every $step tick mark should have a label // should be displayed starting function SetTextLabelInterval($aStep) { if( $aStep < 1 ) JpGraphError::Raise("JpGraph Error: Text label interval must be specified >= 1."); $this->label_step=$aStep; } // Which side of the axis should the labels be on? function SetLabelPos($aSidePos) { $this->labelPos=$aSidePos; } // Set the font function SetFont($aFamily,$aStyle=FS_NORMAL,$aSize=10) { $this->font_family = $aFamily; $this->font_style = $aStyle; $this->font_size = $aSize; } // Which side of the axis should the axis title be? function SetTitleSide($aSideOfAxis) { $this->title_side = $aSideOfAxis; } // Stroke the axis. function Stroke($aOtherAxisScale) { if( $this->hide ) return; if( is_numeric($this->pos) ) { $pos=$aOtherAxisScale->Translate($this->pos); } else { // Default to minimum of other scale if pos not set if( $aOtherAxisScale->GetMinVal() >= 0 || $this->pos=="min" ) { $pos = $aOtherAxisScale->scale_abs[0]; } else { // If negative set x-axis at 0 $this->pos=0; $pos=$aOtherAxisScale->Translate(0); } } $this->img->SetLineWeight($this->weight); $this->img->SetColor($this->color); $this->img->SetFont($this->font_family,$this->font_style,$this->font_size); if( $this->scale->type == "x" ) { $this->img->FilledRectangle($this->img->left_margin,$pos, $this->img->width-$this->img->right_margin,$pos+$this->weight-1); $y=$pos+$this->img->GetFontHeight()+$this->title_margin; if( $this->title_adjust=="high" ) $this->title->Pos($this->img->width-$this->img->right_margin,$y,"right","top"); elseif($this->title_adjust=="middle") $this->title->Pos(($this->img->width-$this->img->left_margin-$this->img->right_margin)/2+$this->img->left_margin,$y,"center","top"); elseif($this->title_adjust=="low") $this->title->Pos($this->img->left_margin,$y,"left","top"); } elseif( $this->scale->type == "y" ) { // Add line weight to the height of the axis since // the x-axis could have a width>1 and we want the axis to fit nicely together. $this->img->FilledRectangle($pos-$this->weight+1,$this->img->top_margin, $pos,$this->img->height-$this->img->bottom_margin+$this->weight-1); $x=$pos ; if( $this->title_side == SIDE_LEFT ) { $x -= $this->title_margin; $halign="right"; } else { $x += $this->title_margin; $halign="left"; } if( $this->title_adjust=="high" ) $this->title->Pos($x,$this->img->top_margin,$halign,"top"); elseif($this->title_adjust=="middle" || $this->title_adjust=="center") $this->title->Pos($x,($this->img->height-$this->img->top_margin-$this->img->bottom_margin)/2+$this->img->top_margin,$halign,"center"); elseif($this->title_adjust=="low") $this->title->Pos($x,$this->img->height-$this->img->bottom_margin,$halign,"bottom"); } $this->scale->ticks->Stroke($this->img,$this->scale,$pos); $this->StrokeLabels($pos); $this->title->Stroke($this->img); } // Position for axis line on the "other" scale function SetPos($aPosOnOtherScale) { $this->pos=$aPosOnOtherScale; } // Specify the angle for the tick labels function SetLabelAngle($aAngle) { $this->label_angle = $aAngle; } //--------------- // PRIVATE METHODS // Draw all the tick labels on major tick marks function StrokeLabels($aPos,$aMinor=false) { $this->img->SetColor($this->label_color); $this->img->SetFont($this->font_family,$this->font_style,$this->font_size); $yoff=$this->img->GetFontHeight()/2; // Only draw labels at major tick marks $nbr = count($this->scale->ticks->maj_ticks_label); // We have the option to not-display the very first mark // (Usefull when the first label might interfere with another // axis.) if( $this->show_first_label ) $start=0; else $start=1; // Note. the $limit is only used for the x axis since we // might otherwise overshoot if the scale has been centered // This is due to us "loosing" the last tick mark if we center. //if( $this->scale->type=="x" ) // $limit=$this->img->width-$this->img->right_margin; //else // $limit=$this->img->height; // $i holds the current index for the label $i=$start; // Now run through all labels making sure we don't overshoot the end // of the scale. while( $i<$nbr ) { // $tpos holds the absolute text position for the label $tpos=$this->scale->ticks->maj_ticklabels_pos[$i]; // we only draw every $label_step label if( ($i % $this->label_step)==0 ) { // If the label has been specified use that and in other case // just label the mark with the actual scale value $m=$this->scale->ticks->GetMajor(); // ticks_label has an entry for each data point if( isset($this->ticks_label[$i*$m]) ) $label=$this->ticks_label[$i*$m]; else $label=$this->scale->ticks->maj_ticks_label[$i]; if( $this->scale->type == "x" ) { if( $this->label_angle==0 || $this->label_angle==90 ) $this->img->SetTextAlign("center","top"); else $this->img->SetTextAlign("topanchor","top"); $this->img->StrokeText($tpos,$aPos+$this->tick_label_margin,$label,$this->label_angle); } else { // scale->type == "y" if( $this->label_angle!=0 ) JpGraphError::Raise("JpGraph Error: Labels at an angle are not supported on Y-axis"); if( $this->labelPos == 0 ) { // To the left of y-axis $this->img->SetTextAlign("right","center"); $this->img->StrokeText($aPos-$this->tick_label_margin,$tpos,$label); } else { // To the right of the y-axis $this->img->SetTextAlign("left","center"); $this->img->StrokeText($aPos+$this->tick_label_margin,$tpos,$label); } } } ++$i; } } } // Class //=================================================== // CLASS Ticks // Description: Abstract base class for drawing linear and logarithmic // tick marks on axis //=================================================== class Ticks { var $minor_abs_size=3, $major_abs_size=5; var $direction=1; // Should ticks be in(=1) the plot area or outside (=-1)? var $scale; var $is_set=false; var $precision=-1; var $supress_zerolabel=false,$supress_first=false; var $supress_last=false,$supress_tickmarks=false,$supress_minor_tickmarks=false; var $mincolor="",$majcolor=""; var $weight=1; var $label_formatstr=""; // C-style format string to use for labels var $label_formfunc=""; //--------------- // CONSTRUCTOR function Ticks(&$aScale) { $this->scale=&$aScale; } //--------------- // PUBLIC METHODS // Set format string for automatic labels function SetLabelFormat($aFormatString) { $this->label_formatstr=$aFormatString; } function SetFormatCallback($aCallbackFuncName) { $this->label_formfunc = $aCallbackFuncName; } // Don't display the first zero label function SupressZeroLabel($aFlag=true) { $this->supress_zerolabel=$aFlag; } // Don't display minor tick marks function SupressMinorTickMarks($aHide=true) { $this->supress_minor_tickmarks=$aHide; } // Don't display major tick marks function SupressTickMarks($aHide=true) { $this->supress_tickmarks=$aHide; } // Hide the first tick mark function SupressFirst($aHide=true) { $this->supress_first=$aHide; } // Hide the last tick mark function SupressLast($aHide=true) { $this->supress_last=$aHide; } // Size (in pixels) of minor tick marks function GetMinTickAbsSize() { return $this->minor_abs_size; } // Size (in pixels) of major tick marks function GetMajTickAbsSize() { return $this->major_abs_size; } // Have the ticks been specified function IsSpecified() { return $this->is_set; } // Set the distance between major and minor tick marks function Set($aMaj,$aMin) { // "Virtual method" // Should be implemented by the concrete subclass // if any action is wanted. } // Specify number of decimals in automtic labels // Deprecated from 1.4. Use SetFormatString() instead function SetPrecision($aPrecision) { $this->precision=$aPrecision; } // Which side of the axis should the ticks be on function SetDirection($aSide=SIDE_RIGHT) { $this->direction=$aSide; } // Set colors for major and minor tick marks function SetMarkColor($aMajorColor,$aMinorColor="") { $this->majcolor=$aMajorColor; // If not specified use same as major if( $aMinorColor=="" ) $this->mincolor=$aMajorColor; else $this->mincolor=$aMinorColor; } function SetWeight($aWeight) { $this->weight=$aWeight; } } // Class //=================================================== // CLASS LinearTicks // Description: Draw linear ticks on axis //=================================================== class LinearTicks extends Ticks { var $minor_step=1, $major_step=2; var $xlabel_offset=0,$xtick_offset=0; var $label_offset=0; // What offset should the displayed label have // i.e should we display 0,1,2 or 1,2,3,4 or 2,3,4 etc var $text_label_start=0; //--------------- // CONSTRUCTOR function LinearTicks() { // Empty } //--------------- // PUBLIC METHODS // Return major step size in world coordinates function GetMajor() { return $this->major_step; } // Return minor step size in world coordinates function GetMinor() { return $this->minor_step; } // Set Minor and Major ticks (in world coordinates) function Set($aMajStep,$aMinStep) { if( $aMajStep <= 0 || $aMinStep <= 0 ) { JpGraphError::Raise("JpGraph Error: Minor or major step size is 0. Check that you haven't got an accidental SetTextTicks(0) in your code.

If this is not the case you might have stumbled upon a bug in JpGraph. Please report this and if possible include the data that caused the problem."); } $this->major_step=$aMajStep; $this->minor_step=$aMinStep; $this->is_set = true; } // Draw linear ticks function Stroke(&$img,&$scale,$pos) { $maj_step_abs = $scale->scale_factor*$this->major_step; $min_step_abs = $scale->scale_factor*$this->minor_step; if( $min_step_abs==0 || $maj_step_abs==0 ) JpGraphError::Raise("JpGraph Error: A plot has an illegal scale. This could for example be that you are trying to use text autoscaling to draw a line plot with only one point or similair abnormality (a line needs two points!)."); $limit = $scale->scale_abs[1]; $nbrmajticks=floor(1.000001*(($scale->GetMaxVal()-$scale->GetMinVal())/$this->major_step))+1; $first=0; // If precision hasn't been specified set it to a sensible value if( $this->precision==-1 ) { $t = log10($this->minor_step); if( $t > 0 ) $precision = 0; else $precision = -floor($t); } else $precision = $this->precision; $img->SetLineWeight($this->weight); // Handle ticks on X-axis if( $scale->type == "x" ) { // Draw the major tick marks $yu = $pos - $this->direction*$this->GetMajTickAbsSize(); // TODO: Add logic to set label_offset for text labels $label = (float)$scale->GetMinVal()+$this->text_label_start+$this->label_offset; $start_abs=$scale->scale_factor*$this->text_label_start; $nbrmajticks=ceil(($scale->GetMaxVal()-$scale->GetMinVal()-$this->text_label_start )/$this->major_step)+1; for( $i=0; $label<=$scale->GetMaxVal()+$this->label_offset; ++$i ) { $x=$scale->scale_abs[0]+$start_abs+$i*$maj_step_abs+$this->xlabel_offset*$min_step_abs; $this->maj_ticklabels_pos[$i]=ceil($x); // Apply format if( $this->label_formfunc != "" ) { $f=$this->label_formfunc; $l = $f($label); } elseif( $this->label_formatstr != "" ) $l = sprintf($this->label_formatstr,$label); else $l = sprintf("%01.".$precision."f",round($label,$precision)); if( ($this->supress_zerolabel && ($l + 0)==0) || ($this->supress_first && $i==0) || ($this->supress_last && $i==$nbrmajticks-1) ) $l=""; $this->maj_ticks_label[$i]=$l; $label+=$this->major_step; // The x-position of the tick marks can be different from the labels. // Note that we record the tick position (not the label) so that the grid // happen upon tick marks and not labels. $xtick=$scale->scale_abs[0]+$start_abs+$i*$maj_step_abs+$this->xtick_offset*$min_step_abs; $this->maj_ticks_pos[$i]=ceil($xtick); if(!($this->xtick_offset > 0 && $i==$nbrmajticks-1) && !$this->supress_tickmarks) { if( $this->majcolor!="" ) $img->PushColor($this->majcolor); $img->Line($xtick,$pos,$xtick,$yu); if( $this->majcolor!="" ) $img->PopColor(); } } // Draw the minor tick marks $yu = $pos - $this->direction*$this->GetMinTickAbsSize(); $label = $scale->GetMinVal(); for( $i=0,$x=$scale->scale_abs[0]; $x<$limit; ++$i ) { $x=$scale->scale_abs[0]+$i*$min_step_abs; $this->ticks_pos[]=$x; $this->ticks_label[]=$label; $label+=$this->minor_step; if( !$this->supress_tickmarks && !$this->supress_minor_tickmarks) { if( $this->mincolor!="" ) $img->PushColor($this->mincolor); $img->Line($x,$pos,$x,$yu); if( $this->mincolor!="" ) $img->PopColor(); } } } elseif( $scale->type == "y" ) { // Draw the major tick marks $xr = $pos + $this->direction*$this->GetMajTickAbsSize(); $label = $scale->GetMinVal(); for( $i=0; $i<$nbrmajticks; ++$i) { $y=$scale->scale_abs[0]+$i*$maj_step_abs; // THe following two lines might seem to be unecessary but they are not! // The reason being that for X-axis we separate the position of the labels // and the tick marks which we don't do for the Y-axis. // We therefore need to make sure both arrays are corcectly filled // since Axis::StrokeLabels() uses the label positions and Grid::Stroke() uses // the tick positions. $this->maj_ticklabels_pos[$i]=$y; $this->maj_ticks_pos[$i]=$y; if( $this->label_formfunc != "" ) { $f=$this->label_formfunc; $l = $f($label); } elseif( $this->label_formatstr != "" ) $l = sprintf($this->label_formatstr,$label); else $l = sprintf("%01.".$precision."f",round($label,$precision)); if( ($this->supress_zerolabel && ($l + 0)==0) || ($this->supress_first && $i==0) || ($this->supress_last && $i==$nbrmajticks-1) ) $l=""; $this->maj_ticks_label[$i]=$l; $label+=$this->major_step; if( !$this->supress_tickmarks ) { if( $this->majcolor!="" ) $img->PushColor($this->majcolor); $img->Line($pos,$y,$xr,$y); if( $this->majcolor!="" ) $img->PopColor(); } } // Draw the minor tick marks $xr = $pos + $this->direction*$this->GetMinTickAbsSize(); $label = $scale->GetMinVal(); for( $i=0,$y=$scale->scale_abs[0]; $y>=$limit; ) { $this->ticks_pos[$i]=$y; $this->ticks_label[$i]=$label; $label+=$this->minor_step; if( !$this->supress_tickmarks && !$this->supress_minor_tickmarks) { if( $this->mincolor!="" ) $img->PushColor($this->mincolor); $img->Line($pos,$y,$xr,$y); if( $this->mincolor!="" ) $img->PopColor(); } ++$i; $y=$scale->scale_abs[0]+$i*$min_step_abs; } } } //--------------- // PRIVATE METHODS // Spoecify the offset of the displayed tick mark with the tick "space" // Legal values for $o is [0,1] used to adjust where the tick marks and label // should be positioned within the major tick-size // $lo specifies the label offset and $to specifies the tick offset // this comes in handy for example in bar graphs where we wont no offset for the // tick but have the labels displayed halfway under the bars. function SetXLabelOffset($aLabelOff,$aTickOff=-1) { $this->xlabel_offset=$aLabelOff; if( $aTickOff==-1 ) // Same as label offset $this->xtick_offset=$aLabelOff; else $this->xtick_offset=$aTickOff; if( $aLabelOff>0 ) $this->SupressLast(); // The last tick wont fit } // Which tick label should we start with? function SetTextLabelStart($aTextLabelOff) { $this->text_label_start=$aTextLabelOff; } } // Class //=================================================== // CLASS LinearScale // Description: Handle linear scaling between screen and world //=================================================== class LinearScale { var $scale=array(0,0); var $scale_abs=array(0,0); var $scale_factor; // Scale factor between world and screen var $world_size; // Plot area size in world coordinates var $world_abs_size; // Plot area size in pixels var $off; // Offset between image edge and plot area var $type; // is this x or y scale ? var $ticks=null; // Store ticks var $autoscale_min=false; // Forced minimum value, useful to let user force 0 as start and autoscale max var $gracetop=0,$gracebottom=0; var $intscale=false; // Restrict autoscale to integers //--------------- // CONSTRUCTOR function LinearScale($aMin=0,$aMax=0,$aType="y") { assert($aType=="x" || $aType=="y" ); assert($aMin<=$aMax); $this->type=$aType; $this->scale=array($aMin,$aMax); $this->world_size=$aMax-$aMin; $this->ticks = new LinearTicks(); } //--------------- // PUBLIC METHODS // Second phase constructor function Init(&$aImg) { $this->InitConstants($aImg); // We want image to notify us when the margins changes so we // can recalculate the constants. // PHP <= 4.04 BUGWARNING: IT IS IMPOSSIBLE TO DO THIS IN THE CONSTRUCTOR // SINCE (FOR SOME REASON) IT IS IMPOSSIBLE TO PASS A REFERENCE // TO 'this' INSTEAD IT WILL ADD AN ANONYMOUS COPY OF THIS OBJECT WHICH WILL // GET ALL THE NOTIFICATIONS. (This took a while to track down...) // Add us as an observer to class Image $aImg->AddObserver("InitConstants",$this); } // Check if scale is set or if we should autoscale // We should do this is either scale or ticks has not been set function IsSpecified() { if( $this->GetMinVal()==$this->GetMaxVal() ) { // Scale not set return false; } return true; } // Set the minimum data value when the autoscaling is used. // Usefull if you want a fix minimum (like 0) but automtic maximum function SetAutoMin($aMin) { $this->autoscale_min=$aMin; } // Specify scale "grace" value (top and bottom) function SetGrace($aGraceTop,$aGraceBottom=0) { if( $aGraceTop<0 || $aGraceBottom < 0 ) JpGraphError::Raise("JpGraph Error: Grace must be larger then 0"); $this->gracetop=$aGraceTop; $this->gracebottom=$aGraceBottom; } // Get the minimum value in the scale function GetMinVal() { return $this->scale[0]; } // get maximum value for scale function GetMaxVal() { return $this->scale[1]; } // Specify a new min/max value for sclae function Update(&$aImg,$aMin,$aMax) { $this->scale=array($aMin,$aMax); $this->world_size=$aMax-$aMin; $this->InitConstants($aImg); } // Translate between world and screen function Translate($aCoord) { return $this->off+round(($aCoord*1.0 - $this->GetMinVal()) * $this->scale_factor,0); } // Relative translate (don't include offset) usefull when we just want // to know the relative position (in pixels) on the axis function RelTranslate($aCoord) { return round(($aCoord*1.0 - $this->GetMinVal()) * $this->scale_factor,0); } // Restrict autoscaling to only use integers function SetIntScale($aIntScale=true) { $this->intscale=$aIntScale; } // Calculate an integer autoscale function IntAutoScale(&$img,$min,$max,$maxsteps,$majend=true) { // Make sure limits are integers $min=floor($min); $max=ceil($max); if( abs($min-$max)==0 ) { --$min; ++$max; } $gracetop=ceil(($this->gracetop/100.0))*abs($max-$min); $gracebottom=ceil(($this->gracebottom/100.0))*abs($max-$min); if( is_numeric($this->autoscale_min) ) { $min = ceil($this->autoscale_min); if( abs($min-$max ) == 0 ) { ++$max; --$min; } } $min -= $gracebottom; $max += $gracetop; // First get tickmarks as multiples of 1, 10, ... list($num1steps,$adj1min,$adj1max,$maj1step) = $this->IntCalcTicks($maxsteps,$min,$max,1); // Then get tick marks as 2:s 2, 20, ... list($num2steps,$adj2min,$adj2max,$maj2step) = $this->IntCalcTicks($maxsteps,$min,$max,5); // Then get tickmarks as 5:s 5, 50, 500, ... list($num5steps,$adj5min,$adj5max,$maj5step) = $this->IntCalcTicks($maxsteps,$min,$max,2); // Check to see whichof 1:s, 2:s or 5:s fit better with // the requested number of major ticks $match1=abs($num1steps-$maxsteps); $match2=abs($num2steps-$maxsteps); if( $maj5step > 1 ) $match5=abs($num5steps-$maxsteps); else $match5=1000000; // Dummy high value // Compare these three values and see which is the closest match // We use a 0.6 weight to gravitate towards multiple of 5:s if( $match1 < $match2 ) { if( $match1 < $match5 ) $r=1; else $r=3; } else { if( $match2 < $match5 ) $r=2; else $r=3; } // Minsteps are always the same as maxsteps for integer scale switch( $r ) { case 1: $this->Update($img,$adj1min,$adj1max); $this->ticks->Set($maj1step,$maj1step); break; case 2: $this->Update($img,$adj2min,$adj2max); $this->ticks->Set($maj2step,$maj2step); break; case 3: $this->Update($img,$adj5min,$adj5max); $this->ticks->Set($maj5step,$maj2step); break; } } // Calculate autoscale. Used if user hasn't given a scale and ticks // $maxsteps is the maximum number of major tickmarks allowed. function AutoScale(&$img,$min,$max,$maxsteps,$majend=true) { if( $this->intscale ) { $this->IntAutoScale($img,$min,$max,$maxsteps,$majend); return; } if( abs($min-$max) < 0.00001 ) { // We need some difference to be able to autoscale // make it 5% above and 5% below value if( $min==0 && $max==0 ) { // Special case $min=-1; $max=1; } else { $delta = abs($max-$min)*0.05; $min -= $delta; $max += $delta; } } $gracetop=($this->gracetop/100.0)*abs($max-$min); $gracebottom=($this->gracebottom/100.0)*abs($max-$min); if( is_numeric($this->autoscale_min) ) { $min = $this->autoscale_min; if( abs($min-$max ) < 0.00001 ) $max *= 1.05; } $min -= $gracebottom; $max += $gracetop; // First get tickmarks as multiples of 0.1, 1, 10, ... list($num1steps,$adj1min,$adj1max,$min1step,$maj1step) = $this->CalcTicks($maxsteps,$min,$max,1,2); // Then get tick marks as 2:s 0.2, 2, 20, ... list($num2steps,$adj2min,$adj2max,$min2step,$maj2step) = $this->CalcTicks($maxsteps,$min,$max,5,2); // Then get tickmarks as 5:s 0.05, 0.5, 5, 50, ... list($num5steps,$adj5min,$adj5max,$min5step,$maj5step) = $this->CalcTicks($maxsteps,$min,$max,2,5); // Check to see whichof 1:s, 2:s or 5:s fit better with // the requested number of major ticks $match1=abs($num1steps-$maxsteps); $match2=abs($num2steps-$maxsteps); $match5=abs($num5steps-$maxsteps); // Compare these three values and see which is the closest match // We use a 0.8 weight to gravitate towards multiple of 5:s $r=$this->MatchMin3($match1,$match2,$match5,0.8); switch( $r ) { case 1: $this->Update($img,$adj1min,$adj1max); $this->ticks->Set($maj1step,$min1step); break; case 2: $this->Update($img,$adj2min,$adj2max); $this->ticks->Set($maj2step,$min2step); break; case 3: $this->Update($img,$adj5min,$adj5max); $this->ticks->Set($maj5step,$min5step); break; } } //--------------- // PRIVATE METHODS // This method recalculates all constants that are depending on the // margins in the image. If the margins in the image are changed // this method should be called for every scale that is registred with // that image. Should really be installed as an observer of that image. function InitConstants(&$img) { if( $this->type=="x" ) { $this->world_abs_size=$img->width - $img->left_margin - $img->right_margin; $this->off=$img->left_margin; $this->scale_factor = 0; if( $this->world_size > 0 ) $this->scale_factor=$this->world_abs_size/($this->world_size*1.0); } else { // y scale $this->world_abs_size=$img->height - $img->top_margin - $img->bottom_margin; $this->off=$img->top_margin+$this->world_abs_size; $this->scale_factor = 0; if( $this->world_size > 0 ) $this->scale_factor=-$this->world_abs_size/($this->world_size*1.0); } $size = $this->world_size * $this->scale_factor; $this->scale_abs=array($this->off,$this->off + $size); } // Initialize the conversion constants for this scale // This tries to pre-calculate as much as possible to speed up the // actual conversion (with Translate()) later on // $start =scale start in absolute pixels (for x-scale this is an y-position // and for an y-scale this is an x-position // $len =absolute length in pixels of scale function SetConstants($aStart,$aLen) { $this->world_abs_size=$aLen; $this->off=$aStart; if( $this->world_size<=0 ) { JpGraphError::Raise("JpGraph Fatal Error:
You have unfortunately stumbled upon a bug in JpGraph.
It seems like the scale range is ".$this->world_size." [for ". $this->type." scale]
Please report Bug #01 to jpgraph@aditus.nu and include the script that gave this error.
This problem could potentially be caused by trying to use \"illegal\" values in the input data arrays (like trying to send in strings or only NULL values) which causes the autoscaling to fail."); } // scale_factor = number of pixels per world unit $this->scale_factor=$this->world_abs_size/($this->world_size*1.0); // scale_abs = start and end points of scale in absolute pixels $this->scale_abs=array($this->off,$this->off+$this->world_size*$this->scale_factor); } // Calculate number of ticks steps with a specific division // $a is the divisor of 10**x to generate the first maj tick intervall // $a=1, $b=2 give major ticks with multiple of 10, ...,0.1,1,10,... // $a=5, $b=2 give major ticks with multiple of 2:s ...,0.2,2,20,... // $a=2, $b=5 give major ticks with multiple of 5:s ...,0.5,5,50,... // We return a vector of // [$numsteps,$adjmin,$adjmax,$minstep,$majstep] // If $majend==true then the first and last marks on the axis will be major // labeled tick marks otherwise it will be adjusted to the closest min tick mark function CalcTicks($maxsteps,$min,$max,$a,$b,$majend=true) { $diff=$max-$min; if( $diff==0 ) $ld=0; else $ld=floor(log10($diff)); // Gravitate min towards zero if we are close if( $min>0 && $min < pow(10,$ld) ) $min=0; $majstep=pow(10,$ld-1)/$a; $minstep=$majstep/$b; $adjmax=ceil($max/$minstep)*$minstep; $adjmin=floor($min/$minstep)*$minstep; $adjdiff = $adjmax-$adjmin; $numsteps=$adjdiff/$majstep; while( $numsteps>$maxsteps ) { $majstep=pow(10,$ld)/$a; $numsteps=$adjdiff/$majstep; ++$ld; } $minstep=$majstep/$b; $adjmin=floor($min/$minstep)*$minstep; $adjdiff = $adjmax-$adjmin; if( $majend ) { $adjmin = floor($min/$majstep)*$majstep; $adjdiff = $adjmax-$adjmin; $adjmax = ceil($adjdiff/$majstep)*$majstep+$adjmin; } else $adjmax=ceil($max/$minstep)*$minstep; return array($numsteps,$adjmin,$adjmax,$minstep,$majstep); } function IntCalcTicks($maxsteps,$min,$max,$a,$majend=true) { $diff=$max-$min; if( $diff==0 ) $ld=0; else $ld=floor(log10($diff)); // Gravitate min towards zero if we are close if( $min>0 && $min < pow(10,$ld) ) $min=0; $majstep=pow(10,$ld-1)/$a; $adjmax=ceil($max/$majstep)*$majstep; $adjmin=floor($min/$majstep)*$majstep; $adjdiff = $adjmax-$adjmin; $numsteps=$adjdiff/$majstep; while( $numsteps>$maxsteps ) { $majstep=pow(10,$ld)/$a; $numsteps=$adjdiff/$majstep; ++$ld; } $adjmin=floor($min/$majstep)*$majstep; $adjdiff = $adjmax-$adjmin; if( $majend ) { $adjmin = floor($min/$majstep)*$majstep; $adjdiff = $adjmax-$adjmin; $adjmax = ceil($adjdiff/$majstep)*$majstep+$adjmin; } else $adjmax=ceil($max/$majstep)*$majstep; return array($numsteps,$adjmin,$adjmax,$majstep); } // Determine the minimum of three values witha weight for last value function MatchMin3($a,$b,$c,$weight) { if( $a < $b ) { if( $a < ($c*$weight) ) return 1; // $a smallest else return 3; // $c smallest } elseif( $b < ($c*$weight) ) return 2; // $b smallest return 3; // $c smallest } } // Class //=================================================== // CLASS RGB // Description: Color definitions as RGB triples //=================================================== class RGB { var $rgb_table; var $img; function RGB(&$aImg) { $this->img = $aImg; // Conversion array between color names and RGB $this->rgb_table = array( "aqua"=> array(0,255,255), "lime"=> array(0,255,0), "teal"=> array(0,128,128), "whitesmoke"=>array(245,245,245), "gainsboro"=>array(220,220,220), "oldlace"=>array(253,245,230), "linen"=>array(250,240,230), "antiquewhite"=>array(250,235,215), "papayawhip"=>array(255,239,213), "blanchedalmond"=>array(255,235,205), "bisque"=>array(255,228,196), "peachpuff"=>array(255,218,185), "navajowhite"=>array(255,222,173), "moccasin"=>array(255,228,181), "cornsilk"=>array(255,248,220), "ivory"=>array(255,255,240), "lemonchiffon"=>array(255,250,205), "seashell"=>array(255,245,238), "mintcream"=>array(245,255,250), "azure"=>array(240,255,255), "aliceblue"=>array(240,248,255), "lavender"=>array(230,230,250), "lavenderblush"=>array(255,240,245), "mistyrose"=>array(255,228,225), "white"=>array(255,255,255), "black"=>array(0,0,0), "darkslategray"=>array(47,79,79), "dimgray"=>array(105,105,105), "slategray"=>array(112,128,144), "lightslategray"=>array(119,136,153), "gray"=>array(190,190,190), "lightgray"=>array(211,211,211), "midnightblue"=>array(25,25,112), "navy"=>array(0,0,128), "cornflowerblue"=>array(100,149,237), "darkslateblue"=>array(72,61,139), "slateblue"=>array(106,90,205), "mediumslateblue"=>array(123,104,238), "lightslateblue"=>array(132,112,255), "mediumblue"=>array(0,0,205), "royalblue"=>array(65,105,225), "blue"=>array(0,0,255), "dodgerblue"=>array(30,144,255), "deepskyblue"=>array(0,191,255), "skyblue"=>array(135,206,235), "lightskyblue"=>array(135,206,250), "steelblue"=>array(70,130,180), "lightred"=>array(211,167,168), "lightsteelblue"=>array(176,196,222), "lightblue"=>array(173,216,230), "powderblue"=>array(176,224,230), "paleturquoise"=>array(175,238,238), "darkturquoise"=>array(0,206,209), "mediumturquoise"=>array(72,209,204), "turquoise"=>array(64,224,208), "cyan"=>array(0,255,255), "lightcyan"=>array(224,255,255), "cadetblue"=>array(95,158,160), "mediumaquamarine"=>array(102,205,170), "aquamarine"=>array(127,255,212), "darkgreen"=>array(0,100,0), "darkolivegreen"=>array(85,107,47), "darkseagreen"=>array(143,188,143), "seagreen"=>array(46,139,87), "mediumseagreen"=>array(60,179,113), "lightseagreen"=>array(32,178,170), "palegreen"=>array(152,251,152), "springgreen"=>array(0,255,127), "lawngreen"=>array(124,252,0), "green"=>array(0,255,0), "chartreuse"=>array(127,255,0), "mediumspringgreen"=>array(0,250,154), "greenyellow"=>array(173,255,47), "limegreen"=>array(50,205,50), "yellowgreen"=>array(154,205,50), "forestgreen"=>array(34,139,34), "olivedrab"=>array(107,142,35), "darkkhaki"=>array(189,183,107), "khaki"=>array(240,230,140), "palegoldenrod"=>array(238,232,170), "lightgoldenrodyellow"=>array(250,250,210), "lightyellow"=>array(255,255,200), "yellow"=>array(255,255,0), "gold"=>array(255,215,0), "lightgoldenrod"=>array(238,221,130), "goldenrod"=>array(218,165,32), "darkgoldenrod"=>array(184,134,11), "rosybrown"=>array(188,143,143), "indianred"=>array(205,92,92), "saddlebrown"=>array(139,69,19), "sienna"=>array(160,82,45), "peru"=>array(205,133,63), "burlywood"=>array(222,184,135), "beige"=>array(245,245,220), "wheat"=>array(245,222,179), "sandybrown"=>array(244,164,96), "tan"=>array(210,180,140), "chocolate"=>array(210,105,30), "firebrick"=>array(178,34,34), "brown"=>array(165,42,42), "darksalmon"=>array(233,150,122), "salmon"=>array(250,128,114), "lightsalmon"=>array(255,160,122), "orange"=>array(255,165,0), "darkorange"=>array(255,140,0), "coral"=>array(255,127,80), "lightcoral"=>array(240,128,128), "tomato"=>array(255,99,71), "orangered"=>array(255,69,0), "red"=>array(255,0,0), "hotpink"=>array(255,105,180), "deeppink"=>array(255,20,147), "pink"=>array(255,192,203), "lightpink"=>array(255,182,193), "palevioletred"=>array(219,112,147), "maroon"=>array(176,48,96), "mediumvioletred"=>array(199,21,133), "violetred"=>array(208,32,144), "magenta"=>array(255,0,255), "violet"=>array(238,130,238), "plum"=>array(221,160,221), "orchid"=>array(218,112,214), "mediumorchid"=>array(186,85,211), "darkorchid"=>array(153,50,204), "darkviolet"=>array(148,0,211), "blueviolet"=>array(138,43,226), "purple"=>array(160,32,240), "mediumpurple"=>array(147,112,219), "thistle"=>array(216,191,216), "snow1"=>array(255,250,250), "snow2"=>array(238,233,233), "snow3"=>array(205,201,201), "snow4"=>array(139,137,137), "seashell1"=>array(255,245,238), "seashell2"=>array(238,229,222), "seashell3"=>array(205,197,191), "seashell4"=>array(139,134,130), "AntiqueWhite1"=>array(255,239,219), "AntiqueWhite2"=>array(238,223,204), "AntiqueWhite3"=>array(205,192,176), "AntiqueWhite4"=>array(139,131,120), "bisque1"=>array(255,228,196), "bisque2"=>array(238,213,183), "bisque3"=>array(205,183,158), "bisque4"=>array(139,125,107), "peachPuff1"=>array(255,218,185), "peachpuff2"=>array(238,203,173), "peachpuff3"=>array(205,175,149), "peachpuff4"=>array(139,119,101), "navajowhite1"=>array(255,222,173), "navajowhite2"=>array(238,207,161), "navajowhite3"=>array(205,179,139), "navajowhite4"=>array(139,121,94), "lemonchiffon1"=>array(255,250,205), "lemonchiffon2"=>array(238,233,191), "lemonchiffon3"=>array(205,201,165), "lemonchiffon4"=>array(139,137,112), "ivory1"=>array(255,255,240), "ivory2"=>array(238,238,224), "ivory3"=>array(205,205,193), "ivory4"=>array(139,139,131), "honeydew"=>array(193,205,193), "lavenderblush1"=>array(255,240,245), "lavenderblush2"=>array(238,224,229), "lavenderblush3"=>array(205,193,197), "lavenderblush4"=>array(139,131,134), "mistyrose1"=>array(255,228,225), "mistyrose2"=>array(238,213,210), "mistyrose3"=>array(205,183,181), "mistyrose4"=>array(139,125,123), "azure1"=>array(240,255,255), "azure2"=>array(224,238,238), "azure3"=>array(193,205,205), "azure4"=>array(131,139,139), "slateblue1"=>array(131,111,255), "slateblue2"=>array(122,103,238), "slateblue3"=>array(105,89,205), "slateblue4"=>array(71,60,139), "royalblue1"=>array(72,118,255), "royalblue2"=>array(67,110,238), "royalblue3"=>array(58,95,205), "royalblue4"=>array(39,64,139), "dodgerblue1"=>array(30,144,255), "dodgerblue2"=>array(28,134,238), "dodgerblue3"=>array(24,116,205), "dodgerblue4"=>array(16,78,139), "steelblue1"=>array(99,184,255), "steelblue2"=>array(92,172,238), "steelblue3"=>array(79,148,205), "steelblue4"=>array(54,100,139), "deepskyblue1"=>array(0,191,255), "deepskyblue2"=>array(0,178,238), "deepskyblue3"=>array(0,154,205), "deepskyblue4"=>array(0,104,139), "skyblue1"=>array(135,206,255), "skyblue2"=>array(126,192,238), "skyblue3"=>array(108,166,205), "skyblue4"=>array(74,112,139), "lightskyblue1"=>array(176,226,255), "lightskyblue2"=>array(164,211,238), "lightskyblue3"=>array(141,182,205), "lightskyblue4"=>array(96,123,139), "slategray1"=>array(198,226,255), "slategray2"=>array(185,211,238), "slategray3"=>array(159,182,205), "slategray4"=>array(108,123,139), "lightsteelblue1"=>array(202,225,255), "lightsteelblue2"=>array(188,210,238), "lightsteelblue3"=>array(162,181,205), "lightsteelblue4"=>array(110,123,139), "lightblue1"=>array(191,239,255), "lightblue2"=>array(178,223,238), "lightblue3"=>array(154,192,205), "lightblue4"=>array(104,131,139), "lightcyan1"=>array(224,255,255), "lightcyan2"=>array(209,238,238), "lightcyan3"=>array(180,205,205), "lightcyan4"=>array(122,139,139), "paleturquoise1"=>array(187,255,255), "paleturquoise2"=>array(174,238,238), "paleturquoise3"=>array(150,205,205), "paleturquoise4"=>array(102,139,139), "cadetblue1"=>array(152,245,255), "cadetblue2"=>array(142,229,238), "cadetblue3"=>array(122,197,205), "cadetblue4"=>array(83,134,139), "turquoise1"=>array(0,245,255), "turquoise2"=>array(0,229,238), "turquoise3"=>array(0,197,205), "turquoise4"=>array(0,134,139), "cyan1"=>array(0,255,255), "cyan2"=>array(0,238,238), "cyan3"=>array(0,205,205), "cyan4"=>array(0,139,139), "darkslategray1"=>array(151,255,255), "darkslategray2"=>array(141,238,238), "darkslategray3"=>array(121,205,205), "darkslategray4"=>array(82,139,139), "aquamarine1"=>array(127,255,212), "aquamarine2"=>array(118,238,198), "aquamarine3"=>array(102,205,170), "aquamarine4"=>array(69,139,116), "darkseagreen1"=>array(193,255,193), "darkseagreen2"=>array(180,238,180), "darkseagreen3"=>array(155,205,155), "darkseagreen4"=>array(105,139,105), "seagreen1"=>array(84,255,159), "seagreen2"=>array(78,238,148), "seagreen3"=>array(67,205,128), "seagreen4"=>array(46,139,87), "palegreen1"=>array(154,255,154), "palegreen2"=>array(144,238,144), "palegreen3"=>array(124,205,124), "palegreen4"=>array(84,139,84), "springgreen1"=>array(0,255,127), "springgreen2"=>array(0,238,118), "springgreen3"=>array(0,205,102), "springgreen4"=>array(0,139,69), "chartreuse1"=>array(127,255,0), "chartreuse2"=>array(118,238,0), "chartreuse3"=>array(102,205,0), "chartreuse4"=>array(69,139,0), "olivedrab1"=>array(192,255,62), "olivedrab2"=>array(179,238,58), "olivedrab3"=>array(154,205,50), "olivedrab4"=>array(105,139,34), "darkolivegreen1"=>array(202,255,112), "darkolivegreen2"=>array(188,238,104), "darkolivegreen3"=>array(162,205,90), "darkolivegreen4"=>array(110,139,61), "khaki1"=>array(255,246,143), "khaki2"=>array(238,230,133), "khaki3"=>array(205,198,115), "khaki4"=>array(139,134,78), "lightgoldenrod1"=>array(255,236,139), "lightgoldenrod2"=>array(238,220,130), "lightgoldenrod3"=>array(205,190,112), "lightgoldenrod4"=>array(139,129,76), "yellow1"=>array(255,255,0), "yellow2"=>array(238,238,0), "yellow3"=>array(205,205,0), "yellow4"=>array(139,139,0), "gold1"=>array(255,215,0), "gold2"=>array(238,201,0), "gold3"=>array(205,173,0), "gold4"=>array(139,117,0), "goldenrod1"=>array(255,193,37), "goldenrod2"=>array(238,180,34), "goldenrod3"=>array(205,155,29), "goldenrod4"=>array(139,105,20), "darkgoldenrod1"=>array(255,185,15), "darkgoldenrod2"=>array(238,173,14), "darkgoldenrod3"=>array(205,149,12), "darkgoldenrod4"=>array(139,101,8), "rosybrown1"=>array(255,193,193), "rosybrown2"=>array(238,180,180), "rosybrown3"=>array(205,155,155), "rosybrown4"=>array(139,105,105), "indianred1"=>array(255,106,106), "indianred2"=>array(238,99,99), "indianred3"=>array(205,85,85), "indianred4"=>array(139,58,58), "sienna1"=>array(255,130,71), "sienna2"=>array(238,121,66), "sienna3"=>array(205,104,57), "sienna4"=>array(139,71,38), "burlywood1"=>array(255,211,155), "burlywood2"=>array(238,197,145), "burlywood3"=>array(205,170,125), "burlywood4"=>array(139,115,85), "wheat1"=>array(255,231,186), "wheat2"=>array(238,216,174), "wheat3"=>array(205,186,150), "wheat4"=>array(139,126,102), "tan1"=>array(255,165,79), "tan2"=>array(238,154,73), "tan3"=>array(205,133,63), "tan4"=>array(139,90,43), "chocolate1"=>array(255,127,36), "chocolate2"=>array(238,118,33), "chocolate3"=>array(205,102,29), "chocolate4"=>array(139,69,19), "firebrick1"=>array(255,48,48), "firebrick2"=>array(238,44,44), "firebrick3"=>array(205,38,38), "firebrick4"=>array(139,26,26), "brown1"=>array(255,64,64), "brown2"=>array(238,59,59), "brown3"=>array(205,51,51), "brown4"=>array(139,35,35), "salmon1"=>array(255,140,105), "salmon2"=>array(238,130,98), "salmon3"=>array(205,112,84), "salmon4"=>array(139,76,57), "lightsalmon1"=>array(255,160,122), "lightsalmon2"=>array(238,149,114), "lightsalmon3"=>array(205,129,98), "lightsalmon4"=>array(139,87,66), "orange1"=>array(255,165,0), "orange2"=>array(238,154,0), "orange3"=>array(205,133,0), "orange4"=>array(139,90,0), "darkorange1"=>array(255,127,0), "darkorange2"=>array(238,118,0), "darkorange3"=>array(205,102,0), "darkorange4"=>array(139,69,0), "coral1"=>array(255,114,86), "coral2"=>array(238,106,80), "coral3"=>array(205,91,69), "coral4"=>array(139,62,47), "tomato1"=>array(255,99,71), "tomato2"=>array(238,92,66), "tomato3"=>array(205,79,57), "tomato4"=>array(139,54,38), "orangered1"=>array(255,69,0), "orangered2"=>array(238,64,0), "orangered3"=>array(205,55,0), "orangered4"=>array(139,37,0), "deeppink1"=>array(255,20,147), "deeppink2"=>array(238,18,137), "deeppink3"=>array(205,16,118), "deeppink4"=>array(139,10,80), "hotpink1"=>array(255,110,180), "hotpink2"=>array(238,106,167), "hotpink3"=>array(205,96,144), "hotpink4"=>array(139,58,98), "pink1"=>array(255,181,197), "pink2"=>array(238,169,184), "pink3"=>array(205,145,158), "pink4"=>array(139,99,108), "lightpink1"=>array(255,174,185), "lightpink2"=>array(238,162,173), "lightpink3"=>array(205,140,149), "lightpink4"=>array(139,95,101), "palevioletred1"=>array(255,130,171), "palevioletred2"=>array(238,121,159), "palevioletred3"=>array(205,104,137), "palevioletred4"=>array(139,71,93), "maroon1"=>array(255,52,179), "maroon2"=>array(238,48,167), "maroon3"=>array(205,41,144), "maroon4"=>array(139,28,98), "violetred1"=>array(255,62,150), "violetred2"=>array(238,58,140), "violetred3"=>array(205,50,120), "violetred4"=>array(139,34,82), "magenta1"=>array(255,0,255), "magenta2"=>array(238,0,238), "magenta3"=>array(205,0,205), "magenta4"=>array(139,0,139), "mediumred"=>array(140,34,34), "orchid1"=>array(255,131,250), "orchid2"=>array(238,122,233), "orchid3"=>array(205,105,201), "orchid4"=>array(139,71,137), "plum1"=>array(255,187,255), "plum2"=>array(238,174,238), "plum3"=>array(205,150,205), "plum4"=>array(139,102,139), "mediumorchid1"=>array(224,102,255), "mediumorchid2"=>array(209,95,238), "mediumorchid3"=>array(180,82,205), "mediumorchid4"=>array(122,55,139), "darkorchid1"=>array(191,62,255), "darkorchid2"=>array(178,58,238), "darkorchid3"=>array(154,50,205), "darkorchid4"=>array(104,34,139), "purple1"=>array(155,48,255), "purple2"=>array(145,44,238), "purple3"=>array(125,38,205), "purple4"=>array(85,26,139), "mediumpurple1"=>array(171,130,255), "mediumpurple2"=>array(159,121,238), "mediumpurple3"=>array(137,104,205), "mediumpurple4"=>array(93,71,139), "thistle1"=>array(255,225,255), "thistle2"=>array(238,210,238), "thistle3"=>array(205,181,205), "thistle4"=>array(139,123,139), "gray1"=>array(10,10,10), "gray2"=>array(40,40,30), "gray3"=>array(70,70,70), "gray4"=>array(100,100,100), "gray5"=>array(130,130,130), "gray6"=>array(160,160,160), "gray7"=>array(190,190,190), "gray8"=>array(210,210,210), "gray9"=>array(240,240,240), "darkgray"=>array(100,100,100), "darkblue"=>array(0,0,139), "darkcyan"=>array(0,139,139), "darkmagenta"=>array(139,0,139), "darkred"=>array(139,0,0), "silver"=>array(192, 192, 192), "eggplant"=>array(144,176,168), "lightgreen"=>array(144,238,144)); } //---------------- // PUBLIC METHODS // Colors can be specified as either // 1. #xxxxxx HTML style // 2. "colorname" as a named color // 3. array(r,g,b) RGB triple // This function translates this to a native RGB format and returns an // RGB triple. function Color($aColor) { if (is_string($aColor)) { // Extract potential adjustment figure at end of color // specification $aColor = strtok($aColor,":"); $adj = 0+strtok(":"); if( $adj==0 ) $adj=1; if (substr($aColor, 0, 1) == "#") { return array($adj*hexdec(substr($aColor, 1, 2)), $adj*hexdec(substr($aColor, 3, 2)), $adj*hexdec(substr($aColor, 5, 2))); } else { if(!isset($this->rgb_table[$aColor]) ) JpGraphError::Raise("JpGraph Error: Unknown color: $aColor"); $tmp=$this->rgb_table[$aColor]; return array($adj*$tmp[0],$adj*$tmp[1],$adj*$tmp[2]); } } elseif( is_array($aColor) && (count($aColor)==3) ) { return $aColor; } else JpGraphError::Raise("JpGraph Error: Unknown color specification: $aColor , size=".count($aColor)); } // Compare two colors // return true if equal function Equal($aCol1,$aCol2) { $c1 = $this->Color($aCol1); $c2 = $this->Color($aCol2); if( $c1[0]==$c2[0] && $c1[1]==$c2[1] && $c1[2]==$c2[2] ) return true; else return false; } // Allocate a new color in the current image // Return new color index, -1 if no more colors could be allocated function Allocate($aColor) { list ($r, $g, $b) = $this->color($aColor); if($GLOBALS['gd2']==true) { return imagecolorresolvealpha($this->img, $r, $g, $b, 0); } else { $index = imagecolorexact($this->img, $r, $g, $b); if ($index == -1) { $index = imagecolorallocate($this->img, $r, $g, $b); if( USE_APPROX_COLORS && $index == -1 ) $index = imagecolorresolve($this->img, $r, $g, $b); } return $index; } } } // Class //=================================================== // CLASS Image // Description: Wrapper class with some goodies to form the // Interface to low level image drawing routines. //=================================================== class Image { var $img_format; var $expired=false; var $img; var $left_margin=30,$right_margin=30,$top_margin=20,$bottom_margin=30; var $plotwidth,$plotheight; var $rgb; var $current_color,$current_color_name; var $lastx=0, $lasty=0; var $width, $height; var $line_weight=1; var $line_style=1; // Default line style is solid var $obs_list=array(); var $font_size=12,$font_family=FF_FONT1, $font_style=FS_NORMAL; var $text_halign="left",$text_valign="bottom"; var $ttf=null; var $use_anti_aliasing=false; var $quality=null; var $colorstack=array(),$colorstackidx=0; //--------------- // CONSTRUCTOR function Image($aWidth,$aHeight,$aFormat=DEFAULT_GFORMAT) { $this->CreateImgCanvas($aWidth,$aHeight); if( !$this->SetImgFormat($aFormat) ) { JpGraphError::Raise("JpGraph: Selected graphic format is either not supported or unknown [$aFormat]"); } $this->ttf = new TTF(); } function SetAutoMargin() { $min_bm=10; if( BRAND_TIMING ) $min_bm=15; $lm = max(12,$this->width/7); $rm = max(12,$this->width/10); $tm = max(24,$this->height/7); $bm = max($min_bm,$this->height/7); $this->SetMargin($lm,$rm,$tm,$bm); } function CreateImgCanvas($aWidth=-1,$aHeight=-1) { $this->width=$aWidth; $this->height=$aHeight; $this->SetAutoMargin(); if( $aWidth==-1 || $aHeight==-1 ) { // We will set the final size later. // Note: The size must be specified before any other // img routines that stroke anything are called. $this->img = null; $this->rgb = null; return; } if( $GLOBALS['gd2']==true && USE_TRUECOLOR ) { $this->img = imagecreatetruecolor($aWidth, $aHeight); imagefilledrectangle($this->img, 0, 0, $aWidth, $aHeight, 0xffffff); } else { $this->img = imagecreate($aWidth, $aHeight); } assert($this->img != 0); $this->rgb = new RGB($this->img); // First index is background so this will be white $this->SetColor("white"); } //--------------- // PUBLIC METHODS // Add observer. The observer will be notified when // the margin changes function AddObserver($aMethod,&$aObject) { $this->obs_list[]=array($aMethod,&$aObject); } // Call all observers function NotifyObservers() { // foreach($this->obs_list as $o) // $o[1]->$o[0]($this); for($i=0; $i < count($this->obs_list); ++$i) { $obj = & $this->obs_list[$i][1]; $method = $this->obs_list[$i][0]; $obj->$method($this); } } function SetFont($family,$style=FS_NORMAL,$size=10) { if($family==FONT1_BOLD || $family==FONT2_BOLD || $family==FONT0 || $family==FONT1 || $family==FONT2 ) JpGraphError::Raise("JpGraph Error: Usage of FONT0, FONT1, FONT2 is deprecated. Use FF_xxx instead."); $this->font_family=$family; $this->font_style=$style; $this->font_size=$size; if( ($this->font_family==FF_FONT1 || $this->font_family==FF_FONT2) && $this->font_style==FS_BOLD ){ ++$this->font_family; } } // Get the specific height for a text string function GetTextHeight($txt="",$angle=0) { // Builtin font? $tmp = split("\n",$txt); $n = count($tmp); $m=0; for($i=0; $ifont_family <= FF_FONT2+1 ) { if( $angle==0 ) return $n*imagefontheight($this->font_family); else return $m*imagefontwidth($this->font_family); } else { $file = $this->ttf->File($this->font_family,$this->font_style); $bbox = ImageTTFBBox($this->font_size,$angle,$file,"XXOOMM"/*$txt*/); return $n*(abs($bbox[5])+abs($bbox[1])); // upper_right_y - lower_left_y } } // Estimate font height function GetFontHeight($txt="XMg",$angle=0) { $tmp = split("\n",$txt); return $this->GetTextHeight($tmp[0],$angle); } // Approximate font width with width of letter "O" function GetFontWidth($txt="O",$angle=0) { return $this->GetTextWidth($txt,$angle); } // Get actual width of text in absolute pixels function GetTextWidth($txt,$angle=0) { // Builtin font? $tmp = split("\n",$txt); $n = count($tmp); $m=0; for($i=0; $ifont_family <= FF_FONT2+1 ) { if( $angle==0 ) { $width=$m*imagefontwidth($this->font_family); return $width; } else return $n*imagefontheight($this->font_family); // 90 degrees internal so height become width } else { $file = $this->ttf->File($this->font_family,$this->font_style); $bbox = ImageTTFBBox($this->font_size,$angle,$file,$txt); return $n*(abs($bbox[2]-$bbox[6])); } } // Draw text with a box around it function StrokeBoxedText($x,$y,$txt,$dir=0,$fcolor="white",$bcolor="black", $shadow=false,$paragraph_align="left") { if( !is_numeric($dir) ) { if( $dir=="h" ) $dir=0; elseif( $dir=="v" ) $dir=90; else JpGraphError::Raise("JpGraph Error: Unknown direction specified in call to StrokeBoxedText() [$dir]"); } $width=$this->GetTextWidth($txt,$dir); $height=$this->GetTextHeight($txt,$dir); if( $this->font_family<=FF_FONT2+1 ) { $xmarg=3; $ymarg=3; } else { $xmarg=6; $ymarg=6; } $height += 2*$ymarg; $width += 2*$xmarg; if( $this->text_halign=="right" ) $x -= $width; elseif( $this->text_halign=="center" ) $x -= $width/2; if( $this->text_valign=="bottom" ) $y -= $height; elseif( $this->text_valign=="center" ) $y -= $height/2; if( $shadow ) { $oc=$this->current_color; $this->SetColor($bcolor); $this->ShadowRectangle($x,$y,$x+$width+2,$y+$height+2,$fcolor,2); $this->current_color=$oc; } else { if( $fcolor ) { $oc=$this->current_color; $this->SetColor($fcolor); $this->FilledRectangle($x,$y,$x+$width,$y+$height); $this->current_color=$oc; } if( $bcolor ) { $oc=$this->current_color; $this->SetColor($bcolor); $this->Rectangle($x,$y,$x+$width,$y+$height); $this->current_color=$oc; } } $h=$this->text_halign; $v=$this->text_valign; $this->SetTextAlign("left","top"); $this->StrokeText($x+$xmarg, $y+$ymarg, $txt, $dir, $paragraph_align); $this->SetTextAlign($h,$v); } // Set text alignment function SetTextAlign($halign,$valign="bottom") { $this->text_halign=$halign; $this->text_valign=$valign; } // Should we use anti-aliasing. Note: This really slows down graphics! function SetAntiAliasing() { $this->use_anti_aliasing=true; } function StrokeText($x,$y,$txt,$dir=0,$paragraph_align) { // Do special language encoding if( LANGUAGE_CYRILLIC ) $txt = LanguageConv::ToCyrillic($txt); if( !is_numeric($dir) ) JpGraphError::Raise("JpGraph Error: Direction for text most be given as an angle between 0 and 90."); if( $this->font_family >= FF_FONT0 && $this->font_family <= FF_FONT2+1) { // Internal font if( is_numeric($dir) && $dir!=90 && $dir!=0) JpGraphError::Raise("JpGraph Error: Internal font does not support drawing text at arbitrary angle. Use TTF fonts instead."); $h=$this->GetTextHeight($txt); $fh=$this->GetFontHeight($txt); $w=$this->GetTextWidth($txt); if( $this->text_halign=="right") $x -= $dir==0 ? $w : $h; elseif( $this->text_halign=="center" ) $x -= $dir==0 ? $w/2 : $h/2; if( $this->text_valign=="top" ) $y += $dir==0 ? $h : $w; elseif( $this->text_valign=="center" ) $y += $dir==0 ? $h/2 : $w/2; if( $dir==90 ) imagestringup($this->img,$this->font_family,$x,$y,$txt,$this->current_color); else { if (ereg("\n",$txt)) { $tmp = split("\n",$txt); for($i=0; $iGetTextWidth($tmp[$i]); if( $paragraph_align=="left" ) { imagestring($this->img,$this->font_family,$x,$y-$h+1+$i*$fh,$tmp[$i],$this->current_color); } elseif( $paragraph_align=="right" ) { imagestring($this->img,$this->font_family,$x+($w-$w1), $y-$h+1+$i*$fh,$tmp[$i],$this->current_color); } else { imagestring($this->img,$this->font_family,$x+$w/2-$w1/2, $y-$h+1+$i*$fh,$tmp[$i],$this->current_color); } } }else{ //Put the text imagestring($this->img,$this->font_family,$x,$y-$h+1,$txt,$this->current_color); } } } elseif($this->font_family >= FF_COURIER && $this->font_family <= FF_BOOK) { // TTF font $file = $this->ttf->File($this->font_family,$this->font_style); $angle=$dir; $bbox=ImageTTFBBox($this->font_size,$angle,$file,$txt); if( $this->text_halign=="right" ) $x -= $bbox[2]-$bbox[0]; elseif( $this->text_halign=="center" ) $x -= ($bbox[4]-$bbox[0])/2; elseif( $this->text_halign=="topanchor" ) $x -= $bbox[4]-$bbox[0]; elseif( $this->text_halign=="left" ) $x += -($bbox[6]-$bbox[0]); if( $this->text_valign=="top" ) $y -= $bbox[5]; elseif( $this->text_valign=="center" ) $y -= ($bbox[5]-$bbox[1])/2; elseif( $this->text_valign=="bottom" ) $y -= $bbox[1]; // Use lower left of bbox as fix-point, not the default baselinepoint. $x -= $bbox[0]; if($GLOBALS['gd2']) { $old = ImageAlphaBlending($this->img, true); } ImageTTFText ($this->img, $this->font_size, $angle, $x, $y, $this->current_color,$file,$txt); if($GLOBALS['gd2']) { ImageAlphaBlending($this->img, $old); } } else JpGraphError::Raise("JpGraph Error: Unknown font font family specification. "); } function SetMargin($lm,$rm,$tm,$bm) { $this->left_margin=$lm; $this->right_margin=$rm; $this->top_margin=$tm; $this->bottom_margin=$bm; $this->plotwidth=$this->width - $this->left_margin-$this->right_margin ; $this->plotheight=$this->height - $this->top_margin-$this->bottom_margin ; $this->NotifyObservers(); } function SetTransparent($color) { imagecolortransparent ($this->img,$this->rgb->allocate($color)); } function SetColor($color) { $this->current_color_name = $color; $this->current_color=$this->rgb->allocate($color); if( $this->current_color == -1 ) { $tc=imagecolorstotal($this->img); JpGraphError::Raise("JpGraph Error: Can't allocate any more colors.
Image has already allocated maximum of $tc colors. This might happen if you have anti-aliasing turned on together with a background image or perhaps gradient fill since this requires many, many colors. Try to turn off anti-aliasing.

If there is still a problem try downgrading the quality of the background image to use a smaller pallete to leave some entries for your graphs. You should try to limit the number of colors in your background image to 64.

If there is still problem set the constant

DEFINE(\"USE_APPROX_COLORS\",true);
in jpgraph.php This will use approximative colors when the palette is full.

Unfortunately there is not much JpGraph can do about this since the palette size is a limitation of current graphic format and what the underlying GD library suppports."); } return $this->current_color; } function PushColor($color) { if( $color != "" ) { $this->colorstack[$this->colorstackidx]=$this->current_color_name; $this->colorstack[$this->colorstackidx+1]=$this->current_color; $this->colorstackidx+=2; $this->SetColor($color); } } function PopColor() { if($this->colorstackidx<0) JpGraphError::Raise("JpGraph Error: Negative Color stack index. Unmatched call to PopColor()"); $this->current_color=$this->colorstack[--$this->colorstackidx]; $this->current_color_name=$this->colorstack[--$this->colorstackidx]; } // Why this duplication? Because this way we can call this method // for any image and not only the current objsct function AdjSat($sat) { $this->_AdjSat($this->img,$sat); } function _AdjSat($img,$sat) { $nbr = imagecolorstotal ($img); for( $i=0; $i<$nbr; ++$i ) { $colarr = imagecolorsforindex ($img,$i); $rgb[0]=$colarr["red"]; $rgb[1]=$colarr["green"]; $rgb[2]=$colarr["blue"]; $rgb = $this->AdjRGBSat($rgb,$sat); imagecolorset ($img, $i, $rgb[0], $rgb[1], $rgb[2]); } } function AdjBrightContrast($bright,$contr=0) { $this->_AdjBrightContrast($this->img,$bright,$contr); } function _AdjBrightContrast($img,$bright,$contr=0) { if( $bright < -1 || $bright > 1 || $contr < -1 || $contr > 1 ) JpGraphError::Raise("JpGraph Error: Parameters for brightness and Contrast out of range [-1,1]"); $nbr = imagecolorstotal ($img); for( $i=0; $i<$nbr; ++$i ) { $colarr = imagecolorsforindex ($img,$i); $r = $this->AdjRGBBrightContrast($colarr["red"],$bright,$contr); $g = $this->AdjRGBBrightContrast($colarr["green"],$bright,$contr); $b = $this->AdjRGBBrightContrast($colarr["blue"],$bright,$contr); imagecolorset ($img, $i, $r, $g, $b); } } // Private helper function for adj sat // Adjust saturation for RGB array $u. $sat is a value between -1 and 1 // Note: Due to GD inability to handle true color the RGB values are only between // 8 bit. This makes saturation quite sensitive for small increases in parameter sat. // // Tip: To get a grayscale picture set sat=-100, values <-100 changes the colors // to it's complement. // // Implementation note: The saturation is implemented directly in the RGB space // by adjusting the perpendicular distance between the RGB point and the "grey" // line (1,1,1). Setting $sat>0 moves the point away from the line along the perp. // distance and a negative value moves the point closer to the line. // The values are truncated when the color point hits the bounding box along the // RGB axis. // DISCLAIMER: I'm not 100% sure this is he correct way to implement a color // saturation function in RGB space. However, it looks ok and has the expected effect. function AdjRGBSat($rgb,$sat) { // TODO: Should be moved to the RGB class // Grey vector $v=array(1,1,1); // Dot product $dot = $rgb[0]*$v[0]+$rgb[1]*$v[1]+$rgb[2]*$v[2]; // Normalize dot product $normdot = $dot/3; // dot/|v|^2 // Direction vector between $u and its projection onto $v for($i=0; $i<3; ++$i) $r[$i] = $rgb[$i] - $normdot*$v[$i]; // Adjustment factor so that sat==1 sets the highest RGB value to 255 if( $sat > 0 ) { $m=0; for( $i=0; $i<3; ++$i) { if( sign($r[$i]) == 1 && $r[$i]>0) $m=max($m,(255-$rgb[$i])/$r[$i]); } $tadj=$m; } else $tadj=1; $tadj = $tadj*$sat; for($i=0; $i<3; ++$i) { $un[$i] = round($rgb[$i] + $tadj*$r[$i]); if( $un[$i]<0 ) $un[$i]=0; // Truncate color when they reach 0 if( $un[$i]>255 ) $un[$i]=255;// Avoid potential rounding error } return $un; } // Private helper function for AdjBrightContrast function AdjRGBBrightContrast($rgb,$bright,$contr) { // TODO: Should be moved to the RGB class // First handle contrast, i.e change the dynamic range around grey if( $contr <= 0 ) { // Decrease contrast $adj = abs($rgb-128) * (-$contr); if( $rgb < 128 ) $rgb += $adj; else $rgb -= $adj; } else { // $contr > 0 // Increase contrast if( $rgb < 128 ) $rgb = $rgb - ($rgb * $contr); else $rgb = $rgb + ((255-$rgb) * $contr); } // Add (or remove) various amount of white $rgb += $bright*255; $rgb=min($rgb,255); $rgb=max($rgb,0); return $rgb; } function SetLineWeight($weight) { $this->line_weight = $weight; } function SetStartPoint($x,$y) { $this->lastx=$x; $this->lasty=$y; } function Arc($cx,$cy,$w,$h,$s,$e) { imagearc($this->img,$cx,$cy,$w,$h,$s,$e,$this->current_color); } function FilledArc($cx,$cy,$w,$h,$s,$e) { if( $GLOBALS['gd2'] == false ) { JpGraphError::Raise("JpGraph Error: This plot type requires GD 2.x or later"); die(); } imagefilledarc($this->img,$cx,$cy,$w,$h,$s,$e,$this->current_color,IMG_ARC_PIE); } function FilledCakeSlice($cx,$cy,$w,$h,$s,$e) { $this->CakeSlice($cx,$cy,$w,$h,$s,$e,$this->current_color_name); } function CakeSlice($cx,$cy,$w,$h,$s,$e,$fillcolor="",$arccolor="",$stepping=2500) { // Calculate a polygon approximation $p[0] = $cx; $p[1] = $cy; // Heuristic on how many polygons we need to make the // arc look good $numsteps = round(8 * abs($e-$s) * ($w*$w+$h*$h)/$stepping); //echo "Numsteps=$numsteps
\n"; if( $numsteps < 2 ) $numsteps=2; $delta = ($e-$s)/$numsteps; $pa=array(); $a = $s; for($i=1; $i<=$numsteps; ++$i ) { $p[2*$i] = round($cx + $w*cos($a)); $p[2*$i+1] = round($cy - $h*sin($a)); $a = $s + $i*$delta; $pa[2*($i-1)] = $p[2*$i]; $pa[2*($i-1)+1] = $p[2*$i+1]; } // Get the last point at the exact ending angle to avoid // any rounding errors. $p[2*$i] = round($cx + $w*cos($e)); $p[2*$i+1] = round($cy - $h*sin($e)); $pa[2*($i-1)] = $p[2*$i]; $pa[2*($i-1)+1] = $p[2*$i+1]; $i++; $p[2*$i] = $cx; $p[2*$i+1] = $cy; if( $fillcolor != "" ) { $this->PushColor($fillcolor); $this->FilledPolygon($p); $this->PopColor(); } $this->Polygon($p); if( $arccolor != "" && ($arccolor != $this->current_color) ) { $n = count($pa)/2; $this->PushColor($arccolor); $this->SetStartPoint($pa[0],$pa[1]); for($i=1; $i<$n; ++$i) $this->LineTo($pa[2*$i],$pa[2*$i+1]); $this->PopColor(); } } function Ellipse($xc,$yc,$w,$h) { $this->Arc($xc,$yc,$w,$h,0,360); } // Breseham circle gives visually better result then using GD // built in arc(). It takes some more time but gives better // accuracy. function BresenhamCircle($xc,$yc,$r) { $d = 3-2*$r; $x = 0; $y = $r; while($x<=$y) { $this->Point($xc+$x,$yc+$y); $this->Point($xc+$x,$yc-$y); $this->Point($xc-$x,$yc+$y); $this->Point($xc-$x,$yc-$y); $this->Point($xc+$y,$yc+$x); $this->Point($xc+$y,$yc-$x); $this->Point($xc-$y,$yc+$x); $this->Point($xc-$y,$yc-$x); if( $d<0 ) $d += 4*$x+6; else { $d += 4*($x-$y)+10; --$y; } ++$x; } } function Circle($xc,$yc,$r) { if( USE_BRESENHAM ) $this->BresenhamCircle($xc,$yc,$r); else { $this->Arc($xc,$yc,$r*2,$r*2,0,360); // For some reason imageellipse() isn't in GD 2.0.1, PHP 4.1.1 //imageellipse($this->img,$xc,$yc,$r,$r,$this->current_color); } } function FilledCircle($xc,$yc,$r) { imagefilledellipse($this->img,$xc,$yc,2*$r,2*$r,$this->current_color); } // Linear Color InterPolation function lip($f,$t,$p) { $p = round($p,1); $r = $f[0] + ($t[0]-$f[0])*$p; $g = $f[1] + ($t[1]-$f[1])*$p; $b = $f[2] + ($t[2]-$f[2])*$p; return array($r,$g,$b); } // Anti-aliased line. // Note that this is roughly 8 times slower then a normal line! function WuLine($x1,$y1,$x2,$y2) { // Get foreground line color $lc = imagecolorsforindex($this->img,$this->current_color); $lc = array($lc["red"],$lc["green"],$lc["blue"]); $dx = $x2-$x1; $dy = $y2-$y1; if( abs($dx) > abs($dy) ) { if( $dx<0 ) { $dx = -$dx;$dy = -$dy; $tmp=$x2;$x2=$x1;$x1=$tmp; $tmp=$y2;$y2=$y1;$y1=$tmp; } $x=$x1<<16; $y=$y1<<16; $yinc = ($dy*65535)/$dx; while( ($x >> 16) < $x2 ) { $bc = imagecolorsforindex($this->img,imagecolorat($this->img,$x>>16,$y>>16)); $bc=array($bc["red"],$bc["green"],$bc["blue"]); $this->SetColor($this->lip($lc,$bc,($y & 0xFFFF)/65535)); imagesetpixel($this->img,$x>>16,$y>>16,$this->current_color); $this->SetColor($this->lip($lc,$bc,(~$y & 0xFFFF)/65535)); imagesetpixel($this->img,$x>>16,($y>>16)+1,$this->current_color); $x += 65536; $y += $yinc; } } else { if( $dy<0 ) { $dx = -$dx;$dy = -$dy; $tmp=$x2;$x2=$x1;$x1=$tmp; $tmp=$y2;$y2=$y1;$y1=$tmp; } $x=$x1<<16; $y=$y1<<16; $xinc = ($dx*65535)/$dy; while( ($y >> 16) < $y2 ) { $bc = imagecolorsforindex($this->img,imagecolorat($this->img,$x>>16,$y>>16)); $bc=array($bc["red"],$bc["green"],$bc["blue"]); $this->SetColor($this->lip($lc,$bc,($x & 0xFFFF)/65535)); imagesetpixel($this->img,$x>>16,$y>>16,$this->current_color); $this->SetColor($this->lip($lc,$bc,(~$x & 0xFFFF)/65535)); imagesetpixel($this->img,($x>>16)+1,$y>>16,$this->current_color); $y += 65536; $x += $xinc; } } $this->SetColor($lc); imagesetpixel($this->img,$x2,$y2,$this->current_color); imagesetpixel($this->img,$x1,$y1,$this->current_color); } // Set line style dashed, dotted etc function SetLineStyle($s) { if( is_numeric($s) ) { if( $s<1 || $s>4 ) JpGraphError::Raise("JpGraph Error: Illegal numeric argument to SetLineStyle(): $s"); } elseif( is_string($s) ) { if( $s == "solid" ) $s=1; elseif( $s == "dotted" ) $s=2; elseif( $s == "dashed" ) $s=3; elseif( $s == "longdashed" ) $s=4; else JpGraphError::Raise("JpGraph Error: Illegal string argument to SetLineStyle(): $s"); } else JpGraphError::Raise("JpGraph Error: Illegal argument to SetLineStyle $s"); $this->line_style=$s; } // Same as Line but take the line_style into account function StyleLine($x1,$y1,$x2,$y2) { switch( $this->line_style ) { case 1:// Solid $this->Line($x1,$y1,$x2,$y2); break; case 2: // Dotted $this->DashedLine($x1,$y1,$x2,$y2,1,6); break; case 3: // Dashed $this->DashedLine($x1,$y1,$x2,$y2,2,4); break; case 4: // Longdashes $this->DashedLine($x1,$y1,$x2,$y2,8,6); break; default: JpGraphError::Raise("JpGraph Error: Unknown line style: $this->line_style "); break; } } function Line($x1,$y1,$x2,$y2) { if( $this->line_weight==0 ) return; if( $this->use_anti_aliasing ) { $dx = $x2-$x1; $dy = $y2-$y1; // Vertical, Horizontal or 45 lines don't need anti-aliasing if( $dx!=0 && $dy!=0 && $dx!=$dy ) { $this->WuLine($x1,$y1,$x2,$y2); return; } } if( $this->line_weight==1 ) imageline($this->img,$x1,$y1,$x2,$y2,$this->current_color); elseif( $x1==$x2 ) { // Special case for vertical lines imageline($this->img,$x1,$y1,$x2,$y2,$this->current_color); $w1=floor($this->line_weight/2); $w2=floor(($this->line_weight-1)/2); for($i=1; $i<=$w1; ++$i) imageline($this->img,$x1+$i,$y1,$x2+$i,$y2,$this->current_color); for($i=1; $i<=$w2; ++$i) imageline($this->img,$x1-$i,$y1,$x2-$i,$y2,$this->current_color); } elseif( $y1==$y2 ) { // Special case for horizontal lines imageline($this->img,$x1,$y1,$x2,$y2,$this->current_color); $w1=floor($this->line_weight/2); $w2=floor(($this->line_weight-1)/2); for($i=1; $i<=$w1; ++$i) imageline($this->img,$x1,$y1+$i,$x2,$y2+$i,$this->current_color); for($i=1; $i<=$w2; ++$i) imageline($this->img,$x1,$y1-$i,$x2,$y2-$i,$this->current_color); } else { // General case with a line at an angle $a = atan2($y1-$y2,$x2-$x1); // Now establish some offsets from the center. This gets a little // bit involved since we are dealing with integer functions and we // want the apperance to be as smooth as possible and never be thicker // then the specified width. // We do the trig stuff to make sure that the endpoints of the line // are perpendicular to the line itself. $dx=(sin($a)*$this->line_weight/2); $dy=(cos($a)*$this->line_weight/2); $pnts = array($x2+$dx,$y2+$dy,$x2-$dx,$y2-$dy,$x1-$dx,$y1-$dy,$x1+$dx,$y1+$dy); imagefilledpolygon($this->img,$pnts,count($pnts)/2,$this->current_color); } $this->lastx=$x2; $this->lasty=$y2; } function Polygon($p) { if( $this->line_weight==0 ) return; $n=count($p)/2; for( $i=0; $i<$n; ++$i ) { $j=($i+1)%$n; $this->Line($p[$i*2],$p[$i*2+1],$p[$j*2],$p[$j*2+1]); } } function FilledPolygon($pts) { imagefilledpolygon($this->img,$pts,count($pts)/2,$this->current_color); } function Rectangle($xl,$yu,$xr,$yl) { $this->Polygon(array($xl,$yu,$xr,$yu,$xr,$yl,$xl,$yl)); } function FilledRectangle($xl,$yu,$xr,$yl) { $this->FilledPolygon(array($xl,$yu,$xr,$yu,$xr,$yl,$xl,$yl)); } function ShadowRectangle($xl,$yu,$xr,$yl,$fcolor=false,$shadow_width=3,$shadow_color=array(102,102,102)) { $this->PushColor($shadow_color); $this->FilledRectangle($xr-$shadow_width,$yu+$shadow_width,$xr,$yl); $this->FilledRectangle($xl+$shadow_width,$yl-$shadow_width,$xr,$yl); $this->PopColor(); if( $fcolor==false ) $this->Rectangle($xl,$yu,$xr-$shadow_width-1,$yl-$shadow_width-1); else { $this->PushColor($fcolor); $this->FilledRectangle($xl,$yu,$xr-$shadow_width-1,$yl-$shadow_width-1); $this->PopColor(); $this->Rectangle($xl,$yu,$xr-$shadow_width-1,$yl-$shadow_width-1); } } function StyleLineTo($x,$y) { $this->StyleLine($this->lastx,$this->lasty,$x,$y); $this->lastx=$x; $this->lasty=$y; } function LineTo($x,$y) { $this->Line($this->lastx,$this->lasty,$x,$y); $this->lastx=$x; $this->lasty=$y; } function Point($x,$y) { imagesetpixel($this->img,$x,$y,$this->current_color); } function Fill($x,$y) { imagefill($this->img,$x,$y,$this->current_color); } function DashedLine($x1,$y1,$x2,$y2,$dash_length=1,$dash_space=4) { // Code based on, but not identical to, work by Ariel Garza and James Pine $line_length = ceil (sqrt(pow(($x2 - $x1),2) + pow(($y2 - $y1),2)) ); $dx = ($x2 - $x1) / $line_length; $dy = ($y2 - $y1) / $line_length; $lastx = $x1; $lasty = $y1; $xmax = max($x1,$x2); $xmin = min($x1,$x2); $ymax = max($y1,$y2); $ymin = min($y1,$y2); for ($i = 0; $i < $line_length; $i += ($dash_length + $dash_space)) { $x = ($dash_length * $dx) + $lastx; $y = ($dash_length * $dy) + $lasty; // The last section might overshoot so we must take a computational hit // and check this. if( $x>$xmax ) $x=$xmax; if( $y>$ymax ) $y=$ymax; if( $x<$xmin ) $x=$xmin; if( $y<$ymin ) $y=$ymin; $this->Line($lastx,$lasty,$x,$y); $lastx = $x + ($dash_space * $dx); $lasty = $y + ($dash_space * $dy); } } // Generate image header function Headers() { if ($this->expired) { header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); header("Last-Modified: " . gmdate("D, d M Y H:i:s") . "GMT"); header("Cache-Control: no-cache, must-revalidate"); header("Pragma: no-cache"); } header("Content-type: image/$this->img_format"); } // Adjust image quality for formats that allow this function SetQuality($q) { $this->quality = $q; } // Stream image to browser or to file function Stream($aFile="") { $func="image".$this->img_format; if( $this->img_format=="jpeg" && $this->quality != null ) { $res = @$func($this->img,$aFile,$this->quality); } else { if( $aFile != "" ) { $res = @$func($this->img,$aFile); } else $res = @$func($this->img); } if( !$res ) JpGraphError::Raise("JpGraph Error: Can't create or stream image to file: $aFile
Check that PHP has enough permission to write a file to the current directory."); } // Clear resource tide up by image function Destroy() { imagedestroy($this->img); } // Specify image format. Note depending on your installation // of PHP not all formats may be supported. function SetImgFormat($aFormat) { $aFormat = strtolower($aFormat); $tst = true; $supported = imagetypes(); if( $aFormat=="auto" ) { if( $supported & IMG_PNG ) $this->img_format="png"; elseif( $supported & IMG_JPG ) $this->img_format="jpeg"; elseif( $supported & IMG_GIF ) $this->img_format="gif"; else JpGraphError::Raise("JpGraph Error: Your PHP (and GD-lib) installation does not appear to support any known graphic formats.". "You need to first make sure GD is compiled as a module to PHP. If you also want to use JPEG images". "you must get the JPEG library. Please see the PHP docs for details."); return true; } else { if( $aFormat=="jpeg" || $aFormat=="png" || $aFormat=="gif" ) { if( $aFormat=="jpeg" && !($supported & IMG_JPG) ) $tst=false; elseif( $aFormat=="png" && !($supported & IMG_PNG) ) $tst=false; elseif( $aFormat=="gif" && !($supported & IMG_GIF) ) $tst=false; else { $this->img_format=$aFormat; return true; } } else $tst=false; if( !$tst ) JpGraphError::Raise("JpGraph Error: Your PHP installation does not support the chosen graphic format: $aFormat"); } } } // CLASS //=================================================== // CLASS RotImage // Description: Exactly as Image but draws the image at // a specified angle around a specified rotation point. //=================================================== class RotImage extends Image { var $m=array(); var $a=0; var $dx=0,$dy=0,$transx=0,$transy=0; function RotImage($aWidth,$aHeight,$a=0,$aFormat=DEFAULT_GFORMAT) { $this->Image($aWidth,$aHeight,$aFormat); $this->dx=$this->left_margin+$this->plotwidth/2; $this->dy=$this->top_margin+$this->plotheight/2; $this->SetAngle($a); } function SetCenter($dx,$dy) { $old_dx = $this->dx; $old_dy = $this->dy; $this->dx=$dx; $this->dy=$dy; return array($old_dx,$old_dy); } function SetTranslation($dx,$dy) { $old = array($this->transx,$this->transy); $this->transx = $dx; $this->transy = $dy; return $old; } function SetAngle($a) { $tmp = $this->a; $this->a = $a; $a *= M_PI/180; $sa=sin($a); $ca=cos($a); // Create the rotation matrix $this->m[0][0] = $ca; $this->m[0][1] = -$sa; $this->m[0][2] = $this->dx*(1-$ca) + $sa*$this->dy ; $this->m[1][0] = $sa; $this->m[1][1] = $ca; $this->m[1][2] = $this->dy*(1-$ca) - $sa*$this->dx ; return $tmp; } function Circle($xc,$yc,$r) { list($xc,$yc) = $this->Rotate($xc,$yc); parent::Circle($xc,$yc,$r); } function FilledCircle($xc,$yc,$r) { list($xc,$yc) = $this->Rotate($xc,$yc); parent::FilledCircle($xc,$yc,$r); } function Arc($xc,$yc,$w,$h,$s,$e) { list($xc,$yc) = $this->Rotate($xc,$yc); parent::Arc($xc,$yc,$w,$h,$s,$e); } function FilledArc($xc,$yc,$w,$h,$s,$e) { list($xc,$yc) = $this->Rotate($xc,$yc); parent::FilledArc($xc,$yc,$w,$h,$s,$e); } function SetMargin($lm,$rm,$tm,$bm) { parent::SetMargin($lm,$rm,$tm,$bm); $this->SetAngle($this->a); } function Rotate($x,$y) { $x1=round($this->m[0][0]*$x + $this->m[0][1]*$y + $this->m[0][2] + $this->transx); $y1=round($this->m[1][0]*$x + $this->m[1][1]*$y + $this->m[1][2] + $this->transy); return array($x1,$y1); } function ArrRotate($pnts) { for($i=0; $i < count($pnts)-1; $i+=2) list($pnts[$i],$pnts[$i+1]) = $this->Rotate($pnts[$i],$pnts[$i+1]); return $pnts; } function Line($x1,$y1,$x2,$y2) { list($x1,$y1) = $this->Rotate($x1,$y1); list($x2,$y2) = $this->Rotate($x2,$y2); parent::Line($x1,$y1,$x2,$y2); } function Rectangle($x1,$y1,$x2,$y2) { $this->Polygon(array($x1,$y1,$x2,$y1,$x2,$y2,$x1,$y2)); } function FilledRectangle($x1,$y1,$x2,$y2) { if( $y1==$y2 || $x1==$x2 ) $this->Line($x1,$y1,$x2,$y2); else $this->FilledPolygon(array($x1,$y1,$x2,$y1,$x2,$y2,$x1,$y2)); } function Polygon($pnts) { //Polygon uses Line() so it will be rotated through that call parent::Polygon($pnts); } function FilledPolygon($pnts) { parent::FilledPolygon($this->ArrRotate($pnts)); } function Point($x,$y) { list($xp,$yp) = $this->Rotate($x,$y); parent::Point($xp,$yp); } function DashedLine($x1,$y1,$x2,$y2,$length=1,$space=4) { list($x1,$y1) = $this->Rotate($x1,$y1); list($x2,$y2) = $this->Rotate($x2,$y2); parent::DashedLine($x1,$y1,$x2,$y2,$length,$space); } function StrokeText($x,$y,$txt,$dir=0,$paragraph_align="left") { list($xp,$yp) = $this->Rotate($x,$y); parent::StrokeText($xp,$yp,$txt,$dir,$paragraph_align); } } //=================================================== // CLASS ImgStreamCache // Description: Handle caching of graphs to files //=================================================== class ImgStreamCache { var $cache_dir; var $img=null; var $timeout=0; // Infinite timeout //--------------- // CONSTRUCTOR function ImgStreamCache(&$aImg, $aCacheDir=CACHE_DIR) { $this->img = &$aImg; $this->cache_dir = $aCacheDir; } //--------------- // PUBLIC METHODS // Specify a timeout (in minutes) for the file. If the file is older then the // timeout value it will be overwritten with a newer version. // If timeout is set to 0 this is the same as infinite large timeout and if // timeout is set to -1 this is the same as infinite small timeout function SetTimeout($aTimeout) { $this->timeout=$aTimeout; } // Output image to browser and also write it to the cache function PutAndStream(&$aImage,$aCacheFileName,$aInline,$aStrokeFileName) { // Some debugging code to brand the image with numbe of colors // used if( JPG_DEBUG ) { $c=$aImage->SetColor("black"); $t=imagecolorstotal($this->img->img); imagestring($this->img->img,2,5,$this->img->height-20,$t,$c); } if( BRAND_TIMING ) { global $tim; $t=$tim->Pop()/1000.0; $c=$aImage->SetColor("black"); $t=sprintf(BRAND_TIME_FORMAT,round($t,3)); imagestring($this->img->img,2,5,$this->img->height-20,$t,$c); } // Check if we should stroke the image to an arbitrary file if( $aStrokeFileName!="" ) { if( $aStrokeFileName == "auto" ) $aStrokeFileName = GenImgName(); if( file_exists($aStrokeFileName) ) { // Delete the old file if( !@unlink($aStrokeFileName) ) JpGraphError::Raise("JpGraph Error: Can't delete cached image $aStrokeFileName. Permission problem?"); } $aImage->Stream($aStrokeFileName); return; } if( $aCacheFileName != "" && USE_CACHE) { $aCacheFileName = $this->cache_dir . $aCacheFileName; if( file_exists($aCacheFileName) ) { if( !$aInline ) { // If we are generating image off-line (just writing to the cache) // and the file exists and is still valid (no timeout) // then do nothing, just return. $diff=time()-filemtime($aCacheFileName); if( $diff < 0 ) JpGraphError::Raise("JpGraph Error: Cached imagefile ($aCacheFileName) has file date in the future!!"); if( $this->timeout>0 && ($diff <= $this->timeout*60) ) return; } if( !@unlink($aCacheFileName) ) JpGraphError::Raise("JpGraph Error: Can't delete cached image $aStrokeFileName. Permission problem?"); $aImage->Stream($aCacheFileName); } else { $this->_MakeDirs(dirname($aCacheFileName)); $aImage->Stream($aCacheFileName); } $res=true; // Set group to specified if( CACHE_FILE_GROUP != "" ) $res = @chgrp($aCacheFileName,CACHE_FILE_GROUP); if( CACHE_FILE_MOD != "" ) $res = @chmod($aCacheFileName,CACHE_FILE_MOD); if( !$res ) JpGraphError::Raise("JpGraph Error: Can't set permission for cached image $aStrokeFileName. Permission problem?"); $aImage->Destroy(); if( $aInline ) { if ($fh = @fopen($aCacheFileName, "rb") ) { $this->img->Headers(); fpassthru($fh); return; } else JpGraphError::Raise("JpGraph Error: Cant open file from cache [$aFile]"); } } elseif( $aInline ) { $this->img->Headers(); $aImage->Stream(); return; } } // Check if a given image is in cache and in that case // pass it directly on to web browser. Return false if the // image file doesn't exist or exists but is to old function GetAndStream($aCacheFileName) { $aCacheFileName = $this->cache_dir.$aCacheFileName; if ( USE_CACHE && file_exists($aCacheFileName) && $this->timeout>=0 ) { $diff=time()-filemtime($aCacheFileName); if( $this->timeout>0 && ($diff > $this->timeout*60) ) { return false; } else { if ($fh = @fopen($aCacheFileName, "rb")) { $this->img->Headers(); fpassthru($fh); fclose($fh); return true; } else JpGraphError::Raise("JpGraph Error: Can't open cached image \"$aCacheFileName\" for reading."); } } return false; } //--------------- // PRIVATE METHODS // Create all necessary directories in a path function _MakeDirs($aFile) { $dirs = array(); while (! (file_exists($aFile))) { $dirs[] = $aFile; $aFile = dirname($aFile); } for ($i = sizeof($dirs)-1; $i>=0; $i--) { if(! @mkdir($dirs[$i],0777) ) JpGraphError::Raise("JpGraph Error: Can't create directory in $aFile. Permission problems?"); // We also specify mode here after we have changed group. // This is necessary if Apache user doesn't belong the // default group and hence can't specify group permission // in the previous mkdir() call if( CACHE_FILE_GROUP != "" ) { $res=true; $res =@chgrp($dirs[$i],CACHE_FILE_GROUP); $res &= @chmod($dirs[$i],0777); if( !$res ) JpGraphError::Raise("JpGraph Error: Can't set permissions for $aFile. Permission problems?"); } } return true; } } // CLASS Cache //=================================================== // CLASS Legend // Description: Responsible for drawing the box containing // all the legend text for the graph //=================================================== class Legend { var $color=array(0,0,0); // Default fram color var $fill_color=array(235,235,235); // Default fill color var $shadow=true; // Shadow around legend "box" var $txtcol=array(); var $mark_abs_size=10,$xmargin=5,$ymargin=5,$shadow_width=2; var $xpos=0.05, $ypos=0.15, $halign="right", $valign="top"; var $font_family=FF_FONT1,$font_style=FS_NORMAL,$font_size=12; var $hide=false,$layout=LEGEND_VERT; var $weight=1; //--------------- // CONSTRUCTOR function Legend() { // Empty } //--------------- // PUBLIC METHODS function Hide($aHide=true) { $this->hide=$aHide; } function SetShadow($aShow=true,$aWidth=2) { $this->shadow=$aShow; $this->shadow_width=$aWidth; } function SetLineWeight($aWeight) { $this->weight = $aWeight; } function SetLayout($aDirection=LEGEND_VERT) { $this->layout=$aDirection; } // Set color on frame around box function SetColor($aColor) { $this->color=$aColor; } function SetFont($aFamily,$aStyle=FS_NORMAL,$aSize=10) { $this->font_family = $aFamily; $this->font_style = $aStyle; $this->font_size = $aSize; } function Pos($aX,$aY,$aHAlign="right",$aVAlign="top") { if( !($aX<1 && $aY<1) ) JpGraphError::Raise("JpGraph Error: Position for legend must be given as percentage in range 0-1"); $this->xpos=$aX; $this->ypos=$aY; $this->halign=$aHAlign; $this->valign=$aVAlign; } function SetBackground($aDummy) { JpGraphError::Raise("JpGraph Error: Deprecated function Legend::SetBaqckground() use Legend::SetFillColor() instead."); } function SetFillColor($aColor) { $this->fill_color=$aColor; } function Add($aTxt,$aColor,$aPlotmark="",$aLinestyle=1) { $this->txtcol[]=array($aTxt,$aColor,$aPlotmark,$aLinestyle); } function Stroke(&$aImg) { if( $this->hide ) return; $nbrplots=count($this->txtcol); if( $nbrplots==0 ) return; $aImg->SetFont($this->font_family,$this->font_style,$this->font_size); if( $this->layout==LEGEND_VERT ) $abs_height=$aImg->GetFontHeight() + $this->mark_abs_size*$nbrplots + $this->ymargin*($nbrplots-1); else $abs_height=2*$this->mark_abs_size+$this->ymargin; if( $this->shadow ) $abs_height += $this->shadow_width; $mtw=0; foreach($this->txtcol as $p) { if( $this->layout==LEGEND_VERT ) $mtw=max($mtw,$aImg->GetTextWidth($p[0])); else $mtw+=$aImg->GetTextWidth($p[0])+$this->mark_abs_size+$this->xmargin; } $abs_width=$mtw+2*$this->mark_abs_size+2*$this->xmargin; if( $this->halign=="left" ) $xp=$this->xpos*$aImg->width; elseif( $this->halign=="center" ) $xp=$this->xpos*$aImg->width - $abs_width/2; else $xp = $aImg->width - $this->xpos*$aImg->width - $abs_width; $yp=$this->ypos*$aImg->height; if( $this->valign=="center" ) $yp-=$abs_height/2; elseif( $this->valign=="bottom" ) $yp-=$abs_height; $aImg->SetColor($this->color); $aImg->SetLineWeight($this->weight); if( $this->shadow ) $aImg->ShadowRectangle($xp,$yp,$xp+$abs_width,$yp+$abs_height,$this->fill_color,$this->shadow_width); else { $aImg->SetColor($this->fill_color); $aImg->FilledRectangle($xp,$yp,$xp+$abs_width,$yp+$abs_height); $aImg->SetColor($this->color); $aImg->Rectangle($xp,$yp,$xp+$abs_width,$yp+$abs_height); } $aImg->SetLineWeight(1); $x1=$xp+$this->mark_abs_size/2; $y1=$yp+$aImg->GetFontHeight()*0.5; foreach($this->txtcol as $p) { $aImg->SetColor($p[1]); if ( $p[2] != "" && $p[2]->GetType() > -1 ) { $p[2]->Stroke($aImg,$x1+$this->mark_abs_size/2,$y1+$aImg->GetFontHeight()/2); } elseif ( $p[2] != "" ) { $aImg->SetLineStyle($p[3]); $aImg->StyleLine($x1,$y1+$aImg->GetFontHeight()/2,$x1+$this->mark_abs_size,$y1+$aImg->GetFontHeight()/2); $aImg->StyleLine($x1,$y1+$aImg->GetFontHeight()/2-1,$x1+$this->mark_abs_size,$y1+$aImg->GetFontHeight()/2-1); } else { $aImg->FilledRectangle($x1,$y1,$x1+$this->mark_abs_size,$y1+$this->mark_abs_size); $aImg->SetColor($this->color); $aImg->Rectangle($x1,$y1,$x1+$this->mark_abs_size,$y1+$this->mark_abs_size); } $aImg->SetColor($this->color); $aImg->SetTextAlign("left"); $aImg->StrokeText($x1+$this->mark_abs_size+$this->xmargin,$y1+$this->mark_abs_size,$p[0]); if( $this->layout==LEGEND_VERT ) $y1 += $this->ymargin+$this->mark_abs_size; else $x1 += 2*$this->ymargin+$this->mark_abs_size+$aImg->GetTextWidth($p[0]); } } } // Class //=================================================== // CLASS Plot // Description: Abstract base class for all concrete plot classes //=================================================== class Plot { var $line_weight=1; var $coords=array(); var $legend=""; var $csimtargets=array(); // Array of targets for CSIM var $csimareas=""; // Resultant CSIM area tags var $csimalts=null; // ALT:s for corresponding target var $color="black"; var $numpoints=0; var $weight=1; //--------------- // CONSTRUCTOR function Plot(&$aDatay,$aDatax=false) { $this->numpoints = count($aDatay); if( $this->numpoints==0 ) JpGraphError::Raise("JpGraph Error: Empty data array specified for plot. Must have at least one data point."); $this->coords[0]=$aDatay; if( is_array($aDatax) ) $this->coords[1]=$aDatax; } //--------------- // PUBLIC METHODS // Stroke the plot // "virtual" function which must be implemented by // the subclasses function Stroke(&$aImg,&$aXScale,&$aYScale) { JpGraphError::Raise("JpGraph: Stroke() must be implemented by concrete subclass to class Plot"); } // Set href targets for CSIM function SetCSIMTargets(&$aTargets,$aAlts=null) { $this->csimtargets=$aTargets; $this->csimalts=$aAlts; } // Get all created areas function GetCSIMareas() { return $this->csimareas; } // "Virtual" function which gets called before any scale // or axis are stroked used to do any plot specific adjustment function PreStrokeAdjust(&$aGraph) { if( substr($aGraph->axtype,0,4) == "text" && (isset($this->coords[1])) ) JpGraphError::Raise("JpGraph: You can't use a text X-scale with specified X-coords. Use a \"int\" or \"lin\" scale instead."); return true; } function SetWeight($aWeight) { $this->weight=$aWeight; } // Get minimum values in plot function Min() { if( isset($this->coords[1]) ) $x=$this->coords[1]; else $x=""; if( $x != "" && count($x) > 0 ) $xm=min($x); else $xm=0; $y=$this->coords[0]; if( count($y) > 0 ) { $ym = $y[0]; $cnt = count($y); $i=0; while( $i<$cnt && !is_numeric($ym=$y[$i]) ) $i++; while( $i < $cnt) { if( is_numeric($y[$i]) ) $ym=min($ym,$y[$i]); ++$i; } } else $ym=""; return array($xm,$ym); } // Get maximum value in plot function Max() { if( isset($this->coords[1]) ) $x=$this->coords[1]; else $x=""; if( $x!="" && count($x) > 0 ) $xm=max($x); else $xm=count($this->coords[0])-1; // We count from 0..(n-1) $y=$this->coords[0]; if( count($y) > 0 ) { if( !isset($y[0]) ) { $y[0] = 0; // Change in 1.5.1 Don't treat this as an error any more. Just silently concert to 0 // JpGraphError::Raise("JpGraph Error: You have not specified a y[0] value!!"); } $cnt = count($y); $i=0; while( $i<$cnt && !is_numeric($ym=$y[$i]) ) $i++; while( $i < $cnt ) { if( is_numeric($y[$i]) ) $ym=max($ym,$y[$i]); ++$i; } } else $ym=""; return array($xm,$ym); } function SetColor($aColor) { $this->color=$aColor; } function SetLegend($aLegend) { $this->legend = $aLegend; } function SetLineWeight($aWeight=1) { $this->line_weight=$aWeight; } // This method gets called by Graph class to plot anything that should go // into the margin after the margin color has been set. function StrokeMargin(&$aImg) { return true; } // Framework function the chance for each plot class to set a legend function Legend(&$aGraph) { if( $this->legend!="" ) $aGraph->legend->Add($this->legend,$this->color); } } // Class //=================================================== // CLASS PlotMark // Description: Handles the plot marks in graphs // mostly used in line and scatter plots. //=================================================== class PlotMark { var $title, $show=true; var $type=-1, $weight=1; var $color="black", $width=5, $fill_color="blue"; // -------------- // CONSTRUCTOR function PlotMark() { $this->title = new Text(); $this->title->Hide(); } //--------------- // PUBLIC METHODS function SetType($t) { $this->type = $t; } function GetType() { return $this->type; } function SetColor($c) { $this->color=$c; } function SetFillColor($c) { $this->fill_color = $c; } function SetWidth($w) { $this->width=$w; } function GetWidth() { return $this->width; } function Hide($aHide=true) { $this->show = !$aHide; } function Show($aShow=true) { $this->show = $aShow; } function Stroke(&$img,$x,$y) { if( !$this->show ) return; $dx=round($this->width/2,0); $dy=round($this->width/2,0); $pts=0; switch( $this->type ) { case MARK_SQUARE: $c[]=$x-$dx;$c[]=$y-$dy; $c[]=$x+$dx;$c[]=$y-$dy; $c[]=$x+$dx;$c[]=$y+$dy; $c[]=$x-$dx;$c[]=$y+$dy; $pts=4; break; case MARK_UTRIANGLE: ++$dx;++$dy; $c[]=$x-$dx;$c[]=$y+0.87*$dy; // tan(60)/2*$dx $c[]=$x;$c[]=$y-0.87*$dy; $c[]=$x+$dx;$c[]=$y+0.87*$dy; $pts=3; break; case MARK_DTRIANGLE: ++$dx;++$dy; $c[]=$x;$c[]=$y+0.87*$dy; // tan(60)/2*$dx $c[]=$x-$dx;$c[]=$y-0.87*$dy; $c[]=$x+$dx;$c[]=$y-0.87*$dy; $pts=3; break; case MARK_DIAMOND: $c[]=$x;$c[]=$y+$dy; $c[]=$x-$dx;$c[]=$y; $c[]=$x;$c[]=$y-$dy; $c[]=$x+$dx;$c[]=$y; $pts=4; break; } if( $pts>0 ) { $img->SetLineWeight($this->weight); $img->SetColor($this->fill_color); $img->FilledPolygon($c); $img->SetColor($this->color); $img->Polygon($c); } elseif( $this->type==MARK_CIRCLE ) { $img->SetColor($this->color); $img->Circle($x,$y,$this->width); } elseif( $this->type==MARK_FILLEDCIRCLE ) { $img->SetColor($this->fill_color); $img->FilledCircle($x,$y,$this->width); $img->SetColor($this->color); $img->Circle($x,$y,$this->width); } elseif( $this->type==MARK_CROSS ) { // Oversize by a pixel to match the X $img->SetColor($this->color); $img->SetLineWeight($this->weight); $img->Line($x,$y+$dy+1,$x,$y-$dy-1); $img->Line($x-$dx-1,$y,$x+$dx+1,$y); } elseif( $this->type==MARK_X ) { $img->SetColor($this->color); $img->SetLineWeight($this->weight); $img->Line($x+$dx,$y+$dy,$x-$dx,$y-$dy); $img->Line($x-$dx,$y+$dy,$x+$dx,$y-$dy); } elseif( $this->type==MARK_STAR ) { $img->SetColor($this->color); $img->SetLineWeight($this->weight); $img->Line($x+$dx,$y+$dy,$x-$dx,$y-$dy); $img->Line($x-$dx,$y+$dy,$x+$dx,$y-$dy); // Oversize by a pixel to match the X $img->Line($x,$y+$dy+1,$x,$y-$dy-1); $img->Line($x-$dx-1,$y,$x+$dx+1,$y); } // Stroke title $this->title->Align("center","center"); $this->title->Stroke($img,$x,$y); } } // Class //============================================================================== // The following section contains classes to implement the "band" functionality //============================================================================== // 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; } function SetDensity($aDens) { if( $aDens <1 || $aDens > 100 ) JpGraphError::Raise("JpGraph Error: 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::Raise("JpGraph Error: 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 Stroke(&$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; } $x1 = $this->rect->x + ($y1-$ye); //$x1 = $this->rect->x +$this->linespacing; $y0=$this->rect->y; $y1=$ye; while( $x0 <= $xe ) { $aImg->Line($x0,$y0,$x1,$y1); $x0 += $this->linespacing; $x1 += $this->linespacing; } $y0=$this->rect->y + ($x0-$xe); $x0=$xe; 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; } $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; 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 // 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=2; $y = $this->rect->ye - round($adj); $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 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 { 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 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 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_LVERT: $obj = new RectPatternVert($aColor,$aWeight); break; case BAND_LHOR: $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::Raise("JpGraph Error: Unknown pattern specification ($aPattern)"); } return $obj; } } //===================================================================== // Class PlotBand // Factory class which is used by the client. // It is reposnsible for factoring the corresponding pattern // concrete class. //===================================================================== class PlotBand { var $prect=null; var $depth; function PlotBand($aDir,$aPattern,$aMin,$aMax,$aColor="black",$aWeight=1,$aDepth=DEPTH_BACK) { $f = new RectPatternFactory(); $this->prect = $f->Create($aPattern,$aColor,$aWeight); $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; } // Display band function Stroke(&$aImg,&$aXScale,&$aYScale) { assert( $this->prect != null ) ; if( $this->dir == HORIZONTAL ) { if( !is_numeric($this->min) && $this->min == "min" ) $this->min = $aYScale->GetMinVal(); if( !is_numeric($this->max) && $this->max == "max" ) $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)); } else { // VERTICAL if( !is_numeric($this->min) && $this->min == "min" ) $this->min = $aXScale->GetMinVal(); if( !is_numeric($this->max) && $this->max == "max" ) $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); } } //=================================================== // CLASS PlotLine // Description: // Data container class to hold properties for a static // line that is drawn directly in the plot area. // Usefull to add static borders inside a plot to show // for example set-values //=================================================== class PlotLine { var $weight=1; var $color="black"; var $direction=-1; var $scaleposition; //--------------- // CONSTRUCTOR function PlotLine($aDir=HORIZONTAL,$aPos=0,$aColor="black",$aWeight=1) { $this->direction = $aDir; $this->color=$aColor; $this->weight=$aWeight; $this->scaleposition=$aPos; } //--------------- // PUBLIC METHODS function SetPosition($aScalePosition) { $this->scaleposition=$aScalePosition; } function SetDirection($aDir) { $this->direction = $aDir; } function SetColor($aColor) { $this->color=$aColor; } function SetWeight($aWeight) { $this->weight=$aWeight; } function Stroke(&$aImg,&$aXScale,&$aYScale) { $aImg->SetColor($this->color); $aImg->SetLineWeight($this->weight); if( $this->direction == VERTICAL ) { $ymin_abs=$aYScale->Translate($aYScale->GetMinVal()); $ymax_abs=$aYScale->Translate($aYScale->GetMaxVal()); $xpos_abs=$aXScale->Translate($this->scaleposition); $aImg->Line($xpos_abs, $ymin_abs, $xpos_abs, $ymax_abs); } elseif( $this->direction == HORIZONTAL ) { $xmin_abs=$aXScale->Translate($aXScale->GetMinVal()); $xmax_abs=$aXScale->Translate($aXScale->GetMaxVal()); $ypos_abs=$aYScale->Translate($this->scaleposition); $aImg->Line($xmin_abs, $ypos_abs, $xmax_abs, $ypos_abs); } else JpGraphError::Raise("JpGraph Error: Illegal direction for static line"); } } // ?> jpgraph-1.5.2/src/jpgraph_gantt.php0100644000076400001440000013145507437547531016043 0ustar ljpusers LOCALE_SE ) JpGraphError::Raise("JpGraph Error: Unsupported locale ($aLocale)"); $this->iLocale = $aLocale; } function GetDayAbb() { return $this->iDayAbb[$this->iLocale]; } function GetShortDay() { return $this->iShortDay[$this->iLocale]; } function GetShortMonth($aMonth=null) { return $this->iShortMonth[$this->iLocale]; } function GetShortMonthName($aNbr) { return $this->iShortMonth[$this->iLocale][$aNbr]; } function GetLongMonthName($aNbr) { return $this->iMonthName[$this->iLocale][$aNbr]; } function GetMonth() { return $this->iMonthName[$this->iLocale]; } } //=================================================== // CLASS GanttGraph // Description: Main class to handle gantt graphs //=================================================== class GanttGraph extends Graph { var $scale; // Public accessible var $iObj=array(); // Gantt objects var $iLabelHMarginFactor=0.2; // 10% margin on each side of the labels var $iLabelVMarginFactor=0.4; // 40% margin on top and bottom of label var $iLayout=GANTT_FROMTOP; // Could also be GANTT_EVEN //--------------- // CONSTRUCTOR // Create a new gantt graph function GanttGraph($aWidth=-1,$aHeight=-1,$aCachedName="",$aTimeOut=0,$aInline=true) { Graph::Graph($aWidth,$aHeight,$aCachedName,$aTimeOut,$aInline); $this->scale = new GanttScale($this->img); $this->img->SetMargin($aWidth/17,$aWidth/17,$aHeight/7,$aHeight/10); $this->scale->ShowHeaders(GANTT_HWEEK|GANTT_HDAY); $this->SetBox(); } //--------------- // PUBLIC METHODS // Set what headers should be shown function ShowHeaders($aFlg) { $this->scale->ShowHeaders($aFlg); } // Specify the fraction of the font height that should be added // as vertical margin function SetLabelVMarginFactor($aVal) { $this->iLabelVMarginFactor = $aVal; } // Add a new Gantt object function Add(&$aObject) { if( is_array($aObject) ) { for($i=0; $iiObj[] = $aObject[$i]; } else $this->iObj[] = $aObject; } // Override inherit method from Graph and give a warning message function SetScale() { JpGraphError::Raise("JpGraph Error: SetScale() is not meaningfull with Gantt charts."); // Empty } // Specify the date range for Gantt graphs (if this is not set it will be // automtically determined from the input data) function SetDateRange($aStart,$aEnd) { $this->scale->SetRange($aStart,$aEnd); } // Get the maximum width of the titles for the bars function GetMaxLabelWidth() { $m=0; if( $this->iObj != null ) { $m = $this->iObj[0]->title->GetWidth($this->img); for($i=1; $iiObj); ++$i) { if( $this->iObj[$i]->title->HasTabs() ) { list($tot,$w) = $this->iObj[$i]->title->GetWidth($this->img,true); $m=max($m,$tot); } else $m=max($m,$this->iObj[$i]->title->GetWidth($this->img)); } } return $m; } // Get the maximum height of the titles for the bars function GetMaxLabelHeight() { $m=0; if( $this->iObj != null ) { $m = $this->iObj[0]->title->GetHeight($this->img); for($i=1; $iiObj); ++$i) { $m=max($m,$this->iObj[$i]->title->GetHeight($this->img)); } } return $m; } function GetMaxBarAbsHeight() { $m=0; if( $this->iObj != null ) { $m = $this->iObj[0]->GetAbsHeight($this->img); for($i=1; $iiObj); ++$i) { $m=max($m,$this->iObj[$i]->GetAbsHeight($this->img)); } } return $m; } // Get the maximum used line number (vertical position) for bars function GetBarMaxLineNumber() { $m=0; if( $this->iObj != null ) { $m = $this->iObj[0]->GetLineNbr(); for($i=1; $iiObj); ++$i) { $m=max($m,$this->iObj[$i]->GetLineNbr()); } } return $m; } // Get the minumum and maximum used dates for all bars function GetBarMinMax() { $max=$this->scale->NormalizeDate($this->iObj[0]->GetMaxDate()); $min=$this->scale->NormalizeDate($this->iObj[0]->GetMinDate()); for($i=1; $iiObj); ++$i) { $max=Max($max,$this->scale->NormalizeDate($this->iObj[$i]->GetMaxDate())); $min=Min($min,$this->scale->NormalizeDate($this->iObj[$i]->GetMinDate())); } $minDate = date("Y-m-d",$min); $min = strtotime($minDate); $maxDate = date("Y-m-d",$max); $max = strtotime($maxDate); return array($min,$max); } // Stroke the gantt chart function Stroke($aStrokeFileName="") { // Should we autoscale dates? if( !$this->scale->IsRangeSet() ) { list($min,$max) = $this->GetBarMinMax(); $this->scale->SetRange($min,$max); } if( $this->img->img == null ) { // The predefined left, right, top, bottom margins. // Note that the top margin might incease depending on // the title. $lm=30;$rm=30;$tm=20;$bm=30; if( BRAND_TIMING ) $bm += 10; // First find out the height $n=$this->GetBarMaxLineNumber()+1; $m=max($this->GetMaxLabelHeight(),$this->GetMaxBarAbsHeight()); $height=$n*((1+$this->iLabelVMarginFactor)*$m); // Add the height of the scale titles $h=$this->scale->GetHeaderHeight(); $height += $h; // Calculate the top margin needed for title and subtitle if( $this->title->t != "" ) { $tm += $this->title->GetFontHeight($this->img); } if( $this->subtitle->t != "" ) { $tm += $this->subtitle->GetFontHeight($this->img); } // ...and then take the bottom and top plot margins into account $height += $tm + $bm + $this->scale->iTopPlotMargin + $this->scale->iBottomPlotMargin; // Now find the minimum width for the chart required $fw=$this->scale->day->GetFontWidth($this->img)+4; $nd=$this->scale->GetNumberOfDays(); if( !$this->scale->IsDisplayDay() ) { // If we don't display the individual days we can shrink the // scale a little bit. This is a little bit pragmatic at the // moment and should be re-written to take into account // a) What scales exactly are shown and // b) what format do they use so we know how wide we need to // make each scale text space at minimum. $fw /= 2; if( !$this->scale->IsDisplayWeek() ) { $fw /= 1.8; } } // Now determine the width for the activity titles column // This is complicated by the fact that the titles may have // tabs. In that case we also need to calculate the individual // tab positions based on the width of the individual columns $titlewidth = $this->GetMaxLabelWidth(); // Now get the total width taking // titlewidth, left and rigt margin, dayfont size // into account $width = $titlewidth + $nd*$fw + $lm+$rm; $this->img->CreateImgCanvas($width,$height); $this->img->SetMargin($lm,$rm,$tm,$bm); } // Should we start from the top or just spread the bars out even over the // available height $this->scale->SetVertLayout($this->iLayout); if( $this->iLayout == GANTT_FROMTOP ) { $maxheight=max($this->GetMaxLabelHeight(),$this->GetMaxBarAbsHeight()); $this->scale->SetVertSpacing($maxheight*(1+$this->iLabelVMarginFactor)); } // If it hasn't been set find out the maximum line number if( $this->scale->iVertLines == -1 ) $this->scale->iVertLines = $this->GetBarMaxLineNumber()+1; $maxwidth=max($this->GetMaxLabelWidth(),$this->scale->tableTitle->GetWidth($this->img)); $this->scale->SetLabelWidth($maxwidth*(1+$this->iLabelHMarginFactor)); $this->StrokePlotArea(); $this->scale->Stroke(); $this->StrokePlotBox(); for($i=0; $iiObj); ++$i) { $this->iObj[$i]->SetLabelLeftMargin(round($maxwidth*$this->iLabelHMarginFactor/2)); $this->iObj[$i]->Stroke($this->img,$this->scale); } $this->StrokeTitles(); $this->cache->PutAndStream($this->img,$this->cache_name,$this->inline,$aStrokeFileName); } } //=================================================== // CLASS TextProperty // Description: Holds properties for a text //=================================================== class TextProperty { var $iFFamily=FF_FONT1,$iFStyle=FS_NORMAL,$iFSize=10; var $iColor="black"; var $iShow=true; var $iText=""; var $iHAlign="left",$iVAlign="bottom"; //--------------- // CONSTRUCTOR function TextProperty($aTxt="") { $this->iText = $aTxt; } //--------------- // PUBLIC METHODS function Set($aTxt) { $this->iText = $aTxt; } // Set text color function SetColor($aColor) { $this->iColor = $aColor; } function HasTabs() { return substr_count($this->iText,"\t") > 0; } // Get number of tabs in string function GetNbrTabs() { substr_count($this->iText,"\t"); } // Set alignment function Align($aHAlign,$aVAlign="bottom") { $this->iHAlign=$aHAlign; $this->iVAlign=$aVAlign; } // Specify font function SetFont($aFFamily,$aFStyle=FS_NORMAL,$aFSize=10) { $this->iFFamily = $aFFamily; $this->iFStyle = $aFStyle; $this->iFSize = $aFSize; } // Get width of text. If text contains several columns separated by // tabs then return both the total width as well as an array with a // width for each column. function GetWidth($aImg,$aUseTabs=false,$aTabExtraMargin=1.1) { if( strlen($this->iText)== 0 ) return; $tmp = split("\t",$this->iText); $aImg->SetFont($this->iFFamily,$this->iFStyle,$this->iFSize); if( count($tmp) <= 1 || !$aUseTabs ) { return $aImg->GetTextWidth($this->iText); } else { $tot=0; for($i=0; $iGetTextWidth($tmp[$i]); $tot += $res[$i]*$aTabExtraMargin; } return array($tot,$res); } } // Get total height of text function GetHeight($aImg) { $aImg->SetFont($this->iFFamily,$this->iFStyle,$this->iFSize); return $aImg->GetFontHeight(); } // Unhide/hide the text function Show($aShow) { $this->iShow=$aShow; } // Stroke text at (x,y) coordinates. If the text contains tabs then the // x parameter should be an array of positions to be used for each successive // tab mark. If no array is supplied then the tabs will be ignored. function Stroke($aImg,$aX,$aY) { if( $this->iShow ) { $aImg->SetColor($this->iColor); $aImg->SetFont($this->iFFamily,$this->iFStyle,$this->iFSize); $aImg->SetTextAlign($this->iHAlign,$this->iVAlign); if( $this->GetNbrTabs() <= 1 || !is_array($aX) ) { // Get rid of any "\t" characters and stroke string $aImg->StrokeText($aX,$aY,str_replace("\t"," ",$this->iText)); } else { $tmp = split("\t",$this->iText); $n = min(count($tmp),count($aX)); for($i=0; $i<$n; ++$i) { $aImg->StrokeText($aX[$i],$aY,$tmp[$i]); } } } } } //=================================================== // CLASS HeaderProperty // Description: Data encapsulating class to hold property // for each type of the scale headers //=================================================== class HeaderProperty { var $iTitleVertMargin=3,$iFFamily=FF_FONT0,$iFStyle=FS_NORMAL,$iFSize=8; var $iFrameColor="black",$iFrameWeight=1; var $iShowLabels=true,$iShowGrid=true; var $iBackgroundColor="white"; var $iWeekendBackgroundColor="lightgray",$iSundayTextColor="red"; // these are only used with day scale var $iTextColor="black"; var $iLabelFormStr="%d"; var $grid,$iStyle=0; //--------------- // CONSTRUCTOR function HeaderProperty() { $this->grid = new LineProperty(); } //--------------- // PUBLIC METHODS function Show($aShow) { $this->iShowLabels = $aShow; } function SetFont($aFFamily,$aFStyle=FS_NORMAL,$aFSize=10) { $this->iFFamily = $aFFamily; $this->iFStyle = $aFStyle; $this->iFSize = $aFSize; } function SetFontColor($aColor) { $this->iTextColor = $aColor; } function GetFontHeight($aImg) { $aImg->SetFont($this->iFFamily,$this->iFStyle,$this->iFSize); return $aImg->GetFontHeight(); } function GetFontWidth($aImg) { $aImg->SetFont($this->iFFamily,$this->iFStyle,$this->iFSize); return $aImg->GetFontWidth(); } function SetStyle($aStyle) { $this->iStyle = $aStyle; } function SetBackgroundColor($aColor) { $this->iBackgroundColor=$aColor; } function SetFrameWeight($aWeight) { $this->iFrameWeight=$aWeight; } function SetFrameColor($aColor) { $this->iFrameColor=$aColor; } // Only used by day scale function SetWeekendColor($aColor) { $this->iWeekendBackgroundColor=$aColor; } // Only used by day scale function SetSundayFontColor($aColor) { $this->iSundayTextColor=$aColor; } function SetTitleVertMargin($aMargin) { $this->iTitleVertMargin=$aMargin; } function SetLabelFormatString($aStr) { $this->iLabelFormStr=$aStr; } } //=================================================== // CLASS GanttScale // Description: Responsible for calculating and showing // the scale in a gantt chart. This includes providing methods for // converting dates to position in the chart as well as stroking the // date headers (days, week, etc). //=================================================== class GanttScale { var $day,$week,$month,$year; var $divider,$dividerh,$tableTitle; var $iStartDate=-1,$iEndDate=-1; // Number of gantt bar position (n.b not necessariliy the same as the number of bars) // we could have on bar in position 1, and one bar in position 5 then there are two // bars but the number of bar positions is 5 var $iVertLines=-1; // The width of the labels (defaults to the widest of all labels) var $iLabelWidth; // Out image to stroke the scale to var $iImg; var $iTableHeaderBackgroundColor="white",$iTableHeaderFrameColor="black"; var $iTableHeaderFrameWeight=1; var $iAvailableHeight=-1,$iVertSpacing=-1,$iVertHeaderSize=-1; var $iDateLocale; var $iVertLayout=GANTT_EVEN; var $iTopPlotMargin=10,$iBottomPlotMargin=15; var $iUsePlotWeekendBackground=true; //--------------- // CONSTRUCTOR function GanttScale(&$aImg) { $this->iImg = &$aImg; $this->iDateLocale = new DateLocale(); $this->day = new HeaderProperty(); $this->day->grid->SetColor("gray"); $this->week = new HeaderProperty(); $this->week->SetLabelFormatString("w%d"); $this->week->SetFont(FF_FONT1); $this->month = new HeaderProperty(); $this->month->SetFont(FF_FONT1,FS_BOLD); $this->year = new HeaderProperty(); $this->year->SetFont(FF_FONT1,FS_BOLD); $this->divider=new LineProperty(); $this->dividerh=new LineProperty(); $this->tableTitle=new TextProperty(); } //--------------- // PUBLIC METHODS // Specify what headers should be visible function ShowHeaders($aFlg) { $this->day->Show($aFlg & GANTT_HDAY); $this->week->Show($aFlg & GANTT_HWEEK); $this->month->Show($aFlg & GANTT_HMONTH); $this->year->Show($aFlg & GANTT_HYEAR); // Make some default settings of gridlines whihc makes sense if( $aFlg & GANTT_HWEEK ) { $this->month->grid->Show(false); $this->year->grid->Show(false); } } // Should the weekend background stretch all the way down in the plotarea function UseWeekendBackground($aShow) { $this->iUsePlotWeekendBackground = $aShow; } // Have a range been specified? function IsRangeSet() { return $this->iStartDate!=-1 && $this->iEndDate!=-1; } // Should the layout be from top or even? function SetVertLayout($aLayout) { $this->iVertLayout = $aLayout; } // Which locale should be used? function SetDateLocale($aLocale) { $this->iDateLocale->Set($aLocale); } // Number of days we are showing function GetNumberOfDays() { return round(($this->iEndDate-$this->iStartDate)/SECPERDAY)+1; } // The widthj of the actual plot area function GetPlotWidth() { $img=$this->iImg; return $img->width - $img->left_margin - $img->right_margin; } // Specify the width of the titles(labels) for the activities // (This is by default set to the minimum width enought for the // widest title) function SetLabelWidth($aLabelWidth) { $this->iLabelWidth=$aLabelWidth; } // Do we show day scale? function IsDisplayDay() { return $this->day->iShowLabels; } // Do we show week scale? function IsDisplayWeek() { return $this->week->iShowLabels; } // Do we show month scale? function IsDisplayMonth() { return $this->month->iShowLabels; } // Do we show year scale? function IsDisplayYear() { return $this->year->iShowLabels; } // Specify spacing (in percent of bar height) between activity bars function SetVertSpacing($aSpacing) { $this->iVertSpacing = $aSpacing; } // Specify scale min and max date either as timestamp or as date strings // Always round to the nearest week boundary function SetRange($aMin,$aMax) { $this->iStartDate = $this->NormalizeDate($aMin); $this->iEndDate = $this->NormalizeDate($aMax); // Get day in week Sun=0 $ds=strftime("%w",$this->iStartDate); $de=strftime("%w",$this->iEndDate); if( $ds==0 ) $ds=7; if( $de==0 ) $de=7; // We want to start on Monday $this->iStartDate -= SECPERDAY*($ds-1); // We want to end on a Sunday $this->iEndDate += SECPERDAY*(7-$de); } // Specify background for the table title area (upper left corner of the table) function SetTableTitleBackground($aColor) { $this->iTableHeaderBackgroundColor = $aColor; } /////////////////////////////////////// // PRIVATE Methods // Determine the height of all the scale headers combined function GetHeaderHeight() { $img=$this->iImg; $height=1; if( $this->day->iShowLabels ) { $height += $this->day->GetFontHeight($img); $height += $this->day->iTitleVertMargin; } if( $this->week->iShowLabels ) { $height += $this->week->GetFontHeight($img); $height += $this->week->iTitleVertMargin; } if( $this->month->iShowLabels ) { $height += $this->month->GetFontHeight($img); $height += $this->month->iTitleVertMargin; } if( $this->year->iShowLabels ) { $height += $this->year->GetFontHeight($img); $height += $this->year->iTitleVertMargin; } return $height; } // Get width (in pisels) for a single day function GetDayWidth() { return ($this->GetPlotWidth()-$this->iLabelWidth+1)/$this->GetNumberOfDays(); } // Nuber of days in a year function GetNumDaysInYear($aYear) { if( $this->IsLeap($aYear) ) return 366; else return 365; } // Get day number in year function GetDayNbrInYear($aDate) { return 0+strftime("%j",$aDate); } // Get week number function GetWeekNbr($aDate) { // We can't use the internal strftime() since it gets the weeknumber // wrong since it doesn't follow ISO. // Even worse is that this works differently if we are on a Windows // or UNIX box (it even differs between UNIX boxes how strftime() // is natively implemented) // // Credit to Nicolas Hoizey for this elegant // version of Week Nbr calculation. $day = $this->NormalizeDate($aDate); /*------------------------------------------------------------------------- According to ISO-8601 : "Week 01 of a year is per definition the first week that has the Thursday in this year, which is equivalent to the week that contains the fourth day of January. In other words, the first week of a new year is the week that has the majority of its days in the new year." Be carefull, with PHP, -3 % 7 = -3, instead of 4 !!! day of year = date("z", $day) + 1 offset to thursday = 3 - (date("w", $day) + 6) % 7 first thursday of year = 1 + (11 - date("w", mktime(0, 0, 0, 1, 1, date("Y", $day)))) % 7 week number = (thursday's day of year - first thursday's day of year) / 7 + 1 ---------------------------------------------------------------------------*/ $thursday = $day + 60 * 60 * 24 * (3 - (date("w", $day) + 6) % 7); // take week's thursday $week = 1 + (date("z", $thursday) - (11 - date("w", mktime(0, 0, 0, 1, 1, date("Y", $thursday)))) % 7) / 7; return $week; } // Is year a leap year? function IsLeap($aYear) { // Is the year a leap year? //$year = 0+date("Y",$aDate); if( $aYear % 4 == 0) if( !($aYear % 100 == 0) || ($aYear % 400 == 0) ) return true; return false; } // Get current year function GetYear($aDate) { return 0+Date("Y",$aDate); } // Return number of days in a year function GetNumDaysInMonth($aMonth,$aYear) { $days=array(31,28,31,30,31,30,31,31,30,31,30,31); $daysl=array(31,29,31,30,31,30,31,31,30,31,30,31); if( $this->IsLeap($aYear)) return $daysl[$aMonth]; else return $days[$aMonth]; } // Get day in month function GetMonthDayNbr($aDate) { return 0+strftime("%d",$aDate); } // Get day in year function GetYearDayNbr($aDate) { return 0+strftime("%j",$aDate); } // Get month number function GetMonthNbr($aDate) { return 0+strftime("%m",$aDate); } // Translate a date to screen coordinates (horizontal scale) function TranslateDate($aDate) { $aDate = $this->NormalizeDate($aDate); $img=$this->iImg; if( $aDate < $this->iStartDate || $aDate > $this->iEndDate ) JpGraphError::Raise("JpGraph Error: Date is outside specified scale range."); return ($aDate-$this->iStartDate)/SECPERDAY*$this->GetDayWidth()+$img->left_margin+$this->iLabelWidth;; } // Get screen coordinatesz for the vertical position for a bar function TranslateVertPos($aPos) { $img=$this->iImg; $ph=$this->iAvailableHeight; if( $aPos > $this->iVertLines ) JpGraphError::Raise("JpGraph Error: Illegal vertical position $aPos"); if( $this->iVertLayout == GANTT_EVEN ) { // Position the top bar at 1 vert spacing from the scale return round($img->top_margin + $this->iVertHeaderSize + ($aPos+1)*$this->iVertSpacing); } else { // position the top bar at 1/2 a vert spacing from the scale return round($img->top_margin + $this->iVertHeaderSize + $this->iTopPlotMargin + ($aPos+1)*$this->iVertSpacing); } } // What is the vertical spacing? function GetVertSpacing() { return $this->iVertSpacing; } // Convert a date to timestamp function NormalizeDate($aDate) { if( is_string($aDate) ) return strtotime($aDate); elseif( is_int($aDate) || is_float($aDate) ) return $aDate; else JpGraphError::Raise("JpGraph Error: Unknown date format in GanttScale ($aDate)."); } // Stroke the day scale (including gridlines) function StrokeDays($aYCoord) { $wdays=$this->iDateLocale->GetDayAbb(); $img=$this->iImg; $daywidth=$this->GetDayWidth(); $xt=$img->left_margin+$this->iLabelWidth; $yt=$aYCoord+$img->top_margin; if( $this->day->iShowLabels ) { $img->SetFont($this->day->iFFamily,$this->day->iFStyle,$this->day->iFSize); $xb=$img->width-$img->right_margin; $yb=$yt + $img->GetFontHeight() + $this->day->iTitleVertMargin + $this->day->iFrameWeight; $img->SetColor($this->day->iBackgroundColor); $img->FilledRectangle($xt,$yt,$xb,$yb); $img->SetColor($this->day->grid->iColor); $x = $xt; $img->SetTextAlign("center"); for($i=0; $i<$this->GetNumberOfDays(); ++$i, $x+=$daywidth) { $day=$i%7; if( $day==5 ) { $img->PushColor($this->day->iWeekendBackgroundColor); if( $this->iUsePlotWeekendBackground ) $img->FilledRectangle($x,$yt+$this->day->iFrameWeight,$x+2*$daywidth,$img->height-$img->bottom_margin); else $img->FilledRectangle($x,$yt+$this->day->iFrameWeight,$x+2*$daywidth,$yb-$this->day->iFrameWeight); $img->PopColor(); } if( $day==6 ) $img->PushColor($this->day->iSundayTextColor); else $img->PushColor($this->day->iTextColor); $img->StrokeText(round($x+$daywidth/2+1), round($yb-$this->day->iTitleVertMargin), $wdays[$i%7]); $img->PopColor(); $img->Line($x,$yt,$x,$yb); $this->day->grid->Stroke($img,$x,$yb,$x,$img->height-$img->bottom_margin); } $img->SetColor($this->day->iFrameColor); $img->SetLineWeight($this->day->iFrameWeight); $img->Rectangle($xt,$yt,$xb,$yb); return $yb - $img->top_margin; } return $aYCoord; } // Stroke week header and grid function StrokeWeeks($aYCoord) { $wdays=$this->iDateLocale->GetDayAbb(); $img=$this->iImg; $weekwidth=$this->GetDayWidth()*7; $xt=$img->left_margin+$this->iLabelWidth; $yt=$aYCoord+$img->top_margin; $img->SetFont($this->week->iFFamily,$this->week->iFStyle,$this->week->iFSize); $xb=$img->width-$img->right_margin; $yb=$yt + $img->GetFontHeight() + $this->week->iTitleVertMargin + $this->week->iFrameWeight; $week = $this->iStartDate; $weeknbr=$this->GetWeekNbr($week); if( $this->week->iShowLabels ) { $img->SetColor($this->week->iBackgroundColor); $img->FilledRectangle($xt,$yt,$xb,$yb); $img->SetColor($this->week->grid->iColor); $x = $xt; if( $this->week->iStyle==WEEKSTYLE_WNBR ) { $img->SetTextAlign("center"); $txtOffset = $weekwidth/2+1; } elseif( $this->week->iStyle==WEEKSTYLE_FIRSTDAY || $this->week->iStyle==WEEKSTYLE_FIRSTDAY2 ) { $img->SetTextAlign("left"); $txtOffset = 2; } else JpGraphError::Raise("JpGraph Error:Unknown formatting style for week."); for($i=0; $i<$this->GetNumberOfDays()/7; ++$i, $x+=$weekwidth) { $img->PushColor($this->week->iTextColor); if( $this->week->iStyle==WEEKSTYLE_WNBR ) $txt = sprintf($this->week->iLabelFormStr,$weeknbr); elseif( $this->week->iStyle==WEEKSTYLE_FIRSTDAY ) $txt = date("j/n",$week); elseif( $this->week->iStyle==WEEKSTYLE_FIRSTDAY2 ) { $monthnbr = date("n",$week)-1; $shortmonth = $this->iDateLocale->GetShortMonthName($monthnbr); $txt = Date("j",$week)." ".$shortmonth; } $img->StrokeText(round($x+$txtOffset),round($yb-$this->week->iTitleVertMargin),$txt); $week += 7*SECPERDAY; $weeknbr = $this->GetWeekNbr($week); $img->PopColor(); $img->Line($x,$yt,$x,$yb); $this->week->grid->Stroke($img,$x,$yb,$x,$img->height-$img->bottom_margin); } $img->SetColor($this->week->iFrameColor); $img->SetLineWeight($this->week->iFrameWeight); $img->Rectangle($xt,$yt,$xb,$yb); return $yb-$img->top_margin; } return $aYCoord; } // Format the mont scale header string function GetMonthLabel($aMonthNbr,$year) { $sn = $this->iDateLocale->GetShortMonthName($aMonthNbr); $ln = $this->iDateLocale->GetLongMonthName($aMonthNbr); switch($this->month->iStyle) { case MONTHSTYLE_SHORTNAME: $m=$sn; break; case MONTHSTYLE_LONGNAME: $m=$ln; break; case MONTHSTYLE_SHORTNAMEYEAR2: $m=$sn." '".substr("".$year,2); break; case MONTHSTYLE_SHORTNAMEYEAR4: $m=$sn." ".$year; break; case MONTHSTYLE_LONGNAMEYEAR2: $m=$ln." '".substr("".$year,2); break; case MONTHSTYLE_LONGNAMEYEAR4: $m=$ln." ".$year; break; } return $m; } // Stroke month scale and gridlines function StrokeMonths($aYCoord) { if( $this->month->iShowLabels ) { $monthnbr = $this->GetMonthNbr($this->iStartDate)-1; $img=$this->iImg; $xt=$img->left_margin+$this->iLabelWidth; $yt=$aYCoord+$img->top_margin; $img->SetFont($this->month->iFFamily,$this->month->iFStyle,$this->month->iFSize); $xb=$img->width-$img->right_margin; $yb=$yt + $img->GetFontHeight() + $this->month->iTitleVertMargin + $this->month->iFrameWeight; $img->SetColor($this->month->iBackgroundColor); $img->FilledRectangle($xt,$yt,$xb,$yb); $img->SetLineWeight($this->month->grid->iWeight); $img->SetColor($this->month->iTextColor); $year = 0+strftime("%Y",$this->iStartDate); $img->SetTextAlign("center"); $monthwidth=$this->GetDayWidth()*($this->GetNumDaysInMonth($monthnbr,$year)-$this->GetMonthDayNbr($this->iStartDate)+1); // Is it enough space to stroke the first month? $monthName = $this->GetMonthLabel($monthnbr,$year); if( $monthwidth >= 1.2*$img->GetTextWidth($monthName) ) { $img->SetColor($this->month->iTextColor); $img->StrokeText(round($xt+$monthwidth/2+1), round($yb-$this->month->iTitleVertMargin), $monthName); } $x = $xt + $monthwidth; while( $x < $xb ) { $img->SetColor($this->month->grid->iColor); $img->Line($x,$yt,$x,$yb); $this->month->grid->Stroke($img,$x,$yb,$x,$img->height-$img->bottom_margin); $monthnbr++; if( $monthnbr==12 ) { $monthnbr=0; $year++; } $monthName = $this->GetMonthLabel($monthnbr,$year); $monthwidth=$this->GetDayWidth()*$this->GetNumDaysInMonth($monthnbr,$year); if( $x + $monthwidth < $xb ) $w = $monthwidth; else $w = $xb-$x; if( $w >= 1.2*$img->GetTextWidth($monthName) ) { $img->SetColor($this->month->iTextColor); $img->StrokeText(round($x+$w/2+1), round($yb-$this->month->iTitleVertMargin),$monthName); } $x += $monthwidth; } $img->SetColor($this->month->iFrameColor); $img->SetLineWeight($this->month->iFrameWeight); $img->Rectangle($xt,$yt,$xb,$yb); return $yb-$img->top_margin; } return $aYCoord; } // Stroke year scale and gridlines function StrokeYears($aYCoord) { if( $this->year->iShowLabels ) { $year = $this->GetYear($this->iStartDate); $img=$this->iImg; $xt=$img->left_margin+$this->iLabelWidth; $yt=$aYCoord+$img->top_margin; $img->SetFont($this->year->iFFamily,$this->year->iFStyle,$this->year->iFSize); $xb=$img->width-$img->right_margin; $yb=$yt + $img->GetFontHeight() + $this->year->iTitleVertMargin + $this->year->iFrameWeight; $img->SetColor($this->year->iBackgroundColor); $img->FilledRectangle($xt,$yt,$xb,$yb); $img->SetLineWeight($this->year->grid->iWeight); $img->SetTextAlign("center"); if( $year == $this->GetYear($this->iEndDate) ) $yearwidth=$this->GetDayWidth()*($this->GetYearDayNbr($this->iEndDate)-$this->GetYearDayNbr($this->iStartDate)+1); else $yearwidth=$this->GetDayWidth()*($this->GetNumDaysInYear($year)-$this->GetYearDayNbr($this->iStartDate)+1); // The space for a year must be at least 20% bigger than the actual text // so we allow 10% margin on each side if( $yearwidth >= 1.20*$img->GetTextWidth("".$year) ) { $img->SetColor($this->year->iTextColor); $img->StrokeText(round($xt+$yearwidth/2+1), round($yb-$this->year->iTitleVertMargin), $year); } $x = $xt + $yearwidth; while( $x < $xb ) { $img->SetColor($this->year->grid->iColor); $img->Line($x,$yt,$x,$yb); $this->year->grid->Stroke($img,$x,$yb,$x,$img->height-$img->bottom_margin); $year += 1; $yearwidth=$this->GetDayWidth()*$this->GetNumDaysInYear($year); if( $x + $yearwidth < $xb ) $w = $yearwidth; else $w = $xb-$x; if( $w >= 1.2*$img->GetTextWidth("".$year) ) { $img->SetColor($this->year->iTextColor); $img->StrokeText(round($x+$w/2+1), round($yb-$this->year->iTitleVertMargin), $year); } $x += $yearwidth; } $img->SetColor($this->year->iFrameColor); $img->SetLineWeight($this->year->iFrameWeight); $img->Rectangle($xt,$yt,$xb,$yb); return $yb-$img->top_margin; } return $aYCoord; } // Stroke table title (upper left corner) function StrokeTableHeaders($aYBottom) { $img=$this->iImg; $xt=$img->left_margin; $yt=$img->top_margin; $xb=$xt+$this->iLabelWidth; $yb=$aYBottom+$img->top_margin; $img->SetColor($this->iTableHeaderBackgroundColor); $img->FilledRectangle($xt,$yt,$xb,$yb); $this->tableTitle->Align("center","center"); $this->tableTitle->Stroke($img,$xt+($xb-$xt)/2+1,$yt+($yb-$yt)/2); $img->SetColor($this->iTableHeaderFrameColor); $img->SetLineWeight($this->iTableHeaderFrameWeight); $img->Rectangle($xt,$yt,$xb,$yb); // Draw the vertical dividing line $this->divider->Stroke($img,$xb,$yt,$xb,$img->height-$img->bottom_margin); // Draw the horizontal dividing line $this->dividerh->Stroke($img,$xt,$yb,$img->width-$img->right_margin,$yb); } // Main entry point to stroke scale function Stroke() { if( !$this->IsRangeSet() ) JpGraphError::Raise("JpGraph Error: Gantt scale has not been specified."); $img=$this->iImg; // Stroke all headers. Aa argument we supply the offset from the // top which depends on any previous headers $offy=$this->StrokeYears(0); $offm=$this->StrokeMonths($offy); $offw=$this->StrokeWeeks($offm); $offd=$this->StrokeDays($offw); // We stroke again in case days also have gridlines that may have // overwritten the weeks gridline (or month/year). It may seem that we should have logic // in the days routine instead but this is much easier and wont make to much // of an performance impact. $this->StrokeWeeks($offm); $this->StrokeMonths($offy); $this->StrokeYears(0); $this->StrokeTableHeaders($offd); // Now we can calculate the correct scaling factor for each vertical position $this->iAvailableHeight = $img->height - $img->top_margin - $img->bottom_margin - $offd; $this->iVertHeaderSize = $offd; if( $this->iVertSpacing == -1 ) $this->iVertSpacing = $this->iAvailableHeight / $this->iVertLines; } } //=================================================== // CLASS GanttPlotObject // The common signature for a Gantt object //=================================================== class GanttPlotObject { var $iVPos=0; // Vertical position var $iLabelLeftMargin=2; // Title margin var $iStart=""; // Start date var $title,$caption; var $iCaptionMargin=5; function GanttPlotObject() { $this->title = new TextProperty(); $this->title->Align("left","center"); $this->caption = new TextProperty(); } function GetMinDate() { return $this->iStart; } function GetMaxDate() { return $this->iStart; } function SetCaptionMargin($aMarg) { $this->iCaptionMargin=$aMarg; } function GetLineNbr() { return 0; } function GetAbsHeight($aImg) { return 0; } function GetLineNbr() { return $this->iVPos; } function SetLabelLeftMargin($aOff) { $this->iLabelLeftMargin=$aOff; } } //=================================================== // CLASS Progress // Holds parameters for the progress indicator // displyed within a bar //=================================================== class Progress { var $iProgress=-1, $iColor="black", $iPattern=GANTT_SOLID; var $iDensity=98, $iHeight=0.65; function Set($aProg) { if( $aProg < 0.0 || $aProg > 1.0 ) JpGraphError::Raise("JpGraph Error: Progress value must in range [0, 1]"); $this->iProgress = $aProg; } function SetPattern($aPattern,$aColor="blue",$aDensity=98) { $this->iPattern = $aPattern; $this->iColor = $aColor; $this->iDensity = $aDensity; } function SetHeight($aHeight) { $this->iHeight = $aHeight; } } //=================================================== // CLASS GanttBar // Responsible for formatting individual gantt bars //=================================================== class GanttBar extends GanttPlotObject { var $iEnd; var $iHeightFactor=0.5; var $iFillColor="white",$iFrameColor="blue"; var $iShadow=false,$iShadowColor="darkgray",$iShadowWidth=1,$iShadowFrame="black"; var $iPattern=GANTT_RDIAG,$iPatternColor="blue",$iPatternDensity=95; var $leftMark,$rightMark; var $progress; //--------------- // CONSTRUCTOR function GanttBar($aPos,$aLabel,$aStart,$aEnd,$aCaption="",$aHeightFactor=0.6) { parent::GanttPlotObject(); $this->iStart = $aStart; // Is the end date given as a date or as number of days added to start date? if( is_string($aEnd) ) $this->iEnd = strtotime($aEnd)+SECPERDAY; elseif(is_int($aEnd) || is_float($aEnd) ) $this->iEnd = strtotime($aStart)+round($aEnd*SECPERDAY); $this->iVPos = $aPos; $this->iHeightFactor = $aHeightFactor; $this->title->Set($aLabel); $this->caption = new TextProperty($aCaption); $this->caption->Align("left","center"); $this->leftMark =new PlotMark(); $this->leftMark->Hide(); $this->rightMark=new PlotMark(); $this->rightMark->Hide(); $this->progress = new Progress(); } //--------------- // PUBLIC METHODS function SetShadow($aShadow=true,$aColor="gray") { $this->iShadow=$aShadow; $this->iShadowColor=$aColor; } function GetMaxDate() { return $this->iEnd; } function SetHeight($aHeight) { $this->iHeightFactor = $aHeight; } function SetColor($aColor) { $this->iFrameColor = $aColor; } function SetFillColor($aColor) { $this->iFillColor = $aColor; } function GetAbsHeight($aImg) { if( is_int($this->iHeightFactor) || $this->leftMark->show || $this->rightMark->show ) { $m=-1; if( is_int($this->iHeightFactor) ) $m = $this->iHeightFactor; if( $this->leftMark->show ) $m = max($m,$this->leftMark->width*2); if( $this->rightMark->show ) $m = max($m,$this->rightMark->width*2); return $m; } else return -1; } function SetPattern($aPattern,$aColor="blue",$aDensity=95) { $this->iPattern = $aPattern; $this->iPatternColor = $aColor; $this->iPatternDensity = $aDensity; } function Stroke($aImg,$aScale) { $factory = new RectPatternFactory(); $prect = $factory->Create($this->iPattern,$this->iPatternColor); $prect->SetDensity($this->iPatternDensity); // If height factor is specified as a float between 0,1 then we take it as meaning // percetage of the scale width between horizontal line. // If it is an integer > 1 we take it to mean the absolute height in pixels if( $this->iHeightFactor > -0.0 && $this->iHeightFactor <= 1.1) $vs = $aScale->GetVertSpacing()*$this->iHeightFactor; elseif(is_int($this->iHeightFactor) && $this->iHeightFactor>2 && $this->iHeightFactor<200) $vs = $this->iHeightFactor; else JpGraphError::Raise("JpGraph Error:Specified height (".$this->iHeightFactor.") for gantt bar is out of range."); $xt = $aScale->TranslateDate($aScale->NormalizeDate($this->iStart)); $xb = $aScale->TranslateDate($aScale->NormalizeDate($this->iEnd)); $yt = $aScale->TranslateVertPos($this->iVPos)-$vs-($aScale->GetVertSpacing()/2-$vs/2); $yb = $aScale->TranslateVertPos($this->iVPos)-($aScale->GetVertSpacing()/2-$vs/2); $prect->ShowFrame(false); $prect->SetBackground($this->iFillColor); if( $this->iShadow ) { $aImg->SetColor($this->iFrameColor); $aImg->ShadowRectangle($xt,$yt,$xb,$yb,$this->iFillColor,$this->iShadowWidth,$this->iShadowColor); $prect->SetPos(new Rectangle($xt+1,$yt+1,$xb-$xt-$this->iShadowWidth-2,$yb-$yt-$this->iShadowWidth-2)); $prect->Stroke($aImg); } else { $prect->SetPos(new Rectangle($xt,$yt,$xb-$xt+1,$yb-$yt+1)); $prect->Stroke($aImg); $aImg->SetColor($this->iFrameColor); $aImg->Rectangle($xt,$yt,$xb,$yb); } if( $this->progress->iProgress > 0 ) { $prog = $factory->Create($this->progress->iPattern,$this->progress->iColor); $prog->SetDensity($this->progress->iDensity); $barheight = ($yb-$yt+1); if( $this->iShadow ) $barheight -= $this->iShadowWidth; $progressheight = floor($barheight*$this->progress->iHeight); $marg = ceil(($barheight-$progressheight)/2); $pos = new Rectangle($xt, $yt + $marg, ($xb-$xt+1)*$this->progress->iProgress, $barheight-2*$marg); $prog->SetPos($pos); $prog->Stroke($aImg); } $middle = round($yt+($yb-$yt)/2); $this->title->Stroke($aImg,$aImg->left_margin+$this->iLabelLeftMargin,$middle); $this->leftMark->Stroke($aImg,$xt,$middle); $this->rightMark->Stroke($aImg,$xb,$middle); $margin = $this->iCaptionMargin; if( $this->rightMark->show ) $margin += $this->rightMark->GetWidth(); $this->caption->Stroke($aImg,$xb+$margin,$middle); } } //=================================================== // CLASS MileStone // Responsible for formatting individual milestones //=================================================== class MileStone extends GanttPlotObject { var $mark; //--------------- // CONSTRUCTOR function MileStone($aVPos,$aLabel,$aDate,$aCaption="") { GanttPlotObject::GanttPlotObject(); $this->caption->Set($aCaption); $this->caption->Align("left","center"); $this->caption->SetFont(FF_FONT1,FS_BOLD); $this->title->Set($aLabel); $this->title->SetColor("darkred"); $this->mark = new PlotMark(); $this->mark->SetWidth(10); $this->mark->SetType(MARK_DIAMOND); $this->mark->SetColor("darkred"); $this->mark->SetFillColor("darkred"); $this->iVPos = $aVPos; $this->iStart = $aDate; } //--------------- // PUBLIC METHODS function GetAbsHeight($aImg) { return max($this->title->GetHeight($aImg),$this->mark->GetWidth()); } function Stroke($aImg,$aScale) { // Put the mark in the middle at the middle of the day $x = $aScale->TranslateDate($aScale->NormalizeDate($this->iStart)+SECPERDAY/2); $y = $aScale->TranslateVertPos($this->iVPos)-($aScale->GetVertSpacing()/2); $this->mark->Stroke($aImg,$x,$y); $this->caption->Stroke($aImg,$x+$this->mark->width/2+$this->iCaptionMargin,$y); $x=$aImg->left_margin+$this->iLabelLeftMargin; $this->title->Stroke($aImg,$x,$y); } } //=================================================== // CLASS GanttVLine // Responsible for formatting individual milestones //=================================================== class GanttVLine extends GanttPlotObject { var $iLine,$title_margin=3; var $iDayOffset=0; // Defult to left edge of day //--------------- // CONSTRUCTOR function GanttVLine($aDate,$aTitle="",$aColor="black",$aWeight=3,$aStyle="dashed") { GanttPlotObject::GanttPlotObject(); $this->iLine = new LineProperty(); $this->iLine->SetColor($aColor); $this->iLine->SetWeight($aWeight); $this->iLine->SetStyle($aStyle); $this->iStart = $aDate; $this->title->Set($aTitle); } //--------------- // PUBLIC METHODS function SetDayOffset($aOff=0.5) { if( $aOff < 0.0 || $aOff > 1.0 ) JpGraphError::Raise("JpGraph Error: Offset for vertical line must be in range [0,1]"); $this->iDayOffset = $aOff; } function SetTitleMargin($aMarg) { $this->title_margin = $aMarg; } function Stroke($aImg,$aScale) { $x = $aScale->TranslateDate($aScale->NormalizeDate($this->iStart)+$this->iDayOffset*SECPERDAY); $y1 = $aScale->iVertHeaderSize+$aImg->top_margin; $y2 = $aImg->height - $aImg->bottom_margin; $this->iLine->Stroke($aImg,$x,$y1,$x,$y2); $this->title->Align("center","top"); $this->title->Stroke($aImg,$x,$y2+$this->title_margin); } } // ?> jpgraph-1.5.2/src/jpgraph_canvas.php0100644000076400001440000000271007437547531016170 0ustar ljpusersGraph($aWidth,$aHeight,$aCachedName,$timeout,$inline); } //--------------- // PUBLIC METHODS // Method description function Stroke($aStrokeFileName="") { if( $this->texts != null ) { for($i=0; $itexts); ++$i) { $this->texts[$i]->Stroke($this->img); } } // Stream the generated picture $this->cache->PutAndStream($this->img,$this->cache_name,$this->inline,$aStrokeFileName); } } // Class /* EOF */ ?>jpgraph-1.5.2/src/Examples/0040755000076400001440000000000007437547737014262 5ustar ljpusersjpgraph-1.5.2/src/Examples/linegraceex.php0100644000076400001440000000122407437547531017245 0ustar ljpusersimg->SetMargin(40,40,40,40); $graph->img->SetAntiAliasing(); $graph->SetScale("textlin"); $graph->SetShadow(); $graph->title->Set("Example of 10% top/bottom grace"); $graph->title->SetFont(FF_FONT1,FS_BOLD); // Add 10% grace to top and bottom of plot $graph->yscale->SetGrace(10,10); $p1 = new LinePlot($datay); $p1->mark->SetType(MARK_FILLEDCIRCLE); $p1->mark->SetFillColor("red"); $p1->mark->SetWidth(4); $p1->SetColor("blue"); $p1->SetCenter(); $graph->Add($p1); $graph->Stroke(); ?> jpgraph-1.5.2/src/Examples/filledline01.php0100754000076400001440000000104407437547531017231 0ustar ljpusersimg->SetMargin(40,40,40,40); $graph->SetScale("textlin"); $graph->SetShadow(); $graph->title->Set("Example of filled line plot"); $graph->title->SetFont(FF_FONT1,FS_BOLD); $p1 = new LinePlot($datay); $p1->SetFillColor("orange"); $p1->mark->SetType(MARK_FILLEDCIRCLE); $p1->mark->SetFillColor("red"); $p1->mark->SetWidth(4); $graph->Add($p1); $graph->Stroke(); ?> jpgraph-1.5.2/src/Examples/pie_csimex1.php0100754000076400001440000000147207437547531017174 0ustar ljpusersSetShadow(); // Set A title for the plot $graph->title->Set("Client side image map"); $graph->title->SetFont(FF_FONT1,FS_BOLD); // Create $p1 = new PiePlot($data); $p1->SetLegends(array("Jan","Feb","Mar","Apr","May","Jun","Jul")); $targ=array("pie_csimex1.php#1","pie_csimex1.php#2","pie_csimex1.php#3", "pie_csimex1.php#4","pie_csimex1.php#5","pie_csimex1.php#6"); $alts=array("val=%v","val=%v","val=%v","val=%v","val=%v","val=%v"); $p1->SetCSIMTargets($targ,$alts); $graph->Add($p1); $graph->Stroke(GenImgName()); echo $graph->GetHTMLImageMap("myimagemap"); echo ""; ?> jpgraph-1.5.2/src/Examples/pie_csimex1.png0100644000076400001440000000342507437547531017167 0ustar ljpusers‰PNG  IHDR,È ñÁfPLTEÿÿÿffffͪîÅ‘zÅÍfÍE‹ëëë–Î}äµIDATxœíœËrã*†Å©™=dìÄë¼Á”Ÿ Uy,òÞx¶ãÕY{çÇ>\t‰ºÕXª:ü±+eÙ/ý7aD§ö'ÙuyîL £†…ÑËû{Ã*Ët)*ú†~ é¿z–ÐL"ÀòjßKé!Ã#W> ±lÍBÿVQI¡—þåJaÏæ•ʆWÉá Òëþ® –™©UõÑ2¯¼ƒî£ÂV¯¼ƒÊüÓGj`é:',û«ÇR>–~z• UM,é2MMï ÑŒõàýØqb©¹‰6Éã&ºWÃ?àaqç–°¶Hg†ƒS^ Àe·sO¸O»Þļª÷ò6’vÕ©9Æ>°HjX5,ŒF £†…ÑvXž«y –q¬GTOÀr£fÂzy¯%:K$ãåo†¥«¶ãÒ½aé‘© ðæ†Ñ2 øÍ±@mpÚ$åE¢%þ:k¬ÓS£eg ·ÃJ*ÄR§ûýT+8{`±šêÎ¥»ó³ÓïB²Y´ÔýÁ¥~=ý^\²æ°4?–Pç¹ò\ÖÝ`±GK„¡¸r¥zÑRúÁ­”q2S¬ob…îti`WÝ^¤ÊqÕ<'F’½”«&W#×6X"M•ì'êa‰L°’\õRþð‘Å:ƒ…k¬Ã§–îN•î¸\¯Å%> °Àôò°,–.5ï"®‹o`#t™+Âå›hOÕL[(=\A´îl¬", \!–yp` [f‰‹@'±Àb1ÑQ…+nc•”Ÿ¬¨cw:b•¸ W•^~ðîbs⬲pÅ\¬uØ=ÕÅ Xž‡äpñ¥ü8ËqàÁ:~k†þ‚e׊HÃ"ºèaKHý)9ÌTRÃåaéKWZ//-VGÇZ†+Ä"lÜ‚Ÿ¨‡DÃÜ2RnÉñëˆY°Ê•Ʋ2–ˆc‘F]3¬Ñê[âÜC,;cƒÇ²«g—X',ž^~é!iHÏ=°!bÍ]ä>'.=$]˜=« \›`ág#ö‹ÅšòQ,¼‹ëõªuzøã2V¬!… Æ:1|ÅeN>÷µ—¯V‹a=!ÖiíŒM<µJÂbÙéš•ÓnV>\©híëT +ëb «Ï¬ XÙpAX¿ç"bA ‘‚5õò5±r..°ω ¬\¸Âþô•qq+¬L¸XŒ›$V:\ ¬·µVÍØTÅ"ÏØbeîh…°ÜŒÍªo1`¬¥¾mEn ¬µ«F Q RúùëFÂêglر,Ó÷ ,7;ŠeÌëõz!c©~Άëc”Ãú“J®¤‰÷Ÿ‰“öðJ´æCÄ̱®)¬·9VÐËßÕš~ëÇ!(çáõšÊùš;:U‹@mµ4oòðšjŠU±"æyX©œ¯ŠR1Xñó&ë+‰•jгzþy‹†%R&s~ŸX·¿›`YMñ–/{Ô±Þòe¯ÀúyLy˜hŠ˜js§i,¸)VÆzˆ× Ö<ã¹±€ä° ¦ˆÉx>¬ÁC0ç1OÁŠç| U eyFkðlŠÕ±¢9?b9ÊxV,¹FA,T¬XryXñ¦ˆÊxÚÒŸÖä!ó¸JHX‘äÊaáR‹†µL.ÏÃxSÄ¥qýÖÂÅ,.µˆX =ãMYqµ[+Ò‘±æ]„ïa é!uÉb+Ò±UP×&<Œä<ÖCò*Ý# ]yM3ìá²)¢ƒE_˜~L`Ís_ë ôp…<ñ¬Â ¬YSô=ïþfÂò\œ{8ÏyW¾[‰)›¿Wcë)K±úïTÜ’GàÞï5X¢ ¶w8B†Mq²Pz+j±Tlï ʰÆÒ…[ŽÉe,¶wP€‡ASô‚å­¨eÄêD7ÛÞáa]¢ÁòWk³b͸<ô°¦ï¥w…–ØcyWÖØ½.ËÜ3_ì"ÚÄp{õpÌù­KÄ¥¼Ùmo¾½Ã1…E¦Z}_µ8F<ì›"jýíÞBŰ.ë¨8îÙqi¬âý**aujé㟷uÛÃòì±àºimg->SetMargin(40,180,40,40); $graph->SetBackgroundImage("tiger_bkg.png",1); // Adjust brightness and contrast for background image // must be between -1 <= x <= 1, (0,0)=original image $graph->AdjBackgroundImage(0,0); $graph->img->SetAntiAliasing("white"); $graph->SetScale("textlin"); $graph->SetShadow(); $graph->title->Set("Background image"); // Use built in font $graph->title->SetFont(FF_FONT1,FS_BOLD); // Slightly adjust the legend from it's default position in the // top right corner. $graph->legend->Pos(0.05,0.5,"right","center"); // Create the first line $p1 = new LinePlot($datay); $p1->mark->SetType(MARK_FILLEDCIRCLE); $p1->mark->SetFillColor("red"); $p1->mark->SetWidth(4); $p1->SetColor("blue"); $p1->SetCenter(); $p1->SetLegend("Triumph Tiger -98"); $graph->Add($p1); // ... and the second $p2 = new LinePlot($data2y); $p2->mark->SetType(MARK_STAR); $p2->mark->SetFillColor("red"); $p2->mark->SetWidth(4); $p2->SetColor("red"); $p2->SetCenter(); $p2->SetLegend("New tiger -99"); $graph->Add($p2); // Output line $graph->Stroke(); ?> jpgraph-1.5.2/src/Examples/backgroundex02.php0100754000076400001440000000220207437547531017574 0ustar ljpusersimg->SetMargin(40,180,40,40); $graph->SetBackgroundImage("tiger_bkg.png",2); $graph->img->SetAntiAliasing("white"); $graph->SetScale("textlin"); $graph->SetShadow(); $graph->title->Set("Background image"); // Use built in font $graph->title->SetFont(FF_FONT1,FS_BOLD); // Slightly adjust the legend from it's default position in the // top right corner. $graph->legend->Pos(0.05,0.5,"right","center"); // Create the first line $p1 = new LinePlot($datay); $p1->mark->SetType(MARK_FILLEDCIRCLE); $p1->mark->SetFillColor("red"); $p1->mark->SetWidth(4); $p1->SetColor("blue"); $p1->SetCenter(); $p1->SetLegend("Triumph Tiger -98"); $graph->Add($p1); // ... and the second $p2 = new LinePlot($data2y); $p2->mark->SetType(MARK_STAR); $p2->mark->SetFillColor("red"); $p2->mark->SetWidth(4); $p2->SetColor("red"); $p2->SetCenter(); $p2->SetLegend("New tiger -99"); $graph->Add($p2); // Output line $graph->Stroke(); ?> jpgraph-1.5.2/src/Examples/backgroundex03.php0100754000076400001440000000220207437547531017575 0ustar ljpusersimg->SetMargin(40,180,40,40); $graph->SetBackgroundImage("tiger_bkg.png",3); $graph->img->SetAntiAliasing("white"); $graph->SetScale("textlin"); $graph->SetShadow(); $graph->title->Set("Background image"); // Use built in font $graph->title->SetFont(FF_FONT1,FS_BOLD); // Slightly adjust the legend from it's default position in the // top right corner. $graph->legend->Pos(0.05,0.5,"right","center"); // Create the first line $p1 = new LinePlot($datay); $p1->mark->SetType(MARK_FILLEDCIRCLE); $p1->mark->SetFillColor("red"); $p1->mark->SetWidth(4); $p1->SetColor("blue"); $p1->SetCenter(); $p1->SetLegend("Triumph Tiger -98"); $graph->Add($p1); // ... and the second $p2 = new LinePlot($data2y); $p2->mark->SetType(MARK_STAR); $p2->mark->SetFillColor("red"); $p2->mark->SetWidth(4); $p2->SetColor("red"); $p2->SetCenter(); $p2->SetLegend("New tiger -99"); $graph->Add($p2); // Output line $graph->Stroke(); ?> jpgraph-1.5.2/src/Examples/negbarvalueex01.php0100644000076400001440000000154507437547531017756 0ustar ljpusersimg->SetMargin(60,30,40,40); $graph->SetScale("textlin"); $graph->SetShadow(); // Create a bar pot $bplot = new BarPlot($datay); $bplot->SetFillColor("orange"); // DIsplay value at top of each bar $bplot->ShowValue(true); $bplot->SetShadow(); $graph->Add($bplot); // Position the scale at the min of the other axis $graph->xaxis->SetPos("min"); // Add 10% more space at top and bottom of graph $graph->yscale->SetGrace(10,10); $graph->xaxis->title->Set("X-title"); $graph->yaxis->title->Set("Y-title"); $graph->title->SetFont(FF_VERDANA,FS_NORMAL,12); $graph->title->Set("Example of bar plot with absolute labels"); $graph->yaxis->title->SetFont(FF_ARIAL,FS_NORMAL,16); $graph->Stroke(); ?> jpgraph-1.5.2/src/Examples/staticlinebarex1.php0100644000076400001440000000260407437547531020224 0ustar ljpusersimg->SetMargin(60,30,50,40); $graph->SetScale("textlin"); $graph->SetShadow(); $graph->title->SetFont(FF_ARIAL,FS_BOLD,15); $graph->title->Set("Cash flow "); $graph->subtitle->Set("(Department X)"); // Show both X and Y grid $graph->xgrid->Show(true,false); // Add 10% grace ("space") at top and botton of Y-scale. $graph->yscale->SetGrace(10,10); // Turn the tick mark out from the plot area $graph->xaxis->SetTickDirection(SIDE_DOWN); $graph->yaxis->SetTickDirection(SIDE_LEFT); // Create a bar pot $bplot = new BarPlot($datay); $bplot->SetFillColor("orange"); $bplot->SetShadow(); // Show the actual value for each bar on top/bottom $bplot->ShowValue(true); $bplot->SetValueFormat("%02d kr"); // Position the X-axis at the bottom of the plotare $graph->xaxis->SetPos("min"); // .. and add the plot to the graph $graph->Add($bplot); // Add mark graph with static lines $graph->AddLine(new PlotLine(HORIZONTAL,0,"black",2)); $graph->AddLine(new PlotLine(VERTICAL,3,"black",2)); //$graph->title->Set("Test of bar gradient fill"); $graph->xaxis->title->Set("X-title"); $graph->yaxis->title->Set("Y-title"); $graph->yaxis->title->SetFont(FF_ARIAL,FS_BOLD,11); $graph->xaxis->title->SetFont(FF_ARIAL,FS_BOLD,11); $graph->Stroke(); ?> jpgraph-1.5.2/src/Examples/testsuit_jpgraph.php0100754000076400001440000000444407437547531020367 0ustar ljpusersread()) { if( !strstr($entry,".phps") && strstr($entry,".php") && strstr($entry,"x") && !strstr($entry,"show")) $a[] = $entry; } $d->Close(); if( empty($a) ) die("JpGraph Tetsuit Error: Apache/PHP does not have enough permission to read". "the testfiles in directory: $dp"); return $a; } $tf=GetArrayOfTestGraphs(getcwd()); sort($tf); echo "

Visual test suit for JpGraph

"; echo "Number of tests: ".count($tf)."

"; echo "

    "; for($i=0; $i'.$exname.''; if( isset($showdate) ) echo '['.date("Y-m-d H:i",filemtime($tf[$i])).']'; echo "\n"; break; case 2: echo '

  1. Filename: '.$exname.'
     '; if( isset($showdate) ) echo ' ['.date('Y-m-d H:i',filemtime($tf[$i])).']'; echo "\n"; break; } } echo "
"; echo "

Test suit done."; /* EOF */ ?>jpgraph-1.5.2/src/Examples/show-image.php0100644000076400001440000000050607437547531017021 0ustar ljpusers Image <?php echo basename($target); ?> <?php echo basename($target); ?> jpgraph-1.5.2/src/Examples/ganttex30.php0100644000076400001440000000531007437547531016574 0ustar ljpusersSetShadow(); $graph->SetBox(); // Titles for chart $graph->title->Set("General conversion plan"); $graph->subtitle->Set("(Revision: 2001-11-18)"); $graph->title->SetFont(FF_ARIAL,FS_BOLD,12); // For illustration we enable all headers. $graph->ShowHeaders(GANTT_HYEAR | GANTT_HMONTH | GANTT_HDAY | GANTT_HWEEK); // For the week we choose to show the start date of the week // the default is to show week number (according to ISO 8601) $graph->scale->week->SetStyle(WEEKSTYLE_FIRSTDAY); // Change the scale font $graph->scale->week->SetFont(FF_FONT0); $graph->scale->year->SetFont(FF_ARIAL,FS_BOLD,12); // Setup some data for the gantt bars $data = array( array(0,"Group 1", "2001-10-29","2001-11-27",FF_FONT1,FS_BOLD,8), array(1," Label 2", "2001-11-8","2001-12-14"), array(2," Label 3", "2001-11-01","2001-11-8"), array(4,"Group 2", "2001-11-07","2001-12-19",FF_FONT1,FS_BOLD,8), array(5," Label 4", "2001-11-8","2001-12-19"), array(6," Label 5", "2001-11-01","2001-11-8") ); for($i=0; $i4 ) $bar->title->SetFont($data[$i][4],$data[$i][5],$data[$i][6]); // If you like each bar can have a shadow // $bar->SetShadow(true,"darkgray"); // For illustration lets make each bar be red with yellow diagonal stripes $bar->SetPattern(BAND_RDIAG,"yellow"); $bar->SetFillColor("red"); // To indicate progress each bar can have a smaller bar within // For illustrative purpose just set the progress to 50% for each bar $bar->progress->Set(0.5); // Each bar may also have optional left and right plot marks // As illustration lets put a filled circle with a number at the end // of each bar $bar->rightMark->SetType(MARK_FILLEDCIRCLE); $bar->rightMark->SetFillColor("red"); $bar->rightMark->SetColor("red"); $bar->rightMark->SetWidth(8); // Title for the mark $bar->rightMark->title->Set("".$i+1); $bar->rightMark->title->SetColor("white"); $bar->rightMark->title->SetFont(FF_ARIAL,FS_BOLD,10); $bar->rightMark->Show(); // ... and add the bar to the gantt chart $graph->Add($bar); } // Create a milestone mark $ms = new MileStone(7,"M5","2001-12-10","10/12"); $ms->title->SetFont(FF_FONT1,FS_BOLD); $graph->Add($ms); // Create a vertical line to emphasize the milestone $vl = new GanttVLine("2001-12-10","Phase 1","darkred"); $vl->SetDayOffset(0.5); // Center the line in the day $graph->Add($vl); // Output the graph $graph->Stroke(); // EOF ?>jpgraph-1.5.2/src/Examples/example1.1.php0100754000076400001440000000110207437547531016627 0ustar ljpusersSetScale("textlin"); $graph->img->SetMargin(30,90,40,50); $graph->xaxis->SetFont(FF_FONT1,FS_BOLD); $graph->title->Set("Example 1.1 same y-values"); // Create the linear plot $lineplot=new LinePlot($ydata); $lineplot->SetLegend("Test 1"); $lineplot->SetColor("blue"); $lineplot->SetWeight(5); // Add the plot to the graph $graph->Add($lineplot); // Display the graph $graph->Stroke(); ?> jpgraph-1.5.2/src/Examples/example1.2.php0100644000076400001440000000134207437547531016634 0ustar ljpusersSetScale("textlin"); $graph->img->SetMargin(30,90,40,50); $graph->xaxis->SetFont(FF_FONT1,FS_BOLD); $graph->title->Set("Dashed lineplot"); // Create the linear plot $lineplot=new LinePlot($ydata); $lineplot->SetLegend("Test 1"); $lineplot->SetColor("blue"); // Style can also be specified as SetStyle([1|2|3|4]) or // SetStyle("solid"|"dotted"|"dashed"|"lobgdashed") $lineplot->SetStyle("dashed"); // Add the plot to the graph $graph->Add($lineplot); // Display the graph $graph->Stroke(); ?> jpgraph-1.5.2/src/Examples/linegrace.php0100754000076400001440000000113607437547531016714 0ustar ljpusersimg->SetMargin(40,40,40,40); $graph->img->SetAntiAliasing(); $graph->SetScale("textlin"); $graph->SetShadow(); $graph->title->Set("Example of 10% grace in line plot"); $graph->title->SetFont(FF_FONT1,FS_BOLD); $graph->yscale->SetGrace(10); $p1 = new LinePlot($datay); $p1->mark->SetType(MARK_FILLEDCIRCLE); $p1->mark->SetFillColor("red"); $p1->mark->SetWidth(4); $p1->SetColor("blue"); $p1->SetCenter(); $graph->Add($p1); $graph->Stroke(); ?> jpgraph-1.5.2/src/Examples/spiderlogex1.php0100754000076400001440000000254707437547531017400 0ustar ljpusersimg->SetAntiAliasing(); // Make the spider graph fill out it's bounding box $graph->SetPlotSize(0.85); // Use logarithmic scale (If you don't use any SetScale() // the spider graph will default to linear scale $graph->SetScale("log"); // Uncomment the following line if you want to supress // minor tick marks //$graph->yscale->ticks->SupressMinorTickMarks(); // We want the major tick marks to be black and minor // slightly less noticable $graph->yscale->ticks->SetMarkColor("black","darkgray"); // Set the axis title font $graph->axis->title->SetFont(FF_ARIAL,FS_BOLD,12); // Use blue axis $graph->axis->SetColor("blue"); $plot = new SpiderPlot($data); $plot->SetLineWeight(1); $plot->SetColor('forestgreen'); $plot2 = new SpiderPlot($data2); $plot2->SetLineWeight(2); $plot2->SetColor('red'); // Add the plot and display the graph $graph->Add($plot); $graph->Add($plot2); $graph->Stroke(); ?> jpgraph-1.5.2/src/Examples/spiderlogex2.php0100644000076400001440000000231707437547531017372 0ustar ljpusersimg->SetAntiAliasing(); // Make the spider graph fill out it's bounding box $graph->SetPlotSize(0.85); // Use logarithmic scale (If you don't use any SetScale() // the spider graph will default to linear scale $graph->SetScale("log"); // Uncomment the following line if you want to supress // minor tick marks // $graph->yscale->ticks->SupressMinorTickMarks(); // We want the major tick marks to be black and minor // slightly less noticable $graph->yscale->ticks->SetMarkColor("black","darkgray"); // Set the axis title font $graph->axis->title->SetFont(FF_ARIAL,FS_BOLD,12); // Use blue axis $graph->axis->SetColor("blue"); $plot = new SpiderPlot($data); $plot->SetLineWeight(2); $plot->SetColor('forestgreen'); // Add the plot and display the graph $graph->Add($plot); $graph->Stroke(); ?> jpgraph-1.5.2/src/Examples/bar_csimex1.php0100644000076400001440000000305507437547531017160 0ustar ljpusersSetScale("textlin"); $graph->img->SetMargin(60,30,20,40); $graph->yaxis->SetTitleMargin(45); $graph->yaxis->scale->SetGrace(30); $graph->SetShadow(); // Turn the tickmarks $graph->xaxis->SetTickDirection(SIDE_DOWN); $graph->yaxis->SetTickDirection(SIDE_LEFT); // Create a bar pot $bplot = new BarPlot($datay); // Create targets for the image maps. One for each column $targ=array("bar_clsmex1.php#1","bar_clsmex1.php#2","bar_clsmex1.php#3","bar_clsmex1.php#4","bar_clsmex1.php#5","bar_clsmex1.php#6"); $alts=array("val=%d","val=%d","val=%d","val=%d","val=%d","val=%d"); $bplot->SetCSIMTargets($targ,$alts); $bplot->SetFillColor("orange"); // Use a shadow on the bar graphs (just use the default settings) $bplot->SetShadow(); $bplot->SetValueFormat(" $ %2.1f",70); $bplot->SetValueFont(FF_ARIAL,FS_NORMAL,9); $bplot->SetValueColor("blue"); $bplot->ShowValue(); $graph->Add($bplot); $graph->title->Set("Image maps barex1"); $graph->xaxis->title->Set("X-title"); $graph->yaxis->title->Set("Y-title"); $graph->title->SetFont(FF_FONT1,FS_BOLD); $graph->yaxis->title->SetFont(FF_FONT1,FS_BOLD); $graph->xaxis->title->SetFont(FF_FONT1,FS_BOLD); // Write the image to a file. $graph->Stroke("auto"); echo $graph->GetHTMLImageMap("myimagemap"); echo ""; ?> jpgraph-1.5.2/src/Examples/bar_csimex1.png0100644000076400001440000000432407437547531017155 0ustar ljpusers‰PNG  IHDR6ú?›àvMÛM[€ÍAe=ŽÐvö7`sQÙ¶Uïiõ|~67•M]×íü’ÛÝ µºr>µ1bSïòÝ{b[Š Ûx^Ž"Tß"Ô7¶{VŠý¾‚íVÞÖ­ç£Ø°©×í²·Ã–µZ#Ç…-_ÞÑq/lUóŒ>Šn¹Û-:{²{,=ŽÛ¶‰«Ž2†€$`³«ª…a3°YõÌ´µE»¾dÀv ªÉ²¢®Šz³]>6-!SeÏ«ê÷¾íxlzB:ª^ûmSæ'¤ã«ßûf‹xlzB:¾Jmßâ±é i ’MKHKP زuB:žŠÇž‹'‚í•êµ…Ì·…Âváõ3ë㞺­Ëâ¡w"6®Jñ)]S™&†¡UÕ]ù¨ë~n¥½[Îãm}¬›=S„ MQ4ìºlzÌ([ÙdU›õ³†¶Hêúø§6„Œ²±õAî0<¯›”öiß±uýY¹Ó§„—K8¶!Öm놧->‰ÇÖ«»2 1K2¶âñçf/ Æ6dÚ„rŒm@V”ýeá8™%[5àj†|¾4 Æ6&¤ËJ\ô‘ÉÆ6ªÞþ×(–”®ù=ùØ.™ÅgFj)a»H&j¾Øaõæ´±©yb[.f¾K‰yIÏý„t©·"`› L-ÔòœuYKB:Š"a›Í˜ŠP- é(bÁæòÅ‹¥Ø*Å¿~þû~üüüþý=¶ !3¶ùm'l‹ïs{›%!EÞæ(æJñ½„t±a‹{IeLHGQ$lw[Sü4¶9Ö³cÓ›¸ð Ï Øvd¯ÒR †»á±5EVÙ¹›AÏRÃÊz_ ÃTžðm»§Ž3<¶ÁÑʺÙw¸k°å²½í%íîZç>cË£‡»Ñ°Ñûà„íÍØF¹có•XlÆE‹<ûàŒ-â,!´·™-òìƒ6ö È©„ôi™-òìƒ36ÎsÛ¹„ôy-òìƒ6þ ȹ„tIÌ€œKHG‘È È©„t @N$¤£ˆ›ÿu@¨ ésr¬Ò”‹ÚåSr­Ò¶•\«4åa›nÜ£&¤Oɲl€Oذ)×B­ã÷‚žÛ«4#as/ <¾q/ôTÞ¥JS\êñ{þsx5å˜%¸Rs«ÿz>|ýý&ViGÑùJqÇ™•Züؼí%Ë{w w]&¥óÁ›åƽ¶¼_Æ ½Ëûb\ý“'b÷´‰ìÂ×v°q$¤wŹúg¼K¶ cwÒ»â\ýSX„!!½+ÎÕ?…acHHï‹qõOiØÎwÙ¦£Õ?•.Rn†-³¯þi lÇ Û®öãh#µ°ñ$¤Í*›ÃP×§]AؘÒFuuÖû⟉bcJH5¤¡Úªµ­ì“(6¦„´QÏ¥f³¦²®b™(6¦„´YeÝ6µ=ÔMOBz\iø>j»²°e i‹ô¶{ ¶Sñi¨pW>¶\â,Ø‚· l¤vÔî'` 0×ýl!満-Ä\W6®\—¦s]1Ø Ô˜°…˜ëJÁf¢Æ…-À\W6#5>l÷\W 6¾.“lÀlÀæM-͙ګœr§,ØÌpP» l»àl•â>Õß¡*ÅûÛø:–· £¯ð¶¨ØÂÌ>â^Iã_LÔÒÁ6ô6€©¥ƒÍÐDlר°›p[`6`n lÀlÂm Ø€M¸-°I¦õ'°åð6`6`6(€ ØdÚ°›p[`6`n lÀ–.¶è…Z·ÀæWhîq ¶¼ØüŠPwzœ‚mlêö ‚mþÝçïî` l$[ŽKC7R³å@º‘š-G¸û¶ Ø>Q¡°úø÷C‚s¶~†MytÇDî~|>¶^̃`ó;<χ°õîÄåØ<LJ׈öhôÞØÂxæÝ±yöÓ›eúiþƒë/ ý2Ør}âóI{yE‚ÈÝl$IÀF°‘l$[¾™…9Å-Ÿ…MÍãKµ|^¿:hè³°©•5 `Û•Z;Û8 çÇ¥×Ùç#†-RÖAºñK­™ÏÂ6árÀfu·Oöš³x›­Â¦_ŒV¯0HÚ ùjÈæ›ŒK»€$`# ØHš°A~± úù ØH6’€$`#éÕU,Î zªƒIEND®B`‚jpgraph-1.5.2/src/Examples/bar_csimex2.php0100644000076400001440000000302507437547531017156 0ustar ljpusersSetScale("textlin"); $graph->img->SetMargin(40,30,20,40); $graph->SetShadow(); // Create the bar plots $b1plot = new BarPlot($data1y); $b1plot->SetFillColor("orange"); $targ=array("bar_clsmex2.php#1","bar_clsmex2.php#2","bar_clsmex2.php#3", "bar_clsmex2.php#4","bar_clsmex2.php#5","bar_clsmex2.php#6"); $alts=array("val=%d","val=%d","val=%d","val=%d","val=%d","val=%d"); $b1plot->SetCSIMTargets($targ,$alts); $b2plot = new BarPlot($data2y); $b2plot->SetFillColor("blue"); $targ=array("bar_clsmex2.php#7","bar_clsmex2.php#8","bar_clsmex2.php#9", "bar_clsmex2.php#10","bar_clsmex2.php#11","bar_clsmex2.php#12"); $alts=array("val=%v","val=%v","val=%v","val=%v","val=%v","val=%v"); $b2plot->SetCSIMTargets($targ,$alts); // Create the grouped bar plot $abplot = new AccBarPlot(array($b1plot,$b2plot)); $abplot->SetShadow(); $abplot->ShowValue(); // ...and add it to the graPH $graph->Add($abplot); $graph->title->Set("Image map barex2"); $graph->xaxis->title->Set("X-title"); $graph->yaxis->title->Set("Y-title"); $graph->title->SetFont(FF_FONT1,FS_BOLD); $graph->yaxis->title->SetFont(FF_FONT1,FS_BOLD); $graph->xaxis->title->SetFont(FF_FONT1,FS_BOLD); // Display the graph $graph->Stroke(GenImgName()); echo $graph->GetHTMLImageMap("myimagemap"); echo ""; ?> jpgraph-1.5.2/src/Examples/bar_csimex2.png0100644000076400001440000000242407437547531017155 0ustar ljpusers‰PNG  IHDR6È}ÐGPLTEÿÿÿfffÆÆÆÄÄÄÿ¥ÿVû­ïºIDATxœí‹‘Ü @MÒ€ “°0.!iáZHÿ%„?ÈF` Ú‹t³ã1§…g a¬Åö$‰Êh²ùP È¶ ³1³1³1³ `“ó$:±IYV§0…_©f+÷©½ìVÌ&úù´ÂnÌVÁ&³™1D”Æv7¶FÂl̆±ýKMÒe=Øl–]•³ÉljQ5y¤_½<ìÓªü[6Y•S=ØÌ©’¶a6ʱP9†tòé*ÿ%›]uQùH67w'Êféf²l³ êSçTªlóty=±I݇Mx¾6ÿÐÿ›U)dÓK¶œ¼[¼<‚[²X[,e­ Ù²×±0[Ÿf¯ÇŠØPùo,[þ:6e³Ú0›Èœ›ËØò×±%l6ÿ7–-¯—²©‹þ6f»èo¨DîÓl Ì6`;™‡X¬v±PŦã%¤;›©¦ÝRÉÖeì­aÓc¶“XÎG)¶Mâ|2ÿÝeìóHÈG{µN5o7èØïè…ýc·ŽlÏ–‹…ÖlËåT{°I´Ý6éÇê}]6hnB… [ÆlÌÆlÌÆl_‰Íkö`k9iÍ–1³1[O6ìüx[]³1Ûö½eê}Ù]604u=RvÍæß& ®GÊ0lr`Ø(È{±?[ø19C(ÈÙØKAÞš ê}Pôxoð‘ßi™>y¿@–MAm¦E†Ê GâŸ_Ž l¬ i`àXÓÕ)õlðµ€6‚Ê`Ë5cCÚb;ój36°€ ì÷ul`, M‰;ˆZŸ‚À±ƒö@Ž!°Þ›½…Ùê„Ùê„›|€wÏ bÛî’þ³n"Ŷ¾\ei!6ûòŽÅŸM´ô'™<Äd›{c” }¿©f›{ŸOÌ-ÎëÓØn¡ÎèXÐîíP~Cħû½¸Þµë†H,`„Ùê„:Û eV,Û4}{f«f«“» J´íî†wIEND®B`‚jpgraph-1.5.2/src/Examples/nullvalueex01.php0100754000076400001440000000250407437547531017470 0ustar ljpusersimg->SetMargin(40,170,40,80); //$graph->img->SetAntiAliasing(); $graph->SetScale("textlin"); $graph->SetShadow(); $graph->title->Set("Line plot with null values"); // Use built in font $graph->title->SetFont(FF_FONT1,FS_BOLD); // Slightly adjust the legend from it's default position in the // top right corner. $graph->legend->Pos(0.03,0.5,"right","center"); // Setup X-scale $graph->xaxis->SetTickLabels($datax); $graph->xaxis->SetFont(FF_FONT1); $graph->xaxis->SetLabelAngle(90); // Create the first line $p1 = new LinePlot($datay); $p1->mark->SetType(MARK_FILLEDCIRCLE); $p1->mark->SetFillColor("red"); $p1->mark->SetWidth(4); $p1->SetColor("blue"); $p1->SetCenter(); $p1->SetLegend("Undefined variant 1"); $graph->Add($p1); // ... and the second $p2 = new LinePlot($data2y); $p2->mark->SetType(MARK_STAR); $p2->mark->SetFillColor("red"); $p2->mark->SetWidth(4); $p2->SetColor("red"); $p2->SetCenter(); $p2->SetLegend("Undefined variant 2"); $graph->Add($p2); // Output line $graph->Stroke(); ?> jpgraph-1.5.2/src/Examples/spiderex6.1.php0100754000076400001440000000174707437547531017043 0ustar ljpuserslegend->Pos(0.05,0.2); $plot = new SpiderPlot($data); $plot->SetLegend("Defects"); $plot2 = new SpiderPlot($data2); $plot2->SetFill(false); $plot2->SetLineWeight(2); $plot2->SetColor("red"); $plot2->SetLegend("Target"); // Set position and size $graph->SetCenter(0.5,0.55); $graph->SetTitles($axtitles); $graph->title->Set("Result 2001 (no anti-aliasing)"); $graph->title->SetFont(FF_FONT1,FS_BOLD); $graph->SupressTickMarks(); $graph->SetShadow(); //$graph->SetColor("teal"); $graph->grid->SetLineStyle("solid"); $graph->grid->SetColor("green"); $graph->grid->Show(); // Add the plot and display the graph //$graph->Add($plot); $graph->Add($plot2); $graph->Stroke(); ?> jpgraph-1.5.2/src/Examples/example2.1.php0100754000076400001440000000121107437547531016631 0ustar ljpusersSetScale("textlin"); // Create the linear plot $lineplot=new LinePlot($ydata); $lineplot->value->Show(); $lineplot->value->SetColor("red"); $lineplot->value->SetFont(FF_FONT1,FS_BOLD); // Add the plot to the graph $graph->Add($lineplot); $graph->img->SetMargin(40,20,20,40); $graph->title->Set("Example 2.1"); $graph->xaxis->title->Set("X-title"); $graph->yaxis->title->Set("Y-title"); // Display the graph $graph->Stroke(); ?> jpgraph-1.5.2/src/Examples/example2.5.php0100754000076400001440000000112507437547531016641 0ustar ljpusersSetScale("textlin"); // Create the linear plot $lineplot=new LinePlot($ydata); // Add the plot to the graph $graph->Add($lineplot); $graph->img->SetMargin(40,20,20,40); $graph->title->Set("Example 2.5"); $graph->xaxis->title->Set("X-title"); $graph->xaxis->SetPos("min"); $graph->yaxis->title->Set("Y-title"); // Display the graph $graph->Stroke(); ?> jpgraph-1.5.2/src/Examples/example2.6.php0100754000076400001440000000121207437547531016637 0ustar ljpusersSetScale("textlin"); // Create the linear plot $lineplot=new LinePlot($ydata); $lineplot->SetStepStyle(); // Add the plot to the graph $graph->Add($lineplot); $graph->img->SetMargin(40,20,20,40); $graph->title->Set("Example 2.6 (Line with stepstyle)"); $graph->xaxis->title->Set("X-title"); $graph->xaxis->SetPos("min"); $graph->yaxis->title->Set("Y-title"); // Display the graph $graph->Stroke(); ?> jpgraph-1.5.2/src/Examples/example10.php0100754000076400001440000000300007437547531016547 0ustar ljpusersimg->SetMargin(40,110,20,40); $graph->SetScale("textlog"); $graph->SetY2Scale("log"); $graph->SetShadow(); $graph->ygrid->Show(true,true); $graph->xgrid->Show(true,false); // Create the linear plot $lineplot=new LinePlot($ydata); $lineplot2=new LinePlot($y2data); $graph->yaxis->scale->ticks->SupressFirst(); $graph->y2axis->scale->ticks->SupressFirst(); // Add the plot to the graph $graph->Add($lineplot); $graph->AddY2($lineplot2); $lineplot2->SetColor("orange"); $lineplot2->SetWeight(2); $graph->y2axis->SetColor("orange"); $graph->title->Set("Example 10"); $graph->xaxis->title->Set("X-title"); $graph->yaxis->title->Set("Y-title"); $graph->title->SetFont(FF_FONT1,FS_BOLD); $graph->yaxis->title->SetFont(FF_FONT1,FS_BOLD); $graph->xaxis->title->SetFont(FF_FONT1,FS_BOLD); $lineplot->SetColor("blue"); $lineplot->SetWeight(2); $lineplot2->SetColor("orange"); $lineplot2->SetWeight(2); $graph->yaxis->SetColor("blue"); $lineplot->SetLegend("Plot 1"); $lineplot2->SetLegend("Plot 2"); $graph->legend->Pos(0.05,0.5,"right","center"); $graph->xaxis->SetTickLabels($datax); $graph->xaxis->SetTextTickInterval(2); // Display the graph $graph->Stroke(); ?> jpgraph-1.5.2/src/Examples/example13.php0100754000076400001440000000165607437547531016571 0ustar ljpusersimg->SetMargin(40,30,20,40); $graph->SetScale("textlin"); $graph->SetShadow(); // Create the linear plot $errplot=new ErrorPlot($errdatay); $errplot->SetColor("red"); $errplot->SetWeight(2); //$errplot->SetCenter(); // Add the plot to the graph $graph->Add($errplot); $graph->title->Set("Example 13"); $graph->xaxis->title->Set("X-title"); $graph->yaxis->title->Set("Y-title"); $graph->title->SetFont(FF_FONT1,FS_BOLD); $graph->yaxis->title->SetFont(FF_FONT1,FS_BOLD); $graph->xaxis->title->SetFont(FF_FONT1,FS_BOLD); $graph->xaxis->SetTickLabels($datax); //$graph->xaxis->SetTextTickInterval(2); // Display the graph $graph->Stroke(); ?> jpgraph-1.5.2/src/Examples/example14.php0100754000076400001440000000165407437547531016570 0ustar ljpusersimg->SetMargin(40,30,20,40); $graph->SetScale("textlin"); $graph->SetShadow(); // Create the linear plot $errplot=new ErrorPlot($errdatay); $errplot->SetColor("red"); $errplot->SetWeight(2); $errplot->SetCenter(); // Add the plot to the graph $graph->Add($errplot); $graph->title->Set("Example 14"); $graph->xaxis->title->Set("X-title"); $graph->yaxis->title->Set("Y-title"); $graph->title->SetFont(FF_FONT1,FS_BOLD); $graph->yaxis->title->SetFont(FF_FONT1,FS_BOLD); $graph->xaxis->title->SetFont(FF_FONT1,FS_BOLD); $graph->xaxis->SetTickLabels($datax); //$graph->xaxis->SetTextTickInterval(2); // Display the graph $graph->Stroke(); ?> jpgraph-1.5.2/src/Examples/example15.php0100754000076400001440000000175507437547531016573 0ustar ljpusersimg->SetMargin(40,30,20,40); $graph->SetScale("textlin"); $graph->SetShadow(); // Create the linear plot $errplot=new ErrorLinePlot($errdatay); $errplot->SetColor("red"); $errplot->SetWeight(2); $errplot->SetCenter(); $errplot->line->SetWeight(2); $errplot->line->SetColor("blue"); // Add the plot to the graph $graph->Add($errplot); $graph->title->Set("Example 15"); $graph->xaxis->title->Set("X-title"); $graph->yaxis->title->Set("Y-title"); $graph->title->SetFont(FF_FONT1,FS_BOLD); $graph->yaxis->title->SetFont(FF_FONT1,FS_BOLD); $graph->xaxis->title->SetFont(FF_FONT1,FS_BOLD); $graph->xaxis->SetTickLabels($datax); //$graph->xaxis->SetTextTickInterval(2); // Display the graph $graph->Stroke(); ?>jpgraph-1.5.2/src/Examples/example16.php0100754000076400001440000000224007437547531016562 0ustar ljpusersimg->SetMargin(40,30,20,40); $graph->SetScale("textlin"); $graph->SetShadow(); $graph->xaxis->SetLabelAngle(0); $graph->xaxis->SetFont(FF_ARIAL,FS_NORMAL,10); $graph->img->SetAntiAliasing("white"); // Create the linear plot $errplot=new ErrorLinePlot($errdatay); $errplot->SetColor("red"); $errplot->SetWeight(2); $errplot->SetCenter(); $errplot->line->SetWeight(2); $errplot->line->SetColor("blue"); $errplot->SetLegend("Min/Max"); $errplot->line->SetLegend("Average"); // Add the plot to the graph $graph->Add($errplot); $graph->title->Set("Example 16"); $graph->yaxis->title->Set("Y-title"); $graph->yaxis->title->SetFont(FF_FONT1,FS_BOLD); $graph->xaxis->title->Set("X-title"); $graph->title->SetFont(FF_FONT1,FS_BOLD); $graph->xaxis->SetTickLabels($datax); $graph->xaxis->SetTextTickInterval(2); // Display the graph $graph->Stroke(); ?> jpgraph-1.5.2/src/Examples/example17.php0100754000076400001440000000230007437547531016560 0ustar ljpusersimg->SetMargin(40,30,20,40); $graph->SetScale("textlin"); $graph->SetShadow(); // Create the linear plots for each category $dplot[] = new LinePLot($new_datay); $dplot[] = new LinePLot($inprogress_datay); $dplot[] = new LinePLot($fixed_datay); $dplot[0]->SetFillColor("red"); $dplot[1]->SetFillColor("blue"); $dplot[2]->SetFillColor("green"); // Create the accumulated graph $accplot = new AccLinePlot($dplot); // Add the plot to the graph $graph->Add($accplot); $graph->xaxis->SetTextTickInterval(2); $graph->title->Set("Example 17"); $graph->xaxis->title->Set("X-title"); $graph->yaxis->title->Set("Y-title"); $graph->title->SetFont(FF_FONT1,FS_BOLD); $graph->yaxis->title->SetFont(FF_FONT1,FS_BOLD); $graph->xaxis->title->SetFont(FF_FONT1,FS_BOLD); // Display the graph $graph->Stroke(); ?> jpgraph-1.5.2/src/Examples/example18.php0100754000076400001440000000130407437547531016564 0ustar ljpusersimg->SetMargin(40,30,20,40); $graph->SetScale("textlin"); $graph->SetShadow(); // Create a bar pot $bplot = new BarPlot($datay); //$bplot->SetFillColor("orange"); $graph->Add($bplot); $graph->title->Set("Example 18"); $graph->xaxis->title->Set("X-title"); $graph->yaxis->title->Set("Y-title"); $graph->title->SetFont(FF_FONT1,FS_BOLD); $graph->yaxis->title->SetFont(FF_FONT1,FS_BOLD); $graph->xaxis->title->SetFont(FF_FONT1,FS_BOLD); // Display the graph $graph->Stroke(); ?> jpgraph-1.5.2/src/Examples/example19.php0100754000076400001440000000130207437547531016563 0ustar ljpusersimg->SetMargin(40,30,20,40); $graph->SetScale("textlin"); $graph->SetShadow(); // Create a bar pot $bplot = new BarPlot($datay); $bplot->SetFillColor("orange"); $graph->Add($bplot); $graph->title->Set("Example 19"); $graph->xaxis->title->Set("X-title"); $graph->yaxis->title->Set("Y-title"); $graph->title->SetFont(FF_FONT1,FS_BOLD); $graph->yaxis->title->SetFont(FF_FONT1,FS_BOLD); $graph->xaxis->title->SetFont(FF_FONT1,FS_BOLD); // Display the graph $graph->Stroke(); ?> jpgraph-1.5.2/src/Examples/example20.php0100754000076400001440000000133007437547531016554 0ustar ljpusersimg->SetMargin(40,30,20,40); $graph->SetScale("textlin"); $graph->SetShadow(); // Create a bar pot $bplot = new BarPlot($datay); $bplot->SetFillColor("orange"); $bplot->SetWidth(1); $graph->Add($bplot); $graph->title->Set("Example 20"); $graph->xaxis->title->Set("X-title"); $graph->yaxis->title->Set("Y-title"); $graph->title->SetFont(FF_FONT1,FS_BOLD); $graph->yaxis->title->SetFont(FF_FONT1,FS_BOLD); $graph->xaxis->title->SetFont(FF_FONT1,FS_BOLD); // Display the graph $graph->Stroke(); ?> jpgraph-1.5.2/src/Examples/example21.php0100754000076400001440000000157707437547531016572 0ustar ljpusersimg->SetMargin(40,30,20,40); $graph->SetScale("textlin"); $graph->SetShadow(); // Create the bar plots $b1plot = new BarPlot($data1y); $b1plot->SetFillColor("orange"); $b2plot = new BarPlot($data2y); $b2plot->SetFillColor("blue"); // Create the grouped bar plot $gbplot = new GroupBarPlot(array($b1plot,$b2plot)); // ...and add it to the graPH $graph->Add($gbplot); $graph->title->Set("Example 21"); $graph->xaxis->title->Set("X-title"); $graph->yaxis->title->Set("Y-title"); $graph->title->SetFont(FF_FONT1,FS_BOLD); $graph->yaxis->title->SetFont(FF_FONT1,FS_BOLD); $graph->xaxis->title->SetFont(FF_FONT1,FS_BOLD); // Display the graph $graph->Stroke(); ?> jpgraph-1.5.2/src/Examples/example22.php0100754000076400001440000000167407437547531016571 0ustar ljpusersimg->SetMargin(40,30,20,40); $graph->SetScale("textlin"); $graph->SetShadow(); // Create the bar plots $b1plot = new BarPlot($data1y); $b1plot->SetFillColor("orange"); $b2plot = new BarPlot($data2y); $b2plot->SetFillColor("blue"); // Create the grouped bar plot $gbplot = new GroupBarPlot(array($b1plot,$b2plot)); $gbplot->SetWidth(0.9); // ...and add it to the graPH $graph->Add($gbplot); $graph->title->Set("Example 22"); $graph->xaxis->title->Set("X-title"); $graph->yaxis->title->Set("Y-title"); $graph->title->SetFont(FF_FONT1,FS_BOLD); $graph->yaxis->title->SetFont(FF_FONT1,FS_BOLD); $graph->xaxis->title->SetFont(FF_FONT1,FS_BOLD); // Display the graph $graph->Stroke(); ?> jpgraph-1.5.2/src/Examples/example23.php0100754000076400001440000000167407437547531016572 0ustar ljpusersimg->SetMargin(40,30,20,40); $graph->SetScale("textlin"); $graph->SetShadow(); // Create the bar plots $b1plot = new BarPlot($data1y); $b1plot->SetFillColor("orange"); $b2plot = new BarPlot($data2y); $b2plot->SetFillColor("blue"); // Create the grouped bar plot $abplot = new AccBarPlot(array($b1plot,$b2plot)); //$gbplot->SetWidth(0.9); // ...and add it to the graPH $graph->Add($abplot); $graph->title->Set("Example 23"); $graph->xaxis->title->Set("X-title"); $graph->yaxis->title->Set("Y-title"); $graph->title->SetFont(FF_FONT1,FS_BOLD); $graph->yaxis->title->SetFont(FF_FONT1,FS_BOLD); $graph->xaxis->title->SetFont(FF_FONT1,FS_BOLD); // Display the graph $graph->Stroke(); ?> jpgraph-1.5.2/src/Examples/example24.php0100754000076400001440000000251607437547531016567 0ustar ljpusersimg->SetMargin(40,30,20,40); $graph->SetScale("textlin"); $graph->SetShadow(); $graph->SetBox(); $graph->SetTickDensity(TICKD_VERYSPARSE); // Create the bar plots $b1plot = new BarPlot($data1y); $b1plot->SetFillColor("orange"); $b2plot = new BarPlot($data2y); $b2plot->SetFillColor("blue"); $b3plot = new BarPlot($data3y); $b3plot->SetFillColor("green"); $b4plot = new BarPlot($data4y); $b4plot->SetFillColor("red"); // Create the accumulated bar plots $ab1plot = new AccBarPlot(array($b1plot,$b2plot)); $ab2plot = new AccBarPlot(array($b3plot,$b4plot)); // Create the grouped bar plot //$gbplot = new GroupBarPlot(array($ab1plot,$ab2plot)); // ...and add it to the graPH //$graph->Add($gbplot); $graph->Add($b1plot); $graph->title->Set("Example 24"); $graph->xaxis->title->Set("X-title"); $graph->yaxis->title->Set("Y-title"); $graph->title->SetFont(FF_FONT1,FS_BOLD); $graph->yaxis->title->SetFont(FF_FONT1,FS_BOLD); $graph->xaxis->title->SetFont(FF_FONT1,FS_BOLD); // Display the graph $graph->Stroke(); ?> jpgraph-1.5.2/src/Examples/example3.1.php0100754000076400001440000000157407437547531016646 0ustar ljpusersSetScale("textlin"); // Create the linear plot $lineplot=new LinePlot($ydata); $lineplot->mark->SetType(MARK_UTRIANGLE); // Add the plot to the graph $graph->Add($lineplot); $graph->img->SetMargin(40,20,20,40); $graph->title->Set("Example 3.1"); $graph->xaxis->title->Set("X-title"); $graph->yaxis->title->Set("Y-title"); $graph->title->SetFont(FF_FONT1,FS_BOLD); $graph->yaxis->title->SetFont(FF_FONT1,FS_BOLD); $graph->xaxis->title->SetFont(FF_FONT1,FS_BOLD); $lineplot->SetColor("blue"); $lineplot->SetWeight(2); $graph->yaxis->SetColor("red"); $graph->yaxis->SetWeight(2); $graph->SetShadow(); // Display the graph $graph->Stroke(); ?> jpgraph-1.5.2/src/Examples/example3.2.php0100754000076400001440000000157107437547531016644 0ustar ljpusersSetScale("textlin"); // Create the linear plot $lineplot=new LinePlot($ydata); $lineplot->mark->SetType(MARK_CIRCLE); // Add the plot to the graph $graph->Add($lineplot); $graph->img->SetMargin(40,20,20,40); $graph->title->Set("Example 3.2"); $graph->xaxis->title->Set("X-title"); $graph->yaxis->title->Set("Y-title"); $graph->title->SetFont(FF_FONT1,FS_BOLD); $graph->yaxis->title->SetFont(FF_FONT1,FS_BOLD); $graph->xaxis->title->SetFont(FF_FONT1,FS_BOLD); $lineplot->SetColor("blue"); $lineplot->SetWeight(2); $graph->yaxis->SetColor("red"); $graph->yaxis->SetWeight(2); $graph->SetShadow(); // Display the graph $graph->Stroke(); ?> jpgraph-1.5.2/src/Examples/centeredlineex01.php0100644000076400001440000000145207437547531020121 0ustar ljpusersimg->SetMargin(40,40,40,40); $graph->img->SetAntiAliasing(); $graph->SetScale("textlin"); $graph->SetShadow(); $graph->title->Set("Example of line centered plot"); $graph->title->SetFont(FF_FONT1,FS_BOLD); // Use 20% "grace" to get slightly larger scale then min/max of // data $graph->yscale->SetGrace(20); $p1 = new LinePlot($datay); $p1->mark->SetType(MARK_FILLEDCIRCLE); $p1->mark->SetFillColor("red"); $p1->mark->SetWidth(4); $p1->SetColor("blue"); $p1->SetCenter(); $graph->Add($p1); $graph->Stroke(); ?> jpgraph-1.5.2/src/Examples/centeredlineex02.php0100644000076400001440000000133707437547531020124 0ustar ljpusersimg->SetMargin(40,40,40,40); $graph->img->SetAntiAliasing(); $graph->SetScale("textlin"); $graph->SetShadow(); $graph->title->Set("Example of filled line centered plot"); $graph->title->SetFont(FF_FONT1,FS_BOLD); $p1 = new LinePlot($datay); $p1->SetFillColor("green"); $p1->mark->SetType(MARK_FILLEDCIRCLE); $p1->mark->SetFillColor("red"); $p1->mark->SetWidth(4); $p1->SetColor("blue"); $p1->SetCenter(); $graph->Add($p1); $graph->Stroke(); ?> jpgraph-1.5.2/src/Examples/centeredlineex03.php0100644000076400001440000000150507437547531020122 0ustar ljpusersimg->SetMargin(40,40,40,80); $graph->img->SetAntiAliasing(); $graph->SetScale("textlin"); $graph->SetShadow(); $graph->title->Set("Example slanted X-labels"); $graph->title->SetFont(FF_VERDANA,FS_NORMAL,18); $graph->xaxis->SetFont(FF_ARIAL,FS_NORMAL,11); $graph->xaxis->SetTickLabels($labels); $graph->xaxis->SetLabelAngle(45); $p1 = new LinePlot($datay); $p1->mark->SetType(MARK_FILLEDCIRCLE); $p1->mark->SetFillColor("red"); $p1->mark->SetWidth(4); $p1->SetColor("blue"); $p1->SetCenter(); $graph->Add($p1); $graph->Stroke(); ?> jpgraph-1.5.2/src/Examples/bargradex1.php0100754000076400001440000000232407437547531017003 0ustar ljpusersimg->SetMargin(60,20,30,50); $graph->SetScale("textlin"); $graph->SetMarginColor("silver"); $graph->SetShadow(); // Set up the title for the graph $graph->title->Set("Example bar gradient fill"); $graph->title->SetFont(FF_VERDANA,FS_NORMAL,18); $graph->title->SetColor("darkred"); // Setup font for axis $graph->xaxis->SetFont(FF_VERDANA,FS_NORMAL,12); $graph->yaxis->SetFont(FF_VERDANA,FS_NORMAL,11); // Show 0 label on Y-axis (default is not to show) $graph->yscale->ticks->SupressZeroLabel(false); // Setup X-axis labels $graph->xaxis->SetTickLabels($datax); $graph->xaxis->SetLabelAngle(50); // Create the bar pot $bplot = new BarPlot($datay); $bplot->SetWidth(0.6); // Setup color for gradient fill style $bplot->SetFillGradient("navy","lightsteelblue",GRAD_MIDVER); // Set color for the frame of each bar $bplot->SetColor("navy"); $graph->Add($bplot); // Finally send the graph to the browser $graph->Stroke(); ?> jpgraph-1.5.2/src/Examples/bargradex2.php0100754000076400001440000000244507437547531017010 0ustar ljpusersimg->SetMargin(60,20,30,50); $graph->SetScale("textlin"); $graph->SetMarginColor("silver"); $graph->SetShadow(); // Set up the title for the graph $graph->title->Set("Example negative bars"); $graph->title->SetFont(FF_VERDANA,FS_NORMAL,18); $graph->title->SetColor("darkred"); // Setup font for axis $graph->xaxis->SetFont(FF_VERDANA,FS_NORMAL,12); $graph->xaxis->SetColor("black","red"); $graph->yaxis->SetFont(FF_VERDANA,FS_NORMAL,11); // Show 0 label on Y-axis (default is not to show) $graph->yscale->ticks->SupressZeroLabel(false); // Setup X-axis labels $graph->xaxis->SetTickLabels($datax); $graph->xaxis->SetLabelAngle(50); // Create the bar pot $bplot = new BarPlot($datay); $bplot->SetWidth(0.6); // Setup color for gradient fill style $bplot->SetFillGradient("navy","steelblue",GRAD_MIDVER); // Set color for the frame of each bar $bplot->SetColor("navy"); $graph->Add($bplot); // Finally send the graph to the browser $graph->Stroke(); ?> jpgraph-1.5.2/src/Examples/bargradex3.php0100754000076400001440000000264707437547531017015 0ustar ljpusersimg->SetMargin(60,20,30,50); $graph->SetScale("textlin"); $graph->SetMarginColor("silver"); $graph->SetShadow(); // Set up the title for the graph $graph->title->Set("Example negative bars"); $graph->title->SetFont(FF_VERDANA,FS_NORMAL,16); $graph->title->SetColor("darkred"); // Setup font for axis $graph->xaxis->SetFont(FF_VERDANA,FS_NORMAL,10); $graph->yaxis->SetFont(FF_VERDANA,FS_NORMAL,10); // Show 0 label on Y-axis (default is not to show) $graph->yscale->ticks->SupressZeroLabel(false); // Setup X-axis labels $graph->xaxis->SetTickLabels($datax); $graph->xaxis->SetLabelAngle(50); // Set X-axis at the minimum value of Y-axis (default will be at 0) $graph->xaxis->SetPos("min"); // "min" will position the x-axis at the minimum value of the Y-axis // Create the bar pot $bplot = new BarPlot($datay); $bplot->SetWidth(0.6); // Setup color for gradient fill style $bplot->SetFillGradient("navy","steelblue",GRAD_MIDVER); // Set color for the frame of each bar $bplot->SetColor("navy"); $graph->Add($bplot); // Finally send the graph to the browser $graph->Stroke(); ?> jpgraph-1.5.2/src/Examples/bargradex4.php0100754000076400001440000000243307437547531017007 0ustar ljpusersimg->SetMargin(60,30,30,40); $graph->SetScale("textlin"); $graph->SetMarginColor("teal"); $graph->SetShadow(); // Set up the title for the graph $graph->title->Set("Bargraph with small variations"); $graph->title->SetColor("white"); $graph->title->SetFont(FF_VERDANA,FS_BOLD,12); // Setup color for axis and labels $graph->xaxis->SetColor("black","white"); $graph->yaxis->SetColor("black","white"); // Setup font for axis $graph->xaxis->SetFont(FF_VERDANA,FS_NORMAL,10); $graph->yaxis->SetFont(FF_VERDANA,FS_NORMAL,10); // Setup X-axis title (color & font) $graph->xaxis->title->Set("X-axis"); $graph->xaxis->title->SetColor("white"); $graph->xaxis->title->SetFont(FF_VERDANA,FS_BOLD,10); // Create the bar pot $bplot = new BarPlot($datay); $bplot->SetWidth(0.6); // Setup color for gradient fill style $tcol=array(100,100,255); $fcol=array(255,100,100); $bplot->SetFillGradient($fcol,$tcol,GRAD_HOR); $graph->Add($bplot); // Finally send the graph to the browser $graph->Stroke(); ?> jpgraph-1.5.2/src/Examples/bargradex5.php0100754000076400001440000000271207437547531017010 0ustar ljpusersimg->SetMargin(60,30,30,40); $graph->SetScale("textlin"); $graph->SetMarginColor("teal"); $graph->SetShadow(); // Create the bar pot $bplot = new BarPlot($datay); $bplot->SetWidth(0.6); // This is how you make the bar graph start from something other than 0 $bplot->SetYMin(0.302); // Setup color for gradient fill style $tcol=array(100,100,255); $fcol=array(255,100,100); $bplot->SetFillGradient($fcol,$tcol,GRAD_HOR); $bplot->SetFillColor("orange"); $graph->Add($bplot); // Set up the title for the graph $graph->title->Set("Bargraph which doesn't start from y=0"); $graph->title->SetColor("yellow"); $graph->title->SetFont(FF_VERDANA,FS_BOLD,12); // Setup color for axis and labels $graph->xaxis->SetColor("black","white"); $graph->yaxis->SetColor("black","white"); // Setup font for axis $graph->xaxis->SetFont(FF_VERDANA,FS_NORMAL,10); $graph->yaxis->SetFont(FF_VERDANA,FS_NORMAL,10); // Setup X-axis title (color & font) $graph->xaxis->title->Set("X-axis"); $graph->xaxis->title->SetColor("white"); $graph->xaxis->title->SetFont(FF_VERDANA,FS_BOLD,10); // Finally send the graph to the browser $graph->Stroke(); ?> jpgraph-1.5.2/src/Examples/bargradex6.php0100644000076400001440000000272207437547531017010 0ustar ljpusersimg->SetMargin(60,150,30,50); $graph->SetScale("textlin"); $graph->SetMarginColor("silver"); $graph->SetShadow(); // Set up the title for the graph $graph->title->Set("Example negative bars"); $graph->title->SetFont(FF_VERDANA,FS_NORMAL,16); $graph->title->SetColor("darkred"); // Setup font for axis $graph->xaxis->SetFont(FF_VERDANA,FS_NORMAL,10); $graph->yaxis->SetFont(FF_VERDANA,FS_NORMAL,10); // Show 0 label on Y-axis (default is not to show) $graph->yscale->ticks->SupressZeroLabel(false); // Setup X-axis labels $graph->xaxis->SetTickLabels($datax); $graph->xaxis->SetLabelAngle(50); // Set X-axis at the minimum value of Y-axis (default will be at 0) $graph->xaxis->SetPos("min"); // "min" will position the x-axis at the minimum value of the Y-axis // Create the bar pot $bplot = new BarPlot($datay); $bplot->SetWidth(0.6); $bplot->SetLegend("Result 1999","blue"); // Setup color for gradient fill style $bplot->SetFillGradient("navy","steelblue",GRAD_MIDVER); // Set color for the frame of each bar $bplot->SetColor("navy"); $graph->Add($bplot); // Finally send the graph to the browser $graph->Stroke(); ?> jpgraph-1.5.2/src/Examples/example1.php0100754000076400001440000000107307437547531016477 0ustar ljpusersSetScale("textlin"); $graph->img->SetMargin(30,90,40,50); $graph->xaxis->SetFont(FF_FONT1,FS_BOLD); $graph->title->Set("Examples for graph"); // Create the linear plot $lineplot=new LinePlot($ydata); $lineplot->SetLegend("Test 1"); $lineplot->SetColor("blue"); // Add the plot to the graph $graph->Add($lineplot); // Display the graph $graph->Stroke(); ?> jpgraph-1.5.2/src/Examples/example2.php0100754000076400001440000000107007437547531016475 0ustar ljpusersSetScale("textlin"); $graph->yscale->SetAutoMin(0); // Create the linear plot $lineplot=new LinePlot($ydata); // Add the plot to the graph $graph->Add($lineplot); $graph->img->SetMargin(40,20,20,40); $graph->title->Set("Example 2"); $graph->xaxis->title->Set("X-title"); $graph->yaxis->title->Set("Y-title"); // Display the graph $graph->Stroke(); ?> jpgraph-1.5.2/src/Examples/example3.php0100754000076400001440000000145607437547531016506 0ustar ljpusersSetScale("textlin"); // Create the linear plot $lineplot=new LinePlot($ydata); // Add the plot to the graph $graph->Add($lineplot); $graph->img->SetMargin(40,20,20,40); $graph->title->Set("Example 3"); $graph->xaxis->title->Set("X-title"); $graph->yaxis->title->Set("Y-title"); $graph->title->SetFont(FF_FONT1,FS_BOLD); $graph->yaxis->title->SetFont(FF_FONT1,FS_BOLD); $graph->xaxis->title->SetFont(FF_FONT1,FS_BOLD); $lineplot->SetColor("blue"); $lineplot->SetWeight(2); $graph->yaxis->SetColor("red"); $graph->yaxis->SetWeight(2); $graph->SetShadow(); // Display the graph $graph->Stroke(); ?> jpgraph-1.5.2/src/Examples/example4.php0100754000076400001440000000172107437547531016502 0ustar ljpusersSetScale("textlin"); // Create the linear plot $lineplot=new LinePlot($ydata); $lineplot2=new LinePlot($ydata2); // Add the plot to the graph $graph->Add($lineplot); $graph->Add($lineplot2); $graph->img->SetMargin(40,20,20,40); $graph->title->Set("Example 4"); $graph->xaxis->title->Set("X-title"); $graph->yaxis->title->Set("Y-title"); $graph->title->SetFont(FF_FONT1,FS_BOLD); $graph->yaxis->title->SetFont(FF_FONT1,FS_BOLD); $graph->xaxis->title->SetFont(FF_FONT1,FS_BOLD); $lineplot->SetColor("blue"); $lineplot->SetWeight(2); $lineplot2->SetColor("orange"); $lineplot2->SetWeight(2); $graph->yaxis->SetColor("red"); $graph->yaxis->SetWeight(2); $graph->SetShadow(); // Display the graph $graph->Stroke(); ?> jpgraph-1.5.2/src/Examples/example5.php0100754000076400001440000000217507437547531016507 0ustar ljpusersimg->SetMargin(40,40,20,40); $graph->SetScale("textlin"); $graph->SetY2Scale("lin"); $graph->SetShadow(); // Create the linear plot $lineplot=new LinePlot($ydata); $lineplot2=new LinePlot($y2data); // Add the plot to the graph $graph->Add($lineplot); $graph->AddY2($lineplot2); $lineplot2->SetColor("orange"); $lineplot2->SetWeight(2); $graph->y2axis->SetColor("orange"); $graph->title->Set("Example 5"); $graph->xaxis->title->Set("X-title"); $graph->yaxis->title->Set("Y-title"); $graph->title->SetFont(FF_FONT1,FS_BOLD); $graph->yaxis->title->SetFont(FF_FONT1,FS_BOLD); $graph->xaxis->title->SetFont(FF_FONT1,FS_BOLD); $lineplot->SetColor("blue"); $lineplot->SetWeight(2); $lineplot2->SetColor("orange"); $lineplot2->SetWeight(2); $graph->yaxis->SetColor("blue"); $lineplot->SetLegend("Plot 1"); $lineplot2->SetLegend("Plot 2"); // Display the graph $graph->Stroke(); ?> jpgraph-1.5.2/src/Examples/example6.php0100754000076400001440000000244107437547531016504 0ustar ljpusersimg->SetMargin(40,40,20,70); $graph->SetScale("textlin"); $graph->SetY2Scale("lin"); $graph->SetShadow(); // Create the linear plot $lineplot=new LinePlot($ydata); $lineplot2=new LinePlot($y2data); // Add the plot to the graph $graph->Add($lineplot); $graph->AddY2($lineplot2); $lineplot2->SetColor("orange"); $lineplot2->SetWeight(2); $graph->y2axis->SetColor("orange"); $graph->title->Set("Example 6"); $graph->xaxis->title->Set("X-title"); $graph->yaxis->title->Set("Y-title"); $graph->title->SetFont(FF_FONT1,FS_BOLD); $graph->yaxis->title->SetFont(FF_FONT1,FS_BOLD); $graph->xaxis->title->SetFont(FF_FONT1,FS_BOLD); $lineplot->SetColor("blue"); $lineplot->SetWeight(2); $lineplot2->SetColor("orange"); $lineplot2->SetWeight(2); $graph->yaxis->SetColor("blue"); $lineplot->SetLegend("Plot 1"); $lineplot2->SetLegend("Plot 2"); $graph->legend->SetLayout(LEGEND_HOR); $graph->legend->Pos(0.5,0.85,"center","center"); $graph->ygrid->SetLineStyle("longdashed"); $graph->ygrid->SetColor("red"); // Display the graph $graph->Stroke(); ?> jpgraph-1.5.2/src/Examples/example7.php0100754000076400001440000000231707437547531016507 0ustar ljpusersimg->SetMargin(40,110,20,40); $graph->SetScale("textlog"); $graph->SetY2Scale("log"); $graph->SetShadow(); // Create the linear plot $lineplot=new LinePlot($ydata); $lineplot2=new LinePlot($y2data); // Add the plot to the graph $graph->Add($lineplot); $graph->AddY2($lineplot2); $lineplot2->SetColor("orange"); $lineplot2->SetWeight(2); $graph->y2axis->SetColor("orange"); $graph->title->Set("Example 7"); $graph->xaxis->title->Set("X-title"); $graph->yaxis->title->Set("Y-title"); $graph->title->SetFont(FF_FONT1,FS_BOLD); $graph->yaxis->title->SetFont(FF_FONT1,FS_BOLD); $graph->xaxis->title->SetFont(FF_FONT1,FS_BOLD); $lineplot->SetColor("blue"); $lineplot->SetWeight(2); $lineplot2->SetColor("orange"); $lineplot2->SetWeight(2); $graph->yaxis->SetColor("blue"); $lineplot->SetLegend("Plot 1"); $lineplot2->SetLegend("Plot 2"); $graph->legend->Pos(0.05,0.5,"right","center"); // Display the graph $graph->Stroke(); ?> jpgraph-1.5.2/src/Examples/example8.php0100754000076400001440000000255407437547531016513 0ustar ljpusersimg->SetMargin(40,110,20,40); $graph->SetScale("textlog"); $graph->SetY2Scale("log"); $graph->SetShadow(); $graph->ygrid->Show(true,true); $graph->xgrid->Show(true,false); // Create the linear plot $lineplot=new LinePlot($ydata); $lineplot2=new LinePlot($y2data); $graph->yaxis->scale->ticks->SupressFirst(); $graph->y2axis->scale->ticks->SupressFirst(); // Add the plot to the graph $graph->Add($lineplot); $graph->AddY2($lineplot2); $lineplot2->SetColor("orange"); $lineplot2->SetWeight(2); $graph->y2axis->SetColor("orange"); $graph->title->Set("Example 8"); $graph->xaxis->title->Set("X-title"); $graph->yaxis->title->Set("Y-title"); $graph->title->SetFont(FF_FONT1,FS_BOLD); $graph->yaxis->title->SetFont(FF_FONT1,FS_BOLD); $graph->xaxis->title->SetFont(FF_FONT1,FS_BOLD); $lineplot->SetColor("blue"); $lineplot->SetWeight(2); $lineplot2->SetColor("orange"); $lineplot2->SetWeight(2); $graph->yaxis->SetColor("blue"); $lineplot->SetLegend("Plot 1"); $lineplot2->SetLegend("Plot 2"); $graph->legend->Pos(0.05,0.5,"right","center"); // Display the graph $graph->Stroke(); ?> jpgraph-1.5.2/src/Examples/example9.php0100754000076400001440000000310207437547531016502 0ustar ljpusersSetScale("textlog"); $graph->img->SetMargin(40,110,20,40); $graph->SetY2Scale("log"); $graph->SetShadow(); $graph->ygrid->Show(true,true); $graph->xgrid->Show(true,false); // Create the linear plot $lineplot=new LinePlot($ydata); $lineplot2=new LinePlot($y2data); $graph->yaxis->scale->ticks->SupressFirst(); $graph->y2axis->scale->ticks->SupressFirst(); // Add the plot to the graph $graph->Add($lineplot); $graph->AddY2($lineplot2); $lineplot2->SetColor("orange"); $lineplot2->SetWeight(2); $graph->y2axis->SetColor("orange"); $graph->title->Set("Examples 9"); $graph->xaxis->title->Set("X-title"); $graph->yaxis->title->Set("Y-title"); $graph->title->SetFont(FF_FONT1,FS_BOLD); $graph->yaxis->title->SetFont(FF_FONT1,FS_BOLD); $graph->xaxis->title->SetFont(FF_FONT1,FS_BOLD); $lineplot->SetColor("blue"); $lineplot->SetWeight(2); $lineplot2->SetColor("orange"); $lineplot2->SetWeight(2); $graph->yaxis->SetColor("blue"); $lineplot->SetLegend("Plot 1"); $lineplot2->SetLegend("Plot 2"); $graph->legend->Pos(0.05,0.5,"right","center"); $graph->xaxis->SetTickLabels($datax); $graph->xaxis->SetTextTickInterval(2); // Display the graph $graph->Stroke(); ?> jpgraph-1.5.2/src/Examples/impulsex1.php0100644000076400001440000000073207437547531016711 0ustar ljpusersimg->SetMargin(40,40,40,40); $graph->SetScale("textlin"); $graph->SetShadow(); $graph->title->Set("Example 1 of impuls scatter plot"); $graph->title->SetFont(FF_FONT1,FS_BOLD); $sp1 = new ScatterPlot($datay); $sp1->mark->SetType(MARK_SQUARE); $sp1->SetImpuls(); $graph->Add($sp1); $graph->Stroke(); ?>jpgraph-1.5.2/src/Examples/impulsex2.php0100644000076400001440000000126007437547531016707 0ustar ljpusersimg->SetMargin(40,40,40,40); $graph->SetScale("textlin"); $graph->SetShadow(); $graph->title->Set("Example 2 of impuls scatter plot"); $graph->title->SetFont(FF_FONT1,FS_BOLD); $graph->xaxis->title->Set("Impuls respons"); $graph->xaxis->title->SetFont(FF_FONT1,FS_BOLD); $sp1 = new ScatterPlot($datay);//,$datax); $sp1->mark->SetType(MARK_FILLEDCIRCLE); $sp1->mark->SetFillColor("red"); $sp1->SetImpuls(); $sp1->SetColor("blue"); $sp1->SetWeight(3); $sp1->mark->SetWidth(4); $graph->Add($sp1); $graph->Stroke(); ?>jpgraph-1.5.2/src/Examples/impulsex3.php0100644000076400001440000000246007437547531016713 0ustar ljpusersSetScale("intlin"); $graph->SetShadow(); $graph->SetBox(); $graph->title->Set("Impuls Example 3"); $graph->title->SetFont(FF_FONT1,FS_BOLD); // Set format for labels $graph->yaxis->SetLabelFormatString("%-02.1f"); $graph->yaxis->SetLabelFormatCallback("mycallback"); // Set X-axis at the minimum value of Y-axis (default will be at 0) $graph->xaxis->SetPos("min"); // "min" will position the x-axis at the minimum value of the Y-axis // Extend the margin for the labels on the Y-axis and reverse the direction // of the ticks on the Y-axis $graph->yaxis->SetTickLabelMargin(12); $graph->xaxis->SetTickLabelMargin(6); $graph->yaxis->SetTickDirection(SIDE_LEFT); $graph->xaxis->SetTickDirection(SIDE_DOWN); // Create a new impuls type scatter plot $sp1 = new ScatterPlot($datay); $sp1->mark->SetType(MARK_SQUARE); $sp1->mark->SetFillColor("red"); $sp1->SetImpuls(); $sp1->SetColor("blue"); $sp1->SetWeight(1); $sp1->mark->SetWidth(3); $graph->Add($sp1); $graph->Stroke(); ?>jpgraph-1.5.2/src/Examples/impulsex4.php0100644000076400001440000000364507437547531016722 0ustar ljpusersSetScale("intlin"); $graph->SetShadow(); $graph->SetBox(); $graph->title->Set("Impuls Example 4"); $graph->title->SetFont(FF_FONT1,FS_BOLD); // Set some other color then the boring default $graph->SetColor("lightyellow"); $graph->SetMarginColor("khaki"); // Set legend box specification $graph->legend->SetFillColor("white"); $graph->legend->SetLineWeight(2); // Set X-axis at the minimum value of Y-axis (default will be at 0) $graph->xaxis->SetPos("min"); // "min" will position the x-axis at the minimum value of the Y-axis // Extend the margin for the labels on the Y-axis and reverse the direction // of the ticks on the Y-axis $graph->yaxis->SetTickLabelMargin(12); $graph->xaxis->SetTickLabelMargin(6); $graph->yaxis->SetTickDirection(SIDE_LEFT); $graph->xaxis->SetTickDirection(SIDE_DOWN); // Add mark graph with static lines $line = new PlotLine(HORIZONTAL,0,"black",2); $graph->AddLine($line); // Create a new impuls type scatter plot $sp1 = new ScatterPlot($datay,$datax); $sp1->mark->SetType(MARK_SQUARE); $sp1->mark->SetFillColor("red"); $sp1->SetImpuls(); $sp1->SetColor("blue"); $sp1->SetWeight(1); $sp1->mark->SetWidth(3); $sp1->SetLegend("Non-causal signal"); $graph->Add($sp1); // Create the envelope plot $ep1 = new LinePlot($datayenv,$datax); $ep1->SetStyle("dotted"); $ep1->SetLegend("Positive envelope"); $graph->Add($ep1); $graph->Stroke(); ?>jpgraph-1.5.2/src/Examples/show-source.php0100644000076400001440000000011007437547531017226 0ustar ljpusers jpgraph-1.5.2/src/Examples/scatterlinkex1.php0100754000076400001440000000120207437547531017716 0ustar ljpusersimg->SetMargin(40,40,40,40); $graph->img->SetAntiAliasing(); $graph->SetScale("linlin"); $graph->SetShadow(); $graph->title->Set("Linked Scatter plot ex1"); $graph->title->SetFont(FF_FONT1,FS_BOLD); $sp1 = new ScatterPlot($datay,$datax); $sp1->SetLinkPoints(true,"red",2); $sp1->mark->SetType(MARK_FILLEDCIRCLE); $sp1->mark->SetFillColor("navy"); $sp1->mark->SetWidth(3); $graph->Add($sp1); $graph->Stroke(); ?> jpgraph-1.5.2/src/Examples/scatterlinkex2.php0100644000076400001440000000140307437547531017720 0ustar ljpusersSetScale("linlin"); $graph->img->SetMargin(40,40,40,40); $graph->SetShadow(); $graph->title->Set("Linked scatter plot"); $graph->title->SetFont(FF_FONT1,FS_BOLD); // 10% top and bottom grace $graph->yscale->SetGrace(5,5); $graph->xscale->SetGrace(1,1); $sp1 = new ScatterPlot($datay,$datax); $sp1->mark->SetType(MARK_FILLEDCIRCLE); $sp1->mark->SetFillColor("red"); $sp1->SetColor("blue"); //$sp1->SetWeight(3); $sp1->mark->SetWidth(4); $sp1->SetLinkPoints(); $graph->Add($sp1); $graph->Stroke(); ?> jpgraph-1.5.2/src/Examples/text-example1.php0100754000076400001440000000056007437547531017461 0ustar ljpusersPos(0.01,0.5); $t1->SetOrientation("h"); $t1->SetFont(FF_FONT1,FS_NORMAL); $t1->SetBox("white","black",true); $t1->SetColor("black"); $graph->AddText($t1); $graph->Stroke(); ?>jpgraph-1.5.2/src/Examples/text-example2.php0100644000076400001440000000070207437547531017456 0ustar ljpusersPos(0.01,100); //$t1->SetOrientation("h"); $t1->SetFont(FF_FONT1,FS_NORMAL); $t1->SetBox("white","black",true); $t1->ParagraphAlign("right"); $t1->SetColor("black"); $graph->AddText($t1); $graph->Stroke(); ?>jpgraph-1.5.2/src/Examples/pie3d_csimex1.php0100644000076400001440000000204507437547531017416 0ustar ljpusersSetShadow(); // Set A title for the plot $graph->title->Set("3D Pie Client side image map"); $graph->title->SetFont(FF_FONT1,FS_BOLD); // Create $p1 = new PiePlot3D($data); $p1->SetLegends(array("Jan (%d)","Feb","Mar","Apr","May","Jun","Jul")); $targ=array("pie3d_csimex1.php?v=1","pie3d_csimex1.php?v=2","pie3d_csimex1.php?v=3", "pie3d_csimex1.php?v=4","pie3d_csimex1.php?v=5","pie3d_csimex1.php?v=6"); $alts=array("val=%v","val=%v","val=%v","val=%v","val=%v","val=%v"); $p1->SetCSIMTargets($targ,$alts); // Use absolute labels $p1->SetLabelType(1); $p1->SetLabelFormat("%d kr"); // Move the pie slightly to the left $p1->SetCenter(0.4,0.5); $graph->Add($p1); // Display the graph $graph->Stroke(GenImgName()); echo $graph->GetHTMLImageMap("myimagemap"); echo ""; ?> jpgraph-1.5.2/src/Examples/pie3d_csimex1.png0100644000076400001440000000334007437547531017412 0ustar ljpusers‰PNG  IHDR,È ñÁf-PLTEÿÿÿfffÿfͪB…nîÅ‘š€^zÅÍO€…fÍB…E‹,Zëëë÷”ÏÛnIDATxœíÜ=rÛ8p`u>OÆg×,|‚dtÏä"ÛèîÒ¦té6]êTê·ñTð:Ã⛀xà‡0üÇ™Š%ýü Š$FêKGáÿ*KcaÒX˜Ü==5Vv°,°7(Û¢¡G‹;ÁÙZ™E¡£ò;°Yjk|MëÕ·gÚ‰'V7æµØ–[»Îdy2šh³xÛTíTAØ~BTî2ø–¼ÔOò-à¿°;©y8XÀ³øcK¶Í ‰n¢*¨ªˆŸ±ª,¶$Æ'ëÆßxYµÄ‹Ê'tX`³øbéúIÛïä7Öd¯nªE,¿GWËÜ¡ #Þ®žSÖøà5ÔM”[@ì‡ËÚ_3AðÁ` dÝ͵2C^uˆ˜‰… ˆüI3ä©lbøU÷åÁŸ5ê`Qð^«Vv “ÆÂ¤±0i,L “Y4û\;¬kN*eÝ=5Vc}–˜úêXŸ¾³p–Mëù× ï«…Å@Cí…ìö,臡×ÅêS®[W‹©É®õ°†k},æYŠxk–(®Ö hU y`_ºZ5MuM§•Îòi¬Æ*bU:äïO,bZ¿^Õ¬UKªd™76±@ìªûP½n[­Á¼±©‹Å¿êdUØÄ‡|*m–7¬Œ4Vc±*òŸ°ô‘ù}sUkÂÜ'¶X=Ü‚„Ò$‹ºî?Ë3S'—ѱoÆKù.kÿ76añuãB*glñ76û6ѰÀé£Ã_û²:S­8k÷j±¿D5äi”%ÎØ X|M˜|òr–ž º +•‹ýªr%L9+‚]8ËSªªÕтՆ,Ç+#q–n"åË™VS-eQÕ?Úeô1P͈j)«#cµbšØÅÜ„j!‹Í"áòkÎß'y¹Œ-ªZ8ä)¨{zöñëtú4U‰°š¢*Îúò‹¥I7ÑÍá«Kæ‡TÿÆ\¼f9¬>^±ÜYþpÔ0 â8»b,Q²Yßù ‹ßØäx1(–h¹,ü„.«_áÍñÈJu²o£lå Kœ®YcWýÍQ¥Ûq¹ÕZ…EïO^’åbœcõ+°¦ª™r…\“!¿”PN)5í²&ˆÄÌ…`A@5ÛÆçÉ{–_EƒªÙ6>OYÉf[˜Q.¿k³"ª™ÉkR®•Y±bÍ·qrT½"K¬‹ÐP“׺gl(?Zy1o÷àLÝ.2Ö?ÿ±¬sÆF°Æ¸À™}PŒµÂøÉœY9eÉ36‹®bDYöåM¼R$çˬY|_òVÂRgl±>GPðKâ¬hÕ›ÐËe=Y/ ÅoãcŠás6Ù¬ŸÁAeTñ6ž/©&áýu>Ë/—ƒJ´b,%‡¯^¹Šµ1ä:?NYA°Æ6¾P‘á—­YÚåªÔð⪭YÒE†—PmÎzý ¡A^g©òXóûPë5­r‡—V¹,ò×SVP¬¿ÿ¤zè´/;²þüNÂtA—j/‡%Zù&Úg¡|"8 ÄKÆìãå² \–(Yh¦Ÿ¢.ﲨϒ5óÃÿÂ*U•²Lœ»we=¤XN|VùG/dU—³Ê¯βŽÇo¥¬ò:,JôuC:u X >>Ãfi’dŽú: -c-(–Í—R:¸%¬òI‹øMT,ÿB"o#šµäP|VäB"saYð•,H5½H,°®-guòvz!‘†õ.:¸fyÍ \HÌq=:ª%0Äò ˜í£bÙgDe.̪:¬Ä…ÎmX¢ÏiÖûEA|ðòÃÇÐkl Q2\àìô mYòxoJú ±îu$°Æl}ÏÌÙ[;T}ä•»Æl!ê/lþ±º€éãRÖlÌÚEwÙLJY‰enÄÈÒcksVö,)>°‰ã®1»5«,…¬ì¦}¨&‚Eõ§ný›àXÙÁm'Á6Q} ö»A²ôQj¿[$Kõ·ß-rȽZ³ß-vÈ«#HÔ~· 8ßïŠoPûÝ‚|ˆét·4&…IcaÒX˜4&…IcaÒX˜4&…IcaÒX˜4&…IcaÒX˜4&…IŬ¬UÿûæN¬OÏ\ɾk “ÆÂä©ÃõË[c\ûIEND®B`‚jpgraph-1.5.2/src/Examples/scatterex1.php0100754000076400001440000000073507437547531017052 0ustar ljpusersimg->SetMargin(40,40,40,40); $graph->SetScale("linlin"); $graph->SetShadow(); $graph->title->Set("Example 1 of scatter plot"); $graph->title->SetFont(FF_FONT1,FS_BOLD); $sp1 = new ScatterPlot($datay,$datax); $graph->Add($sp1); $graph->Stroke(); ?> jpgraph-1.5.2/src/Examples/scatterex2.php0100754000076400001440000000110207437547531017040 0ustar ljpusersimg->SetMargin(40,40,40,40); $graph->SetScale("linlin"); $graph->SetShadow(); $graph->title->Set("Example 2 of scatter plot"); $graph->title->SetFont(FF_FONT1,FS_BOLD); $sp1 = new ScatterPlot($datay,$datax); $sp1->mark->SetType(MARK_FILLEDCIRCLE); $sp1->mark->SetFillColor("navy"); $sp1->mark->SetWidth(3); $graph->Add($sp1); $graph->Stroke(); ?> jpgraph-1.5.2/src/Examples/exampleex9.php0100644000076400001440000000320107437547531017035 0ustar ljpusersSetScale("textlog"); $graph->img->SetMargin(40,110,20,40); $graph->SetY2Scale("log"); $graph->SetShadow(); $graph->ygrid->Show(true,true); $graph->xgrid->Show(true,false); // Create the linear plot $lineplot=new LinePlot($ydata); $lineplot2=new LinePlot($y2data); $graph->yaxis->scale->ticks->SupressFirst(); $graph->y2axis->scale->ticks->SupressFirst(); // Add the plot to the graph $graph->Add($lineplot); $graph->AddY2($lineplot2); $lineplot2->SetColor("orange"); $lineplot2->SetWeight(2); $graph->y2axis->SetColor("orange"); $graph->title->Set("Examples 9"); $graph->xaxis->title->Set("X-title"); $graph->yaxis->title->Set("Y-title"); $graph->title->SetFont(FF_FONT1,FS_BOLD); $graph->yaxis->title->SetFont(FF_FONT1,FS_BOLD); $graph->xaxis->title->SetFont(FF_FONT1,FS_BOLD); $lineplot->SetColor("blue"); $lineplot->SetWeight(2); $lineplot2->SetColor("orange"); $lineplot2->SetWeight(2); $graph->yaxis->SetColor("blue"); $lineplot->SetLegend("Plot 1"); $lineplot2->SetLegend("Plot 2"); $graph->legend->Pos(0.05,0.5,"right","center"); $graph->xaxis->SetTickLabels($datax); $graph->xaxis->SetTextTickInterval(2); // Display the graph $graph->Stroke(); ?> jpgraph-1.5.2/src/Examples/filledlineex01.php0100644000076400001440000000105307437547531017564 0ustar ljpusersimg->SetMargin(40,40,40,40); $graph->SetScale("textlin"); $graph->SetShadow(); $graph->title->Set("Example of filled line plot"); $graph->title->SetFont(FF_FONT1,FS_BOLD); $p1 = new LinePlot($datay); $p1->SetFillColor("orange"); $p1->mark->SetType(MARK_FILLEDCIRCLE); $p1->mark->SetFillColor("red"); $p1->mark->SetWidth(4); $graph->Add($p1); $graph->Stroke(); ?> jpgraph-1.5.2/src/Examples/spiderex1.php0100754000076400001440000000050007437547531016661 0ustar ljpusersAdd($plot); $graph->Stroke(); ?>jpgraph-1.5.2/src/Examples/spiderex2.php0100754000076400001440000000062307437547531016670 0ustar ljpusersSetPlotSize(0.4); $graph->SetCenter(0.3); // Add the plot and display the graph $graph->Add($plot); $graph->Stroke(); ?> jpgraph-1.5.2/src/Examples/spiderex3.php0100754000076400001440000000123507437547531016671 0ustar ljpusersSetLegend("Defects"); // Set position and size $graph->SetCenter(0.5,0.55); $graph->SetTitles($axtitles); $graph->axis->title->SetColor("navy"); $graph->axis->title->SetFont(FF_ARIAL,FS_BOLD,10); $graph->title->Set("Result 2000"); $graph->title->SetFont(FF_COURIER,FS_BOLD,11); // Add the plot and display the graph $graph->Add($plot); $graph->Stroke(); ?> jpgraph-1.5.2/src/Examples/spiderex4.php0100754000076400001440000000147607437547531016701 0ustar ljpusersSetLegend("Defects"); $graph->axis->title->SetFont(FF_FONT1,FS_BOLD); $graph->axis->title->SetColor("blue"); // Set position and size $graph->SetCenter(0.5,0.55); $graph->SetTitles($axtitles); $graph->axis->SetFont(FF_FONT1,FS_BOLD); $graph->title->Set("Result 2001"); $graph->title->SetFont(FF_FONT1,FS_BOLD); $graph->SupressTickMarks(); $graph->grid->SetLineStyle("dashed"); $graph->grid->SetColor("darkred"); $graph->grid->Show(); // Add the plot and display the graph $graph->Add($plot); $graph->Stroke(); ?> jpgraph-1.5.2/src/Examples/spiderex5.php0100754000076400001440000000145107437547531016673 0ustar ljpusersSetLegend("Defects"); // Set position and size $graph->SetCenter(0.5,0.55); $graph->SetTitles($axtitles); $graph->title->Set("Result 2001"); $graph->title->SetFont(FF_FONT1,FS_BOLD); $graph->axis->title->SetFont(FF_ARIAL,FS_BOLD); $graph->SupressTickMarks(); $graph->SetShadow(); $graph->SetColor(array(200,230,230)); $graph->grid->SetLineStyle("dashed"); $graph->grid->SetColor("darkred"); $graph->grid->Show(); // Add the plot and display the graph $graph->Add($plot); $graph->Stroke(); ?> jpgraph-1.5.2/src/Examples/spiderex6.php0100754000076400001440000000173307437547531016677 0ustar ljpusersimg->SetAntiAliasing("white"); $plot = new SpiderPlot($data); $plot->SetLegend("Defects"); $plot2 = new SpiderPlot($data2); $plot2->SetFill(false); $plot2->SetLineWeight(2); $plot2->SetColor("red"); $plot2->SetLegend("Target"); // Set position and size $graph->SetCenter(0.5,0.55); $graph->SetTitles($axtitles); $graph->title->Set("Result 2001"); $graph->title->SetFont(FF_FONT1,FS_BOLD); $graph->SupressTickMarks(); $graph->SetShadow(); //$graph->SetColor("teal"); $graph->grid->SetLineStyle("solid"); $graph->grid->SetColor("blue"); $graph->grid->Show(); // Add the plot and display the graph //$graph->Add($plot); $graph->Add($plot2); $graph->Stroke(); ?> jpgraph-1.5.2/src/Examples/spiderex7.php0100754000076400001440000000165307437547531016701 0ustar ljpusersSetColor("white"); $graph->SetShadow(); $graph->SetCenter(0.4,0.55); $graph->axis->SetFont(FF_FONT1,FS_BOLD); $graph->axis->SetWeight(2); $graph->grid->SetLineStyle("longdashed"); $graph->grid->SetColor("navy"); $graph->grid->Show(); $graph->SupressTickMarks(); $graph->title->Set("Quality result"); $graph->title->SetFont(FF_FONT1,FS_BOLD); $graph->SetTitles(array("One","Two","Three","Four","Five","Sex","Seven","Eight","Nine","Ten")); $plot = new SpiderPlot(array(30,80,60,40,71,81,47)); $plot->SetLegend("Goal"); $plot->SetColor("red","lightred"); $plot->SetFill(false); $plot->SetLineWeight(2); $plot2 = new SpiderPlot(array(70,40,30,80,31,51,14)); $plot2->SetLegend("Actual"); $plot2->SetColor("blue","lightred"); $graph->Add($plot2); $graph->Add($plot); $graph->Stroke(); ?>jpgraph-1.5.2/src/Examples/example16.1.php0100754000076400001440000000222207437547531016721 0ustar ljpusersimg->SetMargin(40,130,20,40); $graph->SetScale("textlin"); $graph->SetShadow(); // Create the linear error plot $l1plot=new LinePlot($l1datay); $l1plot->SetColor("red"); $l1plot->SetWeight(2); $l1plot->SetLegend("Prediction"); // Create the bar plot $l2plot = new LinePlot($l2datay); $l2plot->SetFillColor("orange"); $l2plot->SetLegend("Result"); // Add the plots to the graph $graph->Add($l2plot); $graph->Add($l1plot); $graph->title->Set("Example 16.1"); $graph->xaxis->title->Set("X-title"); $graph->yaxis->title->Set("Y-title"); $graph->title->SetFont(FF_FONT1,FS_BOLD); $graph->yaxis->title->SetFont(FF_FONT1,FS_BOLD); $graph->xaxis->title->SetFont(FF_FONT1,FS_BOLD); //$graph->xaxis->SetTickLabels($datax); //$graph->xaxis->SetTextTickInterval(2); // Display the graph $graph->Stroke(); ?> jpgraph-1.5.2/src/Examples/example16.2.php0100754000076400001440000000215607437547531016730 0ustar ljpusersimg->SetMargin(40,130,20,40); $graph->SetScale("textlin"); $graph->SetShadow(); // Create the linear error plot $l1plot=new LinePlot($l1datay); $l1plot->SetColor("red"); $l1plot->SetWeight(2); $l1plot->SetLegend("Prediction"); // Create the bar plot $l2plot = new BarPlot($l2datay); $l2plot->SetFillColor("orange"); $l2plot->SetLegend("Result"); // Add the plots to the graph $graph->Add($l2plot); $graph->Add($l1plot); $graph->title->Set("Example 16.2"); $graph->xaxis->title->Set("X-title"); $graph->yaxis->title->Set("Y-title"); $graph->title->SetFont(FF_FONT1,FS_BOLD); $graph->yaxis->title->SetFont(FF_FONT1,FS_BOLD); $graph->xaxis->title->SetFont(FF_FONT1,FS_BOLD); //$graph->xaxis->SetTickLabels($datax); //$graph->xaxis->SetTextTickInterval(2); // Display the graph $graph->Stroke(); ?> jpgraph-1.5.2/src/Examples/example16.3.php0100754000076400001440000000267007437547531016732 0ustar ljpusersimg->SetMargin(40,70,20,40); $graph->SetScale("textlin"); $graph->SetShadow(); $graph->SetColor(array(250,250,250)); $graph->img->SetTransparent("white"); $t1 = new Text("This is a text"); $t1->Pos(0.5,0.5); $t1->SetOrientation("h"); $t1->SetFont(FF_FONT1,FS_BOLD); $t1->SetBox("white","black",true); $t1->SetColor("black"); $graph->AddText($t1); // Create the linear error plot $l1plot=new LinePlot($l1datay); $l1plot->SetColor("blue"); $l1plot->SetWeight(2); $l1plot->SetLegend("Prediction"); // Create the bar plot $l2plot = new BarPlot($l2datay); $l2plot->SetFillColor("orange"); $l2plot->SetLegend("Result"); // Add the plots to the graph $graph->Add($l1plot); $graph->Add($l2plot); $graph->title->Set("Example 16.3"); $graph->xaxis->title->Set("Month"); $graph->yaxis->title->Set("x10,000 US$"); $graph->title->SetFont(FF_FONT1,FS_BOLD); $graph->yaxis->title->SetFont(FF_FONT1,FS_BOLD); $graph->xaxis->title->SetFont(FF_FONT1,FS_BOLD); $graph->xaxis->SetTickLabels($datax); //$graph->xaxis->SetTextTickInterval(2); // Display the graph $graph->Stroke(); ?> jpgraph-1.5.2/src/Examples/show-example.php0100644000076400001440000000121607437547531017371 0ustar ljpusers Test suite for JpGraph - <?php echo $target; ?> "; else echo ""; ?> jpgraph-1.5.2/src/Examples/linebarex1.php0100644000076400001440000000347007437547531017016 0ustar ljpusersSetBackgroundImage("tiger_bkg.png",3); $graph->SetShadow(); // Use an integer X-scale $graph->SetScale("textlin"); // Set title and subtitle $graph->title->Set("Combined bar and line plot"); $graph->subtitle->Set("100 data points, X-Scale: 'text'"); // Use built in font $graph->title->SetFont(FF_FONT1,FS_BOLD); // Make the margin around the plot a little bit bigger // then default $graph->img->SetMargin(40,140,40,80); // Slightly adjust the legend from it's default position in the // top right corner to middle right side $graph->legend->Pos(0.05,0.5,"right","center"); // Display every 10:th datalabel $graph->xaxis->SetTextTickInterval(6); $graph->xaxis->SetTextLabelInterval(2); $graph->xaxis->SetTickLabels($databarx); $graph->xaxis->SetLabelAngle(90); // Create a red line plot $p1 = new LinePlot($datay); $p1->SetColor("red"); $p1->SetLegend("Pressure"); // Create the bar plot $b1 = new BarPlot($databary); $b1->SetLegend("Temperature"); $b1->SetAbsWidth(6); $b1->SetShadow(); // The order the plots are added determines who's ontop $graph->Add($p1); $graph->Add($b1); // Finally output the image $graph->Stroke(); ?> jpgraph-1.5.2/src/Examples/linebarex2.php0100644000076400001440000000251507437547531017016 0ustar ljpusersSetBackgroundImage("tiger_bkg.png",3); $graph->SetShadow(); // Use an integer X-scale $graph->SetScale("intlin"); // Set title and subtitle $graph->title->Set("Combined bar and line plot"); $graph->subtitle->Set("(\"left\" aligned bars)"); // Use built in font $graph->title->SetFont(FF_FONT1,FS_BOLD); // Make the margin around the plot a little bit bigger // then default $graph->img->SetMargin(40,120,40,40); // Slightly adjust the legend from it's default position in the // top right corner to middle right side $graph->legend->Pos(0.05,0.5,"right","center"); // Create a red line plot $p1 = new LinePlot($datay,$datax); $p1->SetColor("red"); $p1->SetLegend("Status one"); $graph->Add($p1); // Create the bar plot $b1 = new BarPlot($databary,$databarx); $b1->SetLegend("Status two"); $b1->SetAlign("left"); $b1->SetShadow(); $graph->Add($b1); // Finally output the image $graph->Stroke(); ?> jpgraph-1.5.2/src/Examples/linebarex3.php0100644000076400001440000000227407437547531017021 0ustar ljpusersimg->SetMargin(40,180,40,40); $graph->SetBackgroundImage("tiger_bkg.png",3); //$graph->img->SetAntiAliasing(); $graph->SetScale("intlin"); $graph->SetShadow(); $graph->title->Set("Combined bar and line plot"); $graph->subtitle->Set("(\"center\" aligned bars)"); // Use built in font $graph->title->SetFont(FF_FONT1,FS_BOLD); // Slightly adjust the legend from it's default position in the // top right corner. $graph->legend->Pos(0.05,0.5,"right","center"); // Create the first line $p1 = new LinePlot($datay,$datax); $p1->SetWeight(1); $p1->SetColor("red"); $p1->SetLegend("Triumph Tiger -98"); $graph->Add($p1); $b1 = new BarPlot($databary,$databarx); $b1->SetAbsWidth(10); $b1->SetAlign("center"); $b1->SetShadow(); $graph->Add($b1); $graph->Stroke(); ?> jpgraph-1.5.2/src/Examples/staticbandbarex1.php0100644000076400001440000000244507437547531020204 0ustar ljpusersimg->SetMargin(60,30,50,40); $graph->SetScale("textlin"); $graph->SetShadow(); $graph->title->SetFont(FF_ARIAL,FS_BOLD,15); $graph->title->Set("Cash flow "); $graph->subtitle->Set("(Department X)"); // Show both X and Y grid $graph->xgrid->Show(true,false); // Add 10% grace ("space") at top and botton of Y-scale. $graph->yscale->SetGrace(10,10); // Turn the tick mark out from the plot area $graph->xaxis->SetTickDirection(SIDE_DOWN); $graph->yaxis->SetTickDirection(SIDE_LEFT); // Create a bar pot $bplot = new BarPlot($datay); $bplot->SetFillColor("orange"); // Show the actual value for each bar on top/bottom $bplot->ShowValue(true); $bplot->SetValueFormat("%02d kr"); // Position the X-axis at the bottom of the plotare $graph->xaxis->SetPos("min"); // .. and add the plot to the graph $graph->Add($bplot); // Add band $graph->AddBand(new PlotBand(HORIZONTAL,BAND_LHOR,0,10)); //$graph->title->Set("Test of bar gradient fill"); $graph->xaxis->title->Set("X-title"); $graph->yaxis->title->Set("Y-title"); $graph->yaxis->title->SetFont(FF_ARIAL,FS_BOLD,11); $graph->xaxis->title->SetFont(FF_ARIAL,FS_BOLD,11); $graph->Stroke(); ?> jpgraph-1.5.2/src/Examples/staticbandbarex2.php0100644000076400001440000000246107437547531020203 0ustar ljpusersimg->SetMargin(60,30,50,40); $graph->SetScale("textlin"); $graph->SetShadow(); $graph->title->SetFont(FF_ARIAL,FS_BOLD,15); $graph->title->Set("Cash flow "); $graph->subtitle->Set("(Department X)"); // Show both X and Y grid $graph->xgrid->Show(true,false); // Add 10% grace ("space") at top and botton of Y-scale. $graph->yscale->SetGrace(10,10); // Turn the tick mark out from the plot area $graph->xaxis->SetTickDirection(SIDE_DOWN); $graph->yaxis->SetTickDirection(SIDE_LEFT); // Create a bar pot $bplot = new BarPlot($datay); $bplot->SetFillColor("orange"); // Show the actual value for each bar on top/bottom $bplot->ShowValue(true); $bplot->SetValueFormat("%02d kr"); // Position the X-axis at the bottom of the plotare $graph->xaxis->SetPos("min"); // .. and add the plot to the graph $graph->Add($bplot); // Add band $graph->AddBand(new PlotBand(HORIZONTAL,BAND_RDIAG,0,"max","red",2)); //$graph->title->Set("Test of bar gradient fill"); $graph->xaxis->title->Set("X-title"); $graph->yaxis->title->Set("Y-title"); $graph->yaxis->title->SetFont(FF_ARIAL,FS_BOLD,11); $graph->xaxis->title->SetFont(FF_ARIAL,FS_BOLD,11); $graph->Stroke(); ?> jpgraph-1.5.2/src/Examples/staticbandbarex3.php0100644000076400001440000000275207437547531020207 0ustar ljpusersimg->SetMargin(60,30,50,40); $graph->SetScale("textlin"); $graph->SetShadow(); $graph->title->SetFont(FF_ARIAL,FS_BOLD,15); $graph->title->Set("Cash flow "); $graph->subtitle->Set("(Department X)"); // Show both X and Y grid $graph->xgrid->Show(true,false); // Add 10% grace ("space") at top and botton of Y-scale. $graph->yscale->SetGrace(10,10); // Turn the tick mark out from the plot area $graph->xaxis->SetTickDirection(SIDE_DOWN); $graph->yaxis->SetTickDirection(SIDE_LEFT); // Create a bar pot $bplot = new BarPlot($datay); $bplot->SetFillColor("orange"); // Show the actual value for each bar on top/bottom $bplot->ShowValue(true); $bplot->SetValueFormat("%02d kr"); // Position the X-axis at the bottom of the plotare $graph->xaxis->SetPos("min"); // .. and add the plot to the graph $graph->Add($bplot); // Add upper and lower band and use no frames $uband=new PlotBand(HORIZONTAL,BAND_RDIAG,0,"max","green"); $uband->ShowFrame(false); $lband=new PlotBand(HORIZONTAL,BAND_LDIAG,"min",0,"red"); $lband->ShowFrame(false); $graph->AddBand($uband); $graph->AddBand($lband); //$graph->title->Set("Test of bar gradient fill"); $graph->xaxis->title->Set("X-title"); $graph->yaxis->title->Set("Y-title"); $graph->yaxis->title->SetFont(FF_ARIAL,FS_BOLD,11); $graph->xaxis->title->SetFont(FF_ARIAL,FS_BOLD,11); $graph->Stroke(); ?> jpgraph-1.5.2/src/Examples/staticbandbarex4.php0100644000076400001440000000310207437547531020176 0ustar ljpusersimg->SetMargin(60,30,50,40); $graph->SetScale("textlin"); $graph->SetShadow(); $graph->title->SetFont(FF_ARIAL,FS_BOLD,15); $graph->title->Set("Cash flow "); $graph->subtitle->Set("(Department X)"); // Show both X and Y grid $graph->xgrid->Show(true,false); // Add 10% grace ("space") at top and botton of Y-scale. $graph->yscale->SetGrace(10,10); // Turn the tick mark out from the plot area $graph->xaxis->SetTickDirection(SIDE_DOWN); $graph->yaxis->SetTickDirection(SIDE_LEFT); // Create a bar pot $bplot = new BarPlot($datay); $bplot->SetFillColor("orange"); // Show the actual value for each bar on top/bottom $bplot->ShowValue(true); $bplot->SetValueFormat("%02d kr"); // Position the X-axis at the bottom of the plotare $graph->xaxis->SetPos("min"); // .. and add the plot to the graph $graph->Add($bplot); // Add upper and lower band and use no frames $uband=new PlotBand(HORIZONTAL,BAND_RDIAG,0,"max","green"); $uband->ShowFrame(false); $uband->SetDensity(50); // 50% line density $lband=new PlotBand(HORIZONTAL,BAND_LDIAG,"min",0,"red"); $lband->ShowFrame(false); $lband->SetDensity(20); // 20% line density $graph->AddBand($uband); $graph->AddBand($lband); //$graph->title->Set("Test of bar gradient fill"); $graph->xaxis->title->Set("X-title"); $graph->yaxis->title->Set("Y-title"); $graph->yaxis->title->SetFont(FF_ARIAL,FS_BOLD,11); $graph->xaxis->title->SetFont(FF_ARIAL,FS_BOLD,11); $graph->Stroke(); ?> jpgraph-1.5.2/src/Examples/staticbandbarex5.php0100644000076400001440000000324207437547531020204 0ustar ljpusersimg->SetMargin(60,30,50,40); $graph->SetScale("textlin"); $graph->SetShadow(); $graph->title->SetFont(FF_ARIAL,FS_BOLD,15); $graph->title->Set("Cash flow "); $graph->subtitle->Set("(Department X)"); // Show both X and Y grid $graph->xgrid->Show(true,false); // Add 10% grace ("space") at top and botton of Y-scale. $graph->yscale->SetGrace(10,10); // Turn the tick mark out from the plot area $graph->xaxis->SetTickDirection(SIDE_DOWN); $graph->yaxis->SetTickDirection(SIDE_LEFT); // Create a bar pot $bplot = new BarPlot($datay); $bplot->SetFillColor("orange"); // Show the actual value for each bar on top/bottom $bplot->ShowValue(true); $bplot->SetValueFormat("%02d kr"); // Position the X-axis at the bottom of the plotare $graph->xaxis->SetPos("min"); // .. and add the plot to the graph $graph->Add($bplot); // Add upper and lower band and use no frames $band[0]=new PlotBand(HORIZONTAL,BAND_RDIAG,10,20,"green"); $band[0]->ShowFrame(false); $band[0]->SetDensity(30); $band[1]=new PlotBand(HORIZONTAL,BAND_LDIAG,-20,-10,"red"); $band[1]->ShowFrame(false); $band[1]->SetDensity(40); $band[2]=new PlotBand(HORIZONTAL,BAND_LDIAG,"min",-20,"red"); $band[2]->ShowFrame(false); $band[2]->SetDensity(80); // We can also add band in an array $graph->AddBand($band); //$graph->title->Set("Test of bar gradient fill"); $graph->xaxis->title->Set("X-title"); $graph->yaxis->title->Set("Y-title"); $graph->yaxis->title->SetFont(FF_ARIAL,FS_BOLD,11); $graph->xaxis->title->SetFont(FF_ARIAL,FS_BOLD,11); $graph->Stroke(); ?> jpgraph-1.5.2/src/Examples/staticbandbarex6.php0100644000076400001440000000413407437547531020206 0ustar ljpusersimg->SetMargin(60,30,50,40); $graph->SetScale("textlin"); $graph->SetShadow(); $graph->title->SetFont(FF_ARIAL,FS_BOLD,15); $graph->title->Set("Cash flow "); $graph->subtitle->Set("Shows some possible patterns for bands"); // Show both X and Y grid $graph->xgrid->Show(true,false); // Add 10% grace ("space") at top and botton of Y-scale. $graph->yscale->SetGrace(10,10); // Turn the tick mark out from the plot area $graph->xaxis->SetTickDirection(SIDE_DOWN); $graph->yaxis->SetTickDirection(SIDE_LEFT); // Create a bar pot $bplot = new BarPlot($datay); $bplot->SetFillColor("orange"); $bplot->SetShadow(); // Show the actual value for each bar on top/bottom $bplot->ShowValue(true); $bplot->SetValueFormat("%02d kr"); // Position the X-axis at the bottom of the plotare $graph->xaxis->SetPos("min"); // .. and add the plot to the graph $graph->Add($bplot); // Add upper and lower band and use no frames $band[0]=new PlotBand(HORIZONTAL,BAND_RDIAG,10,20,"green"); $band[0]->ShowFrame(false); $band[1]=new PlotBand(HORIZONTAL,BAND_LDIAG,-20,-10,"red"); $band[1]->ShowFrame(false); $band[1]->SetDensity(20); $band[2]=new PlotBand(HORIZONTAL,BAND_DIAGCROSS,"min",-20,"red"); $band[2]->ShowFrame(false); $band[2]->SetDensity(40); $band[3]=new PlotBand(VERTICAL,BAND_LHOR,0,1,"darkgray"); $band[3]->ShowFrame(false); $band[3]->SetOrder(DEPTH_FRONT); $band[4]=new PlotBand(VERTICAL,BAND_HVCROSS,5,"max","darkgray"); $band[4]->ShowFrame(false); $band[4]->SetOrder(DEPTH_FRONT); $band[5]=new PlotBand(HORIZONTAL,BAND_SOLID,20,"max","lightgreen"); $band[6]=new PlotBand(HORIZONTAL,BAND_3DPLANE,-10,0,"blue"); $band[6]->SetDensity(70); $graph->AddBand($band); $graph->AddLine(new PlotLine(HORIZONTAL,0,"black",2)); //$graph->title->Set("Test of bar gradient fill"); $graph->xaxis->title->Set("X-title"); $graph->yaxis->title->Set("Y-title"); $graph->yaxis->title->SetFont(FF_ARIAL,FS_BOLD,11); $graph->xaxis->title->SetFont(FF_ARIAL,FS_BOLD,11); $graph->Stroke(); ?> jpgraph-1.5.2/src/Examples/staticbandbarex7.php0100644000076400001440000000320007437547531020200 0ustar ljpusersimg->SetMargin(60,30,50,40); $graph->SetScale("textlin"); $graph->SetShadow(); $graph->title->SetFont(FF_ARIAL,FS_BOLD,15); $graph->title->Set("Cash flow "); $graph->subtitle->Set("Use of static line, 3D and solid band"); // Turn off Y-grid (it's on by default) $graph->ygrid->Show(false); // Add 10% grace ("space") at top of Y-scale. $graph->yscale->SetGrace(10); $graph->yscale->SetAutoMin(-20); // Turn the tick mark out from the plot area $graph->xaxis->SetTickDirection(SIDE_DOWN); $graph->yaxis->SetTickDirection(SIDE_LEFT); // Create a bar pot $bplot = new BarPlot($datay); $bplot->SetFillColor("orange"); $bplot->SetShadow("darkblue"); // Show the actual value for each bar on top/bottom $bplot->ShowValue(true); $bplot->SetValueFormat("%02d kr"); // Position the X-axis at the bottom of the plotare $graph->xaxis->SetPos("min"); // .. and add the plot to the graph $graph->Add($bplot); // Add upper and lower band and use no frames $band[0]=new PlotBand(HORIZONTAL,BAND_3DPLANE,"min",0,"blue"); $band[0]->ShowFrame(false); $band[0]->SetDensity(20); $band[1]=new PlotBand(HORIZONTAL,BAND_SOLID,0,"max","steelblue"); $band[1]->ShowFrame(false); $graph->AddBand($band); $graph->AddLine(new PlotLine(HORIZONTAL,0,"black",2)); //$graph->title->Set("Test of bar gradient fill"); $graph->xaxis->title->Set("X-title"); $graph->yaxis->title->Set("Y-title"); $graph->yaxis->title->SetFont(FF_ARIAL,FS_BOLD,11); $graph->xaxis->title->SetFont(FF_ARIAL,FS_BOLD,11); $graph->Stroke(); ?> jpgraph-1.5.2/src/Examples/pieex1.php0100754000076400001440000000121507437547531016154 0ustar ljpusersSetShadow(); // Set A title for the plot $graph->title->Set("Example 1 Pie plot"); $graph->title->SetFont(FF_VERDANA,FS_BOLD,14); $graph->title->SetColor("brown"); // Create pie plot $p1 = new PiePlot($data); //$p1->SetSliceColors(array("red","blue","yellow","green")); $p1->SetTheme("earth"); $p1->SetFont(FF_ARIAL,FS_NORMAL,10); // Set how many pixels each slice should explode $p1->Explode(array(0,15,15,25,15)); $graph->Add($p1); $graph->Stroke(); ?> jpgraph-1.5.2/src/Examples/pieex2.php0100754000076400001440000000074107437547531016160 0ustar ljpusersSetShadow(); // Set A title for the plot $graph->title->Set("Example 2 Pie plot"); $graph->title->SetFont(FF_FONT1,FS_BOLD); // Create $p1 = new PiePlot($data); $p1->SetLegends(array("Jan","Feb","Mar","Apr","May","Jun","Jul")); $graph->Add($p1); $graph->Stroke(); ?> jpgraph-1.5.2/src/Examples/pieex3.php0100754000076400001440000000203207437547531016154 0ustar ljpusersSetShadow(); // Set A title for the plot $graph->title->Set("Example 3 Multiple - Pie plot"); $graph->title->SetFont(FF_FONT1,FS_BOLD); // Create plots $size=0.13; $p1 = new PiePlot($data); $p1->SetLegends(array("Jan","Feb","Mar","Apr","May")); $p1->SetSize($size); $p1->SetCenter(0.25,0.32); $p1->SetFont(FF_FONT0); $p1->title->Set("2001"); $p2 = new PiePlot($data); $p2->SetSize($size); $p2->SetCenter(0.65,0.32); $p2->SetFont(FF_FONT0); $p2->title->Set("2002"); $p3 = new PiePlot($data); $p3->SetSize($size); $p3->SetCenter(0.25,0.75); $p3->SetFont(FF_FONT0); $p3->title->Set("2003"); $p4 = new PiePlot($data); $p4->SetSize($size); $p4->SetCenter(0.65,0.75); $p4->SetFont(FF_FONT0); $p4->title->Set("2004"); $graph->Add($p1); $graph->Add($p2); $graph->Add($p3); $graph->Add($p4); $graph->Stroke(); ?> jpgraph-1.5.2/src/Examples/pieex4.php0100754000076400001440000000076007437547531016163 0ustar ljpusersSetShadow(); $graph->title->Set("Example 4 of pie plot"); $graph->title->SetFont(FF_FONT1,FS_BOLD); $p1 = new PiePlot($data); $p1->SetFont(FF_FONT1,FS_BOLD); $p1->SetFontColor("darkred"); $p1->SetSize(0.3); $p1->SetCenter(0.4); $p1->SetLegends(array("Jan","Feb","Mar","Apr","May")); $graph->Add($p1); $graph->Stroke(); ?> jpgraph-1.5.2/src/Examples/pieex5.php0100754000076400001440000000114407437547531016161 0ustar ljpusersSetShadow(); // Setup graph title $graph->title->Set("Example 5 of pie plot"); $graph->title->SetFont(FF_FONT1,FS_BOLD); // Create pie plot $p1 = new PiePlot($data); $p1->SetFont(FF_VERDANA,FS_BOLD); $p1->SetFontColor("darkred"); $p1->SetSize(0.3); $p1->SetCenter(0.4); $p1->SetLegends(array("Jan","Feb","Mar","Apr","May")); //$p1->SetStartAngle(M_PI/8); $p1->ExplodeSlice(3); $graph->Add($p1); $graph->Stroke(); ?> jpgraph-1.5.2/src/Examples/pieex6.php0100644000076400001440000000163007437547531016160 0ustar ljpusersSetShadow(); // Setup title $graph->title->Set("Example of pie plot with absolute labels"); $graph->title->SetFont(FF_FONT1,FS_BOLD); // The pie plot $p1 = new PiePlot($data); // Move center of pie to the left to make better room // for the legend $p1->SetCenter(0.35,0.5); // Label font and color setup $p1->SetFont(FF_FONT1,FS_BOLD); $p1->SetFontColor("darkred"); // Use absolute values (type==1) $p1->SetLabelType(1); // Label format $p1->SetLabelFormat("$%d"); // Size of pie in fraction of the width of the graph $p1->SetSize(0.3); // Legends $p1->SetLegends(array("May ($%d)","June ($%d)","July ($%d)","Aug ($%d)")); $graph->legend->Pos(0.05,0.15); $graph->Add($p1); $graph->Stroke(); ?> jpgraph-1.5.2/src/Examples/rotateex1.php0100754000076400001440000000212507437547531016676 0ustar ljpusersSetAngle(40); $graph->img->SetMargin(80,80,80,80); $graph->SetScale("textlin"); $graph->SetY2Scale("lin"); $graph->SetShadow(); // Create the linear plot $lineplot=new LinePlot($ydata); $lineplot2=new LinePlot($y2data); // Add the plot to the graph $graph->Add($lineplot); $graph->AddY2($lineplot2); $lineplot2->SetColor("orange"); $lineplot2->SetWeight(2); $graph->y2axis->SetColor("orange"); $graph->title->Set("Example 1 rotated graph (40 degree)"); $graph->legend->Pos(0.05,0.1,"right","top"); $graph->title->SetFont(FF_FONT1,FS_BOLD); $graph->yaxis->title->SetFont(FF_FONT1,FS_BOLD); $graph->xaxis->title->SetFont(FF_FONT1,FS_BOLD); $lineplot->SetColor("blue"); $lineplot->SetWeight(2); $lineplot2->SetColor("orange"); $lineplot2->SetWeight(2); $graph->yaxis->SetColor("blue"); $lineplot->SetLegend("Plot 1"); $lineplot2->SetLegend("Plot 2"); // Display the graph $graph->Stroke(); ?> jpgraph-1.5.2/src/Examples/tiger_bkg.gif0100754000076400001440000004631607437547531016707 0ustar ljpusersGIF89a,BÕÿÿÿÿþõÿüëøÿÿ÷üøíü÷þùõøùýýöæ÷÷÷øõî÷õæî÷öúøáíøðùô×ýïäùîòåöðýðÝþïØþñÏøïæ÷îÝïïïïï÷îïé÷ïØàóíöíÐðïÝæðïãîæõéÝÞïçíêåæææîçÔæçìæãÞæäÕÞçæßäÞÙèãÖåàåÞÖÞÞÞÞÝåßÜ×ÝÚÑÖßÞÖÝÖÚ×àÐÛ×ÛרÖÖÖØ×ßÕÖÐÏÕÕÎÔÐÖÐÒÔÐÏÌÌÌÍÐÕ!ùÿ,,Bÿ@€pH,ȤrÉl:ŸÐ¨tJ­Z¯Ø¬¶yèàÒ»-›Ïè´zÍn»ßð¸|^ ÆÞû1Áˆé€‚ƒ„Cy]J`&&$.$z…‘’“”j_}]$•žŸ „`Fa|˜¥¥D˜¡¬­®l|$²$} š¹~B£ œ¯ÁÂÃB‡H|‹&}¼¶dK|žÑÄÔf‡ÆC`DΉ`}³´·ˆ¾a¼¨èßÓ¢éÛÕï°×î†ya³~a«çvÅéÚ^æØùë3žÁ,ÝŠäé£ÂE2e¹4 ÒcjÜ—^†Zå)ÖÕ©ƒ ¹kò-¢ ‡øöÙ9äÏbAOõZ¢Ãô2¤M&¥ÂqÚ•Dæ‘ÿ‘¶KH‘àÍ£?bÂ,•‘‹èp2[ÇeŽÐR•\DÊÕ×R¶Æ`e–©æŽütÕ)Ç„²vù뤣Z·ž#)£H\BŽ*¨q Ï]LêÔX…+åöý ¥WeT²^C™±g…Ù–áik˜çeQJ…%”0Ýç×ÅBS…ÊÏ3нA 7 T¹°ƒ—£hžúc„[’Þ•ñ-.ܵ”Lqså¦òm©;yf*î¥.Üì“?HL'ÙÓ#O"ÝEC¯•üggy­l ‹Wêq µ[¦è4K~€5ƒ/æÙç`F ‘Ë|ðÉÒ =,׆^ôÿ RÈâH9–$ääâÄ%Éu£a" ±Ú;u²ž‰8j…ÈeÛ2Êéa(—‹3ŽßBÞqÀ`nå褎|Åh›A&©‘Keó‡K³ ’O†—˜‘´¥hV¶–ˆo}1‰ÿÝ!XbâØ›8m‰¤žG2Ã&ƒ¾'}b\Ö`%v¡™çàQÎ4½$狜»ð¡¤^zª¢œ6Šfž>µ£”½”©e\Ť×àXbPêK§b~ñèy¡"O#'Ï8”+¹È¢am°>)«‘Zzœ"~ô…7r©¶Ô´Íf±‹ ;nF-éY¶^LBºÖ%¶a:Çÿ›6º[˜a1Õ7ºôxm{È£%cîzh½±îׯ™’&Ò¿ ðgù ¨p>çuo›Æ-¼pÃBrÛÂN\EÅãøl›áúo0m4 W¢Ä<À-s:r¿';XÎGÊÒ]i!Ès 03`´Ñ2Mò#+<ÅÎP ²¤ 7Tmµ X§%3ÂsèéÀG'ôÒ„5ç´r“&HuÕXÛ´]¸Í  ¬ à Fo-v>KqMï7o¥ue¸`ƒÕˆWý 84Ž+ ¤‚ 5°Øìí^ßCÛliçL«Ûk_Ýöé@gÀ ’§À‚+€à€kžÿÏ"Ò‘-›ßhŸÍK#l£nWÖpó¤)ˆà<Ø dn»e}$#eÈÐOß¼:§gxâV¿m— žÀ¼ä,°Ðú´OŸŽ÷‡|HµgˆÞ„ XƒzÖ‹/¾È• ST ¹ð€Ëûûf7»°Ù.  FNcÿ”H)ÚãMÍÆ@‚¶ñàp¦#ž2èÖð€(\^ëVA*pZG;š !²ôŠ&ÈÀa/߇$$_âÆ÷Åmk&L W>,Ñ€,Œ¢ ?0-æÅ¯½z›2xû•Á‹‰P¯väz’`€,ZwÀ&¦OrË‹ãù¢¨¼NÿQËè4¾þù„cOJ'D·Í/@c$ÔH6…t”£$åxGJnQuq„ȧ»ý'bcÕÄ´#JâCŽl"WYGIVòq¤!_ÊHül&à"ÀyŒ Žñtý{ a±ÆÖ¹Q•­“ãY¸<ç9óy•4ZU° [҇ì/Ÿò‹üÝ„ßæ DdR‚²@á1Ó÷İ2Ž,tæ9ÑÁàÐŒ¸b' #”á¤pˆÛŸ@ߦKš¡å$3h¢-ÚNw²Ž“´#,Ï—ŒYØò@ûԠǸ1@ ´m?£¥ ÞôÉ@˜Ð•cÁBÚ·B4¢ÿwŒcD‚¥Œfô<‹:O#>ÊSMÖ#ÝBzj)¬”¥ }"3#G H øJ8²y±¾¬(= $¥ >x’¬uÐTÝ‚’˜‚£"5©\*ScÕM†µ^IÍG ´ýÕ5œÙh¶d‚Ö™Õ–ëdgKß9IÊѬ¹¼éyæÄ3ÁN ‰S8Ày< "CPQÍXÁ–°”„*\pÔM)v±Ú‹…5…wÆlt5k9]dò8ÛY'&Õ¥­“'TkŽØžv ‚©%ЄuïÒ´“HÙQkëÙ†â6Э äÛßZ<0Úi-‚Z†>”°Ì ,Z—™ÌÂN—¸²ÿný°«Smªox9^ò¾4¢VUo(6ÖØ "eXè|×Yß´Þ—’{Ô¯+2©îbAeò-ª„'Lᢆw‰Q”¤ä> 7»l$ÀÚ#"á€ÉUøÄ°}éKV×ÃÒž^Õð ÛXÂZí슕»¯àƒq!FDqü—7¾±V-L_ðyç›±if/Ü@²ŽÂÑ™d/™É40 a™}NÙ7þ,‚ôâr’p ʆâ/W8Ça^¢óV  ز2‹Ù™a1T,t“ÊP ¹™/ž©ŒV£°%MÊ&§ð°*A‚ Fí¨:×Rÿ3SZ|›Yìd§ƒVë`Eµ¦øº<áðÂSy uÌÍi4tÔ@¢¦Ö´6 tžä;ãÓ mMÄA:|¤¤5…׉>õÉ1}TÌr¯ýûëpÌt¦éÛ9H'ʶÍ#7`ÀA]‚®"Nm⬥}âc¶r’oݶë‚èp<,)K™ àmƒš;q N›à€Zõ{¢ßÛP<ƒŠ[¼â6æ-JfYêÛ…ó)¢ÿ­Y—jñ4´M{/€`¡’+jÄËݶ‹Ûüæ°žðp5ÀÔ—`‡¿Ž!Ç×ïM^h¨¡\DGy _¬ sl÷ t`ƒ${æ<7ηŽÿñ Gd¡ËûšmÉ” —á26èA†{Ñp˜U‰ð~ZnÂ@DZC ñ™û½îâãéGkš¼öÁå,”€¶õ †¥ž´}»,º0Ôµí”xACP,°£Æáýýóá¼èÝæ³Ló–d^!‡IÍk³k,Wø#ãI"/¾ˆøL¤­šzlŽÜƒþ÷Á½@5»Ù•ªp… `}ë]˜ò ëתô{¿?ÝS$ éAvÝÏýà ßj_© ¢ÞºÅ›½›j§+):0swaQm¨'é!~•ø{AãT‹º¸@b÷Jÿ›È@b§Brd~¿ XpÀó„é—?x8F’, UQ·~µ˜&p4NõLÒå‹Ü8EÊSxWˆíbHh5åø{¼åwh;…'9}W=ɳ*À‹»5aÄ—¢ÅTG½Ø¨!Žªà=v¥~§…ˆ³mè3pl¶$a,ô†ò8~F£@»¦2Âu­f‚S”‰>)ö˜BœXK#VˆªáxáCƒçøw±F‰;ÐjVg€®öj9g[?ˆ59•Z™•gH‰˜’3àBÒ‘pveÿ‘&;¼èö4Ë“‰ý‘‚,јUñ(D5†ƒçj9·YÈ”O¸•[ùynóA‘µ2þ0p`qj)–¶`– A5*ðc.ô'È"Þ“Œö7 4¸¸aj‚ˆG1¹PEå…2ðHË#;@˜ZÉ€²#vþPj•Ç’-Ô‰¨PjuãÇO…™ÿ$Ô’Œëh ¨˜ŠÎ(ðF÷ÆT¦ †?„“ãš9À€*`4l‰ºÙ+w9S”f™2¿³6· dDhjã w‚I*ð|Œˆ8²À¥Öwã}¨LPÔ:”ƒšÖ‘VS˜ ˜1Ĥ Hvš,0EFž’‰Uó:N’ÿ)¸9ŽøÃUC¤ Ñ0W7Ðs¬„F¬ùj+e@ Ü·26}`–I£2pqÞ9; jœ``8©éTÉg†ñÁ 7ÒMm#ƒý¥ kãy|å•ç.ô‡'áF¶„•¯Ù}*y z“4*ðjõ¹@'-¥0|雚f”ì äEL÷TJŽ`ŸÜ;]hu㇠¡”šé#\7€¢9HƒV' ˜Sj>‘2$°3°>º–2Ò2–@55ÐgcÊC¤¶:kƒem2PT¯†|·ÖJ*Pq:p—¨÷52°“+5ˆ“úoK™³Ã^k† ”„dY–ˆÚÚ¦²sÿ]Ê7c ©¢t%uvª,`b^(Š•´<šõ…5p—'á’3;ð6 XH(i5®êàq« p4)öyI¥3áɪQw$vHaj³ÈŽ›}Ó$ü”jõcˆ ¢§ „Îù©:`u^x—È­¨—<·PTcƒIØŒ3×­ä/þP®) f9)ÖÐ’¢ø®_Q=†¶R³@t´ =‚¯€PûI9ã7šÉ£©Séj;•>…‘ ÛŒk|9‹8 @£` ¤é¤p%{ØBÄhR¸“˜PtPëáFŠY A&`s+zGí†lV·ª4xlQ©Iq­HWÿcÔ­½à/,A e9Xlàš›}p¢¸´t€“›jyyG%9 ú¾ãk| ª-»åØŠ0WÍØM‰“ˆ6ÐjFj“è·¹´ŽéÀ Á:6ŠÑ+!æzGw·6§P¬C n³pw!µ?sE‹j5êÑÝÑŒrÂk5­Å’è°ð|‰£sŠ€6`4ŸÚ4 Ã31@É«ÃH1Mè¡°. e@ja°n!Œ‚\hq:×)Qzp!,D hæ«v#¦iǰ ×j) ºòYja£a©¥ª t¨lìTÓd·rà„\…—:“ ¤ñ'Èg*q0g¥CO:à]K¿h’ÿX ‰×È娪)Ìj¡*É/œ±–l4JjqŸˆ9\ & ¼©´]ô¶t&9éÃßV¯ÿbb´$°i|à„'1 @ww¼Â·€…,o™ð½_iŽ+J;iŸÅœn–<· »Ì «3áK™¦@¢L¤ÅRæ xòºžM{C-:XuË7pE}ìJVcK,|³ Ïg’w ]­&¾3ô³mlbEU3=ü°›É>\ÁÈá׊­²g a=žhœOÌt;,9ƒ§“¸Àçí»„½ÌÑ·­<«@FcÒñ1Z-Yq}ð-‘àKà Õ\QÊ€„÷†ÿã3E;=- ý´Q`ögfià=C-bswÅc´vHùnbp8½” ÏЗ’·9ɨÀ¯i\“3Ô«¥ ÕuÚB ‡BëÅœIW8 r²nÕ³Óš}ʵðùÂú`è„’&à ÂÕ˜v Kƒ•m}z…†¤Œ=À ÐòÉ7.4a=ƉPÛðÚ˜w›ý #„5É&Á¦ë—CœݘÍ}  Õ=²e¤HY€“]¼ÜT£à7Њç(ƒ-o¿\M%ély9 LÑWEÕ‘nª ,}4ÞSq1­@ÅÝ ü<0j¶ÞìzyXÓ?80Nœ½IÊÐÓ@¯ÿÃyQ~ó/‚Ê™¶T5‹°>¤¸ Ì©JY[åž ƒ•´ 䬕Yß¾C…ÝnwsGý ƼãÔ[Ì+àm˜E¸—r îo<-l3Åàýk¦OÓMV§ÞˆÓе°67hxøËXÓä[uF‚Ë ¸?:Y*~ŸÕÞè:é›.4Úç`ÎÝ8¨³(’Ý6†ƒÝ${Ñçq.äžÀW 2äF3pUÓµàÞI‰miH¹ßý º,Ò2»"àåܘ‰Í EoùT£ø ù@t¯õqמÙ6/ t´$ç=žÙÑ µ÷`œ„àÏðWöýŸ˜„.° !V×]õÿ*`Þµ˜°Æ´¾©‰Žþ“À~ŸìóëOE ¯  Î>Œ”7hOæ3£TwÉPãÐýãqŽhˆd|{ÄÇZC=×z×Qæ+&ª*à ±-J !'¬Ø}LÍ›E"ÀŽ~ïÂ.ºUd^ O{4°ÕOo9JK˜Œ(Wíýƒ ¢¾Ó°¨ˆLbûW`Á;|ð©êbÉVᣔ2â>RL{޶¤ ¬Í}L=a+ôFÏÔ‘÷þò ”‹ÎŽ­ð¾u ¼Q~ƒ0 ¤È b´6ùThÍàœñ~”Ц>äÙÕ¿`€$ FU#ðVÇÔéN:üaŽ> ÂÏ÷M#âköÿç z)F`r¤½|Š=·öfçsÓË*ñ8R0'€­#…rŽC§üãD¿ÓFß?HoꓱYTuVcJF#bü‘v ò yqåx:`ë [»d_ky†@/Ò Ìåk¯a¶% 2cÜo»PL:^F?ƒ5&ðéLÑ?~ßÓ øÖnê%»žæ ‡Œpáå|p­b@ÏÇ&h·×ñv†î~Ô@ãFJ¥Ÿǵ¡¤k%I+Pq 3ÃprZ‰œŽ}´à4^ûžØãoêñmqgãÊ_X#³US £Ôô BŽV?  R"â6@`ëõnÅâИT.“2ç eMÿSÕ”J¦t¥> nÉ㔬–bØm÷—Ïéu@Ÿ×ãÙ‰> CÅ„ÄåÐÅPƒÑÄÑ„1Rr²Ñ1ä%óå’3ðñr2áƒDÅ…ÉåTGG%ä@e¨ÇÔTÐÅæ—G˜‡©Ø¸ÉIFe™¹yæ9'zFå£:¥ ;;ŒEæcàûÛN|œ¼î€ôîpðæð†DZ²žßÞ²“ðS`@JyØ ;É*#;läJ ¢+Cx„ØH²á!\ 9öqÉŽ:ž¹zÖl™ h9,‘ñŒ˜j1µ‰YaÂ9;Ë XР›Ø©8ωˆì>åËÿª¿:Ý“€‘/…F%hy# *ÁE¤¡a>n¤UÛpÈWÅ\Õ5ù oÞÑÞ¨+ʘ™4k†ÉÉqâqèâ`¨G"–¬²~ÌótÏé$Pû¢’˜*03£<Sý²ÁІ `v¨ÚQD 7<¾#–IÄ­ï\ø¨=¸^‘"g$I«c¸HÁ3³]ãÀA>Š©#ZjO¤P‡½˜7¯È"Pd­}szÌç) á"ï»ð*&x‘Tº)ɉ[ÚJ높…j0ĬRá ›é¥a¤º 5ìãªÌ–¹¤?ý™=IÔ;ñÄÌ3¤ÿ¸%J“U´"ð#xø“ ÀDâ +¼8 dž›+>°â‹¦ ƒÃ6|²^šôi4JBIˆ“Ýn€i°ÑC±©Ôû ’ÁÎP‡ÑÒ±IëM#€ÙÆó{æ‰@¨Æ¦Ô¦'¸4Ó@' KÊDÅi§É‚ªœD¼†²t«!^ÅKÁ 3ªñ&äóL%JKd׌J!7¡´¯ÿìΆd VPS¶wÔZâ%™f:C™ehQ”Ø7í£žt®z” ~Éò;ŠøáL3ýR½Î.3áSkB-"5Õa«‡\†Rcnù­ˆa}uÀX«Õ[Dé/ÿ…ÜåÁ'bœ¡ß sr²Ø‚±j”Ãe¥D˜G2‰V V®ÅvÓG.ù¤Ûi±­DdQA Pht(ÂÔ„¤´¬b Ž‘’®x\¨U»\ÙRA£(¨à Ù (ÆØ ;H%µDÕ8‹¸tbŠ+NoB1’áñÖBFY$F–‘“ON9ÇpƒüˆUˆ2¤¯%iÉ7C<Ä%XQaŽ:Q£.È1F,¡7)uÁÚk§FñS@ôš&l^ƒÈmêùì•AbÜ-Ñf•·vyhÛw€)¢Mˆ!õtÀQ@‡ï Št^ø‘æôÿtï¢=Wà3}ÌdFŠ·ÁMÝÙ¸ÞtÀ!ñ²‹‰u£wÅ^ÑU±7{sÙk…wƒc:w wÇÎwÑôÈ*âC˜ŽVÚˆg$<ó<5¼é…Aor‹B—+– i8uÉÉpã½x5ädãú.Á€­Ù( ‡`F1„Žo~ñËÐtâ`Ÿˆâ`§ø Èø£Óˆ$à—G@n™É XÓÍ1RcÒÆUþÁÝ’—häÀi3Jv’1ÎC8ÄmxÄ ÑEÆÚ› ©s:Ü "„z4:ÿa`‡æùßS8!,dA?äÚ9â&Ú¸‘ >`Ëÿ YH(¦­%¿Ø‘ªúè¦×¼mxÂøJÓ\¤‚‘“Òy%±­Odbx[Ñ_Ô¢6˜«…ÒÐðX£Ä ±”¥,cÀÐ@7Ã0Äp€ÑŒC¼ %;Ÿ›$B%dƒ`ÄÀû2ÙLG-,†“áÄf‚¢üà‰€DÍCÊÐxá”Ç\ÕG~s 8%³ A.ÐNwº³µì^a¹¥ðã;Â6'93^äçßÜ`T 5ÀB9‡1ŽQŒ.<`-1B5”ª 0ÁMofXhP8Ñ©®Ú¬K‹%Å +ðЗ¾Ô¥ @;[P ¶ G(aƒ’ÿ–ˆã—u‹˜Ù Œ`@ÀRЧ6@ mè.yÉ: Îå³Uø‘Ì…Pl:@œ âøQ§¸@Aiu/åR§£47ÀÞ\‡T¯yÅ+&0¨²lÑ@FµAV„0bÆj@O™Rœ0(A;PYË. ª˜ª¦ÑsøNaŽñ(2ð'„Á tFJÙ­¡Œ*‘Á,lIC”›[ò> —YŒð(À!È«e]ºNãj‰>;( ›F¶ŸÎEM¾(BÀ1›"”À¥xªe'`lÖzX h;Ô Pœ^tWXkÖÉ€?M#Ý H†2ÆàË’Ôe ¡hq‰L6²•õ´G¤Ûdø*!› P€ß CFÖaò¬Ë°Oæ ƒ!6£àcx€K—j€AC`h€Â^‹cpëhVèH¥æ5Wÿ¡NI †£ õ8†›Ü|1ŒÏ€«w4cˆÑ{—ÝÁÅèM8ð-,`wºÙÁ]g<ð"dú”Ák]Æ£”OTè Ê 6ݧ&¸ žÀH]jS»Õ Põh_à?$£grNÄ  ÇTŒƒc®ãXé”Ñ3¦ DltòØtÊÆš-Ó.·³_' ¦Z®(V„Û~àujÁéAˆ(–+,t[ÀÐø²»Å±DX“ÒäÄ<.Ò‘öH /³°ùŽàg@H“ÁŒÓ$Ö4€lP&u6¹ò@Ù7ÐÀ:óä7(È6QÝïqäÿãBEÝ@¥àÀnù–¹ÜÝÐ|z¸y™ oM}½> |f˜—y¡ dPEÑ‹@ð‚‡,¡À\OÌp þÒÆfBÖ‘*Ü ÀÔ¥ï{æ!»Õ]ÞnÍ‘ÚÙ ¼ÀîSp @ wÇ;ªç÷>¦+õ`õ"2a‚ÂÆW§*ˆBİŒŽŸ‹MJÀ‹Ó‹'.…ìªÓõöÅÅ’ùæÏpÅ@dZ~™>ÀéG¥rÀ¦=F±¹cÒïÜÿù_€Tw/f‚$À„ ÕìAvt žëøÞaÍp¡ ùðˆ?jödB°Ï¨ÆR}Ž2Î=ÿBÐNàVïìTïUšA *-ÿMÐø¯ÿæ`(ª¢QPH:ðA!.¥7~ l„ð&grÖ,ùDñe&6ð •"Ç€ã%^‰ CpôrÀFpÉßïš'äÀj¡Æp kpQAʨð¡)B&¸ÐtÆ„×lUÜÂWødEF·˜°]”À ôb„à;êm ñ#?:‚]øií†Å %.Dúðü®I2 ø&ã^(邎¡ðêðçš&!c– ^áôŽ ŠAóœ` ¦`Í’àS𬎃´ ~iÀ"QQT-¨¤O'ŽLæRQÏ¢ÿÇFÒÅ‘ŸÁ†b#ÂÀ‰­{¦ÈÎ)¨æ¢EJA”<ìDÛ@FÒDEã"Ÿ¬ª…|‘4€†‚ŠÐHTáR”-›\À'Ÿ°ŸñêdO  &ä 7´1} ìpcìbIèy€CM´äÉÖ‹ÉaŒL¨í'ÝÑõDa™‡ˆB3Aí®I£@D±HD3 Ò„T`ØŽ€¸·rËìT¥ ˜ 'Òᬩý㙌qrÂh8² ÂÌ@ÒTm2Hïø'ì‘„§!Z# 2¦®±á<¦"Ú‹X¦Hª`w†#‚ŠlL)¡ÿ²Xʇ)æá(^À14Axßʦý.¢LÀR,lH`e¡0ç" ì ðâÎPÐì| .óÂÅhèò áp€q\ 2œåp@öñ*¿£-•€,gâ ‘‚xL#We¢¾YF¾˜‘!ÿ„Ø.„5S~¨Ì ¦ÞAÙl +{L¾Ããø#ZÓBΑž¤IWB ^ls¡±ÉRÑ'ýRáìF±Ð…s8Ñlº£Zä|ä7žsä #†Àò¾©®°3.l¬6­Gd'5ãKMãMžsÎ=ÃhÊSV퓾·ð”n`á`3™ôç@Dó5lu.6lÞ*G†€âf3j‚ÄhÏ© †õ‚Úÿ6\æUXݤ h÷%§Õ8VtbI î#³5+ÜðHÓkÁâé´½ÊâÜÁ$c?Á…QÅ)mz„hã5n'D¶ÆP#ª€-qAmßæb¥ná¶Àß”ÔH ƒ$ 6Œ‡4Õc?>Ó¹æsÔbOó#rIizà/-vîm5wc÷És¿ätÃÎF7¾‚+!6nó)¤ôÄ `¨htîàñRP$!È F-Â7Ž€gëQX•àvå£ÀA2Àæ'Þ{Ä•m†gÁ .˜•Æg½tf%“Ñ>‚DÆ\ PâÓ*O†VèÚK×Av]€/)‘8‹óaÒ)E¥ÿ¥Î7ÒsJg ’Œ¬2"5brì1õwIANcýÑCé+¸g€;µá² >šŽpSV¯ Ñåµ¾4[«Ìbü6"ú3-|Á-äT\A`|Q) N 'R¹crÕw<™@]¸h?•N‚FgNxÍôbc1¿QX®´Ô2+0á=aÖDF‹i¨S>n§ˆàϨá²È¤PGxâS/Íî.kù7nY8slYiØáZQi“6GÒx{$h8B¬*_H4o€/q"08v½ƒœpE5"v¥\µHÔ{œLŸ\`°.‡„CHE‘8× .ÿo’"óô t]KÇרÕc/2•8643†ôÑ3)îgk¯²f$ÁÚgŽK-çD.Øb±Ø÷"dár­3qXü%$n礘Á•SÓ‡Y9#ÓÉh+â‚/rE¿.‚@©a*±<âh‘½Czû‚%,¯¬ú–TÆ6 ´†pHŸ4Q/圕€t˜ûèžE˜GŽùSc^Ëq™G‰Z+Ó%mA”GÙ} au@/ñ Žô €08}`ʤol)d˜áfÕ5ó‹àákßÄvwÂ\ ~éÁøÈà[úÑžEwvþl½ü¬@Õ+G¸r¦aI%ÿéœÚ.ˆÙkLý`¨µYÕ€ƒ>Gc·Éb&e ü©:“  €;\`¬Á[œ€¿Q-[ßÒ ‘‰-w]„ôB.€ *8Áë†Ï¾'Ñìí•ýÚ"mèDØæ’u™+ ç}y«‘“ @ÀD‘„ÕŠ…s³h£eOô}Áø u.ö]:»Fì‚é2H3—‚¬²Yy†"ÇŽ¡¯][TP‚[!%® ˆ!¶ßÁp<ëAǪAIz{èÖ ¸·à[Û‹…î rY@ÄA¢û¤759×¶*f1ƒû‡èQb¯j™²ƒQ—B=!%!,"e¸ÿÐ$#bgä‚yž%0%p²?'ðÛ1õõ˜œ¥5¢–Žºeœ7F‹h|ñe7¤e÷óÉþ?†!"ü~&| òÁÁÆ{ájÃcfTŠÏœÎ« jÀìHàÕö×'ƒÉÅ—WÁöcý7Û@A wï`u<‘ûiNZ[z‡ LrWV+y$|Á@& =*LX²Aü©k"RnMXa±i8ùl°Å« eûŒ×7Ûd¼'çõòð8ÆŒæ°VŸÇf‡£€ç'N¡”éÜ~üzwÂ<Ê«p¥Pg™œ…ÐÝY½U}ÕøÅÉ·e€2 ŒV‰ÆãRqPÿ÷œ6ÓÝ Öõµ8Ù2?©Œ¡ÿ`ÔUóf¥¯pdlÎpªR=‚žnÀXM±e])\ܹ"è.¼“Hä¹=FÅûetYÒ?®-ÑzƒŽ÷ˆ!Àin´‹Àâ1 2±¶×hâ—?ÿxñ½CP›ô24¶Æ¦ycK/ÁË“,t3"ŒÈ°¦GˆàŸTÀ.PÁ|þt©x(c„B_Ú€ªgY6Ì&‘qH@¬A.ÚKš2¡3àl|—¡Q…ƒÎcµAÇ›¤Ò¾Wâýs€£§Î>š9\Á—PþSÏÉêËGwm§9ìõŠï 0vävzAàwСÎ둵È)¶‘³ÿö—Ðÿ¬YÖ$?LåžJp#Èöæ^áRÅÈ_…êÁöšæI~±#´›)Ù*Z t¼qTÙòx+"¨ýƒ—àR4ô¬ÖÞ|BÜŒg‘kOæBîS†DIí†RWi1)²Á¨Âõ¢Jô•/e·Òa&à“œåˆñ £Àˆ=£põQ|#_JîóëCcõsEvÚGŽ8Šº„ ôµÀd¤Îª-9•ÜDµ´b!°Úãu–"WsbÊ ƒ€sÞ4¡K¢›Ãг)ÐÁY¼žê‹8+¯9Ó¶‡æ(ÒC­0B’ͦ³™2“ÐÅãÝ¢Ò©T庩TÔ›«KêºlR×w;5ÿ‘ÌÝ[¯Ý3ã$!½ž¨ã…‰ýó†m­a™˜|00Ð06:>BFJNJ~¾Ð݉I½ü‘â|¾n©Ìá•Eíì`Ö}ÈÎÎb˜t²=a(eЙ\ÝàäiÅQ‘X%ëP³FeÅiì´Ž…Ç©æ%‚ãõÙ환žFqu&.RÆËÏC¾`ZïA7kÛ¸ ùûRÆ 6PyˆHq‹­†B:µÑÅ£“ ˜]C—GóàÔ ó’=&{Àð©s‚Ô´còÃzNŸ6j ÁChnQA3˜,ÿ^A½ò¦d w†¬Sh':Vª¹ÈPVƃ.ˆâ%jÆ«•-/¢õ¥£óΞƀ¦gK1ë9ƒÕ®a‰Pö„ò3³ýá ¸á&VO@8ÑvžmENÏaÐÉ5$KŸ< qòVDÅLàbI[pF…˜€Úe2àÈÿ ¨e’À‚ɤbV}ñ 3g…’?;"€!t ” ˜’tÔ “Š‚!2q…P$´Ãmùe[j¨ Ê‚ —_àE¢ÂdDva°HÄ‹Tâb & X€ Ž9ƒÚ8z éÍ\¤q˜YBö‘ä:ƒÔ°#8à|à@kÿM ‚ŽX§Vé–ên ªÃOYw˜ Õp—Uik²ˆ=Ÿ€…ƒy^hè…éˆD¢-Š}vƒ™uÜxh¢—-ŠA” ÑDdwÍEpË­2Mwc“²0 K¡NùL’@fÁª¶Gç ø}䊘“þAÓ?ËÖ‰¸vH‚¯dìZ0ÿ½%m¬7üÁ§¼T„æ¯oÀù±i¹Í:»2Ôj& Ž´Ch0âmÈôð 7ê7K"æJ….T€U0) rÉ/{YtáFSøÞE¡”–Î!·M7„ƒ/ð¤—Güß9w“¡Éjp² /ƒS# c³ C+/ê ÃÆ]óñ-ƒŒVcC*r˜å-¡³Õ¡;b°©¹2ÃFsJëp¢%—µÚÒ 'Pø€EVÅ83†þ±4Ó³èàÃ?Cá äǸR‰^¼u5cçFgQÐáÂòòd—}Ã[c}¤6Çç@m‚¹év-ñ±ÍZ”HKÀ&^5ÅÿÞMr |Ì€ËCU²yᵯ!l‚ÿ*»"ƒ]ä°F¾2ì¶P ¡Ó†Þs™‹0ÏKøÒ´qÅÂX@,M%щÿ¸#‚rjTÿH€“a£ä ƒ8ϧ4Q©ƒ,mB øk‚“"C™-k”Êðìe,%1ÕsÂǦ¡%ëgª‹'†¢Ê‘j~ ÒÃ…ùYN+šZþ¦†'ˆ§#*©ÍÒH¤18' äb!€s±<0‚t0oáA*0ÁA€»bph×M2B§hO`R;Q,Ç%6 Á*8ø ‚Y¨çjä‚9šÃ ØÑ0Ñ«"Ct)"ÿ*m\›†Ì!#n:Ø—RÓ¤¿Üà!Z†JÐU à ÀˆAU´¯„S9R¬J¥ŽÚhÉhvpP®÷FFÄ1NͰc ]H;Œnk²HhƒC ,‡¥°£žƒŸK’ ]¨ $‘CÉY²Xp`BG>ƒ @(F`† ¢ r ¶Á™qŒež«0ç­$щ&íbKÌzùËGÄñ.D‘ýŒ ¿’ \E1 “ánW °‘’15áæxNSæé‘/€³ ÒPC¶æMá-8-H€ÊT’å¬)#fh$<ˆâ# =wÚòÌÿˆdèZøÙK_þR{ÁÀ‹9†QG«8t)xN¯"4ƒTt#øòµq5*SCÁ ©µš1SC©š´1ÖIYœ 'úæÎ'Ci*Q²TݧG˜C·–7K}àÈ+¸à %³=(B ºŠ˜@›ô³cZ·ßì¢ÍÌÊLüá´Ï•ö4܈Úú¹vs®‚™Yú¡/߈¤"/[=Ö1ÛÍBáÝN³šôR ýJÖ(»Õˆ3öÁ|Y$Õ6>pÚ Q^pÛÐ/¶§ÁQG5l cGÌ$P„ü… {´Á l[R¶]ÿ°m7 I”ªÄUè-ZB‚ $b2P×ÛY.Y8À_˜sUºÁÆ*ðIë±E4à"0…§×åV)Ñ3l¨44G¢ŠÃËší EƒÓÒë ¨ íQPœA–±ñdɇXDƒ¤³’š r¢—Ϧš ¦ÃyUÒö°€P)hð‹\À¶†\샑öÐAé²å ùbªc­Ë¼ ¡?^˜ÜdicF˜£fã±nC„§â¼ÅíZê?†)ÙÐ9 „þ¶èä+åö’TǦÕ`›„ —{XY¹ ©Ž£!c6Cn6ÈAÄeˆT“š1O5±à-’ñHB€ªÿ5 Cs´µE”¬ƒèÆö¤á%ppƒ°ýé•::Nf´øK>â/Ó\ö&nÁ,¬@¦m4„$UwZ1Ñ"‡f –Ç!Û»°5òÒúÏTÂM»zC*h¨£-žÔ.&$)0ªå²â…pô"Àö•in¤9€¢wÀŠžïtœð›\<ÐƒΠ”OqÃÆá™Tå°eoAqè IßRA6èèI²ŠÇV˜Ó? Þ¥®õ²×Ĥd.°ÒÏxy3ÑdqǸ2Þ™Hú °–]lÀ°nÌ@!;0.âb•Íá ë˜Íµ²ÿB¼‹z7qskð pF„Öâ5 ¥Bè@mQI’Ö¨¢Qw‰]ÝôŸaõÖNý`JÇºÏÆr¥Î÷@’‘UÚ-ÂU±Ópe`³²Tä.ÓûCCkÛEö¸éZ71ȤÕ s—vägx'ÕK$Á3)i3Ê>g!Œ÷V:&ƒ²Øvêéà„‰¦Ìj›4ÆVÐóFÏÆñxïo3Þ @°‚BH zý…µJíŒ$¬N­†²W¥wPøÈl0€T0ÞМ´‘\˜ÅfE0AT®µÝŒkDyåQœ°G¶Eç„ÁБÁ`ÞÜÉË#±O(MAø-ÍÿµøáHÇÞì ‚ôÈ4–cùˆ½ßH¬Äª\È!`QÆ•„!hÞ)ôùÁnxÆãì;Ž–t¼ˆÝ*4¢µ”ƒÿ´Áˆ=ðAP$€ߟ™W1Å*Œ 0TD}°â$C¨ÑI ¶È8ŽŸ«,›Ùžn„Å+–Ô0µPJ¾ý"·èZ€\#N„ˆÉŠ r‰ ŒxAá°‚K–b;í”ò嚊LÛ:ÈElJ×hâ=‰AXVoGc%zÑšYKˆ¥üHç5b±%„•½eEÏdÜAƒ¡Ï¡M`ÿ^bÀ¸Zvéâ¹$#|CÝ›/`•}Šà)Ö 4ôãhÉ™Èq*ßþ‚Á¸`#YE8ÌA‚Îæ’À?ÁÚ‘ôÓkÒÚ}ø€hÂM“ÕíÁ%'8¥u“È( L†SHá‹–‘Hf⨘@É çÔ²1 · Y¥í0)K–£ a&€ôˆn™ãtá(¦pR&öÌ& UÊO±Å‘4Es^)ÐÕâ†eGŒ%“…Ôü(ØæCÁG’Œfœ Q}X·¬ÒeÉÏòC2† KqúÕ2Õ@Ðè_“…n|%N$ª´Ôߨ™…Ø#=Øÿtvcñ1¢Ap‹~"N…\6§t‹)ª‚ÜzìW~aH àBkMmÙ@‡!F¬È¾jsÎR•ÖeŠšÝ „O¦—2%- W¡WIGÑÍ Nôé,Ü„äH«/P¬hâÉ(¢^P¸æ¾z*¸NEclÁÍ€¥@ßSÖËZN#=d+Lb<Ö©‰ŸìVÂæuòã>€:0@š\Ë ã ¢Çv! ’Þ…F@§¦ÖJEqDñ`ÀGúÅóñÁTZ¬¾ OîµÚT< P$ÞŒ=UƒvK-mÈôñ…³Z„ÜÎËåÆx(ªZuQÜ,0íÚŠ%ÿÉÒTC&:Bã!C~’í€ÃiPÏ0¦Œ3Ð^9Zäe!E5ñ¨Â$Ö&|ª“&ƒ*¸k@ °§>VTJËNË­-n0@Û@»R˜¾%ÅJZŽ_f/)Haä­öøáÊÑÙ휆Y´Ø9ÉŒ6®©úhYH¡8´ å6걩ÂxL¯|ÂPé®jmçJïY´(»å›ÇI_hœ’¾Ûv‰Â9žìêf,í­WÄÁJ‘…6ù-·PÊhìœ{ðèâ©l„E ÔÀ[¤FÑ’äÜÚÁÖ÷šãŒ™z`ÀñÄ ñEIlÒ3`ÖÏÑS‚ÆÊÝUCód!ÿSù’íuk¦¢/ JΠ’BŽË¡knH£•H-ô±k\™D…Æé þÎtrA¬•¨µ ºO+PÅ,’€ $p' ¢, @)5*Òƒ= ˆPBJàÛ|¸™>¶EÄ䇱tp¦˜¹U*à4èMXŹl+ˆå·4•žÅTài¡&¼ÛúBÏ £Hůܽ…‹ °XGhQÑ]2!µ¸dÌ4ÌÖ4wJaÒ ‚%—‹rEFÆ ``©i⢒€ UÔ È@lEÆŠ¨è›Ðqd–w™î•61§Z¦€Î¤3ÜMRúûJ™š*êõƒd!Gÿ›yªkꃔŠLÁY™ÍE)_°Ê×¥ÌÜ…¨ùM(ÃgVá-CL¬X˜ÅîÅÚ²!àÛ º®tPF®EÍŸ&VØ1½!²Íu"@eÄ#»¤ÞÚìúä>NóŒ]f#4_6_Â$ŠÌ8P”€†’ ¼…ùáEü…y…ƒ$B:»P†­³]ln(ï…%(rª€ª‚k‚+ã3]úSÛ AŽù³¥é¢TXÖUdC±Šõ‰á8ó¦hÒMs–-Øö¼c oÀ¹,ŸU”ídØ2ØóÁó¦`€CQÑy°ôÖh`}rŠÎu«@ü¤bö’„n¦øâ$ÿ0x± :õ? ” Ï-Þ>$?Ül4Ýž 8ôCW ÙÉÒUß,Ðõ)\SUð¸ØÎzÅ`JQ#<ÏE‡$êÏÊWºÍô|OCä2QYAÎÜ¥·¶Û{ä¥>^ÂxªøÙcá™Ê‘HåúIƒ? ˆ¢»@¶cOð™)=ÝdCi­3˜s¹€ÂWwHmÊ"ޝX‘h/GC”öe lÑ„`‡ÔiLClå,é4OhøöqUA’3°°€”L¸aF¸¯E]TiºÜGZ_*÷{osÀHMtKœ;¡X0È ¡±‹¬Ã;ŸõR˜O†58ë’·2¾!ìÉ‚“6ŨHÿ`È¢€0~,t|ÃUÄE…/9É)7²æä^Çá¡*••˜™›)·ÿök$p ‚gâõW3+-lL hxM @^„ö…ƒ3€jdÆxxv|·ßpVTï\(X®"êÅN%œ•LÞÑcÛM?1‚)r~»Büé66TE“NŠéÆϧfìð+j³Ê‚ ÖŽ´C(‚ x%ÌB]ZhM›€|Qq ôVEpëAmV­åh{ k ù§"ùOƒß¸VDÏtмÕ7QNP~çM8Cëø|P ßK[ü]uQ‹Cj€~0ЕËé©•¨€½sÿ­Tz9p†h:[{ hWÔ/=• ÅzɤÁÆ­­µ 9š¯9(䘦«›s;BÑc Î2ÏÆÐ½³c×t<ºï²,»'(kaEµr—i¨@ 3Jh8v+GöM¦¯Ç{$§¸ú̈y·ÿì2WIÛ5±ºŸ_¼ù:gT8èeì_éIQÃ"©7–¼ø3ÚÂk¼|}ˆ’HU#pƒj䛢ºHع»bÇ„³MótîćjÊ@ì(Å$ZÔh’{7HhPÈðÛGjÖ:¤hQ©D6ĹðXÌÎ9”çÊuÖk–. ê9 ÿ`¦» ]¸ý™Ò©çž7@Ýý¤Ã#·CÛ&üŠ *~ýƒÌÄÇaw@, †’Ðe@O^4éªG²5g~:^1{y³Qk?´}ë®ä8Š9ÝÅ;öm¿« ïæ é0€Ä6r%z­è1c18‹ÑÙ6{€T/¤vNtÇ/&Tl7½Œ”ç;„+ÑLðšî(á·Õ«÷ä„foøð¥|^\¢0ˆ— º‘ñÏ‹e¶Y†ãÖ:æ#œºaÀ„Qd°(-ðì(L¨ñâò™íìZoÞ¦èⱨß;ņú¶yB"Fª™j`™âJ' „Š4—ªâ’”dÐa¥qÔ‚ÊÿÝ(lçœãðÉ} °ã’G´ ß 2¥±Ëã‰>(Kö DE—1‡~Èñ1Õ‚ÑäC„ RqöI *¬t­¤&Ñëé(Gñ’&v®T”HÀSŸ%üê%_–›²¼bbA˜ðE'U 8ä(/!TQ"ÁqЪdHi-Ýzï&qÚ®(ióÐK MtQb%Á@+ ¹šôƒƒ=µ¦L)iD\âðË„ö!ø`êBVÉÎUXkP!¥‘H²">%qõ¢¦Î«GC½<áðW`A¤°X~ëè>º#ÀÀHÀ,•¬Ú˜1[¨Åï˜ëjŒ0Ún÷—Rü½Æ‰-ˆìH).¦±å(¹dsfEï§*L?z]V®HÄBbå{t#\´Jÿ%ÛÜhÂw7ÿyèWÆ$xá!ïï†$mLÆôM ¶#ô²÷èéžØŠVø P3Áe´'+î}D_ís»ÑAL‚껂’(žÉI@1Þ@ ‚18„Ò{`Ĥ¯UÄemd ×e…†Et%X Ÿøh‚x™^;äÚïXÖ² ²æL:…üŠñ”é8˜éæö•s|9¨D‹‚äÂÊ`-3\` •·8’‘PŒÂY…h*˜b;Ð:Ž× j,‘‰w(]®¸¼0Pãcë+‚ÒL¤½!j;bœ½è@1"‡<û2ã`˜Ù8)ÆÙF²œÃȉŽ=ìÿZGö¬K0Гx¤Óž²£FºÂ‹_cÕö¸8F¦Ò(‚i˜½–@‘޽D9É F/U4ÁÅA È(ðˆK°î,„H œôYþ#p­¤æ¿͈ [žƒúò Lf©<Õ\GÍ |±U®ÚÛ¬ ";lJ³]ä\døâ)2èoð .!†ß|òî@BÛ‘Añ íǶÏ{ªc•´sÇD¯ÑY4plÄK7FrJ=êÆ“þêeI/ALWŒ˜c] («?‚É ÄhM1jÎ"l3=ûè†3Þé…߀Á%•Ó@GɈ˜ª„¡ƒ€‚CM›F›8EÌFÿó³x}ÓàtJ}CÔ>¥Ô“ƒI´T8³*•j[ƒHÕ:É #LH^òJ>~fD%@ËçÔD¼Š™ßÕ;éVÄò¢G¡n “üô«j@C¨..©„=+3Ñà̉0 ‰%m±¨ÚK¦(&råPÍd™(‰^öÑ ×$#ÐåÒ,òLl-mo¿·Ø#`¬±‚B"$ë,Þ^ fÊ-é°jK©…n/­²zM#¸è[ì ®EÀ˜j¯š…Öâ¶Ë­•Z=L(s™ÛKIg€‘]ø* ®{•«cá8&F¢¤²­`E‰ÜÕ}ã Üá,Çv­ø&¸qCÁÂõdÿ4¯Üá7±EfA0L [..é|B)™ÙaQ¥è² &±ËÂ+SÞ£ˆZ„GðƘÈ@‡£ËÞoí•P-q¯Ô`?¶vУxëô—ƒÎ<Å<Ä8kJ4 ÉÛõq• 3‡,C/l.¬#%3Icë4ov½‚'ÿbfÇYÑ1¹áFbBÿ]꜀éó'+h Øà¶¦,tÿ®»hPÏ’•gÊIOD•ÈW"½HÛ,Wž›üÁÃO‹³B}뢴â À‰ƒ(êâ9(HŨ¶5p¢°ß1ÿ›ä }šLíP\G{_;$®Æ¶xz|ynÛ Š˜˜Úx™gá:Æ2ZiG|ótûêŠíüÈ•¦ñ©lò»û†Ç¨—n€#Ñ­´ñð#„õ†‹Ë04Ýl}c §”ºêÒdÃ?±-‹d¨;ºÙÄ—š…ôâ+Ç,Eoh‡>Àa§iáé]R«ÉzÓw§gËò€³.v<1>²•»Œàµ‰ºâ÷M™rj$è§Ðât–s܆ÜÑ2- 5·ìuA÷‘è©ãZè4~WÌ‘2¤“Â|γjÙ}òî9Úi_ù4ÿ÷ËX_mëæ'šÇ(æ¾;Ýíêd¤H‰FÃ÷´ûÝv„ƒÁM±“¸gÞpö;ïž#uÈ«[ò“|lfctl>ó¾ÆÞeèþéÐ÷ÝåMôB¦M_ÔÓ+õ\ß}Äÿ  g8öA_ûýâb{ŒØÅ±¹O=áC1ן«ÍD}óð­œq?Š_Ìò™/ÚÌúi8W 4ŒV³ŒÖ¿¸ 7\·:{¿WOr}.½}éê³?ÎTãxíÞ!›¿Ëü×ù€‰±&´Ó?ªkû±]Ù:ö¿^ùO»?õK@\´Cz?ÿûîýA‘ÀBɈ 0ü“… ;jpgraph-1.5.2/src/Examples/tiger_bkg.jpg0100754000076400001440000001763707437547531016726 0ustar ljpusersÿØÿàJFIFKKÿÛC   %# , #&')*)-0-(0%()(ÿÛC   (((((((((((((((((((((((((((((((((((((((((((((((((((ÿÂB,"ÿÄÿÄÿÚ ú¡ÉÓˆ,W'qÄ&N,‰K‘ÓŽÀ8u$& ®ã±Äv!ÁÔ¹, ˆæÐ‰<Ï'SqØWÔ‡=æ.Ÿ+Rl‘@fM*;[‹ Ï\É>g§ÃuvžŒåÔÌÉ›®6õLÖŽkécv ê @‘!¨î¬ò›:ÍÉ­æï^ÑœªŽx™¶xuOI£f ­ÔQŽNº§²7çäë4ò3Δ©£©)îÈMeÕt æ†(MÌ6Uö² ³íu^¤º¢Æ\T[i² æÎ¯KÏõ¼{²—Űe݇p 9£5u‘f~Ó]|‰¦îMbÒX‹_žœK’®ç•[Öa0;ôüÍ,éÉ%êù*ôrkPPQ&VŠÌuJhœúN+¿’¾Ð[~NŽ(o†2ë2ô^‘nk`Ç·“guZ°2õÕIݼÁÞmJ®Ëikf1ÀsÆ›¹äÙm:Ž$0Ï=–ÎmI»*[íͨã›+L¶s ºüÚ@TO$`Õ‘:³š3¹'uŠÈ"B2mƒÏ¯Ô&=I_s æÍœ'VÄ‘ŸFD·F[×®f +²³nœ› 櫆:=>O/ŸV³.™õ_d‚P&1"& 1z^Zk²›RsjåsÝgE6wÁŠ¥úóèX  "‘#Þ äК.ÍaÜÄ–܇ס/²%¨€ ‰"@8®Ú̹¶eKoÁ'£^1wX–ìªõ° H@WœLÕ„‚o V‡aÿÄ$!1 02@A"BÿÚìYeïîZ-nnP©vþúmX–o:É‹Y¿qdóys{o¦¥R^ãìbÏI©˜sìNM4ï=^«ÏÍvq|‹-–EÑ9o¿¢óÆ…åJ¡>¼Xß\|½v“7ˆ®œ]¥ÓO֞Ѽ°Þø“iþ“»YK”µ;/¡uëâÃIf¢R²Å(ix„Ë£’Dñ-'Y*!HiuBl…¥šQ±OÓ•Ÿ•¼H¨‘‹‘¥@£J+¦ ä÷#»¢yEjs<7I¦Pª¢§£ÒÅÑe–[0õWcÿIÔÌHìa*1¹†å"¿‘Ë}³EKŽ´B}žLO%3S„Ýbó‡âOÉsT£º|”#ëå 8«š4#J¡‘d_[á‰“ç œN`ö1<£äEÑ'—Ä§ÏøD¢4C–D–εFK°"ú¥Ã[Ã+%ºÃ$©¦Y.W6>‘ψa“[";Âì—8/øÄˆÈ±u>+yDªK‰&Çeº7ËíæÖTh4 iŒÙ††1MÔ]ä¶##SûG­ŠÄŠ$†&.2E£SÏRTåJ{¬NS´MJª6³­¥¼_8l\ôÏËãY⽬UT²Ò‡§ŸÜP¸óæE¦=ãÆP{ýàC0úñ8O;ÛîGqÇi)D³“LÇ’FLŒhÅóf™%y^ã2m’Ù©šÉKf#=OüÙ¤ÃYVæ7›ð‚¡edyùÄæ=r'}8q·ÝÇ0øˆÉo°¼†.qØq q)‘/¹Œ®8|ý>R"²bT¦D]š4šM%w^éÿ24²%á‘!ϵ$ú6}‰=©+RZ\%y^scí±²jòŒÅ(š¢9åEW¸ÐÐÖv^H‚¯yŒ}0³ÿÄ@0` PÿÚ?ÐÏ. ¤ügTYÈ겚ghoÿÄp !0ÿÚ?­RN2ßf±ÿÿÄ(! 01@APa"Qq2`¡ÿÚ?¤ùöG‚ÑM™aÌZ_„µÅ‘ö~2”,ªû3$¢ã°¹Å F ‡Ž¥h¼4¬Y÷IŲ0w8öΑä>•./ÌáB˜N’X¼4Ã%µÃX}GÔv±)P4ˆAŸ«Î f•z¯à?Ô ø•ÏáÌ5E ʘ3;_—ð0S•¥æ³Ò:|Aj¼œÓlÏ2)аbÆÖV›I1å]‰°Z»QêÀ¸Ô}S÷6UgjöÁà¤â LæAÅ^‘ìJ±Cΰ),ê&(8b•t ®GýKê—©’ãR#œÁôø^˜8!G˜i `å9Ä” C®´ÞE“õ!Ö{V)›e³ì^¶e ²¦Øß‰ÿÿÄ)!1AQaq‘ 0@¡±ÁÑñáðÿÚ?!úÖŒ¤§į‚ÐS¬þjO™Ú·Ú[»Ý‹LÓ÷=gÄ·+óR‘[•å•ëô¸—Ø™ae6~%Bõ(Ð%yé—«/VÞ‘k†+¸“– ¤ùê«Öü–sîèlÇ¢0ízTÒνôçp¬íùŧ]&oÑãmÓí=ÿ0Мëòõ›úhéJ¡k•óÍ=þÅbžò†/æ_–[Ãó1×Þ/ï¥À£[|Û2èÁ gìN.ïÌ;Ì,µÿÊŒÙÅf8k𲆲t^ò%:bï>² š—Ѓ= Å~@ xï·Éå¨u.  ˜üf«´¿šc•ù€Pæ ¦8Wú˜¶¯JÝ=cÚ¿¤-.\™ãŒä̳ÿÖ`â^ÂlÖ&amÎ#‹"Þß {ô0•¼,Åaü]øŸ¿W(8/Þe£wÆ&ÒÕ±KUéz‰N~šWoHß_Ì€ž¾#óø–;}ˆ´V‰X-îÅðo(™ˆäÅBæEö›ÿ‘)ÏC”(3(T\Ø<±×íѲûbZ½Dô¥ý ¼>П¸)Ì?M% /gA¶¤S–;*e­ù䙕…ÑíqÀß~KrÇB’³™§µTÖL¨c'/é ìJ ÿ(/pø¦ÄL/– nøí¢03)kú‘Ë–*­²…—F–ãª;"ÔÏH}‡®©¦Jñ ÚaèJÒWhcr†âæOÔBíéÌ:],ËnZeë+/‹©“#‰•ž!Ìw¤¥ #@,pÜ!‡rã‰Z¿ÙF%+:€ZÏ H£ššÀu yk ²V`@ŠøMËõ9ŸY„L þ r±¶r‹a˜OH©É &"Û7ÑÈÔßú¾Ê£Ã.`Þf!í4TqÇÞda¸ÆT·¼.38ð ÞfëÁ0 >&/PVÀ[¢¼ ÌÄ«·;í*,>S,üÍŠýþÓšéeT¹R·s…¸&§Úxc*Tªgš™-Bƒæ4œÌ¥AFȵ¸l£0¶”ŠQÓ,Î5Jw(®#L£¯³­C:Žc¼èa‹–ÌD&pk¶Ÿ2º3mÙ_Ø7¦lÄ›?ò52~㕘»í4f\7*Ž™ÉŽ†dûCgiYÎå(¢W´†½#,P§?¨€Sƒó?Ê(ÓòÆÆHr¥3üš!ˆˆî Y¢Ü:`•ÚÆ…¹œ=339ž°RÔªžÐɉNÐÜæÍ©Þ]¼ž#¯hÂ\¯/¤Þ›š3 Æq)Y뾆æñ²Ç3ÚqÔv˜¤tGP¬}á|fÅǤq¡£¡CEKŠ( ¾šêø® °q{ìÎbÖI¼9Ž£©³5 ­’Igcâ Áñ/Ù5ÚuE«~÷ÖÑw:8¨ÙÃXÌDÄY Mw–R›]ÌZv¢´"è\m o ×¼tFrCLTG+˜ãw/ÄABº©ª“âŠû6.Ñ£c°&-v†ó)·¸°™j¦&e-¬JO&£Í£“Ûû)pÚéƒCé8†Ü“Ñ0¦÷(Š9èå= \J˜9& ê>Â]·l4ªe‹ãfòÌ ßN™¯WAKÖ .tæ´Çu9†‘ÒÁwÄÌJÍ™f"™Ñ*¶WLuÀ7P‹¹gÖ:Éÿ³P—ÿ&®ßZ¥4«ŠíÈ|G¾%Õwñ ÌÜÁ†)¢l”áïpF-¼ÌÖ1ZšX-ÆŒÌ-w”LÀü¥§a´lg0•Ñÿ°Ä1<ÿe–?WéEjvš²üÊw•@ÝEBˆ>Gªe¿H°šÎúôã ë]æÍÇØ8†k3nn]s¼T“qÚCƒ‰o”°ÆáæTÿ©c7púF^´( ¸Uy=áÉîÊÊï(srà. Ú‰¦¦Øc \XÍ긦ÈsŽ!s) ŠQ¾ÿHíC’µò•*“ ô˜8‚8ë8•›çrÁ·=¥«²^×0ÆS‹ô‹¯©)Ï Îåf½Ó8–f6ø–êPâXÅ|D§1ˈLÁÔUÛ/¼Õâ!† ÐË€eœË†“1QÈ2µF&Mø††7 ˜†#‰Æf]m|ô*ßiæú¶ù†Cî”%CQ1í)5Ú2.©Ä3È<Ÿ}™f“Ò ÈÇN!²‹™eÚ6 ?Úgì&RÐU÷ÃS^ Ù+²¥ lúÀáÙ³æbbᄯ«Ÿ´­ñÌ*©q4¶qÕ} ßâ!õ¨w~Ñ1§áª±Eª–&f+èj_»é² xŠ™ª3N³0¬ÍñÌÒMó0K&/ª:[–†¾–6L¾ÑHxËTÊm1\ôë^މdËìOW9ˆ‚´Ê{A¶á®‡3ÄXzM!6dLŒÔÁQd9ªšbg”ý‰•âpý,±,Ù.\¼½)?é cŠÄä\Ñ‚Úí4[2ÍŠÌ0Í&CgÖxÊú’÷—h‹5ã¥s}ßsÙb¤{ÃZw´0­€iåú”ÃRÈK•Û3_YÃö_ÙmǦVCí‹ NÐÈW´Õl´²w«æÜO >c­33I‚feù'¦TÔæ{C Áž›j*eë ¨7}à¯Ë)h,Ðw C6â¥zÜÏSÂZ• kò^Š'Øn)¼ÅnÉåf+¢nY)yü·=ÜÍ©¨OTðžfl ·Ì~¼nkôŸÿÚ ÂââÅ<óÏ<óÏ8B °LO<£O<óË¢ 0¶UŒ(O<óÏ(€MP!sÏ<óˆ !„Ýû@L8áÏ9-8@ß<1Ë\ÃÇp€ G9Ot‡Ù4ñ_4 BÅ÷>5U&Ï4îP€±ž‚Ïìp° y4@n3,#‰-Ü| #¿D××-›i‚±Ëß§XÍÿI@׌S€<ò´½ß¯ß°V‘ÜIx<ÍIŽŽ|U>´ÞSÏ-5]wØQô×ì SwóÀIŸO,“ÚTÔ‹äq&<ÃO r…ÍÎu~ŸÏ<ó„0!×Ö§#ÀóÊ CÉYE3@ð<óÀò?}uð?ÿÄ !01A@PÿÚ?þeèµÿŒ[†—/$¨“‡ºÌÞ 9ÚåêÛäì ÇØù!Óxa¢žÆåÏUÖ¬ý`ºË1îHÆ\S¡÷>%¿t';9ó.xÐÃsÜÆUÊ•šÜp1%iì94«ÐòfR X8+j•›ï 8<îH8`~$øàÇÿÄ 0@!1P`ÿÚ?üºú+ˆJº… ãƒ'Óˆuo ¡T,9Ì«¨pc¢Òhîh7ºëˆ|—ÀhcÿÄ)!1AQaq‘ ¡±Á0@ðÑáñÿÚ?õ…á9„þNâœ×Ð Äp:týÚD|R+LCQ([²J_'þͼ>® ´ÙdÙéH8HôG”A÷L…'·êI:F¨ ®7á €Ÿt- žÔ?W¬ös¬,bÃ1AM&Š"ÇS}J‚“ŸÚhÔ¡rk(àWIìŒZ-J^ãÝ> v 2…‘ð¡±lY ÑÄ-¢6 ¶¿Û6oëU+÷£2A¶t˜€ç ZÅ6Y£‘ȱ)„­¯í¾z-XôcËøê ›gE$QGðå¬~ /3”Ÿ'd#ÚD$" 2?@ ªzäOe“6F «&ŸX70h:ˆªH+VV´®!—Gè2ÄÒQ X&ÇH ÆÂ+h…ÈèaøE| \ ˆÔt]¾@„ç„~³®qºÇÀÕGhèä €¥‰.IEö‰-%c ÏXÈN„Á3|+ÁÑ'²a|edè€Ô7ºR?ê Écíÿ€?ˆ˜³œd,U'Íß„NÄç`ØNèv-ÈQ0l`¡r¹{zpIå—Û]Ø.À™^ÂyO5Y(‹Žd¢£„Ù+KÅð…Çðçb>„‹Qù Â<@øP~Ò‰`vÌ—B”ðÌY’¸NÒ#¨¶Àp$7x¡¹@pŽZà‚ù(ö˜ad•Gà;žQ,œnŸ¹÷kN¥”Ô‚Ó©£¢?¸òÕpIG@(8—ᑤËJmwÔF]zjF”17¨Ò3¤Ê1?©Nå „äîDоg2tÌ™À'äÂ@ÁÐÛÖL“D³=©ª©ìBÜ…r¨g•g×D \Ó"ŒL§ð É€7A–Û#ÃÁ:¤”ðUÎniÁäˆ<ÀåH$3ºD1È´]›Ä’Gú Áªµ '«²Pï¦6€ï ÷Ä’¶™&ýŒÂQM€5ÄÍ'§B*=ÓÁަžôX(ÎÑ@ƒ¬ iøRÒìˆàÄOÊ&jÈAÎq%ôXIùYÀ„‡ °tz¡@ =cCR†$R ݺ8r䟄c™0¹“Ú"SøXë@û²£\|è‚ÓÆINn%ÊØãÐ'2h/4©²6F\¦Y6€r @Fû\#·Ý8ÈÙIÛšOKïqдœ`ÐÐ,Àn‹b |"ñ¡¥#š3¢i÷G&L8FJ 髨3(ÓÛB˜õ”8wEô\!Î8Œ ðŠVZ­º<« Re:# TôÏßÍ–éã4@†BŽÄ"Nþ8 ‰ 5pv†Ìò;,·#Ð Ë ØéĘjùzUG)8>hÀ‡¨>Ô(›ÃûŽ€Ed!ÍC¡cÉܨÌ»„~fµ¹@,m:2Në=D+¨ô#´ÓÒ¼@)ãDxžá<à Œ2ì¨V‹2ÉÐ5N…ÈicÑ‚lÀ –O#å5²Ï’¤âÙjF†ÿeˆº_´|Û¢Ó<ôl1.KÐ& iŽUÙOFÍd34L #/' 0·¶ˆèVk&½–2#·LúDÒ²0™L¯èÏP ³¢`Øá–ßðì›u0À7¸(½éLd^D¯! »s·C YÊc’(²„.äE Á”Gp‘îL™vdZÉw:iÂ`þ•BðÂj˜|G@P,Bn¤^Æ0Zòˆ8(þÀÄì (ÔœCåÊ,š0ÑLPCñoæiÓ?³º.tY8žå•€‘ôóÓA™î˜#ȉûB¢–yQ0îº&ÝjÍÏD é’m4q¢CBˆPÃ%o[Ï@Qèžû©“:™Q¤n\5žÈMªH'bÃ"˱:1Y£¹<$Ë­H!X2i;~×°áԦȺÜJÒ"A]Â.ÁÇd!†³-4:(Zæ#Š@uLf‘sX::&V9ÄL€ÎÞ¯vY]ìàèrpJì©8ÈtûÔš-¢'Nƒÿðšé%!ž]ƒh¿¢‚9­%àµ?i„Y–çüì©o”NìO$Áf {B’¦ uqª¤ŽNf‘ŽèlƒºÿxBû­º8m|…*¯KÁÔ“‚E¡ð—ÕëСåçXД3fºc™Nfã=r¸^ƒ¶ Ó p¥Èƒ´¬ tÊØ õSðH°£MHæÒVÁýB3xЫì@ȇ«ƒ%¡c cÝU#/‚É„ާϤ¨D=“íCz‹¬ûÃO ò‡.|Ìåw€Ìq(``êè›Ë¥4¥V\ˆôÅBfáZ`äXÊvtAÛEÈeÁ‰;PT;žEš ”ŠØ€SD‹žû#ðeñ—BýƒïºÈM{±"ËØ*i?HB›!'PŒä+P@ëS˜ËJ ‚˜F†!ZɲiZÊÊ©80TçÂjh—‚°ï"T`ª‚ÔJå>‚n0‹Mf–ò›”ødš$ÎÝà"؄İžup ‡ãë¾2ˆ¦´  œ”¡”ápÒ˜Æ#Ø„; £±îƒõÔ&1g:²™ÂdC¢¦` 3!=‘h£ré{%Ž‘²Dš P»¨@àäD ÓØ}õ”ThÁ_@'‹gdÏ(ú¤J#¼‚«ßÊp|‘MÃÁî¸bÎ:¢à aôDEa”'aýÐx åo‘é$ÀpÈteÃS(ÛÒ€†#L#ºb3õÕˆ ÄS†tyKùª£óö© L,º(ß^œ‰ÞT…°W„ ÇNè´"š6’O)Î8M6<˜ð/‡(¾BbI|’8{W Jpî—£áÈ‚5‚‚‡áÇ yâÓkG ø@Z2úÐ)Uc<#–xúD€=ÌBxÒ.8tšy> ô0~BòÀº[BØøkÆž›zvÇ6$½ªª®ïžLþC_ŽfDQö÷×¼œÿл'b¦ÈBà®øGá\1þ‘ÿßiÖà V•þ?’ø0͈«ÜlVz÷µ¯ä‘©t(w‚ÈJxþüš—ö6©pž¨$¤ˆˆ ¬WñÖêñªªÀAcÕÓRÅ3Tü;Yf‘ðWZì†H@옣#‘½¢GOË>ýþ–‡bÖ_éfj}JNõÔDïoÕïT{üùÒî}¡5ɹ&T:ÒKJŸáò¬û“‡¢®Ã[—Åc7….›À ¡rIÎfÆ`éÏgŸ6}]d­÷Ä[…ˆ \þŒÓÝè Ïös¤ waÚ·ÖLDŽˆD.eSqbÑ{ÄmF¨ :{‚Êû²Ä–åfIA³QQ­†'°Bb+ýKOñ|Ù~]*|¬ËÞª­·Á«ò#*&E™ógŸ“׆Ù[ç¡c*Ì]Q¬fQ•ONƒÅZ¿5ÕãêvèI^ä¾áj‹Ì—K˾À>LU}PÖ­ÇsF4zÔàÛ'K/Únö>3«FîêØR¿Ÿ•zG¾ˆÝñuˆ®<[Â{oQ„Œ14²X¨™hÈ‹•õÌ»˜^ÌAEŸÞÃ*XëžQ°8x:¦¶m .âŠ'›£lÇ].‘z+ýYÌo=pà Î*\P „ªâ :}·ºÚ\Íç€|@Qп&ŽYšì¸1°Š2´Ñz½ÝnÇrµgÓ¼®7Ÿ®WËùô˜¯zîÔW¢Y1R=3rظ™à‚‰ xkñŒ‹qu]_ÿ|µº¼dÛå° ew_‘¿ÄC~ð¨QϯðA‘Lòï3Xkº¬W«úçŸ&½5Â[¾E)ç×㮳Á:^’ ç“ªÒ Ï(Ÿ®ÀY×ôÏòr\Ç#ªýœÇñ,bá:Cœ°Õ«¶í29 k¢ªš=Ù rM]_1­VËå%hdm¬—11>áòI¸¼>„ Ö9‡ßÿÌB·­¡E\%Iê'_ tÖÕ•ÁU+-A¬ÞÙ›Ó_ó‰ÚsÈÓy«Å—0R5ÔrÎa#k¡ïAQ¾^?}ÅŠ`]__+fu¢ˆÙªŽ’èÍdùŠìL_øXMÂ*òUO¿î¹÷×5¨&uŠh­ œL«dŠÕ˜N»féÿÚ6X¢`…XD|ÝÏ Jþ:ãªUNŠV]s®×Û#òo¨ñêaΊ«aOÃ"u]¨ý6gÆ"Ç´aÄÞN¢òAOL%`=ù4 ÖõõµÁ|ŒÇV«Ÿ…°ùÜ·MÁz3r8ª/ËbyYЉ¯ÁË®i3¬8ªEÌUžÇ#²Â'ÅêA°Xs¡½–Dñ :ªˆ˜ðjÔö Ú£•¼ô“À".Ùlš>X=в…ñãG¶!¬ÇæmuÌ[3Òi¼mÙ™öôß“.|&ViÝÜV†–Y\þ¹ŽÃËÓh¯Eá+ÅH.É×}Â¥sŸGÖu_Ñ_ £âJŽ~;¦Ã^ky"ú'ÄDã˜×¿'³±7¼l6¬®¯ŽÑªs´þ¶jœÆ]ÈÂÁÐ1¶b³šÙ,<Ñ¢ž/ëV×CA4‚8ëYð÷QQz]cãb‚á‰z:`u}¤¶”~Rƒë­¹;÷ÒH¹‡Ë':‰ÎÕ}´ŽAØ’ê2ýþö3äcµ!¨¤G"ñ)ßÇ’ýX9ZDg…{ß2•žmˆG?ëé´<¬>\ËékÜÁ—$DPÊ'ÈÅÔ1V› qËÖź^>'_ùµIÄÒµíS&m]ÖC `1\IÕ/WWWïDÁßGH–=^~ ,ó†x]]­€Örò® ÃøÂ}çm NïËxÌdñêŠL’Ä÷«ãíÓO²ëõ¸§‚µ*.Hbýf"ZçPô›ÆòÎaŒßFa˾ƒÿr‚2éHuaüù竟?6Íï/Î+îz3TX iK&xÉ‚¦;ÉçžsÝÔY&äA°­•8Ô«wf@‡–Ùeñ:ÄÏü¢0Vãˆêh°š±[¾#ºAtkÖÈêÈÖÃêæúrú®8Ë5­ÏA2âg>%˜º½%9F>ÍlIèpºh˜7:eLp}Xëúzù†'ÍX¥O0“:´¢p)ÑØ¶­ÞWÒgÓ9bðuj“Æâ>טÒWÀ’ãó~”üŒ +ŸQ%ÒZS¢ŠhÀ]LdÜ÷"dÓK/Ñ™¬@.GËà¹QŠx‘¼/—ˆÒ’8ÿj7ÿš•!ŒåçÌ ]À]‰ŠÅ/q¿5ïC¨4ƒt3 ¨í}«Y¾+«ÔI>ÌÉI:¢ë,îU)˜•쓜 7»v¿Ïqº5î‚e¬EÂNß²Z].—˦qLjÞ.U{80\º6º2–¨Dk _Ñ cÛˆúo$„’TÏòI_²UêÜ¥ä`?¾#Ö"v‘ŒOÓ#e6c°:Ο®›/¤§vØÜßU/™ÛO¾[áû—ÖòBék#q?YÃfÅý /a dC=&€=´¨°ØŽ í½P,&5»¿z`oÝÞæu5‰¶ ül¢Ã2œ'ë+< Õ1Zô ´°ÚX!×;C¡u8dh¥B³ðÓ8«¨ÎÃé.À„WtQ4Çúý˜ZBRŒÔç€ÒH?âR§Ù²¢yVéko,þe~U»wæ!öŠ#8G/`ÂûãCÏK)zDÄYo*‘šâ–ɤ:¾I,wû}V ~8´G àò{X9`!Ü„ÍÕƒU ǾmþêÅ [oÙ\PVâßÿ Ýmk5pø÷<Ž Rß„_ ëëOL=/QÂ5îÍ/…•p—¿»½½mrwÌd…¯ýó/¿û]hæ¢1ûp .¶ŒduËg5§}92ȪlÓÒ¹ž¤áâ´–%ÅXI„*„åòãGÔf¡#ÖÆiQÍŠ+æßÞ* ›h@ë!š È™¹Ëï”}œ¦©$bîУЂÙÿñãOL–·¯põ$ {ãÖVœ²Õ #ºšTL.k y8ðz‹hbGç™: XUóùüãÇ~Õò‘Öï#VC Ó ÙBèúšÛófä §$º6\0CÜÕFÁ"´nc½j¶WQÑ"Bß²2ë¡`9šÍ×~mXNÏ€õ!‚…üÎ@g£~‚¢€Eö`6lȇݽZmöã`EZA_THA".v#­›ÂrxM›ÕOß.Xjr{yÓàñûžß ‹¡p©ƒP“ ¼•+Q]›û±jæóœ±€ Àº‘%‘ùj:ÕwFðk£r‚xÏH"'&¸b¹¹½RèýœnÍ“£»Šýo±×k£Î)f:ô°jnùå{ø |äÓµ4ˆMœëºëŸ?~|««a>¤B$VímTþ¸°Í‘¥bš›ÏIüv7ÒO5ñZûÍ’ `då%§¹õÜ€ÂË¡Ý\ÓÚøV½C†Ê§"XôÖIFcKHE³ˆÔÛ­on‚‡½mEM#+â(XPïÅpìJCK±+c% ÿþBÂùÓÇ·[$R¤mWØçñ_ˆåÊÜ´â­ •ég²Â?í÷4*Ñ»Ðò´J9Ël³ý¾ž/çÓV“éÔïoÎIX1X ݧŸ_¬ßøÜì8‰KØ€ÝÅr³ÙÝX±¬ühÈtPæ——Ë ˜E©býù½¾¼LäQ7Ÿ ÌÄq=ùtx2«Ëg\ÿ1õŸÑÔ–”D##ÛαŒ S_`¸i Aç3H Ôú'‹¬H4ˆßìCïê2´†`ñeÏ¡Óçá†ÁâÕ‘¯}þZ`MtC¬XJ¥Õ/Ñö}îàÈì>x…Ek“Ìb ²á#XÝþtW-­ å£è2ƒÕù ]°ÊB1OˆX7æE¡2°¢a­¨Iz7:<‚ê‘'àÙ¦0*ì¶åò…CŒXrÞ¥í;z$@ž<á+f¥ˆCCM¡Û[݇‰Xà׆ïEúA¢+× ,{òz¼“yE’½ÕZQ-XQ9˜°ŒP¡¡ B’V€¥Äý2{Š<‚4¿¨ŽZ^,×Ò³ž–œw¸'fs¬“R(ªªÑ!uÐ[NÀòê‹`{Î!X™âºÃÎò‰MJªv;˜ú¿¿¸È-‡‹ù¼a°.§=—‘t ç+€åÛ%?\C5òåìäÑù«¨Í¼äºÎüzú —PÍ‘ÓápsÈCÈV¢~6)ÛÃH ·ƒ×Í39gæ\ƒÝ’ÝZ¡Û¼¸‚§Çä[´2‹Þ:ºSAk|èfU¥Œï¤y‚ÐW„ßÝÁb Ð½ßµ„µUBì `K‚ Ö|)¼qËå¼Vµa°^v1$–nšBúl¡{¹pÝìwH’£½‡¥ç¥ë¤v#Ÿq‰>ì"!Ñc³.8ºžÃA™¬+ùŽ0i¬¹ÓÔa•4NÂYcayX½¸QJF– ‡¢‰h&—›ÅŸ¼à8/uÄÕ™’ÈY–¶†#X&,G!«mf…Ër ÀºiäËT–èqÒeË>Z D–éà—ö IA”EØï“}§ÑUBù^v/gOOQ¥•»öƒcõ`ãG*E’S`ñ<¢…€~¸!Öâ‡eâ«ÅÂë±/ ©,w@žØfNžb㟅)®öÌÎ>ç­BRJºÐ:$°H´]óâ¯Z¿GØ‚´ÖB±rä Ó²ÇÓ%3­µX {ëµÕ5C‚­‰qË!XDš˜µ¹¹¡ÕUÁêÁ¤Õ977×Ëé T…pI“’”í3“4b:x vØ °üXxGf‘¹È’.aåbµ'°4•ß{Z‡y½†9 gmc—Å)3‹«‘®xÞ2'P$[0{f\ëͧ—)ëÎd…Ìe…£F©wb̪Ò5q ªt¸E&¹ ¶ 8¿Û5¤+ìtòÌ&qJ À:¡ªzr˜sdAüúë¯ìÏÔcP]o–/ßÈÊÙbÇ`yáôÛmUkhdå\¥`iÔq 7º'M…”!FË`+γ¤PX ‹øÞöý~‡âSiUmš  jMe­Ô†€uõrÓŽÒæ`Ò }ÓEÔ {‰gƒ5ÄÊYdœy&F| Ü\X ÙÀkš–¿cõ~Ë…\'ÀÒDÖXH`µxy#í_cJþÅÛv¢½h¨§EwØ}ÞnGVÃdwbÕ;PBM²`_‘Á@ªÍ«å¤äå/Ü&eq껚å=W$ÁQÄû!X"——ˆ¾Tb'ù%1äX¡:À9lõµe1ad–Åb±ûÜE [®8ckÄ7ÒŒÙÀ¥bÐ]î|c$-@ÄOHX¯®?}b¿ƒÓ¶!q4o‘DÓkIëËR cÅt*n¢©øìG@ Ñà ôá&â¼´ŠCÚ7†ñ`çþµžÅ••*«ñöO<ÍayEŠí©£Qï â2ËÀÒ´ÃÅ—aug÷Ã5\«¥‚UËú~ÇK¬\••èܪ°ê ‡èc‰»ºj³õs³‰5r58Ï¿p5-~N¶î5° x­LrÒ˜ùf=.d£`^vÕ+‹Ûíiù`§«ùÍÆ³–ü³:Y[6µ¸cÅV *'ƒ)6¶OÍÆ‹ ¡›È6nYF‰sAÁ½õÉÔ‡à®ñ X-ç µï‚<ÒÝ®µñJÉn?å2çVÜ[È ¾§ Z|+ˆÖEêpƒ_x±”Cß+ `îj%è `áöÂü•@Ë9+°Ê˜®1­Þ ôGèí²¹§|œ!Xš¹¾fEèýV̳dO¨«?}â @/(‡ŒU¯è×Àj}UEoÿQÌɼ5®Rb‘Û‹4±Ÿ²’§ëFÇ8€ Ç€•ùœî º;x6iÿ™Ô,¾ÍMóì_"Ž»E.-lKcW@Å·ÝV*i•¢x/X´|‹õدî;ËCø9=ü&f x âu+^5oo.bWônÐzáoµBP³·¤W/ë噹Vp¿3Om¿—ú,ºnÆ-)ïrûâöªê»)Ës·|'AF^Œ)'ØÒS·K`rnƒï#sU¤s¡_õ%9ƒ\ºmé†@Ö‹pØ(Xâ¢Ä³C·ª»"s-‹ÁbÎj„±$õ9îø”‚‚5N8í*ÍJkN‡—ˆ$ƒžc‰±F‚cÜö=´juéK)® ,í©tÊ\,#1¬Ç²ÈEÄåb1@êZK]Á;-ÉKdÈñaðzŸP,qñúR#ŠI hl'…I5 xÔkb°ì4nÍðbSÿŽ’0™OÌÐÄ;_¯×‘)£U=„–0ƒÅEF½éE±Vµ;ôÌл»îלâ¤DS÷ûÎ 3]xöÐðøãö¶í¢á¦`=aG–GQÏé‘©™­V¯#œ²¹†Äƒ¥;¼I\«kGþZø÷¿ÿ¯Ñ¿ýµýßÿÕ<µ{(#톢ôé $`ušì„ 6G™€—&³ããÐè—0Ó}þ¼pב0iUKus¼ƒ$rªŽ¢»cPyÿ·¿ý`DhE – ¢­Ò\¥$žR‹E1s I|~ó›ßüö·¿ýÝï~÷d`z?ìkEqMçÕZÁªF¶µ?-`…&¾·ÿÄÚG(œ,ÇJúòG¥?ÿ™ÐŠâÙyµ¼bÖ[ØÉX6ù´^{ ÷Ë/ßÿщ><®¢÷#£)=“¢‚žç-Ý„•Òë\[_VàM!±"—éuÔ™ªq@ÑûÿGéÏß}÷O“Þ»®lãá€7pfÖbŠC°š]šŠ÷Ïýëï?üðßLx2ZJ,Ê>¯—FÓ“ðÕ‚ôÌq³}:ïO«*PQ6"{ÁÛI• `W‘>¿K¥Ýç͇ïÿF0Ñmýøãß@Z‚´ßW1þeS»ÕôhBm0kh¤»(鵿ÿøã[Ñ·~÷ý‡ga¥sÊÐr™ ,­7Uýr/[åÁä^xA^Ò2ä¶ËÊqÖ?þø?L‚Öb6i*d1‡`i½îpÙ0Þj›hô¬ßþh}÷݇߼ZB> ¶•°Wss·»iŒ»r‘”BE8ÐÁpagÉë(5ÈP6žíŽ[˜¬ðáûï*R2?üðÇ?”%/éMB#ÑX¢5*hx.®ü_ÿ`ýößýá™`Àe=i.©wÔln6 âÚ¬ƒÄ uՇʨªƒí¯¦fRtqyLmèz·ÁúÀ õß„ÖbQ–¡Í‡ß —ž v}S9LVúåêÿú¯ß}øÓŸ¾ûŸ?þö¹`0hêt4C…¨ÝJkWdë2Y±GªF‘Yá aõzƒÕ‹u»h`6†òÖN°¸ÞÞn?oÜ÷ß3Tßÿ=i¬?þU'ä†.•†ž~ –˜ÍN×%põÇ?¾ÿqÖóÁÏp`ÎOçNÖšãl ãPª-êúšÔ=L5ê•–<Õj“üc[ã=s*,.‹k[~ÿýŸiüî‡þþ÷¿ÿíoÿ¸1g:_ðz`‘š­Ô+—ÐY,†ëO?<_ ­B X?¯dü„¶Ûu%Fî:îJÌ#>>þ »Ëå`éL¸æ½Þa׳ÕQl¬q묮üVC(­¿c1üǯŸ?wƒ×C`ñrhŽá´ê¶­(øßþ”Ö÷y ¬­Ñ\¤KÌwâ/¬æuùÝ;Övæ dÔÓ-åÌÅŒEšÃ5Eè‚ê¨vpW!ÐX¿üB`‰Q Õõ_Ýnî ý±º:•ÛÛ!FßÝ«á0KøîOy!°8RÊ?¹5pêd5a}åÖëJÝ»b±_Ü· ô0ì 4aLƒ¤Y|{«bg&C›J¯ˆíîC±qü³Ðÿõ¯ýø)äÐCë$gÉû¥Øô?}Í=Ó(M¤%"Úd¬|…ˆ›dXý 6®®¹Mzªi¬qÒÖØMA›A²µYþ]éÿøÇ_ÿÙ¤òåiÝ“4Ãå¤íîÈ/üð8} z9¬8ùŽð2ÿe. ¢ïáîóšãÝp;„¬ªEöªN.†igË&Û]Ãä걩ÿ "¤~ýõWœïO°Î=¬…‹Iå ¿ýNé… ’6ÃÒ|õ©a‹îˆ‹mãj‰FÎË(–+9+»aþ—Üxˆh/Ýí!»¥•e¬‘ôš ›)øW#©ÎrâSñ(¯Å)É~ì븋¬“LuòO6J`/nü<´G`]ëÆøk, à¥Ð|LDëá"½.X²ªyè –µv·f#˧¢¶MûÞÈ`ñ¶ÝÀ”‰—=°"[âù7•ÆJ’°ÿô‰Ï¨iËÔ¢ h`dðéÐ…{Y°ÊFÀš§xi }µýü™®Y:Âpe¢ÛK`É;hÌZjkHï†Ìr°ºQÝ£ò|#ã ¸´o ¬`©íž±ÚöÞ·²V+û£çÿ‚%€‚OÁ}%¥xÈ2ùüø?ÇmÚ‡Wn¼`g5$)ùGÂq‡þ%õxM…_Heuýþ€Ü]ÜXJÇGõÁÊ—~»*$Ya±¢¤¸I¸Ï/RúçƒdÃÖ#ÄR û=þÁ¦'©`¿§³мíAÜêj\¡fˆ±9Ã1 ùêÛÏé PjOÙZø)TTˆrl·´ ®Ö¼wìéŸKþòYøïHÁ7xÇ ~,lƒ-XË|ã~°d(?†éiôÛP…Ï[R\[´îBˆe"'Éç|5ÐY¨`ÓMvÐ*t ,ßDkäÔY,JcI²Økq ñx¾Ô„`x:èXÓ]m?·¿ÏÁsÿ^¬z|µì­X‡ÀŽ9;ÔhÀ< VÈ÷ì7>ã[lצ½ Ò°¿ØÄ|FKjµH+åÐoéÂî‹—Ñq°îÐÕT «‰óªãÎ |t Zß{¢ ,äÒäØ6_Ei}âšxí×ÀŠCèê¶÷·M"ÿ:·¸2ÀÊÊ>¸ÓÑ×rGʼnZ,K£Ì1vZ"±¼!N4_RÑÙ#(y kqaÛH`rx>–G"z“ƒ…Vú¶(üI'Q~­}àD}°bÐ,»ŽÑ^¾W#Z«+UèÄX÷Èî÷dwU§Àr(%½Km 'ÁŠ¥«v¨|¼`¥÷Íxøb„N’ í¿Té5§{â;µ.u}Òjˆ¾Î*Ù A£œ!£‡ðB½¨ª¬¶o ÇÎÞ¶à¦Ö‹¡Û‡´”E­Ñ°`Ÿ÷Õ â~‹jÍn4]»2fÓôHœÛ)³wp˱®! 2âÚÞ–婇Yk œW1¾VjôªÖ¸¾‡Àâߥ-çúo—h#Ǹ²£½Ú>Xm–•fåÅÍò&ŸaÓX܈À`/)·ñÞ6eÆzÅ‹Êf`T–Ü}@ñòÜΦǽ·ÑÁŽê²mÏ+aÖ Ê“XRQ‰ßóÆ*¥m°§†à)]U¥2“XäídöÈf6æçc€šÌ-c  ZO]²R<¤æUøk!5PK¼ž·³”°ýt`†ÕQ,ÂÛGWUO Z“«ÚÀ:¬iMÊ4uý `µ Zá]°!±íÑRd &ÏFzi°¸ƒGÁòÛ5ƒeiÀ{ÀrÚH8ú¾×át]óñÁÇ®—6(Xm,á'«'h°ßë ‹[‡ã©ÛaB9a©Ö‰ñ/  QDeLÇ£œ®º«Fëö”1v×-½Á˜y­ÉLŒq°Âi°ð,ƉãD9LÊ”¤ëk¥ÙôåüÅÀ*fçVVSë{œ}ˆ×ÓÝÉ ,//CŒ à¬iÕv[Ñ÷K|¨d7#,'ÃØg¼{­&Áï;Sé)dÚYO†ÒYÚ)‹TK7ºmñr&„¾ Ú4®i„jâ­hûiˆóû¬'Õódz»Z¬y]t‘¼†ø¬Ì ÉÂ!C+ÖPÄÞ‚ì“ômŠV/Ëi;‚^"ÿ£ÍÒÈ~n¥Áž -‹˜¦›Ô¬·ªrऀKVÿÛ¡Z€‹aJ®Jû¤c–yþX0;s¬®'ŽýõPþìí÷µM4ÓVï2fÄ€kšðgºMøA™õÚ¶^C™&×ðÜ+…å²é·°…ä°µVuú­¥µ•¸¶Zôv|²{¬e5ì•´—vçp†Öç¸'fÀ)a·Âíz‘%q&R¾ª`ûV,‹™ (ùoÈbBâA*W«Mo¢¡Ô›1g•Û1¬ˆIÏïbn6¤­¥GÀ²wƒiô>kE]ÕµÇEõG¤QEý«| ¬8À ^¦5VœgÝæÓÁ0y5›ÏG7»±Âö;ñÏÌ6ãØ@S–ÁùmUm½Û4XÖ\1+£ZÛ„¼%¬ßelŒøŒNàtŸ¿ò2fú¡{ ñüJ"æ¬Á²Ì#lt†ú5ÖþÆv‚>Ø9€·ða±^/wSófa«xë$XeáàQ4¤èžOET‘w³ŸÝ2"Ék'H bèIœßq™×+hP@Srk'—AÞ݆ ¼…‰¶çΈEd<ݦ³bzÌSÃÄlÁ2UN€ûê?—Ž–ÑÁ¸Ñg[38:Xê+&†Z6Ê1¼Ö‡.©as»c«•„¹ OÑj®H ¹ƒz“•—ÔõQJ'fó@Þ­{$­ˆ}îŸ}—}Åb1Kwü ¸*)¼ßÂxLõ|¼ëŸ²ÊÀ2ÉLØÌL ¨Þ‡åÐ,ÚjAò¹­—+1{¢ÍÈ|‹‘G>IQöC·hs…äú¸ö(n«P½ŒUZ+h™ŠùJ3ûå œç‹XÚTSÙdáFÚJ÷0€ÉM`yˆ -‰-æTdh•YLÒÝä9!v½ëb‡VÂþ×’1ô"C  ëŠ-o`¡&p ‡ÁM{`á¥ltt7Ù|~›0rÐï Výi·©µL¼9!†tS–ys4ìG2e÷5´)dL¦{¾Y*q¬­´FsÄl¡`ÁaŒãåB+kGIª˜Že߈>‹¬7OZK†öкºúÔ nj£ÁSòt45ܧÝóNØô½2õÙh‰ ÚVžÙµ²D0mé]T¢^B}°_js]%n^äÞq’G_–MWbÄJàÿÄÁ³ž8Áâ,{'h~6ÃàÇÐø:~{`°ÚÖ8*ô‰´`­°…f@çHaÓØÝÂ'?ÙÊm__nþ󨼑îkÔ~ô››2F0I¡¸äköÉwcÖê%‰^ÓHC_5¬Ú=³°B^0%|Àô<°œU^³gÏö»“†•"K&¸JtJîz9«Ó†¹€Q®d9Xbšò)n¶—ò†›ëëOý{ôQgY,Ür™{ä03Õò8™Î«}ŽžŸUkN6ºô¹b!ß›îS­äCSÙÞ~:cûóçuÞêä»~t™Ð_°Æú}íÆ9!p—ë=b+o0f`™•¬×)¿æ˜Å &®?È¥‘µ%²ψ10eünk5®>*l¿ ?h‘ ³M K{¨~Ö€ÖPsdÛbló °f9Y6Л¾2Èô`ài{-ÙRó†YèOË!Ô°ÞaŠ¡¥ODVY_¹ µÍÌÇ"™|~6ú`­+TÐD´ò¾¨x„ÅÖ#¸FùeÕ &GF°·ž75±í€Qº'  ¨2£Âf4rÔwÝ«ÇãlâòÐ(>ìÛ$¬.Ô•fW•eÞΠ ¸évn¶@I.Ç}H m~Ú]ª M¡¯¦¬Pm%&—¼Ùê¬àû™Ä”‘ ´ùN#â>I½ðy‹gÞ’ã4s±ÜKÍÑzÝm{ÕìQ@ù†Ã1¼ÖI~ÕÉÔ‚„ÄS3{°O½uø#¡A‡\âb§´ÆýÀJÏ+Ÿ0dÖ`ZíK0eÉ›? ,Y«p6o+ÇÚ6%Ÿq2 ´–¬…±ìOj?d7˜P °ëö˜ó”…0c@Áª%I¦Tbò÷^™bLÇG°dAÊKº‹U½_UÏK}7²¯ò¾d|/I†ë>©û8¬@mÒ!XXï VË'³éwY`í¬¸è!2‹óÀ6N`5w»nß Y$R;œŸ@:‹sR0sHVÖÈí…Þ‚H·ê€ÖãåPGw#¾Ò!Íž¾R› µè`/›h¡ ~mxD¥•ETF DÎ餩¨p³rí5I×! È?Ø#7Î+=ÏŠá®v0p¨7K ‘X ûþ{m/Ç,½¦ß$Ãa l­ü„œ~¡=†×z!ª¢\‰ø¹‹|Ï$°²‹âIœ I£|Eï5‘(ù–ç 'gÄ9Ϙ&Qçœê° ÂÞ9›Í( ´,bŠp$aµ”«€Öc™Ë­ÅB”¯Æl»då«C y7¯½'&¶m,dêuå)X;ô‚1XA‘I‡~lÏŠÙBaÙYž`ý$[G°§_z¶q½nUgâI75ixŽ+=>ÈÌñ™…¿ÙñqqBUw¼Šñl>S>ùäøc°ba.?‹¥æVOˆƒ9ƒ€ÕÁªª–NZ"œÅÏm¹jhX$‘Rk¶‘ÐH­ºMLŽ\ O€%ö!Sôd(h“ ƒ¥ ݼo%8™$(õLõ ƒxMÀâ&oUZX–ö¨s•ÝÍ„P´è+0\a9‚mZY@Rõ¹l ÆH‰úòÎi]ÇJ ²!X½¨j ­¶MÁ0x V—•løñ´HUzᆺ߸Ҭ6=]ÀJ‹`Pñ¼zÈd±ÖÃ쑈™šŸ[ÙC ºW¢ÚášÆ}ôîdþ…³/“ª–šÊ ín-ób»# I ×Ç`yæU0VY” Ý¡UÕ\¿ ®Òn³Ú”*l|ý<ØÊsÛº–ÅC‹59kq$–í²G³Ö,«-k ¬\s{=à¶»ë8£jÕ"Ÿ·}ïõ,Ckw²V0>§c u]Ùí ¬,tå9¼•Ÿ.$Ì–sƒ€µÛáî ,`2•QÚ:Ÿ^Fï–¨ÀžҼy`é%h-…OÙuWHw€ Ör@<åa­z¯\×É“ã±íÅšŸÕUf»Ž!Ã×ëÝIr2ׇ -ù¶'ib»²äî…°ÿ™ÜuD¦«‚–1i~c³'É€š&Ö{©:h1F‘8KŠIç¬ ª&×umZ Ì a )œLXGh¤ º,‡Ž…´p jÿR°Æ—’IΦ˜ŸVÅEkÃV53 ±ž›šÀúåyN[©m6°²JZ¾Ûê8&|,þTÅúÆÇcùi®±âW<](}†u#Äx1œ'G•dQ7Xƒ z™XÕÅVY±XÌføÿlÖźNÆr웩©8´¯Y­>xArIú–TÊ:‚•ݽlp§`=\“0¶ŒñdöYƘ*x…ê1¬pÊZäQ[$°®§è%÷yä–—¤``AÇ»l"(“ÅG‡ÔÝ Öºp­‚o¾–4:ÛYkĶ{®ü‡¢mkp º©ÛXÈq ¬<}¬eÈmühÊÆ/æó« ;»]Å`]^úÁjx‚„®XˆïÉQ¶äÎl¯u9ZyŽ / ÖÌsPŸÁ輆ô­$ØÜö³ª–‡,sYÒbÔ@z ì(S´·½»V¹^¶O²Õ'Ǽ)‹*Šýê÷ËUM¨qÀ”,Mæ,2!l2l†¦‹yÎZ\ÕÕ’^š Th á=5òÄžh­Çô¡WkuxÖ­MS‡Úc0Fj $Iš¸X» ¢j* Ueº[_x`_‘~2&!³ü‹¢#ÃaÕè()€¥ÁÙ(õ¤ªÅøìùôÐÀƒ$×ûÁš¬Øì11ÓR·5ä•­“§Ñ¼¹,0øõ.Æõxz"¥k§`i°;«•„Çñt¢ØÎÒçÐÜ]-–¤[—ÀJ‰æ4y\‹Z´J¢©œº‹lC8?k‘<—ø›i”aªüm[ðñ";òd”´1xÙiÂO >c×/ýB®c Vr/gõÐ yD›Î|¢]x{´U:òlC‹£,ptH`yㄨr}=°Ø,-fg—ÕÌ,RZŽÜ+ÁAIÞ_'g/†É$àÖÑ;”‘]L|•à‚–O³9è®_ƒTì­‰D+Ö‚éÌ#¡½&s½«°õK‹Å8WÇ÷Ϋîs¼çRã%ƤLV:éj­e`‰¿(Ês‘09Ñ+à4‹J!îœ ²I+éz\ÖÉp¶µ‚ÕÀêºaƒtüD×bi Øo1Ö“¡`~—m89 ¡ÆCÆY•,.Mà ãj½ #«|+z—%ØsoåLQvÏZ"†lR9v<+Þ%ÏE7=´²¾”_±Õ@{V!âÕjªç³Š[±gî w£3l•²)ë.X]­¤’FƒÚV¶–H‘Ír-²¶ï Ÿ—cKž¹¶”!%xΪî,»´àI! –ìÞÇA)qá1ˆfÍá,å{úŽž’ìæ|â¬VËs!,ƒJò|>q!}ÌÊÚ¤zT”ôÔLo„¬ýù°˜$„›Q÷VÐJÔ–áua*pŽÂ9ö Ö8„œ7­Bvñ¦V%Œº˜ÊÆŽâÂ, ¶!¨‹WèÌwO&¬ Ò$œ’D™è qË=JK8M*OÉdãVë—§[™"l‡Ð_+Àµq.)±áo` {͸(È`Ñl;©åL¬١éüüo+Ï_¾˜™…"ˆïW_©¾>F‚IHúbßJ0&^DöÄUG5š‹ôÞR-&„‡NÍ\­íÔ'„ÏÑÙ‡œÇŽÁ’N+•´ºgÎã²T‹¥{øôœ1[çr°°^žÖ’Âïfºü(3W÷i8B+n-T®ZùD“¸;‡ŠÃ!zù=ƒ^XOÀòSÛеˆHÉ\i²[°ýX§`9QZìL§:6mhÊéNó-eË^"`r¯‚¬œàŸ½É˜¥¡³Fjæ0Žª(†{®2˜"C;ÓÙ|8t†>æÜYµñÿ>ètÝ`,Ë šª{"bXq.Z6 «X“Ì‚~Rj…ÏÒxzõ\ÿÀnãEAš8Ö  —-J±âeLˆ¯Œ|}&Ù¶<…S¥ÓòÞ\]ôö¤ìI)»^•gk{ÀH%ɘÁ.`‰CR .5Uï 1»]o-Ÿ@]Ç’ï=Ž)èʉÍ2Kþ¡ÍÇa{‚îpÁ>.lãÓ$›ÙË4ûùÙœµPÛÆþºìJž—'ê MYyºe“^ý!ÜØG+¨­z„Oä»È˜ì—G騂$'»+ue[‹3b(¥H£¡È>Ðu8äÂ'`iå·Ji^³DþóhÆ<ʱ±ÄYqØ„çÄ«âeöntCs\¥é ŸêÆB Év2ž³àðß °‚4Ât{‹ÜtŠió*7V%¦Všx ŒÕ{P·¶§8ª9’? V¥.Ú-h—Ê®ó#bFy7KÛ†Å3AoÌ粪ª³ïã¥xY¥½äøa‹cÅï\^ÁâÁWdƒxÌßœ«·‘ÐpÍÙRíÞ ¢ª$}¸t1Ý‹¸é¨"i|níàfŒ±`>¸d?kqŠàΟÌ\Èž"F[þH’òˆk?M¾½íÝ]Ë~î^·?ÓFôŒ³äî•ãŽàÚ7MUGÖõ¡uØŸ%Ï « ý”Vddââ¦^N§Ô"i¬w–‚”´KÞáR5I ´„Îé¢\Š uâ —h2¾Ù³#Ë•ŒFä]w²ÚL\õ,ß¾Õ*xd}ÛñؾcÛ1²W’²® g$4îZ‹qð(œÄ=ç$…ؽ7 ›xI“^`°úWè5…mÔYñ>x¤Ã¼È.u“Œ„<ªzΕÃB=WbWZg,Þº(Û¡›+RšXó¦ µ=…h¤³íʪò™Åx$9i#fRaKŸÉÄN9Á cIüy[½|¸kÕ ΂uoQ"^¦¸áXŸ´ÞÆ2ʱ­*ÅK·^;PÆy.XâuqG@\:X¹÷™jŠ#í¡¬uŸn¹*.!ak¼U¥k/ÏÞ8 ;4äRÊò JÕð d•ʨ0§›ðÍ=O¨!ETs½kÙt\ÏŽñÖbVù^ñ²ÓFÆW›8±‚‚M­³ÁšJLCQy—iÝú#m7­ÁFÌföbY—xE™ÄA¶iýyÈG}IÎ¿è¾ –hrIü¦óYéÅgsù¢<×VÑY XËó–+`š/z`‰ƒT–^íÈXü¼Ï‹ø¼áØèœãØ‘µlÃiÕ[ÌxYpV jÎ ÝÂÛÇ0'CxªRæ—b"AÓðvއ°ÐO™VQØtH+”씶˪®]1çÁX¤â{`ñÀqè.”õGÅË`q|œ#ƒç¶‰GõX°¦-‘2#!9kQBJßÛÿFÊ 1v‘ôQæ Ëqt+×ô–zfæBüdêo;ÎÓ”äÎf^r8À©`\ƒ>}ÚíjñxæÓyUÅH‚2~W ¸7…Árް¼EKT…æbÄç}¨Ô×W‘Š«=‚5³}êœ"Dõù³Fr«ÜllI,6°Ê´àZÔ}ËÑÑéž°“ ,:M…I 8MÃë°ö{”0Àt°­‹y½” G‘Óãõ&xnŒg°dßb(x>ti>˜,û¡š3±š6&¸àY¥Ó¤äé @§T¡ß6$ `¡ÑçÈbÑŒY̓qX»¿Û‡Ø[!ž%³³Ò…ó%nA (½m¡Ž?JŒþ_k¹f.Û1kí$ª8®w!µ}s˜!|+˜ˆÉ³îfC×X³“ίĕñ«d¢Íf‹,­-?¥²¢˜-² U†VÅò™âl /›Þ±Ó/yœ3¹h–2–­¥ZÁ‘Xî§*‡C[š|ì7—l}‘‡?3mXMÕTs¥óÁòZͽ°1j§ \bKG•¡|é´Ì4'§pˆXš&Š;T—ÍñNÀ=°”Ô»§‹+#X1t·opy«ÕåôÁAd$”Ïhaðøº^žù|Öå%ÀŠ»Ãû’× :â`5l‘ jJ"3•VVT’érë´Bú·B.w^¦bu\#gñN´é;r°lÛ2ÒÜj'Oâj¸ærM)žàªièmÜåå% b²HCn,£|fýrޱ–óâ˜Ó÷œ‡´·ç”cÅ‚È{ŽÆ%Qâ4@ŽùªÌ-A»èµ­°í$Îu´¶âÚnÒ™ >æ,©igÛ!%;¬®d°–\Â,nâl.— JÝXì'6˜$«bXzgEVg²<²ÆòhæàÈ~ˆ¡ñ¶<Ñõ0Ú»Ùv„Â*Öæµ &—QñCQµÁ~‰SêtRÒ/,dº#Ì\ª·$×äù"°¹/äýå¥%¨ëø}<Í£óV- ÛëYª™?y뛑Ëäµtž©Ṵ́sRý×#<ƬÜ7k‡ Á&XÑ]MW††–÷šwï3–Y‰¤¤ÏŽ‹ <×Y@¨‹»ý°Ÿ,wËEû@^ºÖªy.‡tÜ%ËÆ3•Íþ ¦ÑΆj†®téI‚ÖfÑLÓ=¸jVàf'•ä Ø¼j2¸Ì=—{»ÁÞç!k.å• Œ‹ >¦2Ív`Nk0ª±dëjS_ qaCãÉÕ†¶p}°V+\&–5/‡‘³ô3ÀRª\¡A¿iþ[Ýgùá¼=mŽt¹*y4N;g[ÇqZ±¾«BxU (‰)QÐtj×Í]Sä¾ôÝS„y«¢Â¸ ™ÏÅúÒEWøa°ä^$T%F µV½™¥Q7ßs ˉëFK¥±RœA ü°2Ù7uß•Zß\©)¯’˜e.Îr£Ó‘ºæ¢¨L]E°¤Ñ®4°l3õ³Áb®Ò›šr¶–û”.Û£–ÙÊ÷ÀÒ*Ös6B‹(Xe¥´}4]ÙÀÀeXU½Q†k—¸¦é ¬Œ–ãÐÀ²rM⽆=6á­ËKS^­sW°ì2Ä›?8ëa–ÂF VˆQ<'g °ú]¨ÊWÞô¾ä"˜ÀšÅÍq}o†,î¡’Ùk¡î` ‹h¸<¼Ç6å [“ª¨ëŠœÌ9¯â…¾«1{aÄ9yµLÊãm¬‡²a )¾Æ&+ ©¥RMÉ.ooVþ8+)¢JÑâ7>MÖµX Áêy§ZÇ`…XRÅLÁ ÛûÁ¹Ž‡n¹>X¶AïœÃp›¨³LX﫬ö2dÖOˆuìÒW¹ÝõšÁ®æ^¬¬ŒÇ¶^†Ï•:¾O¶; †D–”ÖIÔ‘YD„&¨yõÛ¦ñNÉVCáC2¸ùgÃ^äÈB®+Íãê!$ IDAT G°¤w,WðxǧèÉö8ñ’‘áår°Ž?VêÊ«Sõ*ëñ3Îq+)äbt«*ÉCK<}mðd° Ò+ñ>¯5í¾m{ ¦]¨ÃÎJ¶ èzÉ;f³I¡afžÞ>ÁR€£Œ ²K|n¡`ÍçõÍž\é››Õ†l­¶˜ Š4€ˆ–Nf`i8ŽÁªï×YT°Î–«DZ(˜ÈÖFôê¤þ¼MÀ#ø®Aª˜¶XVŸd\Uʉc”á’Ëæ¡´¸†MSà ÉH¸AÄêXŠX¾‚qÆó!Æz1Òáè(q]^.5ønã•$ò°¬um“þóµ÷Ç`ɺ^¨ÎŠ ^<ÆóÁr¦wÇÀ2JŒÅEvî^­ô²Tʳ¢ÅPÁÊÐŒŬEx Å!(XŒçŠ‚ÉÞƒ¥qUë ß0Å«ŠÄëúûÜD˜zh‰k6ûR|5å˜HÛ'![ñ[žÆ®üW‡? N´×‚ Rt ÖFçÜ=,qgØk?êdnGk:^bhÿ¹Ä`ÅÙ"KËeôeˆm@µF³€Ê| ø]JpFý^ÇvV,ù¢.£V*;»Ÿ Áª1sèõÈ’aü†q¥i —b5“”5Â~Õvë³¾I‹Áx‹n3s¤Ï+™Z2;âóŠã¤Ä/(†ò˜r°æÚLÇpL§h"P5y“©6’¡.½…,†XÂ^H´µÔº ÃU™ùEКÚrxP°Hç`œf`ÍfN6ûÄqÛîs,Ëëq]ȇ+šÆç^-‰²"öæ#N37;ÚÛ¯ØÔs7 æ­°QÉes5â—¼¿Õœ7ª¾kåi7:X¬à&üsqQÌ«ÚB4ÙKøï¼KQÕ™K÷˜¸O }æÍ} ÂÉ,Å `ÅÓG°f³ù²Án] ´»%Ê ¬Ùœ+BgÖ\VS+ZîÜ­äöà‹Sɺ­„ÇÜRÅXÓW¯‡ÔtšÌRA6äRSœN†“L’ÿå´JF+I¼ÃñΚS§bhÃÁkí±zX“$‹I{ ›âŽyK¹ëuÑBŸ#"»V¬Kó<Ôå™Ï›’;¾ƒÍßè9‡,2áf°dgkï®Î˨oÐû>^#`YCÁ‰PÁ ÒTR]4V¤â§,‰I‰ÆÏæ\•äûŒÁ’,ŸK` ^+Ø`Þ’'‹×DHKc†ŽõHhå5`Š4×ð‘—Ù7u}yÁ#2°|Jî[ö:/mœŽù¼P×PwËbý›âÑ—t³q)ÍB6YOn™£õ %²"\¬‡l2±äñÅZ*Ë7±žÂû£Á¸>硼{hȦµ9E¸£^¾¢/VÀDMoh‰ô Åjé\l€•í@6W]U› ,;èi×Õ &ЌɪŒ†Jþ54—xì6<Ü3k­šÕ\Õz–ïJWÚÿ›;Â&“Å‚¹P¥eSÇx…xª¯;¢U¤SVUšž˜´Bfo½ŽšXqãMæ¬X~;½èÉ€KÏÐòúú§ü؉d°6–'ž V×@,ôÀâ`‘P 8öe´ÜÇÅg·ÚÐR#»@|Q!ö{–ÂÊüÇg_â)‰Ãê5Áâ”y#»úxQZ+ ˜N'æû X}¢a~ù}¦/¸:õxgç^šb³ˆ\úûu9k"CÅ;Ì´³CEgͤò.ªÑdÊhöÀãõe«NŒõ‚ûµÚáÕ£×K¿W[ ãZl~ª”¹\p=Yàús)Ìë%¶k=ºä1ËzÕÐH§£¯ìÍuœXö‘¨£D‚YÕýík¬z©ËÁ+^v¶þk¯wÖ†ÉÖHf-câ"Nö›ÄVt¸ByþQ‘#“ÙkSW2Éz¬fãýQÕÚÈ6§¦©S¸1é3:ç ûÕZó¹†gŒ±6•ÖúšôÁаd çûX™Á' XyäSÀšÎeeÖ oƒr°¦¥¥Æ¹‡­,¹íòØ7åy‚˜~Ü4«LÆ󽎎áòYb½!êiA.‡æM±ªcWËêâ"cŽiTù°*µÌ×ÁwÀmú6+ MXÖ•Ö²|ÄXÓQ°œº…¦ÞÍ×™3R8HzO0¦ôxk(†“I’ÃY«gn*Dªjþd¿ðÍÑÀ™ºF†M’ŽÏ9k ¬ÂšÿL —ußz'£ALµgo˜üF¨§à§¬ã…µ|¶ãÏ’}¯tXœzË©nT°Ð©¼±¬°°$ëønìµ ±‡2Íì3?>jyù3›DãÝêãf ²G«ÜÓ¡?²BÞ¯{_¯F.nüÚYˆ/*ùÌŠŸÀ"ŸÆ_ÁW‹jàÖš*Rü©(cYM)ïë­)£˜f.ð‡ NïW€+‚µ±„ËëK¾:œc{«‰;li„Ïqo"1+„â“QN –èy™“ò¨ç(Xü!ç,K‰™ßì¦Q«áR¨¡ÂÇ ÏW$’÷²é;,j;)‹ƒ5ѰH\Ë8Xߪr— ZÆb•OÓ¯vWÕ% œkŽÕÌ ÎVš²7E÷µïê•ÁO麵Ì8j¹ƒâ1ŒÓÙùÜ+ÉCþ³ò†:šßÍzÉ_­ò½r‚ÒøIH2‰EZ ]cT¡J•3+-Aú†hvœ)/´oÆÀB‡µ¾>”Ç ÷QÖ¼ GÕ˜ÕÐ4ÍãêŒÞ E°R¸7™w0ؘI ™J¦é–q÷–db¡Ë‡7_ú¶°ò”u‹&;ÞŒ¢Û­+æ*—¶ºI¶{-ò¾5¬Æ /Ò$3E‹ ·Xò²4E¡5"9T¦²¾¥øh¢VÒdÄsäTÛ¬ƒ-« v‚TÃú)AµI|õÍ„üË{ßÛy2èçYûm#»«1Z›Xyÿ3#`Ù4¥aåæ°ÞÎF‡X"„—ß”…•ѬW¾û¶ÃHSVDJ{ûùg¬îdí.žßœ +©7¨xPzÃ*¿]7'ë_s—õ65›þÅr(û@~³P™âê¡%Xž™¬¿!«÷·)-·€úÚ÷õ*Ô7¶xµ)oÂ(/Ó0Wïµa¬šø*ÏVs4‚ò4bæ`uC¤hÁŽ(ç\eó G“…fŠ•Y[i¤î bÆbºÐ˜à7–ðÖBѲi²÷‚•ë0VY29$‚õí¢•dQx«Ší2í>ÇÈe3z#s}í{z5Êb€=î =¼žÖÿªâÕð†C ÙIEND®B`‚jpgraph-1.5.2/src/Examples/bartutex12.php0100644000076400001440000000453507437547531016770 0ustar ljpusersSetBackgroundImage("tiger_bkg.png",3); $graph->SetShadow(); // Use text X-scale so we can text labels on the X-axis $graph->SetScale("textlin"); // Y2-axis is linear $graph->SetY2Scale("lin"); // Color the two Y-axis to make them easier to associate // to the corresponding plot (we keep the axis black though) $graph->yaxis->SetColor("black","red"); $graph->y2axis->SetColor("black","orange"); // Set title and subtitle $graph->title->Set("Combined bar and line plot"); $graph->subtitle->Set("100 data points, X-Scale: 'text'"); // Use built in font (don't need TTF support) $graph->title->SetFont(FF_FONT1,FS_BOLD); // Make the margin around the plot a little bit bigger then default $graph->img->SetMargin(40,140,40,80); // Slightly adjust the legend from it's default position in the // top right corner to middle right side $graph->legend->Pos(0.03,0.5,"right","center"); // Display every 6:th tickmark $graph->xaxis->SetTextTickInterval(6); // Label every 2:nd tick mark $graph->xaxis->SetTextLabelInterval(2); // Setup the labels $graph->xaxis->SetTickLabels($databarx); $graph->xaxis->SetLabelAngle(90); // Create a red line plot $p1 = new LinePlot($datay); $p1->SetColor("red"); $p1->SetLegend("Pressure"); // Create the bar plot $b1 = new BarPlot($databary); $b1->SetLegend("Temperature"); $b1->SetFillColor("orange"); $b1->SetAbsWidth(8); // Drop shadow on bars adjust the default values a little bit $b1->SetShadow("steelblue",2,2); // The order the plots are added determines who's ontop $graph->Add($p1); $graph->AddY2($b1); // Finally output the image $graph->Stroke(); ?> jpgraph-1.5.2/src/Examples/pie3dex1.php0100754000076400001440000000127007437547531016404 0ustar ljpusersSetShadow(); // Set A title for the plot $graph->title->Set("Example 1 3D Pie plot"); $graph->title->SetFont(FF_VERDANA,FS_BOLD,18); $graph->title->SetColor("darkblue"); $graph->legend->Pos(0.1,0.2); // Create pie plot $p1 = new PiePlot3d($data); $p1->SetTheme("sand"); $p1->SetCenter(0.4); $p1->SetAngle(30); $p1->SetFont(FF_ARIAL,FS_NORMAL,12); $p1->SetLegends(array("Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct")); $graph->Add($p1); $graph->Stroke(); ?> jpgraph-1.5.2/src/jpgraph_scatter.php0100644000076400001440000000464107437547531016367 0ustar ljpusersPlot($datay,$datax); $this->mark = new PlotMark(); $this->mark->SetType(MARK_CIRCLE); $this->mark->SetColor($this->color); } //--------------- // PUBLIC METHODS function SetImpuls($f=true) { $this->impuls = $f; } // Combine the scatter plot points with a line function SetLinkPoints($f=true,$lpc="black",$weight=1) { $this->linkpoints=$f; $this->linkpointcolor=$lpc; $this->linkpointweight=$weight; } function Stroke(&$img,&$xscale,&$yscale) { $ymin=$yscale->scale_abs[0]; if( $yscale->scale[0] < 0 ) $yzero=$yscale->Translate(0); else $yzero=$yscale->scale_abs[0]; for( $i=0; $i<$this->numpoints; ++$i ) { if( isset($this->coords[1]) ) $xt = $xscale->Translate($this->coords[1][$i]); else $xt = $xscale->Translate($i); $yt = $yscale->Translate($this->coords[0][$i]); if( $this->linkpoints && isset($yt_old) ) { $img->SetColor($this->linkpointcolor); $img->SetLineWeight($this->linkpointweight); $img->Line($xt_old,$yt_old,$xt,$yt); } if( $this->impuls ) { $img->SetColor($this->color); $img->SetLineWeight($this->weight); $img->Line($xt,$yzero,$xt,$yt); } $this->mark->Stroke($img,$xt,$yt); $xt_old = $xt; $yt_old = $yt; } } // Framework function function Legend(&$aGraph) { if( $this->legend != "" ) { $aGraph->legend->Add($this->legend,$this->mark->fill_color); } } } // Class /* EOF */ ?>jpgraph-1.5.2/src/jpgraph_log.php0100644000076400001440000001206307437547531015500 0ustar ljpusersLinearScale($min,$max,$type); $this->ticks = new LogTicks(); } //---------------- // PUBLIC METHODS // Translate between world and screen function Translate($a) { if( $a==0 ) $a=1; $a=log10($a); return floor($this->off + ($a*1.0 - $this->scale[0]) * $this->scale_factor); } // Relative translate (don't include offset) usefull when we just want // to know the relative position (in pixels) on the axis function RelTranslate($a) { if( $a==0 ) $a=1; $a=log10($a); return ($a*1.0 - $this->scale[0]) * $this->scale_factor; } function GetMinVal() { return pow(10,$this->scale[0]); } function GetMaxVal() { return pow(10,$this->scale[1]); } // Logarithmic autoscaling is much simplier since we just // set the min and max to logs of the min and max values. // Note that for log autoscale the "maxstep" the fourth argument // isn't used. This is just included to give the method the same // signature as the linear counterpart. function AutoScale(&$img,$min,$max,$dummy) { if( $min==0 ) $min=1; assert($max>0); $smin = floor(log10($min)); $smax = ceil(log10($max)); $this->Update($img,$smin,$smax); } //--------------- // PRIVATE METHODS } // Class //=================================================== // CLASS LogTicks // Description: //=================================================== class LogTicks extends Ticks{ //--------------- // CONSTRUCTOR function LogTicks() { } //--------------- // PUBLIC METHODS function IsSpecified() { return true; } // For log scale it's meaningless to speak about a major step // We just return -1 to make the framework happy specificall // StrokeLabels() function GetMajor() { return -1; } // Draw ticks on image "img" using scale "scale". The axis absolute // position in the image is specified in pos, i.e. for an x-axis // it specifies the absolute y-coord and for Y-ticks it specified the // absolute x-position. function Stroke(&$img,&$scale,$pos) { $start = $scale->GetMinVal(); $limit = $scale->GetMaxVal(); $nextMajor = 10*$start; $step = $nextMajor / 10.0; $img->SetLineWeight($this->weight); if( $scale->type == "y" ) { // member direction specified if the ticks should be on // left or right side. $a=$pos + $this->direction*$this->GetMinTickAbsSize(); $a2=$pos + $this->direction*$this->GetMajTickAbsSize(); $count=1; $this->maj_ticks_pos[0]=$scale->Translate($start); $this->maj_ticklabels_pos[0]=$scale->Translate($start); if( $this->supress_first ) $this->maj_ticks_label[0]=""; else $this->maj_ticks_label[0]=$start; $i=1; for($y=$start; $y<=$limit; $y+=$step,++$count ) { $ys=$scale->Translate($y); $this->ticks_pos[]=$ys; $this->ticklabels_pos[]=$ys; if( $count % 10 == 0 ) { if( $this->majcolor!="" ) $img->PushColor($this->majcolor); $img->Line($pos,$ys,$a2,$ys); if( $this->majcolor!="" ) $img->PopColor(); $this->maj_ticks_pos[$i]=$ys; $this->maj_ticklabels_pos[$i]=$ys; $this->maj_ticks_label[$i]=$nextMajor; ++$i; $nextMajor *= 10; $step *= 10; $count=1; } else { if( $this->mincolor!="" ) $img->PushColor($this->mincolor); $img->Line($pos,$ys,$a,$ys); if( $this->mincolor!="" ) $img->PopCOlor(); } } } else { $a=$pos - $this->direction*$this->GetMinTickAbsSize(); $a2=$pos - $this->direction*$this->GetMajTickAbsSize(); $count=1; $this->maj_ticks_pos[0]=$scale->Translate($start); $this->maj_ticklabels_pos[0]=$scale->Translate($start); if( $this->supress_first ) $this->maj_ticks_label[0]=""; else $this->maj_ticks_label[0]=$start; $i=1; for($x=$start; $x<=$limit; $x+=$step,++$count ) { $xs=$scale->Translate($x); $this->ticks_pos[]=$xs; $this->ticklabels_pos[]=$xs; if( $count % 10 == 0 ) { $img->Line($xs,$pos,$xs,$a2); $this->maj_ticks_pos[$i]=$xs; $this->maj_ticklabels_pos[$i]=$xs; $this->maj_ticks_label[$i]=$nextMajor; ++$i; $nextMajor *= 10; $step *= 10; $count=1; } else $img->Line($xs,$pos,$xs,$a); } } return true; } } // Class /* EOF */ ?>jpgraph-1.5.2/src/jpgraph_spider.php0100644000076400001440000004102507437547531016205 0ustar ljpusersfont_family = $family; $this->font_style = $style; $this->font_size = $size; } function SetColor($c) { $this->font_color = $c; } } class SpiderLogTicks extends Ticks { //--------------- // CONSTRUCTOR function SpiderLogTicks() { } //--------------- // PUBLIC METHODS // TODO: Add Argument grid function Stroke(&$aImg,&$grid,$aPos,$aAxisAngle,&$aScale,&$aMajPos,&$aMajLabel) { $start = $aScale->GetMinVal(); $limit = $aScale->GetMaxVal(); $nextMajor = 10*$start; $step = $nextMajor / 10.0; $count=1; $ticklen_maj=5; $dx_maj=round(sin($aAxisAngle)*$ticklen_maj); $dy_maj=round(cos($aAxisAngle)*$ticklen_maj); $ticklen_min=3; $dx_min=round(sin($aAxisAngle)*$ticklen_min); $dy_min=round(cos($aAxisAngle)*$ticklen_min); $aMajPos=array(); $aMajLabel=array(); if( $this->supress_first ) $aMajLabel[]=""; else $aMajLabel[]=$start; $yr=$aScale->RelTranslate($start); $xt=round($yr*cos($aAxisAngle))+$aScale->scale_abs[0]; $yt=$aPos-round($yr*sin($aAxisAngle)); $aMajPos[]=$xt+2*$dx_maj; $aMajPos[]=$yt-$aImg->GetFontheight()/2; $grid[]=$xt; $grid[]=$yt; $aImg->SetLineWeight($this->weight); for($y=$start; $y<=$limit; $y+=$step,++$count ) { $yr=$aScale->RelTranslate($y); $xt=round($yr*cos($aAxisAngle))+$aScale->scale_abs[0]; $yt=$aPos-round($yr*sin($aAxisAngle)); if( $count % 10 == 0 ) { $grid[]=$xt; $grid[]=$yt; $aMajPos[]=$xt+2*$dx_maj; $aMajPos[]=$yt-$aImg->GetFontheight()/2; if( !$this->supress_tickmarks ) { if( $this->majcolor!="" ) $aImg->PushColor($this->majcolor); $aImg->Line($xt+$dx_maj,$yt+$dy_maj,$xt-$dx_maj,$yt-$dy_maj); if( $this->majcolor!="" ) $aImg->PopColor(); } $aMajLabel[]=$nextMajor; $nextMajor *= 10; $step *= 10; $count=1; } else if( !$this->supress_minor_tickmarks ) { if( $this->mincolor!="" ) $aImg->PushColor($this->mincolor); $aImg->Line($xt+$dx_min,$yt+$dy_min,$xt-$dx_min,$yt-$dy_min); if( $this->mincolor!="" ) $aImg->PopColor(); } } } } class SpiderLinearTicks extends LinearTicks { //--------------- // CONSTRUCTOR function SpiderLinearTicks() { // Empty } //--------------- // PUBLIC METHODS // TODO: Add argument grid function Stroke(&$aImg,&$grid,$aPos,$aAxisAngle,&$aScale,&$aMajPos,&$aMajLabel) { // Prepare to draw linear ticks $maj_step_abs = abs($aScale->scale_factor*$this->major_step); $min_step_abs = abs($aScale->scale_factor*$this->minor_step); $nbrmaj = floor(($aScale->world_abs_size)/$maj_step_abs); $nbrmin = floor(($aScale->world_abs_size)/$min_step_abs); $skip = round($nbrmin/$nbrmaj); // Don't draw minor ontop of major // Draw major ticks $ticklen2=4; $dx=round(sin($aAxisAngle)*$ticklen2); $dy=round(cos($aAxisAngle)*$ticklen2); $label=$aScale->scale[0]+$this->major_step; $aImg->SetLineWeight($this->weight); for($i=1; $i<=$nbrmaj; ++$i) { $xt=round($i*$maj_step_abs*cos($aAxisAngle))+$aScale->scale_abs[0]; $yt=$aPos-round($i*$maj_step_abs*sin($aAxisAngle)); $aMajLabel[]=$label; $label += $this->major_step; $grid[]=$xt; $grid[]=$yt; $aMajPos[($i-1)*2]=$xt+2*$dx; $aMajPos[($i-1)*2+1]=$yt-$aImg->GetFontheight()/2; if( !$this->supress_tickmarks ) { if( $this->majcolor!="" ) $aImg->PushColor($this->majcolor); $aImg->Line($xt+$dx,$yt+$dy,$xt-$dx,$yt-$dy); if( $this->majcolor!="" ) $aImg->PopColor(); } } // Draw minor ticks $ticklen2=3; $dx=round(sin($aAxisAngle)*$ticklen2); $dy=round(cos($aAxisAngle)*$ticklen2); if( !$this->supress_tickmarks && !$this->supress_minor_tickmarks) { if( $this->mincolor!="" ) $aImg->PushColor($this->mincolor); for($i=1; $i<=$nbrmin; ++$i) { if( ($i % $skip) == 0 ) continue; $xt=round($i*$min_step_abs*cos($aAxisAngle))+$aScale->scale_abs[0]; $yt=$pos-round($i*$min_step_abs*sin($aAxisAngle)); $aImg->Line($xt+$dx,$yt+$dy,$xt-$dx,$yt-$dy); } if( $this->mincolor!="" ) $aImg->PopColor(); } } } //=================================================== // CLASS SpiderAxis // Description: Implements axis for the spider graph //=================================================== class SpiderAxis extends Axis { var $title_color="navy"; var $title=null; //--------------- // CONSTRUCTOR function SpiderAxis(&$img,&$aScale,$color=array(0,0,0)) { parent::Axis($img,$aScale,$color); $this->len=$img->plotheight; $this->font_size = FF_FONT1; $this->title = new FontProp(); $this->color = array(0,0,0); } //--------------- // PUBLIC METHODS function SetTickLabels($l) { $this->ticks_label = $l; } // Stroke the axis // $pos = Vertical position of axis // $aAxisAngle = Axis angle // $grid = Returns an array with positions used to draw the grid // $lf = Label flag, TRUE if the axis should have labels function Stroke($pos,$aAxisAngle,&$grid,$title,$lf) { $this->img->SetColor($this->color); // Determine end points for the axis $x=round($this->scale->world_abs_size*cos($aAxisAngle)+$this->scale->scale_abs[0]); $y=round($pos-$this->scale->world_abs_size*sin($aAxisAngle)); // Draw axis $this->img->SetColor($this->color); $this->img->SetLineWeight($this->weight); if( !$this->hide ) $this->img->Line($this->scale->scale_abs[0],$pos,$x,$y); $this->scale->ticks->Stroke($this->img,$grid,$pos,$aAxisAngle,$this->scale,$majpos,$majlabel); // Draw labels if( $lf && !$this->hide ) { $this->img->SetFont($this->font_family,$this->font_style,$this->font_size); $this->img->SetTextAlign("left","top"); $this->img->SetColor($this->color); // majpos contsins (x,y) coordinates for labels for($i=0; $iticks_label != null ) $this->img->StrokeText($majpos[$i*2],$majpos[$i*2+1],$this->ticks_label[$i]); else $this->img->StrokeText($majpos[$i*2],$majpos[$i*2+1],$majlabel[$i]); } } $this->_StrokeAxisTitle($pos,$aAxisAngle,$title); } //--------------- // PRIVATE METHODS function _StrokeAxisTitle($pos,$aAxisAngle,$title) { // Draw title of this axis $this->img->SetFont($this->title->font_family,$this->title->font_style,$this->title->font_size); $this->img->SetColor($this->title->font_color); $marg=6; $xt=round(($this->scale->world_abs_size+$marg)*cos($aAxisAngle)+$this->scale->scale_abs[0]); $yt=round($pos-($this->scale->world_abs_size+$marg)*sin($aAxisAngle)); // Position the axis title. // dx, dy is the offset from the top left corner of the bounding box that sorrounds the text // that intersects with the extension of the corresponding axis. The code looks a little // bit messy but this is really the only way of having a reasonable position of the // axis titles. $h=$this->img->GetFontHeight(); $w=$this->img->GetTextWidth($title); while( $aAxisAngle > 2*M_PI ) $aAxisAngle -= 2*M_PI; if( $aAxisAngle>=7*M_PI/4 || $aAxisAngle <= M_PI/4 ) $dx=0; if( $aAxisAngle>=M_PI/4 && $aAxisAngle <= 3*M_PI/4 ) $dx=($aAxisAngle-M_PI/4)*2/M_PI; if( $aAxisAngle>=3*M_PI/4 && $aAxisAngle <= 5*M_PI/4 ) $dx=1; if( $aAxisAngle>=5*M_PI/4 && $aAxisAngle <= 7*M_PI/4 ) $dx=(1-($aAxisAngle-M_PI*5/4)*2/M_PI); if( $aAxisAngle>=7*M_PI/4 ) $dy=(($aAxisAngle-M_PI)-3*M_PI/4)*2/M_PI; if( $aAxisAngle<=M_PI/4 ) $dy=(1-$aAxisAngle*2/M_PI); if( $aAxisAngle>=M_PI/4 && $aAxisAngle <= 3*M_PI/4 ) $dy=1; if( $aAxisAngle>=3*M_PI/4 && $aAxisAngle <= 5*M_PI/4 ) $dy=(1-($aAxisAngle-3*M_PI/4)*2/M_PI); if( $aAxisAngle>=5*M_PI/4 && $aAxisAngle <= 7*M_PI/4 ) $dy=0; if( !$this->hide ) $this->img->StrokeText($xt-$dx*$w,$yt-$dy*$h,$title); } } // Class //=================================================== // CLASS SpiderGrid // Description: Draws grid for the spider graph //=================================================== class SpiderGrid extends Grid { //------------ // CONSTRUCTOR function SpiderGrid() { } //---------------- // PRIVATE METHODS function Stroke(&$img,&$grid) { if( !$this->show ) return; $nbrticks = count($grid[0])/2; $nbrpnts = count($grid); $img->SetColor($this->grid_color); $img->SetLineWeight($this->weight); for($i=0; $i<$nbrticks; ++$i) { for($j=0; $j<$nbrpnts; ++$j) { $pnts[$j*2]=$grid[$j][$i*2]; $pnts[$j*2+1]=$grid[$j][$i*2+1]; } for($k=0; $k<$nbrpnts; ++$k ){ $l=($k+1)%$nbrpnts; if( $this->type == "solid" ) $img->Line($pnts[$k*2],$pnts[$k*2+1],$pnts[$l*2],$pnts[$l*2+1]); elseif( $this->type == "dotted" ) $img->DashedLine($pnts[$k*2],$pnts[$k*2+1],$pnts[$l*2],$pnts[$l*2+1],1,6); elseif( $this->type == "dashed" ) $img->DashedLine($pnts[$k*2],$pnts[$k*2+1],$pnts[$l*2],$pnts[$l*2+1],2,4); elseif( $this->type == "longdashed" ) $img->DashedLine($pnts[$k*2],$pnts[$k*2+1],$pnts[$l*2],$pnts[$l*2+1],8,6); } $pnts=array(); } } } // Class //=================================================== // CLASS SpiderPlot // Description: Plot a spiderplot //=================================================== class SpiderPlot { var $data=array(); var $fill=false, $fill_color=array(200,170,180); var $color=array(0,0,0); var $legend=""; var $weight=1; //--------------- // CONSTRUCTOR function SpiderPlot($data) { $this->data = $data; } //--------------- // PUBLIC METHODS function Min() { return Min($this->data); } function Max() { return Max($this->data); } function SetLegend($legend) { $this->legend=$legend; } function SetFill($f=true) { $this->fill = $f; } function SetLineWeight($w) { $this->weight=$w; } function SetColor($color,$fill_color=array(160,170,180)) { $this->color = $color; $this->fill_color = $fill_color; } function GetCSIMareas() { JpGraphError::Raise("JpGraph Error: Client side image maps not supported for SpiderPlots."); } function Stroke(&$img, $pos, &$scale, $startangle) { $nbrpnts = count($this->data); $astep=2*M_PI/$nbrpnts; $a=$startangle; // Rotate each point to the correct axis-angle // TODO: Update for LogScale for($i=0; $i<$nbrpnts; ++$i) { //$c=$this->data[$i]; $cs=$scale->RelTranslate($this->data[$i]); $x=round($cs*cos($a)+$scale->scale_abs[0]); $y=round($pos-$cs*sin($a)); /* $c=log10($c); $x=round(($c-$scale->scale[0])*$scale->scale_factor*cos($a)+$scale->scale_abs[0]); $y=round($pos-($c-$scale->scale[0])*$scale->scale_factor*sin($a)); */ $pnts[$i*2]=$x; $pnts[$i*2+1]=$y; $a += $astep; } if( $this->fill ) { $img->SetColor($this->fill_color); $img->FilledPolygon($pnts); } $img->SetLineWeight($this->weight); $img->SetColor($this->color); $img->Polygon($pnts); } //--------------- // PRIVATE METHODS function GetCount() { return count($this->data); } function Legend(&$graph) { if( $this->legend=="" ) return; if( $this->fill ) $graph->legend->Add($this->legend,$this->fill_color); else $graph->legend->Add($this->legend,$this->color); } } // Class //=================================================== // CLASS SpiderGraph // Description: Main container for a spider graph //=================================================== class SpiderGraph extends Graph { var $posx; var $posy; var $len; var $plots=null, $axis_title=null; var $grid,$axis=null; //--------------- // CONSTRUCTOR function SpiderGraph($width=300,$height=200,$cachedName="",$timeout=0,$inline=1) { $this->Graph($width,$height,$cachedName,$timeout,$inline); $this->posx=$width/2; $this->posy=$height/2; $this->len=min($width,$height)*0.35; $this->SetColor(array(255,255,255)); $this->SetTickDensity(TICKD_NORMAL); $this->SetScale("lin"); } //--------------- // PUBLIC METHODS function SupressTickMarks($f=true) { $this->axis->scale->ticks->SupressTickMarks($f); } function SetScale($axtype,$ymin=1,$ymax=1) { if( $axtype != "lin" && $axtype != "log" ) { JpGraphError::Raise("Illegal scale for spiderplot ($axtype). Must be \"lin\" or \"log\""); } if( $axtype=="lin" ) { $this->yscale = & new LinearScale(1,1); $this->yscale->ticks = & new SpiderLinearTicks(); $this->yscale->ticks->SupressMinorTickMarks(); } elseif( $axtype=="log" ) { $this->yscale = & new LogScale(1,1); $this->yscale->ticks = & new SpiderLogTicks(); //JpGraphError::Raise("JpGraph Error: Logarithmic spider plots are not yet supported"); } $this->axis = & new SpiderAxis($this->img,$this->yscale); $this->grid = & new SpiderGrid(); } function SetPlotSize($s) { if( $s<0.1 || $s>1 ) JpGraphError::Raise("JpGraph Error: Spider Plot size must be between 0.1 and 1. (Your value=$s)"); $this->len=min($this->img->width,$this->img->height)*$s/2; } function SetTickDensity($densy=TICKD_NORMAL) { $this->ytick_factor=25; switch( $densy ) { case TICKD_DENSE: $this->ytick_factor=12; break; case TICKD_NORMAL: $this->ytick_factor=25; break; case TICKD_SPARSE: $this->ytick_factor=40; break; case TICKD_VERYSPARSE: $this->ytick_factor=70; break; default: JpGraphError::Raise("Unsupported Tick density: $densy"); } } function SetCenter($px,$py=0.5) { assert($px > 0 && $py > 0 ); $this->posx=$this->img->width*$px; $this->posy=$this->img->height*$py; } function SetColor($c) { $this->SetMarginColor($c); } function SetTitles($title) { $this->axis_title = $title; } function Add(&$splot) { $this->plots[]=$splot; } function GetPlotsYMinMax() { $min=$this->plots[0]->Min(); $max=$this->plots[0]->Max(); foreach( $this->plots as $p ) { $max=max($max,$p->Max()); $min=min($min,$p->Min()); } if( $min < 0 ) JpGraphError::Raise("JpGraph Error: Minimum data $min (Spider plots only makes sence to use when all data points > 0)"); return array($min,$max); } // Stroke the Spider graph function Stroke($aStrokeFileName="") { // Set Y-scale if( !$this->yscale->IsSpecified() && count($this->plots)>0 ) { list($min,$max) = $this->GetPlotsYMinMax(); $this->yscale->AutoScale($this->img,0,$max,$this->len/$this->ytick_factor); } // Set start position end length of scale (in absolute pixels) $this->yscale->SetConstants($this->posx,$this->len); // We need as many axis as there are data points $nbrpnts=$this->plots[0]->GetCount(); // If we have no titles just number the axis 1,2,3,... if( $this->axis_title==null ) { for($i=0; $i<$nbrpnts; ++$i ) $this->axis_title[$i] = $i+1; } elseif(count($this->axis_title)<$nbrpnts) JpGraphError::Raise("JpGraph: Number of titles does not match number of points in plot."); for($i=0; $iplots); ++$i ) if( $nbrpnts != $this->plots[$i]->GetCount() ) JpGraphError::Raise("JpGraph: Each spider plot must have the same number of data points."); $this->StrokeFrame(); $astep=2*M_PI/$nbrpnts; // Prepare legends for($i=0; $iplots); ++$i) $this->plots[$i]->Legend($this); $this->legend->Stroke($this->img); // Plot points $a=M_PI/2; for($i=0; $iplots); ++$i ) $this->plots[$i]->Stroke($this->img, $this->posy, $this->yscale, $a); // Draw axis and grid for( $i=0,$a=M_PI/2; $i<$nbrpnts; ++$i, $a+=$astep ) { $this->axis->Stroke($this->posy,$a,$grid[$i],$this->axis_title[$i],$i==0); } $this->grid->Stroke($this->img,$grid); $this->title->Center($this->img->left_margin,$this->img->width-$this->img->right_margin,5); $this->title->Stroke($this->img); // Stroke texts if( $this->texts != null ) foreach( $this->texts as $t) $t->Stroke($this->img); // Finally output the image $this->cache->PutAndStream($this->img,$this->cache_name,$this->inline,$aStrokeFileName); } } // Class /* EOF */ ?>jpgraph-1.5.2/src/Changelog0100644000076400001440000007415407437547531014316 0ustar ljpusersVersion: $Id: Changelog,v 1.8 2002/03/01 00:39:41 aditus Exp $ Changelog for JpGraph ===================== [29-Feb-2002] JpGraph 1.5.2 =========================== Bug fixes: ---------- * Released the correct 3D pie file (By mistake I mixed the stable version with the development branch for 2.0 in the 1.5.1 release just to prove that I'm still human :-) * [me] Fixed out of bounds error when using shadows for bar graphs with 0 value * [me] Fixed typo in DisplayValue::SetFormat() * [me] Fixed potential array out of bounds error in Plot::Min() and Plot::Max() * [me] Fixed misplaced ')' in string construction in call to JpGraph error. Changes/Additions: ------------------ * [me] Added possibility to use "auto" file name when stroking directly to a file. * [me] Added tag 'title' to the image maps to make for better compatibility with Mozilla. * [me] Moved class LineProprty to jpgraph.php from jpgraph_gantt.php since it can be used in other modules as well. * [me]Added Text::GetTextHeight() which differs from Text::GetFontHeight() in that it takes the total text height (possible multiple lines) into account. * [me] Added Image::FilledArc() * [me] Added RotImage::SetTranslation() Added RotImage::Circle() Added RotImage::FilledCircle() Added RotImage::Arc() Added RotImage::FilledArc() [11-Feb-2002] JpGraph 1.5.1 =========================== * [me] No longer treat a not set $y[0] value as an explicit error. Instead silently set $y[0] to 0. * [me] Changed "include" to "require" in jpgraph.php when including jpgraph_dir.php. This seems to fix the strange problem whereby the constants defined in jpgraph_dir.php didn't have a correct value in jpgraph.php. * [me] Fixed problem with correctly drawing of bars when all bars are negative. (Previously the baseline wasn't correctly handled since min/max values needs to be mirrored for negative bars) Note: Funny this problem has gone unnoticed so long. * [me] Fixed problem with doing gradient fill for negative bars. * [me] Fixed problem with autoscaling when there is a very small difference (< 0.00001) between min and max and when both min and max are negative. This might happen if you have a single negative value. * [me] Added labels for line graph. Each point my now also optionally display it's value on a line graph. Value are controlled trough class DisplayValue and it's instance in LinePlot. LinePlot->value->Show(), LinePlot->value->SetColor(), LinePlot->value->SetFont(), LinePlot->value->SetMargin(), LinePlot->value->SetFormat(), [27-Jan-2002] JpGraph 1.5 ========================= * [me] Fixed misnamed xmin variable in Min() for acc bars * [me] Added possibility to specify paragraph alignment for multi line text, i.e the text can be left,right or center aligned within it's bounded box. The lignment is set by the new method Text::ParagraphAlign() * [me] Changed position specification for text so that if the position is specified in range [0,1] it is interpreted as fraction of image height width and otherwise as absolute pixels. * [me] Added possibility to specify pie size (radius) both as a fraction and absolute size in pixels. * [me] Added possibility to tweak color specification by adding a saturation percentage, i.e you can specify color as "red:0.65" which means 65% of the red value (in other words 35% darker). * [me] Tweaked the estimation of number of segments to approximate an arc in Image::CakeSlice. [17-Jan-2002] JpGraph 1.5beta2a =============================== * [me] Fixed typo in Max() calculation for accumulated bar graphs which caused it to return wrong value. * [me] For Min() calculation for acc bars graphs take the user specified ymin into account. * [Peter Svistunov, me] Added Cyrillic unicode support through the global define LANGUAGE_CYRILLIC. This is also the start of a generic support for Unicode languages through the LanguageConv class. [15-Jan-2002] JpGraph 1.5beta2 ============================== * [me] Rewrite of the pie-chart drawing algorithm. This version is slightly slower but avoids using GD floodfill function. This fixes problems with small slices not being filled completely. As an added bonus it is now possible to explode (and specify the explode radius) for all slices. It is also possible to draw the pie without having internal borders between the slices as well as turning on/off the border surronding the pie. * [me] Added graphic primitive CakeSlice() to the Image class. Used to simplify pie-drawing. * [me] Added more generic error handling. It is now possible to install your own error object with JpGraphError::Install() The default error handler will just abort execution. * [me] Security whole in utility script for displaying source and image in frames fixed. * [Cedric Scheyder] Actively ignore hours in calculating Max/Min values for dates in Gantt charts to avoid problems in autoscaling when users specify start and end dates down to hours. * [Rick Widmer] Fixed problem in calculating min/max value when first Y-value was non-numeric. * [me] Fixed calculation of width and height of text with multiple lines. Multiple text lines (text blocks) should now be almost fully supported. [16-Dec-2001] JpGraph 1.5-BETA ============================== * Take "\n" into (some) account when calculating string height and width Text output now supports multiple lines better. * [me] Removed reference to global PHP_SELF, use HTTP_SERVER_VARS array instead. This makes JpGraph working with 'register_globals' turned off. * [me] Added some rudimentary check that GD is enabled before trying to run JpGraph. * [me] Fixed silly cut-and-paste bug in AccBarPlot::Max() which could cause to small max values to be returned * [me] Added property 'title' to PlotMark. The title is printed in the center of the plotmark. * [DanNY (dulcis28@hotmail.com)] Added JpGraph Logo. (Thanks!) * [me] Added jplintphp.php, jpgendoc.php, jplintdriver.php which are parsing, documentation and pretty printing tools I use to help me to documentation and find unused code. Tthat does some simple static analysis on PHP for silly mistakes that I do (Like using instance variables without qualifying them with "$this->" ) The tool also warns about unused instance variables. Since it also parses the classes and methods I use it to generate the documentation skeleton for the reference section. * [me] Added Gantt chart funcionality, jpgraph_gantt.php . See Gantt tutorial for help on usage. * [me] Added new Gantt tutorial * [me] Added BKIMG_CENTER, possibility to center the background image. * [me] Timeout function now also aplies when you generate an image off-line, i.e if the imagefile exist and is within the time window now file will be written. * [Rasmus Lerdorf] Added patch to make background images work with GD 2.x N.B GD 2.01 has bugs in handling TTF font with truecolor images which are fixed in 2.02 but that has (of this writing) still not been officially released. GD 2.x support in JpGraph is still to be considered experimental. * [me] Fixed some potential rounding errors in 2D Pie plot which in some circumstances might have caused a flood fill to escape. Also added check to better handle very small slices so we don't try to do a fill on the border edge. * [me] Slightly changed the internal design for band patterns. They are now created by a factory class instead. This makes it much easier to re-use and have maximum code reuse. * [me] Factored out some functionlity from Graph::Stroke() to make it possible to re-use some code in GanttGraph::Stroke() * [me] One more instance when PHP surprised me by thinking 0 == "-" aarrghhh Now I think (knock on wood) all problems with data points=0 should be solved * [me] Added '&' to the assignment in Graph::Add() This now lets you specify changes for lines, plots even after they been added to a Graph. But I'm not sure if this is really such a good ide because you will have problem if you write code like for( .... ) { $myplot = new LinePlot(.....); $graph->Add($myplot); } Since this will not work the way you think (why?) Because the same reference to the variable $myplot will be used for all additions and hence the graph will only have multiple instances of the last added LinePlot(). Have to think of this and what is the best way. (I will probably never get used to PHP references....) [11-Nov-2001] JpGraph 1.4 ========================== Bug Fixes: ------------------------------------------------------------------------------------- * [me] Enabled E_NOTICE warnings in my PHP installation and found a couple of glitches (harmeless out-of-bound in two loops) which is now corrected. * [me] Fixed problem in line plots where y-value==0 wasn't drawn. (Once again bitten by the fact that in PHP the following is true: ""==0) * [me] Fixed color specification for bars when initialized as an array of colors * [me] Fixed color of bars using shadow which was advertedly set to shadow color * [me] Fixing incorrect color specification for legends using bars with color arrays * [me] Add check for sum=0 in pie plots to avoid divide by 0 problem * [me] Changed the stroke orderd for FilledRectangle() so that the shadow doesn't overwrite a line with weight > 1 * [me] Fixed incorrect calculation of font height for titles which cause the subtitle to be to close to the title. Additions: ------------------------------------------------------------------------------------- * [me] Added depth parameter (DEPTH_FRONT, DEPTH_BACK) for gridlines Graph::SetGridDepth() * [me] Added possibility to add static horizontal and vertical band with a pattern in the plot area. Graph::AddBand() Supports solid, diagonal, stright line, 3D-plane crosses (both diagonal/vertical) patterns. Graph::AddBand() * [me] Added possibility to have static lines in the plot. This is now implemented with new class PlotLine and two new functions Graph::AddLine(), * [me] Added symbolic constants to specify background image types BGIMG_COPY, BGIMG_FILLPLOT, BGIMG_FILLFRAME * [me] Added extended label formatting through either Axis::SetLabelFormatString() C-style formatting string or Axis::SetLabelFormatCallback() A callback function that are given the value to be displayed and should manipulate the value as it likes The use of the old style digit precision variable will be deprecated from next version. * [me] Added error check if supplied Y-data has unspecified value at index 0 to avoid out of bounds error when corrupted data is sent in to JpGraph. * [me] Added possibility to specify image depth for gridlines. You can now specify Graph::SetGridDepth() as DEPTH_FRONT or DEPTH_BACK. Depending on if you want the gridlines at the back of in front of your plots. * [me] Added possibility to specify Cache file name as "auto". In this case the image file name will have the same name as the scriupt that generates the image with the extension of the automtically generated graphic format. NOTE: You will get the wrong extension using this feature at the same time as specifying a different graphic format thne the automatically choosen one. * [me] Added some more advanced examples for impuls drawings impulsex3.php and impulsex4.php * [me] The values on top of bars can now be at an angle and the horisontal position now account for if a shadow is present. * [me] Added filename to Graph::Stroke() which makes it easy to output an image directly to a file _without_ streaming it back to the browser. Usefull for batch processing * [me] Added new tutorial for bar graphs * [me] New scale type "int". This gives a normal linear scale but restricts ticks (and labels) to integer values. Can be used for both X and Y scales. * [me] Added subtitle to graph * [me] Added possibility to specify an array of X-coordinates with bar plots to position individual bars on the X-scale. Makes it much easier to combine bar plots with other types of plots, (line, scatter etc) * [me] Extended utility adjimage.php to allow it to manipulate color saturation. * [me] Added Image::AdjSat() to allow manipulation of the color saturation in the image. This also makes it very easy to change the image to greyscale (just set saturation=-1). Extended Graph::AdjImage() and Graph::AdjBackgroundImage() to include new parameter for saturation value. * [me] Added BarPlot::SetAlign() which makes it possible to align bars relative the tickmark for linear and int scale * [me] Added possibility to absolutely set the width of bars. This will override the automatically decided with based on the scale and tick distance Changes: ------------------------------------------------------------------------------------- * [me] Legend color for scatter plots now becomes the fill color of the mark * [me] Impulsplots now anchors at Y-value = 0 if the y-axis contains both negative and positive values. Otherwise it will go to the lowest value on the Y-axis. * [me] Bar shadows is now connected to bars to make for a stronger 3D effect. * [me] Removed all deprecated references and usage of FONT0, FONT1, FONT2. Note You can no longer use these. Instead use FF_FONT0, FF_FONT1, FF_FONT2 etc * [me] Text scale now starts default labelling at 0 * [me] All plots internally adjusted to start at default X-coordinate 0 to harmonize better with X-scale. * [me] Graph->Stroke() now just returns instead of exit() * [me] Removed flag argument for BarPlot::SetShadow() * [me] Bar plots are know by default filled with lightblue unless otherwise specified. * [me] Changed the way bars are positioned for linear and integer scale for maximum flexibility when mixing barplot with other plots. * [me] The ALT strings for all image maps now uses printf() syntax to display the actual value. If you have used this feature you must update your ALT strings, for example "val=%v" must become "val=%d" or whatever format you choose. * [me] Changed the formatting of bar graphs by changing the framework so that labels on the x-axis using a text scale is now independent on the tick marks. This makes it possible to have the labels centered under each bar but have the tickmarks between the bars as most other commercial graph packages format these typw of graphs. Introduced Axis::SetTextLabelsInterval() Effects jpgraph.php, jpgraph_log.php and jpgraph_bar.php * [me] Renamed Axis::SetTextTicks() to Axis::SetTextTicksInterval() to make the name more descriptive. The old name is deprecated from this version on but will still work until 2.0 to keep compatibility. * [me] Cleaned up implementation of pie3d so it now inherits from pie to avoid a lot of duplicated code and easier maintainance. (A good example of the real life OO programming where you might not see the similarities between two classes until you fully implement them.) File size of jpgraph_pie3d.php has shrunk by roughly 40% [23-Sep-2001] JpGraph 1.3.1 =========================== Additions: * [Michael Anthon] Added client side image maps to 3D pie plots * [me] Added possibility to better control the labeling of pie graphs with an optional label formatting string PiePlot::SetLabelFormat(), PiePlot::SetLabelType() This also makes it possible to have labels with the absolute value and not only the percentage. (same with pie3d) * [me] Added formatting capabilities for legends on pie and pie3d graphs. Can have the value automtically included (Se Examples/pieex6.php) * [me] Added some more examples, negbarvalueex1.php, scatterlinkex2.php, pie3d_csimex1.php pieex6.php Known bugs and omissions: - Client side image maps does not currently handle exploded pie graphs (just normal pie graphs. Bug fixes: * [me] Fixed problem with positioning the displayed values for negative bars * [me] Fixed shadow for negative bars * [me] Fixed problem in Plot::Min(), PlotMax::Max() whereby zeros where not counted towards minimum since in PHP 0=="". This could sometimes cause strange autoscaling. * [Vitaly E. Ashmarin] Wrong arguments to imagejpeg() for combination of specified image quality and filename = "" * [John Milne] BarPlot::SetFillColor() fixed glitch in loop variable [13-Sep-2001] JpGraph 1.3 ========================= Note: I have to the best of my memory tried to give credit where credit is due. Howevever, since ver 1.2.2 I have received over 2000 mail about JpGraph with Questions/Suggestions/Improvments (and a few bug fixes) etc and I might have missed some in the process of going through these mails. The fault is completely my own and if you recognize some idea I have implemented something which you think you should have credit for please drop me a note and I will adjust the add you to the change notes. Known bugs and omissions: - The automatic value on bar graphs does not work well with negative bar graphs. (Quite easy to fix though..) - Client side image maps does not currently handle exploded pie graphs (just normal pie graphs. IMPORTANT NOTICE: * SC (SOURCE COMPATIBILITY) BREAK !: If you want to rotate the image the parameter is no longer supplied directly in the call to Graph() but rather as a method call Graph::SetAngle(). I decided to make this SC break since I judged it more natural to supply the timeout value just efter the specified cache-file name in the Graph() call. Hopefully this will not hit to many people since my hunch is that few people uses the rotate function and it's very easy to fix those script that does so. Bug Fixes: * [michael@anthon.net] Corrected behviour of accumulated bar graph so it now diffrentiate between the accumulated positive and negative values. * [marko@fly.srk.fer.hr] Fixed Max() calculations for accumulated bar graphs where my original code was a little bit sloppy. (I simply took the max for each plot and added those and this might be more then the real maximum.) * [m.purgar@extracom.de] Spotting an incorrect "jpg" in the image where it should have been "jpeg" * [adam.blomberg@euroseek.net,patrik.johansson@euroseek.net] 3D-Pie filling problem for small slices due to the discrapency between GD arc() and the JpGraphs purely mathematical definition of an ellipse. * [delorme.maxime@free.fr] 2D-Pie Floodfill might "escape" for very small values of slices. * [et.al] Improved handling of 0:s vs "" values. This was necessary since PHP treats 0 as "" the same in a number of situations and JpGraph needs to diffrentiate these two cases. This caused 0 data values to be treated as null values and not be inluded in (for example) autoscaling consideration. Additions: * [me] Added new global constant USE_CACHE which makes it possible to disable writing to the cache even if a filename is supplied in th Graph::Graph() method. * [me] Added LinePlot::SetStyle() to make it possible to make dashed, dotted etc lineplots. (See example1.2). Also adjusted legend to display the same style in the legend. * [michael@anthon.net, me] Added client side image maps for all types of bars and 2D pies with possibility to have the actual value shown in an ALT-tag. * [me] Added drop shadow (or rather "right-up" shadow) to bar graphs BarPlot::SetShadow() * [me] Added possibility to have the actual value of bar graphs displayed at top of graphs via BarPlot::ShowValue(), BarPlot::SetValueFont(), SetValueMargin(), SetValueColor() The format of the value is specified according to standard C printf() string formatting i.e. "val=%d" will for example print a string "val=13" * [me] Added possibility to adjust brightness and contrast for background image via the Graph::AdjBackgroundImage() method. * [me] Added possibility to adjust brightness and contrast in the finished image via the Image::AdjBrightContrast() method. * [me] Added possibility to just generate an image to a file and not stream it directly back to the browser. Added parameter $aInline to Graph::Graph() * [me] Added timout for cache, i.e if the image in the cache is older then the specified number of minutes (=0 never re-generate, -1 always regenerate) then re-generate the image. Just specify a timeout in minutes with a call: $mygraph->cache->SetTimeOut(10) * [me] Added possibility to use logarithmic scale for SpiderPlots. This also resulted in a little bit of internal cleanup in jpgraph_spider.php. * [me] Added SetWeight() method to class Ticks() for control of line thickness for ticks * [me] Added SetMarkColor method to class TIcks() which lets you specify different colors for major and minor tick marks. * [me] Added method RelTranslate() to LinearScale() and LogScale() classes which is used in Spider class. This makes a world to screen relative translation. * [me] Added possibility to link data points in a scatter plot with lines by the addition of method ScatterPlot::SetLinkPoints() * [me,john.milne@one2one.co.uk] Added possibility to have individual colors of bars in bar graphs by having BarPlot::SetColor() accept an array as argument. * [sergio@alsernet.es] Make it possibly to have x-tick labels to consist of two lines by inserting a "\n" separator in the text. * [CK1@wwwtech.de] Adding JPEG quality setting. This is done by adding a method SetQuality() to the img class. After creating a graph this can then be used as $mygraph->img->SetQuality($some_qvalue). Currently this only affects JPEG images. * [delorme.maxime@free.fr] Possibility to use different grace value for top and bottom of graph and not just a single value as in 1.2.2 Changes: * [me] Changed group/permission handling for created files to better adjust itself to the way the local Apache user is setup * [me] The default for spider graphs is now NOT to be filled * [me] Allow all datapoints to be 0 which will set the scale to [0,1] * [me] Removed the need for a DIR_BASE variable [29-Apr-2001] JpGraph 1.2.2 =========================== Bug fixes: * Removed reference to non-existent property 'bypass' in class RotImg * Changed to allow the last X-gridline to be drawn (comparison with limit was '<' where it should have been '<=' ) Additions: * Added possibility to use background image * Added possibility to use approximate color through the "USE_APPROX_COLORS" constant * Handling of diffrent form of "null values" for line graphs. An y-value can now be "" or "-". In the first case (a true null value) this mark will cause a disruption in the line graph to indicate that the value is undefined. In the other case specifying the value as "-" will cause the value to be ignored bu the line will still be drawn between the previous data point and the following. Neither of these cases will have any mark drawn. * Added a fatal warning when no more colors can be allocated for the chosen graphic format. Changes: * "Downgraded" anti-aliasing algorithm to use fewer color levels in the transition to avoid using up to much of the color palette * Cleaned up some of the code to not rely on PHP default initialization of variables. This will help those who have got warnings when they have had all error reporting enabled in php.ini (E_ALL) * Legends now show the plot mark (if defined) instead of just a square of the right color. Acknowledgements: * Thanks to kevin@pricetrak.com for suggesting the treatment of pure NULL values. * Thanks to luca_n@hotmail.com for getting my attention to the warnings caused by relying on PHP default initialization of variables. (My installation had E_NOTICE disabled, hence I never got those warning myself.) [29-Mar-2001] JpGraph 1.2.1 =========================== Bug fixes: * When min and max values for autoscaling was equal this resulted in trying to calculate log10(0) = INF resulting in an infinite loop in LinearTicks::Stroke() * When autoscaling was used with only one data point it tried to calculate log10(0) = INF resulting in an infinite loop * fopen("xxx","r") should be fopen("xxx","rb") causes problems on windows system with IIS5 * JPG streaming function was incorrectly called "imagejpg" should be "imagejpeg" (see the difference?) * Non existent color name in jpgraph_pie.php * Removed all deprecated forced references in function calls * The width of the surrunding box was not calculated correctly for internal bold font Additions: * Color themes for pie graphs * Beta release of 3D pie graphs * Added DIR_BASE as constant to make it possible to use one system wide copy of JpGraph. NOTE: This must be set to the directory where JpGraph is installed. Acknowledgements: * (ck1@wwwtech.de) (and a russian guy which I unfortunately lost the name of) for reporting the imagejpg spelling mistake * (ales.gregor@zps.skoda-auto.cz) for finding the binary file problem with IIS * Several people have reported the problem with autoscaling when all Y-values were equal. Thanks to you all for acting as my privet QA team! [18-Mar-2001] JpGraph 1.2 ========================= Additions: ---------- * Added "BRAND_TIMING" which give possibility to brand each image generated with the time (in ms) it took to generate the image. * Added Gradient Fill for bar graphs, The gradient fill allows 6 different styles. * Added Anti-aliasing for lines. Note drawing anti-aliased lines is 7-10 times slower then "normal" lines! * Added full TTF support. this means an internal SC break (Source Code Break). Normal JpGraph script should not be affected if you have used only publized "public" frunctions. The SC break is to allow uniform treatment of both internal fonts and TTF. This has been achieved by changing the parameter list for SetFont(). However, backward compatibility with the old naming conventions for internal fonts are kepot, e.g. SetFont(FONT1_BOLD) still works but is deprecated and will not be valid from 2.0 * Added possibility to control font for title of Spider Axis through the added property 'title' to the axis in the spider graph. * Added 'SetColor()' in pie graphs as a shortcut to SetMarginColor() to set the background color * Added possibility to draw X-axis labels at arbitrary angle. Internal fonts only supports horizontal and verical. * Added possibility to draw boxed text at an angle * Added possibility to have different colors for axis and the labels on the axis by the addition of extra parameter to SetColor() * Added 350 more named colors. * Added canvas "fake" graph to make it easy to draw arbitrary graphics * Added SetCenter() method for line graphs. * Added SetGrace() for autoscaling purposes. Changes: -------- * If you use a text-scale for X-axis the default labels now start at 1 instead of 0 since this is actually a counting scale and it makes more sense to start at 1. * Improved handling of bar-graphs with negative values. * Updated existing examples to use new format for SetFont() * Made it a critical error to specify a non existant font * Changed so that orientation for Text() is now given as an angle, i.e. SetOrientation(45). Old style of using SetOrientation("v") (for vertical) is deprecated. But will work until V2 Bug fixes: ---------- * Improved handling of computational effects on small values in scaling where a rounding error might cause the last label not to be drawn. * The position for the title of X-axis could in some cases be slightly different in first and second pass due to incorrectly determination of the X-axis labels font height. * Specifying an minimum Y-value for Y-axis on bar graphs could on rare occasions (combination of scale values and specified density of autoscaling ticks) cause a gap between the bottom of each bar and the X-axis. [18-Feb-2001] JpGraph 1.1 ========================= Additions/Changes: ------------------ * Added Spider graphs * Added Pie graph * Added Scatter (and impuls) graphs * Added possibility to rotate plots an arbitrary angle * Added step style rendering to lineplot * Added Breseham circle drawing which gives better visual apperance then the built in Arc() in GD (on the expense of CPU and performance) * Improved Polygon and Rectangle drawing so that it will use line weight settings * Improved the visual appearance of lines with weight>1 by correctly calculating (angle wise) the endpoints and using a filled polygon to draw the line. Unfortunately it would require some real improvements in the GD library to really improve the visual appeance of lines with weight>1. This is as good as it gets without writing a low level pixe-by-pixel correct plotting. With my method you get it to look visually aestethic right in 90% of the cases with just 10% work. * Added MARK_FILLEDCIRCLE as new mark type. Note that due too the poor performance of the basic Arc() image primitive in PHP4 the circles isn't perfect circles, they tend to be a a little bit flat at multiples on PI/2. * Added the possibility to have a separate fill- and line- color for marks * Moved Class PlotMark from jpgraph_line.php to base in jpgraph.php since this class is also used with scatter plots. * Made it a critical error to try to use Text X-scale with specified X-data points. Previously no warning was given for this non-defined state. (Using text scale with specified points really doesn't make sense.) * Made it a critical error to use unknown color rather than silently replacing it with black. * Updated documentation to reflect added capability Bug fixes: ---------- * Fixed minor bug in Line() in which it didn't update the last point for use with subsequent LineTo() calls (forgotten $this->) * Eliminated assumptions in DashedLine() that x1<=x2 and y1<=y2 eliminates the potential pixel overshoot. * Fixed a serious bug in Line plot when used with a specified X-scale (not the normal default) since the X-coordinate wasn't read from the correct vector! * Fixed a serious bug whe using as specified X-scale since the maximum value for a plot wasn't correctly passed to the autoscaling. Note: The reason that these two bugs haven't been discovered previously is the fact that my test specs didn't include test cases to do with specified X-axis (I almost never ever use that). This has now been corrected and added to the test suit. * Fixed so the possible box around the plot area correctly honours the weight specified for it. [05-Feb-2001] JpGraph 1.0 ========================= * Initial release. [EOF] jpgraph-1.5.2/src/jpgraph_bar.php0100644000076400001440000005255107437547531015471 0ustar ljpusersimg = $img; } //--------------- // PUBLIC METHODS // Produce a gradient filled rectangle with a smooth transition between // two colors. // ($xl,$yt) Top left corner // ($xr,$yb) Bottom right // $from_color Starting color in gradient // $to_color End color in the gradient // $style Which way is the gradient oriented? function FilledRectangle($xl,$yt,$xr,$yb,$from_color,$to_color,$style=1) { switch( $style ) { case 1: // HORIZONTAL $steps = abs($xr-$xl); $delta = $xr>=$xl ? 1 : -1; $this->GetColArray($from_color,$to_color,$steps,$colors); for( $i=0, $x=$xl; $i<$steps; ++$i ) { $this->img->current_color = $colors[$i]; $this->img->Line($x,$yt,$x,$yb); $x += $delta; } break; case 2: // VERTICAL $steps = abs($yb-$yt); $delta = $yb>=$yt ? 1 : -1; $this->GetColArray($from_color,$to_color,$steps,$colors); for($i=0,$y=$yt; $i<$steps; ++$i) { $this->img->current_color = $colors[$i]; $this->img->Line($xl,$y,$xr,$y); $y += $delta; } break; case 3: // VERTICAL FROM MIDDLE $steps = abs($yb-$yt)/2; $delta = $yb>=$yt ? 1 : -1; $this->GetColArray($from_color,$to_color,$steps,$colors); for($y=$yt, $i=0; $i<$steps; ++$i) { $this->img->current_color = $colors[$i]; $this->img->Line($xl,$y,$xr,$y); $y += $delta; } --$i; for($j=0; $j<$steps; ++$j, --$i) { $this->img->current_color = $colors[$i]; $this->img->Line($xl,$y,$xr,$y); $y += $delta; } $this->img->Line($xl,$y,$xr,$y); break; case 4: // HORIZONTAL FROM MIDDLE $steps = abs($xr-$xl)/2; $delta = $xr>=$xl ? 1 : -1; $this->GetColArray($from_color,$to_color,$steps,$colors); for($x=$xl, $i=0; $i<$steps; ++$i) { $this->img->current_color = $colors[$i]; $this->img->Line($x,$yb,$x,$yt); $x += $delta; } --$i; for($j=0; $j<$steps; ++$j, --$i) { $this->img->current_color = $colors[$i]; $this->img->Line($x,$yb,$x,$yt); $x += $delta; } $this->img->Line($x,$yb,$x,$yt); break; case 6: // HORIZONTAL WIDER MIDDLE $steps = abs($xr-$xl)/3; $delta = $xr>=$xl ? 1 : -1; $this->GetColArray($from_color,$to_color,$steps,$colors); for($x=$xl, $i=0; $i<$steps; ++$i) { $this->img->current_color = $colors[$i]; $this->img->Line($x,$yb,$x,$yt); $x += $delta; } --$i; $this->img->current_color = $colors[$i]; for($j=0; $j< $steps; ++$j) { $this->img->Line($x,$yb,$x,$yt); $x += $delta; } for($j=0; $j<$steps; ++$j, --$i) { $this->img->current_color = $colors[$i]; $this->img->Line($x,$yb,$x,$yt); $x += $delta; } break; case 7: // VERTICAL WIDER MIDDLE $steps = abs($yb-$yt)/3; $delta = $yb>=$yt? 1 : -1; $this->GetColArray($from_color,$to_color,$steps,$colors); for($y=$yt, $i=0; $i<$steps; ++$i) { $this->img->current_color = $colors[$i]; $this->img->Line($xl,$y,$xr,$y); $y += $delta; } --$i; $this->img->current_color = $colors[$i]; for($j=0; $j< $steps; ++$j) { $this->img->Line($xl,$y,$xr,$y); $y += $delta; } for($j=0; $j<$steps; ++$j, --$i) { $this->img->current_color = $colors[$i]; $this->img->Line($xl,$y,$xr,$y); $y += $delta; } break; case 5: // Rectangle $steps = floor(min(($yb-$yt)+1,($xr-$xl)+1)/2); $this->GetColArray($from_color,$to_color,$steps,$colors); $dx = ($xr-$xl)/2; $dy = ($yb-$yt)/2; $x=$xl;$y=$yt;$x2=$xr;$y2=$yb; for($x=$xl, $i=0; $x<$xl+$dx && $y<$yt+$dy ; ++$x, ++$y, --$x2, --$y2, ++$i) { assert($iimg->current_color = $colors[$i]; $this->img->Rectangle($x,$y,$x2,$y2); } $this->img->Line($x,$y,$x2,$y2); break; default: die("JpGraph Error: Unknown gradient style (=$style)."); break; } } //--------------- // PRIVATE METHODS // Add to the image color map the necessary colors to do the transition // between the two colors using $numcolors intermediate colors function GetColArray($from_color,$to_color,$arr_size,&$colors,$numcols=100) { if( $arr_size==0 ) return; // If color is give as text get it's corresponding r,g,b values $from_color = $this->img->rgb->Color($from_color); $to_color = $this->img->rgb->Color($to_color); $rdelta=($to_color[0]-$from_color[0])/$numcols; $gdelta=($to_color[1]-$from_color[1])/$numcols; $bdelta=($to_color[2]-$from_color[2])/$numcols; $stepspercolor = $numcols/$arr_size; $prevcolnum = -1; for ($i=0; $i<$arr_size; ++$i) { $colnum = floor($stepspercolor*$i); if ( $colnum == $prevcolnum ) $colors[$i] = $colidx; else { $r = floor($from_color[0] + $colnum*$rdelta); $g = floor($from_color[1] + $colnum*$gdelta); $b = floor($from_color[2] + $colnum*$bdelta); $colidx = $this->img->rgb->Allocate(sprintf("#%02x%02x%02x",$r,$g,$b)); $colors[$i] = $colidx; } $prevcolnum = $colnum; } } } // Class //=================================================== // CLASS BarPlot // Description: Main code to produce a bar plot //=================================================== class BarPlot extends Plot { var $width=0.4; // in percent of major ticks var $abswidth=-1; // Width in absolute pixels var $fill_color="lightblue"; // Default is to fill with light blue var $ybase=0; // Bars start at 0 var $align="left"; var $grad=false,$grad_style=1; var $grad_fromcolor=array(50,50,200),$grad_tocolor=array(255,255,255); var $bar_shadow=false; var $bar_shadow_color="black"; var $bar_shadow_hsize=3,$bar_shadow_vsize=3; var $show_value=false,$show_value_format="%d",$show_value_angle=0; var $show_value_ff=FF_FONT1,$show_value_fs=FS_NORMAL,$show_value_fsize=12; var $show_value_color="black",$show_value_margin=3; //--------------- // CONSTRUCTOR function BarPlot(&$datay,$datax=false) { $this->Plot($datay,$datax); ++$this->numpoints; } //--------------- // PUBLIC METHODS // Set a drop shadow for the bar (or rather an "up-right" shadow) function SetShadow($color="black",$hsize=3,$vsize=3) { $this->bar_shadow=true; $this->bar_shadow_color=$color; $this->bar_shadow_vsize=$vsize; $this->bar_shadow_hsize=$hsize; // Adjust the value margin to compensate for shadow $this->show_value_margin += $vsize; } // Display the value of the bar at the top of bar function ShowValue($f=true) { $this->show_value = $f; } function SetValueFormat($format="%d",$angle=0) { $this->show_value_format = $format; $this->show_value_angle = $angle; } function SetValueFont($ff=FF_FONT1,$fs=FS_NORMAL,$size=10) { $this->show_value_ff=$ff; $this->show_value_fs=$fs; $this->show_value_fsize=$size; } function SetValueColor($color) { $this->show_value_color=$color; } function SetValueMargin($m) { $this->show_value_margin=$m; } function SetYStart($y) { die("JpGraph Error: Deprecated function SetYStart. Use SetYMin() instead."); } // DEPRECATED use SetYBase instead function SetYMin($y) { $this->ybase=$y; } // function SetYBase($y) { $this->ybase=$y; } function Legend(&$graph) { if( $this->fill_color && $this->legend!="" ) { if( is_array($this->fill_color) ) $graph->legend->Add($this->legend,$this->fill_color[0]); else $graph->legend->Add($this->legend,$this->fill_color); } } // Gets called before any axis are stroked function PreStrokeAdjust(&$graph) { parent::PreStrokeAdjust($graph); // 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); // Position the labels under each bar in the middle of the // major steps. $graph->SetTextScaleOff(0.5-$this->width/2); } else { // 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*count($this->coords[0])); } } 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($w) { assert($w > 0 && $w <= 1.0); $this->width=$w; } // Specify width in absolute pixels. If specified this // overrides SetWidth() function SetAbsWidth($w) { $this->abswidth=$w; } function SetAlign($a) { $this->align=$a; } function SetNoFill() { $this->grad = false; $this->fill_color=false; } function SetFillColor($c) { $this->fill_color=$c; } function SetFillGradient($from_color,$to_color,$style) { $this->grad=true; $this->grad_fromcolor=$from_color; $this->grad_tocolor=$to_color; $this->grad_style=$style; } function Stroke(&$img,&$xscale,&$yscale) { $numpoints = count($this->coords[0]); if( isset($this->coords[1]) ) { if( count($this->coords[1])!=$numpoints ) die("JpGraph Error: 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]); if( $yscale->scale[0] >= 0 ) $zp=$yscale->scale_abs[0]; else $zp=$yscale->Translate(0.0); if( $this->abswidth > -1 ) $abswidth=$this->abswidth; else $abswidth=round($this->width*$xscale->scale_factor,0); for($i=0; $i<$numbars; $i++) { if( $exist_x ) $x=$this->coords[1][$i]; else $x=$i; $x=$xscale->Translate($x); if($this->align=="center") $x -= $abswidth/2; elseif($this->align=="right") $x -= $abswidth; $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 ) { $grad = new Gradient($img); $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(); } // Remember value of this bar $val=$this->coords[0][$i]; 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; } $img->PushColor($this->bar_shadow_color); $img->FilledPolygon($sp); $img->PopColor(); } // Stroke the outline of the bar if( is_array($this->color) ) $img->SetColor($this->color[$i % count($this->color)]); else $img->SetColor($this->color); $img->SetLineWeight($this->weight); $img->Polygon($pts); if( $this->show_value) { $sval=sprintf($this->show_value_format,$val); $txt = new Text($sval); $txt->SetFont($this->show_value_ff,$this->show_value_fs,$this->show_value_fsize); $txt->SetColor($this->show_value_color); $x=$pts[2]+($pts[4]-$pts[2])/2; if($this->bar_shadow) $x += $ssh; if( $val >= 0 ) { $txt->Pos($x,$pts[3]-$this->show_value_margin); $txt->Align("center","bottom"); } else { $txt->Pos($x,$pts[3]+$this->show_value_margin); $txt->Align("center","top"); } $txt->SetOrientation($this->show_value_angle); $txt->Stroke($img); } // Create the client side image map $this->csimareas.= "csimareas .= "$pts[2], $pts[3], $pts[6], $pts[7]\""; else $this->csimareas .= "$pts[6], $pts[3], $pts[2], $pts[7]\""; } else { if ($pts[2] < $pts[6]) $this->csimareas .= "$pts[2], $pts[7], $pts[6], $pts[3]\""; else $this->csimareas .= "$pts[6], $pts[7], $pts[2], $pts[3]\""; } if( !empty($this->csimtargets[$i]) ) $this->csimareas .= " href=\"".$this->csimtargets[$i]."\""; if( !empty($this->csimalts[$i]) ) { $sval=sprintf($this->csimalts[$i],$this->coords[0][$i]); $this->csimareas .= " alt=\"$sval\" title=\"$sval\" "; } $this->csimareas .= ">\r\n"; } return true; } } // Class //=================================================== // CLASS GroupBarPlot // Description: Produce grouped bar plots //=================================================== class GroupBarPlot extends BarPlot { var $plots; var $width=0.7; var $nbrplots=0; var $numpoints; //--------------- // CONSTRUCTOR function GroupBarPlot($plots) { $this->plots = $plots; $this->nbrplots = count($plots); $this->numpoints = $plots[0]->numpoints; } //--------------- // PUBLIC METHODS function Legend(&$graph) { $n = count($this->plots); for($i=0; $i<$n; ++$i) $this->plots[$i]->Legend($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); 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); for( $i=0; $i<$n; ++$i ) { $this->plots[$i]->ymin=$this->ybase; $this->plots[$i]->SetWidth($this->width/$this->nbrplots); $xscale->off = $tmp+$i*round($xscale->ticks->major_step*$xscale->scale_factor*$this->width/$this->nbrplots); $this->plots[$i]->Stroke($img,$xscale,$yscale); } $xscale->off=$tmp; } } // Class //=================================================== // CLASS AccBarPlot // Description: Produce accumulated bar plots //=================================================== class AccBarPlot extends BarPlot { var $plots=null,$nbrplots=0,$numpoints=0; //--------------- // CONSTRUCTOR function AccBarPlot($plots) { $this->plots = $plots; $this->nbrplots = count($plots); $this->numpoints = $plots[0]->numpoints; } //--------------- // PUBLIC METHODS function Legend(&$graph) { $n = count($this->plots); for( $i=0; $i<$n; ++$i ) $this->plots[$i]->Legend($graph); } function Max() { list($xmax) = $this->plots[0]->Max(); $nmax=0; for($i=0; $iplots); ++$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=$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); // 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; $iplots); ++$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=$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)); // Bar always start at baseline if( $ymin >= $this->ybase ) $ymin = $this->ybase; return array($xmin,$ymin); } // Method description function Stroke(&$img,&$xscale,&$yscale) { $img->SetLineWeight($this->weight); 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 { $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); $abswidth=round($this->width*$xscale->scale_factor,0); $pts=array($xt,$accyt,$xt,$yt,$xt+$abswidth,$yt,$xt+$abswidth,$accyt); if( $this->plots[$j]->grad ) { $grad = new Gradient($img); $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); } elseif ($this->plots[$j]->fill_color ) { $img->SetColor($this->plots[$j]->fill_color); $img->FilledPolygon($pts,4); $img->SetColor($this->plots[$j]->color); } if( $this->bar_shadow ) { $ssh = $this->bar_shadow_hsize; $ssv = $this->bar_shadow_vsize; // Create points to create a "upper-right" shadow $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; $img->SetColor($this->bar_shadow_color); $img->FilledPolygon($sp,4); } if( $i < count($this->plots[$j]->csimtargets) ) { $this->csimareas.= "csimareas.= "$pts[2], $pts[3], $pts[6], $pts[7]\""; } else { $this->csimareas.= "$pts[6], $pts[3], $pts[2], $pts[7]\""; } } else { if ($pts[2] < $pts[6]) { $this->csimareas.= "$pts[2], $pts[7], $pts[6], $pts[3]\""; } else { $this->csimareas.= "$pts[6], $pts[7], $pts[2], $pts[3]\""; } } $this->csimareas.= " href=\"".$this->plots[$j]->csimtargets[$i]."\""; if( !empty($this->plots[$j]->csimalts[$i]) ) { $sval=sprintf($this->plots[$j]->csimalts[$i],$this->plots[$j]->coords[0][$i]); $this->csimareas .= " alt=\"$sval\" title=\"$sval\" "; } $this->csimareas .= ">\r\n"; } $img->Polygon($pts,4); } $yt=$yscale->Translate($accy); if( $this->show_value) { $sval=sprintf($this->show_value_format,$accy); $txt = new Text($sval); $txt->SetFont($this->show_value_ff,$this->show_value_fs,$this->show_value_fsize); $txt->SetColor($this->show_value_color); $x=$pts[2]+($pts[4]-$pts[2])/2; if($this->bar_shadow) $x += $ssh; $txt->Pos($x,$yt-$this->show_value_margin); $txt->Align("center","bottom"); $txt->SetOrientation($this->show_value_angle); $txt->Stroke($img); } } return true; } } // Class /* EOF */ ?> jpgraph-1.5.2/README0100644000076400001440000001664007437547531012571 0ustar ljpusersVersion: $Id: README,v 1.4 2002/02/11 13:08:54 aditus Exp $ README FOR JPGRAPH ================== This is JpGraph 1.5.2 an Object Oriented PHP4 Graph Plotting library. The library is released under GPL 2.0. See COPYING for details about this license. The whole libray is Copyright (C) 2001,2002 Johan Persson and released under GPL 2.0 Included files -------------- README This file COPYING GPL 2.0 Licensee /image_gallery Point your browser to index.html in this directoryt to have a quick view on images from the examples in ./src/Examples /src Changelog Changelog for JpGraph Todo ToDo list for future releases jpgraph.php Base library jpgraph_dir.php Directory paths for base library jpgraph_log.php Extension: logarithmic scales jpgraph_line.php Extension: line plots jpgraph_bar.php Extension: bar plots jpgraph_error.php Extension: error plots jpgraph_scatter.php Extension: scatter/impuls plots jpgraph_spider.php Extension: spider (Web) plots jpgraph_pie.php Extension: pie plots jpgraph_canvas.php Extension: drawing canvas jpgraph_pie3d.php Extension: 3D pie plots jpgraph_gantt.php Extension: Gantt chart /src/utils/ gencolorchart.php Unsupported utility to generate a sample color chart of all named colors adjimg.php Unsupported utility to change contrast/brightness for an image. jplintphp.php Unsupported base library to parse PHP files jplintdriver.php Simply driver for running lint over a file and warns for unused instance variables and possible forgotten $this-> jpgendoc.php Extended driver which uses jplintphp base library to generate a HTML template for a class reference. /src/Examples A directory with over 80 example graphs. Run jpgraph_testsuit.php to get a list of all files and you can easily click on a file to see the code and the resulting image. Requirements: ------------- * PHP 4.02 or higher * GD 1.8.x, Experimental support for GD 2.x CAVEAT 1: JpGraph is developed under Unix and is known to work well. Please note that you may or may not encounter some known issues when trying to run on PHP/Apache/Windows or a combination of PHP/IIS. See below. CAVEAT 2: To get background images working with GD 2.0.1 you MUST enable Truecolor images by setting the constant USE_TRUECOLOR to true. If you don't fo this the background images will just be a black rectangle. The bad thing with this is that the antialias for Truetypes is broken using truecolor images in GD 2.0.1. This means you can't have background and TTF fonts in the same image. Installation ------------ 0. Make sure your PHP is AT LEAST 4.02 (preferrable 4.1.1) and that you have compiled support for GD library. You must make aboslutely sure that you have GD working. Please run phpinfo() to check if GD library is supported in your installation. Please not that JpGraph only fully supports GD 1.x. There are known issues with GD 2.0.1. 1. Unzip and copy the files to a directory of your choice. 2. Set up the directory paths in jpgraph_dir.php where the cache directory should be and where your TTF directory is. Note that Apache/PHP must have write permission in your cache directory. Caveat: On windows there seems to be some problem with including this file and you might have to move all the defines directly into jpgraph.php. If you get an error saying "Font not found" and you have specified the correct font path try the above mentioned workaround. (See also paragraph 5 below) 4. Check that all rest of the DEFINE in the top of JpGraph.php is setup to your preference. The default should be fine for most users. (See also Note 5. below) 3. Make sure PHP have write privileges to your cache directory. 4. Some windows installations seems to have a problem with a PHP script ending in a newline (This newline seems to be sent to the browser and will cause a Header already sent error). If you have this problem try remove all trailing newlines in the jpgraph* files 5. It has been reported that PHP 4.06 under IIS has problem correctly interpreting file paths. This can be solved by hardcoding the CACHE_DIRECTORY and FONT_DIRECTORY const ants directly in the code instead of using the defined constants. 6. Read the FAQ on http://www.aditus.nu/jpgraph/jpg_faq.php. Troubleshooting --------------- 1. Any PHP errors about function "imagecreate" does not exist indicates that your PHP installation does not include the GD library. This must be present. 2. Any error about "parent::" undefined means that you are not using PHP 4.02 or above. You _NEED_ PHP 4.02 or higher. This problem has also been reported to sometimes occur under Windows. This problem has also been reported by people running Zend-cache and is a bug in Zend. A workaround is to move all files into one single file. 3. If you don't get any background images (but rather a black background) you are most likely using GD 2.x which is not yet supported. JpGraph has only been verified with GD 1.x 4. If you are running PHP 4.06 and get an error saying "GD was not built with truetype support" you should know that this is a known problem with GD+PHP 4.06. There are some workarounds (search the net!) but it is really recommended that you instead upgrade to at least PHP 4.1.1 and configure PHP with --with-gd-native-ttf (Please also note that the built in TTF uses point size for fonts whereas Truetype 2 uses pixels.) Please DON't ask me how to resolve the GD Font problem. All mail regarding this will go straight to /dev/null. Upgrade to 4.1.1! 5. If you are running IIS and Win2k and get the error "Can't find font' when trying to use TTF fonts then try to change you paths to UNIX style, i.e. "/usr/local/fonts/ttf/". Remember that the path is absolute and not relative to the htdocs catalogue. 6. If you are using the cache please make sure that you have set the permissions correctly for the cache directory so that Apache/PHP can write to that directory. Documentation ------------- The latest documentation, both on-line, and off-line may be found at http://www.aditus.nu/jpgraph/ Bug reports and suggestions --------------------------- Should be sent to (jpgraph aditus nu) [insert at and dot] Change history: ------------------------------------------------------------------------ Date Ver Comment ------------------------------------------------------------------------ 2002-02-29 1.5.2 Minor bug fixes. 2002-02-11 1.5.1 Minor bug fixes. 2002-01-27 1.5 Functional improvements. Gantt charts. 2002-01-17 1.5-BETA2 Functional improvements, bug fixes 2001-12-16 1.5-BETA Functional improvements, gantt-charts, bug fixes. 2001-11-12 1.4 Functional improvements, bug fixes. 2001-09-23 1.3.1 Minor bug fixes 2001-09-13 1.3 Major functional enhancements and minor bugfixes 2001-04-29 1.2.2 Minor bug fixes. Addded background image support 2001-03-29 1.2.1 Minor bug fixes. Experimental support for 3D pie plots 2001-03-18 1.2 Second release see changes.txt 2001-02-18 1.1 Second release see changes.txt 2001-02-04 1.0 First public release ------------------------------------------------------------------------- Stockholm/London 2002-02-29 Johan Persson (jpgraph aditus nu) [insert at and dot] jpgraph-1.5.2/COPYING0100644000076400001440000004314207437547531012741 0ustar ljpusersGNU GENERAL PUBLIC LICENSE GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 19yy This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) 19yy name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License.