diff --git a/htdocs/comm/propal/stats/index.php b/htdocs/comm/propal/stats/index.php index df41da8328e..e2d21c2e2c4 100644 --- a/htdocs/comm/propal/stats/index.php +++ b/htdocs/comm/propal/stats/index.php @@ -1,6 +1,6 @@ - * Copyright (C) 2004 Laurent Destailleur +/* Copyright (C) 2003 Rodolphe Quiedeville + * Copyright (C) 2004-2006 Laurent Destailleur * * 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 @@ -18,7 +18,6 @@ * * $Id$ * $Source$ - * */ /** @@ -33,7 +32,7 @@ require_once(DOL_DOCUMENT_ROOT."/comm/propal/stats/propalestats.class.php"); require_once(DOL_DOCUMENT_ROOT."/dolgraph.class.php"); $WIDTH=500; -$HEIGHT=250; +$HEIGHT=200; llxHeader(); @@ -44,7 +43,7 @@ $stats = new PropaleStats($db); $year = strftime("%Y", time()); $data = $stats->getNbByMonthWithPrevYear($year); -if (! is_dir($conf->propal->dir_images)) { mkdir($conf->propal->dir_images); } +create_exdir($conf->propal->dir_images); if (!$user->rights->commercial->client->voir || $user->societe_id) { @@ -67,6 +66,9 @@ if (! $mesg) $px->SetMaxValue($px->GetCeilMaxValue()); $px->SetWidth($WIDTH); $px->SetHeight($HEIGHT); + $px->SetShading(5); + $px->SetHorizTickIncrement(1); + $px->SetPrecisionY(0); $px->draw($filename); } diff --git a/htdocs/comm/propal/stats/month.php b/htdocs/comm/propal/stats/month.php index 79e9ad84b9b..d6ea4618c07 100644 --- a/htdocs/comm/propal/stats/month.php +++ b/htdocs/comm/propal/stats/month.php @@ -1,6 +1,6 @@ - * Copyright (C) 2004 Laurent Destailleur +/* Copyright (C) 2003 Rodolphe Quiedeville + * Copyright (C) 2004-2006 Laurent Destailleur * * 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 @@ -18,7 +18,6 @@ * * $Id$ * $Source$ - * */ /** @@ -42,7 +41,7 @@ $mesg.= $langs->trans("Year")." $year"; $mesg.= ' '.img_next().''; $WIDTH=500; -$HEIGHT=250; +$HEIGHT=200; /* * @@ -76,6 +75,9 @@ if (! $mesg) $px->SetMaxValue($px->GetCeilMaxValue()); $px->SetWidth($WIDTH); $px->SetHeight($HEIGHT); + $px->SetShading(5); + $px->SetHorizTickIncrement(1); + $px->SetPrecisionY(0); $px->draw($filename); } @@ -109,6 +111,9 @@ if (! $mesg) $px->SetMaxValue($px->GetCeilMaxValue()); $px->SetWidth($WIDTH); $px->SetHeight($HEIGHT); + $px->SetShading(5); + $px->SetHorizTickIncrement(1); + $px->SetPrecisionY(0); $px->draw($filename_amount, $data, $year); } $res = $stats->getAverageByMonth($year); @@ -141,6 +146,9 @@ if (! $mesg) $px->SetMaxValue($px->GetCeilMaxValue()); $px->SetWidth($WIDTH); $px->SetHeight($HEIGHT); + $px->SetShading(5); + $px->SetHorizTickIncrement(1); + $px->SetPrecisionY(0); $px->draw($filename_avg); } diff --git a/htdocs/commande/stats/index.php b/htdocs/commande/stats/index.php index 1d32ddf5b26..5fea70181e1 100644 --- a/htdocs/commande/stats/index.php +++ b/htdocs/commande/stats/index.php @@ -1,6 +1,6 @@ - * Copyright (c) 2004-2005 Laurent Destailleur + * Copyright (c) 2004-2006 Laurent Destailleur * * 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 @@ -33,7 +33,7 @@ require_once(DOL_DOCUMENT_ROOT."/commande/stats/commandestats.class.php"); require_once(DOL_DOCUMENT_ROOT."/dolgraph.class.php"); $WIDTH=500; -$HEIGHT=250; +$HEIGHT=200; if (!$user->rights->commande->lire) accessforbidden(); @@ -85,7 +85,10 @@ if (! $mesg) $px->SetLegend(array($year - 1, $year)); $px->SetWidth($WIDTH); $px->SetHeight($HEIGHT); - $px->SetYLabel("Nombre de commande"); + $px->SetYLabel($langs->trans("NbOfOrder")); + $px->SetShading(5); + $px->SetHorizTickIncrement(1); + $px->SetPrecisionY(0); $px->draw($filename); } $rows = $stats->getNbByYear(); diff --git a/htdocs/commande/stats/month.php b/htdocs/commande/stats/month.php index 3c21b31bf4e..e6bcf73dd57 100644 --- a/htdocs/commande/stats/month.php +++ b/htdocs/commande/stats/month.php @@ -1,6 +1,6 @@ - * Copyright (c) 2004 Laurent Destailleur + * Copyright (c) 2004-2006 Laurent Destailleur * * 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 @@ -18,7 +18,6 @@ * * $Id$ * $Source$ - * */ /** @@ -49,7 +48,7 @@ $mesg.= $langs->trans("Year")." $year"; $mesg.= ' '.img_next().''; $WIDTH=500; -$HEIGHT=250; +$HEIGHT=200; /* * @@ -79,11 +78,13 @@ $mesg = $px->isGraphKo(); if (! $mesg) { $px->SetData($data); - $px->SetPrecisionY(0); $px->SetMaxValue($px->GetCeilMaxValue()); $px->SetWidth($WIDTH); $px->SetHeight($HEIGHT); - $px->SetYLabel("Nombre de commande"); + $px->SetYLabel($langs->trans("NbOfOrders")); + $px->SetShading(5); + $px->SetHorizTickIncrement(1); + $px->SetPrecisionY(0); $px->draw($filename); } @@ -112,11 +113,13 @@ $mesg = $px->isGraphKo(); if (! $mesg) { $px->SetData($data); - $px->SetPrecisionY(0); $px->SetMaxValue($px->GetCeilMaxValue()); $px->SetWidth($WIDTH); $px->SetHeight($HEIGHT); $px->SetYLabel($langs->trans("AmountTotal")); + $px->SetShading(5); + $px->SetHorizTickIncrement(1); + $px->SetPrecisionY(0); $px->draw($filename_amount); } $res = $stats->getAverageByMonth($year); @@ -144,11 +147,13 @@ $mesg = $px->isGraphKo(); if (! $mesg) { $px->SetData($data); - $px->SetPrecisionY(0); $px->SetMaxValue($px->GetCeilMaxValue()); $px->SetWidth($WIDTH); $px->SetHeight($HEIGHT); $px->SetYLabel($langs->trans("AmountAverage")); + $px->SetShading(5); + $px->SetHorizTickIncrement(1); + $px->SetPrecisionY(0); $px->draw($filename_avg); } diff --git a/htdocs/compta/bank/graph.php b/htdocs/compta/bank/graph.php index eead38c42a9..c560719f71b 100644 --- a/htdocs/compta/bank/graph.php +++ b/htdocs/compta/bank/graph.php @@ -51,8 +51,8 @@ if ($account > 0) $acct->fetch($account); // Definition de $width et $height - $width = 750; - $height = 280; + $width = 700; + $height = 200; // Calcul de $min et $max $sql = "SELECT min(".$db->pdate("datev")."),max(".$db->pdate("datev").")"; @@ -147,18 +147,20 @@ if ($account > 0) $graph_datas=array(); foreach($datas as $i => $val) { - $graph_datas[$i]=array("$labels[$i]",$datas[$i]); + $graph_datas[$i]=array($labels[$i],$datas[$i]); } $px = new DolGraph(); $px->SetData($graph_datas); $px->SetLegend(array($langs->trans("Balance"))); - $px->SetMaxValue($px->GetCeilMaxValue()); - $px->SetMinValue($px->GetFloorMinValue()); + $px->SetMaxValue($px->GetCeilMaxValue()<0?0:$px->GetCeilMaxValue()); + $px->SetMinValue($px->GetFloorMinValue()>0?0:$px->GetFloorMinValue()); $px->SetTitle($title); $px->SetWidth($width); $px->SetHeight($height); $px->SetType('lines'); $px->setBgColor('onglet'); + $px->SetHorizTickIncrement(1); + $px->SetPrecisionY(0); $px->draw($file); @@ -226,7 +228,7 @@ if ($account > 0) } if (strftime("%d",$day) == 15) { - $labels[$i] = strftime("%m",$day); + $labels[$i] = dolibarr_print_date($day,"%b"); } $day += 86400; $xyear = strftime("%Y",$day); @@ -244,12 +246,15 @@ if ($account > 0) $px = new DolGraph(); $px->SetData($graph_datas); $px->SetLegend(array($langs->trans("Balance"))); - $px->SetMaxValue($px->GetCeilMaxValue()); + $px->SetMaxValue($px->GetCeilMaxValue()<0?0:$px->GetCeilMaxValue()); + $px->SetMinValue($px->GetFloorMinValue()>0?0:$px->GetFloorMinValue()); $px->SetTitle($title); $px->SetWidth($width); $px->SetHeight($height); $px->SetType('lines'); $px->setBgColor('onglet'); + $px->SetHorizTickIncrement(30.41); // 30.41 jours/mois en moyenne + $px->SetPrecisionY(0); $px->draw($file); @@ -287,7 +292,7 @@ if ($account > 0) $subtotal = 0; $day = $min; $i = 0; - while ($day <= ($max+1000000)) // On va bien au dela du dernier jour + while ($day <= ($max+86400)) // On va au dela du dernier jour { $subtotal = $subtotal + (isset($amounts[strftime("%Y%m%d",$day)]) ? $amounts[strftime("%Y%m%d",$day)] : 0); //print strftime ("%e %d %m %y",$day)." ".$subtotal."\n
"; @@ -318,13 +323,14 @@ if ($account > 0) $px = new DolGraph(); $px->SetData($graph_datas); $px->SetLegend(array($langs->trans("Balance"))); - $px->SetMaxValue($px->GetCeilMaxValue()); - $px->SetMinValue($px->GetFloorMinValue()); + $px->SetMaxValue($px->GetCeilMaxValue()<0?0:$px->GetCeilMaxValue()); + $px->SetMinValue($px->GetFloorMinValue()>0?0:$px->GetFloorMinValue()); $px->SetTitle($title); $px->SetWidth($width); $px->SetHeight($height); $px->SetType('lines'); $px->setBgColor('onglet'); + $px->SetPrecisionY(0); $px->draw($file); @@ -380,7 +386,7 @@ if ($account > 0) { $data_credit[$i] = isset($credits[substr("0".($i+1),-2)]) ? $credits[substr("0".($i+1),-2)] : 0; $data_debit[$i] = isset($debits[substr("0".($i+1),-2)]) ? $debits[substr("0".($i+1),-2)] : 0; - $labels[$i] = $i+1; + $labels[$i] = strftime("%b",mktime(1,1,1,$i+1,1,2000)); } // Fabrication tableau 4 @@ -394,22 +400,30 @@ if ($account > 0) $px = new DolGraph(); $px->SetData($graph_datas); $px->SetLegend(array($langs->trans("Debit"),$langs->trans("Credit"))); - $px->SetMaxValue($px->GetCeilMaxValue()); - $px->SetMinValue($px->GetFloorMinValue()); + $px->SetMaxValue($px->GetCeilMaxValue()<0?0:$px->GetCeilMaxValue()); + $px->SetMinValue($px->GetFloorMinValue()>0?0:$px->GetFloorMinValue()); $px->SetTitle($title); $px->SetWidth($width); $px->SetHeight($height); $px->SetType('bars'); $px->SetShading(8); $px->setBgColor('onglet'); + $px->SetHorizTickIncrement(1); + $px->SetPrecisionY(0); $px->draw($file); + // Onglets $head=bank_prepare_head($acct); dolibarr_fiche_head($head,'graph',$langs->trans("FinancialAccount"),0); print ''; + print ''; + print ''; - print ''; - print '
'; + $file = "mouvement.$account.$year.png"; + print ''; + print '
'; $file = "solde.$account.$year.$month.png"; print ''; @@ -425,11 +439,6 @@ if ($account > 0) print ''; print '
'; - $file = "mouvement.$account.$year.png"; - print ''; - print '
'; diff --git a/htdocs/compta/facture/stats/index.php b/htdocs/compta/facture/stats/index.php index 42cec6ca7df..479be22e8ef 100644 --- a/htdocs/compta/facture/stats/index.php +++ b/htdocs/compta/facture/stats/index.php @@ -31,7 +31,7 @@ require("./pre.inc.php"); require_once(DOL_DOCUMENT_ROOT."/dolgraph.class.php"); $WIDTH=500; -$HEIGHT=250; +$HEIGHT=200; // Sécurité accés client if ($user->societe_id > 0) @@ -63,7 +63,9 @@ if (! $mesg) $px->SetLegend(array($year - 1, $year)); $px->SetWidth($WIDTH); $px->SetHeight($HEIGHT); - $px->SetShading(4); + $px->SetShading(5); + $px->SetHorizTickIncrement(1); + $px->SetPrecisionY(0); $px->draw($filename); } diff --git a/htdocs/compta/facture/stats/month.php b/htdocs/compta/facture/stats/month.php index 1a62821429c..0815d242ea7 100644 --- a/htdocs/compta/facture/stats/month.php +++ b/htdocs/compta/facture/stats/month.php @@ -1,6 +1,6 @@ - * Copyright (c) 2004-2005 Laurent Destailleur + * Copyright (c) 2004-2006 Laurent Destailleur * * 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 @@ -18,7 +18,6 @@ * * $Id$ * $Source$ - * */ /** @@ -31,18 +30,17 @@ require("./pre.inc.php"); require_once(DOL_DOCUMENT_ROOT."/dolgraph.class.php"); -$GRAPHHEIGHT=250; $GRAPHWIDTH=500; +$GRAPHHEIGHT=200; -/* - * Sécurité accés client - */ +// Sécurité accés client if ($user->societe_id > 0) { $action = ''; $socidp = $user->societe_id; } + llxHeader(); $year = isset($_GET["year"])?$_GET["year"]:date("Y",time()); @@ -70,6 +68,9 @@ if (! $mesg) $px->SetPrecisionY(0); $px->SetWidth($GRAPHWIDTH); $px->SetHeight($GRAPHHEIGHT); + $px->SetShading(5); + $px->SetHorizTickIncrement(1); + $px->SetPrecisionY(0); $px->draw($filename); } @@ -95,6 +96,9 @@ if (! $mesg) $px->SetPrecisionY(0); $px->SetWidth($GRAPHWIDTH); $px->SetHeight($GRAPHHEIGHT); + $px->SetShading(5); + $px->SetHorizTickIncrement(1); + $px->SetPrecisionY(0); $px->draw($filename_amount); } $res = $stats->getAverageByMonth($year); @@ -119,6 +123,9 @@ if (! $mesg) $px->SetMaxValue($px->GetCeilMaxValue()); $px->SetWidth($GRAPHWIDTH); $px->SetHeight($GRAPHHEIGHT); + $px->SetShading(5); + $px->SetHorizTickIncrement(1); + $px->SetPrecisionY(0); $px->draw($filename_avg); } diff --git a/htdocs/dolgraph.class.php b/htdocs/dolgraph.class.php index 6f994ed3c70..ca4ae0b8bc2 100644 --- a/htdocs/dolgraph.class.php +++ b/htdocs/dolgraph.class.php @@ -1,7 +1,7 @@ * Copyright (c) 2004-2006 Laurent Destailleur - * + * * 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 @@ -24,7 +24,7 @@ \file htdocs/dolgraph.class.php \brief Fichier de la classe mère de gestion des graph phplot \version $Revision$ - \remarks Usage: + \remarks Usage: $graph_data = array(array('labelA',yA),array('labelB',yB)); array(array('labelA',yA1,...,yAn),array('labelB',yB1,...yBn)); $px = new DolGraph(); @@ -54,17 +54,19 @@ class DolGraph var $MinValue=0; var $SetShading=0; var $PrecisionY=-1; - + var $SetHorizTickIncrement=-1; + var $SetNumXTicks=-1; + var $graph; // Objet PHPlot - + var $error; - - + + function DolGraph() { global $conf; global $theme_bordercolor, $theme_datacolor, $theme_bgcolor, $theme_bgcoloronglet; - + // Test si module GD présent $modules_list = get_loaded_extensions(); $isgdinstalled=0; @@ -77,19 +79,20 @@ class DolGraph return -1; } - // Vérifie que chemin vers PHPLOT_PATH est connu et defini $graphpath + // Vérifie que chemin vers PHPLOT_PATH est connu et definie $graphpath $graphpathdir=DOL_DOCUMENT_ROOT."/includes/phplot"; + if (defined('PHPLOT_PATH')) $graphpathdir=PHPLOT_PATH; if ($conf->global->PHPLOT_PATH) $graphpathdir=$conf->global->PHPLOT_PATH; if (! eregi('[\\\/]$',$graphpathdir)) $graphpathdir.='/'; include_once($graphpathdir.'phplot.php'); - - + + // Défini propriétés de l'objet graphe $this->bordercolor = array(235,235,224); $this->datacolor = array(array(120,130,150), array(160,160,180), array(190,190,220)); $this->bgcolor = array(235,235,224); - + $color_file = DOL_DOCUMENT_ROOT."/theme/".$conf->theme."/graph-color.php"; if (is_readable($color_file)) { @@ -101,14 +104,14 @@ class DolGraph //print 'bgcolor: '.join(',',$this->bgcolor).'
'; return 1; } - - + + function isGraphKo() { return $this->error; } - - + + /** * \brief Génère le fichier graphique sur le disque * \param file Nom du fichier image @@ -117,11 +120,11 @@ class DolGraph { // Prepare parametres $this->prepare($file); - + // Génère le fichier $file $this->graph->DrawGraph(); } - + /** * \brief Prépare l'objet PHPlot * \param file Nom du fichier image à générer @@ -130,8 +133,12 @@ class DolGraph { // Define the object $this->graph = new PHPlot($this->width, $this->height); + + $phplotversion=4; + if (defined('TOTY')) $phplotversion=5; + $this->graph->SetIsInline(1); - + $this->graph->SetPlotType($this->type); $this->graph->SetDataValues($this->data); @@ -139,20 +146,46 @@ class DolGraph if ($this->PrecisionY > -1) { $this->graph->SetPrecisionY($this->PrecisionY); - // Si precision de 0 - if ($this->PrecisionY == 0) + if ($this->PrecisionY == 0) // Si precision de 0 { - $maxval=$this->getCeilMaxValue(); - if (abs($maxval) < 2) + // Determine un nombre de ticks qui permet decoupage qui tombe juste + $maxval=$this->getMaxValue(); + $minval=$this->getMinValue(); + if ($maxval * $minval >= 0) // Si du meme signe { - $this->SetMaxValue(2); - $this->graph->SetNumVertTicks(2); + $plage=$maxval; } else { - $maxticks=min(10,$maxval); - $this->graph->SetNumVertTicks($maxticks); + $plage=$maxval-$minval; } + if (abs($plage) <= 2) + { + $this->SetMaxValue(2); + $maxticks=2; + } + else + { + $maxticks=10; + if (substr($plage,0,1) == 3 || substr($plage,0,1) == 6) + { + $maxticks=min(6,$plage); + } + elseif (substr($plage,0,1) == 4 || substr($plage,0,1) == 8) + { + $maxticks=min(8,$plage); + } + elseif (substr($plage,0,1) == 7) + { + $maxticks=min(7,$plage); + } + elseif (substr($plage,0,1) == 9) + { + $maxticks=min(9,$plage); + } + } + $this->graph->SetNumVertTicks($maxticks); +// print 'minval='.$minval.' - maxval='.$maxval.' - plage='.$plage.' - maxticks='.$maxticks.'
'; } } else @@ -160,21 +193,23 @@ class DolGraph $this->graph->SetPrecisionY(3-strlen(round($this->GetMaxValueInData()))); } $this->graph->SetPrecisionX(0); - + // Set areas + $top_space=40; + if ($phplotversion >= 5) $top_space=25; $left_space=80; // For y labels $right_space=10; // If no legend if (isset($this->Legend)) $right_space=70; // For legend - $this->graph->SetNewPlotAreaPixels($left_space, 40, $this->width-$right_space, $this->height-40); + $this->graph->SetNewPlotAreaPixels($left_space, $top_space, $this->width-$right_space, $this->height-40); if (isset($this->MaxValue)) { $this->graph->SetPlotAreaWorld(0,$this->MinValue,sizeof($this->data),$this->MaxValue); } // Define title - if (strlen($this->title)) $this->graph->SetTitle($this->title); - + if (isset($this->title)) $this->graph->SetTitle($this->title); + // Défini position du graphe (et legende) au sein de l'image if (isset($this->Legend)) { @@ -191,66 +226,123 @@ class DolGraph $this->graph->SetBackgroundColor($this->bgcolor); $this->graph->SetDataColors($this->datacolor, $this->bordercolor); - //$this->graph->SetDrawHorizTicks(true); // Pour avoir les ticks axe x (phplot 5) - $this->graph->SetHorizTickIncrement(1); + if ($this->SetNumXTicks > -1) + { + if ($phplotversion >= 5) // If PHPlot 5, for compatibility + { + $this->graph->SetXLabelType(''); + $this->graph->SetNumXTicks($this->SetNumXTicks); + } + else + { + $this->graph->SetNumHorizTicks($this->SetNumXTicks); + } + } + if ($this->SetHorizTickIncrement > -1) + { + // Les ticks sont en mode forcé + $this->graph->SetHorizTickIncrement($this->SetHorizTickIncrement); + if ($phplotversion >= 5) // If PHPlot 5, for compatibility + { + $this->graph->SetXLabelType(''); + $this->graph->SetXTickLabelPos('none'); + } + } + else + { + // Les ticks sont en mode automatique + if ($phplotversion >= 5) // If PHPlot 5, for compatibility + { + $this->graph->SetXDataLabelPos('none'); + } + } - - //$this->graph->SetXGridLabelType('data'); - //$this->graph->SetXGridLabelType(''); - //$this->graph->SetXGridLabelType('title'); + if ($phplotversion >= 5) + { + // Ne gere pas la transparence + // $this->graph->SetBgImage(DOL_DOCUMENT_ROOT.'/theme/dolibarr_logo_2.png','tile'); + $this->graph->SetDrawPlotAreaBackground(array(255,255,255)); + } $this->graph->SetPlotBorderType("left"); // Affiche axe y a gauche uniquement $this->graph->SetVertTickPosition('plotleft'); // Affiche tick axe y a gauche uniquement - + $this->graph->SetOutputFile($file); } - + function SetPrecisionY($which_prec) { $this->PrecisionY = $which_prec; return true; } - + + /* + \remarks Utiliser SetNumTicks ou SetHorizTickIncrement mais pas les 2 + */ + function SetHorizTickIncrement($xi) + { + $this->SetHorizTickIncrement = $xi; + return true; + } + + /* + \remarks Utiliser SetNumTicks ou SetHorizTickIncrement mais pas les 2 + */ + function SetNumXTicks($xt) + { + $this->SetNumXTicks = $xt; + return true; + } + + function SetYLabel($label) { $this->YLabel = $label; } - + function SetWidth($w) { $this->width = $w; } - + function SetTitle($title) { $this->title = $title; } - + function SetData($data) { $this->data = $data; } - + function SetType($type) { $this->type = $type; } - + function SetLegend($legend) { $this->Legend = $legend; } - + function SetMaxValue($max) { $this->MaxValue = $max; } + function GetMaxValue() + { + return $this->MaxValue; + } function SetMinValue($min) { $this->MinValue = $min; } - + function GetMinValue() + { + return $this->MinValue; + } + function SetHeight($h) { $this->height = $h; @@ -260,12 +352,12 @@ class DolGraph { $this->SetShading = $s; } - + function ResetBgColor() { unset($this->bgcolor); } - + /** * \brief Definie la couleur de fond du graphique * \param bg_color array(R,G,B) ou 'onglet' ou 'default' @@ -290,7 +382,7 @@ class DolGraph $this->bgcolor = $bg_color; } } - + function ResetDataColor() { unset($this->datacolor); @@ -300,10 +392,10 @@ class DolGraph { $k = 0; $vals = array(); - + $nblines = sizeof($this->data); $nbvalues = sizeof($this->data[0]) - 1; - + for ($j = 0 ; $j < $nblines ; $j++) { for ($i = 0 ; $i < $nbvalues ; $i++) @@ -315,15 +407,15 @@ class DolGraph rsort($vals); return $vals[0]; } - + function GetMinValueInData() { $k = 0; $vals = array(); - + $nblines = sizeof($this->data); $nbvalues = sizeof($this->data[0]) - 1; - + for ($j = 0 ; $j < $nblines ; $j++) { for ($i = 0 ; $i < $nbvalues ; $i++) @@ -335,10 +427,11 @@ class DolGraph sort($vals); return $vals[0]; } - + function GetCeilMaxValue() { $max = $this->GetMaxValueInData(); + if ($max != 0) $max++; $size=strlen(abs(ceil($max))); $factor=1; for ($i=0; $i < ($size-1); $i++) @@ -346,7 +439,7 @@ class DolGraph $factor*=10; } $res=ceil($max/$factor)*$factor; - + //print "max=".$max." res=".$res; return $res; } @@ -354,6 +447,7 @@ class DolGraph function GetFloorMinValue() { $min = $this->GetMinValueInData(); + if ($min != 0) $min--; $size=strlen(abs(floor($min))); $factor=1; for ($i=0; $i < ($size-1); $i++) @@ -361,7 +455,7 @@ class DolGraph $factor*=10; } $res=floor($min/$factor)*$factor; - + //print "min=".$min." res=".$res; return $res; } diff --git a/htdocs/includes/phplot5/.cvsignore b/htdocs/includes/phplot5/.cvsignore new file mode 100644 index 00000000000..6554a8fb276 --- /dev/null +++ b/htdocs/includes/phplot5/.cvsignore @@ -0,0 +1,2 @@ +doc +examples diff --git a/htdocs/includes/phplot5/ChangeLog b/htdocs/includes/phplot5/ChangeLog new file mode 100644 index 00000000000..b1c6d91afb4 --- /dev/null +++ b/htdocs/includes/phplot5/ChangeLog @@ -0,0 +1,1610 @@ +2004-10-24 18:40 migueldb + + * phplot.php: + + + array_merge_php4(): added to cope with the bug introduced by + the change in array_merge() from PHP4 to PHP5 (I haven't verified + this) + + + Fixed some divisions by zero, thanks to an old bug report. + +2004-10-24 17:44 migueldb + + * README.txt, doc/quickstart.html, examples/create_chart.php, + examples/format_chart.php, examples/inline_image.php: + + + Updated to the latest changes in phplot + +2004-10-24 17:40 migueldb + + * doc/index.php: + + + Minimal change + +2004-09-09 20:27 migueldb + + * phplot.php: + + + SetPointSize(): deprecated + + + SetPointSizes(): added as replacement for SetPointSize().Now + able to set point sizes on a per line basis. + + + SetPointShape(): deprecated. + + + SetPointShapes(): added as replacement for SetPointShape(). Now + able to set point shape on a per line basis. + + + DrawDot(): now needs record number to decide which dot shape + and size to draw. + + + CalcMargins(): dirty fix for x data label placing. + + + tile_img(): fixed tile placement. + +2004-06-14 14:19 migueldb + + * phplot.php: + + + SetXTickLabelPos() and others: more on the bug reported by Jo + Demol. + +2004-06-14 11:35 migueldb + + * phplot.php: + + + Fixed bug reported by Jo Demol. + +2004-05-11 14:14 migueldb + + * phplot.php: + + + SetBgImage(): added. + + + SetPlotAreaBgImage(): added. + + + SetInputFile(): deprecated. + + + DrawBackground(): now accepts images as backgrounds. + + + DrawPlotAreaBackground(): now accepts images as backgrounds. + + + tile_img(): internal method added. + +2004-04-14 13:26 migueldb + + * phplot.php: + + + DrawXAxis(): No more horizontal tick nor label at X-axis' + sides. + +2004-03-21 18:01 migueldb + + * phplot.php: + + + x/y_label_type automaticaally set to 'data' when setting label + precision. + + + minor corrections. + +2004-03-03 08:17 afan + + * phplot.php: PlotAreaWorld - last fix + +2004-03-03 02:40 migueldb + + * phplot.php: + + + SetPlotAreaWorld(): fixed. + +2004-03-01 21:14 afan + + * phplot.php: Needed one more = in ($ymin === NULL) + +2004-02-29 11:21 afan + + * phplot.php: phplot.php SetPlotAreaWorld - changed ($!ymin) to + ($ymin == NULL) for cases where $ymin = 0. (also done for ymax, + xmin, xmax) afan + +2004-02-23 10:34 migueldb + + * phplot.php: + + + SetPlotAreaWorld(): Fixed the calculation of max and min y. + +2004-02-14 12:29 migueldb + + * phplot.php: + + + SetPlotAreaWorld(): Fine grained control over which values are + auto-calculated. Should fix some trouble with y-scaling. + + + DrawGraph(): yet another fix to drawing order... + + + CheckOption(): fixes problems with mixedcase arguments. + + + SetFileFormat(), FormatLabel(): typos fixed. + +2004-01-30 12:56 migueldb + + * examples/data_sample1.php: + + + Added "stacked bars" plot type. + +2004-01-30 12:50 migueldb + + * phplot.php: + + + DrawStackedBars(): added plot type. + + + SetEqualXCoord(): renamed to more intuitive CalcBarWidths(). + Modified for stacked bars. + + + Changed graphing order. The grids are again at the background, + as they should. Added var $grid_at_foreground (bool) to alter + this. + + + text-data-pie renamed to text-data-single. + + + SetPlotAreaWorld(): fixed min_y bug. + +2004-01-29 17:10 migueldb + + * phplot.php: + + + SetPlotAreaWorld(): default behaviour is to adjust Y axis to Y + min/max. + + + SetSkipLeftTick(), SetSkipRightTick(): added. + + + SetFileFormat(): fixed silly bug that prevented selections from + being made. + +2004-01-28 20:00 migueldb + + * phplot.php, doc/quickstart.html: + + + Merged final changes to rel-5-0 into main trunk. + +2004-01-28 19:12 migueldb + + * phplot.php: + + + DrawGraph(): Fixed graph drawing order for default plots + (bars). Removed some redundat lines of code. + +2004-01-28 18:58 migueldb + + * doc/quickstart.html: + + + More stuff... + +2004-01-28 18:49 migueldb + + * phplot.php: + + + DrawPieChart(): fixed use of old variable. + + + First steps for data labels autoadjustement and skipping. + +2004-01-27 12:12 migueldb + + * phplot.php: + + + Added missing SetSkipTopTick() + + + Some comments. + + + Fixed option checking for a couple of functions. Added some + more. + +2004-01-27 00:03 migueldb + + * doc/index.php: [no log message] + +2004-01-25 20:28 migueldb + + * doc/index.php: + + + Fixed typo. + +2004-01-25 19:57 migueldb + + * doc/index.php: + + + Commit for 5.0rc1. + +2004-01-25 19:50 migueldb + + * README.txt, doc/index.php, doc/quickstart.html, doc/schema.html: + + + Commit for 5.0rc1. + +2004-01-25 19:44 migueldb + + * phplot.php: + + + Added missing SetDrawXDataLabelLines() and + SetDrawYDataLabelLines(). + + + Added some parameter checking with CheckOption(). + + + Added some comments. + +2004-01-25 19:32 migueldb + + * examples/: create_chart.php, example3.php, format_chart.php: + + + Commiting for 5.0rc1 + +2004-01-25 18:21 migueldb + + * examples/example8.php: [no log message] + +2004-01-25 18:20 migueldb + + * doc/style.css: + + + Added 'box' style. + +2004-01-25 17:11 migueldb + + * phplot.php: + + + Set*Colors(): should be faster when using default values. + + + array_pad_array() non class-member function added. + + + PadArrays(): now pads arrays with themselves, to mimic previous + behaviour, uses array_pad_array() + + + DrawAxisLegend(): skeleton added. To do. + +2004-01-24 23:18 migueldb + + * phplot_data.php: + + + DoMovingAverage(): some corrections. The legend isn't correctly + updated yet. + +2004-01-24 23:16 migueldb + + * phplot.php: + + + PadArrays(): added. Formerly in SetDataValues(), now called + from DrawGraph(). Fixes SetLineWidths() buggy behaviour. + + + Added MINY and MAXY constants, for DrawXDataLine(). + + + DrawGraph(): changed order when drawing axis, to avoid + overwriting. + +2004-01-21 20:08 migueldb + + * doc/quickstart.html: + + + More corrections + + + Some links + + + $Id$ tag + +2004-01-21 19:55 migueldb + + * doc/quickstart.html: + + + HTML heavily cleaned + + + Some corrections + +2004-01-21 18:47 migueldb + + * doc/index.php: + + + Added quickstart. + + + More things in whishlist. + +2004-01-21 18:46 migueldb + + * doc/quickstart.html: + + + Doc by Afan. With slight corrections. + +2004-01-21 18:44 migueldb + + * examples/rgb.inc.php, doc/index.html: [no log message] + +2004-01-21 18:43 migueldb + + * phplot.php: + + + Small changes to functions' documentation. + +2004-01-21 18:06 migueldb + + * phplot_data.php: + + + renamed tedious data_values to data + + + work still in progress + +2004-01-21 18:03 migueldb + + * phplot.php: + + + Added check for __FUNCTION__ for old PHP versions. + + + DrawPieChart(): 'data-data' support added. + + + DrawGraph(): added check to avoid calling FindDataLimits() + twice. + + + DrawXDataLine(): Added. + + + DrawXDataLabels(): Added support for vertical lines to data + points via DrawXDataLine() + + + FindDataLimits(): Added calculation of per-row min_y and max_y, + for DrawDataLine() + +2003-12-30 13:26 migueldb + + * phplot.php: + + + SetDataValues(). Now reads a reference and copies it to + $this->data, a numeric array. All indices are converted to + numeric. num_recs[] holds the number of records per data row. + + + FindDataLimits(). Works with new $this->data + + + The following functions now work with the new data set and use + faster loops: + + + DrawDots() + + + DrawDotsError() + + + DrawThinBarLines() + + + DrawPieChart(). Minimum changes. + + + DrawLines() + + + DrawArea(). Other optimizations too. + + + DrawBars(). Other things too. + +2003-12-30 00:01 migueldb + + * phplot_data.php: + + + Fixed constructor. Added parameters to fit PHPlot()'s + + + Fixed many "undefined index" errors. + + + DoMovingAverage(): puts data in a new row, and sets colors and + legend. Won't work for the moment. + +2003-12-29 21:58 migueldb + + * phplot_data.php: + + + Formatted after phplot.php style (PEAR) + + + Added Doxygen comments. + + + DoScaleData(): Optimized with for loops. Needs testing. + + + DoMovingAverage(): Optimized. Changed behaviour with first + elements in dataset. Needs testing. + + + DoExponentialMovingAverage(): added. Needs testing. + +2003-12-27 14:53 migueldb + + * benjamingothic.ttf: + + + The TTFont is only needed in 'examples/'. + +2003-12-27 14:52 migueldb + + * phplot.php: + + + Removed some (done) TODO marks. + +2003-12-27 14:06 migueldb + + * examples/test_setup.php: [no log message] + +2003-12-27 14:06 migueldb + + * examples/nav.html: + + + This was unnecessary. + +2003-12-27 14:01 migueldb + + * README.txt, LICENSE.GPL, LICENSE.PHP_3_0: [no log message] + +2003-12-27 13:46 migueldb + + * doc/index.php: + + + Added all the examples. + + + Added 5.0 version number. + + + Added myself as author. + +2003-12-27 13:44 migueldb + + * examples/example9.php: + + + Changed to follow phplot function renaming (again!) + +2003-12-24 13:39 migueldb + + * examples/: create_chart.php, format_chart.php: + + + New data type: randfunction, using data-data-error. + +2003-12-24 13:38 migueldb + + * examples/: data_sample1.php, data_sample2.php, data_sample3.php, + data_sample4.php: + + + Moved data type selection links to format_chart.php + +2003-12-24 13:36 migueldb + + * phplot.php: + + + Fixed spurious ticks bug. + + + Corrected some comments. + +2003-12-24 12:52 migueldb + + * examples/example5.php: + + + Now in format_chart.php + +2003-12-24 12:47 migueldb + + * examples/example4.php: Ooops! I deleted the wrong file! + +2003-12-24 12:39 migueldb + + * examples/data_sample5.php: + + + New 'randfunction' data type in example-o-matic. Taken from + deleted example4.php and test1.php. + +2003-12-24 12:37 migueldb + + * examples/example4.php: + + + Inserted example in example-o-matic as 'randfunction' + +2003-12-24 12:35 migueldb + + * examples/test1.php: inserted example in example-o-matic as + 'randfunction' + +2003-12-24 10:38 migueldb + + * phplot.php: + + + Fixed silly typo. + +2003-12-23 17:40 migueldb + + * phplot.php: + + + All renaming with leading underscores undone for compatibility. + It was a mess. + + + Fixed a couple function call typos. + + + Fixed axis position calculation. + +2003-12-17 16:28 migueldb + + * examples/create_chart.php: + + + Fixed to work with phplot.php v1.69 + +2003-12-17 16:28 migueldb + + * phplot.php: + + + Added skip_left_tick and skip_right tick for x axis. + + + Added y_label_angle (last commit) + + + Fixed automatic axis positioning for plots with negative values + or log scales. + + + Deleted messy SetGridParams(), SetTickParams() and + SetDataLabelParams(). I realized they were a bad idea of mine... + :( + + + Some more code grouping and reorganisation. + +2003-12-15 16:52 migueldb + + * examples/: create_chart.php, format_chart.php: + + + Added x/y tick crossing lenghts. + + + Added x axis and y axis positioning. + + + Corrected some label placement options. + +2003-12-15 16:50 migueldb + + * examples/: example4.php, example5.php, example9.php, test1.php: + + + Updated examples to work with new PHPlot. + + + Fixed some things. + +2003-12-15 16:48 migueldb + + * phplot.php: + + + x_tick_pos: added support for 'xaxis' position. + + + x_tick_label_pos: added support for 'xaxis' position. + + + DrawYTick(): fixed 'yaxis' + + + Set[X|Y]TickCrossing(): added. Draw ticks crossing axis by a + specified length in pixels. + + + DrawText(): improved vertical centering for TTF. + + + SetDrawBrokenLines(): fixed silly thing. + + + _DrawPlotBorder(): new option 'right' and 'sides' + + + DrawLinesError(): removed some 'ifs' for speed. + + + DrawDotsError(): removed some 'ifs' for speed. + + + Minor corrections here and there. + +2003-12-13 04:58 migueldb + + * phplot.php: + + + DrawGraph(): Fixed drawing order error. + +2003-12-13 04:44 migueldb + + * phplot.php: + + + _SetIndexColors(): removed. When sessions were not set, indexes + were being calculated twice + + + Centralized color and style defaults in _SetDefaultStyles() + (former _SetDefaultColors()) + + + SetLineWidth(): superseded by new SetLineWidths(). Now using an + array of values for per-line setting. + + + DrawDashedLine(): added again for backward compatibility. + + + DrawBars(): Faster shading. + + + DrawYTicks(): slightly improved, DrawYTick() modified too. + + + DrawGraph(): plot borders now drawn after plots. + + + Added color and style variable declarations for easier + modification. + + + More formatting. Some renaming undone for backwards + compatibility. + +2003-12-10 04:04 migueldb + + * examples/: data_sample1.php, data_sample2.php: + + + New plot type 'squared' added. + +2003-12-10 04:03 migueldb + + * examples/: create_chart.php, format_chart.php: + + + New option 'Draw broken lines' added. + +2003-12-10 04:00 migueldb + + * phplot.php: + + + Better available graph room usage. + + + More renaming and formatting... + + + Parameter validation with _CheckOption(), but I might drop it + if it slows everything down. + + + DrawBinary() is again DrawSquared()... ooops. :) It is at least + now working. + + + DrawSquared() done, quite silly thing, though. + + + SetBrokenLines() added. Tells whether to draw lines for missing + Y data. + +2003-12-10 01:32 migueldb + + * doc/schema.html: + + + Simple [go to index] link. + + + Typos fixed. + +2003-12-10 00:56 migueldb + + * phplot.php: + + + Reworking PEAR coding standards conformance, I had quite + screwed it up. Vim regexes are proving veeeery useful ;) + + + Important comment about the destructor and class instantiation. + + + Internal methods will now have a prepended underscore. I'm + renaming them little by little. + + + SetDefaultDashedStyle(): now accepts any string as style. + + + DrawSquared() renamed to DrawBinary() + + + _CalcMargins(): corrected [x|y]_tick_label_width calculation. + +2003-12-07 18:58 migueldb + + * examples/: example6.php, example7.php: + + + SetDrawXDataLabels(false); + +2003-12-07 18:30 migueldb + + * phplot.php: + + + DrawDotsError(): doesn't fail anymore if data type isn't + data-data-error (might include text-data-error in the future). + + + More variables changed to bool. + + + SetNewPlotAreaPixels(): removed, SetPlotAreaPixels() now does + the same work. + + + SetMarginsPixels(): now updates margin variables. + + + SetTitle(): fixed wrong height calc for empty title. + + + Removed many internal variable declarations. See the beggining + of the class declaration for comments on this. This might be a + bit stupid... :-? + + + DrawSquared(): plot type on the works, addressing Feature + Request [558302]. Just the skeleton for now. + +2003-12-07 02:12 migueldb + + * phplot.php: + + + SetInputFile(): deallocates previously allocated 'img' + + + Added 'line_spacing' and SetLineSpacing() + + + InitImage(): deleted, moved into the constructor + + + DrawError(): shows plain text message if 'img' unavailable. + + + SetXTitle(): Fixed x_title_height calculation for TTF. + + + More code reorganisation. As I seem to be alone in this, that + should be no problem... + +2003-12-07 01:12 migueldb + + * phplot.php: + + + TTF font provided with package now works (it wasn't being + found). + + + TTF placement a bit adjusted. + + + SetTitle(): Fixed wrong title height calculation for TTFonts. + + + DrawLegend(): TTF support added. + + + DrawDot(): renamed dot type 'crosshair' to 'plus'. Added + 'cross' and 'trianglemid'. + + + FormatTickLabel(): now used for tick and data labels. Renamed + to FormatLabel(). + + + draw_x_data_label: variable removed, now using + [x/y]_data_label_pos for both x and y data labels. + + + draw_x_data_label_lines: parameter added. + + + line_width: minor usage fixes. + + + SetXDataLabelAngle() renamed to SetXLabelAngle(). Old function + kept in 'deprecated' section. + + + Changed some options to bool format. + + + Tried to make better decisions on Set*LabelParams() regarding + placement. + + + Removed superfluous DrawLabels() function. + + + Moved CalcXHeights() and CalcYWidths() into CalcMargins() for + speed (unperceptible I must admit) and clarity. + + + Other changes here and there... + +2003-12-07 01:06 migueldb + + * examples/data_sample2.php: + + + Added missing data. + +2003-12-07 01:05 migueldb + + * examples/: create_chart.php, data_sample1.php: [no log message] + +2003-12-07 01:04 migueldb + + * examples/format_chart.php: + + + Added a check to see if we are being called from the right + place. + + + New data label angle option. + + + New line and error bar line width options. + + + New data label options. + + + New point types. + + + Some corrections. + +2003-12-06 21:12 migueldb + + * examples/nav.html: [no log message] + +2003-12-06 21:09 migueldb + + * examples/test_setup.php: + + + Added nav. bar + +2003-12-06 21:08 migueldb + + * examples/nav.html: + + + Simple navigation bar, not very useful yet. + +2003-12-06 20:43 migueldb + + * doc/style.css: + + + New "nav" class. + +2003-12-06 20:42 migueldb + + * doc/index.php: + + + New index, now calls some php. + +2003-12-06 20:41 migueldb + + * doc/php_test.php: + + + Added the test for php functionality in index.php, so this file + is no longer necessary. + +2003-12-05 19:13 migueldb + + * examples/inline_image.php: + + + Added warning message when called on its own. + +2003-11-28 01:21 migueldb + + * phplot.php: + + + Default title position='none' for better positioning of + elements. + + + xtr(), yrt(): return value round()ed + + + DrawLines(): better (?) management of incomplete data sets. No + begin or end points forced. No more "undefined offset x in ..." + + + DrawArea(): more modifications when working with incomplete + data sets. No extra beginning or ending points. + +2003-11-26 17:52 migueldb + + * phplot.php: [no log message] + +2003-11-26 17:16 migueldb + + * examples/: create_chart.php, format_chart.php: + + + Added shading option + +2003-11-26 16:43 migueldb + + * phplot.php: + + + Added spaces after every comma, around every equal sign for + prettier code. :) + + + DrawXTitle(): Another fix. Removed the check for tick_pos I + just introduced. Works better now. + + + _PHPlot(): destructor added. + + + Comments, indenting, and a couple of minor corrections here and + there. + +2003-11-26 12:19 migueldb + + * phplot.php: l + + + DrawXTitle(): check for tick_label_pos when calculating title + position (before the title would be misplaced under certain + circumstances) + + + Added SetIndexDarkColor() and $ndx_data_dark_color[] calculated + from $data_colors[], for shadows. + + + New data type (one value per data row) 'text-data-once' for pie + charts + + + DrawPieChart(): some optimisations. Shading added. + +2003-11-25 17:30 migueldb + + * examples/create_chart.php: + + + Now accepts point size from format_chart.php. + +2003-11-25 17:29 migueldb + + * examples/format_chart.php: + + + New point type 'crosshair' added to the options. + + + Link to the documentation index at the bottom of the page. + +2003-11-25 17:28 migueldb + + * examples/data_sample1.php: + + + Fixed wrong comment. + +2003-11-25 17:28 migueldb + + * phplot.php: + + + DrawDot(): added new variables to avoid calls to ytr() and + xtr(), replaced imagefilledrectangle() with imageline() in + "halfline" and "line" modes. + + + DrawDot(): added point type 'crosshair' + + + DrawArea(): modified to follow the structure of the other plot + drawing methods. Removed obsolete DrawAreaSeries() + + + DrawLines(): same modifications as with other plot drawing + methods. + + + Removed dummy DrawLineSeries() + + + More use of imagesetthickness() + +2003-11-25 01:34 migueldb + + * phplot.php: Right now working on richer data label placement, but + in the meantime: + + + Removed unnecessary (and wrong) right alignment option in + FormatTickLabel() + + + Removed unused (thought it better :) DrawPlotLabel + + + DrawYErrorBar(): uses imagesetthickness() + + + DrawDots() optimised and cleaned. + + + DrawThinBarLines() optimised and cleaned. + + + DrawDotsError() optimised (I hope!) + + + DrawLinesError() optimised. Fixed a bug with multiple lines + + + Other small things, as usual... + +2003-11-25 01:27 migueldb + + * examples/data_sample2.php: + + + Removed bogus tag. + +2003-11-25 00:49 migueldb + + * examples/data_sample4.php: + + + Added 'thinbarline' data plot option. + +2003-11-25 00:48 migueldb + + * examples/data_sample1.php: + + + Added thinbarline plot mode. + + + Added comment on 'text-data' data type. + +2003-11-24 23:32 migueldb + + * examples/: data_sample1.php, data_sample2.php, data_sample4.php, + format_chart.php: + + + Replaced old data type "linear" with new "data" everywhere. + +2003-11-24 23:32 migueldb + + * examples/create_chart.php: + + + Accepts new $data_row format from data_sample3.php + (data-data-error format) + + + Replaced old data type "linear" with new "data". + +2003-11-24 23:30 migueldb + + * examples/data_sample3.php: + + + Replaced old "linear" with new "data" everywhere. + + + Modified code and $data_row organization to allow for easier + changes. + + + Added another set of values (to have two lines in the example) + +2003-11-24 21:06 migueldb + + * examples/data_sample3.php: + + + Removed bogus tag + + + Added slashes to input tags end + +2003-11-24 17:44 migueldb + + * phplot.php: + + + Fixed a typo. + +2003-11-24 17:03 migueldb + + * doc/: examples.html, function_reference.html, quick_start.php: + + + Inserted into index.html (some time ago) + +2003-11-24 17:00 migueldb + + * doc/style.css: + + + Added new classes for the docs. + +2003-11-24 16:37 migueldb + + * phplot.php: + + + Added SetDefaultDashedStyle() + + + Replaced outdated call to imagesetstyle() with SetDashedStyle() + + + Moved the check for dashed_grid from constructor (where it + could lead to strange behaviour) into DrawXTicks() and + DrawYticks() (BTW, shouldn't these be renamed?) + +2003-11-24 16:12 migueldb + + * examples/: data_sample1.php, data_sample2.php, data_sample3.php, + data_sample4.php: + + + HTML tags to lowercase. + + + Added missing closing tags. + + + Indented code. + +2003-11-24 16:05 migueldb + + * examples/create_chart.php: + + + Modified to work with the new format_chart.php + +2003-11-24 16:04 migueldb + + * examples/format_chart.php: + + + New layout + + + Many new options + + + Some introductory words + + + Removed "you have to reload" warning (the default behaviour for + PHPlot now is to send no-cache header) + + + Small corrections + +2003-11-24 14:46 migueldb + + * phplot.php: + + + Added checks for tick placement in CalcMargins() + + + Uninportant renaming of some internal variables. + +2003-11-24 14:25 migueldb + + * phplot.php: + + + Some more renaming for consistency: vtick, vert_tick, etc are + now y_tick_ + + + Same for htick -> x_tick_ + + + + Draw*Ticks() renamed following the same scheme + + + Grouped tick label parameter setting functions in + SetTickLabelParams(). Left original ones in 'deprecated' + + + Grouped grid parameter setting functions in SetGridParams(). + Left original ones in 'deprecated' + + + Grouped Title setting and positioning in Set*Title(). Left + original ones in 'deprecated' + + + Slight modifications to data label placement + +2003-11-24 11:30 migueldb + + * doc/index.html: + + + More reorganisation + +2003-11-23 23:53 migueldb + + * phplot.php: + + + Corrected a typo. + +2003-11-23 23:39 migueldb + + * phplot.php: + + + Restructured internal font management: font variables are now + hashes with all associated info. DrawText() now only needs that + and chooses whether to draw TrueType or not. Almost every "if + ($this->use_ttf)" check removed as a result. + + + Added SetDefaultTTFont() + + + When drawing pie charts (no axis titles nor labels), maximize + plot area. + +2003-11-23 21:48 migueldb + + * doc/index.html: + + + Included function_reference.html links here. + +2003-11-23 21:42 migueldb + + * doc/: index.html, schema.html: [no log message] + +2003-11-23 21:39 migueldb + + * doc/index.html: + + + New welcome page, some text. + + + Some features listed. + + + Uses stylesheet + +2003-11-23 21:37 migueldb + + * doc/: style.css, php_test.php: + + + First commit + +2003-11-23 21:36 migueldb + + * examples/test_setup.php: + + + Added stylesheet + + + Silly change + +2003-11-23 21:35 migueldb + + * examples/inline_image.php: + + + Silly change + +2003-11-23 21:34 migueldb + + * examples/create_chart.php: + + + Renamed SetYLabel() and SetXLabel() to SetYTitle() and + SetXTitle() + +2003-11-23 21:33 migueldb + + * examples/format_chart.php: + + + Added file format option + + + Added stylesheet + +2003-11-23 20:00 migueldb + + * phplot.php: + + + DrawText(): horizontal (left, center and right) and vertical + (top, center, bottom) alignment finished. + + + Replaced all outdated ocurrences of ImageString() with calls to + DrawText(). + + + Removed redundant text placement calculations. + + + DrawLegend() now draws the legend box more accurately (final + solution to bug #527867) + +2003-11-23 02:02 migueldb + + * phplot.php: + + + tick_length and tick_length2 now are htick_length and + vtick_length. + + + Included SetHTickLength() and SetVTickLength() + + + Fixed silly bug with SetDefaultFonts() + + + SetUseTTF() now resets the fonts. + + + More room for title + +2003-11-22 23:40 migueldb + + * phplot.php: + + + Somewhat clearer naming convention for labels, ticks, titles + and fonts. + + + X tick labels and X Title can be: plotdow, plotup, both, none + + + Y tick labels and Y Title can be: plotleft, plotright, both, + none + + + Renamed some Set*() internal functions to Calc*() (Set + + + is to be left for "public" methods) + + + More doxygen comments + + + Optimised FindDataLimits() + + + A few bugfixes + +2003-11-22 18:04 migueldb + + * examples/test_setup.php: + + + Added wbmp format + + + Now using imagetypes() instead of function_exists() + +2003-11-22 13:57 migueldb + + * examples/test_setup.php: + + + Graphic formats availability checks now use function_exists() + + + HTML code restructured. + +2003-11-22 13:55 migueldb + + * examples/create_chart.php: + + + Using $_GET and $_POST + + + SetImageFormat() option added + +2003-11-22 13:54 migueldb + + * examples/format_chart.php: + + + HTML code rewritten, better layout + + + Image format option + +2003-11-22 03:02 migueldb + + * phplot.php: + + + Improved datalabel_font + + + + Added SetDatalabelFontSize() + + + Added many more doxygen comments. + + + Other micro-changes. + +2003-11-22 02:06 migueldb + + * examples/inline_image.php: + + + register_globals default (PHP4) setting taken into account + +2003-11-22 01:46 migueldb + + * phplot.php: + + + Bug #790745 fixed. Thx. to the poster. + + + DrawError() now accepts position and centers text + + + '[423202] Catch error on empty arrays' solved. No more 'divide + by zero's + + + Some (random) doxygen comments inserted. It might be a good + idea for auto-docs. + +2003-11-21 22:27 migueldb + + * phplot.php: My first commit, here are the changes (that I + remember) + + + Y axis tick and label options now work + + + X axis tick and label options: plotdown,plotup,both,none + + + Implemented tick_length2 for rightmost/upper side + + + More default data colors assigned to data_color and error_color + arrays + + + Deprecated draw_vert_ticks and SetDrawVertTicks() in favor of + 'none' value in vert_tick_position + + + Better? upper,lower, rightmost margin calculation + + + Dashed grid lines + + + Added FormatTickLabel(). Removed redundant code in + DrawHorizontalTicks() + + + Removed all calls left to DrawDataLabel(), moved to + "deprecated"... + + + Moved some code and functions around. + + + Attempted correction for Bug [440065] "Pie labels not centered + correctly" + + + Corrected '$which_pt not an acceptable plot type' typo [682068] + + + Now using SetFileFormat() for PHP4 + + + Bug [484235] might be solved by now (not sure!) + +2003-11-21 20:42 migueldb + + * examples/create_chart.php: Now works with register_globals off + +2002-06-21 01:35 afan + + * examples/test_setup.php: Testing update: (Moved GIF to last + check) + +2002-04-30 15:25 afan + + * phplot.php: Fixed error in pie graphs with data=0. Changed + functions and tabs to PEAR standards + + Afan + +2002-02-22 03:15 afan + + * phplot.php: No changes - just settting up new server + +2001-04-19 03:03 afan + + * phplot.php, examples/inline_image.php: fix error on function + +2001-04-19 00:18 mdj_guardian + + * phplot.php: Fixed problem with example 8. Also modified the + default y_padding value so the examples with zero on the bottom + turn out that way. + +2001-04-18 07:18 mdj_guardian + + * phplot.php: Made the following changes: + + + Fixed the case of built in functions to match PHP documentation + + + Modified SetFileFormat to work in PHP3 & 4 with no changes + + + Improved auto-scaling signifcantly (SetVertPadding, y_padding, + SetPlotAreaWorld) (needs docs and examples) + + + Fixed a problem in DrawDashedLine when the line segments were + zero length + + + Modified DrawLegend to fix positioning of lower right corner of + box. Was cutting through text + + + Removed a duplicated line in FindDataLimits + +2001-04-08 15:58 afan + + * phplot.php: Minor change to formatting + +2001-03-27 07:42 afan + + * phplot.php, phplot_data.php, examples/data.php, + examples/data_sample1.php, examples/data_sample3.php, + examples/example1.php, examples/example2.php, + examples/example3.php, examples/example4.php, + examples/example6.php, examples/example7.php, + examples/example8.php, examples/example9.php, + examples/format_chart.php, examples/inline_image.php, + examples/test_setup.php: Committing 4.4.6 + +2001-03-19 16:08 afan + + * phplot.php, doc/user_functions.html: Cleaned up Shading Function + for Bars Bug Fix in Placement of Datalabels. + +2001-03-17 16:40 afan + + * examples/: data.php, data_date.php, data_date2.php, + data_sample1.php, data_sample2.php, data_sample3.php, + example1.php, example2.php, example3.php, example6.php, + example7.php, example8.php, example9.php, format_chart.php, + inline_image.php, test_setup.php: changed examples from ? to ?php + format. + +2001-03-16 13:59 afan + + * phplot.php: Error in line 361 corrected. + +2001-03-16 03:10 afan + + * phplot.php: Major updates to DrawDots and DrawBars to make it + easy to put labels and dots overwriting bars. Code optimizations + and checks to make sure you don't need to set error_reporting(0). + +2001-03-09 19:58 afan + + * phplot.php: Minor bug fixes + +2001-03-01 17:47 afan + + * README.txt, phplot.php, rgb_small.inc.php, examples/example8.php: + Bug on line 164 corrected Removed rgb_small.inc.php + +2001-02-27 17:49 afan + + * phplot.php: Added ability to use background Images with plots + Changed Image Color Allocation to work even with background + Images Note: this change requires usage of PHPLOT 3.0.2 or later. + +2001-02-23 21:22 afan + + * phplot.php, phplot_data.php, examples/example3.php, + examples/example6.php, examples/example9.php: DrawText, + SetRGBColor, Sessions fixes + +2001-02-16 16:40 afan + + * phplot.php, examples/example1.php: Added output_file and + input_file Added Constructor Added check to see if an image index + has already been added for smaller files + +2001-02-14 21:06 afan + + * phplot.php, examples/example1.php: Added Function SetColorIndex + for operating on image color indexes directly Also checks to see + if the color has already been defined for image size + optimization. + +2001-02-13 20:50 afan + + * phplot.php, examples/example1.php: Minor Bugfix + +2001-02-13 18:16 afan + + * phplot.php, examples/data.php, examples/example2.php, + examples/example3.php, examples/example4.php: Title + modifications, added movable Y axis + +2001-02-12 14:54 afan + + * examples/example8.php: Adding example8: two plots on one image + +2001-02-09 18:56 afan + + * phplot.php: Added SetYAxisPosition and changed DrawYAxisCode + +2001-02-09 10:14 afan + + * phplot.php: Added Title return lines + +2001-02-08 05:35 afan + + * README.txt, phplot.php, doc/user_functions.html, + doc/user_internal_functions.html, examples/data.php, + examples/example1.php, examples/example4.php: Added Error Bar + Widths, Missing Data Handling, Minor bugfix, More docs + +2001-01-29 05:51 afan + + * phplot.php, examples/create_chart.php, examples/example7.php: + Added NumHorizTicks, fixed bug in example 7 + +2001-01-23 05:09 afan + + * doc/user_functions.html: Doc Fix + +2001-01-23 05:04 afan + + * phplot.php: Minor Changes + +2001-01-23 05:03 afan + + * phplot.php, doc/internal_functions.html, doc/user_functions.html: + Updated Documentation + +2001-01-23 04:36 afan + + * phplot.php, examples/example3.php: Minor bug fixes. + +2001-01-23 01:33 afan + + * phplot.php: Minor fix to phplot after major update + +2001-01-23 01:06 afan + + * README.txt, phplot.php, phplot_data.php, + examples/create_chart.php, examples/data.php, + examples/data_date.php, examples/data_date2.php, + examples/example2.php, examples/example4.php, + examples/example6.php, examples/example7.php, examples/test1.php: + Lots changed: easier to make multiple images, logs, etc. + +2001-01-17 04:05 afan + + * phplot.php: [no log message] + +2001-01-17 03:42 afan + + * phplot.php: Implemented Log Plots. Very little error checking + +2001-01-17 03:41 afan + + * phplot.php: Log plots implemented. Very little data error + checking. + +2001-01-14 03:02 extensive + + * phplot.php, phplot_data.php, doc/internal_functions.html, + doc/user_functions.html: Changed ReportError to DrawError + respectively PrintError, added new functionality to PHPlot_data + and added some documentation of PHPlot_data + +2001-01-11 18:43 afan + + * phplot.php, doc/internal_functions.html: Added documentation. + +2001-01-11 17:07 afan + + * create_chart.php, data_sample1.php, data_sample2.php, + data_sample3.php, data_sample4.php, doc.htm, format_chart.php, + phplot.php, doc/examples.html, doc/function_reference.html, + doc/index.html, doc/internal_functions.html, doc/quick_start.php, + doc/user_functions.html, doc/user_internal_functions.html, + examples/benjamingothic.ttf, examples/create_chart.php, + examples/data_sample1.php, examples/data_sample2.php, + examples/data_sample3.php, examples/data_sample4.php, + examples/format_chart.php, examples/inline_image.php, + examples/test_setup.php: Major change to structure of PHPLOT. Doc + directory, moved examples to examples directory. + +2001-01-11 16:25 extensive + + * phplot.php: just added ReportError() and changed all DrawError() + calls to use ReportError(). phplot seems to be broken on my + system but I don't think it is my fault (this was the first time + I was testing a 3.7.x version), let's address that later. Is it + broken on your system, too, Afan? + +2001-01-11 02:14 extensive + + * phplot.php, phplot_data.php: I just corrected some typos (mostly + my name being misspelled ;-) + +2001-01-08 00:53 afan + + * doc.htm, phplot.php, phplot_data.php: Added Plot Border types + +2001-01-07 00:35 afan + + * doc.htm, phplot_data.php: Adding phplot_data for release 3.7.0 + +2001-01-07 00:30 afan + + * examples/: data.php, example1.php, example2.php, example3.php, + example4.php, example5.php, rgb.inc.php, test1.php: Adding + PHPLOT_DATA routines. Defining the first sub-class. Added + examples: Afan + +2001-01-07 00:23 afan + + * README.txt, create_chart.php, data_sample3.php, doc.htm, + phplot.php, stocks.php, stocks1.php, test1.php: 3.6.4 Committed + +2000-12-13 22:02 afan + + * phplot.php: Allowing data in time_format but printed using + strftime + +2000-12-13 04:47 afan + + * doc.htm, phplot.php, stocks.php: ver 3.2.1 and New Docs + +2000-12-11 18:03 afan + + * create_chart.php, data_sample2.php, format_chart.php, phplot.php: + Release version 3.2.0 + +2000-11-29 17:12 afan + + * README.txt, benjamingothic.ttf, create_chart.php, + data_sample1.php, data_sample2.php, data_sample3.php, + data_sample4.php, doc.htm, format_chart.php, phplot.php, + rgb.inc.php, rgb_small.inc.php, stocks.php, stocks1.php, + test1.php: Initial revision + +2000-11-29 17:12 afan + + * README.txt, benjamingothic.ttf, create_chart.php, + data_sample1.php, data_sample2.php, data_sample3.php, + data_sample4.php, doc.htm, format_chart.php, phplot.php, + rgb.inc.php, rgb_small.inc.php, stocks.php, stocks1.php, + test1.php: The first upload! Afan Ottenheimer + diff --git a/htdocs/includes/phplot5/LICENSE.GPL b/htdocs/includes/phplot5/LICENSE.GPL new file mode 100644 index 00000000000..5b6e7c66c27 --- /dev/null +++ b/htdocs/includes/phplot5/LICENSE.GPL @@ -0,0 +1,340 @@ + 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) + + 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) year 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. diff --git a/htdocs/includes/phplot5/LICENSE.PHP_3_0 b/htdocs/includes/phplot5/LICENSE.PHP_3_0 new file mode 100644 index 00000000000..ffc1ab71f36 --- /dev/null +++ b/htdocs/includes/phplot5/LICENSE.PHP_3_0 @@ -0,0 +1,68 @@ +-------------------------------------------------------------------- + The PHP License, version 3.0 +Copyright (c) 1999 - 2003 The PHP Group. All rights reserved. +-------------------------------------------------------------------- + +Redistribution and use in source and binary forms, with or without +modification, is permitted provided that the following conditions +are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + 3. The name "PHP" must not be used to endorse or promote products + derived from this software without prior written permission. For + written permission, please contact group@php.net. + + 4. Products derived from this software may not be called "PHP", nor + may "PHP" appear in their name, without prior written permission + from group@php.net. You may indicate that your software works in + conjunction with PHP by saying "Foo for PHP" instead of calling + it "PHP Foo" or "phpfoo" + + 5. The PHP Group may publish revised and/or new versions of the + license from time to time. Each version will be given a + distinguishing version number. + Once covered code has been published under a particular version + of the license, you may always continue to use it under the terms + of that version. You may also choose to use such covered code + under the terms of any subsequent version of the license + published by the PHP Group. No one other than the PHP Group has + the right to modify the terms applicable to covered code created + under this License. + + 6. Redistributions of any form whatsoever must retain the following + acknowledgment: + "This product includes PHP, freely available from + ". + +THIS SOFTWARE IS PROVIDED BY THE PHP DEVELOPMENT TEAM ``AS IS'' AND +ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PHP +DEVELOPMENT TEAM OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED +OF THE POSSIBILITY OF SUCH DAMAGE. + +-------------------------------------------------------------------- + +This software consists of voluntary contributions made by many +individuals on behalf of the PHP Group. + +The PHP Group can be contacted via Email at group@php.net. + +For more information on the PHP Group and the PHP project, +please see . + +This product includes the Zend Engine, freely available at +. diff --git a/htdocs/includes/phplot5/README.txt b/htdocs/includes/phplot5/README.txt new file mode 100644 index 00000000000..26e2191d22f --- /dev/null +++ b/htdocs/includes/phplot5/README.txt @@ -0,0 +1,45 @@ +This is a class for creating scientific and business charts. +To start extract the files with + + tar zxvf phplot-5.0rc2.tar.gz + +and then point your browser to + + doc/index.php. + +There are some configuration settings that you will need to make +based on your setup. + +1. File Type: Depending on the version of GD you are using, + you may or may not be able to use GIF or PNG. That is + set with the function. + + SetFileFormat("") where is png, gif, jpeg, ... + + or edit the file phplot.php and change the line + + var $file_format = ""; + +2. TTF: If you have TTF installed then use (and read the docs) + + SetUseTTF(TRUE); + + otherwise use + + SetUseTTF(FALSE); + +Everything else should be independent of what version you are using. +This has been tested with PHP3, PHP4, GD1.2 and GD 3.8. + +To start please see doc/index.php. There you'll find examples, tests and +some introductory documents. + +-------------------------- + +This is distributed with NO WARRANTY and under the terms of the GNU GPL +and PHP licenses. If you use it - a cookie or some credit would be nice. + +You can get a copy of the GNU GPL at http://www.gnu.org/copyleft/gpl.html +You can get a copy of the PHP License at http://www.php.net/license.html + +See http://www.sourceforge.net/projects/phplot/ for the latest changes. diff --git a/htdocs/includes/phplot5/phplot.php b/htdocs/includes/phplot5/phplot.php new file mode 100644 index 00000000000..2ae549690d9 --- /dev/null +++ b/htdocs/includes/phplot5/phplot.php @@ -0,0 +1,4455 @@ + + * + * Requires PHP 4.2.0 or later (CHECK THIS) + */ + +if (! defined(__FUNCTION__)) + define(__FUNCTION__, '__FUNCTION__ Requires at least PHP 4.3.0.'); + +define ('MINY', -1); // Indexes in $data (for DrawXDataLine()) +define ('MAXY', -2); +define ('TOTY', -3); + +// LDR +//error_reporting(E_ALL); + +class PHPlot { + + /* I have removed internal variable declarations, some isset() checking was required, + * but now the variables left are those which can be tweaked by the user. This is intended to + * be the first step towards moving most of the Set...() methods into a subclass which will be + * used only when strictly necessary. Many users will be able to put default values here in the + * class and thus avoid memory overhead and reduce parsing times. + */ + //////////////// CONFIG PARAMETERS ////////////////////// + + var $is_inline = FALSE; // FALSE = Sends headers, TRUE = sends just raw image data + var $browser_cache = FALSE; // FALSE = Sends headers for browser to not cache the image, + // (only if is_inline = FALSE also) + + var $safe_margin = 5; // Extra margin used in several places. In pixels + + var $x_axis_position = ''; // Where to draw both axis (world coordinates), + var $y_axis_position = ''; // leave blank for X axis at 0 and Y axis at left of plot. + + var $xscale_type = 'linear'; // linear, log + var $yscale_type = 'linear'; + +//Fonts + var $use_ttf = FALSE; // Use True Type Fonts? + var $ttf_path = '.'; // Default path to look in for TT Fonts. + var $default_ttfont = 'benjamingothic.ttf'; + var $line_spacing = 4; // Pixels between lines. + + // Font angles: 0 or 90 degrees for fixed fonts, any for TTF + var $x_label_angle = 0; // For labels on X axis (tick and data) + var $y_label_angle = 0; // For labels on Y axis (tick and data) + var $x_title_angle = 0; // Don't change this if you don't want to screw things up! + var $y_title_angle = 90; // Nor this. + var $title_angle = 0; // Or this. + +//Formats + var $file_format = 'png'; + var $output_file = ''; // For output to a file instead of stdout + +//Data + var $data_type = 'text-data'; // text-data, data-data-error, data-data, text-data-single + var $plot_type= 'linepoints'; // bars, lines, linepoints, area, points, pie, thinbarline, squared + + var $label_scale_position = 0.5; // Shifts data labes in pie charts. 1 = top, 0 = bottom + var $group_frac_width = 0.7; // value from 0 to 1 = width of bar groups + var $bar_width_adjust = 1; // 1 = bars of normal width, must be > 0 + + var $y_precision = 1; + var $x_precision = 1; + + var $data_units_text = ''; // Units text for 'data' labels (i.e: '¤', '$', etc.) + +// Titles + var $title_txt = ''; + + var $x_title_txt = ''; + var $x_title_pos = 'plotdown'; // plotdown, plotup, both, none + + var $y_title_txt = ''; + var $y_title_pos = 'plotleft'; // plotleft, plotright, both, none + + +//Labels + // There are two types of labels in PHPlot: + // Tick labels: they follow the grid, next to ticks in axis. (DONE) + // they are drawn at grid drawing time, by DrawXTicks() and DrawYTicks() + // Data labels: they follow the data points, and can be placed on the axis or the plot (x/y) (TODO) + // they are drawn at graph plotting time, by Draw*DataLabel(), called by DrawLines(), etc. + // Draw*DataLabel() also draws H/V lines to datapoints depending on draw_*_data_label_lines + + // Tick Labels + var $x_tick_label_pos = 'plotdown'; // plotdown, plotup, both, xaxis, none + var $y_tick_label_pos = 'plotleft'; // plotleft, plotright, both, yaxis, none + + // Data Labels: + var $x_data_label_pos = 'plotdown'; // plotdown, plotup, both, plot, all, none + var $y_data_label_pos = 'plotleft'; // plotleft, plotright, both, plot, all, none + + var $draw_x_data_label_lines = FALSE; // Draw a line from the data point to the axis? + var $draw_y_data_label_lines = FALSE; // TODO + + // Label types: (for tick, data and plot labels) + var $x_label_type = ''; // data, time. Leave blank for no formatting. + var $y_label_type = ''; // data, time. Leave blank for no formatting. + var $x_time_format = '%H:%m:%s'; // See http://www.php.net/manual/html/function.strftime.html + var $y_time_format = '%H:%m:%s'; // SetYTimeFormat() too... + + // Skipping labels + var $x_label_inc = 1; // Draw a label every this many (1 = all) (TODO) + var $y_label_inc = 1; + var $_x_label_cnt = 0; // internal count FIXME: work in progress + + // Legend + var $legend = ''; // An array with legend titles + var $legend_x_pos = ''; + var $legend_y_pos = ''; + + +//Ticks + var $x_tick_length = 5; // tick length in pixels for upper/lower axis + var $y_tick_length = 5; // tick length in pixels for left/right axis + + var $x_tick_cross = 3; // ticks cross x axis this many pixels + var $y_tick_cross = 3; // ticks cross y axis this many pixels + + var $x_tick_pos = 'plotdown'; // plotdown, plotup, both, xaxis, none + var $y_tick_pos = 'plotleft'; // plotright, plotleft, both, yaxis, none + + var $num_x_ticks = ''; + var $num_y_ticks = ''; + + var $x_tick_inc = ''; // Set num_x_ticks or x_tick_inc, not both. + var $y_tick_inc = ''; // Set num_y_ticks or y_tick_inc, not both. + + var $skip_top_tick = FALSE; + var $skip_bottom_tick = FALSE; + var $skip_left_tick = FALSE; + var $skip_right_tick = FALSE; + +//Grid Formatting + var $draw_x_grid = FALSE; + var $draw_y_grid = TRUE; + + var $dashed_grid = TRUE; + var $grid_at_foreground = FALSE; // Chooses whether to draw the grid below or above the graph + +//Colors and styles (all colors can be array (R,G,B) or named color) + var $color_array = 'small'; // 'small', 'large' or array (define your own colors) + // See rgb.inc.php and SetRGBArray() + var $i_border = array(194, 194, 194); + var $plot_bg_color = 'white'; + var $bg_color = 'white'; + var $label_color = 'black'; + var $text_color = 'black'; + var $grid_color = 'black'; + var $light_grid_color = 'gray'; + var $tick_color = 'black'; + var $title_color = 'black'; + var $data_colors = array('SkyBlue', 'green', 'orange', 'blue', 'orange', 'red', 'violet', 'azure1'); + var $error_bar_colors = array('SkyBlue', 'green', 'orange', 'blue', 'orange', 'red', 'violet', 'azure1'); + var $data_border_colors = array('black'); + + var $line_widths = 1; // single value or array + var $line_styles = array('solid', 'solid', 'dashed'); // single value or array + var $dashed_style = '2-4'; // colored dots-transparent dots + + var $point_sizes = array(5,5,3); // single value or array + var $point_shapes = array('diamond'); // rect, circle, diamond, triangle, dot, line, halfline, cross + + var $error_bar_size = 5; // right and left size of tee + var $error_bar_shape = 'tee'; // 'tee' or 'line' + var $error_bar_line_width = 1; // single value (or array TODO) + + var $plot_border_type = 'sides'; // left, sides, none, full + var $image_border_type = 'none'; // 'raised', 'plain', 'none' + + var $shading = 5; // 0 for no shading, > 0 is size of shadows in pixels + + var $draw_plot_area_background = FALSE; + var $draw_broken_lines = FALSE; // Tells not to draw lines for missing Y data. + + +////////////////////////////////////////////////////// +//BEGIN CODE +////////////////////////////////////////////////////// + + /*! + * Constructor: Setup img resource, colors and size of the image, and font sizes. + * + * \param which_width int Image width in pixels. + * \param which_height int Image height in pixels. + * \param which_output_file string Filename for output. + * \param which_input_fule string Path to a file to be used as background. + */ + function PHPlot($which_width=600, $which_height=400, $which_output_file=NULL, $which_input_file=NULL) + { + /* + * Please see http://www.php.net/register_shutdown_function + * PLEASE NOTE: register_shutdown_function() will take a copy of the object rather than a reference + * so we put an ampersand. However, the function registered will work on the object as it + * was upon registration. To solve this, one of two methods can be used: + * $obj = new object(); + * register_shutdown_function(array(&$obj,'shutdown')); + * OR + * $obj = &new object(); + * HOWEVER, as the second statement assigns $obj a reference to the current object, it might be that + * several instances mess things up... (CHECK THIS) + * + * AND + * as $this->img is set upon construction of the object, problems will not arise for us (for the + * moment maybe, so I put all this here just in case) + */ + register_shutdown_function(array(&$this, '_PHPlot')); + + $this->SetRGBArray($this->color_array); + + $this->background_done = FALSE; // Set to TRUE after background image is drawn once + + if ($which_output_file) + $this->SetOutputFile($which_output_file); + + if ($which_input_file) + $this->SetInputFile($which_input_file); + else { + $this->image_width = $which_width; + $this->image_height = $which_height; + + $this->img = ImageCreate($this->image_width, $this->image_height); + if (! $this->img) + $this->PrintError('PHPlot(): Could not create image resource.'); + + } + + $this->SetDefaultStyles(); + $this->SetDefaultFonts(); + + $this->SetTitle(''); + $this->SetXTitle(''); + $this->SetYTitle(''); + + $this->print_image = TRUE; // Use for multiple plots per image (TODO: automatic) + } + + /*! + * Destructor. Image resources not deallocated can be memory hogs, I think + * it is safer to automatically call imagedestroy upon script termination than + * do it ourselves. + * See notes in the constructor code. + */ + function _PHPlot () + { + ImageDestroy($this->img); + return; + } + + +///////////////////////////////////////////// +////////////// COLORS +///////////////////////////////////////////// + + /*! + * Returns an index to a color passed in as anything (string, hex, rgb) + * + * \param which_color * Color (can be '#AABBCC', 'Colorname', or array(r,g,b)) + */ + function SetIndexColor($which_color) + { + list ($r, $g, $b) = $this->SetRGBColor($which_color); //Translate to RGB + $index = ImageColorExact($this->img, $r, $g, $b); + if ($index == -1) { + return ImageColorResolve($this->img, $r, $g, $b); + } else { + return $index; + } + } + + + /*! + * Returns an index to a slightly darker color than the one requested. + */ + function SetIndexDarkColor($which_color) + { + list ($r, $g, $b) = $this->SetRGBColor($which_color); + + $r -= 0x30; $r = ($r < 0) ? 0 : $r; + $g -= 0x30; $g = ($g < 0) ? 0 : $g; + $b -= 0x30; $b = ($b < 0) ? 0 : $b; + + $index = ImageColorExact($this->img, $r, $g, $b); + if ($index == -1) { + return ImageColorResolve($this->img, $r, $g, $b); + } else { + return $index; + } + } + + /*! + * Sets/reverts all colors and styles to their defaults. If session is set, then only updates indices, + * as they are lost with every script execution, else, sets the default colors by name or value and + * then updates indices too. + * + * FIXME Isn't this too slow? + * + */ + function SetDefaultStyles() + { + /* Some of the Set*() functions use default values when they get no parameters. */ + + if (! isset($this->session_set)) { + // If sessions are enabled, this variable will be preserved, so upon future executions, we + // will have it set, as well as color names (though not color indices, that's why we + // need to rebuild them) + $this->session_set = TRUE; + + // These only need to be set once + $this->SetLineWidths(); + $this->SetLineStyles(); + $this->SetDefaultDashedStyle($this->dashed_style); + $this->SetPointSizes($this->point_sizes); + } + + $this->SetImageBorderColor($this->i_border); + $this->SetPlotBgColor($this->plot_bg_color); + $this->SetBackgroundColor($this->bg_color); + $this->SetLabelColor($this->label_color); + $this->SetTextColor($this->text_color); + $this->SetGridColor($this->grid_color); + $this->SetLightGridColor($this->light_grid_color); + $this->SetTickColor($this->tick_color); + $this->SetTitleColor($this->title_color); + $this->SetDataColors(); + $this->SetErrorBarColors(); + $this->SetDataBorderColors(); + } + + + /* + * + */ + function SetBackgroundColor($which_color) + { + $this->bg_color= $which_color; + $this->ndx_bg_color= $this->SetIndexColor($this->bg_color); + return TRUE; + } + + /* + * + */ + function SetPlotBgColor($which_color) + { + $this->plot_bg_color= $which_color; + $this->ndx_plot_bg_color= $this->SetIndexColor($this->plot_bg_color); + return TRUE; + } + + /* + * + */ + function SetTitleColor($which_color) + { + $this->title_color= $which_color; + $this->ndx_title_color= $this->SetIndexColor($this->title_color); + return TRUE; + } + + /* + * + */ + function SetTickColor ($which_color) + { + $this->tick_color= $which_color; + $this->ndx_tick_color= $this->SetIndexColor($this->tick_color); + return TRUE; + } + + + /* + * + */ + function SetLabelColor ($which_color) + { + $this->label_color = $which_color; + $this->ndx_title_color= $this->SetIndexColor($this->label_color); + return TRUE; + } + + + /* + * + */ + function SetTextColor ($which_color) + { + $this->text_color= $which_color; + $this->ndx_text_color= $this->SetIndexColor($this->text_color); + return TRUE; + } + + + /* + * + */ + function SetLightGridColor ($which_color) + { + $this->light_grid_color= $which_color; + $this->ndx_light_grid_color= $this->SetIndexColor($this->light_grid_color); + return TRUE; + } + + + /* + * + */ + function SetGridColor ($which_color) + { + $this->grid_color = $which_color; + $this->ndx_grid_color= $this->SetIndexColor($this->grid_color); + return TRUE; + } + + + /* + * + */ + function SetImageBorderColor($which_color) + { + $this->i_border = $which_color; + $this->ndx_i_border = $this->SetIndexColor($this->i_border); + $this->ndx_i_border_dark = $this->SetIndexDarkColor($this->i_border); + return TRUE; + } + + + /* + * + */ + function SetTransparentColor($which_color) + { + ImageColorTransparent($this->img, $this->SetIndexColor($which_color)); + return TRUE; + } + + + /*! + * Sets the array of colors to be used. It can be user defined, a small predefined one + * or a large one included from 'rgb.inc.php'. + * + * \param which_color_array If an array, the used as color array. If a string can + * be one of 'small' or 'large'. + */ + function SetRGBArray ($which_color_array) + { + if ( is_array($which_color_array) ) { // User defined array + $this->rgb_array = $which_color_array; + return TRUE; + } elseif ($which_color_array == 'small') { // Small predefined color array + $this->rgb_array = array( + 'white' => array(255, 255, 255), + 'snow' => array(255, 250, 250), + 'PeachPuff' => array(255, 218, 185), + 'ivory' => array(255, 255, 240), + 'lavender' => array(230, 230, 250), + 'black' => array( 0, 0, 0), + 'DimGrey' => array(105, 105, 105), + 'gray' => array(190, 190, 190), + 'grey' => array(190, 190, 190), + 'navy' => array( 0, 0, 128), + 'SlateBlue' => array(106, 90, 205), + 'blue' => array( 0, 0, 255), + 'SkyBlue' => array(135, 206, 235), + 'cyan' => array( 0, 255, 255), + 'DarkGreen' => array( 0, 100, 0), + 'green' => array( 0, 255, 0), + 'YellowGreen' => array(154, 205, 50), + 'yellow' => array(255, 255, 0), + 'orange' => array(255, 165, 0), + 'gold' => array(255, 215, 0), + 'peru' => array(205, 133, 63), + 'beige' => array(245, 245, 220), + 'wheat' => array(245, 222, 179), + 'tan' => array(210, 180, 140), + 'brown' => array(165, 42, 42), + 'salmon' => array(250, 128, 114), + 'red' => array(255, 0, 0), + 'pink' => array(255, 192, 203), + 'maroon' => array(176, 48, 96), + 'magenta' => array(255, 0, 255), + 'violet' => array(238, 130, 238), + 'plum' => array(221, 160, 221), + 'orchid' => array(218, 112, 214), + 'purple' => array(160, 32, 240), + 'azure1' => array(240, 255, 255), + 'aquamarine1' => array(127, 255, 212) + ); + return TRUE; + } elseif ($which_color_array === 'large') { // Large color array + include("./rgb.inc.php"); + $this->rgb_array = $RGBArray; + } else { // Default to black and white only. + $this->rgb_array = array('white' => array(255, 255, 255), 'black' => array(0, 0, 0)); + } + + return TRUE; + } + + /*! + * Returns an array in R, G, B format 0-255 + * + * \param color_asked array(R,G,B) or string (named color or '#AABBCC') + */ + function SetRGBColor($color_asked) + { + if ($color_asked == '') { $color_asked = array(0, 0, 0); }; + + if ( count($color_asked) == 3 ) { // already array of 3 rgb + $ret_val = $color_asked; + } else { // asking for a color by string + if(substr($color_asked, 0, 1) == '#') { // asking in #FFFFFF format. + $ret_val = array(hexdec(substr($color_asked, 1, 2)), hexdec(substr($color_asked, 3, 2)), + hexdec(substr($color_asked, 5, 2))); + } else { // asking by color name +// LDR +// $ret_val = $this->rgb_array[$color_asked]; + $ret_val = isset($this->rgb_array[$color_asked]) ? $this->rgb_array[$color_asked] : 0; + } + } + return $ret_val; + } + + + /*! + * Sets the colors for the data. + */ + function SetDataColors($which_data = NULL, $which_border = NULL) + { + if (is_null($which_data) && is_array($this->data_colors)) { + // use already set data_colors + } else if (! is_array($which_data)) { + $this->data_colors = ($which_data) ? array($which_data) : array('blue', 'red', 'green', 'orange'); + } else { + $this->data_colors = $which_data; + } + + $i = 0; + foreach ($this->data_colors as $col) { + $this->ndx_data_colors[$i] = $this->SetIndexColor($col); + $this->ndx_data_dark_colors[$i] = $this->SetIndexDarkColor($col); + $i++; + } + + // For past compatibility: + $this->SetDataBorderColors($which_border); + } // function SetDataColors() + + + /*! + * + */ + function SetDataBorderColors($which_br = NULL) + { + if (is_null($which_br) && is_array($this->data_border_colors)) { + // use already set data_border_colors + } else if (! is_array($which_br)) { + // Create new array with specified color + $this->data_border_colors = ($which_br) ? array($which_br) : array('black'); + } else { + $this->data_border_colors = $which_br; + } + + $i = 0; + foreach($this->data_border_colors as $col) { + $this->ndx_data_border_colors[$i] = $this->SetIndexColor($col); + $i++; + } + } // function SetDataBorderColors() + + + /*! + * Sets the colors for the data error bars. + */ + function SetErrorBarColors($which_err = NULL) + { + if (is_null($which_err) && is_array($this->error_bar_colors)) { + // use already set error_bar_colors + } else if (! is_array($which_err)) { + $this->error_bar_colors = ($which_err) ? array($which_err) : array('black'); + } else { + $this->error_bar_colors = $which_err; + } + + $i = 0; + foreach($this->error_bar_colors as $col) { + $this->ndx_error_bar_colors[$i] = $this->SetIndexColor($col); + $i++; + } + return TRUE; + + } // function SetErrorBarColors() + + + /*! + * Sets the default dashed style. + * \param which_style A string specifying order of colored and transparent dots, + * i.e: '4-3' means 4 colored, 3 transparent; + * '2-3-1-2' means 2 colored, 3 transparent, 1 colored, 2 transparent. + */ + function SetDefaultDashedStyle($which_style) + { + // String: "numcol-numtrans-numcol-numtrans..." + $asked = explode('-', $which_style); + + if (count($asked) < 2) { + $this->DrawError("SetDefaultDashedStyle(): Wrong parameter '$which_style'."); + return FALSE; + } + + // Build the string to be eval()uated later by SetDashedStyle() + $this->default_dashed_style = 'array( '; + + $t = 0; + foreach($asked as $s) { + if ($t % 2 == 0) { + $this->default_dashed_style .= str_repeat('$which_ndxcol,', $s); + } else { + $this->default_dashed_style .= str_repeat('IMG_COLOR_TRANSPARENT,', $s); + } + $t++; + } + // Remove trailing comma and add closing parenthesis + $this->default_dashed_style = substr($this->default_dashed_style, 0, -1); + $this->default_dashed_style .= ')'; + + return TRUE; + } + + + /*! + * Sets the style before drawing a dashed line. Defaults to $this->default_dashed_style + * \param which_ndxcol Color index to be used. + */ + function SetDashedStyle($which_ndxcol) + { + // See SetDefaultDashedStyle() to understand this. + eval ("\$style = $this->default_dashed_style;"); + return imagesetstyle($this->img, $style); + } + + + /*! + * Sets line widths on a per-line basis. + */ + function SetLineWidths($which_lw=NULL) + { + if (is_null($which_lw)) { + // Do nothing, use default value. + } else if (is_array($which_lw)) { + // Did we get an array with line widths? + $this->line_widths = $which_lw; + } else { + $this->line_widths = array($which_lw); + } + return TRUE; + } + + /*! + * + */ + function SetLineStyles($which_ls=NULL) + { + if (is_null($which_ls)) { + // Do nothing, use default value. + } else if (! is_array($which_ls)) { + // Did we get an array with line styles? + $this->line_styles = $which_ls; + } else { + $this->line_styles = ($which_ls) ? array($which_ls) : array('solid'); + } + return TRUE; + } + + +///////////////////////////////////////////// +////////////// FONTS +///////////////////////////////////////////// + + + /*! + * Sets number of pixels between lines of the same text. + */ + function SetLineSpacing($which_spc) + { + $this->line_spacing = $which_spc; + } + + + /*! + * Enables use of TrueType fonts in the graph. Font initialisation methods + * depend on this setting, so when called, SetUseTTF() resets the font + * settings + */ + function SetUseTTF($which_ttf) + { + $this->use_ttf = $which_ttf; + if ($which_ttf) + $this->SetDefaultFonts(); + return TRUE; + } + + /*! + * Sets the directory name to look into for TrueType fonts. + */ + function SetTTFPath($which_path) + { + // Maybe someone needs really dynamic config. He'll need this: + // clearstatcache(); + + if (is_dir($which_path) && is_readable($which_path)) { + $this->ttf_path = $which_path; + return TRUE; + } else { + $this->PrintError("SetTTFPath(): $which_path is not a valid path."); + return FALSE; + } + } + + /*! + * Sets the default TrueType font and updates all fonts to that. + */ + function SetDefaultTTFont($which_font) + { + if (is_file($which_font) && is_readable($which_font)) { + $this->default_ttfont = $which_font; + return $this->SetDefaultFonts(); + } else { + $this->PrintError("SetDefaultTTFont(): $which_font is not a valid font file."); + return FALSE; + } + } + + /*! + * Sets fonts to their defaults + */ + function SetDefaultFonts() + { + // TTF: + if ($this->use_ttf) { + //$this->SetTTFPath(dirname($_SERVER['PHP_SELF'])); + $this->SetTTFPath(getcwd()); + $this->SetFont('generic', $this->default_ttfont, 8); + $this->SetFont('title', $this->default_ttfont, 14); + $this->SetFont('legend', $this->default_ttfont, 8); + $this->SetFont('x_label', $this->default_ttfont, 6); + $this->SetFont('y_label', $this->default_ttfont, 6); + $this->SetFont('x_title', $this->default_ttfont, 10); + $this->SetFont('y_title', $this->default_ttfont, 10); + } + // Fixed: + else { + $this->SetFont('generic', 2); + $this->SetFont('title', 5); + $this->SetFont('legend', 2); + $this->SetFont('x_label', 1); + $this->SetFont('y_label', 1); + $this->SetFont('x_title', 3); + $this->SetFont('y_title', 3); + } + + return TRUE; + } + + /*! + * Sets Fixed/Truetype font parameters. + * \param $which_elem Is the element whose font is to be changed. + * It can be one of 'title', 'legend', 'generic', + * 'x_label', 'y_label', x_title' or 'y_title' + * \param $which_font Can be a number (for fixed font sizes) or + * a string with the filename when using TTFonts. + * \param $which_size Point size (TTF only) + * Calculates and updates internal height and width variables. + */ + function SetFont($which_elem, $which_font, $which_size = 12) + { + // TTF: + if ($this->use_ttf) { + $path = $this->ttf_path.'/'.$which_font; + + if (! is_file($path) || ! is_readable($path) ) { + $this->DrawError("SetFont(): True Type font $path doesn't exist"); + return FALSE; + } + + switch ($which_elem) { + case 'generic': + $this->generic_font['font'] = $path; + $this->generic_font['size'] = $which_size; + break; + case 'title': + $this->title_font['font'] = $path; + $this->title_font['size'] = $which_size; + break; + case 'legend': + $this->legend_font['font'] = $path; + $this->legend_font['size'] = $which_size; + break; + case 'x_label': + $this->x_label_font['font'] = $path; + $this->x_label_font['size'] = $which_size; + break; + case 'y_label': + $this->y_label_font['font'] = $path; + $this->y_label_font['size'] = $which_size; + break; + case 'x_title': + $this->x_title_font['font'] = $path; + $this->x_title_font['size'] = $which_size; + break; + case 'y_title': + $this->y_title_font['font'] = $path; + $this->y_title_font['size'] = $which_size; + break; + default: + $this->DrawError("SetFont(): Unknown element '$which_elem' specified."); + return FALSE; + } + return TRUE; + + } + + // Fixed fonts: + if ($which_font > 5 || $which_font < 0) { + $this->DrawError('SetFont(): Non-TTF font size must be 1, 2, 3, 4 or 5'); + return FALSE; + } + + switch ($which_elem) { + case 'generic': + $this->generic_font['font'] = $which_font; + $this->generic_font['height'] = ImageFontHeight($which_font); + $this->generic_font['width'] = ImageFontWidth($which_font); + break; + case 'title': + $this->title_font['font'] = $which_font; + $this->title_font['height'] = ImageFontHeight($which_font); + $this->title_font['width'] = ImageFontWidth($which_font); + break; + case 'legend': + $this->legend_font['font'] = $which_font; + $this->legend_font['height'] = ImageFontHeight($which_font); + $this->legend_font['width'] = ImageFontWidth($which_font); + break; + case 'x_label': + $this->x_label_font['font'] = $which_font; + $this->x_label_font['height'] = ImageFontHeight($which_font); + $this->x_label_font['width'] = ImageFontWidth($which_font); + break; + case 'y_label': + $this->y_label_font['font'] = $which_font; + $this->y_label_font['height'] = ImageFontHeight($which_font); + $this->y_label_font['width'] = ImageFontWidth($which_font); + break; + case 'x_title': + $this->x_title_font['font'] = $which_font; + $this->x_title_font['height'] = ImageFontHeight($which_font); + $this->x_title_font['width'] = ImageFontWidth($which_font); + break; + case 'y_title': + $this->y_title_font['font'] = $which_font; + $this->y_title_font['height'] = ImageFontHeight($which_font); + $this->y_title_font['width'] = ImageFontWidth($which_font); + break; + default: + $this->DrawError("SetFont(): Unknown element '$which_elem' specified."); + return FALSE; + } + return TRUE; + } + + + /*! + * Returns an array with the size of the bounding box of an + * arbitrarily placed (rotated) TrueType text string. + */ + function TTFBBoxSize($size, $angle, $font, $string) + { + // First, assume angle < 90 + $arr = ImageTTFBBox($size, 0, $font, $string); + $flat_width = $arr[2] - $arr[0]; + $flat_height = abs($arr[3] - $arr[5]); + + // Now the bounding box + $angle = deg2rad($angle); + $width = ceil(abs($flat_width*cos($angle) + $flat_height*sin($angle))); //Must be integer + $height = ceil(abs($flat_width*sin($angle) + $flat_height*cos($angle))); //Must be integer + + return array($width, $height); + } + + + /*! + * Draws a string of text. Horizontal and vertical alignment are relative to + * to the drawing. That is: vertical text (90 deg) gets centered along y-axis + * with v_align = 'center', and adjusted to the left of x-axis with h_align = 'right', + * + * \note Original multiple lines code submitted by Remi Ricard. + * \note Original vertical code submitted by Marlin Viss. + */ + function DrawText($which_font, $which_angle, $which_xpos, $which_ypos, $which_color, $which_text, + $which_halign = 'left', $which_valign = 'bottom') + { + // TTF: + if ($this->use_ttf) { + $size = $this->TTFBBoxSize($which_font['size'], $which_angle, $which_font['font'], $which_text); + $rads = deg2rad($which_angle); + + if ($which_valign == 'center') + $which_ypos += $size[1]/2; + + if ($which_valign == 'bottom') + $which_ypos += $size[1]; + + if ($which_halign == 'center') + $which_xpos -= ($size[0]/2) * cos($rads); + + if ($which_halign == 'left') + $which_xpos += $size[0] * sin($rads); + + if ($which_halign == 'right') + $which_xpos -= $size[0] * cos($rads); + + ImageTTFText($this->img, $which_font['size'], $which_angle, + $which_xpos, $which_ypos, $which_color, $which_font['font'], $which_text); + } + // Fixed fonts: + else { + // Split the text by its lines, and count them + $which_text = ereg_replace("\r", "", $which_text); + $str = split("\n", $which_text); + $nlines = count($str); + $spacing = $this->line_spacing * ($nlines - 1); + + // Vertical text: + // (Remember the alignment convention with vertical text) + if ($which_angle == 90) { + // The text goes around $which_xpos. + if ($which_halign == 'center') + $which_xpos -= ($nlines * ($which_font['height'] + $spacing))/2; + + // Left alignment requires no modification to $xpos... + // Right-align it. $which_xpos designated the rightmost x coordinate. + else if ($which_halign == 'right') + $which_xpos += ($nlines * ($which_font['height'] + $spacing)); + + $ypos = $which_ypos; + for($i = 0; $i < $nlines; $i++) { + // Center the text vertically around $which_ypos (each line) + if ($which_valign == 'center') + $ypos = $which_ypos + (strlen($str[$i]) * $which_font['width']) / 2; + // Make the text finish (vertically) at $which_ypos + if ($which_valign == 'bottom') + $ypos = $which_ypos + strlen($str[$i]) * $which_font['width']; + + ImageStringUp($this->img, $which_font['font'], + $i * ($which_font['height'] + $spacing) + $which_xpos, + $ypos, $str[$i], $which_color); + } + } + // Horizontal text: + else { + // The text goes above $which_ypos + if ($which_valign == 'top') + $which_ypos -= $nlines * ($which_font['height'] + $spacing); + // The text is centered around $which_ypos + if ($which_valign == 'center') + $which_ypos -= ($nlines * ($which_font['height'] + $spacing))/2; + // valign = 'bottom' requires no modification + + $xpos = $which_xpos; + for($i = 0; $i < $nlines; $i++) { + // center the text around $which_xpos + if ($which_halign == 'center') + $xpos = $which_xpos - (strlen($str[$i]) * $which_font['width'])/2; + // make the text finish at $which_xpos + if ($which_halign == 'right') + $xpos = $which_xpos - strlen($str[$i]) * $which_font['width']; + + ImageString($this->img, $which_font['font'], $xpos, + $i * ($which_font['height'] + $spacing) + $which_ypos, + $str[$i], $which_color); + } + } + } + return TRUE; + } // function DrawText() + + +///////////////////////////////////////////// +/////////// INPUT / OUTPUT CONTROL +///////////////////////////////////////////// + + /*! + * Sets output file format. + */ + function SetFileFormat($format) + { + $asked = $this->CheckOption($format, 'jpg, png, gif, wbmp', __FUNCTION__); + + switch ($asked) { + case 'jpg': + if (imagetypes() & IMG_JPG) + $this->file_format = 'jpg'; + return TRUE; + break; + case 'png': + if (imagetypes() & IMG_PNG) + $this->file_format = 'png'; + return TRUE; + break; + case 'gif': + if (imagetypes() & IMG_GIF) + $this->file_format = 'gif'; + return TRUE; + break; + case 'wbmp': + if (imagetypes() & IMG_WBMP) + $this->file_format = 'wbmp'; + return TRUE; + break; + default: + $this->PrintError("SetFileFormat():File format '$format' not supported"); + return FALSE; + } + } + + + /*! + * Selects an input file to be used as graph background and scales or tiles this image + * to fit the sizes. + * \param input_file string Path to the file to be used (jpeg, png and gif accepted) + * \param mode string 'centeredtile', 'tile', 'scale' (the image to the graph's size) + */ + function SetBgImage($input_file, $mode='centeredtile') + { + $this->bgmode = $this->CheckOption($mode, 'tile, centeredtile, scale', __FUNCTION__); + $this->bgimg = $input_file; + } + + /*! + * Selects an input file to be used as plot area background and scales or tiles this image + * to fit the sizes. + * \param input_file string Path to the file to be used (jpeg, png and gif accepted) + * \param mode string 'centeredtile', 'tile', 'scale' (the image to the graph's size) + */ + function SetPlotAreaBgImage($input_file, $mode='tile') + { + $this->plotbgmode = $this->CheckOption($mode, 'tile, centeredtile, scale', __FUNCTION__); + $this->plotbgimg = $input_file; + } + + + /*! + * Sets the name of the file to be used as output file. + */ + function SetOutputFile($which_output_file) + { + $this->output_file = $which_output_file; + return TRUE; + } + + /*! + * Sets the output image as 'inline', that is: no Content-Type headers are sent + * to the browser. Needed if you want to embed the images. + */ + function SetIsInline($which_ii) + { + $this->is_inline = (bool)$which_ii; + return TRUE; + } + + + /*! + * Performs the actual outputting of the generated graph, and + * destroys the image resource. + */ + function PrintImage() + { + // Browser cache stuff submitted by Thiemo Nagel + if ( (! $this->browser_cache) && (! $this->is_inline)) { + 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'); + } + + switch($this->file_format) { + case 'png': + if (! $this->is_inline) { + Header('Content-type: image/png'); + } + if ($this->is_inline && $this->output_file != '') { + ImagePng($this->img, $this->output_file); + } else { + ImagePng($this->img); + } + break; + case 'jpg': + if (! $this->is_inline) { + Header('Content-type: image/jpeg'); + } + if ($this->is_inline && $this->output_file != '') { + ImageJPEG($this->img, $this->output_file); + } else { + ImageJPEG($this->img); + } + break; + case 'gif': + if (! $this->is_inline) { + Header('Content-type: image/gif'); + } + if ($this->is_inline && $this->output_file != '') { + ImageGIF($this->img, $this->output_file); + } else { + ImageGIF($this->img); + } + + break; + case 'wbmp': // wireless bitmap, 2 bit. + if (! $this->is_inline) { + Header('Content-type: image/wbmp'); + } + if ($this->is_inline && $this->output_file != '') { + ImageWBMP($this->img, $this->output_file); + } else { + ImageWBMP($this->img); + } + + break; + default: + $this->PrintError('PrintImage(): Please select an image type!'); + break; + } + return TRUE; + } + + /*! + * Prints an error message to stdout and dies + */ + function PrintError($error_message) + { + echo "

Fatal error: $error_message

"; + die; + } + + /*! + * Prints an error message inline into the generated image and draws it centered + * around the given coordinates (defaults to center of the image) + * \param error_message Message to be drawn + * \param where_x X coordinate + * \param where_y Y coordinate + */ + function DrawError($error_message, $where_x = NULL, $where_y = NULL) + { + if (! $this->img) + $this->PrintError('_DrawError(): Warning, no image resource allocated. '. + 'The message to be written was: '.$error_message); + + $ypos = (! $where_y) ? $this->image_height/2 : $where_y; + $xpos = (! $where_x) ? $this->image_width/2 : $where_x; + ImageRectangle($this->img, 0, 0, $this->image_width, $this->image_height, + ImageColorAllocate($this->img, 255, 255, 255)); + + $this->DrawText($this->generic_font, 0, $xpos, $ypos, ImageColorAllocate($this->img, 0, 0, 0), + $error_message, 'center', 'center'); + + $this->PrintImage(); + exit; +// return TRUE; + } + +///////////////////////////////////////////// +/////////// LABELS +///////////////////////////////////////////// + + + /*! + * Sets position for X labels following data points. + */ + function SetXDataLabelPos($which_xdlp) + { + $this->x_data_label_pos = $this->CheckOption($which_xdlp, 'plotdown, plotup, both, xaxis, all, none', + __FUNCTION__); + if ($which_xdlp != 'none') + $this->x_tick_label_pos = 'none'; + + return TRUE; + } + + /*! + * Sets position for Y labels following data points. + */ + function SetYDataLabelPos($which_ydlp) + { + $this->y_data_label_pos = $this->CheckOption($which_ydlp, 'plotleft, plotright, both, yaxis, all, none', + __FUNCTION__); + if ($which_ydlp != 'none') + $this->y_tick_label_pos = 'none'; + + return TRUE; + } + + + /*! + * Sets position for X labels following ticks (hence grid lines) + */ + function SetXTickLabelPos($which_xtlp) + { + $this->x_tick_label_pos = $this->CheckOption($which_xtlp, 'plotdown, plotup, both, xaxis, all, none', + __FUNCTION__); + if ($which_xtlp != 'none') + $this->x_data_label_pos = 'none'; + + return TRUE; + } + + /*! + * Sets position for Y labels following ticks (hence grid lines) + */ + function SetYTickLabelPos($which_ytlp) + { + $this->y_tick_label_pos = $this->CheckOption($which_ytlp, 'plotleft, plotright, both, yaxis, all, none', + __FUNCTION__); + if ($which_ytlp != 'none') + $this->y_data_label_pos = 'none'; + + return TRUE; + } + + /*! + * Sets type for tick and data labels on X axis. + * \note 'title' type left for backwards compatibility. + */ + function SetXLabelType($which_xlt) + { + $this->x_label_type = $this->CheckOption($which_xlt, 'data, time, title', __FUNCTION__); + return TRUE; + } + + /*! + * Sets type for tick and data labels on Y axis. + */ + function SetYLabelType($which_ylt) + { + $this->y_label_type = $this->CheckOption($which_ylt, 'data, time', __FUNCTION__); + return TRUE; + } + + function SetXTimeFormat($which_xtf) + { + $this->x_time_format = $which_xtf; + return TRUE; + } + function SetYTimeFormat($which_ytf) + { + $this->y_time_format = $which_ytf; + return TRUE; + } + + function SetXLabelAngle($which_xla) + { + $this->x_label_angle = $which_xla; + return TRUE; + } + + function SetYLabelAngle($which_yla) + { + $this->y_label_angle = $which_yla; + return TRUE; + } + +///////////////////////////////////////////// +/////////// MISC +///////////////////////////////////////////// + + /*! + * Checks the valididy of an option. + * \param which_opt String to check. + * \param which_acc String of accepted choices. + * \param which_func Name of the calling function, for error messages. + * \note If checking everywhere for correctness slows things down, we could provide a + * child class overriding every Set...() method which uses CheckOption(). Those new + * methods could proceed in the unsafe but faster way. + */ + function CheckOption($which_opt, $which_acc, $which_func) + { + $asked = trim($which_opt); + + // FIXME: this for backward compatibility, as eregi() fails with empty strings. + if ($asked == '') + return ''; + + $asked = strtolower($asked); + if (@ eregi($asked, $which_acc)) { + return $asked; + } else { + $this->DrawError("$which_func(): '$which_opt' not in available choices: '$which_acc'."); + return NULL; + } + } + + + /*! + * \note Submitted by Thiemo Nagel + */ + function SetBrowserCache($which_browser_cache) + { + $this->browser_cache = $which_browser_cache; + return TRUE; + } + + /*! + * Whether to show the final image or not + */ + function SetPrintImage($which_pi) + { + $this->print_image = $which_pi; + return TRUE; + } + + /*! + * Sets the graph's legend. If argument is not an array, appends it to the legend. + */ + function SetLegend($which_leg) + { + if (is_array($which_leg)) { // use array + $this->legend = $which_leg; + return TRUE; + } else if (! is_null($which_leg)) { // append string + $this->legend[] = $which_leg; + return TRUE; + } else { + $this->DrawError("SetLegend(): argument must not be null."); + return FALSE; + } + } + + /*! + * Specifies the absolute (relative to image's up/left corner) position + * of the legend's upper/leftmost corner. + * $which_type not yet used (TODO) + */ + function SetLegendPixels($which_x, $which_y, $which_type=NULL) + { + $this->legend_x_pos = $which_x; + $this->legend_y_pos = $which_y; + + return TRUE; + } + + /*! + * Specifies the relative (to graph's origin) position of the legend's + * upper/leftmost corner. MUST be called after scales are set up. + * $which_type not yet used (TODO) + */ + function SetLegendWorld($which_x, $which_y, $which_type=NULL) + { + if (! isset($this->scale_is_set)) + $this->CalcTranslation(); + + $this->legend_x_pos = $this->xtr($which_x); + $this->legend_y_pos = $this->ytr($which_y); + + return TRUE; + } + + /*! + * Accepted values are: left, sides, none, full + */ + function SetPlotBorderType($pbt) + { + $this->plot_border_type = $this->CheckOption($pbt, 'left, sides, none, full', __FUNCTION__); + } + + /*! + * Accepted values are: raised, plain + */ + function SetImageBorderType($sibt) + { + $this->image_border_type = $this->CheckOption($sibt, 'raised, plain', __FUNCTION__); + } + + + /*! + * \param dpab bool + */ + function SetDrawPlotAreaBackground($dpab) + { + $this->draw_plot_area_background = (bool)$dpab; + } + + + /*! + * \param dyg bool + */ + function SetDrawYGrid($dyg) + { + $this->draw_y_grid = (bool)$dyg; + return TRUE; + } + + + /*! + * \param dxg bool + */ + function SetDrawXGrid($dxg) + { + $this->draw_x_grid = (bool)$dxg; + return TRUE; + } + + + /*! + * \param ddg bool + */ + function SetDrawDashedGrid($ddg) + { + $this->dashed_grid = (bool)$ddg; + return TRUE; + } + + + /*! + * \param dxdl bool + */ + function SetDrawXDataLabelLines($dxdl) + { + $this->draw_x_data_label_lines = (bool)$dxdl; + return TRUE; + } + + + /*! + * TODO: draw_y_data_label_lines not implemented. + * \param dydl bool + */ + function SetDrawYDataLabelLines($dydl) + { + $this->draw_y_data_label_lines = $dydl; + return TRUE; + } + + /*! + * Sets the graph's title. + * TODO: add parameter to choose title placement: left, right, centered= + */ + function SetTitle($which_title) + { + $this->title_txt = $which_title; + + if ($which_title == '') { + $this->title_height = 0; + return TRUE; + } + + $str = split("\n", $which_title); + $lines = count($str); + $spacing = $this->line_spacing * ($lines - 1); + + if ($this->use_ttf) { + $size = $this->TTFBBoxSize($this->title_font['size'], 0, $this->title_font['font'], $which_title); + $this->title_height = $size[1] * $lines; + } else { + $this->title_height = ($this->title_font['height'] + $spacing) * $lines; + } + return TRUE; + } + + /*! + * Sets the X axis title and position. + */ + function SetXTitle($which_xtitle, $which_xpos = 'plotdown') + { + if ($which_xtitle == '') + $which_xpos = 'none'; + + $this->x_title_pos = $this->CheckOption($which_xpos, 'plotdown, plotup, both, none', __FUNCTION__); + + $this->x_title_txt = $which_xtitle; + + $str = split("\n", $which_xtitle); + $lines = count($str); + $spacing = $this->line_spacing * ($lines - 1); + + if ($this->use_ttf) { + $size = $this->TTFBBoxSize($this->x_title_font['size'], 0, $this->x_title_font['font'], $which_xtitle); + $this->x_title_height = $size[1] * $lines; + } else { + $this->x_title_height = ($this->y_title_font['height'] + $spacing) * $lines; + } + + return TRUE; + } + + + /*! + * Sets the Y axis title and position. + */ + function SetYTitle($which_ytitle, $which_ypos = 'plotleft') + { + if ($which_ytitle == '') + $which_ypos = 'none'; + + $this->y_title_pos = $this->CheckOption($which_ypos, 'plotleft, plotright, both, none', __FUNCTION__); + + $this->y_title_txt = $which_ytitle; + + $str = split("\n", $which_ytitle); + $lines = count($str); + $spacing = $this->line_spacing * ($lines - 1); + + if ($this->use_ttf) { + $size = $this->TTFBBoxSize($this->y_title_font['size'], 90, $this->y_title_font['font'], + $which_ytitle); + $this->y_title_width = $size[0] * $lines; + } else { + $this->y_title_width = ($this->y_title_font['height'] + $spacing) * $lines; + } + + return TRUE; + } + + /*! + * Sets the size of the drop shadow for bar and pie charts. + * \param which_s int Size in pixels. + */ + function SetShading($which_s) + { + $this->shading = (int)$which_s; + return TRUE; + } + + function SetPlotType($which_pt) + { + $this->plot_type = $this->CheckOption($which_pt, + 'bars, stackedbars, lines, linepoints, area, points, pie, thinbarline, squared', + __FUNCTION__); + } + + /*! + * Sets the position of Y axis. + * \param pos int Position in world coordinates. + */ + function SetYAxisPosition($pos) + { + $this->y_axis_position = (int)$pos; + if (isset($this->scale_is_set)) { + $this->CalcTranslation(); + } + return TRUE; + } + + /*! + * Sets the position of X axis. + * \param pos int Position in world coordinates. + */ + function SetXAxisPosition($pos) + { + $this->x_axis_position = (int)$pos; + if (isset($this->scale_is_set)) { + $this->CalcTranslation(); + } + return TRUE; + } + + + function SetXScaleType($which_xst) + { + $this->xscale_type = $this->CheckOption($which_xst, 'linear, log', __FUNCTION__); + return TRUE; + } + + function SetYScaleType($which_yst) + { + $this->yscale_type = $this->CheckOption($which_yst, 'linear, log', __FUNCTION__); + return TRUE; + } + + function SetPrecisionX($which_prec) + { + $this->x_precision = $which_prec; + $this->SetXLabelType('data'); + return TRUE; + } + + function SetPrecisionY($which_prec) + { + $this->y_precision = $which_prec; + $this->SetYLabelType('data'); + return TRUE; + } + + function SetErrorBarLineWidth($which_seblw) + { + $this->error_bar_line_width = $which_seblw; + return TRUE; + } + + function SetLabelScalePosition($which_blp) + { + //0 to 1 + $this->label_scale_position = $which_blp; + return TRUE; + } + + function SetErrorBarSize($which_ebs) + { + //in pixels + $this->error_bar_size = $which_ebs; + return TRUE; + } + + /*! + * Can be one of: 'tee', 'line' + */ + function SetErrorBarShape($which_ebs) + { + $this->error_bar_shape = $this->CheckOption($which_ebs, 'tee, line', __FUNCTION__); + } + + /*! + * Sets point shape for each data set via an array. + * Shape can be one of: 'halfline', 'line', 'plus', 'cross', 'rect', 'circle', 'dot', + * 'diamond', 'triangle', 'trianglemid' + */ + function SetPointShapes($which_pt) + { + if (is_null($which_pt)) { + // Do nothing, use default value. + } else if (is_array($which_pt)) { + // Did we get an array with point shapes? + $this->point_shapes = $which_pt; + } else { + // Single value into array + $this->point_shapes = array($which_pt); + } + + foreach ($this->point_shapes as $shape) + { + // TODO, better check, per element rectification + $this->CheckOption($shape, + 'halfline, line, plus, cross, rect, circle, dot, diamond, triangle, trianglemid', + __FUNCTION__); + } + + // Make both point_shapes and point_sizes same size. + $ps = count($this->point_sizes); + $pt = count($this->point_shapes); + + if ($ps < $pt) { + array_pad_array($this->point_sizes, $pt); + } else if ($pt > $ps) { + array_pad_array($this->point_shapes, $ps); + } + return TRUE; + } + + /*! + * Sets the point size for point plots. + * \param ps int Size in pixels. + * \note Test this more extensively + */ + function SetPointSizes($which_ps) + { + if (is_null($which_ps)) { + // Do nothing, use default value. + } else if (is_array($which_ps)) { + // Did we get an array with point sizes? + $this->point_sizes = $which_ps; + } else { + // Single value into array + $this->point_sizes = array($which_ps); + } + + // Make both point_shapes and point_sizes same size. + $ps = count($this->point_sizes); + $pt = count($this->point_shapes); + + if ($ps < $pt) { + array_pad_array($this->point_sizes, $pt); + } else if ($pt > $ps) { + array_pad_array($this->point_shapes, $ps); + } + + // Fix odd point sizes for point shapes which need it + for ($i = 0; $i < $pt; $i++) { + if ($this->point_shapes[$i] == 'diamond' or $this->point_shapes[$i] == 'triangle') { + if ($this->point_sizes[$i] % 2 != 0) { + $this->point_sizes[$i]++; + } + } + } + return TRUE; + } + + + /*! + * Tells not to draw lines for missing Y data. Only works with 'lines' and 'squared' plots. + * \param bl bool + */ + function SetDrawBrokenLines($bl) + { + $this->draw_broken_lines = (bool)$bl; + } + + + /*! + * text-data: ('label', y1, y2, y3, ...) + * text-data-single: ('label', data), for some pie charts. + * data-data: ('label', x, y1, y2, y3, ...) + * data-data-error: ('label', x1, y1, e1+, e2-, y2, e2+, e2-, y3, e3+, e3-, ...) + */ + function SetDataType($which_dt) + { + //The next four lines are for past compatibility. + if ($which_dt == 'text-linear') { $which_dt = 'text-data'; }; + if ($which_dt == 'linear-linear') { $which_dt = 'data-data'; }; + if ($which_dt == 'linear-linear-error') { $which_dt = 'data-data-error'; }; + if ($which_dt == 'text-data-pie') { $which_dt = 'text-data-single'; } + + + $this->data_type = $this->CheckOption($which_dt, 'text-data, text-data-single, '. + 'data-data, data-data-error', __FUNCTION__); + return TRUE; + } + + /*! + * Copy the array passed as data values. We convert to numerical indexes, for its + * use for (or while) loops, which sometimes are faster. Performance improvements + * vary from 28% in DrawLines() to 49% in DrawArea() for plot drawing functions. + */ + function SetDataValues(&$which_dv) + { + unset ($this->data_limits_done); // Reset this for every new data_set + $this->num_data_rows = count($which_dv); + $this->total_records = 0; // Perform some useful calculations. + $this->records_per_group = 1; + for ($i = 0, $recs = 0; $i < $this->num_data_rows; $i++) { + // Copy + $this->data[$i] = array_values($which_dv[$i]); // convert to numerical indices. + + // Compute some values + $recs = count($this->data[$i]); + $this->total_records += $recs; + + if ($recs > $this->records_per_group) + $this->records_per_group = $recs; + + $this->num_recs[$i] = $recs; + } + } + + /*! + * Pad styles arrays for later use by plot drawing functions: + * This removes the need for $max_data_colors, etc. and $color_index = $color_index % $max_data_colors + * in DrawBars(), DrawLines(), etc. + */ + function PadArrays() + { + array_pad_array($this->line_widths, $this->records_per_group); + array_pad_array($this->line_styles, $this->records_per_group); + + array_pad_array($this->data_colors, $this->records_per_group); + array_pad_array($this->data_border_colors, $this->records_per_group); + array_pad_array($this->error_bar_colors, $this->records_per_group); + + $this->SetDataColors(); + $this->SetDataBorderColors(); + $this->SetErrorBarColors(); + + return TRUE; + } + + +////////////////////////////////////////////////////////// +/////////// DATA ANALYSIS, SCALING AND TRANSLATION +////////////////////////////////////////////////////////// + + /*! + * Analizes data and sets up internal maxima and minima + * Needed by: CalcMargins(), ... + * Text-Data is different than data-data graphs. For them what + * we have, instead of X values, is # of records equally spaced on data. + * text-data is passed in as $data[] = (title, y1, y2, y3, y4, ...) + * data-data is passed in as $data[] = (title, x, y1, y2, y3, y4, ...) + */ + function FindDataLimits() + { + // Set some default min and max values before running through the data + switch ($this->data_type) { + case 'text-data': + $minx = 0; + $maxx = $this->num_data_rows - 1 ; + $miny = $this->data[0][1]; + $maxy = $miny; + break; + default: //Everything else: data-data, etc, take first value + $minx = $this->data[0][1]; + $maxx = $minx; + $miny = $this->data[0][2]; + $maxy = $miny; + break; + } + + $mine = 0; // Maximum value for the -error bar (assume error bars always > 0) + $maxe = 0; // Maximum value for the +error bar (assume error bars always > 0) + $maxt = 0; // Maximum number of characters in text labels + + $minminy = $miny; + $maxmaxy = $maxy; + + if ($this->plot_type == 'stackedbars') { $maxmaxy = $minminy = 0; } + + // Process each row of data + for ($i=0; $i < $this->num_data_rows; $i++) { + $j=0; + // Extract maximum text label length + $val = @ strlen($this->data[$i][$j++]); + $maxt = ($val > $maxt) ? $val : $maxt; + + + if ($this->plot_type == 'stackedbars') { $maxy = $miny = 0; } + + switch ($this->data_type) { + case 'text-data': // Data is passed in as (title, y1, y2, y3, ...) + case 'text-data-single': // This one is for some pie charts + // $numrecs = @ count($this->data[$i]); + $miny = $maxy = (double)$this->data[$i][$j]; + for (; $j < $this->num_recs[$i]; $j++) { + $val = (double)$this->data[$i][$j]; + if ($this->plot_type == 'stackedbars') { + $maxy += abs($val); // only positive values for the moment + } else { + $maxy = ($val > $maxy) ? $val : $maxy; + $miny = ($val < $miny) ? $val : $miny; + } + } + break; + case 'data-data': // Data is passed in as (title, x, y, y2, y3, ...) + // X value: + $val = (double)$this->data[$i][$j++]; + $maxx = ($val > $maxx) ? $val : $maxx; + $minx = ($val < $minx) ? $val : $minx; + + $miny = $maxy = (double)$this->data[$i][$j]; + // $numrecs = @ count($this->data[$i]); + for (; $j < $this->num_recs[$i]; $j++) { + $val = (double)$this->data[$i][$j]; + $maxy = ($val > $maxy) ? $val : $maxy; + $miny = ($val < $miny) ? $val : $miny; + } + break; + case 'data-data-error': // Data is passed in as (title, x, y, err+, err-, y2, err2+, err2-,...) + // X value: + $val = (double)$this->data[$i][$j++]; + $maxx = ($val > $maxx) ? $val : $maxx; + $minx = ($val < $minx) ? $val : $minx; + + $miny = $maxy = (double)$this->data[$i][$j]; + // $numrecs = @ count($this->data[$i]); + for (; $j < $this->num_recs[$i];) { + // Y value: + $val = (double)$this->data[$i][$j++]; + $maxy = ($val > $maxy) ? $val : $maxy; + $miny = ($val < $miny) ? $val : $miny; + // Error +: + $val = (double)$this->data[$i][$j++]; + $maxe = ($val > $maxe) ? $val : $maxe; + // Error -: + $val = (double)$this->data[$i][$j++]; + $mine = ($val > $mine) ? $val : $mine; + } + $maxy = $maxy + $maxe; + $miny = $miny - $mine; // assume error bars are always > 0 + break; + default: + $this->PrintError("FindDataLimits(): Unknown data type '$data_type'."); + break; + } + $this->data[$i][MINY] = $miny; // This row's min Y, for DrawXDataLine() + $this->data[$i][MAXY] = $maxy; // This row's max Y, for DrawXDataLine() + + $minminy = ($miny < $minminy) ? $miny : $minminy; // global min + $maxmaxy = ($maxy > $maxmaxy) ? $maxy : $maxmaxy; // global max + } + + $this->min_x = $minx; + $this->max_x = $maxx; + $this->min_y = $minminy; + $this->max_y = $maxmaxy; + $this->max_t = $maxt; + + $this->data_limits_done = TRUE; + + return TRUE; + } + + + /*! + * Calculates image margins on the fly from title positions and sizes, + * and tick labels positions and sizes. + * + * FIXME: fix x_data_label_pos behaviour. Now we are leaving room for it AND x_tick_label_pos + * maybe it shouldn't be so... + * + * FIXME: y_data_label_pos is not yet used... + * + * TODO: add x_tick_label_width and y_tick_label_height and use them to calculate + * max_x_labels and max_y_labels, to be used by drawing functions to avoid overlapping. + */ + function CalcMargins() + { + // Temporary variables for label size calculation + $xlab = $this->FormatLabel('x', $this->max_x); + $ylab = $this->FormatLabel('y', $this->max_y); + + // dirty fix: + // max_t is the maximum data label length (from column 0 of each data row). + if ($this->max_t > strlen ($xlab)) + $xlab = sprintf ("%{$this->max_t}s","_"); + + //////// Calculate maximum X/Y axis label height and width: + + // TTFonts: + if ($this->use_ttf) { + // Maximum X axis label height + $size = $this->TTFBBoxSize($this->x_label_font['size'], $this->x_label_angle, + $this->x_label_font['font'], $xlab); + $this->x_tick_label_height = $size[1]; + + // Maximum Y axis label width + $size = $this->TTFBBoxSize($this->y_label_font['size'], $this->y_label_angle, + $this->y_label_font['font'], $ylab); + $this->y_tick_label_width = $size[0]; + } + // Fixed fonts: + else { + // Maximum X axis label height + if ($this->x_label_angle == 90) + $this->x_tick_label_height = strlen($xlab) * $this->x_label_font['width']; + else + $this->x_tick_label_height = $this->x_label_font['height']; + + // Maximum Y axis label width + $this->y_tick_label_width = strlen($ylab) * $this->y_label_font['width']; + } + + + ///////// Calculate margins: + + // Upper title, ticks and tick labels, and data labels: + $this->y_top_margin = $this->title_height + $this->safe_margin * 2; + + if ($this->x_title_pos == 'plotup' || $this->x_title_pos == 'both') + $this->y_top_margin += $this->x_title_height + $this->safe_margin; + + if ($this->x_tick_label_pos == 'plotup' || $this->x_tick_label_pos == 'both') + $this->y_top_margin += $this->x_tick_label_height; + + if ($this->x_tick_pos == 'plotup' || $this->x_tick_pos == 'both') + $this->y_top_margin += $this->x_tick_length * 2; + + if ($this->x_data_label_pos == 'plotup' || $this->x_data_label_pos == 'both') + $this->y_top_margin += $this->x_tick_label_height; + + // Lower title, ticks and tick labels, and data labels: + $this->y_bot_margin = $this->safe_margin * 2; + + if ($this->x_title_pos == 'plotdown' || $this->x_title_pos == 'both') + $this->y_bot_margin += $this->x_title_height; + + if ($this->x_tick_pos == 'plotdown' || $this->x_tick_pos == 'both') + $this->y_bot_margin += $this->x_tick_length * 2; + + if ($this->x_tick_pos == 'xaxis' && ($this->x_axis_position == '' || $this->x_axis_position == 0)) + $this->y_bot_margin += $this->x_tick_length * 2; + + if ($this->x_tick_label_pos == 'plotdown' || $this->x_tick_label_pos == 'both') + $this->y_bot_margin += $this->x_tick_label_height; + + if ($this->x_tick_label_pos == 'xaxis' && ($this->x_axis_position == '' || $this->x_axis_position == 0)) + $this->y_bot_margin += $this->x_tick_label_height; + + if ($this->x_data_label_pos == 'plotdown' || $this->x_data_label_pos == 'both') + $this->y_bot_margin += $this->x_tick_label_height; + + // Left title, ticks and tick labels: + $this->x_left_margin = $this->safe_margin * 2; + + if ($this->y_title_pos == 'plotleft' || $this->y_title_pos == 'both') + $this->x_left_margin += $this->y_title_width + $this->safe_margin; + + if ($this->y_tick_label_pos == 'plotleft' || $this->y_tick_label_pos == 'both') + $this->x_left_margin += $this->y_tick_label_width; + + if ($this->y_tick_pos == 'plotleft' || $this->y_tick_pos == 'both') + $this->x_left_margin += $this->y_tick_length * 2 ; + + // Right title, ticks and tick labels: + $this->x_right_margin = $this->safe_margin * 2; + + if ($this->y_title_pos == 'plotright' || $this->y_title_pos == 'both') + $this->x_right_margin += $this->y_title_width + $this->safe_margin; + + if ($this->y_tick_label_pos == 'plotright' || $this->y_tick_label_pos == 'both') + $this->x_right_margin += $this->y_tick_label_width; + + if ($this->y_tick_pos == 'plotright' || $this->y_tick_pos == 'both') + $this->x_right_margin += $this->y_tick_length * 2; + + + $this->x_tot_margin = $this->x_left_margin + $this->x_right_margin; + $this->y_tot_margin = $this->y_top_margin + $this->y_bot_margin; + + return; + } + + + /*! + * Set the margins in pixels (left, right, top, bottom) + */ + function SetMarginsPixels($which_lm, $which_rm, $which_tm, $which_bm) + { + + $this->x_left_margin = $which_lm; + $this->x_right_margin = $which_rm; + $this->x_tot_margin = $which_lm + $which_rm; + + $this->y_top_margin = $which_tm; + $this->y_bot_margin = $which_bm; + $this->y_tot_margin = $which_tm + $which_bm; + + $this->SetPlotAreaPixels(); + + return; + } + + + /*! + * Sets the limits for the plot area. If no arguments are supplied, uses + * values calculated from CalcMargins(); + * Like in GD, (0,0) is upper left + * + * This resets the scale if SetPlotAreaWorld() was already called + */ + function SetPlotAreaPixels($x1=NULL, $y1=NULL, $x2=NULL, $y2=NULL) + { + if ($x2 && $y2) { + $this->plot_area = array($x1, $y1, $x2, $y2); + } else { + if (! isset($this->x_tot_margin)) + $this->CalcMargins(); + + $this->plot_area = array($this->x_left_margin, $this->y_top_margin, + $this->image_width - $this->x_right_margin, + $this->image_height - $this->y_bot_margin); + } + $this->plot_area_width = $this->plot_area[2] - $this->plot_area[0]; + $this->plot_area_height = $this->plot_area[3] - $this->plot_area[1]; + + // Reset the scale with the new plot area. + if (isset($this->plot_max_x)) + $this->CalcTranslation(); + + return TRUE; + + } + + + /*! + * Sets minimum and maximum x and y values in the plot using FindDataLimits() + * or from the supplied parameters, if any. + * + * This resets the scale if SetPlotAreaPixels() was already called + */ + function SetPlotAreaWorld($xmin=NULL, $ymin=NULL, $xmax=NULL, $ymax=NULL) + { + if (! isset($this->data_limits_done)) { // For automatic setting of data we need data limits + $this->FindDataLimits() ; + } + + if ($xmin === NULL || $xmin === '') { + if ($this->data_type == 'text-data') // Valid for data without X values only. + $xmin = 0; + else + $xmin = $this->min_x; + } + if ($xmax === NULL || $xmax === '') { + if ($this->data_type == 'text-data') // Valid for data without X values only. + $xmax = $this->max_x + 1; + else + $xmax = $this->max_x; + } + + // Leave room above and below the highest and lowest data points. + + if ($ymin === NULL || $ymin === '') { + if ($this->min_y < 0) + $ymin = ceil($this->min_y * 1.1); + else + $ymin = floor($this->min_y * 0.9); + } + if ($ymax === NULL || $ymax === '') { + if ($this->max_y < 0) + $ymax = floor($this->max_y * 0.9); + else + $ymax = ceil($this->max_y * 1.1); + } + + // Error checking + + if ($ymin == $ymax) // Minimum height + $ymax += 1; + + if ($this->yscale_type == 'log') { + if ($ymin <= 0) { + $ymin = 1; + } + if ($ymax <= 0) { + $this->PrintError('SetPlotAreaWorld(): Log plots need data greater than 0'); + return FALSE; + } + } + + if ($ymax <= $ymin) { + $this->DrawError('SetPlotAreaWorld(): Error in data - max not greater than min'); + return FALSE; + } + + + // Reset (if it was already set) the scale with the new maxs and mins + + $this->plot_min_x = $xmin; + $this->plot_max_x = $xmax; + $this->plot_min_y = $ymin; + $this->plot_max_y = $ymax; + + if (isset($this->plot_area_width)) { + $this->CalcTranslation(); + } + + return TRUE; + } //function SetPlotAreaWorld + + + /*! + * For bar plots, which have equally spaced x variables. + */ + function CalcBarWidths() + { + $group_width = ($this->plot_area[2] - $this->plot_area[0]) / + $this->num_data_rows * $this->group_frac_width; + if ($this->plot_type == 'bars') { + $this->record_bar_width = $group_width / $this->records_per_group; + } else if ($this->plot_type == 'stackedbars') { + $this->record_bar_width = $group_width; + } + $this->data_group_space = $group_width / 2; + return TRUE; + } + + /*! + * Calculates scaling stuff... + */ + function CalcTranslation() + { + if ($this->plot_max_x - $this->plot_min_x == 0) { // Check for div by 0 + $this->xscale = 0; + } else { + if ($this->xscale_type == 'log') { + $this->xscale = ($this->plot_area_width)/(log10($this->plot_max_x) - log10($this->plot_min_x)); + } else { + $this->xscale = ($this->plot_area_width)/($this->plot_max_x - $this->plot_min_x); + } + } + + if ($this->plot_max_y - $this->plot_min_y == 0) { // Check for div by 0 + $this->yscale = 0; + } else { + if ($this->yscale_type == 'log') { + $this->yscale = ($this->plot_area_height)/(log10($this->plot_max_y) - log10($this->plot_min_y)); + } else { + $this->yscale = ($this->plot_area_height)/($this->plot_max_y - $this->plot_min_y); + } + } + // GD defines x = 0 at left and y = 0 at TOP so -/+ respectively + if ($this->xscale_type == 'log') { + $this->plot_origin_x = $this->plot_area[0] - ($this->xscale * log10($this->plot_min_x) ); + } else { + $this->plot_origin_x = $this->plot_area[0] - ($this->xscale * $this->plot_min_x); + } + if ($this->yscale_type == 'log') { + $this->plot_origin_y = $this->plot_area[3] + ($this->yscale * log10($this->plot_min_y)); + } else { + $this->plot_origin_y = $this->plot_area[3] + ($this->yscale * $this->plot_min_y); + } + + $this->scale_is_set = TRUE; + + /************** FIXME?? *************/ + // There should be a better place for this. + + // User provided y axis position? + if ($this->y_axis_position != '') { + // Make sure we draw our axis inside the plot + $this->y_axis_position = ($this->y_axis_position < $this->plot_min_x) + ? $this->plot_min_x : $this->y_axis_position; + $this->y_axis_position = ($this->y_axis_position > $this->plot_max_x) + ? $this->plot_max_x : $this->y_axis_position; + $this->y_axis_x_pixels = $this->xtr($this->y_axis_position); + } else { + // Default to left axis + $this->y_axis_x_pixels = $this->xtr($this->plot_min_x); + } + // User provided x axis position? + if ($this->x_axis_position != '') { + // Make sure we draw our axis inside the plot + $this->x_axis_position = ($this->x_axis_position < $this->plot_min_y) + ? $this->plot_min_y : $this->x_axis_position; + $this->x_axis_position = ($this->x_axis_position > $this->plot_max_y) + ? $this->plot_max_y : $this->x_axis_position; + $this->x_axis_y_pixels = $this->ytr($this->x_axis_position); + } else { + if ($this->yscale_type == 'log') + $this->x_axis_y_pixels = $this->ytr(1); + else + // Default to axis at 0 or plot_min_y (should be 0 anyway, from SetPlotAreaWorld()) + $this->x_axis_y_pixels = ($this->plot_min_y <= 0) && (0 <= $this->plot_max_y) + ? $this->ytr(0) : $this->ytr($this->plot_min_y); + } + + } // function CalcTranslation() + + + /*! + * Translate X world coordinate into pixel coordinate + * Needs values calculated by _CalcTranslation() + */ + function xtr($x_world) + { + //$x_pixels = $this->x_left_margin + ($this->image_width - $this->x_tot_margin)* + // (($x_world - $this->plot_min_x) / ($this->plot_max_x - $this->plot_min_x)) ; + //which with a little bit of math reduces to ... + if ($this->xscale_type == 'log') { + $x_pixels = $this->plot_origin_x + log10($x_world) * $this->xscale ; + } else { + $x_pixels = $this->plot_origin_x + $x_world * $this->xscale ; + } + return round($x_pixels); + } + + + /*! + * Translate Y world coordinate into pixel coordinate. + * Needs values calculated by _CalcTranslation() + */ + function ytr($y_world) + { + if ($this->yscale_type == 'log') { + //minus because GD defines y = 0 at top. doh! + $y_pixels = $this->plot_origin_y - log10($y_world) * $this->yscale ; + } else { + $y_pixels = $this->plot_origin_y - $y_world * $this->yscale ; + } + return round($y_pixels); + } + + /*! + * Formats a tick or data label. + * + * \note Time formatting suggested by Marlin Viss + */ + function FormatLabel($which_pos, $which_lab) + { + switch ($which_pos) { + case 'x': + case 'plotx': + switch ($this->x_label_type) { + case 'title': + $lab = @ $this->data[$which_lab][0]; + break; + case 'data': +// LDR +// if (is_numeric($which_lab)) $lab = number_format($which_lab, $this->x_precision, '.', ',').$this->data_units_text; +// else $lab = $which_lab; + $lab = number_format($which_lab, $this->x_precision, '.', ',').$this->data_units_text; + break; + case 'time': + $lab = strftime($this->x_time_format, $which_lab); + break; + default: + // Unchanged from whatever format it is passed in + $lab = $which_lab; + break; + } + break; + case 'y': + case 'ploty': + switch ($this->y_label_type) { + case 'data': + $lab = number_format($which_lab, $this->y_precision, '.', ',').$this->data_units_text; + break; + case 'time': + $lab = strftime($this->y_time_format, $which_lab); + break; + default: + // Unchanged from whatever format it is passed in + $lab = $which_lab; + break; + } + break; + default: + $this->PrintError("FormatLabel(): Unknown label type $which_type"); + return NULL; + } + + return $lab; + } //function FormatLabel + + + +///////////////////////////////////////////// +/////////////// TICKS +///////////////////////////////////////////// + + /*! + * Use either this or SetNumXTicks() to set where to place x tick marks + */ + function SetXTickIncrement($which_ti=NULL) + { + if ($which_ti) { + $this->x_tick_inc = $which_ti; //world coordinates + } else { + if (! isset($this->data_limits_done)) { + $this->FindDataLimits(); //Get maxima and minima for scaling + } + $this->x_tick_inc = ($this->plot_max_x - $this->plot_min_x )/10; + } + $this->num_x_ticks = ''; //either use num_y_ticks or y_tick_inc, not both + return TRUE; + } + + /*! + * Use either this or SetNumYTicks() to set where to place y tick marks + */ + function SetYTickIncrement($which_ti=NULL) + { + if ($which_ti) { + $this->y_tick_inc = $which_ti; //world coordinates + } else { + if (! isset($this->data_limits_done)) { + $this->FindDataLimits(); //Get maxima and minima for scaling + } + if (! isset($this->plot_max_y)) + $this->SetPlotAreaWorld(); + + $this->y_tick_inc = ($this->plot_max_y - $this->plot_min_y )/10; + } + $this->num_y_ticks = ''; //either use num_y_ticks or y_tick_inc, not both + return TRUE; + } + + + function SetNumXTicks($which_nt) + { + $this->num_x_ticks = $which_nt; + $this->x_tick_inc = ''; //either use num_x_ticks or x_tick_inc, not both + return TRUE; + } + + function SetNumYTicks($which_nt) + { + $this->num_y_ticks = $which_nt; + $this->y_tick_inc = ''; //either use num_y_ticks or y_tick_inc, not both + return TRUE; + } + + /*! + * + */ + function SetYTickPos($which_tp) + { + $this->y_tick_pos = $this->CheckOption($which_tp, 'plotleft, plotright, both, yaxis, none', __FUNCTION__); + return TRUE; + } + /*! + * + */ + function SetXTickPos($which_tp) + { + $this->x_tick_pos = $this->CheckOption($which_tp, 'plotdown, plotup, both, xaxis, none', __FUNCTION__); + return TRUE; + } + + /*! + * \param skip bool + */ + function SetSkipTopTick($skip) + { + $this->skip_top_tick = (bool)$skip; + return TRUE; + } + + /*! + * \param skip bool + */ + function SetSkipBottomTick($skip) + { + $this->skip_bottom_tick = (bool)$skip; + return TRUE; + } + + /*! + * \param skip bool + */ + function SetSkipLeftTick($skip) + { + $this->skip_left_tick = (bool)$skip; + return TRUE; + } + + /*! + * \param skip bool + */ + function SetSkipRightTick($skip) + { + $this->skip_right_tick = (bool)$skip; + return TRUE; + } + + function SetXTickLength($which_xln) + { + $this->x_tick_length = $which_xln; + return TRUE; + } + + function SetYTickLength($which_yln) + { + $this->y_tick_length = $which_yln; + return TRUE; + } + + function SetXTickCrossing($which_xc) + { + $this->x_tick_cross = $which_xc; + return TRUE; + } + + function SetYTickCrossing($which_yc) + { + $this->y_tick_cross = $which_yc; + return TRUE; + } + + +///////////////////////////////////////////// +//////////////////// GENERIC DRAWING +///////////////////////////////////////////// + + /*! + * Fills the background. + */ + function DrawBackground() + { + // Don't draw this twice if drawing two plots on one image + if (! $this->background_done) { + if (isset($this->bgimg)) { // If bgimg is defined, use it + $this->tile_img($this->bgimg, 0, 0, $this->image_width, $this->image_height, $this->bgmode); + } else { // Else use solid color + ImageFilledRectangle($this->img, 0, 0, $this->image_width, $this->image_height, + $this->ndx_bg_color); + } + $this->background_done = TRUE; + return TRUE; // Done + } + return FALSE; // Nothing done + } + + + /*! + * Fills the plot area background. + */ + function DrawPlotAreaBackground() + { + if (isset($this->plotbgimg)) { + $this->tile_img($this->plotbgimg, $this->plot_area[0], $this->plot_area[1], + $this->plot_area_width, $this->plot_area_height, $this->plotbgmode); + } + else { + if ($this->draw_plot_area_background) { + ImageFilledRectangle($this->img, $this->plot_area[0], $this->plot_area[1], + $this->plot_area[2], $this->plot_area[3], $this->ndx_plot_bg_color); + } + } + + return TRUE; + } + + + /*! + * Tiles an image at some given coordinates. + * + * \param $file string Filename of the picture to be used as tile. + * \param $xorig int X coordinate of the plot where the tile is to begin. + * \param $yorig int Y coordinate of the plot where the tile is to begin. + * \param $width int Width of the area to be tiled. + * \param $height int Height of the area to be tiled. + * \param $mode string One of 'centeredtile', 'tile', 'scale'. + */ + function tile_img($file, $xorig, $yorig, $width, $height, $mode) + { + $size = getimagesize($file); + $input_format = $size[2]; + + switch($input_format) { + case 1: + $im = @ imagecreatefromGIF ($file); + if (! $im) { + $this->PrintError("tile_img:() Unable to open $file as a GIF."); + return FALSE; + } + break; + case 2: + $im = @ imagecreatefromJPEG ($file); + if (! $im) { + $this->PrintError("tile_img(): Unable to open $file as a JPG."); + return FALSE; + } + break; + case 3: + $im = @ imagecreatefromPNG ($file); + if (! $im) { + $this->PrintError("tile_img(): Unable to open $file as a PNG."); + return FALSE; + } + break; + default: + $this->PrintError('tile_img(): Please select a gif, jpg, or png image.'); + return FALSE; + break; + } + + + if ($mode == 'scale') { + imagecopyresized($this->img, $im, $xorig, $yorig, 0, 0, $width, $height, $size[0],$size[1]); + return TRUE; + } else if ($mode == 'centeredtile') { + $x0 = - floor($size[0]/2); // Make the tile look better + $y0 = - floor($size[1]/2); + } else if ($mode = 'tile') { + $x0 = 0; + $y0 = 0; + } + + // Actually draw the tile + + // But first on a temporal image. + $tmp = ImageCreate($width, $height); + if (! $tmp) + $this->PrintError('tile_img(): Could not create image resource.'); + + for ($x = $x0; $x < $width; $x += $size[0]) + for ($y = $y0; $y < $height; $y += $size[1]) + imagecopy($tmp, $im, $x, $y, 0, 0, $size[0], $size[1]); + + // Copy the temporal image onto the final one. + imagecopy($this->img, $tmp, $xorig, $yorig, 0,0, $width, $height); + + // Free resources + imagedestroy($tmp); + imagedestroy($im); + + return TRUE; + } // function tile_img + + + /*! + * Draws a border around the final image. + */ + function DrawImageBorder() + { + switch ($this->image_border_type) { + case 'raised': + ImageLine($this->img, 0, 0, $this->image_width-1, 0, $this->ndx_i_border); + ImageLine($this->img, 1, 1, $this->image_width-2, 1, $this->ndx_i_border); + ImageLine($this->img, 0, 0, 0, $this->image_height-1, $this->ndx_i_border); + ImageLine($this->img, 1, 1, 1, $this->image_height-2, $this->ndx_i_border); + ImageLine($this->img, $this->image_width-1, 0, $this->image_width-1, + $this->image_height-1, $this->ndx_i_border_dark); + ImageLine($this->img, 0, $this->image_height-1, $this->image_width-1, + $this->image_height-1, $this->ndx_i_border_dark); + ImageLine($this->img, $this->image_width-2, 1, $this->image_width-2, + $this->image_height-2, $this->ndx_i_border_dark); + ImageLine($this->img, 1, $this->image_height-2, $this->image_width-2, + $this->image_height-2, $this->ndx_i_border_dark); + break; + case 'plain': + ImageLine($this->img, 0, 0, $this->image_width, 0, $this->ndx_i_border_dark); + ImageLine($this->img, $this->image_width-1, 0, $this->image_width-1, + $this->image_height, $this->ndx_i_border_dark); + ImageLine($this->img, $this->image_width-1, $this->image_height-1, 0, $this->image_height-1, + $this->ndx_i_border_dark); + ImageLine($this->img, 0, 0, 0, $this->image_height, $this->ndx_i_border_dark); + break; + case 'none': + break; + default: + $this->DrawError("DrawImageBorder(): unknown image_border_type: '$this->image_border_type'"); + return FALSE; + } + return TRUE; + } + + + /*! + * Adds the title to the graph. + */ + function DrawTitle() + { + // Center of the plot area + //$xpos = ($this->plot_area[0] + $this->plot_area_width )/ 2; + + // Center of the image: + $xpos = $this->image_width / 2; + + // Place it at almost at the top + $ypos = $this->safe_margin; + + $this->DrawText($this->title_font, $this->title_angle, $xpos, $ypos, + $this->ndx_title_color, $this->title_txt, 'center', 'bottom'); + + return TRUE; + + } + + + /*! + * Draws the X-Axis Title + */ + function DrawXTitle() + { + if ($this->x_title_pos == 'none') + return; + + // Center of the plot + $xpos = ($this->plot_area[2] + $this->plot_area[0]) / 2; + + // Upper title + if ($this->x_title_pos == 'plotup' || $this->x_title_pos == 'both') { + $ypos = $this->safe_margin + $this->title_height + $this->safe_margin; + $this->DrawText($this->x_title_font, $this->x_title_angle, + $xpos, $ypos, $this->ndx_title_color, $this->x_title_txt, 'center'); + } + // Lower title + if ($this->x_title_pos == 'plotdown' || $this->x_title_pos == 'both') { + $ypos = $this->image_height - $this->x_title_height - $this->safe_margin; + $this->DrawText($this->x_title_font, $this->x_title_angle, + $xpos, $ypos, $this->ndx_title_color, $this->x_title_txt, 'center'); + } + return TRUE; + } + + /*! + * Draws the Y-Axis Title + */ + function DrawYTitle() + { + if ($this->y_title_pos == 'none') + return; + + // Center the title vertically to the plot + $ypos = ($this->plot_area[3] + $this->plot_area[1]) / 2; + + if ($this->y_title_pos == 'plotleft' || $this->y_title_pos == 'both') { + $xpos = $this->safe_margin; + $this->DrawText($this->y_title_font, 90, $xpos, $ypos, $this->ndx_title_color, + $this->y_title_txt, 'left', 'center'); + } + if ($this->y_title_pos == 'plotright' || $this->y_title_pos == 'both') { + $xpos = $this->image_width - $this->safe_margin - $this->y_title_width - $this->safe_margin; + $this->DrawText($this->y_title_font, 90, $xpos, $ypos, $this->ndx_title_color, + $this->y_title_txt, 'left', 'center'); + } + + return TRUE; + } + + + /* + * \note Horizontal grid lines overwrite horizontal axis with y=0, so call this first, then DrawXAxis() + */ + function DrawYAxis() + { + // Draw ticks, labels and grid, if any + $this->DrawYTicks(); + + // Draw Y axis at X = y_axis_x_pixels + ImageLine($this->img, $this->y_axis_x_pixels, $this->plot_area[1], + $this->y_axis_x_pixels, $this->plot_area[3], $this->ndx_grid_color); + + return TRUE; + } + + /* + * + */ + function DrawXAxis() + { + // Draw ticks, labels and grid + $this->DrawXTicks(); + + /* This tick and label tend to overlap with regular Y Axis labels, + * as Mike Pullen pointed out. + * + //Draw Tick and Label for X axis + if (! $this->skip_bottom_tick) { + $ylab =$this->FormatLabel('y', $this->x_axis_position); + $this->DrawYTick($ylab, $this->x_axis_y_pixels); + } + */ + //Draw X Axis at Y = x_axis_y_pixels + ImageLine($this->img, $this->plot_area[0]+1, $this->x_axis_y_pixels, + $this->plot_area[2]-1, $this->x_axis_y_pixels, $this->ndx_grid_color); + + return TRUE; + } + + /*! + * Draw Just one Tick, called from DrawYTicks() and DrawXAxis() + * TODO? Move this inside DrawYTicks() and Modify DrawXAxis() ? + */ + function DrawYTick($which_ylab, $which_ypix) + { + // Ticks on Y axis + if ($this->y_tick_pos == 'yaxis') { + ImageLine($this->img, $this->y_axis_x_pixels - $this->y_tick_length, $which_ypix, + $this->y_axis_x_pixels + $this->y_tick_cross, $which_ypix, + $this->ndx_tick_color); + } + + // Labels on Y axis + if ($this->y_tick_label_pos == 'yaxis') { + $this->DrawText($this->y_label_font, $this->y_label_angle, + $this->y_axis_x_pixels - $this->y_tick_length * 1.5, $which_ypix, + $this->ndx_text_color, $which_ylab, 'right', 'center'); + } + + // Ticks to the left of the Plot Area + if (($this->y_tick_pos == 'plotleft') || ($this->y_tick_pos == 'both') ) { + ImageLine($this->img, $this->plot_area[0] - $this->y_tick_length, + $which_ypix, $this->plot_area[0] + $this->y_tick_cross, + $which_ypix, $this->ndx_tick_color); + } + + // Ticks to the right of the Plot Area + if (($this->y_tick_pos == 'plotright') || ($this->y_tick_pos == 'both') ) { + ImageLine($this->img, ($this->plot_area[2] + $this->y_tick_length), + $which_ypix, $this->plot_area[2] - $this->y_tick_cross, + $which_ypix, $this->ndx_tick_color); + } + + // Labels to the left of the plot area + if ($this->y_tick_label_pos == 'plotleft' || $this->y_tick_label_pos == 'both') { + $this->DrawText($this->y_label_font, $this->y_label_angle, + $this->plot_area[0] - $this->y_tick_length * 1.5, $which_ypix, + $this->ndx_text_color, $which_ylab, 'right', 'center'); + } + // Labels to the right of the plot area + if ($this->y_tick_label_pos == 'plotright' || $this->y_tick_label_pos == 'both') { + $this->DrawText($this->y_label_font, $this->y_label_angle, + $this->plot_area[2] + $this->y_tick_length * 1.5, $which_ypix, + $this->ndx_text_color, $which_ylab, 'left', 'center'); + } + } // Function DrawYTick() + + + /*! + * Draws Grid, Ticks and Tick Labels along Y-Axis + * Ticks and ticklabels can be left of plot only, right of plot only, + * both on the left and right of plot, or crossing a user defined Y-axis + * TODO: marks at whole numbers (-10, 10, 20, 30 ...) no matter where the plot begins (-3, 4.7, etc.) + */ + function DrawYTicks() + { + // Sets the line style for IMG_COLOR_STYLED lines (grid) + if ($this->dashed_grid) { + $this->SetDashedStyle($this->ndx_light_grid_color); + $style = IMG_COLOR_STYLED; + } else { + $style = $this->ndx_light_grid_color; + } + + // maxy is always > miny so delta_y is always positive + if ($this->y_tick_inc) { + $delta_y = $this->y_tick_inc; + } elseif ($this->num_y_ticks) { + $delta_y = ($this->plot_max_y - $this->plot_min_y) / $this->num_y_ticks; + } else { + $delta_y = ($this->plot_max_y - $this->plot_min_y) / 10 ; + } + + // NOTE: When working with floats, because of approximations when adding $delta_y, + // $y_tmp never equals $y_end at the for loop, so one spurious line would get drawn where + // not for the substraction to $y_end here. + $y_tmp = (double)$this->plot_min_y; + $y_end = (double)$this->plot_max_y - ($delta_y/2); + + if ($this->skip_bottom_tick) + $y_tmp += $delta_y; + + if ($this->skip_top_tick) + $y_end -= $delta_y; + + for (;$y_tmp < $y_end; $y_tmp += $delta_y) { + $ylab = $this->FormatLabel('y', $y_tmp); + $y_pixels = $this->ytr($y_tmp); + + // Horizontal grid line + if ($this->draw_y_grid) { + ImageLine($this->img, $this->plot_area[0]+1, $y_pixels, $this->plot_area[2]-1, $y_pixels, $style); + } + + // Draw ticks + $this->DrawYTick($ylab, $y_pixels); + } + return TRUE; + } // function DrawYTicks + + + /*! + * Draws Grid, Ticks and Tick Labels along X-Axis + * Ticks and tick labels can be down of plot only, up of plot only, + * both on up and down of plot, or crossing a user defined X-axis + * + * \note Original vertical code submitted by Marlin Viss + */ + function DrawXTicks() + { + // Sets the line style for IMG_COLOR_STYLED lines (grid) + if ($this->dashed_grid) { + $this->SetDashedStyle($this->ndx_light_grid_color); + $style = IMG_COLOR_STYLED; + } else { + $style = $this->ndx_light_grid_color; + } + + // Calculate x increment between ticks + if ($this->x_tick_inc) { + $delta_x = $this->x_tick_inc; + } elseif ($this->num_x_ticks) { + $delta_x = ($this->plot_max_x - $this->plot_min_x) / $this->num_x_ticks; + } else { + $delta_x =($this->plot_max_x - $this->plot_min_x) / 10 ; + } + + // NOTE: When working with decimals, because of approximations when adding $delta_x, + // $x_tmp never equals $x_end at the for loop, so one spurious line would get drawn where + // not for the substraction to $x_end here. + $x_tmp = (double)$this->plot_min_x; + $x_end = (double)$this->plot_max_x - ($delta_x/2); + + // Should the leftmost tick be drawn? + if ($this->skip_left_tick) + $x_tmp += $delta_x; + + // And the rightmost? + if (! $this->skip_right_tick) + $x_end += $delta_x; + + for (;$x_tmp < $x_end; $x_tmp += $delta_x) { + $xlab = $this->FormatLabel('x', $x_tmp); + $x_pixels = $this->xtr($x_tmp); + + // Vertical grid lines + if ($this->draw_x_grid) { + ImageLine($this->img, $x_pixels, $this->plot_area[1], $x_pixels, $this->plot_area[3], $style); + } + + // Tick on X Axis + if ($this->x_tick_pos == 'xaxis') { + + ImageLine($this->img, $x_pixels, $this->x_axis_y_pixels - $this->x_tick_cross, + $x_pixels, $this->x_axis_y_pixels + $this->x_tick_length, $this->ndx_tick_color); + } + + // Label on X axis + if ($this->x_tick_label_pos == 'xaxis') { + $this->DrawText($this->x_label_font, $this->x_label_angle, $x_pixels, + $this->x_axis_y_pixels + $this->x_tick_length*1.5, $this->ndx_text_color, + $xlab, 'center', 'bottom'); + } + + // Top of the plot area tick + if ($this->x_tick_pos == 'plotup' || $this->x_tick_pos == 'both') { + ImageLine($this->img, $x_pixels, $this->plot_area[1] - $this->x_tick_length, + $x_pixels, $this->plot_area[1] + $this->x_tick_cross, $this->ndx_tick_color); + } + // Bottom of the plot area tick + if ($this->x_tick_pos == 'plotdown' || $this->x_tick_pos == 'both') { + ImageLine($this->img, $x_pixels, $this->plot_area[3] + $this->x_tick_length, + $x_pixels, $this->plot_area[3] - $this->x_tick_cross, $this->ndx_tick_color); + } + + // Top of the plot area tick label + if ($this->x_tick_label_pos == 'plotup' || $this->x_tick_label_pos == 'both') { + $this->DrawText($this->x_label_font, $this->x_label_angle, $x_pixels, + $this->plot_area[1] - $this->x_tick_length*1.5, $this->ndx_text_color, + $xlab, 'center', 'top'); + } + + // Bottom of the plot area tick label + if ($this->x_tick_label_pos == 'plotdown' || $this->x_tick_label_pos == 'both') { + $this->DrawText($this->x_label_font, $this->x_label_angle, $x_pixels, + $this->plot_area[3] + $this->x_tick_length*1.5, $this->ndx_text_color, + $xlab, 'center', 'bottom'); + } + } + return; + } // function DrawXTicks + + + /*! + * + */ + function DrawPlotBorder() + { + switch ($this->plot_border_type) { + case 'left': // for past compatibility + case 'plotleft': + ImageLine($this->img, $this->plot_area[0], $this->ytr($this->plot_min_y), + $this->plot_area[0], $this->ytr($this->plot_max_y), $this->ndx_grid_color); + break; + case 'right': + case 'plotright': + ImageLine($this->img, $this->plot_area[2], $this->ytr($this->plot_min_y), + $this->plot_area[2], $this->ytr($this->plot_max_y), $this->ndx_grid_color); + break; + case 'both': + case 'sides': + ImageLine($this->img, $this->plot_area[0], $this->ytr($this->plot_min_y), + $this->plot_area[0], $this->ytr($this->plot_max_y), $this->ndx_grid_color); + ImageLine($this->img, $this->plot_area[2], $this->ytr($this->plot_min_y), + $this->plot_area[2], $this->ytr($this->plot_max_y), $this->ndx_grid_color); + break; + case 'none': + //Draw No Border + break; + case 'full': + default: + ImageRectangle($this->img, $this->plot_area[0], $this->ytr($this->plot_min_y), + $this->plot_area[2], $this->ytr($this->plot_max_y), $this->ndx_grid_color); + break; + } + return TRUE; + } + + + /*! + * Draws the data label associated with a point in the plot. + * This is different from x_labels drawn by DrawXTicks() and care + * should be taken not to draw both, as they'd probably overlap. + * Calling of this function in DrawLines(), etc is decided after x_data_label_pos value. + * Leave the last parameter out, to avoid the drawing of vertical lines, no matter + * what the setting is (for plots that need it, like DrawSquared()) + */ + function DrawXDataLabel($xlab, $xpos, $row=FALSE) + { + // FIXME!! not working... + if (($this->_x_label_cnt++ % $this->x_label_inc) != 0) + return; + + $xlab = $this->FormatLabel('x', $xlab); + + // Labels below the plot area + if ($this->x_data_label_pos == 'plotdown' || $this->x_data_label_pos == 'both') + $this->DrawText($this->x_label_font, $this->x_label_angle, $xpos, + $this->plot_area[3] + $this->x_tick_length, + $this->ndx_text_color, $xlab, 'center', 'bottom'); + + // Labels above the plot area + if ($this->x_data_label_pos == 'plotup' || $this->x_data_label_pos == 'both') + $this->DrawText($this->x_label_font, $this->x_label_angle, $xpos, + $this->plot_area[1] - $this->x_tick_length , + $this->ndx_text_color, $xlab, 'center', 'top'); + + if ($row && $this->draw_x_data_label_lines) + $this->DrawXDataLine($xpos, $row); + } + + /*! + * Draws Vertical lines from data points up and down. + * Which lines are drawn depends on the value of x_data_label_pos, + * and whether this is at all done or not, on draw_x_data_label_lines + * + * \param xpos int position in pixels of the line. + * \param row int index of the data row being drawn. + */ + function DrawXDataLine($xpos, $row) + { + // Sets the line style for IMG_COLOR_STYLED lines (grid) + if($this->dashed_grid) { + $this->SetDashedStyle($this->ndx_light_grid_color); + $style = IMG_COLOR_STYLED; + } else { + $style = $this->ndx_light_grid_color; + } + + // Lines from the bottom up + if ($this->x_data_label_pos == 'both') { + ImageLine($this->img, $xpos, $this->plot_area[3], $xpos, $this->plot_area[1], $style); + } + // Lines coming from the bottom of the plot + else if ($this->x_data_label_pos == 'plotdown') { + // See FindDataLimits() to see why 'MAXY' index. + $ypos = $this->ytr($this->data[$row][MAXY]); + ImageLine($this->img, $xpos, $ypos, $xpos, $this->plot_area[3], $style); + } + // Lines coming from the top of the plot + else if ($this->x_data_label_pos == 'plotup') { + // See FindDataLimits() to see why 'MINY' index. + $ypos = $this->ytr($this->data[$row][MINY]); + ImageLine($this->img, $xpos, $this->plot_area[1], $xpos, $ypos, $style); + } + } + +/* + function DrawPlotLabel($xlab, $xpos, $ypos) + { + $this->DrawText($this->x_label_font, $this->x_label_angle, $xpos, $this +*/ + + /*! + * Draws the graph legend + * + * \note Base code submitted by Marlin Viss + * FIXME: maximum label length should be calculated more accurately for TT fonts + * Performing a BBox calculation for every legend element, for example. + */ + function DrawLegend($which_x1, $which_y1, $which_boxtype) + { + // Find maximum legend label length + $max_len = 0; + foreach ($this->legend as $leg) { + $len = strlen($leg); + $max_len = ($len > $max_len) ? $len : $max_len; + } + $max_len += 5; // Leave room for the boxes and margins + + /////// Calculate legend labels sizes: FIXME - dirty hack - FIXME + // TTF: + if ($this->use_ttf) { + $size = $this->TTFBBoxSize($this->legend_font['size'], 0, + $this->legend_font['font'], '_'); + $char_w = $size[0]; + + $size = $this->TTFBBoxSize($this->legend_font['size'], 0, + $this->legend_font['font'], '|'); + $char_h = $size[1]; + } + // Fixed fonts: + else { + $char_w = $this->legend_font['width']; + $char_h = $this->legend_font['height']; + } + + $v_margin = $char_h/2; // Between vertical borders and labels + $dot_height = $char_h + $this->line_spacing; // Height of the small colored boxes + $width = $char_w * $max_len; + + //////// Calculate box size + // upper Left + if ( (! $which_x1) || (! $which_y1) ) { + $box_start_x = $this->plot_area[2] - $width; + $box_start_y = $this->plot_area[1] + 5; + } else { + $box_start_x = $which_x1; + $box_start_y = $which_y1; + } + + // Lower right corner + $box_end_y = $box_start_y + $dot_height*(count($this->legend)) + 2*$v_margin; + $box_end_x = $box_start_x + $width - 5; + + + // Draw outer box + ImageFilledRectangle($this->img, $box_start_x, $box_start_y, $box_end_x, $box_end_y, $this->ndx_bg_color); + ImageRectangle($this->img, $box_start_x, $box_start_y, $box_end_x, $box_end_y, $this->ndx_grid_color); + + $color_index = 0; + $max_color_index = count($this->ndx_data_colors) - 1; + + $dot_left_x = $box_end_x - $char_w * 2; + $dot_right_x = $box_end_x - $char_w; + $y_pos = $box_start_y + $v_margin; + + foreach ($this->legend as $leg) { + // Text right aligned to the little box + $this->DrawText($this->legend_font, 0, $dot_left_x - $char_w, $y_pos, + $this->ndx_text_color, $leg, 'right'); + // Draw a box in the data color + ImageFilledRectangle($this->img, $dot_left_x, $y_pos + 1, $dot_right_x, + $y_pos + $dot_height-1, $this->ndx_data_colors[$color_index]); + // Draw a rectangle around the box + ImageRectangle($this->img, $dot_left_x, $y_pos + 1, $dot_right_x, + $y_pos + $dot_height-1, $this->ndx_text_color); + + $y_pos += $char_h + $this->line_spacing; + + $color_index++; + if ($color_index > $max_color_index) + $color_index = 0; + } + } // Function DrawLegend() + + + /*! + * TODO Draws a legend over (or below) an axis of the plot. + */ + function DrawAxisLegend() + { + // Calculate available room + // Calculate length of all items (boxes included) + // Calculate number of lines and room it would take. FIXME: this should be known in CalcMargins() + // Draw. + } + +///////////////////////////////////////////// +//////////////////// PLOT DRAWING +///////////////////////////////////////////// + + + /*! + * Draws a pie chart. Data has to be 'text-data' type. + * + * This can work in two ways: the classical, with a column for each sector + * (computes the column totals and draws the pie with that) + * OR + * Takes each row as a sector and uses it's first value. This has the added + * advantage of using the labels provided, which is not the case with the + * former method. This might prove useful for pie charts from GROUP BY sql queries + */ + function DrawPieChart() + { + $xpos = $this->plot_area[0] + $this->plot_area_width/2; + $ypos = $this->plot_area[1] + $this->plot_area_height/2; + $diameter = min($this->plot_area_width, $this->plot_area_height); + $radius = $diameter/2; + + // Get sum of each column? One pie slice per column + if ($this->data_type === 'text-data') { + for ($i = 0; $i < $this->num_data_rows; $i++) { + for ($j = 1; $j < $this->num_recs[$i]; $j++) { // Label ($row[0]) unused in these pie charts + @ $sumarr[$j] += abs($this->data[$i][$j]); // NOTE! sum > 0 to make pie charts + } + } + } + // Or only one column per row, one pie slice per row? + else if ($this->data_type == 'text-data-single') { + for ($i = 0; $i < $this->num_data_rows; $i++) { + $legend[$i] = $this->data[$i][0]; // Set the legend to column labels + $sumarr[$i] = $this->data[$i][1]; + } + } + else if ($this->data_type == 'data-data') { + for ($i = 0; $i < $this->num_data_rows; $i++) { + for ($j = 2; $j < $this->num_recs[$i]; $j++) { + @ $sumarr[$j] += abs($this->data[$i][$j]); + } + } + } + else { + $this->DrawError("DrawPieChart(): Data type '$this->data_type' not supported."); + return FALSE; + } + + $total = array_sum($sumarr); + + if ($total == 0) { + $this->DrawError('DrawPieChart(): Empty data set'); + return FALSE; + } + + if ($this->shading) { + $diam2 = $diameter / 2; + } else { + $diam2 = $diameter; + } + $max_data_colors = count ($this->data_colors); + + for ($h = $this->shading; $h >= 0; $h--) { + $color_index = 0; + $start_angle = 0; + $end_angle = 0; + foreach ($sumarr as $val) { + // For shaded pies: the last one (at the top of the "stack") has a brighter color: + if ($h == 0) + $slicecol = $this->ndx_data_colors[$color_index]; + else + $slicecol = $this->ndx_data_dark_colors[$color_index]; + + $label_txt = number_format(($val / $total * 100), $this->y_precision, '.', ', ') . '%'; + $val = 360 * ($val / $total); + + // NOTE that imagefilledarc measures angles CLOCKWISE (go figure why), + // so the pie chart would start clockwise from 3 o'clock, would it not be + // for the reversal of start and end angles in imagefilledarc() + $start_angle = $end_angle; + $end_angle += $val; + $mid_angle = deg2rad($end_angle - ($val / 2)); + + // Draw the slice + ImageFilledArc($this->img, $xpos, $ypos+$h, $diameter, $diam2, + 360-$end_angle, 360-$start_angle, + $slicecol, IMG_ARC_PIE); + + // Draw the labels only once + if ($h == 0) { + // Draw the outline + if (! $this->shading) + ImageFilledArc($this->img, $xpos, $ypos+$h, $diameter, $diam2, + 360-$end_angle, 360-$start_angle, + $this->ndx_grid_color, IMG_ARC_PIE | IMG_ARC_EDGED |IMG_ARC_NOFILL); + + + // The '* 1.2' trick is to get labels out of the pie chart so there are more + // chances they can be seen in small sectors. + $label_x = $xpos + ($diameter * 1.2 * cos($mid_angle)) * $this->label_scale_position; + $label_y = $ypos+$h - ($diam2 * 1.2 * sin($mid_angle)) * $this->label_scale_position; + + $this->DrawText($this->generic_font, 0, $label_x, $label_y, $this->ndx_grid_color, + $label_txt, 'center', 'center'); + } + $color_index++; + $color_index = $color_index % $max_data_colors; + } // end for + } // end for + } + + + /*! + * Supported data formats: data-data-error, text-data-error (doesn't exist yet) + * ( data comes in as array("title", x, y, error+, error-, y2, error2+, error2-, ...) ) + */ + function DrawDotsError() + { + $this->CheckOption($this->data_type, 'data-data-error', __FUNCTION__); + + for($row = 0, $cnt = 0; $row < $this->num_data_rows; $row++) { + $record = 1; // Skip record #0 (title) + + // Do we have a value for X? + if ($this->data_type == 'data-data-error') + $x_now = $this->data[$row][$record++]; // Read it, advance record index + else + $x_now = 0.5 + $cnt++; // Place text-data at X = 0.5, 1.5, 2.5, etc... + + // Draw X Data labels? + if ($this->x_data_label_pos != 'none') + $this->DrawXDataLabel($this->data[$row][0], $x_now_pixels, $row); + + while ($record < $this->num_recs[$row]) { + // Y: + $y_now = $this->data[$row][$record]; + $this->DrawDot($x_now, $y_now, $record, $this->ndx_data_colors[$record++]); + + // Error + + $val = $this->data[$row][$record]; + $this->DrawYErrorBar($x_now, $y_now, $val, $this->error_bar_shape, + $this->ndx_error_bar_colors[$record++]); + // Error - + $val = $this->data[$row][$record]; + $this->DrawYErrorBar($x_now, $y_now, -$val, $this->error_bar_shape, + $this->ndx_error_bar_colors[$record++]); + } + } + } // function DrawDotsError() + + + /* + * Supported data types: + * - data-data ("title", x, y1, y2, y3, ...) + * - text-data ("title", y1, y2, y3, ...) + */ + function DrawDots() + { + $this->CheckOption($this->data_type, 'text-data, data-data', __FUNCTION__); + + for ($row = 0, $cnt = 0; $row < $this->num_data_rows; $row++) { + $rec = 1; // Skip record #0 (data label) + + // Do we have a value for X? + if ($this->data_type == 'data-data') + $x_now = $this->data[$row][$rec++]; // Read it, advance record index + else + $x_now = 0.5 + $cnt++; // Place text-data at X = 0.5, 1.5, 2.5, etc... + + $x_now_pixels = $this->xtr($x_now); + + // Draw X Data labels? + if ($this->x_data_label_pos != 'none') + $this->DrawXDataLabel($this->data[$row][0], $x_now_pixels, $row); + + // Proceed with Y values + for($idx = 0;$rec < $this->num_recs[$row]; $rec++, $idx++) { + if (is_numeric($this->data[$row][$rec])) { // Allow for missing Y data + $this->DrawDot($x_now, $this->data[$row][$rec], + $rec, $this->ndx_data_colors[$idx]); + } + } + } + } //function DrawDots + + + /*! + * A clean, fast routine for when you just want charts like stock volume charts + */ + function DrawThinBarLines() + { + $this->CheckOption($this->data_type, 'text-data, data-data', __FUNCTION__); + + for ($row = 0, $cnt = 0; $row < $this->num_data_rows; $row++) { + $rec = 1; // Skip record #0 (data label) + + // Do we have a value for X? + if ($this->data_type == 'data-data') + $x_now = $this->data[$row][$rec++]; // Read it, advance record index + else + $x_now = 0.5 + $cnt++; // Place text-data at X = 0.5, 1.5, 2.5, etc... + + $x_now_pixels = $this->xtr($x_now); + + // Draw X Data labels? + if ($this->x_data_label_pos != 'none') + $this->DrawXDataLabel($this->data[$row][0], $x_now_pixels); + + // Proceed with Y values + for($idx = 0;$rec < $this->num_recs[$row]; $rec++, $idx++) { + if (is_numeric($this->data[$row][$rec])) { // Allow for missing Y data + ImageSetThickness($this->img, $this->line_widths[$idx]); + // Draws a line from user defined x axis position up to ytr($val) + ImageLine($this->img, $x_now_pixels, $this->x_axis_y_pixels, $x_now_pixels, + $this->ytr($this->data[$row][$rec]), $this->ndx_data_colors[$idx]); + } + } + } + + ImageSetThickness($this->img, 1); + } //function DrawThinBarLines + + /*! + * + */ + function DrawYErrorBar($x_world, $y_world, $error_height, $error_bar_type, $color) + { + /* + // TODO: add a parameter to show datalabels next to error bars? + // something like this: + if ($this->x_data_label_pos == 'plot') { + $this->DrawText($this->error_font, 90, $x1, $y2, + $color, $label, 'center', 'top'); + */ + + $x1 = $this->xtr($x_world); + $y1 = $this->ytr($y_world); + $y2 = $this->ytr($y_world+$error_height) ; + + ImageSetThickness($this->img, $this->error_bar_line_width); + ImageLine($this->img, $x1, $y1 , $x1, $y2, $color); + + switch ($error_bar_type) { + case 'line': + break; + case 'tee': + ImageLine($this->img, $x1-$this->error_bar_size, $y2, $x1+$this->error_bar_size, $y2, $color); + break; + default: + ImageLine($this->img, $x1-$this->error_bar_size, $y2, $x1+$this->error_bar_size, $y2, $color); + break; + } + + ImageSetThickness($this->img, 1); + return TRUE; + } + + /*! + * Draws a styled dot. Uses world coordinates. + * Supported types: 'halfline', 'line', 'plus', 'cross', 'rect', 'circle', 'dot', + * 'diamond', 'triangle', 'trianglemid' + */ + function DrawDot($x_world, $y_world, $record, $color) + { + // TODO: optimize, avoid counting every time we are called. + $record = $record % count ($this->point_shapes); + + $half_point = $this->point_sizes[$record] / 2; + + $x_mid = $this->xtr($x_world); + $y_mid = $this->ytr($y_world); + + $x1 = $x_mid - $half_point; + $x2 = $x_mid + $half_point; + $y1 = $y_mid - $half_point; + $y2 = $y_mid + $half_point; + + switch ($this->point_shapes[$record]) { + case 'halfline': + ImageLine($this->img, $x1, $y_mid, $x_mid, $y_mid, $color); + break; + case 'line': + ImageLine($this->img, $x1, $y_mid, $x2, $y_mid, $color); + break; + case 'plus': + ImageLine($this->img, $x1, $y_mid, $x2, $y_mid, $color); + ImageLine($this->img, $x_mid, $y1, $x_mid, $y2, $color); + break; + case 'cross': + ImageLine($this->img, $x1, $y1, $x2, $y2, $color); + ImageLine($this->img, $x1, $y2, $x2, $y1, $color); + break; + case 'rect': + ImageFilledRectangle($this->img, $x1, $y1, $x2, $y2, $color); + break; + case 'circle': + ImageArc($this->img, $x_mid, $y_mid, $this->point_sizes[$record], $this->point_sizes[$record], 0, 360, $color); + break; + case 'dot': + ImageFilledArc($this->img, $x_mid, $y_mid, $this->point_sizes[$record], $this->point_sizes[$record], 0, 360, + $color, IMG_ARC_PIE); + break; + case 'diamond': + $arrpoints = array( $x1, $y_mid, $x_mid, $y1, $x2, $y_mid, $x_mid, $y2); + ImageFilledPolygon($this->img, $arrpoints, 4, $color); + break; + case 'triangle': + $arrpoints = array( $x1, $y_mid, $x2, $y_mid, $x_mid, $y2); + ImageFilledPolygon($this->img, $arrpoints, 3, $color); + break; + case 'trianglemid': + $arrpoints = array( $x1, $y1, $x2, $y1, $x_mid, $y_mid); + ImageFilledPolygon($this->img, $arrpoints, 3, $color); + break; + default: + ImageFilledRectangle($this->img, $x1, $y1, $x2, $y2, $color); + break; + } + return TRUE; + } + + /*! + * Draw an area plot. Supported data types: + * 'text-data' + * 'data-data' + * NOTE: This function used to add first and last data values even on incomplete + * sets. That is not the behaviour now. As for missing data in between, + * there are two posibilities: replace the point with one on the X axis (previous + * way), or forget about it and use the preceding and following ones to draw the polygon. + * There is the possibility to use both, we just need to add the method to set + * it. Something like SetMissingDataBehaviour(), for example. + */ + function DrawArea() + { + $incomplete_data_defaults_to_x_axis = FALSE; // TODO: make this configurable + + for ($row = 0, $cnt = 0; $row < $this->num_data_rows; $row++) { + $rec = 1; // Skip record #0 (data label) + + if ($this->data_type == 'data-data') // Do we have a value for X? + $x_now = $this->data[$row][$rec++]; // Read it, advance record index + else + $x_now = 0.5 + $cnt++; // Place text-data at X = 0.5, 1.5, 2.5, etc... + + $x_now_pixels = $this->xtr($x_now); // Absolute coordinates + + + if ($this->x_data_label_pos != 'none') // Draw X Data labels? + $this->DrawXDataLabel($this->data[$row][0], $x_now_pixels); + + // Proceed with Y values + // Create array of points for imagefilledpolygon() + for($idx = 0; $rec < $this->num_recs[$row]; $rec++, $idx++) { + if (is_numeric($this->data[$row][$rec])) { // Allow for missing Y data + $y_now_pixels = $this->ytr($this->data[$row][$rec]); + + $posarr[$idx][] = $x_now_pixels; + $posarr[$idx][] = $y_now_pixels; + + $num_points[$idx] = isset($num_points[$idx]) ? $num_points[$idx]+1 : 1; + } + // If there's missing data... + else { + if (isset ($incomplete_data_defaults_to_x_axis)) { + $posarr[$idx][] = $x_now_pixels; + $posarr[$idx][] = $this->x_axis_y_pixels; + $num_points[$idx] = isset($num_points[$idx]) ? $num_points[$idx]+1 : 1; + } + } + } + } // end for + + $end = count($posarr); + for ($i = 0; $i < $end; $i++) { + // Prepend initial points. X = first point's X, Y = x_axis_y_pixels + $x = $posarr[$i][0]; + array_unshift($posarr[$i], $x, $this->x_axis_y_pixels); + + // Append final points. X = last point's X, Y = x_axis_y_pixels + $x = $posarr[$i][count($posarr[$i])-2]; + array_push($posarr[$i], $x, $this->x_axis_y_pixels); + + $num_points[$i] += 2; + + // Draw the poligon + ImageFilledPolygon($this->img, $posarr[$i], $num_points[$i], $this->ndx_data_colors[$i]); + } + + } // function DrawArea() + + + /*! + * Draw Lines. Supported data-types: + * 'data-data', + * 'text-data' + * NOTE: Please see the note regarding incomplete data sets on DrawArea() + */ + function DrawLines() + { + // This will tell us if lines have already begun to be drawn. + // It is an array to keep separate information for every line, with a single + // variable we would sometimes get "undefined offset" errors and no plot... + $start_lines = array_fill(0, $this->records_per_group, FALSE); + + if ($this->data_type == 'text-data') { + $lastx[0] = $this->xtr(0); + $lasty[0] = $this->xtr(0); + } + + for ($row = 0, $cnt = 0; $row < $this->num_data_rows; $row++) { + $record = 1; // Skip record #0 (data label) + + if ($this->data_type == 'data-data') // Do we have a value for X? + $x_now = $this->data[$row][$record++]; // Read it, advance record index + else + $x_now = 0.5 + $cnt++; // Place text-data at X = 0.5, 1.5, 2.5, etc... + + $x_now_pixels = $this->xtr($x_now); // Absolute coordinates + + if ($this->x_data_label_pos != 'none') // Draw X Data labels? + $this->DrawXDataLabel($this->data[$row][0], $x_now_pixels, $row); + + for ($idx = 0; $record < $this->num_recs[$row]; $record++, $idx++) { + if (is_numeric($this->data[$row][$record])) { //Allow for missing Y data + $y_now_pixels = $this->ytr($this->data[$row][$record]); + + if ($start_lines[$idx] == TRUE) { + // Set line width, revert it to normal at the end + ImageSetThickness($this->img, $this->line_widths[$idx]); + + if ($this->line_styles[$idx] == 'dashed') { + $this->SetDashedStyle($this->ndx_data_colors[$idx]); + ImageLine($this->img, $x_now_pixels, $y_now_pixels, $lastx[$idx], $lasty[$idx], + IMG_COLOR_STYLED); + } else { + ImageLine($this->img, $x_now_pixels, $y_now_pixels, $lastx[$idx], $lasty[$idx], + $this->ndx_data_colors[$idx]); + } + + } + $lasty[$idx] = $y_now_pixels; + $lastx[$idx] = $x_now_pixels; + $start_lines[$idx] = TRUE; + } + // Y data missing... should we leave a blank or not? + else if ($this->draw_broken_lines) { + $start_lines[$idx] = FALSE; + } + } // end for + } // end for + + ImageSetThickness($this->img, 1); // Revert to original state for lines to be drawn later. + } // function DrawLines() + + + /*! + * Draw lines with error bars - data comes in as + * array("label", x, y, error+, error-, y2, error2+, error2-, ...); + */ + function DrawLinesError() + { + if ($this->data_type != 'data-data-error') { + $this->DrawError("DrawLinesError(): Data type '$this->data_type' not supported."); + return FALSE; + } + + $start_lines = array_fill(0, $this->records_per_group, FALSE); + + for ($row = 0, $cnt = 0; $row < $this->num_data_rows; $row++) { + $record = 1; // Skip record #0 (data label) + + $x_now = $this->data[$row][$record++]; // Read X value, advance record index + + $x_now_pixels = $this->xtr($x_now); // Absolute coordinates. + + + if ($this->x_data_label_pos != 'none') // Draw X Data labels? + $this->DrawXDataLabel($this->data[$row][0], $x_now_pixels, $row); + + // Now go for Y, E+, E- + for ($idx = 0; $record < $this->num_recs[$row]; $idx++) { + // Y + $y_now = $this->data[$row][$record++]; + $y_now_pixels = $this->ytr($y_now); + + if ($start_lines[$idx] == TRUE) { + ImageSetThickness($this->img, $this->line_widths[$idx]); + + if ($this->line_styles[$idx] == 'dashed') { + $this->SetDashedStyle($this->ndx_data_colors[$idx]); + ImageLine($this->img, $x_now_pixels, $y_now_pixels, $lastx[$idx], $lasty[$idx], + IMG_COLOR_STYLED); + } else { + ImageLine($this->img, $x_now_pixels, $y_now_pixels, $lastx[$idx], $lasty[$idx], + $this->ndx_data_colors[$idx]); + } + } + + // Error+ + $val = $this->data[$row][$record++]; + $this->DrawYErrorBar($x_now, $y_now, $val, $this->error_bar_shape, + $this->ndx_error_bar_colors[$idx]); + + // Error- + $val = $this->data[$row][$record++]; + $this->DrawYErrorBar($x_now, $y_now, -$val, $this->error_bar_shape, + $this->ndx_error_bar_colors[$idx]); + + // Update indexes: + $start_lines[$idx] = TRUE; // Tells us if we already drew the first column of points, + // thus having $lastx and $lasty ready for the next column. + $lastx[$idx] = $x_now_pixels; + $lasty[$idx] = $y_now_pixels; + } // end while + } // end for + + ImageSetThickness($this->img, 1); // Revert to original state for lines to be drawn later. + } // function DrawLinesError() + + + + /*! + * This is a mere copy of DrawLines() with one more line drawn for each point + */ + function DrawSquared() + { + // This will tell us if lines have already begun to be drawn. + // It is an array to keep separate information for every line, for with a single + // variable we could sometimes get "undefined offset" errors and no plot... + $start_lines = array_fill(0, $this->records_per_group, FALSE); + + if ($this->data_type == 'text-data') { + $lastx[0] = $this->xtr(0); + $lasty[0] = $this->xtr(0); + } + + for ($row = 0, $cnt = 0; $row < $this->num_data_rows; $row++) { + $record = 1; // Skip record #0 (data label) + + if ($this->data_type == 'data-data') // Do we have a value for X? + $x_now = $this->data[$row][$record++]; // Read it, advance record index + else + $x_now = 0.5 + $cnt++; // Place text-data at X = 0.5, 1.5, 2.5, etc... + + $x_now_pixels = $this->xtr($x_now); // Absolute coordinates + + if ($this->x_data_label_pos != 'none') // Draw X Data labels? + $this->DrawXDataLabel($this->data[$row][0], $x_now_pixels); // notice there is no last param. + + // Draw Lines + for ($idx = 0; $record < $this->num_recs[$row]; $record++, $idx++) { + if (is_numeric($this->data[$row][$record])) { // Allow for missing Y data + $y_now_pixels = $this->ytr($this->data[$row][$record]); + + if ($start_lines[$idx] == TRUE) { + // Set line width, revert it to normal at the end + ImageSetThickness($this->img, $this->line_widths[$idx]); + + if ($this->line_styles[$idx] == 'dashed') { + $this->SetDashedStyle($this->ndx_data_colors[$idx]); + ImageLine($this->img, $lastx[$idx], $lasty[$idx], $x_now_pixels, $lasty[$idx], + IMG_COLOR_STYLED); + ImageLine($this->img, $x_now_pixels, $lasty[$idx], $x_now_pixels, $y_now_pixels, + IMG_COLOR_STYLED); + } else { + ImageLine($this->img, $lastx[$idx], $lasty[$idx], $x_now_pixels, $lasty[$idx], + $this->ndx_data_colors[$idx]); + ImageLine($this->img, $x_now_pixels, $lasty[$idx], $x_now_pixels, $y_now_pixels, + $this->ndx_data_colors[$idx]); + } + } + $lastx[$idx] = $x_now_pixels; + $lasty[$idx] = $y_now_pixels; + $start_lines[$idx] = TRUE; + } + // Y data missing... should we leave a blank or not? + else if ($this->draw_broken_lines) { + $start_lines[$idx] = FALSE; + } + } + } // end while + + ImageSetThickness($this->img, 1); + } // function DrawSquared() + + + /*! + * Data comes in as array("title", x, y, y2, y3, ...) + */ + function DrawBars() + { + if ($this->data_type != 'text-data') { + $this->DrawError('DrawBars(): Bar plots must be text-data: use function SetDataType("text-data")'); + return FALSE; + } + + for ($row = 0; $row < $this->num_data_rows; $row++) { + $record = 1; // Skip record #0 (data label) + + $x_now_pixels = $this->xtr(0.5 + $row); // Place text-data at X = 0.5, 1.5, 2.5, etc... + + if ($this->x_data_label_pos != 'none') // Draw X Data labels? TODO:labels on top of bars. + { + $this->DrawXDataLabel($this->data[$row][0], $x_now_pixels); + } + // Draw the bar + for ($idx = 0; $record < $this->num_recs[$row]; $record++, $idx++) { + if (is_numeric($this->data[$row][$record])) { // Allow for missing Y data + $x1 = $x_now_pixels - $this->data_group_space + ($idx * $this->record_bar_width); + $x2 = $x1 + ($this->bar_width_adjust * $this->record_bar_width); + + if ($this->data[$row][$record] < $this->x_axis_position) { + $y1 = $this->x_axis_y_pixels; + $y2 = $this->ytr($this->data[$row][$record]); + } else { + $y1 = $this->ytr($this->data[$row][$record]); + $y2 = $this->x_axis_y_pixels; + } + + if ($this->shading) { // Draw the shade? + ImageFilledPolygon($this->img, array($x1, $y1, + $x1 + $this->shading, $y1 - $this->shading, + $x2 + $this->shading, $y1 - $this->shading, + $x2 + $this->shading, $y2 - $this->shading, + $x2, $y2, + $x2, $y1), + 6, $this->ndx_data_dark_colors[$idx]); + } + // Or draw a border? + else { + ImageRectangle($this->img, $x1, $y1, $x2,$y2, $this->ndx_data_border_colors[$idx]); + } + // Draw the bar + ImageFilledRectangle($this->img, $x1, $y1, $x2, $y2, $this->ndx_data_colors[$idx]); + } + } // end for + } // end for + } //function DrawBars + + + /*! + * Data comes in as array("title", x, y, y2, y3, ...) + * \note Original stacked bars idea by Laurent Kruk < lolok at users.sourceforge.net > + */ + function DrawStackedBars() + { + if ($this->data_type != 'text-data') { + $this->DrawError('DrawStackedBars(): Bar plots must be text-data: use SetDataType("text-data")'); + return FALSE; + } + + for ($row = 0; $row < $this->num_data_rows; $row++) { + $record = 1; // Skip record #0 (data label) + + $x_now_pixels = $this->xtr(0.5 + $row); // Place text-data at X = 0.5, 1.5, 2.5, etc... + + if ($this->x_data_label_pos != 'none') // Draw X Data labels? + $this->DrawXDataLabel($this->data[$row][0], $x_now_pixels); + + // Draw the bars + $oldv = 0; + for ($idx = 0; $record < $this->num_recs[$row]; $record++, $idx++) { + if (is_numeric($this->data[$row][$record])) { // Allow for missing Y data + $x1 = $x_now_pixels - $this->data_group_space; + $x2 = $x_now_pixels + $this->data_group_space; + + $y1 = $this->ytr(abs($this->data[$row][$record]) + $oldv); + $y2 = $this->ytr($this->x_axis_position + $oldv); + $oldv += abs($this->data[$row][$record]); + + if ($this->shading) { // Draw the shade? + ImageFilledPolygon($this->img, array($x1, $y1, + $x1 + $this->shading, $y1 - $this->shading, + $x2 + $this->shading, $y1 - $this->shading, + $x2 + $this->shading, $y2 - $this->shading, + $x2, $y2, + $x2, $y1), + 6, $this->ndx_data_dark_colors[$idx]); + } + // Or draw a border? + else { + ImageRectangle($this->img, $x1, $y1, $x2,$y2, $this->ndx_data_border_colors[$idx]); + } + // Draw the bar + ImageFilledRectangle($this->img, $x1, $y1, $x2, $y2, $this->ndx_data_colors[$idx]); + + } + } // end for + } // end for + } //function DrawStackedBars + + + /*! + * + */ + function DrawGraph() + { + if (! $this->img) { + $this->DrawError('DrawGraph(): No image resource allocated'); + return FALSE; + } + + if (! is_array($this->data)) { + $this->DrawError("DrawGraph(): No array of data in \$data"); + return FALSE; + } + + if (! isset($this->data_limits_done)) + $this->FindDataLimits(); // Get maxima and minima for scaling + + if ($this->total_records == 0) { // Check for empty data sets + $this->DrawError('Empty data set'); + return FALSE; + } + + $this->CalcMargins(); // Calculate margins + + if (! isset($this->plot_area_width)) // Set plot area pixel values (plot_area[]) + $this->SetPlotAreaPixels(); + + if (! isset($this->plot_max_y)) // Set plot area world values (plot_max_x, etc.) + $this->SetPlotAreaWorld(); + + if ($this->plot_type == 'bars' || $this->plot_type == 'stackedbars') // Calculate bar widths + $this->CalcBarWidths(); +/* FIXME!! this sort of thing should not be done without user's consent + if ($this->x_data_label_pos != 'none') { // Default: do not draw tick stuff if + $this->x_tick_label_pos = 'none'; // there are data labels. + $this->x_tick_pos = 'none'; + } +*/ + $this->PadArrays(); // Pad color and style arrays to fit records per group. + + $this->DrawBackground(); + + $this->DrawImageBorder(); + + $this->DrawPlotAreaBackground(); + + $this->DrawTitle(); + $this->DrawXTitle(); + $this->DrawYTitle(); + + // Pie charts are drawn differently, handle them first + if ($this->plot_type == 'pie') { + // Pie charts can maximize image space usage. + $this->SetPlotAreaPixels($this->safe_margin, $this->title_height, + $this->image_width - $this->safe_margin, + $this->image_height - $this->safe_margin); + $this->DrawPieChart(); + + if ($this->legend) + $this->DrawLegend($this->legend_x_pos, $this->legend_y_pos, ''); + + if ($this->print_image) + $this->PrintImage(); + + return; + } + + ////// All other chart types: + + if (! $this->grid_at_foreground) { // Usually one wants grids to go back, but... + $this->DrawYAxis(); // Y axis must be drawn before X axis (see DrawYAxis()) + $this->DrawXAxis(); + } + + switch ($this->plot_type) { + case 'thinbarline': + $this->DrawThinBarLines(); + break; + case 'area': + $this->DrawArea(); + break; + case 'squared': + $this->DrawSquared(); + break; + case 'lines': + if ( $this->data_type == 'data-data-error') { + $this->DrawLinesError(); + } else { + $this->DrawLines(); + } + break; + case 'linepoints': // FIXME !!! DrawXDataLabel gets called in DrawLines() and DrawDots() + if ( $this->data_type == 'data-data-error') { + $this->DrawLinesError(); + $this->DrawDotsError(); + } else { + $this->DrawLines(); + $this->DrawDots(); + } + break; + case 'points'; + if ( $this->data_type == 'data-data-error') { + $this->DrawDotsError(); + } else { + $this->DrawDots(); + } + break; + case 'stackedbars': + $this->DrawStackedBars(); + break; + case 'bars': + $this->DrawBars(); + break; + default: + $this->plot_type = 'bars'; // Set it if it wasn't already set. + $this->DrawBars(); + break; + } // end switch + + if ($this->grid_at_foreground) { // Usually one wants grids to go back, but... + $this->DrawYAxis(); // Y axis must be drawn before X axis (see DrawYAxis()) + $this->DrawXAxis(); + } + + $this->DrawPlotBorder(); + + if ($this->legend) + $this->DrawLegend($this->legend_x_pos, $this->legend_y_pos, ''); + + if ($this->print_image) + $this->PrintImage(); + + } //function DrawGraph() + +///////////////////////////////////////////// +////////////////// DEPRECATED METHODS +///////////////////////////////////////////// + + /*! + * Deprecated, use SetYTickPos() + */ + function SetDrawVertTicks($which_dvt) + { + if ($which_dvt != 1) + $this->SetYTickPos('none'); + return TRUE; + } + + /*! + * Deprecated, use SetXTickPos() + */ + function SetDrawHorizTicks($which_dht) + { + if ($which_dht != 1) + $this->SetXTickPos('none'); + return TRUE; + } + + /*! + * \deprecated Use SetNumXTicks() + */ + function SetNumHorizTicks($n) + { + return $this->SetNumXTicks($n); + } + + /*! + * \deprecated Use SetNumYTicks() + */ + function SetNumVertTicks($n) + { + return $this->SetNumYTicks($n); + } + + /*! + * \deprecated Use SetXTickIncrement() + */ + function SetHorizTickIncrement($inc) + { + return $this->SetXTickIncrement($inc); + } + + + /*! + * \deprecated Use SetYTickIncrement() + */ + function SetVertTickIncrement($inc) + { + return $this->SetYTickIncrement($inc); + } + + /*! + * \deprecated Use SetYTickPos() + */ + function SetVertTickPosition($which_tp) + { + return $this->SetYTickPos($which_tp); + } + + /*! + * \deprecated Use SetXTickPos() + */ + function SetHorizTickPosition($which_tp) + { + return $this->SetXTickPos($which_tp); + } + + /*! + * \deprecated Use SetFont() + */ + function SetTitleFontSize($which_size) + { + return $this->SetFont('title', $which_size); + } + + /*! + * \deprecated Use SetFont() + */ + function SetAxisFontSize($which_size) + { + $this->SetFont('x_label', $which_size); + $this->SetFont('y_label', $whic_size); + } + + /*! + * \deprecated Use SetFont() + */ + function SetSmallFontSize($which_size) + { + return $this->SetFont('generic', $which_size); + } + + /*! + * \deprecated Use SetFont() + */ + function SetXLabelFontSize($which_size) + { + return $this->SetFont('x_title', $which_size); + } + + /*! + * \deprecated Use SetFont() + */ + function SetYLabelFontSize($which_size) + { + return $this->SetFont('y_title', $which_size); + } + + /*! + * \deprecated Use SetXTitle() + */ + function SetXLabel($which_xlab) + { + return $this->SetXTitle($which_xlab); + } + + /*! + * \deprecated Use SetYTitle() + */ + function SetYLabel($which_ylab) + { + return $this->SetYTitle($which_ylab); + } + + /*! + * \deprecated This is now an Internal function - please set width and + * height via PHPlot() upon object construction + */ + function SetImageArea($which_iw, $which_ih) + { + $this->image_width = $which_iw; + $this->image_height = $which_ih; + + return TRUE; + } + + /*! + * \deprecated Use SetXTickLength() and SetYTickLength() instead. + */ + function SetTickLength($which_tl) + { + $this->SetXTickLength($which_tl); + $this->SetYTickLength($which_tl); + return TRUE; + } + + /*! + * \deprecated Use SetYLabelType() + */ + function SetYGridLabelType($which_yglt) + { + return $this->SetYLabelType($which_yglt); + } + + /*! + * \deprecated Use SetXLabelType() + */ + function SetXGridLabelType($which_xglt) + { + return $this->SetXLabelType($which_xglt); + } + /*! + * \deprecated Use SetYTickLabelPos() + */ + function SetYGridLabelPos($which_yglp) + { + return $this->SetYTickLabelPos($which_yglp); + } + /*! + * \deprecated Use SetXTickLabelPos() + */ + function SetXGridLabelPos($which_xglp) + { + return $this->SetXTickLabelPos($which_xglp); + } + + + /*! + * \deprecated Use SetXtitle() + */ + function SetXTitlePos($xpos) + { + $this->x_title_pos = $xpos; + return TRUE; + } + + /*! + * \deprecated Use SetYTitle() + */ + function SetYTitlePos($xpos) + { + $this->y_title_pos = $xpos; + return TRUE; + } + + /*! + * \deprecated Use DrawDots() + */ + function DrawDotSeries() + { + $this->DrawDots(); + } + + /*! + * \deprecated Use SetXLabelAngle() + */ + function SetXDataLabelAngle($which_xdla) + { + return $this->SetXLabelAngle($which_xdla); + } + + /*! + * Draw Labels (not grid labels) on X Axis, following data points. Default position is + * down of plot. Care must be taken not to draw these and x_tick_labels as they'd probably overlap. + * + * \deprecated Use SetXDataLabelPos() + */ + function SetDrawXDataLabels($which_dxdl) + { + if ($which_dxdl == '1' ) + $this->SetXDataLabelPos('plotdown'); + else + $this->SetXDataLabelPos('none'); + } + + /*! + * \deprecated This method was intended to improve performance by being specially + * written for 'data-data'. However, the improvement didn't pay. Use DrawLines() instead + */ + function DrawLineSeries() + { + return $this->DrawLines(); + } + + /*! + * \deprecated Calculates maximum X-Axis label height. Now inside CalcMargins() + */ + function CalcXHeights() + { + // TTF + if ($this->use_ttf) { + $xstr = str_repeat('.', $this->max_t); + $size = $this->TTFBBoxSize($this->x_label_font['size'], $this->x_label_angle, + $this->x_label_font['font'], $xstr); + $this->x_tick_label_height = $size[1]; + } + // Fixed font + else { // For Non-TTF fonts we can have only angles 0 or 90 + if ($this->x_label_angle == 90) + $this->x_tick_label_height = $this->max_t * $this->x_label_font['width']; + else + $this->x_tick_label_height = $this->x_label_font['height']; + } + + return TRUE; + } + + + /*! + * \deprecated Calculates Maximum Y-Axis tick label width. Now inside CalcMargins() + */ + function CalcYWidths() + { + //the "." is for space. It isn't actually printed + $ylab = number_format($this->max_y, $this->y_precision, '.', ', ') . $this->data_units_text . '.'; + + // TTF + if ($this->use_ttf) { + // Maximum Y tick label width + $size = $this->TTFBBoxSize($this->y_label_font['size'], 0, $this->y_label_font['font'], $ylab); + $this->y_tick_label_width = $size[0]; + + } + // Fixed font + else { + // Y axis title width + $this->y_tick_label_width = strlen($ylab) * $this->y_label_font['width']; + } + + return TRUE; + } + + /*! + * \deprecated Superfluous. + */ + function DrawLabels() + { + $this->DrawTitle(); + $this->DrawXTitle(); + $this->DrawYTitle(); + } + + /*! + * Set up the image resource 'img' + * \deprecated The constructor should init 'img' + */ + function InitImage() + { + $this->img = ImageCreate($this->image_width, $this->image_height); + + if (! $this->img) + $this->PrintError('InitImage(): Could not create image resource'); + return TRUE; + } + + /*! + * \deprecated + */ + function SetNewPlotAreaPixels($x1, $y1, $x2, $y2) + { + //Like in GD 0, 0 is upper left set via pixel Coordinates + $this->plot_area = array($x1, $y1, $x2, $y2); + $this->plot_area_width = $this->plot_area[2] - $this->plot_area[0]; + $this->plot_area_height = $this->plot_area[3] - $this->plot_area[1]; + $this->y_top_margin = $this->plot_area[1]; + + if (isset($this->plot_max_x)) + $this->CalcTranslation(); + + return TRUE; + } + + /*! + * \deprecated Use _SetRGBColor() + */ + function SetColor($which_color) + { + $this->SetRGBColor($which_color); + return TRUE; + } + + /* + * \deprecated Use SetLineWidths(). + */ + function SetLineWidth($which_lw) + { + + $this->SetLineWidths($which_lw); + + if (!$this->error_bar_line_width) { + $this->SetErrorBarLineWidth($which_lw); + } + return TRUE; + } + + /*! + * \deprecated + */ + function DrawDashedLine($x1, $y1, $x2, $y2 , $dash_length, $dash_space, $color) + { + if ($dash_length) + $dashes = array_fill(0, $dash_length, $color); + else + $dashes = array(); + if ($dash_space) + $spaces = array_fill(0, $dash_space, IMG_COLOR_TRANSPARENT); + else + $spaces = array(); + + $style = array_merge($dashes, $spaces); + ImageSetStyle($this->img, $style); + ImageLine($this->img, $x1, $y1, $x2, $y2, IMG_COLOR_STYLED); + } + + /*! + * \deprecated Selects an input file to be used as background for the whole graph. + * This resizes the graph to the image's size. + */ + function SetInputFile($which_input_file) + { + $size = GetImageSize($which_input_file); + $input_type = $size[2]; + + switch($input_type) { + case 1: + $im = @ ImageCreateFromGIF ($which_input_file); + if (!$im) { // See if it failed + $this->PrintError("Unable to open $which_input_file as a GIF"); + return FALSE; + } + break; + case 3: + $im = @ ImageCreateFromPNG ($which_input_file); + if (!$im) { // See if it failed + $this->PrintError("Unable to open $which_input_file as a PNG"); + return FALSE; + } + break; + case 2: + $im = @ ImageCreateFromJPEG ($which_input_file); + if (!$im) { // See if it failed + $this->PrintError("Unable to open $which_input_file as a JPG"); + return FALSE; + } + break; + default: + $this->PrintError('SetInputFile(): Please select gif, jpg, or png for image type!'); + return FALSE; + break; + } + + // Set Width and Height of Image + $this->image_width = $size[0]; + $this->image_height = $size[1]; + + // Deallocate any resources previously allocated + if ($this->img) + imagedestroy($this->img); + + $this->img = $im; + + return TRUE; + + } + + + /* + * \deprecated Use SetPointShapes(). + */ + function SetPointShape($which_pt) + { + $this->SetPointShapes($which_pt); + return TRUE; + } + + /* + * \deprecated Use SetPointSizes(). + */ + function SetPointSize($which_ps) + { + $this->SetPointSizes($which_ps); + return TRUE; + } +} // class PHPlot + + + +//////////////////////// + + +/*! + * Pads an array with another or with itself. + * \param arr array Original array (reference) + * \param size int Size of the resulting array. + * \param arr2 array If specified, array to use for padding. If unspecified, pad with $arr. + */ +function array_pad_array(&$arr, $size, $arr2=NULL) +{ + if (! is_array($arr2)) { + $arr2 = $arr; // copy the original array + } + while (count($arr) < $size) + $arr = array_merge_php4($arr, $arr2); // append until done +} + +/*! + * Fixes problem with array_merge() in PHP5. + * \note I simply copied this from a bug report. I am not running php5 yet, so + * I cannot reproduce it, which is why I trust the reporter. + */ +function array_merge_php4($array1,$array2) +{ + $return=array(); + + foreach(func_get_args() as $arg){ + if(!is_array($arg)){ + $arg=array($arg); + } + foreach($arg as $key=>$val){ + if(!is_int($key)){ + $return[$key]=$val; + }else{ + $return[]=$val; + } + } + } + return $return; + } + + + + +?> diff --git a/htdocs/includes/phplot5/phplot_data.php b/htdocs/includes/phplot5/phplot_data.php new file mode 100644 index 00000000000..37351504c14 --- /dev/null +++ b/htdocs/includes/phplot5/phplot_data.php @@ -0,0 +1,258 @@ +img)) { + $this->PHPlot($which_width, $which_height, $which_output_file, $which_input_file); + } + } + + /*! + * Will scale all data rows + * Maybe later I will do a function that only scales some rows + * if $even is TRUE, data will be scaled with "even" factors. + * \note Original code by Thiemo Nagel + */ + function DoScaleData($even, $show_in_legend) + { + $offset = 0; // We use this not to read labels in text-data + + if ($this->data_type == 'text-data') { + $offset = 1; + } elseif ($this->data_type != 'data-data') { + $this->DrawError('wrong data type!!'); + return FALSE; + } + + // Determine maxima for each data row in array $max + // Put maximum of the maxima in $maxmax + $maxmax = 0; + for($i=0; $i < $this->num_data_rows; $i++) { + $rowsize = count($this->data[$i]); + for ($j=$offset; $j < $rowsize; $j++) { + if ($this->data[$i][$j] > @ $max[$j]) + $max[$j] = $this->data[$i][$j]; + if (@ $max[$j] > $maxmax) + $maxmax = $max[$j]; + } + } + + // determine amplification factor $amplify + $end = count($max) + $offset; + for ($i=$offset; $i < $end; $i++) { + if ($max[$i] == 0 || $max[$i] == $maxmax) { + $amplify[$i] = 1; // no divide by zero + } else { + if ($even) { + $amp = pow(10,round(log10($maxmax / $max[$i]))-1); + if ($amp * $max[$i] * 5 < $maxmax) { + $amp *= 5; + } elseif ($amp * $max[$i] * 2 < $maxmax) { + $amp *= 2; + } + } else { + $amp = $maxmax / $max[$i]; + $digits = floor(log10($amp)); + $amp = round($amp/pow(10,$digits-1))*pow(10,$digits-1); + } + $amplify[$i] = $amp; + } + if ($amplify[$i] != 1 && $show_in_legend) + @ $this->legend[$i] .= "*$amplify[$i]"; + } + + // Amplify data + // On my machine, running 1000 iterations over 1000 rows of 12 elements each, + // the for loops were 43.2% faster (MBD) + for ($i = 0; $i < $this->num_data_rows; $i++) { + $rowsize = count($this->data[$i]); + for ($j=$offset; $j < $rowsize; $j++) { + $this->data[$i][$j] *= $amplify[$j]; + } + } + + //Re-Scale Vertical Ticks if not already set + if ( ! $this->y_tick_increment) { + $this->SetYTickIncrement() ; + } + + return TRUE; + } //function DoScaleData + + + /*! + * Computes a moving average of strength $interval for + * data row number $datarow, where 0 denotes the first + * row of y-data. + * + * \param int datarow Index of the row whereupon to make calculations + * \param int interval Number of elements to use in average ("strength") + * \param bool show Whether to tell about the moving average in the legend. + * \param string color Color for the line to be drawn. This color is darkened. + * Can be named or #RRGGBB. + * \param int width Width of the line to be drawn. + * + * \note Original idea by Theimo Nagel + */ + function DoMovingAverage($datarow, $interval, $show=TRUE, $color=NULL, $width=NULL) + { + $off = 1; // Skip record #0 (data label) + + $this->PadArrays(); + + if ($interval == 0) { + $this->DrawError('DoMovingAverage(): interval can\'t be 0'); + return FALSE; + } + + if ($datarow >= $this->records_per_group) { + $this->DrawError("DoMovingAverage(): Data row out of bounds ($datarow >= $this->records_per_group)"); + return FALSE; + } + + if ($this->data_type == 'text-data') { + // Ok. No need to set the offset to skip more records. + } elseif ($this->data_type == 'data-data') { + $off++; // first Y value at $data[][2] + } else { + $this->DrawError('DoMovingAverage(): wrong data type!!'); + return FALSE; + } + + // Set color: + if ($color) { + array_push($this->ndx_data_colors, $this->SetIndexDarkColor($color)); + } else { + array_push($this->ndx_data_colors, $this->SetIndexDarkColor($this->data_colors[$datarow])); + } + // Set line width: + if ($width) { + array_push($this->line_widths, $width); + } else { + array_push($this->line_widths, $this->line_widths[$datarow] * 2); + } + // Show in legend? + if ($show) { + $this->legend[$this->records_per_group-1] = "(MA[$datarow]:$interval)"; + } + + $datarow += $off; + for ($i = 0; $i < $this->num_data_rows; $i++) { + $storage[$i % $interval] = @ $this->data[$i][$datarow]; + $ma = array_sum($storage); + $ma /= count($storage); + array_push($this->data[$i], $ma); // Push the data onto the array + $this->num_recs[$i]++; // Tell the drawing functions it is there + } + $this->records_per_group++; +// $this->FindDataLimits(); + return TRUE; + } //function DoMovingAverage() + + + /** + * Computes an exponentially smoothed moving average. + * @param int perc "smoothing percentage" + * FIXME!!! I haven't checked this. + */ + function DoExponentialMovingAverage($datarow, $perc, $show_in_legend) + { + if ($this->data_type == 'text-data') { + $datarow++; + } elseif ($this->data_type != 'data-data') { + $this->DrawError('DoWeightedMovingAverage(): wrong data type!!'); + return FALSE; + } + + if ($show_in_legend) { + $this->legend[$datarow] .= " (MA: $interval)"; + } + + $storage[0] = $this->data[0][$datarow]; + for ($i=1;$i < $this->num_data_rows; $i++) { + $storage[$i] = @ $storage[$i-1] + $perc * ($this->data[$i][$datarow] - $storage[$i-1]); + $ma = array_sum($storage); + $ma /= count($storage); + $this->data[$i][$datarow] = $ma; + } + return TRUE; + } // function DoExponentialMovingAverage() + + + /*! + * Removes the DataSet of number $index + */ + function DoRemoveDataSet($index) + { + $offset = 1; + if ($this->data_type == 'data-data') { + $offset++; + } elseif ($this->data_type != 'text-data') { + $this->DrawError('wrong data type!!'); + return FALSE; + } + + $index += $offset; + foreach ($this->data as $key=>$val) { + foreach ($val as $key2=>$val2) { + if ($key2 >= $index) { + if (isset($this->data[$key][$key2+1])) { + $this->data[$key][$key2] = $this->data[$key][$key2+1]; + } else { + unset($this->data[$key][$key2]); + } + } + } + } + } // function DoRemoveDataSet + + + /*! + * Computes row x divided by row y, stores the result in row x + * and deletes row y + */ + function DoDivision($x,$y) + { + $offset = 1; + if ($this->data_type == 'data-data') { + $offset++; + } elseif ($this->data_type != 'text-data') { + $this->DrawError('wrong data type!!'); + return FALSE; + } + + $x += $offset; $y += $offset; + reset($this->data); + while (list($key, $val) = each($this->data)) { + if ($this->data[$key][$y] == 0) { + $this->data[$key][$x] = 0; + } else { + $this->data[$key][$x] /= $this->data[$key][$y]; + } + } + + $this->DoRemoveDataSet($y-$offset); + } // function DoDivision + +} // class PHPlot_Data extends PHPlot +?> diff --git a/htdocs/includes/phplot5/rgb.inc.php b/htdocs/includes/phplot5/rgb.inc.php new file mode 100644 index 00000000000..3353e28e50e --- /dev/null +++ b/htdocs/includes/phplot5/rgb.inc.php @@ -0,0 +1,744 @@ + array(255, 250, 250), + "ghost white" => array(248, 248, 255), + "GhostWhite" => array(248, 248, 255), + "white smoke" => array(245, 245, 245), + "WhiteSmoke" => array(245, 245, 245), + "gainsboro" => array(220, 220, 220), + "floral white" => array(255, 250, 240), + "FloralWhite" => array(255, 250, 240), + "old lace" => array(253, 245, 230), + "OldLace" => array(253, 245, 230), + "linen" => array(250, 240, 230), + "antique white" => array(250, 235, 215), + "AntiqueWhite" => array(250, 235, 215), + "papaya whip" => array(255, 239, 213), + "PapayaWhip" => array(255, 239, 213), + "blanched almond" => array(255, 235, 205), + "BlanchedAlmond" => array(255, 235, 205), + "bisque" => array(255, 228, 196), + "peach puff" => array(255, 218, 185), + "PeachPuff" => array(255, 218, 185), + "navajo white" => array(255, 222, 173), + "NavajoWhite" => array(255, 222, 173), + "moccasin" => array(255, 228, 181), + "cornsilk" => array(255, 248, 220), + "ivory" => array(255, 255, 240), + "lemon chiffon" => array(255, 250, 205), + "LemonChiffon" => array(255, 250, 205), + "seashell" => array(255, 245, 238), + "honeydew" => array(240, 255, 240), + "mint cream" => array(245, 255, 250), + "MintCream" => array(245, 255, 250), + "azure" => array(240, 255, 255), + "alice blue" => array(240, 248, 255), + "AliceBlue" => array(240, 248, 255), + "lavender" => array(230, 230, 250), + "lavender blush" => array(255, 240, 245), + "LavenderBlush" => array(255, 240, 245), + "misty rose" => array(255, 228, 225), + "MistyRose" => array(255, 228, 225), + "white" => array(255, 255, 255), + "black" => array( 0, 0, 0), + "dark slate gray" => array( 47, 79, 79), + "DarkSlateGray" => array( 47, 79, 79), + "dark slate grey" => array( 47, 79, 79), + "DarkSlateGrey" => array( 47, 79, 79), + "dim gray" => array(105, 105, 105), + "DimGray" => array(105, 105, 105), + "dim grey" => array(105, 105, 105), + "DimGrey" => array(105, 105, 105), + "slate gray" => array(112, 128, 144), + "SlateGray" => array(112, 128, 144), + "slate grey" => array(112, 128, 144), + "SlateGrey" => array(112, 128, 144), + "light slate gray" => array(119, 136, 153), + "LightSlateGray" => array(119, 136, 153), + "light slate grey" => array(119, 136, 153), + "LightSlateGrey" => array(119, 136, 153), + "gray" => array(190, 190, 190), + "grey" => array(190, 190, 190), + "light grey" => array(211, 211, 211), + "LightGrey" => array(211, 211, 211), + "light gray" => array(211, 211, 211), + "LightGray" => array(211, 211, 211), + "midnight blue" => array( 25, 25, 112), + "MidnightBlue" => array( 25, 25, 112), + "navy" => array( 0, 0, 128), + "navy blue" => array( 0, 0, 128), + "NavyBlue" => array( 0, 0, 128), + "cornflower blue" => array(100, 149, 237), + "CornflowerBlue" => array(100, 149, 237), + "dark slate blue" => array( 72, 61, 139), + "DarkSlateBlue" => array( 72, 61, 139), + "slate blue" => array(106, 90, 205), + "SlateBlue" => array(106, 90, 205), + "medium slate blue" => array(123, 104, 238), + "MediumSlateBlue" => array(123, 104, 238), + "light slate blue" => array(132, 112, 255), + "LightSlateBlue" => array(132, 112, 255), + "medium blue" => array( 0, 0, 205), + "MediumBlue" => array( 0, 0, 205), + "royal blue" => array( 65, 105, 225), + "RoyalBlue" => array( 65, 105, 225), + "blue" => array( 0, 0, 255), + "dodger blue" => array( 30, 144, 255), + "DodgerBlue" => array( 30, 144, 255), + "deep sky blue" => array( 0, 191, 255), + "DeepSkyBlue" => array( 0, 191, 255), + "sky blue" => array(135, 206, 235), + "SkyBlue" => array(135, 206, 235), + "light sky blue" => array(135, 206, 250), + "LightSkyBlue" => array(135, 206, 250), + "steel blue" => array( 70, 130, 180), + "SteelBlue" => array( 70, 130, 180), + "light steel blue" => array(176, 196, 222), + "LightSteelBlue" => array(176, 196, 222), + "light blue" => array(173, 216, 230), + "LightBlue" => array(173, 216, 230), + "powder blue" => array(176, 224, 230), + "PowderBlue" => array(176, 224, 230), + "pale turquoise" => array(175, 238, 238), + "PaleTurquoise" => array(175, 238, 238), + "dark turquoise" => array( 0, 206, 209), + "DarkTurquoise" => array( 0, 206, 209), + "medium turquoise" => array( 72, 209, 204), + "MediumTurquoise" => array( 72, 209, 204), + "turquoise" => array( 64, 224, 208), + "cyan" => array( 0, 255, 255), + "light cyan" => array(224, 255, 255), + "LightCyan" => array(224, 255, 255), + "cadet blue" => array( 95, 158, 160), + "CadetBlue" => array( 95, 158, 160), + "medium aquamarine" => array(102, 205, 170), + "MediumAquamarine" => array(102, 205, 170), + "aquamarine" => array(127, 255, 212), + "dark green" => array( 0, 100, 0), + "DarkGreen" => array( 0, 100, 0), + "dark olive green" => array( 85, 107, 47), + "DarkOliveGreen" => array( 85, 107, 47), + "dark sea green" => array(143, 188, 143), + "DarkSeaGreen" => array(143, 188, 143), + "sea green" => array( 46, 139, 87), + "SeaGreen" => array( 46, 139, 87), + "medium sea green" => array( 60, 179, 113), + "MediumSeaGreen" => array( 60, 179, 113), + "light sea green" => array( 32, 178, 170), + "LightSeaGreen" => array( 32, 178, 170), + "pale green" => array(152, 251, 152), + "PaleGreen" => array(152, 251, 152), + "spring green" => array( 0, 255, 127), + "SpringGreen" => array( 0, 255, 127), + "lawn green" => array(124, 252, 0), + "LawnGreen" => array(124, 252, 0), + "green" => array( 0, 255, 0), + "chartreuse" => array(127, 255, 0), + "medium spring green" => array( 0, 250, 154), + "MediumSpringGreen" => array( 0, 250, 154), + "green yellow" => array(173, 255, 47), + "GreenYellow" => array(173, 255, 47), + "lime green" => array( 50, 205, 50), + "LimeGreen" => array( 50, 205, 50), + "yellow green" => array(154, 205, 50), + "YellowGreen" => array(154, 205, 50), + "forest green" => array( 34, 139, 34), + "ForestGreen" => array( 34, 139, 34), + "olive drab" => array(107, 142, 35), + "OliveDrab" => array(107, 142, 35), + "dark khaki" => array(189, 183, 107), + "DarkKhaki" => array(189, 183, 107), + "khaki" => array(240, 230, 140), + "pale goldenrod" => array(238, 232, 170), + "PaleGoldenrod" => array(238, 232, 170), + "light goldenrod yellow" => array(250, 250, 210), + "LightGoldenrodYellow" => array(250, 250, 210), + "light yellow" => array(255, 255, 224), + "LightYellow" => array(255, 255, 224), + "yellow" => array(255, 255, 0), + "gold" => array(255, 215, 0), + "light goldenrod" => array(238, 221, 130), + "LightGoldenrod" => array(238, 221, 130), + "goldenrod" => array(218, 165, 32), + "dark goldenrod" => array(184, 134, 11), + "DarkGoldenrod" => array(184, 134, 11), + "rosy brown" => array(188, 143, 143), + "RosyBrown" => array(188, 143, 143), + "indian red" => array(205, 92, 92), + "IndianRed" => array(205, 92, 92), + "saddle brown" => array(139, 69, 19), + "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), + "sandy brown" => array(244, 164, 96), + "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), + "dark salmon" => array(233, 150, 122), + "DarkSalmon" => array(233, 150, 122), + "salmon" => array(250, 128, 114), + "light salmon" => array(255, 160, 122), + "LightSalmon" => array(255, 160, 122), + "orange" => array(255, 165, 0), + "dark orange" => array(255, 140, 0), + "DarkOrange" => array(255, 140, 0), + "coral" => array(255, 127, 80), + "light coral" => array(240, 128, 128), + "LightCoral" => array(240, 128, 128), + "tomato" => array(255, 99, 71), + "orange red" => array(255, 69, 0), + "OrangeRed" => array(255, 69, 0), + "red" => array(255, 0, 0), + "hot pink" => array(255, 105, 180), + "HotPink" => array(255, 105, 180), + "deep pink" => array(255, 20, 147), + "DeepPink" => array(255, 20, 147), + "pink" => array(255, 192, 203), + "light pink" => array(255, 182, 193), + "LightPink" => array(255, 182, 193), + "pale violet red" => array(219, 112, 147), + "PaleVioletRed" => array(219, 112, 147), + "maroon" => array(176, 48, 96), + "medium violet red" => array(199, 21, 133), + "MediumVioletRed" => array(199, 21, 133), + "violet red" => array(208, 32, 144), + "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), + "medium orchid" => array(186, 85, 211), + "MediumOrchid" => array(186, 85, 211), + "dark orchid" => array(153, 50, 204), + "DarkOrchid" => array(153, 50, 204), + "dark violet" => array(148, 0, 211), + "DarkViolet" => array(148, 0, 211), + "blue violet" => array(138, 43, 226), + "BlueViolet" => array(138, 43, 226), + "purple" => array(160, 32, 240), + "medium purple" => array(147, 112, 219), + "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), + "cornsilk1" => array(255, 248, 220), + "cornsilk2" => array(238, 232, 205), + "cornsilk3" => array(205, 200, 177), + "cornsilk4" => array(139, 136, 120), + "ivory1" => array(255, 255, 240), + "ivory2" => array(238, 238, 224), + "ivory3" => array(205, 205, 193), + "ivory4" => array(139, 139, 131), + "honeydew1" => array(240, 255, 240), + "honeydew2" => array(224, 238, 224), + "honeydew3" => array(193, 205, 193), + "honeydew4" => array(131, 139, 131), + "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), + "blue1" => array( 0, 0, 255), + "blue2" => array( 0, 0, 238), + "blue3" => array( 0, 0, 205), + "blue4" => array( 0, 0, 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), + "green1" => array( 0, 255, 0), + "green2" => array( 0, 238, 0), + "green3" => array( 0, 205, 0), + "green4" => array( 0, 139, 0), + "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), + "LightYellow1" => array(255, 255, 224), + "LightYellow2" => array(238, 238, 209), + "LightYellow3" => array(205, 205, 180), + "LightYellow4" => array(139, 139, 122), + "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), + "red1" => array(255, 0, 0), + "red2" => array(238, 0, 0), + "red3" => array(205, 0, 0), + "red4" => array(139, 0, 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), + "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), + "gray0" => array( 0, 0, 0), + "grey0" => array( 0, 0, 0), + "gray1" => array( 3, 3, 3), + "grey1" => array( 3, 3, 3), + "gray2" => array( 5, 5, 5), + "grey2" => array( 5, 5, 5), + "gray3" => array( 8, 8, 8), + "grey3" => array( 8, 8, 8), + "gray4" => array( 10, 10, 10), + "grey4" => array( 10, 10, 10), + "gray5" => array( 13, 13, 13), + "grey5" => array( 13, 13, 13), + "gray6" => array( 15, 15, 15), + "grey6" => array( 15, 15, 15), + "gray7" => array( 18, 18, 18), + "grey7" => array( 18, 18, 18), + "gray8" => array( 20, 20, 20), + "grey8" => array( 20, 20, 20), + "gray9" => array( 23, 23, 23), + "grey9" => array( 23, 23, 23), + "gray10" => array( 26, 26, 26), + "grey10" => array( 26, 26, 26), + "gray11" => array( 28, 28, 28), + "grey11" => array( 28, 28, 28), + "gray12" => array( 31, 31, 31), + "grey12" => array( 31, 31, 31), + "gray13" => array( 33, 33, 33), + "grey13" => array( 33, 33, 33), + "gray14" => array( 36, 36, 36), + "grey14" => array( 36, 36, 36), + "gray15" => array( 38, 38, 38), + "grey15" => array( 38, 38, 38), + "gray16" => array( 41, 41, 41), + "grey16" => array( 41, 41, 41), + "gray17" => array( 43, 43, 43), + "grey17" => array( 43, 43, 43), + "gray18" => array( 46, 46, 46), + "grey18" => array( 46, 46, 46), + "gray19" => array( 48, 48, 48), + "grey19" => array( 48, 48, 48), + "gray20" => array( 51, 51, 51), + "grey20" => array( 51, 51, 51), + "gray21" => array( 54, 54, 54), + "grey21" => array( 54, 54, 54), + "gray22" => array( 56, 56, 56), + "grey22" => array( 56, 56, 56), + "gray23" => array( 59, 59, 59), + "grey23" => array( 59, 59, 59), + "gray24" => array( 61, 61, 61), + "grey24" => array( 61, 61, 61), + "gray25" => array( 64, 64, 64), + "grey25" => array( 64, 64, 64), + "gray26" => array( 66, 66, 66), + "grey26" => array( 66, 66, 66), + "gray27" => array( 69, 69, 69), + "grey27" => array( 69, 69, 69), + "gray28" => array( 71, 71, 71), + "grey28" => array( 71, 71, 71), + "gray29" => array( 74, 74, 74), + "grey29" => array( 74, 74, 74), + "gray30" => array( 77, 77, 77), + "grey30" => array( 77, 77, 77), + "gray31" => array( 79, 79, 79), + "grey31" => array( 79, 79, 79), + "gray32" => array( 82, 82, 82), + "grey32" => array( 82, 82, 82), + "gray33" => array( 84, 84, 84), + "grey33" => array( 84, 84, 84), + "gray34" => array( 87, 87, 87), + "grey34" => array( 87, 87, 87), + "gray35" => array( 89, 89, 89), + "grey35" => array( 89, 89, 89), + "gray36" => array( 92, 92, 92), + "grey36" => array( 92, 92, 92), + "gray37" => array( 94, 94, 94), + "grey37" => array( 94, 94, 94), + "gray38" => array( 97, 97, 97), + "grey38" => array( 97, 97, 97), + "gray39" => array( 99, 99, 99), + "grey39" => array( 99, 99, 99), + "gray40" => array(102, 102, 102), + "grey40" => array(102, 102, 102), + "gray41" => array(105, 105, 105), + "grey41" => array(105, 105, 105), + "gray42" => array(107, 107, 107), + "grey42" => array(107, 107, 107), + "gray43" => array(110, 110, 110), + "grey43" => array(110, 110, 110), + "gray44" => array(112, 112, 112), + "grey44" => array(112, 112, 112), + "gray45" => array(115, 115, 115), + "grey45" => array(115, 115, 115), + "gray46" => array(117, 117, 117), + "grey46" => array(117, 117, 117), + "gray47" => array(120, 120, 120), + "grey47" => array(120, 120, 120), + "gray48" => array(122, 122, 122), + "grey48" => array(122, 122, 122), + "gray49" => array(125, 125, 125), + "grey49" => array(125, 125, 125), + "gray50" => array(127, 127, 127), + "grey50" => array(127, 127, 127), + "gray51" => array(130, 130, 130), + "grey51" => array(130, 130, 130), + "gray52" => array(133, 133, 133), + "grey52" => array(133, 133, 133), + "gray53" => array(135, 135, 135), + "grey53" => array(135, 135, 135), + "gray54" => array(138, 138, 138), + "grey54" => array(138, 138, 138), + "gray55" => array(140, 140, 140), + "grey55" => array(140, 140, 140), + "gray56" => array(143, 143, 143), + "grey56" => array(143, 143, 143), + "gray57" => array(145, 145, 145), + "grey57" => array(145, 145, 145), + "gray58" => array(148, 148, 148), + "grey58" => array(148, 148, 148), + "gray59" => array(150, 150, 150), + "grey59" => array(150, 150, 150), + "gray60" => array(153, 153, 153), + "grey60" => array(153, 153, 153), + "gray61" => array(156, 156, 156), + "grey61" => array(156, 156, 156), + "gray62" => array(158, 158, 158), + "grey62" => array(158, 158, 158), + "gray63" => array(161, 161, 161), + "grey63" => array(161, 161, 161), + "gray64" => array(163, 163, 163), + "grey64" => array(163, 163, 163), + "gray65" => array(166, 166, 166), + "grey65" => array(166, 166, 166), + "gray66" => array(168, 168, 168), + "grey66" => array(168, 168, 168), + "gray67" => array(171, 171, 171), + "grey67" => array(171, 171, 171), + "gray68" => array(173, 173, 173), + "grey68" => array(173, 173, 173), + "gray69" => array(176, 176, 176), + "grey69" => array(176, 176, 176), + "gray70" => array(179, 179, 179), + "grey70" => array(179, 179, 179), + "gray71" => array(181, 181, 181), + "grey71" => array(181, 181, 181), + "gray72" => array(184, 184, 184), + "grey72" => array(184, 184, 184), + "gray73" => array(186, 186, 186), + "grey73" => array(186, 186, 186), + "gray74" => array(189, 189, 189), + "grey74" => array(189, 189, 189), + "gray75" => array(191, 191, 191), + "grey75" => array(191, 191, 191), + "gray76" => array(194, 194, 194), + "grey76" => array(194, 194, 194), + "gray77" => array(196, 196, 196), + "grey77" => array(196, 196, 196), + "gray78" => array(199, 199, 199), + "grey78" => array(199, 199, 199), + "gray79" => array(201, 201, 201), + "grey79" => array(201, 201, 201), + "gray80" => array(204, 204, 204), + "grey80" => array(204, 204, 204), + "gray81" => array(207, 207, 207), + "grey81" => array(207, 207, 207), + "gray82" => array(209, 209, 209), + "grey82" => array(209, 209, 209), + "gray83" => array(212, 212, 212), + "grey83" => array(212, 212, 212), + "gray84" => array(214, 214, 214), + "grey84" => array(214, 214, 214), + "gray85" => array(217, 217, 217), + "grey85" => array(217, 217, 217), + "gray86" => array(219, 219, 219), + "grey86" => array(219, 219, 219), + "gray87" => array(222, 222, 222), + "grey87" => array(222, 222, 222), + "gray88" => array(224, 224, 224), + "grey88" => array(224, 224, 224), + "gray89" => array(227, 227, 227), + "grey89" => array(227, 227, 227), + "gray90" => array(229, 229, 229), + "grey90" => array(229, 229, 229), + "gray91" => array(232, 232, 232), + "grey91" => array(232, 232, 232), + "gray92" => array(235, 235, 235), + "grey92" => array(235, 235, 235), + "gray93" => array(237, 237, 237), + "grey93" => array(237, 237, 237), + "gray94" => array(240, 240, 240), + "grey94" => array(240, 240, 240), + "gray95" => array(242, 242, 242), + "grey95" => array(242, 242, 242), + "gray96" => array(245, 245, 245), + "grey96" => array(245, 245, 245), + "gray97" => array(247, 247, 247), + "grey97" => array(247, 247, 247), + "gray98" => array(250, 250, 250), + "grey98" => array(250, 250, 250), + "gray99" => array(252, 252, 252), + "grey99" => array(252, 252, 252), + "gray100" => array(255, 255, 255) +); +?> diff --git a/htdocs/install/upgrade2.php b/htdocs/install/upgrade2.php index 2d84887abab..22b2c6f296a 100644 --- a/htdocs/install/upgrade2.php +++ b/htdocs/install/upgrade2.php @@ -108,19 +108,26 @@ if (isset($_POST['action']) && $_POST['action'] == 'upgrade') * Pour utiliser d'autres versions des librairies externes que les * versions embarquées dans Dolibarr, définir les constantes adequates: * Pour FPDF: FPDF_PATH - * Pour PEAR: PEAR_PATH + * Pour Pear: PEAR_PATH * Pour PHP_WriteExcel: PHP_WRITEEXCEL_PATH - * Pour PHPlot: PHPLOT_PATH * Pour MagpieRss: MAGPIERSS_PATH + * Pour PHPlot: PHPLOT_PATH + * Pour JPGraph: JPGRAPH_PATH + * Pour NuSOAP: NUSOAP_PATH + * Pour TCPDF: TCPDF_PATH */ if (! defined('FPDF_PATH')) { define('FPDF_PATH', DOL_DOCUMENT_ROOT .'/includes/fpdf/fpdf/'); } if (! defined('PEAR_PATH')) { define('PEAR_PATH', DOL_DOCUMENT_ROOT .'/includes/pear/'); } if (! defined('PHP_WRITEEXCEL_PATH')) { define('PHP_WRITEEXCEL_PATH',DOL_DOCUMENT_ROOT .'/includes/php_writeexcel/'); } - if (! defined('PHPLOT_PATH')) { define('PHPLOT_PATH', DOL_DOCUMENT_ROOT .'/includes/phplot/'); } if (! defined('MAGPIERSS_PATH')) { define('MAGPIERSS_PATH', DOL_DOCUMENT_ROOT .'/includes/magpierss/'); } + if (! defined('PHPLOT_PATH')) { define('PHPLOT_PATH', DOL_DOCUMENT_ROOT .'/includes/phplot/'); } if (! defined('JPGRAPH_PATH')) { define('JPGRAPH_PATH', DOL_DOCUMENT_ROOT .'/includes/jpgraph/'); } - define('FPDF_FONTPATH', FPDF_PATH . 'font/'); - define('MAGPIE_DIR', MAGPIERSS_PATH); + if (! defined('NUSOAP_PATH')) { define('NUSOAP_PATH', DOL_DOCUMENT_ROOT .'/includes/nusoap/lib/'); } + if (! defined('TCPDF_PATH')) { define('TCPDF_PATH', DOL_DOCUMENT_ROOT .'/includes/fpdf/tcpdf/'); } + // Les autres path + if (! defined('FPDF_FONTPATH')) { define('FPDF_FONTPATH', FPDF_PATH . 'font/'); } + if (! defined('MAGPIE_DIR')) { define('MAGPIE_DIR', MAGPIERSS_PATH); } + if (! defined('MAGPIE_CACHE_DIR')) { define('MAGPIE_CACHE_DIR', DOL_DATA_ROOT .'/rsscache'); } /*************************************************************************************** diff --git a/htdocs/master.inc.php b/htdocs/master.inc.php index ae221f19f86..90c04dd2307 100644 --- a/htdocs/master.inc.php +++ b/htdocs/master.inc.php @@ -140,10 +140,10 @@ $langs->setPhpLang($conf->global->MAIN_LANG_DEFAULT); * Pour utiliser d'autres versions des librairies externes que les * versions embarquées dans Dolibarr, définir les constantes adequates: * Pour FPDF: FPDF_PATH - * Pour PEAR: PEAR_PATH + * Pour Pear: PEAR_PATH * Pour PHP_WriteExcel: PHP_WRITEEXCEL_PATH - * Pour PHPlot: PHPLOT_PATH * Pour MagpieRss: MAGPIERSS_PATH + * Pour PHPlot: PHPLOT_PATH * Pour JPGraph: JPGRAPH_PATH * Pour NuSOAP: NUSOAP_PATH * Pour TCPDF: TCPDF_PATH @@ -152,8 +152,18 @@ $langs->setPhpLang($conf->global->MAIN_LANG_DEFAULT); if (! defined('FPDF_PATH')) { define('FPDF_PATH', DOL_DOCUMENT_ROOT .'/includes/fpdf/fpdf/'); } if (! defined('PEAR_PATH')) { define('PEAR_PATH', DOL_DOCUMENT_ROOT .'/includes/pear/'); } if (! defined('PHP_WRITEEXCEL_PATH')) { define('PHP_WRITEEXCEL_PATH',DOL_DOCUMENT_ROOT .'/includes/php_writeexcel/'); } -if (! defined('PHPLOT_PATH')) { define('PHPLOT_PATH', DOL_DOCUMENT_ROOT .'/includes/phplot/'); } if (! defined('MAGPIERSS_PATH')) { define('MAGPIERSS_PATH', DOL_DOCUMENT_ROOT .'/includes/magpierss/'); } +if (! defined('PHPLOT_PATH')) +{ + if (versioncompare(versionphp(),array(4,2,0)) >= 0) + { + define('PHPLOT_PATH', DOL_DOCUMENT_ROOT .'/includes/phplot5/'); + } + else + { + define('PHPLOT_PATH', DOL_DOCUMENT_ROOT .'/includes/phplot/'); + } +} if (! defined('JPGRAPH_PATH')) { define('JPGRAPH_PATH', DOL_DOCUMENT_ROOT .'/includes/jpgraph/'); } if (! defined('NUSOAP_PATH')) { define('NUSOAP_PATH', DOL_DOCUMENT_ROOT .'/includes/nusoap/lib/'); } if (! defined('TCPDF_PATH')) { define('TCPDF_PATH', DOL_DOCUMENT_ROOT .'/includes/fpdf/tcpdf/'); } diff --git a/htdocs/product.class.php b/htdocs/product.class.php index c3f62bb76b7..a0f5625064a 100644 --- a/htdocs/product.class.php +++ b/htdocs/product.class.php @@ -1204,71 +1204,69 @@ class Product } - /** - * \brief Renvoie le nombre de factures dans lesquelles figure le produit par mois - * \param socid id societe - * \return array nombre de factures par mois - */ - - function get_num_vente($socid=0) - { - global $conf; - global $user; - - $sql = "SELECT count(*), date_format(f.datef, '%Y%m') "; - $sql .= " FROM ".MAIN_DB_PREFIX."facturedet as d, ".MAIN_DB_PREFIX."facture as f"; - if (!$user->rights->commercial->client->voir && !$socid) $sql .= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc"; - $sql .= " WHERE f.rowid = d.fk_facture AND d.fk_product =".$this->id; - if (!$user->rights->commercial->client->voir && !$socid) $sql .= " AND f.fk_soc = sc.fk_soc AND sc.fk_user = " .$user->id; - if ($socid > 0) + /** + * \brief Renvoie le nombre de factures dans lesquelles figure le produit par mois + * \param socid id societe + * \return array nombre de factures par mois + */ + function get_num_vente($socid=0) { - $sql .= " AND f.fk_soc = $socid"; + global $conf; + global $user; + + $sql = "SELECT count(*), date_format(f.datef, '%Y%m') "; + $sql .= " FROM ".MAIN_DB_PREFIX."facturedet as d, ".MAIN_DB_PREFIX."facture as f"; + if (!$user->rights->commercial->client->voir && !$socid) $sql .= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc"; + $sql .= " WHERE f.rowid = d.fk_facture AND d.fk_product =".$this->id; + if (!$user->rights->commercial->client->voir && !$socid) $sql .= " AND f.fk_soc = sc.fk_soc AND sc.fk_user = " .$user->id; + if ($socid > 0) + { + $sql .= " AND f.fk_soc = $socid"; + } + $sql .= " GROUP BY date_format(f.datef,'%Y%m') DESC ;"; + + return $this->_get_stats($sql); } - $sql .= " GROUP BY date_format(f.datef,'%Y%m') DESC ;"; - - return $this->_get_stats($sql); - } - - - /** - * \brief Renvoie le nombre de propales dans lesquelles figure le produit par mois - * \param socid id societe - * \return array nombre de propales par mois - */ - - function get_num_propal($socid=0) - { - global $conf; - global $user; - - $sql = "SELECT count(*), date_format(p.datep, '%Y%m') "; - $sql .= " FROM ".MAIN_DB_PREFIX."propaldet as d, ".MAIN_DB_PREFIX."propal as p"; - if (!$user->rights->commercial->client->voir && !$socid) $sql .= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc"; - $sql .= " WHERE p.rowid = d.fk_propal and d.fk_product =".$this->id; - if (!$user->rights->commercial->client->voir && !$socid) $sql .= " AND p.fk_soc = sc.fk_soc AND sc.fk_user = " .$user->id; - if ($socid > 0) + + + /** + * \brief Renvoie le nombre de propales dans lesquelles figure le produit par mois + * \param socid id societe + * \return array nombre de propales par mois + */ + function get_num_propal($socid=0) { - $sql .= " AND p.fk_soc = $socid"; + global $conf; + global $user; + + $sql = "SELECT count(*), date_format(p.datep, '%Y%m') "; + $sql .= " FROM ".MAIN_DB_PREFIX."propaldet as d, ".MAIN_DB_PREFIX."propal as p"; + if (!$user->rights->commercial->client->voir && !$socid) $sql .= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc"; + $sql .= " WHERE p.rowid = d.fk_propal and d.fk_product =".$this->id; + if (!$user->rights->commercial->client->voir && !$socid) $sql .= " AND p.fk_soc = sc.fk_soc AND sc.fk_user = " .$user->id; + if ($socid > 0) + { + $sql .= " AND p.fk_soc = $socid"; + } + $sql .= " GROUP BY date_format(p.datep,'%Y%m') DESC ;"; + + return $this->_get_stats($sql); } - $sql .= " GROUP BY date_format(p.datep,'%Y%m') DESC ;"; - return $this->_get_stats($sql); - } -/** - * \brief Lie un sousproduit au produit/service - * \param id_pere Id du produit auquel sera lié le produit à lier - * \param id_fils Id du produit à lier - * \return int < 0 si erreur, > 0 si ok - */ - - function add_sousproduit($id_pere, $id_fils,$qty) - { + /** + * \brief Lie un sousproduit au produit/service + * \param id_pere Id du produit auquel sera lié le produit à lier + * \param id_fils Id du produit à lier + * \return int < 0 si erreur, > 0 si ok + */ + function add_sousproduit($id_pere, $id_fils,$qty) + { $sql = 'delete from '.MAIN_DB_PREFIX.'product_association'; $sql .= ' WHERE fk_product_pere = "'.$id_pere.'" and fk_product_fils = "'.$id_fils.'"'; if (! $this->db->query($sql)) { dolibarr_print_error($this->db); - return -1; + return -1; } else { @@ -1277,12 +1275,12 @@ class Product if (! $this->db->query($sql)) { dolibarr_print_error($this->db); - return -1; + return -1; } else { $result = $this->db->query($sql) ; - if ($result) + if ($result) { $num = $this->db->num_rows($result); if($num > 0) @@ -1292,119 +1290,119 @@ class Product } else { - $sql = 'insert into '.MAIN_DB_PREFIX.'product_association(fk_product_pere,fk_product_fils,qty)'; - $sql .= ' VALUES ("'.$id_pere.'","'.$id_fils.'","'.$qty.'")'; - if (! $this->db->query($sql)) - { - dolibarr_print_error($this->db); - return -1; - } - else - { - return 1; - } + $sql = 'insert into '.MAIN_DB_PREFIX.'product_association(fk_product_pere,fk_product_fils,qty)'; + $sql .= ' VALUES ("'.$id_pere.'","'.$id_fils.'","'.$qty.'")'; + if (! $this->db->query($sql)) + { + dolibarr_print_error($this->db); + return -1; + } + else + { + return 1; + } } } } - + } - } -/** - * \brief retire le lien entre un sousproduit et un produit/service - * \param id_pere Id du produit auquel ne sera plus lié le produit lié - * \param id_fils Id du produit à ne plus lié - * \return int < 0 si erreur, > 0 si ok - */ - - function del_sousproduit($id_pere, $id_fils) - { - $sql = 'delete from '.MAIN_DB_PREFIX.'product_association'; + } + + /** + * \brief retire le lien entre un sousproduit et un produit/service + * \param id_pere Id du produit auquel ne sera plus lié le produit li + * \param id_fils Id du produit à ne plus li + * \return int < 0 si erreur, > 0 si ok + */ + function del_sousproduit($id_pere, $id_fils) + { + $sql = 'delete from '.MAIN_DB_PREFIX.'product_association'; $sql .= ' WHERE fk_product_pere = "'.$id_pere.'" and fk_product_fils = "'.$id_fils.'"'; if (! $this->db->query($sql)) { dolibarr_print_error($this->db); - return -1; + return -1; } else - return 1; - } -/** - * \brief retire le lien entre un sousproduit et un produit/service - * \param id_pere Id du produit auquel ne sera plus lié le produit lié - * \param id_fils Id du produit à ne plus lié - * \return int < 0 si erreur, > 0 si ok - */ - - function is_sousproduit($id_pere, $id_fils) - { - $sql = 'select fk_product_pere,qty from '.MAIN_DB_PREFIX.'product_association'; + return 1; + } + + /** + * \brief retire le lien entre un sousproduit et un produit/service + * \param id_pere Id du produit auquel ne sera plus lié le produit li + * \param id_fils Id du produit à ne plus li + * \return int < 0 si erreur, > 0 si ok + */ + function is_sousproduit($id_pere, $id_fils) + { + $sql = 'select fk_product_pere,qty from '.MAIN_DB_PREFIX.'product_association'; $sql .= ' WHERE fk_product_pere = "'.$id_pere.'" and fk_product_fils = "'.$id_fils.'"'; if (! $this->db->query($sql)) { dolibarr_print_error($this->db); - return -1; + return -1; } else { $result = $this->db->query($sql) ; - if ($result) - { - $num = $this->db->num_rows($result); + if ($result) + { + $num = $this->db->num_rows($result); if($num > 0) { $obj = $this->db->fetch_object($result); - $this->is_sousproduit_qty = $obj->qty; - + $this->is_sousproduit_qty = $obj->qty; + return true; } else - return false; + return false; } } - } - /** - * \brief Lie un fournisseur au produit/service - * \param user Utilisateur qui fait le lien - * \param id_fourn Id du fournisseur - * \param ref_fourn Reference chez le fournisseur - * \return int < 0 si erreur, > 0 si ok - */ - - function add_fournisseur($user, $id_fourn, $ref_fourn) - { - $sql = "SELECT count(*) as nb"; - $sql.= " FROM ".MAIN_DB_PREFIX."product_fournisseur"; - $sql.= " WHERE fk_product = ".$this->id." AND fk_soc = ".$id_fourn; - //$sql.= " AND ref_fourn = '".$ref_fourn."'"; // crée des doublons - - $resql=$this->db->query($sql); - if ($resql) - { - $obj = $this->db->fetch_object($resql); - if ($obj->nb == 0) - { - $sql = "INSERT INTO ".MAIN_DB_PREFIX."product_fournisseur "; - $sql .= " (datec, fk_product, fk_soc, ref_fourn, fk_user_author)"; - $sql .= " VALUES (now(), $this->id, $id_fourn, '$ref_fourn', $user->id)"; - - if ($this->db->query($sql)) - { - return 1; - } - else - { - $this->error=$this->db->error(); - return -1; - } - } - $this->db->free($resql); - } - else - { - $this->error=$this->db->error(); - return -2; - } - } + } + + /** + * \brief Lie un fournisseur au produit/service + * \param user Utilisateur qui fait le lien + * \param id_fourn Id du fournisseur + * \param ref_fourn Reference chez le fournisseur + * \return int < 0 si erreur, > 0 si ok + */ + function add_fournisseur($user, $id_fourn, $ref_fourn) + { + $sql = "SELECT count(*) as nb"; + $sql.= " FROM ".MAIN_DB_PREFIX."product_fournisseur"; + $sql.= " WHERE fk_product = ".$this->id." AND fk_soc = ".$id_fourn; + //$sql.= " AND ref_fourn = '".$ref_fourn."'"; // crée des doublons + + $resql=$this->db->query($sql); + if ($resql) + { + $obj = $this->db->fetch_object($resql); + if ($obj->nb == 0) + { + $sql = "INSERT INTO ".MAIN_DB_PREFIX."product_fournisseur "; + $sql .= " (datec, fk_product, fk_soc, ref_fourn, fk_user_author)"; + $sql .= " VALUES (now(), $this->id, $id_fourn, '$ref_fourn', $user->id)"; + + if ($this->db->query($sql)) + { + return 1; + } + else + { + $this->error=$this->db->error(); + return -1; + } + } + $this->db->free($resql); + } + else + { + $this->error=$this->db->error(); + return -2; + } + } /** diff --git a/htdocs/product/stats/fiche.php b/htdocs/product/stats/fiche.php index e6182ce15e0..2598a88b39e 100644 --- a/htdocs/product/stats/fiche.php +++ b/htdocs/product/stats/fiche.php @@ -99,11 +99,13 @@ if ($_GET["id"] || $_GET["ref"]) { $graph_data = $product->get_num_vente($socid); $px->SetData($graph_data); - $px->SetMaxValue($px->GetCeilMaxValue()); + $px->SetMaxValue($px->GetCeilMaxValue()<0?0:$px->GetCeilMaxValue()); + $px->SetMinValue($px->GetFloorMinValue()>0?0:$px->GetFloorMinValue()); $px->SetWidth($WIDTH); $px->SetHeight($HEIGHT); + $px->SetHorizTickIncrement(1); $px->SetPrecisionY(0); - $px->SetShading(6); + $px->SetShading(5); $px->draw($filenbvente); } @@ -113,11 +115,13 @@ if ($_GET["id"] || $_GET["ref"]) { $graph_data = $product->get_nb_vente($socid); $px->SetData($graph_data); - $px->SetMaxValue($px->GetCeilMaxValue()); + $px->SetMaxValue($px->GetCeilMaxValue()<0?0:$px->GetCeilMaxValue()); + $px->SetMinValue($px->GetFloorMinValue()>0?0:$px->GetFloorMinValue()); $px->SetWidth($WIDTH); $px->SetHeight($HEIGHT); + $px->SetHorizTickIncrement(1); $px->SetPrecisionY(0); - $px->SetShading(6); + $px->SetShading(5); $px->draw($filenbpiece); } @@ -127,11 +131,13 @@ if ($_GET["id"] || $_GET["ref"]) { $graph_data = $product->get_num_propal($socid); $px->SetData($graph_data); - $px->SetMaxValue($px->GetCeilMaxValue()); + $px->SetMaxValue($px->GetCeilMaxValue()<0?0:$px->GetCeilMaxValue()); + $px->SetMinValue($px->GetFloorMinValue()>0?0:$px->GetFloorMinValue()); $px->SetWidth($WIDTH); $px->SetHeight($HEIGHT); + $px->SetHorizTickIncrement(1); $px->SetPrecisionY(0); - $px->SetShading(6); + $px->SetShading(5); $px->draw($filenbpropal); }